Skip to content

Commit

Permalink
rustPlatform.importCargoLock: Support 'cargo-vendor --no-merge-source…
Browse files Browse the repository at this point in the history
…s' feature
  • Loading branch information
junjihashimoto committed Jan 27, 2025
1 parent fa9a43a commit 356c02d
Show file tree
Hide file tree
Showing 9 changed files with 210 additions and 35 deletions.
71 changes: 56 additions & 15 deletions pkgs/build-support/rust/import-cargo-lock.nix
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,26 @@ let
builtins.map nameGitSha (builtins.filter (pkg: lib.hasPrefix "git+" pkg.source) depPackages)
);

nameGitSha = pkg: let gitParts = parseGit pkg.source; in {
name = "${pkg.name}-${pkg.version}";
value = gitParts.sha;
};
namesGitShasWithSha = builtins.listToAttrs (
builtins.map nameGitShaWithSha (builtins.filter (pkg: lib.hasPrefix "git+" pkg.source) depPackages)
);

nameGitSha = pkg:
let
gitParts = parseGit pkg.source;
in {
name = "${pkg.name}-${pkg.version}";
value = gitParts.sha;
};

nameGitShaWithSha = pkg:
let
gitParts = parseGit pkg.source;
suffix = if builtins.isNull gitParts then "" else "-" + gitParts.sha;
in {
name = "${pkg.name}-${pkg.version}${suffix}";
value = gitParts.sha;
};

