@@ -309,6 +309,18 @@ Goal::Co DerivationGoal::haveDerivation()
309
309
}
310
310
311
311
312
+ /* *
313
+ * Used for `inputGoals` local variable below
314
+ */
315
+ struct value_comparison
316
+ {
317
+ template <typename T>
318
+ bool operator ()(const ref<T> & lhs, const ref<T> & rhs) const {
319
+ return *lhs < *rhs;
320
+ }
321
+ };
322
+
323
+
312
324
/* At least one of the output paths could not be
313
325
produced using a substitute. So we have to build instead. */
314
326
Goal::Co DerivationGoal::gaveUpOnSubstitution ()
@@ -317,19 +329,22 @@ Goal::Co DerivationGoal::gaveUpOnSubstitution()
317
329
is no need to restart. */
318
330
needRestart = NeedRestartForMoreOutputs::BuildInProgressWillNotNeed;
319
331
320
- /* The inputs must be built before we can build this goal. */
321
- inputDrvOutputs. clear ();
332
+ std::map<ref< const SingleDerivedPath>, GoalPtr, value_comparison> inputGoals;
333
+
322
334
if (useDerivation) {
323
- std::function<void (ref<SingleDerivedPath>, const DerivedPathMap<StringSet>::ChildNode &)> addWaiteeDerivedPath;
335
+ std::function<void (ref<const SingleDerivedPath>, const DerivedPathMap<StringSet>::ChildNode &)> addWaiteeDerivedPath;
324
336
325
- addWaiteeDerivedPath = [&](ref<SingleDerivedPath> inputDrv, const DerivedPathMap<StringSet>::ChildNode & inputNode) {
326
- if (!inputNode.value .empty ())
327
- addWaitee ( worker.makeGoal (
337
+ addWaiteeDerivedPath = [&](ref<const SingleDerivedPath> inputDrv, const DerivedPathMap<StringSet>::ChildNode & inputNode) {
338
+ if (!inputNode.value .empty ()) {
339
+ auto g = worker.makeGoal (
328
340
DerivedPath::Built {
329
341
.drvPath = inputDrv,
330
342
.outputs = inputNode.value ,
331
343
},
332
- buildMode == bmRepair ? bmRepair : bmNormal));
344
+ buildMode == bmRepair ? bmRepair : bmNormal);
345
+ inputGoals.insert_or_assign (inputDrv, g);
346
+ addWaitee (std::move (g));
347
+ }
333
348
for (const auto & [outputName, childNode] : inputNode.childMap )
334
349
addWaiteeDerivedPath (
335
350
make_ref<SingleDerivedPath>(SingleDerivedPath::Built { inputDrv, outputName }),
@@ -417,15 +432,32 @@ Goal::Co DerivationGoal::gaveUpOnSubstitution()
417
432
[&](const DerivationType::Impure &) {
418
433
return true ;
419
434
}
420
- }, drvType.raw );
435
+ }, drvType.raw )
436
+ /* no inputs are outputs of dynamic derivations */
437
+ || std::ranges::any_of (
438
+ fullDrv.inputDrvs .map .begin (),
439
+ fullDrv.inputDrvs .map .end (),
440
+ [](auto & pair) { return !pair.second .childMap .empty (); });
421
441
422
442
if (resolveDrv && !fullDrv.inputDrvs .map .empty ()) {
423
443
experimentalFeatureSettings.require (Xp::CaDerivations);
424
444
425
445
/* We are be able to resolve this derivation based on the
426
446
now-known results of dependencies. If so, we become a
427
447
stub goal aliasing that resolved derivation goal. */
428
- std::optional attempt = fullDrv.tryResolve (worker.store , inputDrvOutputs);
448
+ std::optional attempt = fullDrv.tryResolve (worker.store ,
449
+ [&](ref<const SingleDerivedPath> drvPath, const std::string & outputName) -> std::optional<StorePath> {
450
+ auto mEntry = get (inputGoals, drvPath);
451
+ if (!mEntry ) return std::nullopt;
452
+
453
+ auto buildResult = (*mEntry )->getBuildResult (DerivedPath::Built{drvPath, OutputsSpec::Names{outputName}});
454
+ if (!buildResult.success ()) return std::nullopt;
455
+
456
+ auto i = get (buildResult.builtOutputs , outputName);
457
+ if (!i) return std::nullopt;
458
+
459
+ return i->outPath ;
460
+ });
429
461
if (!attempt) {
430
462
/* TODO (impure derivations-induced tech debt) (see below):
431
463
The above attempt should have found it, but because we manage
@@ -456,54 +488,31 @@ Goal::Co DerivationGoal::gaveUpOnSubstitution()
456
488
co_return resolvedFinished ();
457
489
}
458
490
459
- std::function< void ( const StorePath &, const DerivedPathMap<StringSet>::ChildNode &)> accumInputPaths;
460
-
461
- accumInputPaths = [&]( const StorePath & depDrvPath, const DerivedPathMap<StringSet>::ChildNode & inputNode ) {
462
- /* Add the relevant output closures of the input derivation
463
- `i' as input paths. Only add the closures of output paths
464
- that are specified as inputs. */
465
- auto getOutput = [&]( const std::string & outputName) {
466
- /* TODO (impure derivations-induced tech debt):
467
- Tracking input derivation outputs statefully through the
468
- goals is error prone and has led to bugs.
469
- For a robust nix, we need to move towards the `else` branch,
470
- which does not rely on goal state to match up with the
471
- reality of the store, which is our real source of truth.
472
- However, the impure derivations feature still relies on this
473
- fragile way of doing things, because its builds do not have
474
- a representation in the store, which is a usability problem
475
- in itself. When implementing this logic entirely with lookups
476
- make sure that they're cached. */
477
- if ( auto outPath = get (inputDrvOutputs, { depDrvPath, outputName })) {
478
- return *outPath ;
491
+ /* If we get this far, we know no dynamic drvs inputs */
492
+
493
+ for ( auto & [ depDrvPath, depNode] : fullDrv. inputDrvs . map ) {
494
+ for ( auto & outputName : depNode. value ) {
495
+ /* Don't need to worry about `inputGoals`, because
496
+ impure derivations are always resolved above. Can
497
+ just use DB. This case only happens in the (older)
498
+ input addressed and fixed output derivation cases. */
499
+ auto outMap = [&]{
500
+ for ( auto * drvStore : { &worker. evalStore , &worker. store })
501
+ if (drvStore-> isValidPath (depDrvPath))
502
+ return worker. store . queryDerivationOutputMap (depDrvPath, drvStore);
503
+ assert ( false );
504
+ }();
505
+
506
+ auto outMapPath = outMap. find (outputName);
507
+ if (outMapPath == outMap. end ()) {
508
+ throw Error (
509
+ " derivation '%s' requires non-existent output '%s' from input derivation '%s' " ,
510
+ worker. store . printStorePath (drvPath), outputName, worker. store . printStorePath (depDrvPath)) ;
479
511
}
480
- else {
481
- auto outMap = [&]{
482
- for (auto * drvStore : { &worker.evalStore , &worker.store })
483
- if (drvStore->isValidPath (depDrvPath))
484
- return worker.store .queryDerivationOutputMap (depDrvPath, drvStore);
485
- assert (false );
486
- }();
487
-
488
- auto outMapPath = outMap.find (outputName);
489
- if (outMapPath == outMap.end ()) {
490
- throw Error (
491
- " derivation '%s' requires non-existent output '%s' from input derivation '%s'" ,
492
- worker.store .printStorePath (drvPath), outputName, worker.store .printStorePath (depDrvPath));
493
- }
494
- return outMapPath->second ;
495
- }
496
- };
497
512
498
- for (auto & outputName : inputNode.value )
499
- worker.store .computeFSClosure (getOutput (outputName), inputPaths);
500
-
501
- for (auto & [outputName, childNode] : inputNode.childMap )
502
- accumInputPaths (getOutput (outputName), childNode);
503
- };
504
-
505
- for (auto & [depDrvPath, depNode] : fullDrv.inputDrvs .map )
506
- accumInputPaths (depDrvPath, depNode);
513
+ worker.store .computeFSClosure (outMapPath->second , inputPaths);
514
+ }
515
+ }
507
516
}
508
517
509
518
/* Second, the input sources. */
@@ -1532,35 +1541,4 @@ Goal::Done DerivationGoal::done(
1532
1541
return amDone (buildResult.success () ? ecSuccess : ecFailed, std::move (ex));
1533
1542
}
1534
1543
1535
-
1536
- void DerivationGoal::waiteeDone (GoalPtr waitee, ExitCode result)
1537
- {
1538
- Goal::waiteeDone (waitee, result);
1539
-
1540
- if (!useDerivation || !drv) return ;
1541
- auto & fullDrv = *dynamic_cast <Derivation *>(drv.get ());
1542
-
1543
- std::optional info = tryGetConcreteDrvGoal (waitee);
1544
- if (!info) return ;
1545
- const auto & [dg, drvReq] = *info;
1546
-
1547
- auto * nodeP = fullDrv.inputDrvs .findSlot (drvReq.get ());
1548
- if (!nodeP) return ;
1549
- auto & outputs = nodeP->value ;
1550
-
1551
- for (auto & outputName : outputs) {
1552
- auto buildResult = dg.get ().getBuildResult (DerivedPath::Built {
1553
- .drvPath = makeConstantStorePathRef (dg.get ().drvPath ),
1554
- .outputs = OutputsSpec::Names { outputName },
1555
- });
1556
- if (buildResult.success ()) {
1557
- auto i = buildResult.builtOutputs .find (outputName);
1558
- if (i != buildResult.builtOutputs .end ())
1559
- inputDrvOutputs.insert_or_assign (
1560
- { dg.get ().drvPath , outputName },
1561
- i->second .outPath );
1562
- }
1563
- }
1564
- }
1565
-
1566
1544
}
0 commit comments