+9
README.md
+9
README.md
···
···
1
+
# Force RustRover to semi-work with Rust installs from Nixpkgs
2
+
3
+
- Tested with a toolchain from Nixpkgs, see examples/nixpkgs.nix and Fenix, see examples/fenix.nix
4
+
- Works by creating a toolchain in your `.idea` folder
5
+
6
+
TODO:
7
+
8
+
- [ ] A proper API for adding native libraries for linking
9
+
- [ ] An example of using in Flakes (without relying on `toString ./.` being the impure project root)
+125
default.nix
+125
default.nix
···
···
1
+
{
2
+
lib,
3
+
mkShell,
4
+
writeShellScriptBin,
5
+
runCommand,
6
+
buildEnv,
7
+
coreutils,
8
+
nushell,
9
+
10
+
rustc,
11
+
cargo,
12
+
rustc-unwrapped,
13
+
withNonRustupSysroot ? true,
14
+
rustLibSrc ? null,
15
+
addToToolchain ? [ ],
16
+
17
+
projectRoot,
18
+
}:
19
+
args:
20
+
assert withNonRustupSysroot -> rustLibSrc != null;
21
+
assert withNonRustupSysroot -> rustc-unwrapped != null;
22
+
let
23
+
sysrootCacheDir = ''
24
+
SYSROOT_HASH=$(echo "${rustc-unwrapped}" | ${coreutils}/bin/md5sum | ${coreutils}/bin/cut -d' ' -f1)
25
+
CACHE_DIR="${projectRoot}/.idea/nix-rust-sysroot/$SYSROOT_HASH"
26
+
'';
27
+
28
+
createFakeSysrootNonRustup = writeShellScriptBin "create-fake-sysroot" ''
29
+
${sysrootCacheDir}
30
+
if [ ! -d "$CACHE_DIR" ]; then
31
+
mkdir -p "$CACHE_DIR"
32
+
33
+
cp -r ${rustc-unwrapped}/* "$CACHE_DIR/"
34
+
chmod -R u+w "$CACHE_DIR"
35
+
36
+
mkdir -p "$CACHE_DIR/lib/rustlib"
37
+
if [ ! -d "$CACHE_DIR/lib/rustlib/src" ]; then
38
+
cp -r ${rustc-unwrapped}/lib/rustlib/rustc-src "$CACHE_DIR/lib/rustlib/src"
39
+
chmod -R u+w "$CACHE_DIR/lib/rustlib/src"
40
+
41
+
rm -rf "$CACHE_DIR/lib/rustlib/src/rust/library"
42
+
cp -r ${rustLibSrc} "$CACHE_DIR/lib/rustlib/src/rust/library"
43
+
chmod -R u+w "$CACHE_DIR/lib/rustlib/src/rust/library"
44
+
fi
45
+
fi
46
+
47
+
echo "$CACHE_DIR"
48
+
'';
49
+
50
+
createFakeSysrootRustup = writeShellScriptBin "create-fake-sysroot" ''
51
+
${sysrootCacheDir}
52
+
if [ ! -d "$CACHE_DIR" ]; then
53
+
mkdir -p "$CACHE_DIR"
54
+
cp -r ${rustc}/* "$CACHE_DIR/"
55
+
fi
56
+
57
+
echo "$CACHE_DIR"
58
+
'';
59
+
60
+
createFakeSysroot =
61
+
if withNonRustupSysroot then createFakeSysrootNonRustup else createFakeSysrootRustup;
62
+
63
+
rustcWrapper = writeShellScriptBin "rustc" ''
64
+
if [ "$1" = "--print" ] && [ "$2" = "sysroot" ]; then
65
+
exec ${lib.getExe createFakeSysroot}
66
+
else
67
+
exec ${rustc}/bin/rustc "$@"
68
+
fi
69
+
'';
70
+
71
+
rustcWithRRLib = runCommand "rustc-wrapper-${rustc.version or "unknown"}" { } ''
72
+
mkdir -p $out/bin
73
+
ln -s ${rustc}/bin/* $out/bin
74
+
rm $out/bin/rustc
75
+
ln -s ${rustcWrapper}/bin/rustc $out/bin/rustc
76
+
${lib.concatMapStrings (output: "ln -s ${rustc.${output}} \$${output}\n") (
77
+
lib.remove "out" rustc.outputs
78
+
)}
79
+
'';
80
+
81
+
cargoWrapper = writeShellScriptBin "cargo" ''
82
+
export PATH="${rustc}/bin:$PATH"
83
+
args=()
84
+
for arg in "$@"; do
85
+
if [[ "$arg" != +* ]]; then
86
+
args+=("$arg")
87
+
fi
88
+
done
89
+
exec ${cargo}/bin/cargo "''${args[@]}"
90
+
'';
91
+
92
+
baseToolchain = buildEnv {
93
+
name = (args.name or "rr") + "-base-toolchain";
94
+
paths = [
95
+
(lib.hiPrio cargoWrapper)
96
+
rustcWithRRLib
97
+
]
98
+
++ addToToolchain;
99
+
};
100
+
101
+
fakeRustup = writeShellScriptBin "rustup" ''
102
+
export PATH="${baseToolchain}/bin:$PATH"
103
+
exec ${lib.getExe nushell} ${./src/rustup.nu} $@
104
+
'';
105
+
106
+
toolchain = buildEnv {
107
+
name = (args.name or "rr") + "-toolchain";
108
+
109
+
paths = [
110
+
baseToolchain
111
+
fakeRustup
112
+
];
113
+
};
114
+
in
115
+
mkShell (
116
+
args
117
+
// {
118
+
packages = (args.packages or [ ]) ++ [ toolchain ];
119
+
120
+
shellHook = (args.shellHook or "") + ''
121
+
mkdir -p .idea
122
+
ln -snf ${toolchain} .idea/rust-toolchain
123
+
'';
124
+
}
125
+
)
+22
examples/fenix.nix
+22
examples/fenix.nix
···
···
1
+
let
2
+
pkgs = import <nixpkgs> { };
3
+
fenix = import <fenix> { inherit pkgs; };
4
+
5
+
inherit (fenix.stable) toolchain;
6
+
mkShellRR = pkgs.callPackage ../. {
7
+
withNonRustupSysroot = false;
8
+
9
+
rustc = toolchain;
10
+
cargo = toolchain;
11
+
12
+
projectRoot = toString ./.;
13
+
};
14
+
in
15
+
mkShellRR {
16
+
packages = [ pkgs.taplo ];
17
+
18
+
shellHook = ''
19
+
echo "Welcome to the RustRover Fenix Shell!"
20
+
echo "Add .idea/rust-toolchain/bin to RustRover to use this toolchain"
21
+
'';
22
+
}
+21
examples/nixpkgs.nix
+21
examples/nixpkgs.nix
···
···
1
+
let
2
+
pkgs = import <nixpkgs> { };
3
+
mkShellRR = pkgs.callPackage ../. {
4
+
inherit (pkgs.rustPlatform) rustLibSrc;
5
+
6
+
addToToolchain = [
7
+
pkgs.clippy
8
+
pkgs.rustfmt
9
+
];
10
+
11
+
projectRoot = toString ./.;
12
+
};
13
+
in
14
+
mkShellRR {
15
+
packages = [ pkgs.taplo ];
16
+
17
+
shellHook = ''
18
+
echo "Welcome to the RustRover Nixpkgs Shell!"
19
+
echo "Add .idea/rust-toolchain/bin to RustRover to use this toolchain"
20
+
'';
21
+
}
+139
src/rustup.nu
+139
src/rustup.nu
···
···
1
+
#!/usr/bin/env nu
2
+
3
+
def get_target [] {
4
+
rustc -vV | lines | where ($it | str starts-with "host:") | first | split row ":" | get 1 | str trim
5
+
}
6
+
7
+
def get_toolchain_name [] {
8
+
$"stable-(get_target)"
9
+
}
10
+
11
+
def main [
12
+
--verbose (-v)
13
+
--quiet (-q)
14
+
--version (-V)
15
+
--help (-h)
16
+
...args
17
+
] {
18
+
if $version {
19
+
print "rustup 1.28.2 (1970-01-01)"
20
+
return
21
+
}
22
+
23
+
if $help or ($args | is-empty) {
24
+
print "rustup 1.28.2 (1970-01-01)"
25
+
print ""
26
+
print "The Rust toolchain installer"
27
+
print ""
28
+
print "Usage: rustup[EXE] [OPTIONS] [+toolchain] [COMMAND]"
29
+
print ""
30
+
print "Commands:"
31
+
print " toolchain Install, uninstall, or list toolchains"
32
+
print " default Set the default toolchain"
33
+
print " show Show the active and installed toolchains or profiles"
34
+
print " update Update Rust toolchains and rustup"
35
+
print " check Check for updates to Rust toolchains and rustup"
36
+
print " target Modify a toolchain's supported targets"
37
+
print " component Modify a toolchain's installed components"
38
+
print " override Modify toolchain overrides for directories"
39
+
print " run Run a command with an environment configured for a given toolchain"
40
+
print " which Display which binary will be run for a given command"
41
+
print " doc Open the documentation for the current toolchain"
42
+
print " man View the man page for a given command"
43
+
print " self Modify the rustup installation"
44
+
print " set Alter rustup settings"
45
+
print " completions Generate tab-completion scripts for your shell"
46
+
print " help Print this message or the help of the given subcommand(s)"
47
+
print ""
48
+
print "Arguments:"
49
+
print " [+toolchain] Release channel (e.g. +stable) or custom toolchain to set override"
50
+
print ""
51
+
print "Options:"
52
+
print " -v, --verbose Set log level to 'DEBUG' if 'RUSTUP_LOG' is unset"
53
+
print " -q, --quiet Disable progress output, set log level to 'WARN' if 'RUSTUP_LOG' is unset"
54
+
print " -h, --help Print help"
55
+
print " -V, --version Print version"
56
+
return
57
+
}
58
+
59
+
let command = ($args | first)
60
+
let rest = ($args | skip 1)
61
+
62
+
match $command {
63
+
"show" => {
64
+
if ($rest | is-empty) or (($rest | first) == "active-toolchain") {
65
+
let toolchain = (get_toolchain_name)
66
+
print $"($toolchain) \(default\)"
67
+
} else {
68
+
print $"installed toolchains"
69
+
print "--------------------"
70
+
print ""
71
+
let toolchain = (get_toolchain_name)
72
+
print $"($toolchain) \(default\)"
73
+
}
74
+
}
75
+
"which" => {
76
+
if ($rest | length) > 0 {
77
+
let cmd = ($rest | first)
78
+
try {
79
+
which $cmd | get path.0
80
+
} catch {
81
+
print $"error: toolchain '(get_toolchain_name)' does not have binary '($cmd)'"
82
+
}
83
+
}
84
+
}
85
+
"run" => {
86
+
if ($rest | length) > 1 {
87
+
let rest = ($rest | skip 1)
88
+
let cmd = ($rest | first)
89
+
let cmd_args = ($rest | skip 1)
90
+
^$cmd ...$cmd_args
91
+
}
92
+
}
93
+
"default" => {
94
+
if ($rest | is-empty) {
95
+
let toolchain = (get_toolchain_name)
96
+
print $"($toolchain) \(default\)"
97
+
} else {
98
+
print $"info: default toolchain set to '($rest | first)'"
99
+
}
100
+
}
101
+
"toolchain" => {
102
+
if ($rest | is-empty) or (($rest | first) == "list") {
103
+
let toolchain = (get_toolchain_name)
104
+
print $"($toolchain) \(default\)"
105
+
}
106
+
}
107
+
"target" => {
108
+
if ($rest | length) > 0 {
109
+
let subcmd = ($rest | first)
110
+
if $subcmd == "list" {
111
+
if ($rest | length) > 1 and (($rest | get 1) == "--installed") {
112
+
print (get_target)
113
+
} else {
114
+
print (get_target)
115
+
}
116
+
}
117
+
}
118
+
}
119
+
"component" => {
120
+
if ($rest | length) > 0 {
121
+
let subcmd = ($rest | first)
122
+
if $subcmd == "list" {
123
+
if ($rest | length) > 1 and (($rest | get 1) == "--installed") {
124
+
print "rust-std"
125
+
print "rustc"
126
+
print "cargo"
127
+
} else {
128
+
print "rust-std (installed)"
129
+
print "rustc (installed)"
130
+
print "cargo (installed)"
131
+
}
132
+
}
133
+
}
134
+
}
135
+
_ => {
136
+
print $"error: unknown command: '($command)'"
137
+
}
138
+
}
139
+
}