# Convert the attrset provided through the `outputHashes` argument to a
# a mapping from git commit SHA -> output hash.
Expand All @@ -88,7 +104,7 @@ let
gitShaOutputHash = lib.mapAttrs' (nameVer: hash:
let
unusedHash = throw "A hash was specified for ${nameVer}, but there is no corresponding git dependency.";
rev = namesGitShas.${nameVer} or unusedHash; in {
rev = namesGitShasWithSha.${nameVer} or namesGitShas.${nameVer} or unusedHash; in {
name = rev;
value = hash;
}) outputHashes;
Expand Down Expand Up @@ -122,12 +138,13 @@ let
let
gitParts = parseGit pkg.source;
registryIndexUrl = lib.removePrefix "registry+" pkg.source;
suffix = if builtins.isNull gitParts then "" else "-" + gitParts.sha;
in
if (lib.hasPrefix "registry+" pkg.source || lib.hasPrefix "sparse+" pkg.source)
&& builtins.hasAttr registryIndexUrl registries then
let
crateTarball = fetchCrate pkg registries.${registryIndexUrl};
in runCommand "${pkg.name}-${pkg.version}" {} ''
in runCommand "${pkg.name}-${pkg.version}${suffix}" {} ''
mkdir $out
tar xf "${crateTarball}" -C $out --strip-components=1
Expand All @@ -137,13 +154,19 @@ let
else if gitParts != null then
let
missingHash = throw ''
No hash was found while vendoring the git dependency ${pkg.name}-${pkg.version}. You can add
No hash was found while vendoring the git dependency ${pkg.name}-${pkg.version} or ${pkg.name}-${pkg.version}${suffix}. You can add
a hash through the `outputHashes` argument of `importCargoLock`:
outputHashes = {
"${pkg.name}-${pkg.version}" = "<hash>";
};
or
outputHashes = {
"${pkg.name}-${pkg.version}${suffix}" = "<hash>";
};
If you use `buildRustPackage`, you can add this attribute to the `cargoLock`
attribute set.
'';
Expand All @@ -163,7 +186,7 @@ let
}
else
missingHash;
in runCommand "${pkg.name}-${pkg.version}" {} ''
in runCommand "${pkg.name}-${pkg.version}${suffix}" {} ''
tree=${tree}
# If the target package is in a workspace, or if it's the top-level
Expand All @@ -187,7 +210,7 @@ let
done
if [[ -z $crateCargoTOML ]]; then
>&2 echo "Cannot find path for crate '${pkg.name}-${pkg.version}' in the tree in: $tree"
>&2 echo "Cannot find path for crate '${pkg.name}-${pkg.version}${suffix}' in the tree in: $tree"
exit 1
fi
fi
Expand Down Expand Up @@ -215,12 +238,16 @@ let
''}
''}
# Set up configuration for the vendor directory.
# Set up configuration for the vendor directory with package name and version.
cat > $out/.cargo-config <<EOF
[source."${pkg.source}"]
#pkg: ${pkg.name}
#version: ${pkg.version}
[source."${gitParts.url}${lib.optionalString (gitParts ? type) "?${gitParts.type}=$gitPartsValue"}"]
git = "${gitParts.url}"
${lib.optionalString (gitParts ? type) "${gitParts.type} = \"$gitPartsValue\""}
replace-with = "vendored-sources"
replace-with = "vendored-sources-git-${gitParts.sha}"
[source.vendored-sources-git-${gitParts.sha}]
directory = "cargo-vendor-dir/git-${gitParts.sha}"
EOF
''
else throw "Cannot handle crate source: ${pkg.source}";
Expand All @@ -247,7 +274,7 @@ let
replace-with = "vendored-sources"
[source.vendored-sources]
directory = "cargo-vendor-dir"
directory = "cargo-vendor-dir/registry"
EOF
declare -A keysSeen
Expand All @@ -260,17 +287,31 @@ registry = "$registry"
replace-with = "vendored-sources"
EOF
done
mkdir $out/registry
for crate in ${toString depCrates}; do
# Link the crate directory, removing the output path hash from the destination.
ln -s "$crate" $out/$(basename "$crate" | cut -c 34-)
# When the crate directory has a directory directive, putting it to git-* directory.
if [ -e "$crate/.cargo-config" ]; then
key=$(sed 's/\[source\."\(.*\)"\]/\1/; t; d' < "$crate/.cargo-config")
directory=$(sed 's/directory = "\(.*\)"/\1/; t; d' < "$crate/.cargo-config")
package_name=$(sed 's/#pkg: \(.*\)/\1/; t; d' < "$crate/.cargo-config")
if [[ ! -z "$directory" ]]; then
gitdir=$(basename "$directory")
if [ ! -d $out/$gitdir ] ; then
mkdir $out/$gitdir
fi
ln -s "$crate" $out/$gitdir/$(basename "$crate" | cut -c 34-)
else
>&2 echo "The key of 'directory' is empty in $crate/.cargo-config."
exit 1
fi
if [[ -z ''${keysSeen[$key]} ]]; then
keysSeen[$key]=1
cat "$crate/.cargo-config" >> $out/.cargo/config.toml
fi
else
ln -s "$crate" $out/registry/$(basename "$crate" | cut -c 34-)
fi
done
'';
Expand Down
40 changes: 21 additions & 19 deletions pkgs/build-support/rust/replace-workspace-values.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,34 +31,36 @@ def replace_key(
local_dep = table[key]
del local_dep["workspace"]

workspace_dep = workspace_manifest[section][key]

if section == "dependencies":
if isinstance(workspace_dep, str):
workspace_dep = {"version": workspace_dep}
if key in workspace_manifest[section]:
workspace_dep = workspace_manifest[section][key]
if isinstance(workspace_dep, str):
workspace_dep = {"version": workspace_dep}

final: dict[str, Any] = workspace_dep.copy()
final: dict[str, Any] = workspace_dep.copy()

merged_features = local_dep.pop("features", []) + workspace_dep.get("features", [])
if merged_features:
final["features"] = merged_features
merged_features = local_dep.pop("features", []) + workspace_dep.get("features", [])
if merged_features:
final["features"] = merged_features

local_default_features = local_dep.pop("default-features", None)
workspace_default_features = workspace_dep.get("default-features")
local_default_features = local_dep.pop("default-features", None)
workspace_default_features = workspace_dep.get("default-features")

if not workspace_default_features and local_default_features:
final["default-features"] = True
if not workspace_default_features and local_default_features:
final["default-features"] = True

optional = local_dep.pop("optional", False)
if optional:
final["optional"] = True
optional = local_dep.pop("optional", False)
if optional:
final["optional"] = True

if local_dep:
raise Exception(f"Unhandled keys in inherited dependency {key}: {local_dep}")
if local_dep:
raise Exception(f"Unhandled keys in inherited dependency {key}: {local_dep}")

table[key] = final
table[key] = final
elif section == "package":
table[key] = workspace_dep
if key in workspace_manifest[section]:
workspace_dep = workspace_manifest[section][key]
table[key] = workspace_dep

return True

Expand Down
1 change: 1 addition & 0 deletions pkgs/build-support/rust/test/import-cargo-lock/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
basicDynamic = callPackage ./basic-dynamic { };
gitDependency = callPackage ./git-dependency { };
gitDependencyRev = callPackage ./git-dependency-rev { };
gitDependencyRevWithHash = callPackage ./git-dependency-rev-with-hash { };
gitDependencyRevNonWorkspaceNestedCrate = callPackage ./git-dependency-rev-non-workspace-nested-crate { };
gitDependencyTag = callPackage ./git-dependency-tag { };
gitDependencyBranch = callPackage ./git-dependency-branch { };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
rustPlatform,
pkg-config,
openssl,
zlib,
lib,
darwin,
stdenv,
Expand Down Expand Up @@ -29,6 +30,7 @@ rustPlatform.buildRustPackage {
buildInputs =
[
openssl
zlib
]
++ lib.optionals stdenv.hostPlatform.isDarwin [
darwin.apple_sdk.frameworks.Security
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "git-dependency-rev-with-hash"
version = "0.1.0"
authors = ["Daniël de Kok <me@danieldk.eu>"]
edition = "2018"

[dependencies]
rand = { git = "https://github.com/rust-random/rand.git", rev = "0.8.3" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{ lib, rustPlatform }:
let
fs = lib.fileset;
in
rustPlatform.buildRustPackage {
pname = "git-dependency-rev-with-hash";
version = "0.1.0";

src = fs.toSource {
root = ./.;
fileset = fs.unions [
./Cargo.toml
./Cargo.lock
./src
];
};

cargoLock = {
lockFile = ./Cargo.lock;
outputHashes = {
"rand-0.8.3-6ecbe2626b2cc6110a25c97b1702b347574febc7" =
"0l3p174bpwia61vcvxz5mw65a13ri3wy94z04xrnyy5lzciykz4f";
};
};

doInstallCheck = true;

installCheckPhase = ''
$out/bin/git-dependency-rev-with-hash
'';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use rand::Rng;

fn main() {
let mut rng = rand::thread_rng();

// Always draw zero :).
let roll: u8 = rng.gen_range(0..1);
assert_eq!(roll, 0);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ keywords = [
bar = "1.0.0"

[dependencies.foo]
version = "1.0.0"
features = [
"cat",
"meow",
]
version = "1.0.0"

0 comments on commit 356c02d

Please sign in to comment.