diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index f6e0b1b3811..9bf970366e3 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -599,7 +599,7 @@ std::vector, BuiltPathWithResult>> Installable::build case Realise::Nothing: case Realise::Derivation: - printMissing(store, pathsToBuild, lvlError); + printMissing(store, pathsToBuild, lvlError, &*evalStore); for (auto & path : pathsToBuild) { for (auto & aux : backmap[path]) { @@ -629,7 +629,7 @@ std::vector, BuiltPathWithResult>> Installable::build case Realise::Outputs: { if (settings.printMissing) - printMissing(store, pathsToBuild, lvlInfo); + printMissing(store, pathsToBuild, lvlInfo, &*evalStore); auto buildResults = store->getBuilder(evalStore)->buildPathsWithResults(pathsToBuild, bMode); throwBuildErrors(buildResults, *store); diff --git a/src/libmain/include/nix/main/shared.hh b/src/libmain/include/nix/main/shared.hh index 7a7ecb29c3d..f27a52026e1 100644 --- a/src/libmain/include/nix/main/shared.hh +++ b/src/libmain/include/nix/main/shared.hh @@ -36,7 +36,8 @@ void printGCWarning(); class Store; struct MissingPaths; -void printMissing(ref store, const std::vector & paths, Verbosity lvl = lvlInfo); +void printMissing( + ref store, const std::vector & paths, Verbosity lvl = lvlInfo, Store * evalStore = nullptr); void printMissing(ref store, const MissingPaths & missing, Verbosity lvl = lvlInfo); diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index f0e3365c249..1872bfb39b1 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -54,9 +54,9 @@ void printGCWarning() "the result might be removed by the garbage collector"); } -void printMissing(ref store, const std::vector & paths, Verbosity lvl) +void printMissing(ref store, const std::vector & paths, Verbosity lvl, Store * evalStore) { - printMissing(store, store->queryMissing(paths), lvl); + printMissing(store, store->queryMissing(paths, evalStore), lvl); } void printMissing(ref store, const MissingPaths & missing, Verbosity lvl) diff --git a/src/libstore/include/nix/store/remote-store.hh b/src/libstore/include/nix/store/remote-store.hh index b357b78f942..fe74a28f551 100644 --- a/src/libstore/include/nix/store/remote-store.hh +++ b/src/libstore/include/nix/store/remote-store.hh @@ -146,7 +146,7 @@ public: void addSignatures(const StorePath & storePath, const std::set & sigs) override; - MissingPaths queryMissing(const std::vector & targets) override; + MissingPaths queryMissing(const std::vector & targets, Store * evalStore = nullptr) override; void addBuildLog(const StorePath & drvPath, std::string_view log) override; diff --git a/src/libstore/include/nix/store/store-api.hh b/src/libstore/include/nix/store/store-api.hh index 06122cc746c..567abdc756b 100644 --- a/src/libstore/include/nix/store/store-api.hh +++ b/src/libstore/include/nix/store/store-api.hh @@ -944,8 +944,11 @@ public: * Given a set of paths that are to be built, return the set of * derivations that will be built, and the set of output paths that * will be substituted. + * + * @param evalStore If given, derivations not (yet) present in this + * store are read from there, like the builder does. */ - virtual MissingPaths queryMissing(const std::vector & targets); + virtual MissingPaths queryMissing(const std::vector & targets, Store * evalStore = nullptr); /** * Sort a set of paths topologically under the references diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc index 67822e170bf..5af725a6e16 100644 --- a/src/libstore/misc.cc +++ b/src/libstore/misc.cc @@ -167,10 +167,12 @@ void Store::querySubstitutablePathInfos(const StorePathCAMap & paths, Substituta std::rethrow_exception(ex); } -MissingPaths Store::queryMissing(const std::vector & targets) +MissingPaths Store::queryMissing(const std::vector & targets, Store * evalStore_) { Activity act(*logger, lvlDebug, actUnknown, "querying info about missing paths"); + auto & evalStore = evalStore_ ? *evalStore_ : *this; + MissingPaths res; auto mustBuildDrv = [&](const StorePath & drvPath, const Derivation & drv, std::set & edges) { @@ -202,7 +204,8 @@ MissingPaths Store::queryMissing(const std::vector & targets) } auto & drvPath = drvPathP->path; - if (!isValidPath(drvPath)) { + auto * drvStore = evalStore.isValidPath(drvPath) ? &evalStore : this; + if (!drvStore->isValidPath(drvPath)) { // FIXME: we could try to substitute the derivation. res.unknown.insert(drvPath); co_return; @@ -212,7 +215,7 @@ MissingPaths Store::queryMissing(const std::vector & targets) /* true for regular derivations, and CA derivations for which we have a trust mapping for all wanted outputs. */ auto knownOutputPaths = true; - for (auto & [outputName, pathOpt] : queryPartialDerivationOutputMap(drvPath)) { + for (auto & [outputName, pathOpt] : queryPartialDerivationOutputMap(drvPath, drvStore)) { if (!pathOpt) { knownOutputPaths = false; break; @@ -223,7 +226,7 @@ MissingPaths Store::queryMissing(const std::vector & targets) if (knownOutputPaths && invalid.empty()) co_return; - auto drv = make_ref(derivationFromPath(drvPath)); + auto drv = make_ref(drvStore->readDerivation(drvPath)); DerivationOptions drvOptions; try { // FIXME: this is a lot of work just to get the value diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index d6cd21f5a7f..eace5160278 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -840,9 +840,9 @@ void RemoteStore::addSignatures(const StorePath & storePath, const std::setfrom); } -MissingPaths RemoteStore::queryMissing(const std::vector & targets) +MissingPaths RemoteStore::queryMissing(const std::vector & targets, Store * evalStore) { - { + if (!evalStore || evalStore == this) { auto conn(getConnection()); if (conn->protoVersion.number < WorkerProto::Version::Number{1, 19}) // Don't hold the connection handle in the fallback case @@ -860,7 +860,8 @@ MissingPaths RemoteStore::queryMissing(const std::vector & targets) } fallback: - return Store::queryMissing(targets); + // The daemon cannot see the eval store, so do the traversal here. + return Store::queryMissing(targets, evalStore); } void RemoteStore::addBuildLog(const StorePath & drvPath, std::string_view log) diff --git a/src/libstore/restricted-store.cc b/src/libstore/restricted-store.cc index 68d38525eb1..96357c7b1a1 100644 --- a/src/libstore/restricted-store.cc +++ b/src/libstore/restricted-store.cc @@ -145,7 +145,7 @@ struct RestrictedStore : public virtual IndirectRootStore, public virtual GcStor unsupported("addSignatures"); } - MissingPaths queryMissing(const std::vector & targets) override; + MissingPaths queryMissing(const std::vector & targets, Store * evalStore = nullptr) override; virtual std::optional getBuildLogExact(const StorePath & path) override { @@ -370,7 +370,7 @@ RestrictedBuilder::buildPathsWithResults(const std::vector & paths, return results; } -MissingPaths RestrictedStore::queryMissing(const std::vector & targets) +MissingPaths RestrictedStore::queryMissing(const std::vector & targets, Store * evalStore) { /* This is slightly impure since it leaks information to the client about what paths will be built/substituted or are @@ -385,7 +385,7 @@ MissingPaths RestrictedStore::queryMissing(const std::vector & targ unknown.insert(pathPartOfReq(req)); } - auto res = next->queryMissing(allowed); + auto res = next->queryMissing(allowed, evalStore); for (auto & p : unknown) res.unknown.insert(p); diff --git a/src/nix/build.cc b/src/nix/build.cc index 435872b6032..edfb06689e7 100644 --- a/src/nix/build.cc +++ b/src/nix/build.cc @@ -140,7 +140,7 @@ struct CmdBuild : InstallablesCommand, MixOutLinkByDefault, MixDryRun, MixJSON, for (auto & b : i->toDerivedPaths()) pathsToBuild.push_back(b.path); - printMissing(store, pathsToBuild, lvlError); + printMissing(store, pathsToBuild, lvlError, &*getEvalStore()); if (json) printJSON(derivedPathsToJSON(pathsToBuild, *store)); diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 96de12623a6..a17217932b9 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -814,7 +814,7 @@ struct CmdFlakeCheck : FlakeCommand, MixPrintOutPaths, MixOutLinkBase // For now, we skip building derivations whose outputs are already available // via substitution, as `nix flake check` only needs to verify buildability, // not actually produce the outputs. - auto missing = store->queryMissing(drvPaths); + auto missing = store->queryMissing(drvPaths, &*getEvalStore()); std::vector toBuild; for (auto & path : missing.willBuild) { diff --git a/src/nix/nix-build/nix-build.cc b/src/nix/nix-build/nix-build.cc index 9d05e575229..9ffa337529a 100644 --- a/src/nix/nix-build/nix-build.cc +++ b/src/nix/nix-build/nix-build.cc @@ -448,7 +448,7 @@ static void main_nix_build(int argc, char ** argv) auto buildPaths = [&](const std::vector & paths) { if (settings.printMissing) - printMissing(ref(store), paths); + printMissing(ref(store), paths, lvlInfo, &*evalStore); if (!dryRun) store->getBuilder(evalStore)->buildPaths(paths, buildMode); diff --git a/tests/functional/eval-store.sh b/tests/functional/eval-store.sh index d32c905165a..4a11d6a50e5 100755 --- a/tests/functional/eval-store.sh +++ b/tests/functional/eval-store.sh @@ -11,6 +11,12 @@ needLocalStore "“--eval-store” doesn't achieve much with the daemon" eval_store=$TEST_ROOT/eval-store +# The build store has not seen the .drv files yet. queryMissing must read +# them from the eval store instead of reporting them as unknown. +out=$(nix build -f dependencies.nix --eval-store "$eval_store" --dry-run 2>&1) +[[ $out != *"don't know how to build"* ]] +[[ $out == *"will be built"* ]] + nix build -f dependencies.nix --eval-store "$eval_store" -o "$TEST_ROOT/result" [[ -e $TEST_ROOT/result/foobar ]] if [[ -z "${NIX_TESTS_CA_BY_DEFAULT:-}" ]]; then