forked from lix-project/lix
buildPaths(): Add an evalStore argument
With this, we don't have to copy the entire .drv closure to the destination store ahead of time (or at all). Instead, buildPaths() reads .drv files from the eval store and copies inputSrcs to the destination store if it needs to build a derivation. Issue #5025.
This commit is contained in:
parent
668abd3e57
commit
eb6db4fd38
|
@ -766,7 +766,7 @@ BuiltPaths build(ref<Store> evalStore, ref<Store> store, Realise mode,
|
||||||
if (mode == Realise::Nothing)
|
if (mode == Realise::Nothing)
|
||||||
printMissing(store, pathsToBuild, lvlError);
|
printMissing(store, pathsToBuild, lvlError);
|
||||||
else if (mode == Realise::Outputs)
|
else if (mode == Realise::Outputs)
|
||||||
store->buildPaths(pathsToBuild, bMode);
|
store->buildPaths(pathsToBuild, bMode, evalStore);
|
||||||
|
|
||||||
return getBuiltPaths(evalStore, store, pathsToBuild);
|
return getBuiltPaths(evalStore, store, pathsToBuild);
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,7 +165,7 @@ void DerivationGoal::getDerivation()
|
||||||
/* The first thing to do is to make sure that the derivation
|
/* The first thing to do is to make sure that the derivation
|
||||||
exists. If it doesn't, it may be created through a
|
exists. If it doesn't, it may be created through a
|
||||||
substitute. */
|
substitute. */
|
||||||
if (buildMode == bmNormal && worker.store.isValidPath(drvPath)) {
|
if (buildMode == bmNormal && worker.evalStore.isValidPath(drvPath)) {
|
||||||
loadDerivation();
|
loadDerivation();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -188,12 +188,12 @@ void DerivationGoal::loadDerivation()
|
||||||
/* `drvPath' should already be a root, but let's be on the safe
|
/* `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
|
side: if the user forgot to make it a root, we wouldn't want
|
||||||
things being garbage collected while we're busy. */
|
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. */
|
/* Get the derivation. */
|
||||||
drv = std::make_unique<Derivation>(worker.store.derivationFromPath(drvPath));
|
drv = std::make_unique<Derivation>(worker.evalStore.derivationFromPath(drvPath));
|
||||||
|
|
||||||
haveDerivation();
|
haveDerivation();
|
||||||
}
|
}
|
||||||
|
@ -212,8 +212,8 @@ void DerivationGoal::haveDerivation()
|
||||||
if (i.second.second)
|
if (i.second.second)
|
||||||
worker.store.addTempRoot(*i.second.second);
|
worker.store.addTempRoot(*i.second.second);
|
||||||
|
|
||||||
auto outputHashes = staticOutputHashes(worker.store, *drv);
|
auto outputHashes = staticOutputHashes(worker.evalStore, *drv);
|
||||||
for (auto &[outputName, outputHash] : outputHashes)
|
for (auto & [outputName, outputHash] : outputHashes)
|
||||||
initialOutputs.insert({
|
initialOutputs.insert({
|
||||||
outputName,
|
outputName,
|
||||||
InitialOutput{
|
InitialOutput{
|
||||||
|
@ -337,6 +337,16 @@ void DerivationGoal::gaveUpOnSubstitution()
|
||||||
for (auto & i : dynamic_cast<Derivation *>(drv.get())->inputDrvs)
|
for (auto & i : dynamic_cast<Derivation *>(drv.get())->inputDrvs)
|
||||||
addWaitee(worker.makeDerivationGoal(i.first, i.second, buildMode == bmRepair ? bmRepair : bmNormal));
|
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) {
|
for (auto & i : drv->inputSrcs) {
|
||||||
if (worker.store.isValidPath(i)) continue;
|
if (worker.store.isValidPath(i)) continue;
|
||||||
if (!settings.useSubstitutes)
|
if (!settings.useSubstitutes)
|
||||||
|
@ -478,8 +488,8 @@ void DerivationGoal::inputsRealised()
|
||||||
/* Add the relevant output closures of the input derivation
|
/* Add the relevant output closures of the input derivation
|
||||||
`i' as input paths. Only add the closures of output paths
|
`i' as input paths. Only add the closures of output paths
|
||||||
that are specified as inputs. */
|
that are specified as inputs. */
|
||||||
assert(worker.store.isValidPath(drvPath));
|
assert(worker.evalStore.isValidPath(drvPath));
|
||||||
auto outputs = worker.store.queryPartialDerivationOutputMap(depDrvPath);
|
auto outputs = worker.evalStore.queryPartialDerivationOutputMap(depDrvPath);
|
||||||
for (auto & j : wantedDepOutputs) {
|
for (auto & j : wantedDepOutputs) {
|
||||||
if (outputs.count(j) > 0) {
|
if (outputs.count(j) > 0) {
|
||||||
auto optRealizedInput = outputs.at(j);
|
auto optRealizedInput = outputs.at(j);
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
|
|
||||||
namespace nix {
|
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;
|
Goals goals;
|
||||||
for (auto & br : reqs) {
|
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,
|
BuildResult Store::buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
|
||||||
BuildMode buildMode)
|
BuildMode buildMode)
|
||||||
{
|
{
|
||||||
Worker worker(*this);
|
Worker worker(*this, *this);
|
||||||
auto goal = worker.makeBasicDerivationGoal(drvPath, drv, {}, buildMode);
|
auto goal = worker.makeBasicDerivationGoal(drvPath, drv, {}, buildMode);
|
||||||
|
|
||||||
BuildResult result;
|
BuildResult result;
|
||||||
|
@ -93,7 +93,7 @@ void Store::ensurePath(const StorePath & path)
|
||||||
/* If the path is already valid, we're done. */
|
/* If the path is already valid, we're done. */
|
||||||
if (isValidPath(path)) return;
|
if (isValidPath(path)) return;
|
||||||
|
|
||||||
Worker worker(*this);
|
Worker worker(*this, *this);
|
||||||
GoalPtr goal = worker.makePathSubstitutionGoal(path);
|
GoalPtr goal = worker.makePathSubstitutionGoal(path);
|
||||||
Goals goals = {goal};
|
Goals goals = {goal};
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ void Store::ensurePath(const StorePath & path)
|
||||||
|
|
||||||
void LocalStore::repairPath(const StorePath & path)
|
void LocalStore::repairPath(const StorePath & path)
|
||||||
{
|
{
|
||||||
Worker worker(*this);
|
Worker worker(*this, *this);
|
||||||
GoalPtr goal = worker.makePathSubstitutionGoal(path, Repair);
|
GoalPtr goal = worker.makePathSubstitutionGoal(path, Repair);
|
||||||
Goals goals = {goal};
|
Goals goals = {goal};
|
||||||
|
|
||||||
|
|
|
@ -1254,8 +1254,10 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
|
||||||
return next->queryRealisation(id);
|
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");
|
if (buildMode != bmNormal) throw Error("unsupported build mode");
|
||||||
|
|
||||||
StorePathSet newPaths;
|
StorePathSet newPaths;
|
||||||
|
|
|
@ -9,11 +9,12 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
Worker::Worker(Store & store)
|
Worker::Worker(Store & store, Store & evalStore)
|
||||||
: act(*logger, actRealise)
|
: act(*logger, actRealise)
|
||||||
, actDerivations(*logger, actBuilds)
|
, actDerivations(*logger, actBuilds)
|
||||||
, actSubstitutions(*logger, actCopyPaths)
|
, actSubstitutions(*logger, actCopyPaths)
|
||||||
, store(store)
|
, store(store)
|
||||||
|
, evalStore(evalStore)
|
||||||
{
|
{
|
||||||
/* Debugging: prevent recursive workers. */
|
/* Debugging: prevent recursive workers. */
|
||||||
nrLocalBuilds = 0;
|
nrLocalBuilds = 0;
|
||||||
|
|
|
@ -110,6 +110,7 @@ public:
|
||||||
bool checkMismatch;
|
bool checkMismatch;
|
||||||
|
|
||||||
Store & store;
|
Store & store;
|
||||||
|
Store & evalStore;
|
||||||
|
|
||||||
std::unique_ptr<HookInstance> hook;
|
std::unique_ptr<HookInstance> hook;
|
||||||
|
|
||||||
|
@ -131,7 +132,7 @@ public:
|
||||||
it answers with "decline-permanently", we don't try again. */
|
it answers with "decline-permanently", we don't try again. */
|
||||||
bool tryBuildHook = true;
|
bool tryBuildHook = true;
|
||||||
|
|
||||||
Worker(Store & store);
|
Worker(Store & store, Store & evalStore);
|
||||||
~Worker();
|
~Worker();
|
||||||
|
|
||||||
/* Make a goal (with caching). */
|
/* Make a goal (with caching). */
|
||||||
|
|
|
@ -267,8 +267,11 @@ public:
|
||||||
return status;
|
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());
|
auto conn(connections->get());
|
||||||
|
|
||||||
conn->to << cmdBuildPaths;
|
conn->to << cmdBuildPaths;
|
||||||
|
|
|
@ -45,7 +45,7 @@ struct Realisation {
|
||||||
size_t checkSignatures(const PublicKeys & publicKeys) const;
|
size_t checkSignatures(const PublicKeys & publicKeys) const;
|
||||||
|
|
||||||
static std::set<Realisation> closure(Store &, const std::set<Realisation> &);
|
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;
|
bool isCompatibleWith(const Realisation & other) const;
|
||||||
|
|
||||||
|
|
|
@ -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());
|
auto conn(getConnection());
|
||||||
conn->to << wopBuildPaths;
|
conn->to << wopBuildPaths;
|
||||||
assert(GET_PROTOCOL_MINOR(conn->daemonVersion) >= 13);
|
assert(GET_PROTOCOL_MINOR(conn->daemonVersion) >= 13);
|
||||||
|
|
|
@ -85,7 +85,7 @@ public:
|
||||||
|
|
||||||
std::optional<const Realisation> queryRealisation(const DrvOutput &) override;
|
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,
|
BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
|
||||||
BuildMode buildMode) override;
|
BuildMode buildMode) override;
|
||||||
|
|
|
@ -497,7 +497,8 @@ public:
|
||||||
not derivations, substitute them. */
|
not derivations, substitute them. */
|
||||||
virtual void buildPaths(
|
virtual void buildPaths(
|
||||||
const std::vector<DerivedPath> & paths,
|
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
|
/* Build a single non-materialized derivation (i.e. not from an
|
||||||
on-disk .drv file).
|
on-disk .drv file).
|
||||||
|
|
|
@ -341,7 +341,7 @@ static void main_nix_build(int argc, char * * argv)
|
||||||
printMissing(ref<Store>(store), willBuild, willSubstitute, unknown, downloadSize, narSize);
|
printMissing(ref<Store>(store), willBuild, willSubstitute, unknown, downloadSize, narSize);
|
||||||
|
|
||||||
if (!dryRun)
|
if (!dryRun)
|
||||||
store->buildPaths(paths, buildMode);
|
store->buildPaths(paths, buildMode, evalStore);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (runEnv) {
|
if (runEnv) {
|
||||||
|
@ -397,8 +397,6 @@ static void main_nix_build(int argc, char * * argv)
|
||||||
pathsToCopy.insert(src);
|
pathsToCopy.insert(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
copyClosure(*evalStore, *store, pathsToCopy);
|
|
||||||
|
|
||||||
buildPaths(pathsToBuild);
|
buildPaths(pathsToBuild);
|
||||||
|
|
||||||
if (dryRun) return;
|
if (dryRun) return;
|
||||||
|
@ -449,7 +447,7 @@ static void main_nix_build(int argc, char * * argv)
|
||||||
if (env.count("__json")) {
|
if (env.count("__json")) {
|
||||||
StorePathSet inputs;
|
StorePathSet inputs;
|
||||||
for (auto & [depDrvPath, wantedDepOutputs] : drv.inputDrvs) {
|
for (auto & [depDrvPath, wantedDepOutputs] : drv.inputDrvs) {
|
||||||
auto outputs = store->queryPartialDerivationOutputMap(depDrvPath);
|
auto outputs = evalStore->queryPartialDerivationOutputMap(depDrvPath);
|
||||||
for (auto & i : wantedDepOutputs) {
|
for (auto & i : wantedDepOutputs) {
|
||||||
auto o = outputs.at(i);
|
auto o = outputs.at(i);
|
||||||
store->computeFSClosure(*o, inputs);
|
store->computeFSClosure(*o, inputs);
|
||||||
|
@ -564,8 +562,6 @@ static void main_nix_build(int argc, char * * argv)
|
||||||
drvMap[drvPath] = {drvMap.size(), {outputName}};
|
drvMap[drvPath] = {drvMap.size(), {outputName}};
|
||||||
}
|
}
|
||||||
|
|
||||||
copyClosure(*evalStore, *store, drvsToCopy);
|
|
||||||
|
|
||||||
buildPaths(pathsToBuild);
|
buildPaths(pathsToBuild);
|
||||||
|
|
||||||
if (dryRun) return;
|
if (dryRun) return;
|
||||||
|
@ -578,7 +574,7 @@ static void main_nix_build(int argc, char * * argv)
|
||||||
if (counter)
|
if (counter)
|
||||||
drvPrefix += fmt("-%d", counter + 1);
|
drvPrefix += fmt("-%d", counter + 1);
|
||||||
|
|
||||||
auto builtOutputs = store->queryPartialDerivationOutputMap(drvPath);
|
auto builtOutputs = evalStore->queryPartialDerivationOutputMap(drvPath);
|
||||||
|
|
||||||
auto maybeOutputPath = builtOutputs.at(outputName);
|
auto maybeOutputPath = builtOutputs.at(outputName);
|
||||||
assert(maybeOutputPath);
|
assert(maybeOutputPath);
|
||||||
|
|
|
@ -171,15 +171,15 @@ const static std::string getEnvSh =
|
||||||
modified derivation with the same dependencies and nearly the same
|
modified derivation with the same dependencies and nearly the same
|
||||||
initial environment variables, that just writes the resulting
|
initial environment variables, that just writes the resulting
|
||||||
environment to a file and exits. */
|
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);
|
auto builder = baseNameOf(drv.builder);
|
||||||
if (builder != "bash")
|
if (builder != "bash")
|
||||||
throw Error("'nix develop' only works on derivations that use 'bash' as their builder");
|
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)};
|
drv.args = {store->printStorePath(getEnvShPath)};
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ StorePath getDerivationEnvironment(ref<Store> store, const StorePath & drvPath)
|
||||||
output.second = { .output = DerivationOutputInputAddressed { .path = StorePath::dummy } };
|
output.second = { .output = DerivationOutputInputAddressed { .path = StorePath::dummy } };
|
||||||
drv.env[output.first] = "";
|
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) {
|
for (auto & output : drv.outputs) {
|
||||||
auto outPath = store->makeOutputPath(output.first, h, drv.name);
|
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. */
|
/* 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);
|
assert(optPath);
|
||||||
auto & outPath = *optPath;
|
auto & outPath = *optPath;
|
||||||
assert(store->isValidPath(outPath));
|
assert(store->isValidPath(outPath));
|
||||||
|
@ -347,7 +347,7 @@ struct Common : InstallableCommand, MixProfile
|
||||||
|
|
||||||
auto & drvPath = *drvs.begin();
|
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);
|
debug("reading environment file '%s'", strPath);
|
||||||
|
|
||||||
return {BuildEnvironment::fromJSON(readFile(strPath)), strPath};
|
return {BuildEnvironment::fromJSON(readFile(store->toRealPath(shellOutPath))), strPath};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue