aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexpr')
-rw-r--r--src/libexpr/common-eval-args.cc2
-rw-r--r--src/libexpr/flake/call-flake.nix2
-rw-r--r--src/libexpr/flake/flake.cc52
-rw-r--r--src/libexpr/flake/flake.hh2
-rw-r--r--src/libexpr/flake/flakeref.cc22
-rw-r--r--src/libexpr/flake/flakeref.hh10
-rw-r--r--src/libexpr/flake/lockfile.cc40
-rw-r--r--src/libexpr/flake/lockfile.hh4
-rw-r--r--src/libexpr/parser.y2
-rw-r--r--src/libexpr/primops/fetchGit.cc10
-rw-r--r--src/libexpr/primops/fetchMercurial.cc14
-rw-r--r--src/libexpr/primops/fetchTree.cc69
12 files changed, 127 insertions, 102 deletions
diff --git a/src/libexpr/common-eval-args.cc b/src/libexpr/common-eval-args.cc
index 8665abe8c..6b48ead1f 100644
--- a/src/libexpr/common-eval-args.cc
+++ b/src/libexpr/common-eval-args.cc
@@ -76,7 +76,7 @@ Path lookupFileArg(EvalState & state, string s)
if (isUri(s)) {
return state.store->toRealPath(
fetchers::downloadTarball(
- state.store, resolveUri(s), "source", false).storePath);
+ state.store, resolveUri(s), "source", false).first.storePath);
} else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') {
Path p = s.substr(1, s.size() - 2);
return state.findFile(p);
diff --git a/src/libexpr/flake/call-flake.nix b/src/libexpr/flake/call-flake.nix
index 8ee17b8f4..2084e3fb3 100644
--- a/src/libexpr/flake/call-flake.nix
+++ b/src/libexpr/flake/call-flake.nix
@@ -11,7 +11,7 @@ let
sourceInfo =
if key == lockFile.root
then rootSrc
- else fetchTree ({ inherit (node.info) narHash; } // removeAttrs node.locked ["dir"]);
+ else fetchTree (node.info or {} // removeAttrs node.locked ["dir"]);
subdir = if key == lockFile.root then rootSubdir else node.locked.dir or "";
flake = import (sourceInfo + (if subdir != "" then "/" else "") + subdir + "/flake.nix");
inputs = builtins.mapAttrs (inputName: key: allNodes.${key}) (node.inputs or {});
diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc
index 78b58cdfa..9741d98c5 100644
--- a/src/libexpr/flake/flake.cc
+++ b/src/libexpr/flake/flake.cc
@@ -19,7 +19,7 @@ static FlakeRef maybeLookupFlake(
const FlakeRef & flakeRef,
bool allowLookup)
{
- if (!flakeRef.input->isDirect()) {
+ if (!flakeRef.input.isDirect()) {
if (allowLookup)
return flakeRef.resolve(store);
else
@@ -49,16 +49,15 @@ static FlakeRef lookupInFlakeCache(
static std::tuple<fetchers::Tree, FlakeRef, FlakeRef> fetchOrSubstituteTree(
EvalState & state,
const FlakeRef & originalRef,
- std::optional<TreeInfo> treeInfo,
bool allowLookup,
FlakeCache & flakeCache)
{
/* The tree may already be in the Nix store, or it could be
substituted (which is often faster than fetching from the
original source). So check that. */
- if (treeInfo && originalRef.input->isDirect() && originalRef.input->isImmutable()) {
+ if (originalRef.input.isDirect() && originalRef.input.isImmutable() && originalRef.input.hasAllInfo()) {
try {
- auto storePath = treeInfo->computeStorePath(*state.store);
+ auto storePath = originalRef.input.computeStorePath(*state.store);
state.store->ensurePath(storePath);
@@ -74,7 +73,6 @@ static std::tuple<fetchers::Tree, FlakeRef, FlakeRef> fetchOrSubstituteTree(
Tree {
.actualPath = actualPath,
.storePath = std::move(storePath),
- .info = *treeInfo,
},
originalRef,
originalRef
@@ -99,8 +97,7 @@ static std::tuple<fetchers::Tree, FlakeRef, FlakeRef> fetchOrSubstituteTree(
if (state.allowedPaths)
state.allowedPaths->insert(tree.actualPath);
- if (treeInfo)
- assert(tree.storePath == treeInfo->computeStorePath(*state.store));
+ assert(!originalRef.input.getNarHash() || tree.storePath == originalRef.input.computeStorePath(*state.store));
return {std::move(tree), resolvedRef, lockedRef};
}
@@ -202,12 +199,11 @@ static std::map<FlakeId, FlakeInput> parseFlakeInputs(
static Flake getFlake(
EvalState & state,
const FlakeRef & originalRef,
- std::optional<TreeInfo> treeInfo,
bool allowLookup,
FlakeCache & flakeCache)
{
auto [sourceInfo, resolvedRef, lockedRef] = fetchOrSubstituteTree(
- state, originalRef, treeInfo, allowLookup, flakeCache);
+ state, originalRef, allowLookup, flakeCache);
// Guard against symlink attacks.
auto flakeFile = canonPath(sourceInfo.actualPath + "/" + lockedRef.subdir + "/flake.nix");
@@ -278,7 +274,7 @@ static Flake getFlake(
Flake getFlake(EvalState & state, const FlakeRef & originalRef, bool allowLookup)
{
FlakeCache flakeCache;
- return getFlake(state, originalRef, {}, allowLookup, flakeCache);
+ return getFlake(state, originalRef, allowLookup, flakeCache);
}
/* Compute an in-memory lock file for the specified top-level flake,
@@ -292,7 +288,7 @@ LockedFlake lockFlake(
FlakeCache flakeCache;
- auto flake = getFlake(state, topRef, {}, lockFlags.useRegistries, flakeCache);
+ auto flake = getFlake(state, topRef, lockFlags.useRegistries, flakeCache);
// FIXME: symlink attack
auto oldLockFile = LockFile::read(
@@ -393,7 +389,7 @@ LockedFlake lockFlake(
didn't change and there is no override from a
higher level flake. */
auto childNode = std::make_shared<LockedNode>(
- oldLock->lockedRef, oldLock->originalRef, oldLock->info, oldLock->isFlake);
+ oldLock->lockedRef, oldLock->originalRef, oldLock->isFlake);
node->inputs.insert_or_assign(id, childNode);
@@ -409,7 +405,7 @@ LockedFlake lockFlake(
if (hasChildUpdate) {
auto inputFlake = getFlake(
- state, oldLock->lockedRef, oldLock->info, false, flakeCache);
+ state, oldLock->lockedRef, false, flakeCache);
computeLocks(inputFlake.inputs, childNode, inputPath, oldLock);
} else {
/* No need to fetch this flake, we can be
@@ -440,11 +436,11 @@ LockedFlake lockFlake(
/* We need to create a new lock file entry. So fetch
this input. */
- if (!lockFlags.allowMutable && !input.ref.input->isImmutable())
+ if (!lockFlags.allowMutable && !input.ref.input.isImmutable())
throw Error("cannot update flake input '%s' in pure mode", inputPathS);
if (input.isFlake) {
- auto inputFlake = getFlake(state, input.ref, {}, lockFlags.useRegistries, flakeCache);
+ auto inputFlake = getFlake(state, input.ref, lockFlags.useRegistries, flakeCache);
/* Note: in case of an --override-input, we use
the *original* ref (input2.ref) for the
@@ -454,7 +450,7 @@ LockedFlake lockFlake(
file. That is, overrides are sticky unless you
use --no-write-lock-file. */
auto childNode = std::make_shared<LockedNode>(
- inputFlake.lockedRef, input2.ref, inputFlake.sourceInfo->info);
+ inputFlake.lockedRef, input2.ref);
node->inputs.insert_or_assign(id, childNode);
@@ -479,9 +475,9 @@ LockedFlake lockFlake(
else {
auto [sourceInfo, resolvedRef, lockedRef] = fetchOrSubstituteTree(
- state, input.ref, {}, lockFlags.useRegistries, flakeCache);
+ state, input.ref, lockFlags.useRegistries, flakeCache);
node->inputs.insert_or_assign(id,
- std::make_shared<LockedNode>(lockedRef, input.ref, sourceInfo.info, false));
+ std::make_shared<LockedNode>(lockedRef, input.ref, false));
}
}
}
@@ -534,7 +530,7 @@ LockedFlake lockFlake(
printInfo("inputs of flake '%s' changed:\n%s", topRef, chomp(diff));
if (lockFlags.writeLockFile) {
- if (auto sourcePath = topRef.input->getSourcePath()) {
+ if (auto sourcePath = topRef.input.getSourcePath()) {
if (!newLockFile.isImmutable()) {
if (settings.warnDirty)
warn("will not write lock file of flake '%s' because it has a mutable input", topRef);
@@ -555,7 +551,7 @@ LockedFlake lockFlake(
newLockFile.write(path);
- topRef.input->markChangedFile(
+ topRef.input.markChangedFile(
(topRef.subdir == "" ? "" : topRef.subdir + "/") + "flake.lock",
lockFlags.commitLockFile
? std::optional<std::string>(fmt("%s: %s\n\nFlake input changes:\n\n%s",
@@ -567,19 +563,19 @@ LockedFlake lockFlake(
also just clear the 'rev' field... */
auto prevLockedRef = flake.lockedRef;
FlakeCache dummyCache;
- flake = getFlake(state, topRef, {}, lockFlags.useRegistries, dummyCache);
+ flake = getFlake(state, topRef, lockFlags.useRegistries, dummyCache);
if (lockFlags.commitLockFile &&
- flake.lockedRef.input->getRev() &&
- prevLockedRef.input->getRev() != flake.lockedRef.input->getRev())
- warn("committed new revision '%s'", flake.lockedRef.input->getRev()->gitRev());
+ flake.lockedRef.input.getRev() &&
+ prevLockedRef.input.getRev() != flake.lockedRef.input.getRev())
+ warn("committed new revision '%s'", flake.lockedRef.input.getRev()->gitRev());
/* Make sure that we picked up the change,
i.e. the tree should usually be dirty
now. Corner case: we could have reverted from a
dirty to a clean tree! */
if (flake.lockedRef.input == prevLockedRef.input
- && !flake.lockedRef.input->isImmutable())
+ && !flake.lockedRef.input.isImmutable())
throw Error("'%s' did not change after I updated its 'flake.lock' file; is 'flake.lock' under version control?", flake.originalRef);
}
} else
@@ -625,7 +621,7 @@ static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Va
{
auto flakeRefS = state.forceStringNoCtx(*args[0], pos);
auto flakeRef = parseFlakeRef(flakeRefS, {}, true);
- if (evalSettings.pureEval && !flakeRef.input->isImmutable())
+ if (evalSettings.pureEval && !flakeRef.input.isImmutable())
throw Error("cannot call 'getFlake' on mutable flake reference '%s', at %s (use --impure to override)", flakeRefS, pos);
callFlake(state,
@@ -650,8 +646,8 @@ Fingerprint LockedFlake::getFingerprint() const
return hashString(htSHA256,
fmt("%s;%d;%d;%s",
flake.sourceInfo->storePath.to_string(),
- flake.sourceInfo->info.revCount.value_or(0),
- flake.sourceInfo->info.lastModified.value_or(0),
+ flake.lockedRef.input.getRevCount().value_or(0),
+ flake.lockedRef.input.getLastModified().value_or(0),
lockFile));
}
diff --git a/src/libexpr/flake/flake.hh b/src/libexpr/flake/flake.hh
index 59a1adb3b..ebf81362c 100644
--- a/src/libexpr/flake/flake.hh
+++ b/src/libexpr/flake/flake.hh
@@ -104,7 +104,7 @@ void callFlake(
void emitTreeAttrs(
EvalState & state,
const fetchers::Tree & tree,
- std::shared_ptr<const fetchers::Input> input,
+ const fetchers::Input & input,
Value & v);
}
diff --git a/src/libexpr/flake/flakeref.cc b/src/libexpr/flake/flakeref.cc
index a70261a41..615269218 100644
--- a/src/libexpr/flake/flakeref.cc
+++ b/src/libexpr/flake/flakeref.cc
@@ -15,7 +15,7 @@ const static std::string subDirRegex = subDirElemRegex + "(?:/" + subDirElemRege
std::string FlakeRef::to_string() const
{
- auto url = input->toURL();
+ auto url = input.toURL();
if (subdir != "")
url.query.insert_or_assign("dir", subdir);
return url.to_string();
@@ -23,7 +23,7 @@ std::string FlakeRef::to_string() const
fetchers::Attrs FlakeRef::toAttrs() const
{
- auto attrs = input->toAttrs();
+ auto attrs = input.toAttrs();
if (subdir != "")
attrs.emplace("dir", subdir);
return attrs;
@@ -37,13 +37,13 @@ std::ostream & operator << (std::ostream & str, const FlakeRef & flakeRef)
bool FlakeRef::operator ==(const FlakeRef & other) const
{
- return *input == *other.input && subdir == other.subdir;
+ return input == other.input && subdir == other.subdir;
}
FlakeRef FlakeRef::resolve(ref<Store> store) const
{
auto [input2, extraAttrs] = lookupInRegistries(store, input);
- return FlakeRef(input2, fetchers::maybeGetStrAttr(extraAttrs, "dir").value_or(subdir));
+ return FlakeRef(std::move(input2), fetchers::maybeGetStrAttr(extraAttrs, "dir").value_or(subdir));
}
FlakeRef parseFlakeRef(
@@ -98,7 +98,7 @@ std::pair<FlakeRef, std::string> parseFlakeRefWithFragment(
};
return std::make_pair(
- FlakeRef(inputFromURL(parsedURL), ""),
+ FlakeRef(Input::fromURL(parsedURL), ""),
percentDecode(std::string(match[6])));
}
@@ -143,7 +143,7 @@ std::pair<FlakeRef, std::string> parseFlakeRefWithFragment(
}
return std::make_pair(
- FlakeRef(inputFromURL(parsedURL), get(parsedURL.query, "dir").value_or("")),
+ FlakeRef(Input::fromURL(parsedURL), get(parsedURL.query, "dir").value_or("")),
fragment);
}
@@ -155,7 +155,7 @@ std::pair<FlakeRef, std::string> parseFlakeRefWithFragment(
attrs.insert_or_assign("type", "path");
attrs.insert_or_assign("path", path);
- return std::make_pair(FlakeRef(inputFromAttrs(attrs), ""), fragment);
+ return std::make_pair(FlakeRef(Input::fromAttrs(std::move(attrs)), ""), fragment);
}
else {
@@ -163,7 +163,7 @@ std::pair<FlakeRef, std::string> parseFlakeRefWithFragment(
std::string fragment;
std::swap(fragment, parsedURL.fragment);
return std::make_pair(
- FlakeRef(inputFromURL(parsedURL), get(parsedURL.query, "dir").value_or("")),
+ FlakeRef(Input::fromURL(parsedURL), get(parsedURL.query, "dir").value_or("")),
fragment);
}
}
@@ -183,14 +183,14 @@ FlakeRef FlakeRef::fromAttrs(const fetchers::Attrs & attrs)
auto attrs2(attrs);
attrs2.erase("dir");
return FlakeRef(
- fetchers::inputFromAttrs(attrs2),
+ fetchers::Input::fromAttrs(std::move(attrs2)),
fetchers::maybeGetStrAttr(attrs, "dir").value_or(""));
}
std::pair<fetchers::Tree, FlakeRef> FlakeRef::fetchTree(ref<Store> store) const
{
- auto [tree, lockedInput] = input->fetchTree(store);
- return {std::move(tree), FlakeRef(lockedInput, subdir)};
+ auto [tree, lockedInput] = input.fetch(store);
+ return {std::move(tree), FlakeRef(std::move(lockedInput), subdir)};
}
}
diff --git a/src/libexpr/flake/flakeref.hh b/src/libexpr/flake/flakeref.hh
index 72cbb2908..f4eb825a6 100644
--- a/src/libexpr/flake/flakeref.hh
+++ b/src/libexpr/flake/flakeref.hh
@@ -14,17 +14,15 @@ typedef std::string FlakeId;
struct FlakeRef
{
- std::shared_ptr<const fetchers::Input> input;
+ fetchers::Input input;
Path subdir;
bool operator==(const FlakeRef & other) const;
- FlakeRef(const std::shared_ptr<const fetchers::Input> & input, const Path & subdir)
- : input(input), subdir(subdir)
- {
- assert(input);
- }
+ FlakeRef(fetchers::Input && input, const Path & subdir)
+ : input(std::move(input)), subdir(subdir)
+ { }
// FIXME: change to operator <<.
std::string to_string() const;
diff --git a/src/libexpr/flake/lockfile.cc b/src/libexpr/flake/lockfile.cc
index 5c58d6080..68e587650 100644
--- a/src/libexpr/flake/lockfile.cc
+++ b/src/libexpr/flake/lockfile.cc
@@ -5,35 +5,40 @@
namespace nix::flake {
-FlakeRef flakeRefFromJson(const nlohmann::json & json)
-{
- return FlakeRef::fromAttrs(jsonToAttrs(json));
-}
-
FlakeRef getFlakeRef(
const nlohmann::json & json,
- const char * attr)
+ const char * attr,
+ const char * info)
{
auto i = json.find(attr);
- if (i != json.end())
- return flakeRefFromJson(*i);
+ if (i != json.end()) {
+ auto attrs = jsonToAttrs(*i);
+ // FIXME: remove when we drop support for version 5.
+ if (info) {
+ auto j = json.find(info);
+ if (j != json.end()) {
+ for (auto k : jsonToAttrs(*j))
+ attrs.insert_or_assign(k.first, k.second);
+ }
+ }
+ return FlakeRef::fromAttrs(attrs);
+ }
throw Error("attribute '%s' missing in lock file", attr);
}
LockedNode::LockedNode(const nlohmann::json & json)
- : lockedRef(getFlakeRef(json, "locked"))
- , originalRef(getFlakeRef(json, "original"))
- , info(TreeInfo::fromJson(json))
+ : lockedRef(getFlakeRef(json, "locked", "info"))
+ , originalRef(getFlakeRef(json, "original", nullptr))
, isFlake(json.find("flake") != json.end() ? (bool) json["flake"] : true)
{
- if (!lockedRef.input->isImmutable())
- throw Error("lockfile contains mutable flakeref '%s'", lockedRef);
+ if (!lockedRef.input.isImmutable())
+ throw Error("lockfile contains mutable lock '%s'", attrsToJson(lockedRef.input.toAttrs()));
}
StorePath LockedNode::computeStorePath(Store & store) const
{
- return info.computeStorePath(store);
+ return lockedRef.input.computeStorePath(store);
}
std::shared_ptr<Node> Node::findInput(const InputPath & path)
@@ -53,7 +58,7 @@ std::shared_ptr<Node> Node::findInput(const InputPath & path)
LockFile::LockFile(const nlohmann::json & json, const Path & path)
{
auto version = json.value("version", 0);
- if (version != 5)
+ if (version < 5 || version > 6)
throw Error("lock file '%s' has unsupported version %d", path, version);
std::unordered_map<std::string, std::shared_ptr<Node>> nodeMap;
@@ -119,7 +124,6 @@ nlohmann::json LockFile::toJson() const
if (auto lockedNode = std::dynamic_pointer_cast<const LockedNode>(node)) {
n["original"] = fetchers::attrsToJson(lockedNode->originalRef.toAttrs());
n["locked"] = fetchers::attrsToJson(lockedNode->lockedRef.toAttrs());
- n["info"] = lockedNode->info.toJson();
if (!lockedNode->isFlake) n["flake"] = false;
}
@@ -129,7 +133,7 @@ nlohmann::json LockFile::toJson() const
};
nlohmann::json json;
- json["version"] = 5;
+ json["version"] = 6;
json["root"] = dumpNode("root", root);
json["nodes"] = std::move(nodes);
@@ -176,7 +180,7 @@ bool LockFile::isImmutable() const
for (auto & i : nodes) {
if (i == root) continue;
auto lockedNode = std::dynamic_pointer_cast<const LockedNode>(i);
- if (lockedNode && !lockedNode->lockedRef.input->isImmutable()) return false;
+ if (lockedNode && !lockedNode->lockedRef.input.isImmutable()) return false;
}
return true;
diff --git a/src/libexpr/flake/lockfile.hh b/src/libexpr/flake/lockfile.hh
index c34939ebc..ba47f9b89 100644
--- a/src/libexpr/flake/lockfile.hh
+++ b/src/libexpr/flake/lockfile.hh
@@ -31,15 +31,13 @@ struct Node : std::enable_shared_from_this<Node>
struct LockedNode : Node
{
FlakeRef lockedRef, originalRef;
- TreeInfo info;
bool isFlake = true;
LockedNode(
const FlakeRef & lockedRef,
const FlakeRef & originalRef,
- const TreeInfo & info,
bool isFlake = true)
- : lockedRef(lockedRef), originalRef(originalRef), info(info), isFlake(isFlake)
+ : lockedRef(lockedRef), originalRef(originalRef), isFlake(isFlake)
{ }
LockedNode(const nlohmann::json & json);
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index 1993fa6c1..1ac5217ba 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -689,7 +689,7 @@ std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathEl
if (isUri(elem.second)) {
try {
res = { true, store->toRealPath(fetchers::downloadTarball(
- store, resolveUri(elem.second), "source", false).storePath) };
+ store, resolveUri(elem.second), "source", false).first.storePath) };
} catch (FileTransferError & e) {
printError(format("warning: Nix search path entry '%1%' cannot be downloaded, ignoring") % elem.second);
res = { false, "" };
diff --git a/src/libexpr/primops/fetchGit.cc b/src/libexpr/primops/fetchGit.cc
index 1a8798fcc..a6539e888 100644
--- a/src/libexpr/primops/fetchGit.cc
+++ b/src/libexpr/primops/fetchGit.cc
@@ -56,23 +56,23 @@ static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Va
attrs.insert_or_assign("url", url.find("://") != std::string::npos ? url : "file://" + url);
if (ref) attrs.insert_or_assign("ref", *ref);
if (rev) attrs.insert_or_assign("rev", rev->gitRev());
- if (fetchSubmodules) attrs.insert_or_assign("submodules", true);
- auto input = fetchers::inputFromAttrs(attrs);
+ if (fetchSubmodules) attrs.insert_or_assign("submodules", fetchers::Explicit<bool>{true});
+ auto input = fetchers::Input::fromAttrs(std::move(attrs));
// FIXME: use name?
- auto [tree, input2] = input->fetchTree(state.store);
+ auto [tree, input2] = input.fetch(state.store);
state.mkAttrs(v, 8);
auto storePath = state.store->printStorePath(tree.storePath);
mkString(*state.allocAttr(v, state.sOutPath), storePath, PathSet({storePath}));
// Backward compatibility: set 'rev' to
// 0000000000000000000000000000000000000000 for a dirty tree.
- auto rev2 = input2->getRev().value_or(Hash(htSHA1));
+ auto rev2 = input2.getRev().value_or(Hash(htSHA1));
mkString(*state.allocAttr(v, state.symbols.create("rev")), rev2.gitRev());
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), rev2.gitShortRev());
// Backward compatibility: set 'revCount' to 0 for a dirty tree.
mkInt(*state.allocAttr(v, state.symbols.create("revCount")),
- tree.info.revCount.value_or(0));
+ input2.getRevCount().value_or(0));
mkBool(*state.allocAttr(v, state.symbols.create("submodules")), fetchSubmodules);
v.attrs->sort();
diff --git a/src/libexpr/primops/fetchMercurial.cc b/src/libexpr/primops/fetchMercurial.cc
index 0a1ba49d5..90030ea76 100644
--- a/src/libexpr/primops/fetchMercurial.cc
+++ b/src/libexpr/primops/fetchMercurial.cc
@@ -59,23 +59,23 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
attrs.insert_or_assign("url", url.find("://") != std::string::npos ? url : "file://" + url);
if (ref) attrs.insert_or_assign("ref", *ref);
if (rev) attrs.insert_or_assign("rev", rev->gitRev());
- auto input = fetchers::inputFromAttrs(attrs);
+ auto input = fetchers::Input::fromAttrs(std::move(attrs));
// FIXME: use name
- auto [tree, input2] = input->fetchTree(state.store);
+ auto [tree, input2] = input.fetch(state.store);
state.mkAttrs(v, 8);
auto storePath = state.store->printStorePath(tree.storePath);
mkString(*state.allocAttr(v, state.sOutPath), storePath, PathSet({storePath}));
- if (input2->getRef())
- mkString(*state.allocAttr(v, state.symbols.create("branch")), *input2->getRef());
+ if (input2.getRef())
+ mkString(*state.allocAttr(v, state.symbols.create("branch")), *input2.getRef());
// Backward compatibility: set 'rev' to
// 0000000000000000000000000000000000000000 for a dirty tree.
- auto rev2 = input2->getRev().value_or(Hash(htSHA1));
+ auto rev2 = input2.getRev().value_or(Hash(htSHA1));
mkString(*state.allocAttr(v, state.symbols.create("rev")), rev2.gitRev());
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), std::string(rev2.gitRev(), 0, 12));
- if (tree.info.revCount)
- mkInt(*state.allocAttr(v, state.symbols.create("revCount")), *tree.info.revCount);
+ if (auto revCount = input2.getRevCount())
+ mkInt(*state.allocAttr(v, state.symbols.create("revCount")), *revCount);
v.attrs->sort();
if (state.allowedPaths)
diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc
index f9dfb1164..a1ad0a7b9 100644
--- a/src/libexpr/primops/fetchTree.cc
+++ b/src/libexpr/primops/fetchTree.cc
@@ -13,31 +13,36 @@ namespace nix {
void emitTreeAttrs(
EvalState & state,
const fetchers::Tree & tree,
- std::shared_ptr<const fetchers::Input> input,
+ const fetchers::Input & input,
Value & v)
{
+ assert(input.isImmutable());
+
state.mkAttrs(v, 8);
auto storePath = state.store->printStorePath(tree.storePath);
mkString(*state.allocAttr(v, state.sOutPath), storePath, PathSet({storePath}));
- assert(tree.info.narHash);
+ // FIXME: support arbitrary input attributes.
+
+ auto narHash = input.getNarHash();
+ assert(narHash);
mkString(*state.allocAttr(v, state.symbols.create("narHash")),
- tree.info.narHash.to_string(SRI));
+ narHash->to_string(SRI));
- if (input->getRev()) {
- mkString(*state.allocAttr(v, state.symbols.create("rev")), input->getRev()->gitRev());
- mkString(*state.allocAttr(v, state.symbols.create("shortRev")), input->getRev()->gitShortRev());
+ if (auto rev = input.getRev()) {
+ mkString(*state.allocAttr(v, state.symbols.create("rev")), rev->gitRev());
+ mkString(*state.allocAttr(v, state.symbols.create("shortRev")), rev->gitShortRev());
}
- if (tree.info.revCount)
- mkInt(*state.allocAttr(v, state.symbols.create("revCount")), *tree.info.revCount);
+ if (auto revCount = input.getRevCount())
+ mkInt(*state.allocAttr(v, state.symbols.create("revCount")), *revCount);
- if (tree.info.lastModified) {
- mkInt(*state.allocAttr(v, state.symbols.create("lastModified")), *tree.info.lastModified);
+ if (auto lastModified = input.getLastModified()) {
+ mkInt(*state.allocAttr(v, state.symbols.create("lastModified")), *lastModified);
mkString(*state.allocAttr(v, state.symbols.create("lastModifiedDate")),
- fmt("%s", std::put_time(std::gmtime(&*tree.info.lastModified), "%Y%m%d%H%M%S")));
+ fmt("%s", std::put_time(std::gmtime(&*lastModified), "%Y%m%d%H%M%S")));
}
v.attrs->sort();
@@ -47,7 +52,7 @@ static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, V
{
settings.requireExperimentalFeature("flakes");
- std::shared_ptr<const fetchers::Input> input;
+ fetchers::Input input;
PathSet context;
state.forceValue(*args[0]);
@@ -62,7 +67,7 @@ static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, V
if (attr.value->type == tString)
attrs.emplace(attr.name, attr.value->string.s);
else if (attr.value->type == tBool)
- attrs.emplace(attr.name, attr.value->boolean);
+ attrs.emplace(attr.name, fetchers::Explicit<bool>{attr.value->boolean});
else if (attr.value->type == tInt)
attrs.emplace(attr.name, attr.value->integer);
else
@@ -73,18 +78,42 @@ static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, V
if (!attrs.count("type"))
throw Error("attribute 'type' is missing in call to 'fetchTree', at %s", pos);
- input = fetchers::inputFromAttrs(attrs);
+ input = fetchers::Input::fromAttrs(std::move(attrs));
} else
- input = fetchers::inputFromURL(state.coerceToString(pos, *args[0], context, false, false));
+ input = fetchers::Input::fromURL(state.coerceToString(pos, *args[0], context, false, false));
- if (!evalSettings.pureEval && !input->isDirect())
+ if (!evalSettings.pureEval && !input.isDirect())
input = lookupInRegistries(state.store, input).first;
- if (evalSettings.pureEval && !input->isImmutable())
+ if (evalSettings.pureEval && !input.isImmutable())
throw Error("in pure evaluation mode, 'fetchTree' requires an immutable input, at %s", pos);
- // FIXME: use fetchOrSubstituteTree
- auto [tree, input2] = input->fetchTree(state.store);
+ /* The tree may already be in the Nix store, or it could be
+ substituted (which is often faster than fetching from the
+ original source). So check that. */
+ if (input.hasAllInfo()) {
+ auto storePath = input.computeStorePath(*state.store);
+
+ try {
+ state.store->ensurePath(storePath);
+
+ debug("using substituted/cached input '%s' in '%s'",
+ input.to_string(), state.store->printStorePath(storePath));
+
+ auto actualPath = state.store->toRealPath(storePath);
+
+ if (state.allowedPaths)
+ state.allowedPaths->insert(actualPath);
+
+ emitTreeAttrs(state, fetchers::Tree { .actualPath = actualPath, .storePath = std::move(storePath) }, input, v);
+
+ return;
+ } catch (Error & e) {
+ debug("substitution of input '%s' failed: %s", input.to_string(), e.what());
+ }
+ }
+
+ auto [tree, input2] = input.fetch(state.store);
if (state.allowedPaths)
state.allowedPaths->insert(tree.actualPath);
@@ -137,7 +166,7 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
auto storePath =
unpack
- ? fetchers::downloadTarball(state.store, *url, name, (bool) expectedHash).storePath
+ ? fetchers::downloadTarball(state.store, *url, name, (bool) expectedHash).first.storePath
: fetchers::downloadFile(state.store, *url, name, (bool) expectedHash).storePath;
auto path = state.store->toRealPath(storePath);