diff options
Diffstat (limited to 'pkgs/rust/lib/crate2nix-package.nix')
| -rw-r--r-- | pkgs/rust/lib/crate2nix-package.nix | 34 |
1 files changed, 31 insertions, 3 deletions
diff --git a/pkgs/rust/lib/crate2nix-package.nix b/pkgs/rust/lib/crate2nix-package.nix index ee75096..9b16b15 100644 --- a/pkgs/rust/lib/crate2nix-package.nix +++ b/pkgs/rust/lib/crate2nix-package.nix @@ -24,12 +24,15 @@ # attrs or (args -> attrs), for every workspace member , workspaceOverride ? {} -# IFD only; Cargo.json has its features baked in +# Root features. A JSON plan has its features baked in; cargoToml checks them. , features ? [ "default" ] # Cargo.lock the JSON plan must match; null: no check , cargoLock ? null +# Cargo.toml to check the plan's root features; null: no check +, cargoToml ? null + , resolvedJson ? null }: @@ -71,6 +74,31 @@ let inherit buildRustCrateForPkgs; }; + plan = builtins.fromJSON (builtins.readFile resolvedJson'); + + # Fails evaluation if the plan's root crate wasn't resolved with features: + # its declared features must be exactly those reachable from features + # through Cargo.toml's [features], and features not declared there (implicit + # features of optional dependencies) must be present. + checkFeatures = result: + let + declared = (builtins.fromTOML (builtins.readFile cargoToml)).features or { }; + resolved = plan.crates.${plan.root}.resolvedDefaultFeatures or [ ]; + # default is always valid, even when Cargo.toml doesn't declare it. + requested = builtins.filter (f: f != "default" || declared ? default) features; + expected = map (x: x.key) (builtins.genericClosure { + startSet = map (key: { inherit key; }) (builtins.filter (f: declared ? ${f}) requested); + operator = x: map (key: { inherit key; }) (builtins.filter (f: declared ? ${f}) declared.${x.key}); + }); + actual = builtins.filter (f: declared ? ${f}) resolved; + extra = lib.subtractLists expected actual; + missing = lib.unique (lib.subtractLists actual expected + ++ builtins.filter (f: !(declared ? ${f}) && !(builtins.elem f resolved)) requested); + show = l: "[ ${lib.concatStringsSep " " l} ]"; + in + if cargoToml == null || plan.root or null == null || extra == [ ] && missing == [ ] then result + else throw "crate2nix-package: ${toString resolvedJson'} was generated with other features than ${show features}${lib.optionalString (missing != [ ]) "; missing ${show missing}"}${lib.optionalString (extra != [ ]) "; extra ${show extra}"}"; + # Fails evaluation if the plan uses a crate version the lock doesn't have, # i.e. Cargo.lock changed since Cargo.json was generated. Dependencies added # to the lock aren't detected, since the plan may leave out crates for @@ -84,13 +112,13 @@ let (builtins.filter (p: p ? source) lockPackages)); planned = lib.mapAttrsToList (_: c: id c.crateName c.version) (lib.filterAttrs (_: c: (c.source.type or "local") != "local") - (builtins.fromJSON (builtins.readFile resolvedJson')).crates); + plan.crates); missing = builtins.filter (i: !(locked ? ${i})) planned; in if cargoLock == null || missing == [] then result else throw "crate2nix-package: ${toString resolvedJson'} is stale against ${toString cargoLock}; not in the lock: ${lib.concatStringsSep ", " (lib.take 5 missing)}${lib.optionalString (builtins.length missing > 5) ", ..."}"; - cargoNix = if useJson then checkLock fromJson else fromLock; + cargoNix = if useJson then checkFeatures (checkLock fromJson) else fromLock; in cargoNix // { build = |
