aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/build/drv-output-substitution-goal.cc
blob: 1703e845d9dc3a28e5bc48f829246372b3a626d8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include "drv-output-substitution-goal.hh"
#include "worker.hh"
#include "substitution-goal.hh"

namespace nix {

DrvOutputSubstitutionGoal::DrvOutputSubstitutionGoal(const DrvOutput& id, Worker & worker, RepairFlag repair, std::optional<ContentAddress> ca)
    : Goal(worker)
    , id(id)
{
    state = &DrvOutputSubstitutionGoal::init;
    name = fmt("substitution of '%s'", id.to_string());
    trace("created");
}


void DrvOutputSubstitutionGoal::init()
{
    trace("init");
    subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>();
    tryNext();
}

void DrvOutputSubstitutionGoal::tryNext()
{
    trace("Trying next substituter");

    if (subs.size() == 0) {
        /* None left.  Terminate this goal and let someone else deal
           with it. */
        debug("drv output '%s' is required, but there is no substituter that can provide it", id.to_string());

        /* Hack: don't indicate failure if there were no substituters.
           In that case the calling derivation should just do a
           build. */
        amDone(substituterFailed ? ecFailed : ecNoSubstituters);

        if (substituterFailed) {
            worker.failedSubstitutions++;
            worker.updateProgress();
        }

        return;
    }

    auto sub = subs.front();
    subs.pop_front();

    // FIXME: Make async
    outputInfo = sub->queryRealisation(id);
    if (!outputInfo) {
        tryNext();
        return;
    }

    for (const auto & [drvOutputDep, _] : outputInfo->dependentRealisations) {
        if (drvOutputDep != id) {
            addWaitee(worker.makeDrvOutputSubstitutionGoal(drvOutputDep));
        }
    }

    addWaitee(worker.makePathSubstitutionGoal(outputInfo->outPath));

    if (waitees.empty()) outPathValid();
    else state = &DrvOutputSubstitutionGoal::outPathValid;
}

void DrvOutputSubstitutionGoal::outPathValid()
{
    assert(outputInfo);
    trace("Output path substituted");

    if (nrFailed > 0) {
        debug("The output path of the derivation output '%s' could not be substituted", id.to_string());
        amDone(nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed);
        return;
    }

    worker.store.registerDrvOutput(*outputInfo);
    finished();
}

void DrvOutputSubstitutionGoal::finished()
{
    trace("finished");
    amDone(ecSuccess);
}

string DrvOutputSubstitutionGoal::key()
{
    /* "a$" ensures substitution goals happen before derivation
       goals. */
    return "a$" + std::string(id.to_string());
}

void DrvOutputSubstitutionGoal::work()
{
    (this->*state)();
}

}