mirror of
https://github.com/NixOS/nix
synced 2025-07-02 05:11:47 +02:00
Merge remote-tracking branch 'origin/master' into lfs
This commit is contained in:
commit
1cb9a354fb
61 changed files with 921 additions and 478 deletions
|
@ -36,14 +36,6 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
Goal::Co DerivationGoal::init() {
|
||||
if (useDerivation) {
|
||||
co_return getDerivation();
|
||||
} else {
|
||||
co_return haveDerivation();
|
||||
}
|
||||
}
|
||||
|
||||
DerivationGoal::DerivationGoal(const StorePath & drvPath,
|
||||
const OutputsSpec & wantedOutputs, Worker & worker, BuildMode buildMode)
|
||||
: Goal(worker, DerivedPath::Built { .drvPath = makeConstantStorePathRef(drvPath), .outputs = wantedOutputs })
|
||||
|
@ -141,50 +133,44 @@ void DerivationGoal::addWantedOutputs(const OutputsSpec & outputs)
|
|||
}
|
||||
|
||||
|
||||
Goal::Co DerivationGoal::getDerivation()
|
||||
{
|
||||
Goal::Co DerivationGoal::init() {
|
||||
trace("init");
|
||||
|
||||
/* The first thing to do is to make sure that the derivation
|
||||
exists. If it doesn't, it may be created through a
|
||||
substitute. */
|
||||
if (buildMode == bmNormal && worker.evalStore.isValidPath(drvPath)) {
|
||||
co_return loadDerivation();
|
||||
}
|
||||
if (useDerivation) {
|
||||
/* The first thing to do is to make sure that the derivation
|
||||
exists. If it doesn't, it may be created through a
|
||||
substitute. */
|
||||
|
||||
addWaitee(upcast_goal(worker.makePathSubstitutionGoal(drvPath)));
|
||||
|
||||
co_await Suspend{};
|
||||
co_return loadDerivation();
|
||||
}
|
||||
|
||||
|
||||
Goal::Co DerivationGoal::loadDerivation()
|
||||
{
|
||||
trace("loading derivation");
|
||||
|
||||
if (nrFailed != 0) {
|
||||
co_return done(BuildResult::MiscFailure, {}, Error("cannot build missing derivation '%s'", worker.store.printStorePath(drvPath)));
|
||||
}
|
||||
|
||||
/* `drvPath' should already be a root, but let's be on the safe
|
||||
side: if the user forgot to make it a root, we wouldn't want
|
||||
things being garbage collected while we're busy. */
|
||||
worker.evalStore.addTempRoot(drvPath);
|
||||
|
||||
/* Get the derivation. It is probably in the eval store, but it might be inthe main store:
|
||||
|
||||
- Resolved derivation are resolved against main store realisations, and so must be stored there.
|
||||
|
||||
- Dynamic derivations are built, and so are found in the main store.
|
||||
*/
|
||||
for (auto * drvStore : { &worker.evalStore, &worker.store }) {
|
||||
if (drvStore->isValidPath(drvPath)) {
|
||||
drv = std::make_unique<Derivation>(drvStore->readDerivation(drvPath));
|
||||
break;
|
||||
if (buildMode != bmNormal || !worker.evalStore.isValidPath(drvPath)) {
|
||||
addWaitee(upcast_goal(worker.makePathSubstitutionGoal(drvPath)));
|
||||
co_await Suspend{};
|
||||
}
|
||||
|
||||
trace("loading derivation");
|
||||
|
||||
if (nrFailed != 0) {
|
||||
co_return done(BuildResult::MiscFailure, {}, Error("cannot build missing derivation '%s'", worker.store.printStorePath(drvPath)));
|
||||
}
|
||||
|
||||
/* `drvPath' should already be a root, but let's be on the safe
|
||||
side: if the user forgot to make it a root, we wouldn't want
|
||||
things being garbage collected while we're busy. */
|
||||
worker.evalStore.addTempRoot(drvPath);
|
||||
|
||||
/* Get the derivation. It is probably in the eval store, but it might be inthe main store:
|
||||
|
||||
- Resolved derivation are resolved against main store realisations, and so must be stored there.
|
||||
|
||||
- Dynamic derivations are built, and so are found in the main store.
|
||||
*/
|
||||
for (auto * drvStore : { &worker.evalStore, &worker.store }) {
|
||||
if (drvStore->isValidPath(drvPath)) {
|
||||
drv = std::make_unique<Derivation>(drvStore->readDerivation(drvPath));
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(drv);
|
||||
}
|
||||
assert(drv);
|
||||
|
||||
co_return haveDerivation();
|
||||
}
|
||||
|
@ -235,12 +221,14 @@ Goal::Co DerivationGoal::haveDerivation()
|
|||
}
|
||||
});
|
||||
|
||||
/* Check what outputs paths are not already valid. */
|
||||
auto [allValid, validOutputs] = checkPathValidity();
|
||||
{
|
||||
/* Check what outputs paths are not already valid. */
|
||||
auto [allValid, validOutputs] = checkPathValidity();
|
||||
|
||||
/* If they are all valid, then we're done. */
|
||||
if (allValid && buildMode == bmNormal) {
|
||||
co_return done(BuildResult::AlreadyValid, std::move(validOutputs));
|
||||
/* If they are all valid, then we're done. */
|
||||
if (allValid && buildMode == bmNormal) {
|
||||
co_return done(BuildResult::AlreadyValid, std::move(validOutputs));
|
||||
}
|
||||
}
|
||||
|
||||
/* We are first going to try to create the invalid output paths
|
||||
|
@ -268,12 +256,7 @@ Goal::Co DerivationGoal::haveDerivation()
|
|||
}
|
||||
|
||||
if (!waitees.empty()) co_await Suspend{}; /* to prevent hang (no wake-up event) */
|
||||
co_return outputsSubstitutionTried();
|
||||
}
|
||||
|
||||
|
||||
Goal::Co DerivationGoal::outputsSubstitutionTried()
|
||||
{
|
||||
trace("all outputs substituted (maybe)");
|
||||
|
||||
assert(!drv->type().isImpure());
|
||||
|
@ -399,84 +382,7 @@ Goal::Co DerivationGoal::gaveUpOnSubstitution()
|
|||
}
|
||||
|
||||
if (!waitees.empty()) co_await Suspend{}; /* to prevent hang (no wake-up event) */
|
||||
co_return inputsRealised();
|
||||
}
|
||||
|
||||
|
||||
Goal::Co DerivationGoal::repairClosure()
|
||||
{
|
||||
assert(!drv->type().isImpure());
|
||||
|
||||
/* If we're repairing, we now know that our own outputs are valid.
|
||||
Now check whether the other paths in the outputs closure are
|
||||
good. If not, then start derivation goals for the derivations
|
||||
that produced those outputs. */
|
||||
|
||||
/* Get the output closure. */
|
||||
auto outputs = queryDerivationOutputMap();
|
||||
StorePathSet outputClosure;
|
||||
for (auto & i : outputs) {
|
||||
if (!wantedOutputs.contains(i.first)) continue;
|
||||
worker.store.computeFSClosure(i.second, outputClosure);
|
||||
}
|
||||
|
||||
/* Filter out our own outputs (which we have already checked). */
|
||||
for (auto & i : outputs)
|
||||
outputClosure.erase(i.second);
|
||||
|
||||
/* Get all dependencies of this derivation so that we know which
|
||||
derivation is responsible for which path in the output
|
||||
closure. */
|
||||
StorePathSet inputClosure;
|
||||
if (useDerivation) worker.store.computeFSClosure(drvPath, inputClosure);
|
||||
std::map<StorePath, StorePath> outputsToDrv;
|
||||
for (auto & i : inputClosure)
|
||||
if (i.isDerivation()) {
|
||||
auto depOutputs = worker.store.queryPartialDerivationOutputMap(i, &worker.evalStore);
|
||||
for (auto & j : depOutputs)
|
||||
if (j.second)
|
||||
outputsToDrv.insert_or_assign(*j.second, i);
|
||||
}
|
||||
|
||||
/* Check each path (slow!). */
|
||||
for (auto & i : outputClosure) {
|
||||
if (worker.pathContentsGood(i)) continue;
|
||||
printError(
|
||||
"found corrupted or missing path '%s' in the output closure of '%s'",
|
||||
worker.store.printStorePath(i), worker.store.printStorePath(drvPath));
|
||||
auto drvPath2 = outputsToDrv.find(i);
|
||||
if (drvPath2 == outputsToDrv.end())
|
||||
addWaitee(upcast_goal(worker.makePathSubstitutionGoal(i, Repair)));
|
||||
else
|
||||
addWaitee(worker.makeGoal(
|
||||
DerivedPath::Built {
|
||||
.drvPath = makeConstantStorePathRef(drvPath2->second),
|
||||
.outputs = OutputsSpec::All { },
|
||||
},
|
||||
bmRepair));
|
||||
}
|
||||
|
||||
if (waitees.empty()) {
|
||||
co_return done(BuildResult::AlreadyValid, assertPathValidity());
|
||||
} else {
|
||||
co_await Suspend{};
|
||||
co_return closureRepaired();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Goal::Co DerivationGoal::closureRepaired()
|
||||
{
|
||||
trace("closure repaired");
|
||||
if (nrFailed > 0)
|
||||
throw Error("some paths in the output closure of derivation '%s' could not be repaired",
|
||||
worker.store.printStorePath(drvPath));
|
||||
co_return done(BuildResult::AlreadyValid, assertPathValidity());
|
||||
}
|
||||
|
||||
|
||||
Goal::Co DerivationGoal::inputsRealised()
|
||||
{
|
||||
trace("all inputs realised");
|
||||
|
||||
if (nrFailed != 0) {
|
||||
|
@ -766,6 +672,73 @@ Goal::Co DerivationGoal::tryLocalBuild() {
|
|||
}
|
||||
|
||||
|
||||
Goal::Co DerivationGoal::repairClosure()
|
||||
{
|
||||
assert(!drv->type().isImpure());
|
||||
|
||||
/* If we're repairing, we now know that our own outputs are valid.
|
||||
Now check whether the other paths in the outputs closure are
|
||||
good. If not, then start derivation goals for the derivations
|
||||
that produced those outputs. */
|
||||
|
||||
/* Get the output closure. */
|
||||
auto outputs = queryDerivationOutputMap();
|
||||
StorePathSet outputClosure;
|
||||
for (auto & i : outputs) {
|
||||
if (!wantedOutputs.contains(i.first)) continue;
|
||||
worker.store.computeFSClosure(i.second, outputClosure);
|
||||
}
|
||||
|
||||
/* Filter out our own outputs (which we have already checked). */
|
||||
for (auto & i : outputs)
|
||||
outputClosure.erase(i.second);
|
||||
|
||||
/* Get all dependencies of this derivation so that we know which
|
||||
derivation is responsible for which path in the output
|
||||
closure. */
|
||||
StorePathSet inputClosure;
|
||||
if (useDerivation) worker.store.computeFSClosure(drvPath, inputClosure);
|
||||
std::map<StorePath, StorePath> outputsToDrv;
|
||||
for (auto & i : inputClosure)
|
||||
if (i.isDerivation()) {
|
||||
auto depOutputs = worker.store.queryPartialDerivationOutputMap(i, &worker.evalStore);
|
||||
for (auto & j : depOutputs)
|
||||
if (j.second)
|
||||
outputsToDrv.insert_or_assign(*j.second, i);
|
||||
}
|
||||
|
||||
/* Check each path (slow!). */
|
||||
for (auto & i : outputClosure) {
|
||||
if (worker.pathContentsGood(i)) continue;
|
||||
printError(
|
||||
"found corrupted or missing path '%s' in the output closure of '%s'",
|
||||
worker.store.printStorePath(i), worker.store.printStorePath(drvPath));
|
||||
auto drvPath2 = outputsToDrv.find(i);
|
||||
if (drvPath2 == outputsToDrv.end())
|
||||
addWaitee(upcast_goal(worker.makePathSubstitutionGoal(i, Repair)));
|
||||
else
|
||||
addWaitee(worker.makeGoal(
|
||||
DerivedPath::Built {
|
||||
.drvPath = makeConstantStorePathRef(drvPath2->second),
|
||||
.outputs = OutputsSpec::All { },
|
||||
},
|
||||
bmRepair));
|
||||
}
|
||||
|
||||
if (waitees.empty()) {
|
||||
co_return done(BuildResult::AlreadyValid, assertPathValidity());
|
||||
} else {
|
||||
co_await Suspend{};
|
||||
|
||||
trace("closure repaired");
|
||||
if (nrFailed > 0)
|
||||
throw Error("some paths in the output closure of derivation '%s' could not be repaired",
|
||||
worker.store.printStorePath(drvPath));
|
||||
co_return done(BuildResult::AlreadyValid, assertPathValidity());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void chmod_(const Path & path, mode_t mode)
|
||||
{
|
||||
if (chmod(path.c_str(), mode) == -1)
|
||||
|
@ -1249,7 +1222,7 @@ SingleDrvOutputs DerivationGoal::registerOutputs()
|
|||
to do anything here.
|
||||
|
||||
We can only early return when the outputs are known a priori. For
|
||||
floating content-addressed derivations this isn't the case.
|
||||
floating content-addressing derivations this isn't the case.
|
||||
*/
|
||||
return assertPathValidity();
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ struct DerivationGoal : public Goal
|
|||
/**
|
||||
* Mapping from input derivations + output names to actual store
|
||||
* paths. This is filled in by waiteeDone() as each dependency
|
||||
* finishes, before inputsRealised() is reached.
|
||||
* finishes, before `trace("all inputs realised")` is reached.
|
||||
*/
|
||||
std::map<std::pair<StorePath, std::string>, StorePath> inputDrvOutputs;
|
||||
|
||||
|
@ -233,13 +233,8 @@ struct DerivationGoal : public Goal
|
|||
* The states.
|
||||
*/
|
||||
Co init() override;
|
||||
Co getDerivation();
|
||||
Co loadDerivation();
|
||||
Co haveDerivation();
|
||||
Co outputsSubstitutionTried();
|
||||
Co gaveUpOnSubstitution();
|
||||
Co closureRepaired();
|
||||
Co inputsRealised();
|
||||
Co tryToBuild();
|
||||
virtual Co tryLocalBuild();
|
||||
Co buildDone();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
-- Extension of the sql schema for content-addressed derivations.
|
||||
-- Extension of the sql schema for content-addressing derivations.
|
||||
-- Won't be loaded unless the experimental feature `ca-derivations`
|
||||
-- is enabled
|
||||
|
||||
|
|
|
@ -593,7 +593,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
|||
|
||||
auto drvType = drv.type();
|
||||
|
||||
/* Content-addressed derivations are trustless because their output paths
|
||||
/* Content-addressing derivations are trustless because their output paths
|
||||
are verified by their content alone, so any derivation is free to
|
||||
try to produce such a path.
|
||||
|
||||
|
|
|
@ -300,7 +300,7 @@ static DerivationOutput parseDerivationOutput(
|
|||
} else {
|
||||
xpSettings.require(Xp::CaDerivations);
|
||||
if (pathS != "")
|
||||
throw FormatError("content-addressed derivation output should not specify output path");
|
||||
throw FormatError("content-addressing derivation output should not specify output path");
|
||||
return DerivationOutput::CAFloating {
|
||||
.method = std::move(method),
|
||||
.hashAlgo = std::move(hashAlgo),
|
||||
|
|
|
@ -187,7 +187,7 @@ struct DerivationType {
|
|||
};
|
||||
|
||||
/**
|
||||
* Content-addressed derivation types
|
||||
* Content-addressing derivation types
|
||||
*/
|
||||
struct ContentAddressed {
|
||||
/**
|
||||
|
|
|
@ -189,7 +189,7 @@ public:
|
|||
this, SYSTEM, "system",
|
||||
R"(
|
||||
The system type of the current Nix installation.
|
||||
Nix will only build a given [derivation](@docroot@/language/derivations.md) locally when its `system` attribute equals any of the values specified here or in [`extra-platforms`](#conf-extra-platforms).
|
||||
Nix will only build a given [store derivation](@docroot@/glossary.md#gloss-store-derivation) locally when its `system` attribute equals any of the values specified here or in [`extra-platforms`](#conf-extra-platforms).
|
||||
|
||||
The default value is set when Nix itself is compiled for the system it will run on.
|
||||
The following system types are widely used, as Nix is actively supported on these platforms:
|
||||
|
@ -825,7 +825,7 @@ public:
|
|||
R"(
|
||||
System types of executables that can be run on this machine.
|
||||
|
||||
Nix will only build a given [derivation](@docroot@/language/derivations.md) locally when its `system` attribute equals any of the values specified here or in the [`system` option](#conf-system).
|
||||
Nix will only build a given [store derivation](@docroot@/glossary.md#gloss-store-derivation) locally when its `system` attribute equals any of the values specified here or in the [`system` option](#conf-system).
|
||||
|
||||
Setting this can be useful to build derivations locally on compatible machines:
|
||||
- `i686-linux` executables can be run on `x86_64-linux` machines (set by default)
|
||||
|
|
|
@ -608,7 +608,7 @@ void RemoteStore::queryRealisationUncached(const DrvOutput & id,
|
|||
auto conn(getConnection());
|
||||
|
||||
if (GET_PROTOCOL_MINOR(conn->protoVersion) < 27) {
|
||||
warn("the daemon is too old to support content-addressed derivations, please upgrade it to 2.4");
|
||||
warn("the daemon is too old to support content-addressing derivations, please upgrade it to 2.4");
|
||||
return callback(nullptr);
|
||||
}
|
||||
|
||||
|
|
|
@ -715,7 +715,7 @@ public:
|
|||
|
||||
/**
|
||||
* Given a store path, return the realisation actually used in the realisation of this path:
|
||||
* - If the path is a content-addressed derivation, try to resolve it
|
||||
* - If the path is a content-addressing derivation, try to resolve it
|
||||
* - Otherwise, find one of its derivers
|
||||
*/
|
||||
std::optional<StorePath> getBuildDerivationPath(const StorePath &);
|
||||
|
|
|
@ -800,7 +800,7 @@ void LocalDerivationGoal::startBuilder()
|
|||
out. */
|
||||
for (auto & i : drv->outputsAndOptPaths(worker.store)) {
|
||||
/* If the name isn't known a priori (i.e. floating
|
||||
content-addressed derivation), the temporary location we use
|
||||
content-addressing derivation), the temporary location we use
|
||||
should be fresh. Freshness means it is impossible that the path
|
||||
is already in the sandbox, so we don't need to worry about
|
||||
removing it. */
|
||||
|
@ -2291,7 +2291,7 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
|
|||
to do anything here.
|
||||
|
||||
We can only early return when the outputs are known a priori. For
|
||||
floating content-addressed derivations this isn't the case.
|
||||
floating content-addressing derivations this isn't the case.
|
||||
*/
|
||||
if (hook)
|
||||
return DerivationGoal::registerOutputs();
|
||||
|
|
|
@ -130,7 +130,7 @@ struct LocalDerivationGoal : public DerivationGoal
|
|||
* rewrite after the build. Otherwise the regular predetermined paths are
|
||||
* put here.
|
||||
*
|
||||
* - Floating content-addressed derivations do not know their final build
|
||||
* - Floating content-addressing derivations do not know their final build
|
||||
* output paths until the outputs are hashed, so random locations are
|
||||
* used, and then renamed. The randomness helps guard against hidden
|
||||
* self-references.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue