Skip to content

Instantly share code, notes, and snippets.

@andir
Last active April 28, 2022 08:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save andir/99e3260b75a511c4462a0001cc65198e to your computer and use it in GitHub Desktop.
Save andir/99e3260b75a511c4462a0001cc65198e to your computer and use it in GitHub Desktop.
Edolstra's import-cargo without the flake.
# based on https://github.com/edolstra/import-cargo @ 25d40be4a73d40a2572e0cc233b83253554f06c5
{ runCommand, makeSetupHook, writeScript }:
{ lockFile }:
let lockFile' = builtins.fromTOML (builtins.readFile lockFile); in
rec {
# Fetch and unpack the crates specified in the lock file.
unpackedCrates = map
(pkg:
let
isGit = builtins.match ''git\+(.*)\?rev=([0-9a-f]+)(#.*)?'' pkg.source;
registry = "registry+https://github.com/rust-lang/crates.io-index";
in
if pkg.source == registry then
let
sha256 = pkg.checksum or lockFile'.metadata."checksum ${pkg.name} ${pkg.version} (${registry})";
tarball = import <nix/fetchurl.nix> {
url = "https://crates.io/api/v1/crates/${pkg.name}/${pkg.version}/download";
inherit sha256;
};
in
runCommand "${pkg.name}-${pkg.version}" { }
''
mkdir $out
tar xvf ${tarball} -C $out --strip-components=1
# Add just enough metadata to keep Cargo happy.
printf '{"files":{},"package":"${sha256}"}' > "$out/.cargo-checksum.json"
''
else if isGit != null then
let
rev = builtins.elemAt isGit 1;
url = builtins.elemAt isGit 0;
tree = builtins.fetchGit { inherit url rev; };
in
runCommand "${pkg.name}-${pkg.version}" { }
''
tree=${tree}
if grep --quiet '\[workspace\]' $tree/Cargo.toml; then
if [[ -e $tree/${pkg.name} ]]; then
tree=$tree/${pkg.name}
fi
fi
cp -prvd $tree/ $out
chmod u+w $out
# Add just enough metadata to keep Cargo happy.
printf '{"files":{},"package":null}' > "$out/.cargo-checksum.json"
cat > $out/.cargo-config <<EOF
[source."${url}"]
git = "${url}"
rev = "${rev}"
replace-with = "vendored-sources"
EOF
''
else throw "Unsupported crate source '${pkg.source}' in dependency '${pkg.name}-${pkg.version}'.")
(builtins.filter (pkg: pkg.source or "" != "") lockFile'.package);
# Create a directory that symlinks all the crate sources and
# contains a cargo configuration file that redirects to those
# sources.
vendorDir = runCommand "cargo-vendor-dir" { }
''
mkdir -p $out/vendor
cat > $out/vendor/config <<EOF
[source.crates-io]
replace-with = "vendored-sources"
[source.vendored-sources]
directory = "vendor"
EOF
declare -A keysSeen
for i in ${toString unpackedCrates}; do
ln -s $i $out/vendor/$(basename "$i" | cut -c 34-)
if [[ -e "$i/.cargo-config" ]]; then
# Ensure we emit TOML keys only once.
key=$(sed 's/\[source\."\(.*\)"\]/\1/; t; d' < "$i/.cargo-config")
if [[ -z ''${keysSeen[$key]} ]]; then
keysSeen[$key]=1
cat "$i/.cargo-config" >> $out/vendor/config
fi
fi
done
'';
# Create a setup hook that will initialize CARGO_HOME. Note:
# we don't point CARGO_HOME at the vendor tree directly
# because then we end up with a runtime dependency on it.
cargoHome = makeSetupHook { }
(writeScript "make-cargo-home" ''
if [[ -z "''${CARGO_HOME-}" || "''${CARGO_HOME-}" = /build ]]; then
export CARGO_HOME=$TMPDIR/vendor
# FIXME: work around Rust 1.36 wanting a $CARGO_HOME/.package-cache file.
#ln -s ${vendorDir}/vendor $CARGO_HOME
cp -prd ${vendorDir}/vendor $CARGO_HOME
chmod -R u+w $CARGO_HOME
fi
'');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment