diff --git a/flake.nix b/flake.nix index d9e16881f..3e5023cb6 100644 --- a/flake.nix +++ b/flake.nix @@ -552,7 +552,7 @@ type -p nix-env # Note: we're filtering out nixos-install-tools because https://github.com/NixOS/nixpkgs/pull/153594#issuecomment-1020530593. time nix-env --store dummy:// -f ${nixpkgs-regression} -qaP --drv-path | sort | grep -v nixos-install-tools > packages - [[ $(sha1sum < packages | cut -c1-40) = ff451c521e61e4fe72bdbe2d0ca5d1809affa733 ]] + [[ $(sha1sum < packages | cut -c1-40) = 402242fca90874112b34718b8199d844e8b03d12 ]] mkdir $out ''; diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 495407c39..e686ffe8c 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -296,22 +296,16 @@ void DrvInfo::setMeta(const std::string & name, Value * v) typedef std::set Done; -/* Evaluate value `v'. If it evaluates to a set of type `derivation', - then put information about it in `drvs' (unless it's already in `done'). - The result boolean indicates whether it makes sense +/* The result boolean indicates whether it makes sense for the caller to recursively search for derivations in `v'. */ static bool getDerivation(EvalState & state, Value & v, - const std::string & attrPath, DrvInfos & drvs, Done & done, + const std::string & attrPath, DrvInfos & drvs, bool ignoreAssertionFailures) { try { state.forceValue(v, v.determinePos(noPos)); if (!state.isDerivation(v)) return true; - /* Remove spurious duplicates (e.g., a set like `rec { x = - derivation {...}; y = x;}'. */ - if (!done.insert(v.attrs).second) return false; - DrvInfo drv(state, attrPath, v.attrs); drv.queryName(); @@ -330,9 +324,8 @@ static bool getDerivation(EvalState & state, Value & v, std::optional getDerivation(EvalState & state, Value & v, bool ignoreAssertionFailures) { - Done done; DrvInfos drvs; - getDerivation(state, v, "", drvs, done, ignoreAssertionFailures); + getDerivation(state, v, "", drvs, ignoreAssertionFailures); if (drvs.size() != 1) return {}; return std::move(drvs.front()); } @@ -347,6 +340,9 @@ static std::string addToPath(const std::string & s1, const std::string & s2) static std::regex attrRegex("[A-Za-z_][A-Za-z0-9-_+]*"); +/* Evaluate value `v'. If it evaluates to a set of type `derivation', + then put information about it in `drvs'. If it evaluates to a different + kind of set recurse (unless it's already in `done'). */ static void getDerivations(EvalState & state, Value & vIn, const std::string & pathPrefix, Bindings & autoArgs, DrvInfos & drvs, Done & done, @@ -356,10 +352,14 @@ static void getDerivations(EvalState & state, Value & vIn, state.autoCallFunction(autoArgs, vIn, v); /* Process the expression. */ - if (!getDerivation(state, v, pathPrefix, drvs, done, ignoreAssertionFailures)) ; + if (!getDerivation(state, v, pathPrefix, drvs, ignoreAssertionFailures)) ; else if (v.type() == nAttrs) { + /* Dont consider sets we've already seen, e.g. y in + `rec { x.d = derivation {...}; y = x; }`. */ + if (!done.insert(v.attrs).second) return; + /* !!! undocumented hackery to support combining channels in nix-env.cc. */ bool combineChannels = v.attrs->find(state.symbols.create("_combineChannels")) != v.attrs->end(); @@ -376,7 +376,7 @@ static void getDerivations(EvalState & state, Value & vIn, std::string pathPrefix2 = addToPath(pathPrefix, state.symbols[i->name]); if (combineChannels) getDerivations(state, *i->value, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures); - else if (getDerivation(state, *i->value, pathPrefix2, drvs, done, ignoreAssertionFailures)) { + else if (getDerivation(state, *i->value, pathPrefix2, drvs, ignoreAssertionFailures)) { /* If the value of this attribute is itself a set, should we recurse into it? => Only if it has a `recurseForDerivations = true' attribute. */ @@ -390,9 +390,11 @@ static void getDerivations(EvalState & state, Value & vIn, } else if (v.type() == nList) { + // NOTE we can't really deduplicate here because small lists don't have stable addresses + // and can cause spurious duplicate detections due to v being on the stack. for (auto [n, elem] : enumerate(v.listItems())) { std::string pathPrefix2 = addToPath(pathPrefix, fmt("%d", n)); - if (getDerivation(state, *elem, pathPrefix2, drvs, done, ignoreAssertionFailures)) + if (getDerivation(state, *elem, pathPrefix2, drvs, ignoreAssertionFailures)) getDerivations(state, *elem, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures); } }