Make RustRover work with Rust from Nixpkgs
1{
2 lib,
3 mkShell,
4 writeShellScriptBin,
5 buildEnv,
6 rsync,
7 lndir,
8 rustup,
9
10 rustc,
11 cargo,
12 rustc-unwrapped,
13 withNonRustupSysroot ? true,
14 rustLibSrc ? null,
15 addToToolchain ? [ ],
16
17 projectRoot,
18}:
19args:
20assert withNonRustupSysroot -> rustLibSrc != null;
21assert withNonRustupSysroot -> rustc-unwrapped != null;
22let
23 ideaDir = "${projectRoot}/.idea/nix-rust";
24 sysrootDir = "${ideaDir}/sysroot";
25 rustupHome = "${ideaDir}/rustup-home";
26 fingerprintFile = "${ideaDir}/environment.fingerprint";
27 envFile = "${ideaDir}/shell-env";
28 toolchainName = "nix-toolchain";
29
30 tools = buildEnv {
31 name = (args.name or "rr") + "-tools";
32 paths = addToToolchain;
33 };
34
35 environmentFingerprint = builtins.hashString "sha256" (toString [
36 rustc
37 cargo
38 rustup
39 (lib.optionals withNonRustupSysroot [
40 rustc-unwrapped
41 rustLibSrc
42 ])
43 tools
44 ]);
45
46 checkFingerprint = writeShellScriptBin "check-fingerprint" ''
47 if [ -f "${fingerprintFile}" ] && [ -d ${sysrootDir} ]; then
48 STORED_FINGERPRINT=$(cat "${fingerprintFile}")
49 if [ "$STORED_FINGERPRINT" = "${environmentFingerprint}" ]; then
50 echo "Environment is up to date at ${ideaDir}"
51 exit 0
52 fi
53 fi
54 echo "Environment changed, recreating..."
55 rm -rf ${ideaDir} && exit 1
56 '';
57
58 createSysrootNonRustup = writeShellScriptBin "create-sysroot" ''
59 mkdir -p ${sysrootDir}
60
61 ${lib.getExe lndir} ${rustc-unwrapped} ${sysrootDir}
62
63 mkdir -p "${sysrootDir}/lib/rustlib/src/rust"
64 rm -rf "${sysrootDir}/lib/rustlib/src/rust/library"
65 ${lib.getExe rsync} -aq ${rustLibSrc}/ "${sysrootDir}/lib/rustlib/src/rust/library/"
66 chmod -R u+w "${sysrootDir}/lib/rustlib/src/rust/library"
67
68 ${lib.getExe lndir} ${cargo}/bin ${sysrootDir}/bin
69 ${lib.getExe lndir} ${tools}/bin ${sysrootDir}/bin
70
71 echo "${environmentFingerprint}" > "${fingerprintFile}"
72 echo "Sysroot created at ${sysrootDir}"
73 '';
74
75 createSysrootRustup = writeShellScriptBin "create-sysroot" ''
76 mkdir -p ${sysrootDir}
77 ${lndir}/bin/lndir ${rustc} ${sysrootDir} >/dev/null 2>&1
78 ${lndir}/bin/lndir ${cargo}/bin "${sysrootDir}/bin" >/dev/null 2>&1
79 ${lndir}/bin/lndir ${tools}/bin "${sysrootDir}/bin" >/dev/null 2>&1
80
81 echo "${environmentFingerprint}" > "${fingerprintFile}"
82 echo "Sysroot created at ${sysrootDir}"
83 '';
84
85 sourceEnv = ''
86 if [ -f "${envFile}" ]; then
87 set -a && source "${envFile}" && set +a
88 fi
89 '';
90
91 rustcWrapper = writeShellScriptBin "rustc" ''
92 ${sourceEnv}
93 if [ "$1" = "--print" ] && [ "$2" = "sysroot" ]; then
94 echo ${sysrootDir}
95 else
96 exec ${rustup}/bin/rustc "$@"
97 fi
98 '';
99
100 rustupWrapper = writeShellScriptBin "rustup" ''
101 ${sourceEnv}
102 if [ "$1" = "component" ] && [ "$2" = "list" ]; then
103 shift 2
104 exec ${./list-components.sh} ${sysrootDir} "$@"
105 else
106 exec -a "$0" ${rustup}/bin/rustup "$@"
107 fi
108 '';
109
110 createSysroot = if withNonRustupSysroot then createSysrootNonRustup else createSysrootRustup;
111
112 createEnvironment = writeShellScriptBin "create-environment" ''
113 ${lib.getExe checkFingerprint} && exit 0
114
115 mkdir -p .idea
116 ${lib.getExe createSysroot}
117
118 mkdir -p ${ideaDir}/bin
119
120 ${lib.getExe lndir} ${rustup}/bin ${ideaDir}/bin && rm ${ideaDir}/bin/rustc ${ideaDir}/bin/rustup
121 ${lib.getExe lndir} ${rustcWrapper}/bin ${ideaDir}/bin
122 ${lib.getExe lndir} ${rustupWrapper}/bin ${ideaDir}/bin
123
124 mkdir -p "$RUSTUP_HOME/toolchains"
125
126 ${rustup}/bin/rustup toolchain link ${toolchainName} "${sysrootDir}"
127 ${rustup}/bin/rustup default ${toolchainName}
128 '';
129in
130mkShell (
131 args
132 // {
133 packages = (args.packages or [ ]) ++ [ rustup ];
134
135 env.RUSTUP_HOME = rustupHome;
136 shellHook = (args.shellHook or "") + ''
137 ${lib.getExe createEnvironment}
138 export -p | grep -vE '^declare -x (TMPDIR|TMP|TEMP|TEMPDIR)=' > "${envFile}"
139 '';
140 }
141)