diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 00f8105aea33cf77882e3f05383de95cdd30fc4d..e3ce564b0aba10454ecae3410dd46a21154d7981 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -766,7 +766,7 @@ BuiltPaths build(ref<Store> evalStore, ref<Store> store, Realise mode, if (mode == Realise::Nothing) printMissing(store, pathsToBuild, lvlError); else if (mode == Realise::Outputs) - store->buildPaths(pathsToBuild, bMode); + store->buildPaths(pathsToBuild, bMode, evalStore); return getBuiltPaths(evalStore, store, pathsToBuild); } diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc index 7df59740014e46d15ff65ad2c14a7db2c40bfe0d..dad8717a2c4a670af57598e959146e091ddf3d91 100644 --- a/src/libstore/build/derivation-goal.cc +++ b/src/libstore/build/derivation-goal.cc @@ -165,7 +165,7 @@ void DerivationGoal::getDerivation() /* 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.store.isValidPath(drvPath)) { + if (buildMode == bmNormal && worker.evalStore.isValidPath(drvPath)) { loadDerivation(); return; } @@ -188,12 +188,12 @@ void DerivationGoal::loadDerivation() /* `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.store.addTempRoot(drvPath); + worker.evalStore.addTempRoot(drvPath); - assert(worker.store.isValidPath(drvPath)); + assert(worker.evalStore.isValidPath(drvPath)); /* Get the derivation. */ - drv = std::make_unique<Derivation>(worker.store.derivationFromPath(drvPath)); + drv = std::make_unique<Derivation>(worker.evalStore.derivationFromPath(drvPath)); haveDerivation(); } @@ -212,8 +212,8 @@ void DerivationGoal::haveDerivation() if (i.second.second) worker.store.addTempRoot(*i.second.second); - auto outputHashes = staticOutputHashes(worker.store, *drv); - for (auto &[outputName, outputHash] : outputHashes) + auto outputHashes = staticOutputHashes(worker.evalStore, *drv); + for (auto & [outputName, outputHash] : outputHashes) initialOutputs.insert({ outputName, InitialOutput{ @@ -337,6 +337,16 @@ void DerivationGoal::gaveUpOnSubstitution() for (auto & i : dynamic_cast<Derivation *>(drv.get())->inputDrvs) addWaitee(worker.makeDerivationGoal(i.first, i.second, buildMode == bmRepair ? bmRepair : bmNormal)); + /* Copy the input sources from the eval store to the build + store. */ + if (&worker.evalStore != &worker.store) { + RealisedPath::Set inputSrcs, inputClosure; + for (auto & i : drv->inputSrcs) + inputSrcs.insert(i); + RealisedPath::closure(worker.evalStore, inputSrcs, inputClosure); + copyClosure(worker.evalStore, worker.store, inputClosure); + } + for (auto & i : drv->inputSrcs) { if (worker.store.isValidPath(i)) continue; if (!settings.useSubstitutes) @@ -478,8 +488,8 @@ void DerivationGoal::inputsRealised() /* Add the relevant output closures of the input derivation `i' as input paths. Only add the closures of output paths that are specified as inputs. */ - assert(worker.store.isValidPath(drvPath)); - auto outputs = worker.store.queryPartialDerivationOutputMap(depDrvPath); + assert(worker.evalStore.isValidPath(drvPath)); + auto outputs = worker.evalStore.queryPartialDerivationOutputMap(depDrvPath); for (auto & j : wantedDepOutputs) { if (outputs.count(j) > 0) { auto optRealizedInput = outputs.at(j); diff --git a/src/libstore/build/entry-points.cc b/src/libstore/build/entry-points.cc index 732d4785d6ee2c8dbdc91c159dd3a5cebda15179..96deb81d1e7be846f9e651e0392fac1e92bcc656 100644 --- a/src/libstore/build/entry-points.cc +++ b/src/libstore/build/entry-points.cc @@ -6,9 +6,9 @@ namespace nix { -void Store::buildPaths(const std::vector<DerivedPath> & reqs, BuildMode buildMode) +void Store::buildPaths(const std::vector<DerivedPath> & reqs, BuildMode buildMode, std::shared_ptr<Store> evalStore) { - Worker worker(*this); + Worker worker(*this, evalStore ? *evalStore : *this); Goals goals; for (auto & br : reqs) { @@ -51,7 +51,7 @@ void Store::buildPaths(const std::vector<DerivedPath> & reqs, BuildMode buildMod BuildResult Store::buildDerivation(const StorePath & drvPath, const BasicDerivation & drv, BuildMode buildMode) { - Worker worker(*this); + Worker worker(*this, *this); auto goal = worker.makeBasicDerivationGoal(drvPath, drv, {}, buildMode); BuildResult result; @@ -93,7 +93,7 @@ void Store::ensurePath(const StorePath & path) /* If the path is already valid, we're done. */ if (isValidPath(path)) return; - Worker worker(*this); + Worker worker(*this, *this); GoalPtr goal = worker.makePathSubstitutionGoal(path); Goals goals = {goal}; @@ -111,7 +111,7 @@ void Store::ensurePath(const StorePath & path) void LocalStore::repairPath(const StorePath & path) { - Worker worker(*this); + Worker worker(*this, *this); GoalPtr goal = worker.makePathSubstitutionGoal(path, Repair); Goals goals = {goal}; diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc index 11c99d9f08faba6003b2002912bc3e60ef9c6a32..990ff60b75f0384111810e232b7e3a7fe66a6790 100644 --- a/src/libstore/build/local-derivation-goal.cc +++ b/src/libstore/build/local-derivation-goal.cc @@ -1254,8 +1254,10 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo return next->queryRealisation(id); } - void buildPaths(const std::vector<DerivedPath> & paths, BuildMode buildMode) override + void buildPaths(const std::vector<DerivedPath> & paths, BuildMode buildMode, std::shared_ptr<Store> evalStore) override { + assert(!evalStore); + if (buildMode != bmNormal) throw Error("unsupported build mode"); StorePathSet newPaths; diff --git a/src/libstore/build/worker.cc b/src/libstore/build/worker.cc index 0f2ade348d15c687f28fc642408e39b43da15073..a7a6b92a6c001b3a3531d0199fa87639c3c5ef5e 100644 --- a/src/libstore/build/worker.cc +++ b/src/libstore/build/worker.cc @@ -9,11 +9,12 @@ namespace nix { -Worker::Worker(Store & store) +Worker::Worker(Store & store, Store & evalStore) : act(*logger, actRealise) , actDerivations(*logger, actBuilds) , actSubstitutions(*logger, actCopyPaths) , store(store) + , evalStore(evalStore) { /* Debugging: prevent recursive workers. */ nrLocalBuilds = 0; diff --git a/src/libstore/build/worker.hh b/src/libstore/build/worker.hh index 918de35f6dc5d7902c4b3681e540c9dce60e9713..6a3b99c02d10fa11c10e790f262e9397522d8d12 100644 --- a/src/libstore/build/worker.hh +++ b/src/libstore/build/worker.hh @@ -110,6 +110,7 @@ public: bool checkMismatch; Store & store; + Store & evalStore; std::unique_ptr<HookInstance> hook; @@ -131,7 +132,7 @@ public: it answers with "decline-permanently", we don't try again. */ bool tryBuildHook = true; - Worker(Store & store); + Worker(Store & store, Store & evalStore); ~Worker(); /* Make a goal (with caching). */ diff --git a/src/libstore/legacy-ssh-store.cc b/src/libstore/legacy-ssh-store.cc index edaf751367eed102089e1d89f166f125856e7726..45eed57075649279aea28e919828130ad790bd6d 100644 --- a/src/libstore/legacy-ssh-store.cc +++ b/src/libstore/legacy-ssh-store.cc @@ -267,8 +267,11 @@ public: return status; } - void buildPaths(const std::vector<DerivedPath> & drvPaths, BuildMode buildMode) override + void buildPaths(const std::vector<DerivedPath> & drvPaths, BuildMode buildMode, std::shared_ptr<Store> evalStore) override { + if (evalStore && evalStore.get() != this) + throw Error("building on an SSH store is incompatible with '--eval-store'"); + auto conn(connections->get()); conn->to << cmdBuildPaths; diff --git a/src/libstore/realisation.hh b/src/libstore/realisation.hh index 05d2bc44f1d10762a092a939e1f637dea66eada7..9070a6ee21d43fe44b491f129a00958dd24a8ca0 100644 --- a/src/libstore/realisation.hh +++ b/src/libstore/realisation.hh @@ -45,7 +45,7 @@ struct Realisation { size_t checkSignatures(const PublicKeys & publicKeys) const; static std::set<Realisation> closure(Store &, const std::set<Realisation> &); - static void closure(Store &, const std::set<Realisation> &, std::set<Realisation>& res); + static void closure(Store &, const std::set<Realisation> &, std::set<Realisation> & res); bool isCompatibleWith(const Realisation & other) const; diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index cd2d718eceb948e4d4da85650ac8c2d57b9889b5..77b34d000190ff8a11177a54c6844b91e2047356 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -705,8 +705,11 @@ static void writeDerivedPaths(RemoteStore & store, ConnectionHandle & conn, cons } } -void RemoteStore::buildPaths(const std::vector<DerivedPath> & drvPaths, BuildMode buildMode) +void RemoteStore::buildPaths(const std::vector<DerivedPath> & drvPaths, BuildMode buildMode, std::shared_ptr<Store> evalStore) { + if (evalStore && evalStore.get() != this) + throw Error("building on a remote store is incompatible with '--eval-store'"); + auto conn(getConnection()); conn->to << wopBuildPaths; assert(GET_PROTOCOL_MINOR(conn->daemonVersion) >= 13); diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh index 293393c32ff2f4e9b1d7d559caa482cc9d7bfe50..fbec40b4bcb72be2eb321a70070ae49a2677e831 100644 --- a/src/libstore/remote-store.hh +++ b/src/libstore/remote-store.hh @@ -85,7 +85,7 @@ public: std::optional<const Realisation> queryRealisation(const DrvOutput &) override; - void buildPaths(const std::vector<DerivedPath> & paths, BuildMode buildMode) override; + void buildPaths(const std::vector<DerivedPath> & paths, BuildMode buildMode, std::shared_ptr<Store> evalStore) override; BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv, BuildMode buildMode) override; diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 80edac2442d07684744d7daa4a470820ea731ac3..3ad74f35cc4cbb6a99449dd8ff5dfdd9cc3a2c40 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -497,7 +497,8 @@ public: not derivations, substitute them. */ virtual void buildPaths( const std::vector<DerivedPath> & paths, - BuildMode buildMode = bmNormal); + BuildMode buildMode = bmNormal, + std::shared_ptr<Store> evalStore = nullptr); /* Build a single non-materialized derivation (i.e. not from an on-disk .drv file). diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc index 3b791e61918b7a78436df0e56071b5a3f2feb56c..848b108dd26c605211bdf3a2336d0d39dedc64ca 100755 --- a/src/nix-build/nix-build.cc +++ b/src/nix-build/nix-build.cc @@ -341,7 +341,7 @@ static void main_nix_build(int argc, char * * argv) printMissing(ref<Store>(store), willBuild, willSubstitute, unknown, downloadSize, narSize); if (!dryRun) - store->buildPaths(paths, buildMode); + store->buildPaths(paths, buildMode, evalStore); }; if (runEnv) { @@ -397,8 +397,6 @@ static void main_nix_build(int argc, char * * argv) pathsToCopy.insert(src); } - copyClosure(*evalStore, *store, pathsToCopy); - buildPaths(pathsToBuild); if (dryRun) return; @@ -449,7 +447,7 @@ static void main_nix_build(int argc, char * * argv) if (env.count("__json")) { StorePathSet inputs; for (auto & [depDrvPath, wantedDepOutputs] : drv.inputDrvs) { - auto outputs = store->queryPartialDerivationOutputMap(depDrvPath); + auto outputs = evalStore->queryPartialDerivationOutputMap(depDrvPath); for (auto & i : wantedDepOutputs) { auto o = outputs.at(i); store->computeFSClosure(*o, inputs); @@ -564,8 +562,6 @@ static void main_nix_build(int argc, char * * argv) drvMap[drvPath] = {drvMap.size(), {outputName}}; } - copyClosure(*evalStore, *store, drvsToCopy); - buildPaths(pathsToBuild); if (dryRun) return; @@ -578,7 +574,7 @@ static void main_nix_build(int argc, char * * argv) if (counter) drvPrefix += fmt("-%d", counter + 1); - auto builtOutputs = store->queryPartialDerivationOutputMap(drvPath); + auto builtOutputs = evalStore->queryPartialDerivationOutputMap(drvPath); auto maybeOutputPath = builtOutputs.at(outputName); assert(maybeOutputPath); diff --git a/src/nix/develop.cc b/src/nix/develop.cc index cb173b91b1cee49ab1cc3e553ca62e0e914d6fac..9a93cdb03a7b906151fefecce6a0fb586ef361b1 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -171,15 +171,15 @@ const static std::string getEnvSh = modified derivation with the same dependencies and nearly the same initial environment variables, that just writes the resulting environment to a file and exits. */ -StorePath getDerivationEnvironment(ref<Store> store, const StorePath & drvPath) +static StorePath getDerivationEnvironment(ref<Store> store, ref<Store> evalStore, const StorePath & drvPath) { - auto drv = store->derivationFromPath(drvPath); + auto drv = evalStore->derivationFromPath(drvPath); auto builder = baseNameOf(drv.builder); if (builder != "bash") throw Error("'nix develop' only works on derivations that use 'bash' as their builder"); - auto getEnvShPath = store->addTextToStore("get-env.sh", getEnvSh, {}); + auto getEnvShPath = evalStore->addTextToStore("get-env.sh", getEnvSh, {}); drv.args = {store->printStorePath(getEnvShPath)}; @@ -205,7 +205,7 @@ StorePath getDerivationEnvironment(ref<Store> store, const StorePath & drvPath) output.second = { .output = DerivationOutputInputAddressed { .path = StorePath::dummy } }; drv.env[output.first] = ""; } - Hash h = std::get<0>(hashDerivationModulo(*store, drv, true)); + Hash h = std::get<0>(hashDerivationModulo(*evalStore, drv, true)); for (auto & output : drv.outputs) { auto outPath = store->makeOutputPath(output.first, h, drv.name); @@ -214,12 +214,12 @@ StorePath getDerivationEnvironment(ref<Store> store, const StorePath & drvPath) } } - auto shellDrvPath = writeDerivation(*store, drv); + auto shellDrvPath = writeDerivation(*evalStore, drv); /* Build the derivation. */ - store->buildPaths({DerivedPath::Built{shellDrvPath}}); + store->buildPaths({DerivedPath::Built{shellDrvPath}}, bmNormal, evalStore); - for (auto & [_0, optPath] : store->queryPartialDerivationOutputMap(shellDrvPath)) { + for (auto & [_0, optPath] : evalStore->queryPartialDerivationOutputMap(shellDrvPath)) { assert(optPath); auto & outPath = *optPath; assert(store->isValidPath(outPath)); @@ -347,7 +347,7 @@ struct Common : InstallableCommand, MixProfile auto & drvPath = *drvs.begin(); - return getDerivationEnvironment(store, drvPath); + return getDerivationEnvironment(store, getEvalStore(), drvPath); } } @@ -361,7 +361,7 @@ struct Common : InstallableCommand, MixProfile debug("reading environment file '%s'", strPath); - return {BuildEnvironment::fromJSON(readFile(strPath)), strPath}; + return {BuildEnvironment::fromJSON(readFile(store->toRealPath(shellOutPath))), strPath}; } };