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