mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-11-25 16:33:15 +00:00
rustPlatform.importCargoLock: add support for git dependencies that use workspace inheritance
Rust 1.64.0 added support for workspace inheritance, which allows for crates to inherit values such as dependency version constraints or package metadata information from their workspaces [0]. This works by having workspace members specify a value as a table, with `workspace` set to true. Thus, supporting this in importCargoLock is as simple as walking the crate's Cargo.toml, replacing inherited values with their workspace counterpart. This is also what a forthcoming Cargo release will do for `cargo vendor` [1], but we can get ahead of it ;) [0]: https://blog.rust-lang.org/2022/09/22/Rust-1.64.0.html#cargo-improvements-workspace-inheritance-and-multi-target-builds [1]: https://github.com/rust-lang/cargo/pull/11414
This commit is contained in:
parent
7c7d4f615f
commit
5686f0064d
@ -1,4 +1,4 @@
|
||||
{ fetchgit, fetchurl, lib, runCommand, cargo, jq }:
|
||||
{ fetchgit, fetchurl, lib, writers, python3Packages, runCommand, cargo, jq }:
|
||||
|
||||
{
|
||||
# Cargo lock file
|
||||
@ -93,6 +93,11 @@ let
|
||||
sha256 = checksum;
|
||||
};
|
||||
|
||||
# Replaces values inherited by workspace members.
|
||||
replaceWorkspaceValues = writers.writePython3 "replace-workspace-values"
|
||||
{ libraries = with python3Packages; [ tomli tomli-w ]; flakeIgnore = [ "E501" ]; }
|
||||
(builtins.readFile ./replace-workspace-values.py);
|
||||
|
||||
# Fetch and unpack a crate.
|
||||
mkCrate = pkg:
|
||||
let
|
||||
@ -171,6 +176,11 @@ let
|
||||
cp -prvd "$tree/" $out
|
||||
chmod u+w $out
|
||||
|
||||
if grep -q workspace "$out/Cargo.toml"; then
|
||||
chmod u+w "$out/Cargo.toml"
|
||||
${replaceWorkspaceValues} "$out/Cargo.toml" "${tree}/Cargo.toml"
|
||||
fi
|
||||
|
||||
# Cargo is happy with empty metadata.
|
||||
printf '{"files":{},"package":null}' > "$out/.cargo-checksum.json"
|
||||
|
||||
|
95
pkgs/build-support/rust/replace-workspace-values.py
Normal file
95
pkgs/build-support/rust/replace-workspace-values.py
Normal file
@ -0,0 +1,95 @@
|
||||
# This script implements the workspace inheritance mechanism described
|
||||
# here: https://doc.rust-lang.org/cargo/reference/workspaces.html#the-package-table
|
||||
#
|
||||
# Please run `mypy --strict`, `black`, and `isort --profile black` on this after editing, thanks!
|
||||
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
import tomli
|
||||
import tomli_w
|
||||
|
||||
|
||||
def load_file(path: str) -> dict[str, Any]:
|
||||
with open(path, "rb") as f:
|
||||
return tomli.load(f)
|
||||
|
||||
|
||||
def replace_key(
|
||||
workspace_manifest: dict[str, Any], table: dict[str, Any], section: str, key: str
|
||||
) -> bool:
|
||||
if "workspace" in table[key] and table[key]["workspace"] is True:
|
||||
print("replacing " + key)
|
||||
|
||||
replaced = table[key]
|
||||
del replaced["workspace"]
|
||||
|
||||
workspace_copy = workspace_manifest[section][key]
|
||||
|
||||
if section == "dependencies":
|
||||
crate_features = replaced.get("features")
|
||||
|
||||
if type(workspace_copy) is str:
|
||||
replaced["version"] = workspace_copy
|
||||
else:
|
||||
replaced.update(workspace_copy)
|
||||
|
||||
merged_features = (crate_features or []) + (
|
||||
workspace_copy.get("features") or []
|
||||
)
|
||||
|
||||
if len(merged_features) > 0:
|
||||
# Dictionaries are guaranteed to be ordered (https://stackoverflow.com/a/7961425)
|
||||
replaced["features"] = list(dict.fromkeys(merged_features))
|
||||
elif section == "package":
|
||||
table[key] = replaced = workspace_copy
|
||||
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def replace_dependencies(
|
||||
workspace_manifest: dict[str, Any], root: dict[str, Any]
|
||||
) -> bool:
|
||||
changed = False
|
||||
|
||||
for key in ["dependencies", "dev-dependencies", "build-dependencies"]:
|
||||
if key in root:
|
||||
for k in root[key].keys():
|
||||
changed |= replace_key(workspace_manifest, root[key], "dependencies", k)
|
||||
|
||||
return changed
|
||||
|
||||
|
||||
def main() -> None:
|
||||
crate_manifest = load_file(sys.argv[1])
|
||||
workspace_manifest = load_file(sys.argv[2])["workspace"]
|
||||
|
||||
if "workspace" in crate_manifest:
|
||||
return
|
||||
|
||||
changed = False
|
||||
|
||||
for key in crate_manifest["package"].keys():
|
||||
changed |= replace_key(
|
||||
workspace_manifest, crate_manifest["package"], "package", key
|
||||
)
|
||||
|
||||
changed |= replace_dependencies(workspace_manifest, crate_manifest)
|
||||
|
||||
if "target" in crate_manifest:
|
||||
for key in crate_manifest["target"].keys():
|
||||
changed |= replace_dependencies(
|
||||
workspace_manifest, crate_manifest["target"][key]
|
||||
)
|
||||
|
||||
if not changed:
|
||||
return
|
||||
|
||||
with open(sys.argv[1], "wb") as f:
|
||||
tomli_w.dump(crate_manifest, f)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,4 +1,4 @@
|
||||
{ callPackage }:
|
||||
{ callPackage, writers, python3Packages }:
|
||||
|
||||
# Build like this from nixpkgs root:
|
||||
# $ nix-build -A tests.importCargoLock
|
||||
@ -12,4 +12,9 @@
|
||||
gitDependencyBranch = callPackage ./git-dependency-branch { };
|
||||
maturin = callPackage ./maturin { };
|
||||
v1 = callPackage ./v1 { };
|
||||
gitDependencyWorkspaceInheritance = callPackage ./git-dependency-workspace-inheritance {
|
||||
replaceWorkspaceValues = writers.writePython3 "replace-workspace-values"
|
||||
{ libraries = with python3Packages; [ tomli tomli-w ]; flakeIgnore = [ "E501" ]; }
|
||||
(builtins.readFile ../../replace-workspace-values.py);
|
||||
};
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
[package]
|
||||
version = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
foo = { workspace = true, features = ["cat"] }
|
||||
bar = "1.0.0"
|
@ -0,0 +1,7 @@
|
||||
{ replaceWorkspaceValues, runCommand }:
|
||||
|
||||
runCommand "git-dependency-workspace-inheritance-test" { } ''
|
||||
cp --no-preserve=mode ${./crate.toml} "$out"
|
||||
${replaceWorkspaceValues} "$out" ${./workspace.toml}
|
||||
diff -u "$out" ${./want.toml}
|
||||
''
|
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
version = "1.0.0"
|
||||
|
||||
[dependencies]
|
||||
bar = "1.0.0"
|
||||
|
||||
[dependencies.foo]
|
||||
features = [
|
||||
"cat",
|
||||
"meow",
|
||||
]
|
||||
version = "1.0.0"
|
@ -0,0 +1,5 @@
|
||||
[workspace.package]
|
||||
version = "1.0.0"
|
||||
|
||||
[workspace.dependencies]
|
||||
foo = { version = "1.0.0", features = ["meow"] }
|
Loading…
Reference in New Issue
Block a user