2024-07-12 16:37:54 +03:00
|
|
|
|
#include <unordered_set>
|
|
|
|
|
|
Eliminate the "store" global variable
Also, move a few free-standing functions into StoreAPI and Derivation.
Also, introduce a non-nullable smart pointer, ref<T>, which is just a
wrapper around std::shared_ptr ensuring that the pointer is never
null. (For reference-counted values, this is better than passing a
"T&", because the latter doesn't maintain the refcount. Usually, the
caller will have a shared_ptr keeping the value alive, but that's not
always the case, e.g., when passing a reference to a std::thread via
std::bind.)
2016-02-04 15:28:26 +02:00
|
|
|
|
#include "derivations.hh"
|
2019-09-03 17:02:12 +03:00
|
|
|
|
#include "parsed-derivations.hh"
|
2012-05-01 02:15:34 +03:00
|
|
|
|
#include "globals.hh"
|
Eliminate the "store" global variable
Also, move a few free-standing functions into StoreAPI and Derivation.
Also, introduce a non-nullable smart pointer, ref<T>, which is just a
wrapper around std::shared_ptr ensuring that the pointer is never
null. (For reference-counted values, this is better than passing a
"T&", because the latter doesn't maintain the refcount. Usually, the
caller will have a shared_ptr keeping the value alive, but that's not
always the case, e.g., when passing a reference to a std::thread via
std::bind.)
2016-02-04 15:28:26 +02:00
|
|
|
|
#include "store-api.hh"
|
2016-07-21 15:13:35 +03:00
|
|
|
|
#include "thread-pool.hh"
|
2022-03-18 17:35:45 +02:00
|
|
|
|
#include "realisation.hh"
|
2020-07-27 23:45:34 +03:00
|
|
|
|
#include "topo-sort.hh"
|
2020-09-21 19:40:11 +03:00
|
|
|
|
#include "callback.hh"
|
2021-05-18 15:30:32 +03:00
|
|
|
|
#include "closure.hh"
|
2021-12-13 22:08:42 +02:00
|
|
|
|
#include "filetransfer.hh"
|
2006-09-05 00:06:23 +03:00
|
|
|
|
|
|
|
|
|
namespace nix {
|
2004-06-18 21:09:32 +03:00
|
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
|
void Store::computeFSClosure(const StorePathSet & startPaths,
|
|
|
|
|
StorePathSet & paths_, bool flipDirection, bool includeOutputs, bool includeDerivers)
|
2005-01-19 13:16:11 +02:00
|
|
|
|
{
|
2021-05-18 15:30:32 +03:00
|
|
|
|
std::function<std::set<StorePath>(const StorePath & path, std::future<ref<const ValidPathInfo>> &)> queryDeps;
|
|
|
|
|
if (flipDirection)
|
|
|
|
|
queryDeps = [&](const StorePath& path,
|
|
|
|
|
std::future<ref<const ValidPathInfo>> & fut) {
|
|
|
|
|
StorePathSet res;
|
|
|
|
|
StorePathSet referrers;
|
|
|
|
|
queryReferrers(path, referrers);
|
2023-02-01 17:07:54 +02:00
|
|
|
|
for (auto& ref : referrers)
|
2021-05-18 15:30:32 +03:00
|
|
|
|
if (ref != path)
|
|
|
|
|
res.insert(ref);
|
|
|
|
|
|
|
|
|
|
if (includeOutputs)
|
2023-02-01 17:07:54 +02:00
|
|
|
|
for (auto& i : queryValidDerivers(path))
|
2021-05-18 15:30:32 +03:00
|
|
|
|
res.insert(i);
|
|
|
|
|
|
|
|
|
|
if (includeDerivers && path.isDerivation())
|
2023-02-01 17:07:54 +02:00
|
|
|
|
for (auto& [_, maybeOutPath] : queryPartialDerivationOutputMap(path))
|
2021-06-12 13:24:53 +03:00
|
|
|
|
if (maybeOutPath && isValidPath(*maybeOutPath))
|
2021-06-11 10:24:24 +03:00
|
|
|
|
res.insert(*maybeOutPath);
|
2021-05-18 15:30:32 +03:00
|
|
|
|
return res;
|
|
|
|
|
};
|
|
|
|
|
else
|
|
|
|
|
queryDeps = [&](const StorePath& path,
|
|
|
|
|
std::future<ref<const ValidPathInfo>> & fut) {
|
|
|
|
|
StorePathSet res;
|
|
|
|
|
auto info = fut.get();
|
2023-02-01 17:07:54 +02:00
|
|
|
|
for (auto& ref : info->references)
|
2023-01-14 23:38:43 +02:00
|
|
|
|
if (ref != path)
|
|
|
|
|
res.insert(ref);
|
2021-05-18 15:30:32 +03:00
|
|
|
|
|
|
|
|
|
if (includeOutputs && path.isDerivation())
|
2023-02-01 17:07:54 +02:00
|
|
|
|
for (auto& [_, maybeOutPath] : queryPartialDerivationOutputMap(path))
|
2021-06-11 10:24:24 +03:00
|
|
|
|
if (maybeOutPath && isValidPath(*maybeOutPath))
|
|
|
|
|
res.insert(*maybeOutPath);
|
2021-05-18 15:30:32 +03:00
|
|
|
|
|
|
|
|
|
if (includeDerivers && info->deriver && isValidPath(*info->deriver))
|
|
|
|
|
res.insert(*info->deriver);
|
|
|
|
|
return res;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
computeClosure<StorePath>(
|
|
|
|
|
startPaths, paths_,
|
|
|
|
|
[&](const StorePath& path,
|
|
|
|
|
std::function<void(std::promise<std::set<StorePath>>&)>
|
|
|
|
|
processEdges) {
|
|
|
|
|
std::promise<std::set<StorePath>> promise;
|
|
|
|
|
std::function<void(std::future<ref<const ValidPathInfo>>)>
|
|
|
|
|
getDependencies =
|
|
|
|
|
[&](std::future<ref<const ValidPathInfo>> fut) {
|
|
|
|
|
try {
|
|
|
|
|
promise.set_value(queryDeps(path, fut));
|
|
|
|
|
} catch (...) {
|
|
|
|
|
promise.set_exception(std::current_exception());
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
queryPathInfo(path, getDependencies);
|
|
|
|
|
processEdges(promise);
|
|
|
|
|
});
|
2005-02-14 19:35:10 +02:00
|
|
|
|
}
|
2006-03-06 13:21:15 +02:00
|
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
|
void Store::computeFSClosure(const StorePath & startPath,
|
|
|
|
|
StorePathSet & paths_, bool flipDirection, bool includeOutputs, bool includeDerivers)
|
2016-11-10 18:45:04 +02:00
|
|
|
|
{
|
2019-12-05 20:11:09 +02:00
|
|
|
|
StorePathSet paths;
|
2020-06-16 23:20:18 +03:00
|
|
|
|
paths.insert(startPath);
|
2019-12-05 20:11:09 +02:00
|
|
|
|
computeFSClosure(paths, paths_, flipDirection, includeOutputs, includeDerivers);
|
2016-11-10 18:45:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2023-04-19 21:48:53 +03:00
|
|
|
|
const ContentAddress * getDerivationCA(const BasicDerivation & drv)
|
2020-06-12 17:49:09 +03:00
|
|
|
|
{
|
2020-06-22 20:08:11 +03:00
|
|
|
|
auto out = drv.outputs.find("out");
|
2020-10-13 02:51:23 +03:00
|
|
|
|
if (out == drv.outputs.end())
|
2023-04-19 21:48:53 +03:00
|
|
|
|
return nullptr;
|
2023-08-16 19:29:23 +03:00
|
|
|
|
if (auto dof = std::get_if<DerivationOutput::CAFixed>(&out->second.raw)) {
|
2023-04-19 21:48:53 +03:00
|
|
|
|
return &dof->ca;
|
2020-07-30 20:38:24 +03:00
|
|
|
|
}
|
2023-04-19 21:48:53 +03:00
|
|
|
|
return nullptr;
|
2020-06-12 17:49:09 +03:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-05 16:48:18 +03:00
|
|
|
|
void Store::queryMissing(const std::vector<DerivedPath> & targets,
|
2019-12-05 20:11:09 +02:00
|
|
|
|
StorePathSet & willBuild_, StorePathSet & willSubstitute_, StorePathSet & unknown_,
|
2020-07-30 14:10:49 +03:00
|
|
|
|
uint64_t & downloadSize_, uint64_t & narSize_)
|
2006-03-06 13:21:15 +02:00
|
|
|
|
{
|
2017-08-31 17:02:36 +03:00
|
|
|
|
Activity act(*logger, lvlDebug, actUnknown, "querying info about missing paths");
|
|
|
|
|
|
2016-07-21 18:40:40 +03:00
|
|
|
|
downloadSize_ = narSize_ = 0;
|
2006-03-06 13:21:15 +02:00
|
|
|
|
|
2021-12-13 22:08:42 +02:00
|
|
|
|
// FIXME: make async.
|
|
|
|
|
ThreadPool pool(fileTransferSettings.httpConnections);
|
download-from-binary-cache: parallelise fetching of NAR info files
Getting substitute information using the binary cache substituter has
non-trivial latency overhead. A package or NixOS system configuration
can have hundreds of dependencies, and in the worst case (when the
local info cache is empty) we have to do a separate HTTP request for
each of these. If the ping time to the server is t, getting N info
files will take tN seconds; e.g., with a ping time of 0.1s to
nixos.org, sequentially downloading 1000 info files (a typical NixOS
config) will take at least 100 seconds.
To fix this problem, the binary cache substituter can now perform
requests in parallel. This required changing the substituter
interface to support a function querySubstitutablePathInfos() that
queries multiple paths at the same time, and rewriting queryMissing()
to take advantage of parallelism. (Due to local caching,
parallelising queryMissing() is sufficient for most use cases, since
it's almost always called before building a derivation and thus fills
the local info cache.)
For example, parallelism speeds up querying all 1056 paths in a
particular NixOS system configuration from 116s to 2.6s. It works so
well because the eccentricity of the top-level derivation in the
dependency graph is only 9. So we only need 10 round-trips (when
using an unlimited number of parallel connections) to get everything.
Currently we do a maximum of 150 parallel connections to the server.
Thus it's important that the binary cache server (e.g. nixos.org) has
a high connection limit. Alternatively we could use HTTP pipelining,
but WWW::Curl doesn't support it and libcurl has a hard-coded limit of
5 requests per pipeline.
2012-07-07 02:08:20 +03:00
|
|
|
|
|
2016-07-21 18:40:40 +03:00
|
|
|
|
struct State
|
|
|
|
|
{
|
2019-12-05 20:11:09 +02:00
|
|
|
|
std::unordered_set<std::string> done;
|
|
|
|
|
StorePathSet & unknown, & willSubstitute, & willBuild;
|
2020-07-30 14:10:49 +03:00
|
|
|
|
uint64_t & downloadSize;
|
|
|
|
|
uint64_t & narSize;
|
2016-07-21 18:40:40 +03:00
|
|
|
|
};
|
download-from-binary-cache: parallelise fetching of NAR info files
Getting substitute information using the binary cache substituter has
non-trivial latency overhead. A package or NixOS system configuration
can have hundreds of dependencies, and in the worst case (when the
local info cache is empty) we have to do a separate HTTP request for
each of these. If the ping time to the server is t, getting N info
files will take tN seconds; e.g., with a ping time of 0.1s to
nixos.org, sequentially downloading 1000 info files (a typical NixOS
config) will take at least 100 seconds.
To fix this problem, the binary cache substituter can now perform
requests in parallel. This required changing the substituter
interface to support a function querySubstitutablePathInfos() that
queries multiple paths at the same time, and rewriting queryMissing()
to take advantage of parallelism. (Due to local caching,
parallelising queryMissing() is sufficient for most use cases, since
it's almost always called before building a derivation and thus fills
the local info cache.)
For example, parallelism speeds up querying all 1056 paths in a
particular NixOS system configuration from 116s to 2.6s. It works so
well because the eccentricity of the top-level derivation in the
dependency graph is only 9. So we only need 10 round-trips (when
using an unlimited number of parallel connections) to get everything.
Currently we do a maximum of 150 parallel connections to the server.
Thus it's important that the binary cache server (e.g. nixos.org) has
a high connection limit. Alternatively we could use HTTP pipelining,
but WWW::Curl doesn't support it and libcurl has a hard-coded limit of
5 requests per pipeline.
2012-07-07 02:08:20 +03:00
|
|
|
|
|
2016-07-21 18:40:40 +03:00
|
|
|
|
struct DrvState
|
|
|
|
|
{
|
|
|
|
|
size_t left;
|
|
|
|
|
bool done = false;
|
2019-12-05 20:11:09 +02:00
|
|
|
|
StorePathSet outPaths;
|
2016-07-21 18:40:40 +03:00
|
|
|
|
DrvState(size_t left) : left(left) { }
|
|
|
|
|
};
|
download-from-binary-cache: parallelise fetching of NAR info files
Getting substitute information using the binary cache substituter has
non-trivial latency overhead. A package or NixOS system configuration
can have hundreds of dependencies, and in the worst case (when the
local info cache is empty) we have to do a separate HTTP request for
each of these. If the ping time to the server is t, getting N info
files will take tN seconds; e.g., with a ping time of 0.1s to
nixos.org, sequentially downloading 1000 info files (a typical NixOS
config) will take at least 100 seconds.
To fix this problem, the binary cache substituter can now perform
requests in parallel. This required changing the substituter
interface to support a function querySubstitutablePathInfos() that
queries multiple paths at the same time, and rewriting queryMissing()
to take advantage of parallelism. (Due to local caching,
parallelising queryMissing() is sufficient for most use cases, since
it's almost always called before building a derivation and thus fills
the local info cache.)
For example, parallelism speeds up querying all 1056 paths in a
particular NixOS system configuration from 116s to 2.6s. It works so
well because the eccentricity of the top-level derivation in the
dependency graph is only 9. So we only need 10 round-trips (when
using an unlimited number of parallel connections) to get everything.
Currently we do a maximum of 150 parallel connections to the server.
Thus it's important that the binary cache server (e.g. nixos.org) has
a high connection limit. Alternatively we could use HTTP pipelining,
but WWW::Curl doesn't support it and libcurl has a hard-coded limit of
5 requests per pipeline.
2012-07-07 02:08:20 +03:00
|
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
|
Sync<State> state_(State{{}, unknown_, willSubstitute_, willBuild_, downloadSize_, narSize_});
|
download-from-binary-cache: parallelise fetching of NAR info files
Getting substitute information using the binary cache substituter has
non-trivial latency overhead. A package or NixOS system configuration
can have hundreds of dependencies, and in the worst case (when the
local info cache is empty) we have to do a separate HTTP request for
each of these. If the ping time to the server is t, getting N info
files will take tN seconds; e.g., with a ping time of 0.1s to
nixos.org, sequentially downloading 1000 info files (a typical NixOS
config) will take at least 100 seconds.
To fix this problem, the binary cache substituter can now perform
requests in parallel. This required changing the substituter
interface to support a function querySubstitutablePathInfos() that
queries multiple paths at the same time, and rewriting queryMissing()
to take advantage of parallelism. (Due to local caching,
parallelising queryMissing() is sufficient for most use cases, since
it's almost always called before building a derivation and thus fills
the local info cache.)
For example, parallelism speeds up querying all 1056 paths in a
particular NixOS system configuration from 116s to 2.6s. It works so
well because the eccentricity of the top-level derivation in the
dependency graph is only 9. So we only need 10 round-trips (when
using an unlimited number of parallel connections) to get everything.
Currently we do a maximum of 150 parallel connections to the server.
Thus it's important that the binary cache server (e.g. nixos.org) has
a high connection limit. Alternatively we could use HTTP pipelining,
but WWW::Curl doesn't support it and libcurl has a hard-coded limit of
5 requests per pipeline.
2012-07-07 02:08:20 +03:00
|
|
|
|
|
2021-04-05 16:48:18 +03:00
|
|
|
|
std::function<void(DerivedPath)> doPath;
|
download-from-binary-cache: parallelise fetching of NAR info files
Getting substitute information using the binary cache substituter has
non-trivial latency overhead. A package or NixOS system configuration
can have hundreds of dependencies, and in the worst case (when the
local info cache is empty) we have to do a separate HTTP request for
each of these. If the ping time to the server is t, getting N info
files will take tN seconds; e.g., with a ping time of 0.1s to
nixos.org, sequentially downloading 1000 info files (a typical NixOS
config) will take at least 100 seconds.
To fix this problem, the binary cache substituter can now perform
requests in parallel. This required changing the substituter
interface to support a function querySubstitutablePathInfos() that
queries multiple paths at the same time, and rewriting queryMissing()
to take advantage of parallelism. (Due to local caching,
parallelising queryMissing() is sufficient for most use cases, since
it's almost always called before building a derivation and thus fills
the local info cache.)
For example, parallelism speeds up querying all 1056 paths in a
particular NixOS system configuration from 116s to 2.6s. It works so
well because the eccentricity of the top-level derivation in the
dependency graph is only 9. So we only need 10 round-trips (when
using an unlimited number of parallel connections) to get everything.
Currently we do a maximum of 150 parallel connections to the server.
Thus it's important that the binary cache server (e.g. nixos.org) has
a high connection limit. Alternatively we could use HTTP pipelining,
but WWW::Curl doesn't support it and libcurl has a hard-coded limit of
5 requests per pipeline.
2012-07-07 02:08:20 +03:00
|
|
|
|
|
Allow dynamic derivation deps in `inputDrvs`
We use the same nested map representation we used for goals, again in
order to save space. We might someday want to combine with `inputDrvs`,
by doing `V = bool` instead of `V = std::set<OutputName>`, but we are
not doing that yet for sake of a smaller diff.
The ATerm format for Derivations also needs to be extended, in addition
to the in-memory format. To accomodate this, we added a new basic
versioning scheme, so old versions of Nix will get nice errors. (And
going forward, if the ATerm format changes again the errors will be even
better.)
`parsedStrings`, an internal function used as part of parsing
derivations in A-Term format, used to consume the final `]` but expect
the initial `[` to already be consumed. This made for what looked like
unbalanced brackets at callsites, which was confusing. Now it consumes
both which is hopefully less confusing.
As part of testing, we also created a unit test for the A-Term format for
regular non-experimental derivations too.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
Apply suggestions from code review
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
2021-10-02 01:05:53 +03:00
|
|
|
|
std::function<void(ref<SingleDerivedPath>, const DerivedPathMap<StringSet>::ChildNode &)> enqueueDerivedPaths;
|
|
|
|
|
|
|
|
|
|
enqueueDerivedPaths = [&](ref<SingleDerivedPath> inputDrv, const DerivedPathMap<StringSet>::ChildNode & inputNode) {
|
|
|
|
|
if (!inputNode.value.empty())
|
|
|
|
|
pool.enqueue(std::bind(doPath, DerivedPath::Built { inputDrv, inputNode.value }));
|
|
|
|
|
for (const auto & [outputName, childNode] : inputNode.childMap)
|
|
|
|
|
enqueueDerivedPaths(
|
|
|
|
|
make_ref<SingleDerivedPath>(SingleDerivedPath::Built { inputDrv, outputName }),
|
|
|
|
|
childNode);
|
|
|
|
|
};
|
|
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
|
auto mustBuildDrv = [&](const StorePath & drvPath, const Derivation & drv) {
|
2016-07-21 18:40:40 +03:00
|
|
|
|
{
|
|
|
|
|
auto state(state_.lock());
|
2020-06-16 23:20:18 +03:00
|
|
|
|
state->willBuild.insert(drvPath);
|
2016-07-21 18:40:40 +03:00
|
|
|
|
}
|
2012-07-31 02:55:41 +03:00
|
|
|
|
|
Allow dynamic derivation deps in `inputDrvs`
We use the same nested map representation we used for goals, again in
order to save space. We might someday want to combine with `inputDrvs`,
by doing `V = bool` instead of `V = std::set<OutputName>`, but we are
not doing that yet for sake of a smaller diff.
The ATerm format for Derivations also needs to be extended, in addition
to the in-memory format. To accomodate this, we added a new basic
versioning scheme, so old versions of Nix will get nice errors. (And
going forward, if the ATerm format changes again the errors will be even
better.)
`parsedStrings`, an internal function used as part of parsing
derivations in A-Term format, used to consume the final `]` but expect
the initial `[` to already be consumed. This made for what looked like
unbalanced brackets at callsites, which was confusing. Now it consumes
both which is hopefully less confusing.
As part of testing, we also created a unit test for the A-Term format for
regular non-experimental derivations too.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
Apply suggestions from code review
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
2021-10-02 01:05:53 +03:00
|
|
|
|
for (const auto & [inputDrv, inputNode] : drv.inputDrvs.map) {
|
|
|
|
|
enqueueDerivedPaths(makeConstantStorePathRef(inputDrv), inputNode);
|
|
|
|
|
}
|
2016-07-21 18:40:40 +03:00
|
|
|
|
};
|
download-from-binary-cache: parallelise fetching of NAR info files
Getting substitute information using the binary cache substituter has
non-trivial latency overhead. A package or NixOS system configuration
can have hundreds of dependencies, and in the worst case (when the
local info cache is empty) we have to do a separate HTTP request for
each of these. If the ping time to the server is t, getting N info
files will take tN seconds; e.g., with a ping time of 0.1s to
nixos.org, sequentially downloading 1000 info files (a typical NixOS
config) will take at least 100 seconds.
To fix this problem, the binary cache substituter can now perform
requests in parallel. This required changing the substituter
interface to support a function querySubstitutablePathInfos() that
queries multiple paths at the same time, and rewriting queryMissing()
to take advantage of parallelism. (Due to local caching,
parallelising queryMissing() is sufficient for most use cases, since
it's almost always called before building a derivation and thus fills
the local info cache.)
For example, parallelism speeds up querying all 1056 paths in a
particular NixOS system configuration from 116s to 2.6s. It works so
well because the eccentricity of the top-level derivation in the
dependency graph is only 9. So we only need 10 round-trips (when
using an unlimited number of parallel connections) to get everything.
Currently we do a maximum of 150 parallel connections to the server.
Thus it's important that the binary cache server (e.g. nixos.org) has
a high connection limit. Alternatively we could use HTTP pipelining,
but WWW::Curl doesn't support it and libcurl has a hard-coded limit of
5 requests per pipeline.
2012-07-07 02:08:20 +03:00
|
|
|
|
|
2016-07-21 18:40:40 +03:00
|
|
|
|
auto checkOutput = [&](
|
2021-03-05 02:49:46 +02:00
|
|
|
|
const StorePath & drvPath, ref<Derivation> drv, const StorePath & outPath, ref<Sync<DrvState>> drvState_)
|
2016-07-21 18:40:40 +03:00
|
|
|
|
{
|
|
|
|
|
if (drvState_->lock()->done) return;
|
download-from-binary-cache: parallelise fetching of NAR info files
Getting substitute information using the binary cache substituter has
non-trivial latency overhead. A package or NixOS system configuration
can have hundreds of dependencies, and in the worst case (when the
local info cache is empty) we have to do a separate HTTP request for
each of these. If the ping time to the server is t, getting N info
files will take tN seconds; e.g., with a ping time of 0.1s to
nixos.org, sequentially downloading 1000 info files (a typical NixOS
config) will take at least 100 seconds.
To fix this problem, the binary cache substituter can now perform
requests in parallel. This required changing the substituter
interface to support a function querySubstitutablePathInfos() that
queries multiple paths at the same time, and rewriting queryMissing()
to take advantage of parallelism. (Due to local caching,
parallelising queryMissing() is sufficient for most use cases, since
it's almost always called before building a derivation and thus fills
the local info cache.)
For example, parallelism speeds up querying all 1056 paths in a
particular NixOS system configuration from 116s to 2.6s. It works so
well because the eccentricity of the top-level derivation in the
dependency graph is only 9. So we only need 10 round-trips (when
using an unlimited number of parallel connections) to get everything.
Currently we do a maximum of 150 parallel connections to the server.
Thus it's important that the binary cache server (e.g. nixos.org) has
a high connection limit. Alternatively we could use HTTP pipelining,
but WWW::Curl doesn't support it and libcurl has a hard-coded limit of
5 requests per pipeline.
2012-07-07 02:08:20 +03:00
|
|
|
|
|
2016-07-21 18:40:40 +03:00
|
|
|
|
SubstitutablePathInfos infos;
|
2023-04-19 21:48:53 +03:00
|
|
|
|
auto * cap = getDerivationCA(*drv);
|
|
|
|
|
querySubstitutablePathInfos({
|
|
|
|
|
{
|
|
|
|
|
outPath,
|
|
|
|
|
cap ? std::optional { *cap } : std::nullopt,
|
|
|
|
|
},
|
|
|
|
|
}, infos);
|
2012-11-26 16:39:10 +02:00
|
|
|
|
|
2016-07-21 18:40:40 +03:00
|
|
|
|
if (infos.empty()) {
|
|
|
|
|
drvState_->lock()->done = true;
|
|
|
|
|
mustBuildDrv(drvPath, *drv);
|
|
|
|
|
} else {
|
|
|
|
|
{
|
|
|
|
|
auto drvState(drvState_->lock());
|
|
|
|
|
if (drvState->done) return;
|
|
|
|
|
assert(drvState->left);
|
|
|
|
|
drvState->left--;
|
2020-06-16 23:20:18 +03:00
|
|
|
|
drvState->outPaths.insert(outPath);
|
2016-07-21 18:40:40 +03:00
|
|
|
|
if (!drvState->left) {
|
|
|
|
|
for (auto & path : drvState->outPaths)
|
2021-04-05 16:48:18 +03:00
|
|
|
|
pool.enqueue(std::bind(doPath, DerivedPath::Opaque { path } ));
|
download-from-binary-cache: parallelise fetching of NAR info files
Getting substitute information using the binary cache substituter has
non-trivial latency overhead. A package or NixOS system configuration
can have hundreds of dependencies, and in the worst case (when the
local info cache is empty) we have to do a separate HTTP request for
each of these. If the ping time to the server is t, getting N info
files will take tN seconds; e.g., with a ping time of 0.1s to
nixos.org, sequentially downloading 1000 info files (a typical NixOS
config) will take at least 100 seconds.
To fix this problem, the binary cache substituter can now perform
requests in parallel. This required changing the substituter
interface to support a function querySubstitutablePathInfos() that
queries multiple paths at the same time, and rewriting queryMissing()
to take advantage of parallelism. (Due to local caching,
parallelising queryMissing() is sufficient for most use cases, since
it's almost always called before building a derivation and thus fills
the local info cache.)
For example, parallelism speeds up querying all 1056 paths in a
particular NixOS system configuration from 116s to 2.6s. It works so
well because the eccentricity of the top-level derivation in the
dependency graph is only 9. So we only need 10 round-trips (when
using an unlimited number of parallel connections) to get everything.
Currently we do a maximum of 150 parallel connections to the server.
Thus it's important that the binary cache server (e.g. nixos.org) has
a high connection limit. Alternatively we could use HTTP pipelining,
but WWW::Curl doesn't support it and libcurl has a hard-coded limit of
5 requests per pipeline.
2012-07-07 02:08:20 +03:00
|
|
|
|
}
|
2008-08-04 14:44:50 +03:00
|
|
|
|
}
|
download-from-binary-cache: parallelise fetching of NAR info files
Getting substitute information using the binary cache substituter has
non-trivial latency overhead. A package or NixOS system configuration
can have hundreds of dependencies, and in the worst case (when the
local info cache is empty) we have to do a separate HTTP request for
each of these. If the ping time to the server is t, getting N info
files will take tN seconds; e.g., with a ping time of 0.1s to
nixos.org, sequentially downloading 1000 info files (a typical NixOS
config) will take at least 100 seconds.
To fix this problem, the binary cache substituter can now perform
requests in parallel. This required changing the substituter
interface to support a function querySubstitutablePathInfos() that
queries multiple paths at the same time, and rewriting queryMissing()
to take advantage of parallelism. (Due to local caching,
parallelising queryMissing() is sufficient for most use cases, since
it's almost always called before building a derivation and thus fills
the local info cache.)
For example, parallelism speeds up querying all 1056 paths in a
particular NixOS system configuration from 116s to 2.6s. It works so
well because the eccentricity of the top-level derivation in the
dependency graph is only 9. So we only need 10 round-trips (when
using an unlimited number of parallel connections) to get everything.
Currently we do a maximum of 150 parallel connections to the server.
Thus it's important that the binary cache server (e.g. nixos.org) has
a high connection limit. Alternatively we could use HTTP pipelining,
but WWW::Curl doesn't support it and libcurl has a hard-coded limit of
5 requests per pipeline.
2012-07-07 02:08:20 +03:00
|
|
|
|
}
|
2016-07-21 18:40:40 +03:00
|
|
|
|
};
|
download-from-binary-cache: parallelise fetching of NAR info files
Getting substitute information using the binary cache substituter has
non-trivial latency overhead. A package or NixOS system configuration
can have hundreds of dependencies, and in the worst case (when the
local info cache is empty) we have to do a separate HTTP request for
each of these. If the ping time to the server is t, getting N info
files will take tN seconds; e.g., with a ping time of 0.1s to
nixos.org, sequentially downloading 1000 info files (a typical NixOS
config) will take at least 100 seconds.
To fix this problem, the binary cache substituter can now perform
requests in parallel. This required changing the substituter
interface to support a function querySubstitutablePathInfos() that
queries multiple paths at the same time, and rewriting queryMissing()
to take advantage of parallelism. (Due to local caching,
parallelising queryMissing() is sufficient for most use cases, since
it's almost always called before building a derivation and thus fills
the local info cache.)
For example, parallelism speeds up querying all 1056 paths in a
particular NixOS system configuration from 116s to 2.6s. It works so
well because the eccentricity of the top-level derivation in the
dependency graph is only 9. So we only need 10 round-trips (when
using an unlimited number of parallel connections) to get everything.
Currently we do a maximum of 150 parallel connections to the server.
Thus it's important that the binary cache server (e.g. nixos.org) has
a high connection limit. Alternatively we could use HTTP pipelining,
but WWW::Curl doesn't support it and libcurl has a hard-coded limit of
5 requests per pipeline.
2012-07-07 02:08:20 +03:00
|
|
|
|
|
2021-04-05 16:48:18 +03:00
|
|
|
|
doPath = [&](const DerivedPath & req) {
|
2012-07-31 02:55:41 +03:00
|
|
|
|
|
2016-07-21 18:40:40 +03:00
|
|
|
|
{
|
|
|
|
|
auto state(state_.lock());
|
2021-04-05 16:24:42 +03:00
|
|
|
|
if (!state->done.insert(req.to_string(*this)).second) return;
|
2016-07-21 18:40:40 +03:00
|
|
|
|
}
|
download-from-binary-cache: parallelise fetching of NAR info files
Getting substitute information using the binary cache substituter has
non-trivial latency overhead. A package or NixOS system configuration
can have hundreds of dependencies, and in the worst case (when the
local info cache is empty) we have to do a separate HTTP request for
each of these. If the ping time to the server is t, getting N info
files will take tN seconds; e.g., with a ping time of 0.1s to
nixos.org, sequentially downloading 1000 info files (a typical NixOS
config) will take at least 100 seconds.
To fix this problem, the binary cache substituter can now perform
requests in parallel. This required changing the substituter
interface to support a function querySubstitutablePathInfos() that
queries multiple paths at the same time, and rewriting queryMissing()
to take advantage of parallelism. (Due to local caching,
parallelising queryMissing() is sufficient for most use cases, since
it's almost always called before building a derivation and thus fills
the local info cache.)
For example, parallelism speeds up querying all 1056 paths in a
particular NixOS system configuration from 116s to 2.6s. It works so
well because the eccentricity of the top-level derivation in the
dependency graph is only 9. So we only need 10 round-trips (when
using an unlimited number of parallel connections) to get everything.
Currently we do a maximum of 150 parallel connections to the server.
Thus it's important that the binary cache server (e.g. nixos.org) has
a high connection limit. Alternatively we could use HTTP pipelining,
but WWW::Curl doesn't support it and libcurl has a hard-coded limit of
5 requests per pipeline.
2012-07-07 02:08:20 +03:00
|
|
|
|
|
2021-03-02 05:50:41 +02:00
|
|
|
|
std::visit(overloaded {
|
2021-10-01 00:31:21 +03:00
|
|
|
|
[&](const DerivedPath::Built & bfd) {
|
Make the Derived Path family of types inductive for dynamic derivations
We want to be able to write down `foo.drv^bar.drv^baz`:
`foo.drv^bar.drv` is the dynamic derivation (since it is itself a
derivation output, `bar.drv` from `foo.drv`).
To that end, we create `Single{Derivation,BuiltPath}` types, that are
very similar except instead of having multiple outputs (in a set or
map), they have a single one. This is for everything to the left of the
rightmost `^`.
`NixStringContextElem` has an analogous change, and now can reuse
`SingleDerivedPath` at the top level. In fact, if we ever get rid of
`DrvDeep`, `NixStringContextElem` could be replaced with
`SingleDerivedPath` entirely!
Important note: some JSON formats have changed.
We already can *produce* dynamic derivations, but we can't refer to them
directly. Today, we can merely express building or example at the top
imperatively over time by building `foo.drv^bar.drv`, and then with a
second nix invocation doing `<result-from-first>^baz`, but this is not
declarative. The ethos of Nix of being able to write down the full plan
everything you want to do, and then execute than plan with a single
command, and for that we need the new inductive form of these types.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
2023-01-16 00:39:04 +02:00
|
|
|
|
auto drvPathP = std::get_if<DerivedPath::Opaque>(&*bfd.drvPath);
|
|
|
|
|
if (!drvPathP) {
|
|
|
|
|
// TODO make work in this case.
|
|
|
|
|
warn("Ignoring dynamic derivation %s while querying missing paths; not yet implemented", bfd.drvPath->to_string(*this));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
auto & drvPath = drvPathP->path;
|
|
|
|
|
|
|
|
|
|
if (!isValidPath(drvPath)) {
|
2016-07-21 18:40:40 +03:00
|
|
|
|
// FIXME: we could try to substitute the derivation.
|
|
|
|
|
auto state(state_.lock());
|
Make the Derived Path family of types inductive for dynamic derivations
We want to be able to write down `foo.drv^bar.drv^baz`:
`foo.drv^bar.drv` is the dynamic derivation (since it is itself a
derivation output, `bar.drv` from `foo.drv`).
To that end, we create `Single{Derivation,BuiltPath}` types, that are
very similar except instead of having multiple outputs (in a set or
map), they have a single one. This is for everything to the left of the
rightmost `^`.
`NixStringContextElem` has an analogous change, and now can reuse
`SingleDerivedPath` at the top level. In fact, if we ever get rid of
`DrvDeep`, `NixStringContextElem` could be replaced with
`SingleDerivedPath` entirely!
Important note: some JSON formats have changed.
We already can *produce* dynamic derivations, but we can't refer to them
directly. Today, we can merely express building or example at the top
imperatively over time by building `foo.drv^bar.drv`, and then with a
second nix invocation doing `<result-from-first>^baz`, but this is not
declarative. The ethos of Nix of being able to write down the full plan
everything you want to do, and then execute than plan with a single
command, and for that we need the new inductive form of these types.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
2023-01-16 00:39:04 +02:00
|
|
|
|
state->unknown.insert(drvPath);
|
2016-07-21 18:40:40 +03:00
|
|
|
|
return;
|
|
|
|
|
}
|
2012-11-26 18:15:09 +02:00
|
|
|
|
|
2021-03-05 02:49:46 +02:00
|
|
|
|
StorePathSet invalid;
|
2020-08-07 22:09:26 +03:00
|
|
|
|
/* true for regular derivations, and CA derivations for which we
|
|
|
|
|
have a trust mapping for all wanted outputs. */
|
|
|
|
|
auto knownOutputPaths = true;
|
Make the Derived Path family of types inductive for dynamic derivations
We want to be able to write down `foo.drv^bar.drv^baz`:
`foo.drv^bar.drv` is the dynamic derivation (since it is itself a
derivation output, `bar.drv` from `foo.drv`).
To that end, we create `Single{Derivation,BuiltPath}` types, that are
very similar except instead of having multiple outputs (in a set or
map), they have a single one. This is for everything to the left of the
rightmost `^`.
`NixStringContextElem` has an analogous change, and now can reuse
`SingleDerivedPath` at the top level. In fact, if we ever get rid of
`DrvDeep`, `NixStringContextElem` could be replaced with
`SingleDerivedPath` entirely!
Important note: some JSON formats have changed.
We already can *produce* dynamic derivations, but we can't refer to them
directly. Today, we can merely express building or example at the top
imperatively over time by building `foo.drv^bar.drv`, and then with a
second nix invocation doing `<result-from-first>^baz`, but this is not
declarative. The ethos of Nix of being able to write down the full plan
everything you want to do, and then execute than plan with a single
command, and for that we need the new inductive form of these types.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
2023-01-16 00:39:04 +02:00
|
|
|
|
for (auto & [outputName, pathOpt] : queryPartialDerivationOutputMap(drvPath)) {
|
2020-08-07 22:09:26 +03:00
|
|
|
|
if (!pathOpt) {
|
|
|
|
|
knownOutputPaths = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2023-01-12 01:57:18 +02:00
|
|
|
|
if (bfd.outputs.contains(outputName) && !isValidPath(*pathOpt))
|
2021-03-05 02:49:46 +02:00
|
|
|
|
invalid.insert(*pathOpt);
|
2020-08-07 22:09:26 +03:00
|
|
|
|
}
|
|
|
|
|
if (knownOutputPaths && invalid.empty()) return;
|
|
|
|
|
|
Make the Derived Path family of types inductive for dynamic derivations
We want to be able to write down `foo.drv^bar.drv^baz`:
`foo.drv^bar.drv` is the dynamic derivation (since it is itself a
derivation output, `bar.drv` from `foo.drv`).
To that end, we create `Single{Derivation,BuiltPath}` types, that are
very similar except instead of having multiple outputs (in a set or
map), they have a single one. This is for everything to the left of the
rightmost `^`.
`NixStringContextElem` has an analogous change, and now can reuse
`SingleDerivedPath` at the top level. In fact, if we ever get rid of
`DrvDeep`, `NixStringContextElem` could be replaced with
`SingleDerivedPath` entirely!
Important note: some JSON formats have changed.
We already can *produce* dynamic derivations, but we can't refer to them
directly. Today, we can merely express building or example at the top
imperatively over time by building `foo.drv^bar.drv`, and then with a
second nix invocation doing `<result-from-first>^baz`, but this is not
declarative. The ethos of Nix of being able to write down the full plan
everything you want to do, and then execute than plan with a single
command, and for that we need the new inductive form of these types.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
2023-01-16 00:39:04 +02:00
|
|
|
|
auto drv = make_ref<Derivation>(derivationFromPath(drvPath));
|
|
|
|
|
ParsedDerivation parsedDrv(StorePath(drvPath), *drv);
|
2006-03-06 13:21:15 +02:00
|
|
|
|
|
2023-06-30 18:11:12 +03:00
|
|
|
|
if (!knownOutputPaths && settings.useSubstitutes && parsedDrv.substitutesAllowed()) {
|
|
|
|
|
experimentalFeatureSettings.require(Xp::CaDerivations);
|
|
|
|
|
|
|
|
|
|
// If there are unknown output paths, attempt to find if the
|
|
|
|
|
// paths are known to substituters through a realisation.
|
|
|
|
|
auto outputHashes = staticOutputHashes(*this, *drv);
|
|
|
|
|
knownOutputPaths = true;
|
|
|
|
|
|
|
|
|
|
for (auto [outputName, hash] : outputHashes) {
|
|
|
|
|
if (!bfd.outputs.contains(outputName))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
bool found = false;
|
|
|
|
|
for (auto &sub : getDefaultSubstituters()) {
|
|
|
|
|
auto realisation = sub->queryRealisation({hash, outputName});
|
|
|
|
|
if (!realisation)
|
|
|
|
|
continue;
|
|
|
|
|
found = true;
|
|
|
|
|
if (!isValidPath(realisation->outPath))
|
|
|
|
|
invalid.insert(realisation->outPath);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!found) {
|
|
|
|
|
// Some paths did not have a realisation, this must be built.
|
|
|
|
|
knownOutputPaths = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-07 22:09:26 +03:00
|
|
|
|
if (knownOutputPaths && settings.useSubstitutes && parsedDrv.substitutesAllowed()) {
|
2016-07-21 18:40:40 +03:00
|
|
|
|
auto drvState = make_ref<Sync<DrvState>>(DrvState(invalid.size()));
|
|
|
|
|
for (auto & output : invalid)
|
Make the Derived Path family of types inductive for dynamic derivations
We want to be able to write down `foo.drv^bar.drv^baz`:
`foo.drv^bar.drv` is the dynamic derivation (since it is itself a
derivation output, `bar.drv` from `foo.drv`).
To that end, we create `Single{Derivation,BuiltPath}` types, that are
very similar except instead of having multiple outputs (in a set or
map), they have a single one. This is for everything to the left of the
rightmost `^`.
`NixStringContextElem` has an analogous change, and now can reuse
`SingleDerivedPath` at the top level. In fact, if we ever get rid of
`DrvDeep`, `NixStringContextElem` could be replaced with
`SingleDerivedPath` entirely!
Important note: some JSON formats have changed.
We already can *produce* dynamic derivations, but we can't refer to them
directly. Today, we can merely express building or example at the top
imperatively over time by building `foo.drv^bar.drv`, and then with a
second nix invocation doing `<result-from-first>^baz`, but this is not
declarative. The ethos of Nix of being able to write down the full plan
everything you want to do, and then execute than plan with a single
command, and for that we need the new inductive form of these types.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
2023-01-16 00:39:04 +02:00
|
|
|
|
pool.enqueue(std::bind(checkOutput, drvPath, drv, output, drvState));
|
download-from-binary-cache: parallelise fetching of NAR info files
Getting substitute information using the binary cache substituter has
non-trivial latency overhead. A package or NixOS system configuration
can have hundreds of dependencies, and in the worst case (when the
local info cache is empty) we have to do a separate HTTP request for
each of these. If the ping time to the server is t, getting N info
files will take tN seconds; e.g., with a ping time of 0.1s to
nixos.org, sequentially downloading 1000 info files (a typical NixOS
config) will take at least 100 seconds.
To fix this problem, the binary cache substituter can now perform
requests in parallel. This required changing the substituter
interface to support a function querySubstitutablePathInfos() that
queries multiple paths at the same time, and rewriting queryMissing()
to take advantage of parallelism. (Due to local caching,
parallelising queryMissing() is sufficient for most use cases, since
it's almost always called before building a derivation and thus fills
the local info cache.)
For example, parallelism speeds up querying all 1056 paths in a
particular NixOS system configuration from 116s to 2.6s. It works so
well because the eccentricity of the top-level derivation in the
dependency graph is only 9. So we only need 10 round-trips (when
using an unlimited number of parallel connections) to get everything.
Currently we do a maximum of 150 parallel connections to the server.
Thus it's important that the binary cache server (e.g. nixos.org) has
a high connection limit. Alternatively we could use HTTP pipelining,
but WWW::Curl doesn't support it and libcurl has a hard-coded limit of
5 requests per pipeline.
2012-07-07 02:08:20 +03:00
|
|
|
|
} else
|
Make the Derived Path family of types inductive for dynamic derivations
We want to be able to write down `foo.drv^bar.drv^baz`:
`foo.drv^bar.drv` is the dynamic derivation (since it is itself a
derivation output, `bar.drv` from `foo.drv`).
To that end, we create `Single{Derivation,BuiltPath}` types, that are
very similar except instead of having multiple outputs (in a set or
map), they have a single one. This is for everything to the left of the
rightmost `^`.
`NixStringContextElem` has an analogous change, and now can reuse
`SingleDerivedPath` at the top level. In fact, if we ever get rid of
`DrvDeep`, `NixStringContextElem` could be replaced with
`SingleDerivedPath` entirely!
Important note: some JSON formats have changed.
We already can *produce* dynamic derivations, but we can't refer to them
directly. Today, we can merely express building or example at the top
imperatively over time by building `foo.drv^bar.drv`, and then with a
second nix invocation doing `<result-from-first>^baz`, but this is not
declarative. The ethos of Nix of being able to write down the full plan
everything you want to do, and then execute than plan with a single
command, and for that we need the new inductive form of these types.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
2023-01-16 00:39:04 +02:00
|
|
|
|
mustBuildDrv(drvPath, *drv);
|
2006-03-06 13:21:15 +02:00
|
|
|
|
|
2021-03-02 05:50:41 +02:00
|
|
|
|
},
|
2021-10-01 00:31:21 +03:00
|
|
|
|
[&](const DerivedPath::Opaque & bo) {
|
2012-07-31 02:55:41 +03:00
|
|
|
|
|
2021-03-02 05:50:41 +02:00
|
|
|
|
if (isValidPath(bo.path)) return;
|
2016-07-21 18:40:40 +03:00
|
|
|
|
|
|
|
|
|
SubstitutablePathInfos infos;
|
2021-03-02 05:50:41 +02:00
|
|
|
|
querySubstitutablePathInfos({{bo.path, std::nullopt}}, infos);
|
2016-07-21 18:40:40 +03:00
|
|
|
|
|
|
|
|
|
if (infos.empty()) {
|
|
|
|
|
auto state(state_.lock());
|
2021-03-02 05:50:41 +02:00
|
|
|
|
state->unknown.insert(bo.path);
|
2016-07-21 18:40:40 +03:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-02 05:50:41 +02:00
|
|
|
|
auto info = infos.find(bo.path);
|
2016-07-21 18:40:40 +03:00
|
|
|
|
assert(info != infos.end());
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
auto state(state_.lock());
|
2021-03-02 05:50:41 +02:00
|
|
|
|
state->willSubstitute.insert(bo.path);
|
2016-07-21 18:40:40 +03:00
|
|
|
|
state->downloadSize += info->second.downloadSize;
|
|
|
|
|
state->narSize += info->second.narSize;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-14 23:38:43 +02:00
|
|
|
|
for (auto & ref : info->second.references)
|
2021-04-05 16:48:18 +03:00
|
|
|
|
pool.enqueue(std::bind(doPath, DerivedPath::Opaque { ref }));
|
2021-03-02 05:50:41 +02:00
|
|
|
|
},
|
2021-04-05 16:24:42 +03:00
|
|
|
|
}, req.raw());
|
2016-07-21 18:40:40 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (auto & path : targets)
|
|
|
|
|
pool.enqueue(std::bind(doPath, path));
|
|
|
|
|
|
|
|
|
|
pool.process();
|
2006-03-06 13:21:15 +02:00
|
|
|
|
}
|
2006-09-05 00:06:23 +03:00
|
|
|
|
|
2012-07-31 02:55:41 +03:00
|
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
|
StorePaths Store::topoSortPaths(const StorePathSet & paths)
|
2011-12-30 17:02:50 +02:00
|
|
|
|
{
|
2020-07-27 23:45:34 +03:00
|
|
|
|
return topoSort(paths,
|
|
|
|
|
{[&](const StorePath & path) {
|
|
|
|
|
try {
|
2023-01-14 23:38:43 +02:00
|
|
|
|
return queryPathInfo(path)->references;
|
2020-07-27 23:45:34 +03:00
|
|
|
|
} catch (InvalidPath &) {
|
2021-10-14 11:04:13 +03:00
|
|
|
|
return StorePathSet();
|
2020-07-27 23:45:34 +03:00
|
|
|
|
}
|
|
|
|
|
}},
|
|
|
|
|
{[&](const StorePath & path, const StorePath & parent) {
|
|
|
|
|
return BuildError(
|
|
|
|
|
"cycle detected in the references of '%s' from '%s'",
|
|
|
|
|
printStorePath(path),
|
|
|
|
|
printStorePath(parent));
|
|
|
|
|
}});
|
2011-12-30 17:02:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 17:09:02 +03:00
|
|
|
|
std::map<DrvOutput, StorePath> drvOutputReferences(
|
2021-06-21 17:37:45 +03:00
|
|
|
|
const std::set<Realisation> & inputRealisations,
|
|
|
|
|
const StorePathSet & pathReferences)
|
2021-05-19 11:35:31 +03:00
|
|
|
|
{
|
2021-05-26 17:09:02 +03:00
|
|
|
|
std::map<DrvOutput, StorePath> res;
|
2011-12-30 17:02:50 +02:00
|
|
|
|
|
2021-05-26 17:09:02 +03:00
|
|
|
|
for (const auto & input : inputRealisations) {
|
|
|
|
|
if (pathReferences.count(input.outPath)) {
|
|
|
|
|
res.insert({input.id, input.outPath});
|
|
|
|
|
}
|
2021-05-19 11:35:31 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
2011-12-30 17:02:50 +02:00
|
|
|
|
|
2021-05-26 17:09:02 +03:00
|
|
|
|
std::map<DrvOutput, StorePath> drvOutputReferences(
|
2021-05-19 11:35:31 +03:00
|
|
|
|
Store & store,
|
|
|
|
|
const Derivation & drv,
|
2023-12-11 04:21:21 +02:00
|
|
|
|
const StorePath & outputPath,
|
|
|
|
|
Store * evalStore_)
|
2021-05-19 11:35:31 +03:00
|
|
|
|
{
|
2023-12-11 04:21:21 +02:00
|
|
|
|
auto & evalStore = evalStore_ ? *evalStore_ : store;
|
|
|
|
|
|
2021-05-19 11:35:31 +03:00
|
|
|
|
std::set<Realisation> inputRealisations;
|
|
|
|
|
|
Allow dynamic derivation deps in `inputDrvs`
We use the same nested map representation we used for goals, again in
order to save space. We might someday want to combine with `inputDrvs`,
by doing `V = bool` instead of `V = std::set<OutputName>`, but we are
not doing that yet for sake of a smaller diff.
The ATerm format for Derivations also needs to be extended, in addition
to the in-memory format. To accomodate this, we added a new basic
versioning scheme, so old versions of Nix will get nice errors. (And
going forward, if the ATerm format changes again the errors will be even
better.)
`parsedStrings`, an internal function used as part of parsing
derivations in A-Term format, used to consume the final `]` but expect
the initial `[` to already be consumed. This made for what looked like
unbalanced brackets at callsites, which was confusing. Now it consumes
both which is hopefully less confusing.
As part of testing, we also created a unit test for the A-Term format for
regular non-experimental derivations too.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
Apply suggestions from code review
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
2021-10-02 01:05:53 +03:00
|
|
|
|
std::function<void(const StorePath &, const DerivedPathMap<StringSet>::ChildNode &)> accumRealisations;
|
|
|
|
|
|
|
|
|
|
accumRealisations = [&](const StorePath & inputDrv, const DerivedPathMap<StringSet>::ChildNode & inputNode) {
|
|
|
|
|
if (!inputNode.value.empty()) {
|
|
|
|
|
auto outputHashes =
|
2023-12-11 04:21:21 +02:00
|
|
|
|
staticOutputHashes(evalStore, evalStore.readDerivation(inputDrv));
|
Allow dynamic derivation deps in `inputDrvs`
We use the same nested map representation we used for goals, again in
order to save space. We might someday want to combine with `inputDrvs`,
by doing `V = bool` instead of `V = std::set<OutputName>`, but we are
not doing that yet for sake of a smaller diff.
The ATerm format for Derivations also needs to be extended, in addition
to the in-memory format. To accomodate this, we added a new basic
versioning scheme, so old versions of Nix will get nice errors. (And
going forward, if the ATerm format changes again the errors will be even
better.)
`parsedStrings`, an internal function used as part of parsing
derivations in A-Term format, used to consume the final `]` but expect
the initial `[` to already be consumed. This made for what looked like
unbalanced brackets at callsites, which was confusing. Now it consumes
both which is hopefully less confusing.
As part of testing, we also created a unit test for the A-Term format for
regular non-experimental derivations too.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
Apply suggestions from code review
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
2021-10-02 01:05:53 +03:00
|
|
|
|
for (const auto & outputName : inputNode.value) {
|
|
|
|
|
auto outputHash = get(outputHashes, outputName);
|
|
|
|
|
if (!outputHash)
|
|
|
|
|
throw Error(
|
|
|
|
|
"output '%s' of derivation '%s' isn't realised", outputName,
|
|
|
|
|
store.printStorePath(inputDrv));
|
|
|
|
|
auto thisRealisation = store.queryRealisation(
|
|
|
|
|
DrvOutput{*outputHash, outputName});
|
|
|
|
|
if (!thisRealisation)
|
|
|
|
|
throw Error(
|
|
|
|
|
"output '%s' of derivation '%s' isn’t built", outputName,
|
|
|
|
|
store.printStorePath(inputDrv));
|
|
|
|
|
inputRealisations.insert(*thisRealisation);
|
|
|
|
|
}
|
2021-05-19 11:35:31 +03:00
|
|
|
|
}
|
Allow dynamic derivation deps in `inputDrvs`
We use the same nested map representation we used for goals, again in
order to save space. We might someday want to combine with `inputDrvs`,
by doing `V = bool` instead of `V = std::set<OutputName>`, but we are
not doing that yet for sake of a smaller diff.
The ATerm format for Derivations also needs to be extended, in addition
to the in-memory format. To accomodate this, we added a new basic
versioning scheme, so old versions of Nix will get nice errors. (And
going forward, if the ATerm format changes again the errors will be even
better.)
`parsedStrings`, an internal function used as part of parsing
derivations in A-Term format, used to consume the final `]` but expect
the initial `[` to already be consumed. This made for what looked like
unbalanced brackets at callsites, which was confusing. Now it consumes
both which is hopefully less confusing.
As part of testing, we also created a unit test for the A-Term format for
regular non-experimental derivations too.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
Apply suggestions from code review
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
2021-10-02 01:05:53 +03:00
|
|
|
|
if (!inputNode.value.empty()) {
|
|
|
|
|
auto d = makeConstantStorePathRef(inputDrv);
|
|
|
|
|
for (const auto & [outputName, childNode] : inputNode.childMap) {
|
|
|
|
|
SingleDerivedPath next = SingleDerivedPath::Built { d, outputName };
|
|
|
|
|
accumRealisations(
|
|
|
|
|
// TODO deep resolutions for dynamic derivations, issue #8947, would go here.
|
2023-12-11 04:21:21 +02:00
|
|
|
|
resolveDerivedPath(store, next, evalStore_),
|
Allow dynamic derivation deps in `inputDrvs`
We use the same nested map representation we used for goals, again in
order to save space. We might someday want to combine with `inputDrvs`,
by doing `V = bool` instead of `V = std::set<OutputName>`, but we are
not doing that yet for sake of a smaller diff.
The ATerm format for Derivations also needs to be extended, in addition
to the in-memory format. To accomodate this, we added a new basic
versioning scheme, so old versions of Nix will get nice errors. (And
going forward, if the ATerm format changes again the errors will be even
better.)
`parsedStrings`, an internal function used as part of parsing
derivations in A-Term format, used to consume the final `]` but expect
the initial `[` to already be consumed. This made for what looked like
unbalanced brackets at callsites, which was confusing. Now it consumes
both which is hopefully less confusing.
As part of testing, we also created a unit test for the A-Term format for
regular non-experimental derivations too.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
Apply suggestions from code review
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
2021-10-02 01:05:53 +03:00
|
|
|
|
childNode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (const auto & [inputDrv, inputNode] : drv.inputDrvs.map)
|
|
|
|
|
accumRealisations(inputDrv, inputNode);
|
2021-05-19 11:35:31 +03:00
|
|
|
|
|
|
|
|
|
auto info = store.queryPathInfo(outputPath);
|
|
|
|
|
|
2023-01-14 23:38:43 +02:00
|
|
|
|
return drvOutputReferences(Realisation::closure(store, inputRealisations), info->references);
|
2021-05-19 11:35:31 +03:00
|
|
|
|
}
|
2022-03-11 14:23:23 +02:00
|
|
|
|
|
2023-01-12 01:57:18 +02:00
|
|
|
|
OutputPathMap resolveDerivedPath(Store & store, const DerivedPath::Built & bfd, Store * evalStore_)
|
|
|
|
|
{
|
Make the Derived Path family of types inductive for dynamic derivations
We want to be able to write down `foo.drv^bar.drv^baz`:
`foo.drv^bar.drv` is the dynamic derivation (since it is itself a
derivation output, `bar.drv` from `foo.drv`).
To that end, we create `Single{Derivation,BuiltPath}` types, that are
very similar except instead of having multiple outputs (in a set or
map), they have a single one. This is for everything to the left of the
rightmost `^`.
`NixStringContextElem` has an analogous change, and now can reuse
`SingleDerivedPath` at the top level. In fact, if we ever get rid of
`DrvDeep`, `NixStringContextElem` could be replaced with
`SingleDerivedPath` entirely!
Important note: some JSON formats have changed.
We already can *produce* dynamic derivations, but we can't refer to them
directly. Today, we can merely express building or example at the top
imperatively over time by building `foo.drv^bar.drv`, and then with a
second nix invocation doing `<result-from-first>^baz`, but this is not
declarative. The ethos of Nix of being able to write down the full plan
everything you want to do, and then execute than plan with a single
command, and for that we need the new inductive form of these types.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
2023-01-16 00:39:04 +02:00
|
|
|
|
auto drvPath = resolveDerivedPath(store, *bfd.drvPath, evalStore_);
|
|
|
|
|
|
|
|
|
|
auto outputsOpt_ = store.queryPartialDerivationOutputMap(drvPath, evalStore_);
|
2023-01-12 01:57:18 +02:00
|
|
|
|
|
2023-07-19 21:52:35 +03:00
|
|
|
|
auto outputsOpt = std::visit(overloaded {
|
2023-01-12 01:57:18 +02:00
|
|
|
|
[&](const OutputsSpec::All &) {
|
2023-07-19 21:52:35 +03:00
|
|
|
|
// Keep all outputs
|
|
|
|
|
return std::move(outputsOpt_);
|
2023-01-12 01:57:18 +02:00
|
|
|
|
},
|
|
|
|
|
[&](const OutputsSpec::Names & names) {
|
2023-07-19 21:52:35 +03:00
|
|
|
|
// 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'",
|
Make the Derived Path family of types inductive for dynamic derivations
We want to be able to write down `foo.drv^bar.drv^baz`:
`foo.drv^bar.drv` is the dynamic derivation (since it is itself a
derivation output, `bar.drv` from `foo.drv`).
To that end, we create `Single{Derivation,BuiltPath}` types, that are
very similar except instead of having multiple outputs (in a set or
map), they have a single one. This is for everything to the left of the
rightmost `^`.
`NixStringContextElem` has an analogous change, and now can reuse
`SingleDerivedPath` at the top level. In fact, if we ever get rid of
`DrvDeep`, `NixStringContextElem` could be replaced with
`SingleDerivedPath` entirely!
Important note: some JSON formats have changed.
We already can *produce* dynamic derivations, but we can't refer to them
directly. Today, we can merely express building or example at the top
imperatively over time by building `foo.drv^bar.drv`, and then with a
second nix invocation doing `<result-from-first>^baz`, but this is not
declarative. The ethos of Nix of being able to write down the full plan
everything you want to do, and then execute than plan with a single
command, and for that we need the new inductive form of these types.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
2023-01-16 00:39:04 +02:00
|
|
|
|
bfd.drvPath->to_string(store), output);
|
2023-07-19 21:52:35 +03:00
|
|
|
|
outputsOpt.insert_or_assign(output, std::move(*pOutputPathOpt));
|
|
|
|
|
}
|
|
|
|
|
return outputsOpt;
|
2023-01-12 01:57:18 +02:00
|
|
|
|
},
|
2023-08-16 19:29:23 +03:00
|
|
|
|
}, bfd.outputs.raw);
|
2023-07-19 21:52:35 +03:00
|
|
|
|
|
|
|
|
|
OutputPathMap outputs;
|
|
|
|
|
for (auto & [outputName, outputPathOpt] : outputsOpt) {
|
|
|
|
|
if (!outputPathOpt)
|
Make the Derived Path family of types inductive for dynamic derivations
We want to be able to write down `foo.drv^bar.drv^baz`:
`foo.drv^bar.drv` is the dynamic derivation (since it is itself a
derivation output, `bar.drv` from `foo.drv`).
To that end, we create `Single{Derivation,BuiltPath}` types, that are
very similar except instead of having multiple outputs (in a set or
map), they have a single one. This is for everything to the left of the
rightmost `^`.
`NixStringContextElem` has an analogous change, and now can reuse
`SingleDerivedPath` at the top level. In fact, if we ever get rid of
`DrvDeep`, `NixStringContextElem` could be replaced with
`SingleDerivedPath` entirely!
Important note: some JSON formats have changed.
We already can *produce* dynamic derivations, but we can't refer to them
directly. Today, we can merely express building or example at the top
imperatively over time by building `foo.drv^bar.drv`, and then with a
second nix invocation doing `<result-from-first>^baz`, but this is not
declarative. The ethos of Nix of being able to write down the full plan
everything you want to do, and then execute than plan with a single
command, and for that we need the new inductive form of these types.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
2023-01-16 00:39:04 +02:00
|
|
|
|
throw MissingRealisation(bfd.drvPath->to_string(store), outputName);
|
2023-07-19 21:52:35 +03:00
|
|
|
|
auto & outputPath = *outputPathOpt;
|
|
|
|
|
outputs.insert_or_assign(outputName, outputPath);
|
2023-01-12 01:57:18 +02:00
|
|
|
|
}
|
|
|
|
|
return outputs;
|
2021-05-19 11:35:31 +03:00
|
|
|
|
}
|
2022-03-11 14:23:23 +02:00
|
|
|
|
|
Make the Derived Path family of types inductive for dynamic derivations
We want to be able to write down `foo.drv^bar.drv^baz`:
`foo.drv^bar.drv` is the dynamic derivation (since it is itself a
derivation output, `bar.drv` from `foo.drv`).
To that end, we create `Single{Derivation,BuiltPath}` types, that are
very similar except instead of having multiple outputs (in a set or
map), they have a single one. This is for everything to the left of the
rightmost `^`.
`NixStringContextElem` has an analogous change, and now can reuse
`SingleDerivedPath` at the top level. In fact, if we ever get rid of
`DrvDeep`, `NixStringContextElem` could be replaced with
`SingleDerivedPath` entirely!
Important note: some JSON formats have changed.
We already can *produce* dynamic derivations, but we can't refer to them
directly. Today, we can merely express building or example at the top
imperatively over time by building `foo.drv^bar.drv`, and then with a
second nix invocation doing `<result-from-first>^baz`, but this is not
declarative. The ethos of Nix of being able to write down the full plan
everything you want to do, and then execute than plan with a single
command, and for that we need the new inductive form of these types.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
2023-01-16 00:39:04 +02:00
|
|
|
|
|
|
|
|
|
StorePath resolveDerivedPath(Store & store, const SingleDerivedPath & req, Store * evalStore_)
|
|
|
|
|
{
|
|
|
|
|
auto & evalStore = evalStore_ ? *evalStore_ : store;
|
|
|
|
|
|
|
|
|
|
return std::visit(overloaded {
|
|
|
|
|
[&](const SingleDerivedPath::Opaque & bo) {
|
|
|
|
|
return bo.path;
|
|
|
|
|
},
|
|
|
|
|
[&](const SingleDerivedPath::Built & bfd) {
|
|
|
|
|
auto drvPath = resolveDerivedPath(store, *bfd.drvPath, evalStore_);
|
|
|
|
|
auto outputPaths = evalStore.queryPartialDerivationOutputMap(drvPath, evalStore_);
|
|
|
|
|
if (outputPaths.count(bfd.output) == 0)
|
|
|
|
|
throw Error("derivation '%s' does not have an output named '%s'",
|
|
|
|
|
store.printStorePath(drvPath), bfd.output);
|
|
|
|
|
auto & optPath = outputPaths.at(bfd.output);
|
|
|
|
|
if (!optPath)
|
2023-08-16 07:05:35 +03:00
|
|
|
|
throw MissingRealisation(bfd.drvPath->to_string(store), bfd.output);
|
Make the Derived Path family of types inductive for dynamic derivations
We want to be able to write down `foo.drv^bar.drv^baz`:
`foo.drv^bar.drv` is the dynamic derivation (since it is itself a
derivation output, `bar.drv` from `foo.drv`).
To that end, we create `Single{Derivation,BuiltPath}` types, that are
very similar except instead of having multiple outputs (in a set or
map), they have a single one. This is for everything to the left of the
rightmost `^`.
`NixStringContextElem` has an analogous change, and now can reuse
`SingleDerivedPath` at the top level. In fact, if we ever get rid of
`DrvDeep`, `NixStringContextElem` could be replaced with
`SingleDerivedPath` entirely!
Important note: some JSON formats have changed.
We already can *produce* dynamic derivations, but we can't refer to them
directly. Today, we can merely express building or example at the top
imperatively over time by building `foo.drv^bar.drv`, and then with a
second nix invocation doing `<result-from-first>^baz`, but this is not
declarative. The ethos of Nix of being able to write down the full plan
everything you want to do, and then execute than plan with a single
command, and for that we need the new inductive form of these types.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
2023-01-16 00:39:04 +02:00
|
|
|
|
return *optPath;
|
|
|
|
|
},
|
|
|
|
|
}, req.raw());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
OutputPathMap resolveDerivedPath(Store & store, const DerivedPath::Built & bfd)
|
|
|
|
|
{
|
|
|
|
|
auto drvPath = resolveDerivedPath(store, *bfd.drvPath);
|
|
|
|
|
auto outputMap = store.queryDerivationOutputMap(drvPath);
|
|
|
|
|
auto outputsLeft = std::visit(overloaded {
|
|
|
|
|
[&](const OutputsSpec::All &) {
|
|
|
|
|
return StringSet {};
|
|
|
|
|
},
|
|
|
|
|
[&](const OutputsSpec::Names & names) {
|
|
|
|
|
return static_cast<StringSet>(names);
|
|
|
|
|
},
|
2023-08-16 19:29:23 +03:00
|
|
|
|
}, bfd.outputs.raw);
|
Make the Derived Path family of types inductive for dynamic derivations
We want to be able to write down `foo.drv^bar.drv^baz`:
`foo.drv^bar.drv` is the dynamic derivation (since it is itself a
derivation output, `bar.drv` from `foo.drv`).
To that end, we create `Single{Derivation,BuiltPath}` types, that are
very similar except instead of having multiple outputs (in a set or
map), they have a single one. This is for everything to the left of the
rightmost `^`.
`NixStringContextElem` has an analogous change, and now can reuse
`SingleDerivedPath` at the top level. In fact, if we ever get rid of
`DrvDeep`, `NixStringContextElem` could be replaced with
`SingleDerivedPath` entirely!
Important note: some JSON formats have changed.
We already can *produce* dynamic derivations, but we can't refer to them
directly. Today, we can merely express building or example at the top
imperatively over time by building `foo.drv^bar.drv`, and then with a
second nix invocation doing `<result-from-first>^baz`, but this is not
declarative. The ethos of Nix of being able to write down the full plan
everything you want to do, and then execute than plan with a single
command, and for that we need the new inductive form of these types.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
2023-01-16 00:39:04 +02:00
|
|
|
|
for (auto iter = outputMap.begin(); iter != outputMap.end();) {
|
|
|
|
|
auto & outputName = iter->first;
|
|
|
|
|
if (bfd.outputs.contains(outputName)) {
|
|
|
|
|
outputsLeft.erase(outputName);
|
|
|
|
|
++iter;
|
|
|
|
|
} else {
|
|
|
|
|
iter = outputMap.erase(iter);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!outputsLeft.empty())
|
|
|
|
|
throw Error("derivation '%s' does not have an outputs %s",
|
|
|
|
|
store.printStorePath(drvPath),
|
2024-07-12 23:09:27 +03:00
|
|
|
|
dropEmptyInitThenConcatStringsSep(", ", quoteStrings(std::get<OutputsSpec::Names>(bfd.outputs.raw))));
|
Make the Derived Path family of types inductive for dynamic derivations
We want to be able to write down `foo.drv^bar.drv^baz`:
`foo.drv^bar.drv` is the dynamic derivation (since it is itself a
derivation output, `bar.drv` from `foo.drv`).
To that end, we create `Single{Derivation,BuiltPath}` types, that are
very similar except instead of having multiple outputs (in a set or
map), they have a single one. This is for everything to the left of the
rightmost `^`.
`NixStringContextElem` has an analogous change, and now can reuse
`SingleDerivedPath` at the top level. In fact, if we ever get rid of
`DrvDeep`, `NixStringContextElem` could be replaced with
`SingleDerivedPath` entirely!
Important note: some JSON formats have changed.
We already can *produce* dynamic derivations, but we can't refer to them
directly. Today, we can merely express building or example at the top
imperatively over time by building `foo.drv^bar.drv`, and then with a
second nix invocation doing `<result-from-first>^baz`, but this is not
declarative. The ethos of Nix of being able to write down the full plan
everything you want to do, and then execute than plan with a single
command, and for that we need the new inductive form of these types.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
2023-01-16 00:39:04 +02:00
|
|
|
|
return outputMap;
|
|
|
|
|
}
|
|
|
|
|
|
2006-09-05 00:06:23 +03:00
|
|
|
|
}
|