Liberate checkDerivationOutputs
from LocalStore
Make it instead a method on `Derivation` that can work with any store. We will need this for a CLI command to create a derivation.
This commit is contained in:
parent
b200784cec
commit
4e9f32f993
|
@ -890,6 +890,66 @@ std::optional<BasicDerivation> Derivation::tryResolve(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Derivation::checkInvariants(Store & store, const StorePath & drvPath) const
|
||||||
|
{
|
||||||
|
assert(drvPath.isDerivation());
|
||||||
|
std::string drvName(drvPath.name());
|
||||||
|
drvName = drvName.substr(0, drvName.size() - drvExtension.size());
|
||||||
|
|
||||||
|
if (drvName != name) {
|
||||||
|
throw Error("Derivation '%s' has name '%s' which does not match its path", store.printStorePath(drvPath), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto envHasRightPath = [&](const StorePath & actual, const std::string & varName)
|
||||||
|
{
|
||||||
|
auto j = env.find(varName);
|
||||||
|
if (j == env.end() || store.parseStorePath(j->second) != actual)
|
||||||
|
throw Error("derivation '%s' has incorrect environment variable '%s', should be '%s'",
|
||||||
|
store.printStorePath(drvPath), varName, store.printStorePath(actual));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Don't need the answer, but do this anyways to assert is proper
|
||||||
|
// combination. The code below is more general and naturally allows
|
||||||
|
// combinations that are currently prohibited.
|
||||||
|
type();
|
||||||
|
|
||||||
|
std::optional<DrvHash> hashesModulo;
|
||||||
|
for (auto & i : outputs) {
|
||||||
|
std::visit(overloaded {
|
||||||
|
[&](const DerivationOutput::InputAddressed & doia) {
|
||||||
|
if (!hashesModulo) {
|
||||||
|
// somewhat expensive so we do lazily
|
||||||
|
hashesModulo = hashDerivationModulo(store, *this, true);
|
||||||
|
}
|
||||||
|
auto currentOutputHash = get(hashesModulo->hashes, i.first);
|
||||||
|
if (!currentOutputHash)
|
||||||
|
throw Error("derivation '%s' has unexpected output '%s' (local-store / hashesModulo) named '%s'",
|
||||||
|
store.printStorePath(drvPath), store.printStorePath(doia.path), i.first);
|
||||||
|
StorePath recomputed = store.makeOutputPath(i.first, *currentOutputHash, drvName);
|
||||||
|
if (doia.path != recomputed)
|
||||||
|
throw Error("derivation '%s' has incorrect output '%s', should be '%s'",
|
||||||
|
store.printStorePath(drvPath), store.printStorePath(doia.path), store.printStorePath(recomputed));
|
||||||
|
envHasRightPath(doia.path, i.first);
|
||||||
|
},
|
||||||
|
[&](const DerivationOutput::CAFixed & dof) {
|
||||||
|
StorePath path = store.makeFixedOutputPath(dof.hash.method, dof.hash.hash, drvName);
|
||||||
|
envHasRightPath(path, i.first);
|
||||||
|
},
|
||||||
|
[&](const DerivationOutput::CAFloating &) {
|
||||||
|
/* Nothing to check */
|
||||||
|
},
|
||||||
|
[&](const DerivationOutput::Deferred &) {
|
||||||
|
/* Nothing to check */
|
||||||
|
},
|
||||||
|
[&](const DerivationOutput::Impure &) {
|
||||||
|
/* Nothing to check */
|
||||||
|
},
|
||||||
|
}, i.second.raw());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const Hash impureOutputHash = hashString(htSHA256, "impure");
|
const Hash impureOutputHash = hashString(htSHA256, "impure");
|
||||||
|
|
||||||
nlohmann::json DerivationOutput::toJSON(
|
nlohmann::json DerivationOutput::toJSON(
|
||||||
|
|
|
@ -333,6 +333,14 @@ struct Derivation : BasicDerivation
|
||||||
Store & store,
|
Store & store,
|
||||||
const std::map<std::pair<StorePath, std::string>, StorePath> & inputDrvOutputs) const;
|
const std::map<std::pair<StorePath, std::string>, StorePath> & inputDrvOutputs) const;
|
||||||
|
|
||||||
|
/* Check that the derivation is valid and does not present any
|
||||||
|
illegal states.
|
||||||
|
|
||||||
|
This is mainly a matter of checking the outputs, where our C++
|
||||||
|
representation supports all sorts of combinations we do not yet
|
||||||
|
allow. */
|
||||||
|
void checkInvariants(Store & store, const StorePath & drvPath) const;
|
||||||
|
|
||||||
Derivation() = default;
|
Derivation() = default;
|
||||||
Derivation(const BasicDerivation & bd) : BasicDerivation(bd) { }
|
Derivation(const BasicDerivation & bd) : BasicDerivation(bd) { }
|
||||||
Derivation(BasicDerivation && bd) : BasicDerivation(std::move(bd)) { }
|
Derivation(BasicDerivation && bd) : BasicDerivation(std::move(bd)) { }
|
||||||
|
|
|
@ -710,62 +710,6 @@ void canonicalisePathMetaData(const Path & path,
|
||||||
canonicalisePathMetaData(path, uidRange, inodesSeen);
|
canonicalisePathMetaData(path, uidRange, inodesSeen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LocalStore::checkDerivationOutputs(const StorePath & drvPath, const Derivation & drv)
|
|
||||||
{
|
|
||||||
assert(drvPath.isDerivation());
|
|
||||||
std::string drvName(drvPath.name());
|
|
||||||
drvName = drvName.substr(0, drvName.size() - drvExtension.size());
|
|
||||||
|
|
||||||
auto envHasRightPath = [&](const StorePath & actual, const std::string & varName)
|
|
||||||
{
|
|
||||||
auto j = drv.env.find(varName);
|
|
||||||
if (j == drv.env.end() || parseStorePath(j->second) != actual)
|
|
||||||
throw Error("derivation '%s' has incorrect environment variable '%s', should be '%s'",
|
|
||||||
printStorePath(drvPath), varName, printStorePath(actual));
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Don't need the answer, but do this anyways to assert is proper
|
|
||||||
// combination. The code below is more general and naturally allows
|
|
||||||
// combinations that are currently prohibited.
|
|
||||||
drv.type();
|
|
||||||
|
|
||||||
std::optional<DrvHash> hashesModulo;
|
|
||||||
for (auto & i : drv.outputs) {
|
|
||||||
std::visit(overloaded {
|
|
||||||
[&](const DerivationOutput::InputAddressed & doia) {
|
|
||||||
if (!hashesModulo) {
|
|
||||||
// somewhat expensive so we do lazily
|
|
||||||
hashesModulo = hashDerivationModulo(*this, drv, true);
|
|
||||||
}
|
|
||||||
auto currentOutputHash = get(hashesModulo->hashes, i.first);
|
|
||||||
if (!currentOutputHash)
|
|
||||||
throw Error("derivation '%s' has unexpected output '%s' (local-store / hashesModulo) named '%s'",
|
|
||||||
printStorePath(drvPath), printStorePath(doia.path), i.first);
|
|
||||||
StorePath recomputed = makeOutputPath(i.first, *currentOutputHash, drvName);
|
|
||||||
if (doia.path != recomputed)
|
|
||||||
throw Error("derivation '%s' has incorrect output '%s', should be '%s'",
|
|
||||||
printStorePath(drvPath), printStorePath(doia.path), printStorePath(recomputed));
|
|
||||||
envHasRightPath(doia.path, i.first);
|
|
||||||
},
|
|
||||||
[&](const DerivationOutput::CAFixed & dof) {
|
|
||||||
StorePath path = makeFixedOutputPath(dof.hash.method, dof.hash.hash, drvName);
|
|
||||||
envHasRightPath(path, i.first);
|
|
||||||
},
|
|
||||||
[&](const DerivationOutput::CAFloating &) {
|
|
||||||
/* Nothing to check */
|
|
||||||
},
|
|
||||||
[&](const DerivationOutput::Deferred &) {
|
|
||||||
/* Nothing to check */
|
|
||||||
},
|
|
||||||
[&](const DerivationOutput::Impure &) {
|
|
||||||
/* Nothing to check */
|
|
||||||
},
|
|
||||||
}, i.second.raw());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LocalStore::registerDrvOutput(const Realisation & info, CheckSigsFlag checkSigs)
|
void LocalStore::registerDrvOutput(const Realisation & info, CheckSigsFlag checkSigs)
|
||||||
{
|
{
|
||||||
experimentalFeatureSettings.require(Xp::CaDerivations);
|
experimentalFeatureSettings.require(Xp::CaDerivations);
|
||||||
|
@ -876,7 +820,7 @@ uint64_t LocalStore::addValidPath(State & state,
|
||||||
derivations). Note that if this throws an error, then the
|
derivations). Note that if this throws an error, then the
|
||||||
DB transaction is rolled back, so the path validity
|
DB transaction is rolled back, so the path validity
|
||||||
registration above is undone. */
|
registration above is undone. */
|
||||||
if (checkOutputs) checkDerivationOutputs(info.path, drv);
|
if (checkOutputs) drv.checkInvariants(*this, info.path);
|
||||||
|
|
||||||
for (auto & i : drv.outputsAndOptPaths(*this)) {
|
for (auto & i : drv.outputsAndOptPaths(*this)) {
|
||||||
/* Floating CA derivations have indeterminate output paths until
|
/* Floating CA derivations have indeterminate output paths until
|
||||||
|
@ -1175,8 +1119,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
|
||||||
for (auto & [_, i] : infos)
|
for (auto & [_, i] : infos)
|
||||||
if (i.path.isDerivation()) {
|
if (i.path.isDerivation()) {
|
||||||
// FIXME: inefficient; we already loaded the derivation in addValidPath().
|
// FIXME: inefficient; we already loaded the derivation in addValidPath().
|
||||||
checkDerivationOutputs(i.path,
|
readInvalidDerivation(i.path).checkInvariants(*this, i.path);
|
||||||
readInvalidDerivation(i.path));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do a topological sort of the paths. This will throw an
|
/* Do a topological sort of the paths. This will throw an
|
||||||
|
|
|
@ -270,8 +270,6 @@ private:
|
||||||
|
|
||||||
std::pair<Path, AutoCloseFD> createTempDirInStore();
|
std::pair<Path, AutoCloseFD> createTempDirInStore();
|
||||||
|
|
||||||
void checkDerivationOutputs(const StorePath & drvPath, const Derivation & drv);
|
|
||||||
|
|
||||||
typedef std::unordered_set<ino_t> InodeHash;
|
typedef std::unordered_set<ino_t> InodeHash;
|
||||||
|
|
||||||
InodeHash loadInodeHash();
|
InodeHash loadInodeHash();
|
||||||
|
|
Loading…
Reference in a new issue