forked from lix-project/lix
Give queryPartialDerivationOutputMap
an evalStore
parameter
This makes it more useful. In general, the derivation will be in one store, and the realisation info is in another. This also helps us avoid duplication. See how `resolveDerivedPath` is now simpler because it uses `queryPartialDerivationOutputMap`. In #8369 we get more flavors of derived path, and need more code to resolve them all, and this problem only gets worse. The fact that we need a new method to deal with the multiple dispatch is unfortunate, but this generally relates to the fact that `Store` is a sub-par interface, too bulky/unwieldy and conflating separate concerns. Solving that is out of scope of this PR. This is part of the RFC 92 work. See tracking issue #6316
This commit is contained in:
parent
f62543fe1c
commit
6bc98c7fba
|
@ -1251,11 +1251,13 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
|
||||||
void queryReferrers(const StorePath & path, StorePathSet & referrers) override
|
void queryReferrers(const StorePath & path, StorePathSet & referrers) override
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
std::map<std::string, std::optional<StorePath>> queryPartialDerivationOutputMap(const StorePath & path) override
|
std::map<std::string, std::optional<StorePath>> queryPartialDerivationOutputMap(
|
||||||
|
const StorePath & path,
|
||||||
|
Store * evalStore = nullptr) override
|
||||||
{
|
{
|
||||||
if (!goal.isAllowed(path))
|
if (!goal.isAllowed(path))
|
||||||
throw InvalidPath("cannot query output map for unknown path '%s' in recursive Nix", printStorePath(path));
|
throw InvalidPath("cannot query output map for unknown path '%s' in recursive Nix", printStorePath(path));
|
||||||
return next->queryPartialDerivationOutputMap(path);
|
return next->queryPartialDerivationOutputMap(path, evalStore);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override
|
std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override
|
||||||
|
|
|
@ -1022,9 +1022,9 @@ StorePathSet LocalStore::queryValidDerivers(const StorePath & path)
|
||||||
|
|
||||||
|
|
||||||
std::map<std::string, std::optional<StorePath>>
|
std::map<std::string, std::optional<StorePath>>
|
||||||
LocalStore::queryPartialDerivationOutputMap(const StorePath & path)
|
LocalStore::queryStaticPartialDerivationOutputMap(const StorePath & path)
|
||||||
{
|
{
|
||||||
auto outputs = retrySQLite<std::map<std::string, std::optional<StorePath>>>([&]() {
|
return retrySQLite<std::map<std::string, std::optional<StorePath>>>([&]() {
|
||||||
auto state(_state.lock());
|
auto state(_state.lock());
|
||||||
std::map<std::string, std::optional<StorePath>> outputs;
|
std::map<std::string, std::optional<StorePath>> outputs;
|
||||||
uint64_t drvId;
|
uint64_t drvId;
|
||||||
|
@ -1036,21 +1036,6 @@ LocalStore::queryPartialDerivationOutputMap(const StorePath & path)
|
||||||
|
|
||||||
return outputs;
|
return outputs;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!experimentalFeatureSettings.isEnabled(Xp::CaDerivations))
|
|
||||||
return outputs;
|
|
||||||
|
|
||||||
auto drv = readInvalidDerivation(path);
|
|
||||||
auto drvHashes = staticOutputHashes(*this, drv);
|
|
||||||
for (auto& [outputName, hash] : drvHashes) {
|
|
||||||
auto realisation = queryRealisation(DrvOutput{hash, outputName});
|
|
||||||
if (realisation)
|
|
||||||
outputs.insert_or_assign(outputName, realisation->outPath);
|
|
||||||
else
|
|
||||||
outputs.insert({outputName, std::nullopt});
|
|
||||||
}
|
|
||||||
|
|
||||||
return outputs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<StorePath> LocalStore::queryPathFromHashPart(const std::string & hashPart)
|
std::optional<StorePath> LocalStore::queryPathFromHashPart(const std::string & hashPart)
|
||||||
|
|
|
@ -165,7 +165,7 @@ public:
|
||||||
|
|
||||||
StorePathSet queryValidDerivers(const StorePath & path) override;
|
StorePathSet queryValidDerivers(const StorePath & path) override;
|
||||||
|
|
||||||
std::map<std::string, std::optional<StorePath>> queryPartialDerivationOutputMap(const StorePath & path) override;
|
std::map<std::string, std::optional<StorePath>> queryStaticPartialDerivationOutputMap(const StorePath & path) override;
|
||||||
|
|
||||||
std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override;
|
std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override;
|
||||||
|
|
||||||
|
|
|
@ -310,43 +310,34 @@ std::map<DrvOutput, StorePath> drvOutputReferences(
|
||||||
|
|
||||||
OutputPathMap resolveDerivedPath(Store & store, const DerivedPath::Built & bfd, Store * evalStore_)
|
OutputPathMap resolveDerivedPath(Store & store, const DerivedPath::Built & bfd, Store * evalStore_)
|
||||||
{
|
{
|
||||||
auto & evalStore = evalStore_ ? *evalStore_ : store;
|
auto outputsOpt_ = store.queryPartialDerivationOutputMap(bfd.drvPath, evalStore_);
|
||||||
|
|
||||||
OutputPathMap outputs;
|
auto outputsOpt = std::visit(overloaded {
|
||||||
auto drv = evalStore.readDerivation(bfd.drvPath);
|
|
||||||
auto outputHashes = staticOutputHashes(store, drv);
|
|
||||||
auto drvOutputs = drv.outputsAndOptPaths(store);
|
|
||||||
auto outputNames = std::visit(overloaded {
|
|
||||||
[&](const OutputsSpec::All &) {
|
[&](const OutputsSpec::All &) {
|
||||||
StringSet names;
|
// Keep all outputs
|
||||||
for (auto & [outputName, _] : drv.outputs)
|
return std::move(outputsOpt_);
|
||||||
names.insert(outputName);
|
|
||||||
return names;
|
|
||||||
},
|
},
|
||||||
[&](const OutputsSpec::Names & names) {
|
[&](const OutputsSpec::Names & names) {
|
||||||
return static_cast<std::set<std::string>>(names);
|
// Get just those mentioned by name
|
||||||
|
std::map<std::string, std::optional<StorePath>> outputsOpt;
|
||||||
|
for (auto & output : names) {
|
||||||
|
auto * pOutputPathOpt = get(outputsOpt_, output);
|
||||||
|
if (!pOutputPathOpt)
|
||||||
|
throw Error(
|
||||||
|
"the derivation '%s' doesn't have an output named '%s'",
|
||||||
|
store.printStorePath(bfd.drvPath), output);
|
||||||
|
outputsOpt.insert_or_assign(output, std::move(*pOutputPathOpt));
|
||||||
|
}
|
||||||
|
return outputsOpt;
|
||||||
},
|
},
|
||||||
}, bfd.outputs.raw());
|
}, bfd.outputs.raw());
|
||||||
for (auto & output : outputNames) {
|
|
||||||
auto outputHash = get(outputHashes, output);
|
OutputPathMap outputs;
|
||||||
if (!outputHash)
|
for (auto & [outputName, outputPathOpt] : outputsOpt) {
|
||||||
throw Error(
|
if (!outputPathOpt)
|
||||||
"the derivation '%s' doesn't have an output named '%s'",
|
throw MissingRealisation(store.printStorePath(bfd.drvPath), outputName);
|
||||||
store.printStorePath(bfd.drvPath), output);
|
auto & outputPath = *outputPathOpt;
|
||||||
if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)) {
|
outputs.insert_or_assign(outputName, outputPath);
|
||||||
DrvOutput outputId { *outputHash, output };
|
|
||||||
auto realisation = store.queryRealisation(outputId);
|
|
||||||
if (!realisation)
|
|
||||||
throw MissingRealisation(outputId);
|
|
||||||
outputs.insert_or_assign(output, realisation->outPath);
|
|
||||||
} else {
|
|
||||||
// If ca-derivations isn't enabled, assume that
|
|
||||||
// the output path is statically known.
|
|
||||||
auto drvOutput = get(drvOutputs, output);
|
|
||||||
assert(drvOutput);
|
|
||||||
assert(drvOutput->second);
|
|
||||||
outputs.insert_or_assign(output, *drvOutput->second);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return outputs;
|
return outputs;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "hash.hh"
|
#include "hash.hh"
|
||||||
#include "path.hh"
|
#include "path.hh"
|
||||||
|
#include "derived-path.hh"
|
||||||
#include <nlohmann/json_fwd.hpp>
|
#include <nlohmann/json_fwd.hpp>
|
||||||
#include "comparator.hh"
|
#include "comparator.hh"
|
||||||
#include "crypto.hh"
|
#include "crypto.hh"
|
||||||
|
@ -143,9 +144,13 @@ class MissingRealisation : public Error
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MissingRealisation(DrvOutput & outputId)
|
MissingRealisation(DrvOutput & outputId)
|
||||||
: Error( "cannot operate on an output of the "
|
: MissingRealisation(outputId.outputName, outputId.strHash())
|
||||||
|
{}
|
||||||
|
MissingRealisation(std::string_view drv, std::string outputName)
|
||||||
|
: Error( "cannot operate on output '%s' of the "
|
||||||
"unbuilt derivation '%s'",
|
"unbuilt derivation '%s'",
|
||||||
outputId.to_string())
|
outputName,
|
||||||
|
drv)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -378,27 +378,36 @@ StorePathSet RemoteStore::queryDerivationOutputs(const StorePath & path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::map<std::string, std::optional<StorePath>> RemoteStore::queryPartialDerivationOutputMap(const StorePath & path)
|
std::map<std::string, std::optional<StorePath>> RemoteStore::queryPartialDerivationOutputMap(const StorePath & path, Store * evalStore_)
|
||||||
{
|
{
|
||||||
if (GET_PROTOCOL_MINOR(getProtocol()) >= 0x16) {
|
if (GET_PROTOCOL_MINOR(getProtocol()) >= 0x16) {
|
||||||
auto conn(getConnection());
|
if (!evalStore_) {
|
||||||
conn->to << WorkerProto::Op::QueryDerivationOutputMap << printStorePath(path);
|
auto conn(getConnection());
|
||||||
conn.processStderr();
|
conn->to << WorkerProto::Op::QueryDerivationOutputMap << printStorePath(path);
|
||||||
return WorkerProto::Serialise<std::map<std::string, std::optional<StorePath>>>::read(*this, *conn);
|
conn.processStderr();
|
||||||
|
return WorkerProto::Serialise<std::map<std::string, std::optional<StorePath>>>::read(*this, *conn);
|
||||||
|
} else {
|
||||||
|
auto & evalStore = *evalStore_;
|
||||||
|
auto outputs = evalStore.queryStaticPartialDerivationOutputMap(path);
|
||||||
|
// union with the first branch overriding the statically-known ones
|
||||||
|
// when non-`std::nullopt`.
|
||||||
|
for (auto && [outputName, optPath] : queryPartialDerivationOutputMap(path, nullptr)) {
|
||||||
|
if (optPath)
|
||||||
|
outputs.insert_or_assign(std::move(outputName), std::move(optPath));
|
||||||
|
else
|
||||||
|
outputs.insert({std::move(outputName), std::nullopt});
|
||||||
|
}
|
||||||
|
return outputs;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
auto & evalStore = evalStore_ ? *evalStore_ : *this;
|
||||||
// Fallback for old daemon versions.
|
// Fallback for old daemon versions.
|
||||||
// For floating-CA derivations (and their co-dependencies) this is an
|
// For floating-CA derivations (and their co-dependencies) this is an
|
||||||
// under-approximation as it only returns the paths that can be inferred
|
// under-approximation as it only returns the paths that can be inferred
|
||||||
// from the derivation itself (and not the ones that are known because
|
// from the derivation itself (and not the ones that are known because
|
||||||
// the have been built), but as old stores don't handle floating-CA
|
// the have been built), but as old stores don't handle floating-CA
|
||||||
// derivations this shouldn't matter
|
// derivations this shouldn't matter
|
||||||
auto derivation = readDerivation(path);
|
return evalStore.queryStaticPartialDerivationOutputMap(path);
|
||||||
auto outputsWithOptPaths = derivation.outputsAndOptPaths(*this);
|
|
||||||
std::map<std::string, std::optional<StorePath>> ret;
|
|
||||||
for (auto & [outputName, outputAndPath] : outputsWithOptPaths) {
|
|
||||||
ret.emplace(outputName, outputAndPath.second);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ public:
|
||||||
|
|
||||||
StorePathSet queryDerivationOutputs(const StorePath & path) override;
|
StorePathSet queryDerivationOutputs(const StorePath & path) override;
|
||||||
|
|
||||||
std::map<std::string, std::optional<StorePath>> queryPartialDerivationOutputMap(const StorePath & path) override;
|
std::map<std::string, std::optional<StorePath>> queryPartialDerivationOutputMap(const StorePath & path, Store * evalStore = nullptr) override;
|
||||||
std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override;
|
std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override;
|
||||||
|
|
||||||
StorePathSet querySubstitutablePaths(const StorePathSet & paths) override;
|
StorePathSet querySubstitutablePaths(const StorePathSet & paths) override;
|
||||||
|
|
|
@ -496,22 +496,50 @@ bool Store::PathInfoCacheValue::isKnownNow()
|
||||||
return std::chrono::steady_clock::now() < time_point + ttl;
|
return std::chrono::steady_clock::now() < time_point + ttl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, std::optional<StorePath>> Store::queryPartialDerivationOutputMap(const StorePath & path)
|
std::map<std::string, std::optional<StorePath>> Store::queryStaticPartialDerivationOutputMap(const StorePath & path)
|
||||||
{
|
{
|
||||||
std::map<std::string, std::optional<StorePath>> outputs;
|
std::map<std::string, std::optional<StorePath>> outputs;
|
||||||
auto drv = readInvalidDerivation(path);
|
auto drv = readInvalidDerivation(path);
|
||||||
for (auto& [outputName, output] : drv.outputsAndOptPaths(*this)) {
|
for (auto & [outputName, output] : drv.outputsAndOptPaths(*this)) {
|
||||||
outputs.emplace(outputName, output.second);
|
outputs.emplace(outputName, output.second);
|
||||||
}
|
}
|
||||||
return outputs;
|
return outputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::map<std::string, std::optional<StorePath>> Store::queryPartialDerivationOutputMap(
|
||||||
|
const StorePath & path,
|
||||||
|
Store * evalStore_)
|
||||||
|
{
|
||||||
|
auto & evalStore = evalStore_ ? *evalStore_ : *this;
|
||||||
|
|
||||||
|
auto outputs = evalStore.queryStaticPartialDerivationOutputMap(path);
|
||||||
|
|
||||||
|
if (!experimentalFeatureSettings.isEnabled(Xp::CaDerivations))
|
||||||
|
return outputs;
|
||||||
|
|
||||||
|
auto drv = evalStore.readInvalidDerivation(path);
|
||||||
|
auto drvHashes = staticOutputHashes(*this, drv);
|
||||||
|
for (auto & [outputName, hash] : drvHashes) {
|
||||||
|
auto realisation = queryRealisation(DrvOutput{hash, outputName});
|
||||||
|
if (realisation) {
|
||||||
|
outputs.insert_or_assign(outputName, realisation->outPath);
|
||||||
|
} else {
|
||||||
|
// queryStaticPartialDerivationOutputMap is not guaranteed
|
||||||
|
// to return std::nullopt for outputs which are not
|
||||||
|
// statically known.
|
||||||
|
outputs.insert({outputName, std::nullopt});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputs;
|
||||||
|
}
|
||||||
|
|
||||||
OutputPathMap Store::queryDerivationOutputMap(const StorePath & path) {
|
OutputPathMap Store::queryDerivationOutputMap(const StorePath & path) {
|
||||||
auto resp = queryPartialDerivationOutputMap(path);
|
auto resp = queryPartialDerivationOutputMap(path);
|
||||||
OutputPathMap result;
|
OutputPathMap result;
|
||||||
for (auto & [outName, optOutPath] : resp) {
|
for (auto & [outName, optOutPath] : resp) {
|
||||||
if (!optOutPath)
|
if (!optOutPath)
|
||||||
throw Error("output '%s' of derivation '%s' has no store path mapped to it", outName, printStorePath(path));
|
throw MissingRealisation(printStorePath(path), outName);
|
||||||
result.insert_or_assign(outName, *optOutPath);
|
result.insert_or_assign(outName, *optOutPath);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -425,7 +425,20 @@ public:
|
||||||
* derivation. All outputs are mentioned so ones mising the mapping
|
* derivation. All outputs are mentioned so ones mising the mapping
|
||||||
* are mapped to `std::nullopt`.
|
* are mapped to `std::nullopt`.
|
||||||
*/
|
*/
|
||||||
virtual std::map<std::string, std::optional<StorePath>> queryPartialDerivationOutputMap(const StorePath & path);
|
virtual std::map<std::string, std::optional<StorePath>> queryPartialDerivationOutputMap(
|
||||||
|
const StorePath & path,
|
||||||
|
Store * evalStore = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like `queryPartialDerivationOutputMap` but only considers
|
||||||
|
* statically known output paths (i.e. those that can be gotten from
|
||||||
|
* the derivation itself.
|
||||||
|
*
|
||||||
|
* Just a helper function for implementing
|
||||||
|
* `queryPartialDerivationOutputMap`.
|
||||||
|
*/
|
||||||
|
virtual std::map<std::string, std::optional<StorePath>> queryStaticPartialDerivationOutputMap(
|
||||||
|
const StorePath & path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query the mapping outputName=>outputPath for the given derivation.
|
* Query the mapping outputName=>outputPath for the given derivation.
|
||||||
|
|
Loading…
Reference in a new issue