aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr
diff options
context:
space:
mode:
authoreldritch horrors <pennae@lix.systems>2024-03-08 13:56:43 +0100
committereldritch horrors <pennae@lix.systems>2024-03-10 03:18:32 -0600
commit71e0114708d406fdc0d9ca34d4b67cb190881439 (patch)
tree62ae7bc26eaf210794ed5e4a906caebd17856354 /src/libexpr
parent2a84123631c2a86df54326f9025660b4684f95bf (diff)
remove getDerivations deduplication
deduplication does not currently work fully, showing derivations multiple times if they have different underlying values. this can happen by selecting the same derivation twice for two different attributes of a set, using inherit-from (which reduces to the previous), importing nixpkgs twice, or any other number of things. since users already have to deal with duplicates for this reason it won't hurt to add *more* duplicates. the alternative would be to deduplicate fully, which would drop derivations that are currently returned and those pose a regression risk. Change-Id: I64b397351237e10375d270f1bddecb71f62aa131
Diffstat (limited to 'src/libexpr')
-rw-r--r--src/libexpr/get-drvs.cc28
1 files changed, 15 insertions, 13 deletions
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<Bindings *> 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<DrvInfo> 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);
}
}