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
4 changed files with 70 additions and 61 deletions
|
@ -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");
|
||||
|
||||
nlohmann::json DerivationOutput::toJSON(
|
||||
|
|
|
@ -333,6 +333,14 @@ struct Derivation : BasicDerivation
|
|||
Store & store,
|
||||
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(const BasicDerivation & bd) : BasicDerivation(bd) { }
|
||||
Derivation(BasicDerivation && bd) : BasicDerivation(std::move(bd)) { }
|
||||
|
|
|
@ -710,62 +710,6 @@ void canonicalisePathMetaData(const Path & path,
|
|||
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)
|
||||
{
|
||||
experimentalFeatureSettings.require(Xp::CaDerivations);
|
||||
|
@ -876,7 +820,7 @@ uint64_t LocalStore::addValidPath(State & state,
|
|||
derivations). Note that if this throws an error, then the
|
||||
DB transaction is rolled back, so the path validity
|
||||
registration above is undone. */
|
||||
if (checkOutputs) checkDerivationOutputs(info.path, drv);
|
||||
if (checkOutputs) drv.checkInvariants(*this, info.path);
|
||||
|
||||
for (auto & i : drv.outputsAndOptPaths(*this)) {
|
||||
/* Floating CA derivations have indeterminate output paths until
|
||||
|
@ -1175,8 +1119,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
|
|||
for (auto & [_, i] : infos)
|
||||
if (i.path.isDerivation()) {
|
||||
// FIXME: inefficient; we already loaded the derivation in addValidPath().
|
||||
checkDerivationOutputs(i.path,
|
||||
readInvalidDerivation(i.path));
|
||||
readInvalidDerivation(i.path).checkInvariants(*this, i.path);
|
||||
}
|
||||
|
||||
/* Do a topological sort of the paths. This will throw an
|
||||
|
|
|
@ -270,8 +270,6 @@ private:
|
|||
|
||||
std::pair<Path, AutoCloseFD> createTempDirInStore();
|
||||
|
||||
void checkDerivationOutputs(const StorePath & drvPath, const Derivation & drv);
|
||||
|
||||
typedef std::unordered_set<ino_t> InodeHash;
|
||||
|
||||
InodeHash loadInodeHash();
|
||||
|
|
Loading…
Reference in a new issue