Skip to content

Commit 1be0099

Browse files
committed
[nix] Hack to use vendored deps in shell
This has to materialise a number of .cargo/config.toml into the tree in order to point Cargo at the Nix-vendored deps. Ideally, the cargo wrapper script would just pass some config information, but unfortunately, due to rust-lang/cargo#11031, external subcommands do not respect --config and will only pick up configuration that's actually in .cargo/config.toml files in the tree. In order to reduce the risk of these getting improperly committed to the repository, the script also adds them to .git/info/exclude whenever it creates them. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
1 parent 2632ed9 commit 1be0099

1 file changed

Lines changed: 71 additions & 5 deletions

File tree

flake.nix

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,38 +96,81 @@
9696
rustc = toolchains.stable.rust;
9797
};
9898

99+
# Script snippet, used in the cargo/rustc wrappers below,
100+
# which creates a number of .cargo/config.toml files in
101+
# order to allow using Nix-fetched dependencies (this must
102+
# be done for the guests, as well as for the main
103+
# workspace). Ideally, we would just use environment
104+
# variables or the --config option to Cargo, but
105+
# unfortunately that tends not to play well with subcommands
106+
# like `cargo clippy` and `cargo hyperlight` (see
107+
# https://github.com/rust-lang/cargo/issues/11031).
108+
materialiseDeps = deps: let
109+
sortedNames = lib.lists.reverseList (builtins.attrNames deps);
110+
matchClause = path: '' */${path}) root="''${manifest%${path}}" ;;'';
111+
matchClauses = lib.strings.concatStringsSep "\n"
112+
(builtins.map matchClause sortedNames);
113+
makeClause = manifest: vendor: let
114+
dir = builtins.dirOf manifest;
115+
gitExclude = builtins.toString (/. + "${dir}/.cargo");
116+
in ''
117+
mkdir -p $root/${dir}/.cargo
118+
cat >$root/${dir}/.cargo/config.toml <<EOF
119+
[source.crates-io]
120+
replace-with = "vendored-sources"
121+
122+
[source.vendored-sources]
123+
directory = "${vendor}"
124+
EOF
125+
printf "# vendor dependency configuration generated by nix\n%s\n" "${gitExclude}" >> $root/.git/info/exclude
126+
'';
127+
makeClauses = lib.strings.concatStringsSep "\n"
128+
(lib.mapAttrsToList makeClause deps);
129+
in ''
130+
manifest=$(''${base}/bin/cargo locate-project --message-format plain --workspace)
131+
case "$manifest" in
132+
${matchClauses}
133+
esac
134+
if [ -f ''${root}/flake.nix ]; then
135+
sed -i '/# vendor dependency configuration generated by nix/{N;d;}' $root/.git/info/exclude
136+
${makeClauses}
137+
fi
138+
'';
139+
99140
# Hyperlight scripts use cargo in a bunch of ways that don't
100141
# make sense for Nix cargo, including the `rustup +toolchain`
101142
# syntax to use a specific toolchain and `cargo install`, so we
102143
# build wrappers for rustc and cargo that enable this. The
103144
# scripts also use `rustup toolchain install` in some cases, in
104145
# order to work in CI, so we provide a fake rustup that does
105146
# nothing as well.
106-
rustup-like-wrapper = name: pkgs.writeShellScriptBin name
147+
rustup-like-wrapper = name: deps: pkgs.writeShellScriptBin name
107148
(let
108149
clause = name: toolchain:
109150
"+${name}) base=\"${toolchain.rust}\"; shift 1; ;;";
110151
clauses = lib.strings.concatStringsSep "\n"
111152
(lib.mapAttrsToList clause toolchains);
112153
in ''
113154
base="${toolchains.stable.rust}"
155+
${materialiseDeps deps}
114156
case "$1" in
115157
${clauses}
116158
install) exit 0; ;;
117159
esac
118160
export PATH="$base/bin:$PATH"
119161
exec "$base/bin/${name}" "$@"
120162
'');
121-
fake-rustup = pkgs.symlinkJoin {
163+
fake-rustup = deps: pkgs.symlinkJoin {
122164
name = "fake-rustup";
123165
paths = [
124166
(pkgs.writeShellScriptBin "rustup" "")
125-
(rustup-like-wrapper "rustc")
126-
(rustup-like-wrapper "cargo")
167+
(rustup-like-wrapper "rustc" deps)
168+
(rustup-like-wrapper "cargo" deps)
127169
];
128170
};
129171

130172
buildRustPackageClang = rust-platform.buildRustPackage.override { stdenv = clangStdenv; };
173+
131174
cargo-hyperlight = buildRustPackageClang rec {
132175
pname = "cargo-hyperlight";
133176
version = "0.1.5";
@@ -139,6 +182,29 @@
139182
};
140183
cargoHash = "sha256-muiMVrK1TydQiMitihfo7xYidqUIIQ+Hw3BIeo5rLFw=";
141184
};
185+
# when building a guest with cargo-hyperlight, we need to
186+
# include any crates.io dependencies of the standard library
187+
# (e.g. rustc-literal-escaper)
188+
stdlibLocks = lib.mapAttrsToList (_: toolchain:
189+
"${toolchain.rust}/lib/rustlib/src/rust/library/Cargo.lock"
190+
) toolchains;
191+
stdlibDeps = builtins.map (lockFile:
192+
rust-platform.importCargoLock { inherit lockFile; }) stdlibLocks;
193+
withStdlibLock = lockFile:
194+
pkgs.symlinkJoin {
195+
name = "cargo-deps";
196+
paths = stdlibDeps ++ [
197+
(rust-platform.importCargoLock {
198+
inherit lockFile;
199+
})
200+
];
201+
};
202+
deps = finalRootVendor: {
203+
"Cargo.toml" = finalRootVendor;
204+
"src/tests/rust_guests/dummyguest/Cargo.toml" = withStdlibLock ./src/tests/rust_guests/dummyguest/Cargo.lock;
205+
"src/tests/rust_guests/simpleguest/Cargo.toml" = withStdlibLock ./src/tests/rust_guests/simpleguest/Cargo.lock;
206+
"src/tests/rust_guests/witguest/Cargo.toml" = withStdlibLock ./src/tests/rust_guests/witguest/Cargo.lock;
207+
};
142208
in (buildRustPackageClang (mkDerivationAttrs: {
143209
pname = "hyperlight";
144210
version = "0.0.0";
@@ -179,7 +245,7 @@
179245
# Set this through shellHook rather than nativeBuildInputs to be
180246
# really sure that it overrides the real cargo.
181247
postHook = ''
182-
export PATH="${fake-rustup}/bin:$PATH"
248+
export PATH="${fake-rustup (deps mkDerivationAttrs.cargoDeps)}/bin:$PATH"
183249
'';
184250
})).overrideAttrs(oA: {
185251
hardeningDisable = [ "all" ];

0 commit comments

Comments
 (0)