1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-18 08:19:35 +01:00

Tagging release 2.27.1

-----BEGIN PGP SIGNATURE-----
 
 iQFHBAABCAAxFiEEtUHVUwEnDgvPFcpdgXC0cm1xmN4FAmfheacTHGVkb2xzdHJh
 QGdtYWlsLmNvbQAKCRCBcLRybXGY3kt2B/4tQvs6iDXA12d409ClHbVQjr1d0FLP
 rv8RxZ7Z4+Jaw8r2ra/I+gpr9juI5ULyEJWqfES72hTvbYPjH1Grsrrjak1tx57E
 +STs21oEPojE8LXsFH1oZamGPPIIpyQdxCvTgZs1N6cqUfCRQ3Jx97X6E6SIGJDR
 VqBM4ruSXCY57yT36HqwYydTkxzZHiNP5wwABGfSb7u9pYW5x3r8W7+fQ3udTnCw
 kCRhA5vnfxIQSlxu4j7dJqSCGzOIPnhYB19bXDV4aPhl4sn3pkBCdMZxPBlCWSwx
 it0ngMITf+TeiMpVl2TtvMBOHtlGrbhusbyKcsqzFYULGyGOC9ngTAY3
 =/JzB
 -----END PGP SIGNATURE-----

Merge tag '2.27.1' into detsys-main

Tagging release 2.27.1
This commit is contained in:
Eelco Dolstra 2025-03-24 21:28:03 +01:00
commit dab0ff4f9e
200 changed files with 4734 additions and 1977 deletions

View file

@ -12,6 +12,7 @@
#include "flake/settings.hh"
#include "value-to-json.hh"
#include "local-fs-store.hh"
#include "fetch-to-store.hh"
#include <nlohmann/json.hpp>
@ -24,7 +25,7 @@ namespace flake {
struct FetchedFlake
{
FlakeRef lockedRef;
StorePath storePath;
ref<SourceAccessor> accessor;
};
typedef std::map<FlakeRef, FetchedFlake> FlakeCache;
@ -40,7 +41,7 @@ static std::optional<FetchedFlake> lookupInFlakeCache(
return i->second;
}
static std::tuple<StorePath, FlakeRef, FlakeRef> fetchOrSubstituteTree(
static std::tuple<ref<SourceAccessor>, FlakeRef, FlakeRef> fetchOrSubstituteTree(
EvalState & state,
const FlakeRef & originalRef,
bool useRegistries,
@ -51,8 +52,8 @@ static std::tuple<StorePath, FlakeRef, FlakeRef> fetchOrSubstituteTree(
if (!fetched) {
if (originalRef.input.isDirect()) {
auto [storePath, lockedRef] = originalRef.fetchTree(state.store);
fetched.emplace(FetchedFlake{.lockedRef = lockedRef, .storePath = storePath});
auto [accessor, lockedRef] = originalRef.lazyFetch(state.store);
fetched.emplace(FetchedFlake{.lockedRef = lockedRef, .accessor = accessor});
} else {
if (useRegistries) {
resolvedRef = originalRef.resolve(
@ -64,8 +65,8 @@ static std::tuple<StorePath, FlakeRef, FlakeRef> fetchOrSubstituteTree(
});
fetched = lookupInFlakeCache(flakeCache, originalRef);
if (!fetched) {
auto [storePath, lockedRef] = resolvedRef.fetchTree(state.store);
fetched.emplace(FetchedFlake{.lockedRef = lockedRef, .storePath = storePath});
auto [accessor, lockedRef] = resolvedRef.lazyFetch(state.store);
fetched.emplace(FetchedFlake{.lockedRef = lockedRef, .accessor = accessor});
}
flakeCache.insert_or_assign(resolvedRef, *fetched);
}
@ -76,14 +77,27 @@ static std::tuple<StorePath, FlakeRef, FlakeRef> fetchOrSubstituteTree(
flakeCache.insert_or_assign(originalRef, *fetched);
}
debug("got tree '%s' from '%s'",
state.store->printStorePath(fetched->storePath), fetched->lockedRef);
debug("got tree '%s' from '%s'", fetched->accessor, fetched->lockedRef);
state.allowPath(fetched->storePath);
return {fetched->accessor, resolvedRef, fetched->lockedRef};
}
assert(!originalRef.input.getNarHash() || fetched->storePath == originalRef.input.computeStorePath(*state.store));
static StorePath copyInputToStore(
EvalState & state,
fetchers::Input & input,
const fetchers::Input & originalInput,
ref<SourceAccessor> accessor)
{
auto storePath = fetchToStore(*state.store, accessor, FetchMode::Copy, input.getName());
return {fetched->storePath, resolvedRef, fetched->lockedRef};
state.allowPath(storePath);
auto narHash = state.store->queryPathInfo(storePath)->narHash;
input.attrs.insert_or_assign("narHash", narHash.to_string(HashFormat::SRI, true));
assert(!originalInput.getNarHash() || storePath == originalInput.computeStorePath(*state.store));
return storePath;
}
static void forceTrivialValue(EvalState & state, Value & value, const PosIdx pos)
@ -101,19 +115,54 @@ static void expectType(EvalState & state, ValueType type,
showType(type), showType(value.type()), state.positions[pos]);
}
static std::map<FlakeId, FlakeInput> parseFlakeInputs(
static std::pair<std::map<FlakeId, FlakeInput>, fetchers::Attrs> parseFlakeInputs(
EvalState & state,
Value * value,
const PosIdx pos,
const InputPath & lockRootPath,
const SourcePath & flakeDir);
const InputAttrPath & lockRootAttrPath,
const SourcePath & flakeDir,
bool allowSelf);
static void parseFlakeInputAttr(
EvalState & state,
const Attr & attr,
fetchers::Attrs & attrs)
{
// Allow selecting a subset of enum values
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch-enum"
switch (attr.value->type()) {
case nString:
attrs.emplace(state.symbols[attr.name], attr.value->c_str());
break;
case nBool:
attrs.emplace(state.symbols[attr.name], Explicit<bool> { attr.value->boolean() });
break;
case nInt: {
auto intValue = attr.value->integer().value;
if (intValue < 0)
state.error<EvalError>("negative value given for flake input attribute %1%: %2%", state.symbols[attr.name], intValue).debugThrow();
attrs.emplace(state.symbols[attr.name], uint64_t(intValue));
break;
}
default:
if (attr.name == state.symbols.create("publicKeys")) {
experimentalFeatureSettings.require(Xp::VerifiedFetches);
NixStringContext emptyContext = {};
attrs.emplace(state.symbols[attr.name], printValueAsJSON(state, true, *attr.value, attr.pos, emptyContext).dump());
} else
state.error<TypeError>("flake input attribute '%s' is %s while a string, Boolean, or integer is expected",
state.symbols[attr.name], showType(*attr.value)).debugThrow();
}
#pragma GCC diagnostic pop
}
static FlakeInput parseFlakeInput(
EvalState & state,
std::string_view inputName,
Value * value,
const PosIdx pos,
const InputPath & lockRootPath,
const InputAttrPath & lockRootAttrPath,
const SourcePath & flakeDir)
{
expectType(state, nAttrs, *value, pos);
@ -137,7 +186,7 @@ static FlakeInput parseFlakeInput(
else if (attr.value->type() == nPath) {
auto path = attr.value->path();
if (path.accessor != flakeDir.accessor)
throw Error("input path '%s' at %s must be in the same source tree as %s",
throw Error("input attribute path '%s' at %s must be in the same source tree as %s",
path, state.positions[attr.pos], flakeDir);
url = "path:" + flakeDir.path.makeRelative(path.path);
}
@ -149,44 +198,14 @@ static FlakeInput parseFlakeInput(
expectType(state, nBool, *attr.value, attr.pos);
input.isFlake = attr.value->boolean();
} else if (attr.name == sInputs) {
input.overrides = parseFlakeInputs(state, attr.value, attr.pos, lockRootPath, flakeDir);
input.overrides = parseFlakeInputs(state, attr.value, attr.pos, lockRootAttrPath, flakeDir, false).first;
} else if (attr.name == sFollows) {
expectType(state, nString, *attr.value, attr.pos);
auto follows(parseInputPath(attr.value->c_str()));
follows.insert(follows.begin(), lockRootPath.begin(), lockRootPath.end());
auto follows(parseInputAttrPath(attr.value->c_str()));
follows.insert(follows.begin(), lockRootAttrPath.begin(), lockRootAttrPath.end());
input.follows = follows;
} else {
// Allow selecting a subset of enum values
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch-enum"
switch (attr.value->type()) {
case nString:
attrs.emplace(state.symbols[attr.name], attr.value->c_str());
break;
case nBool:
attrs.emplace(state.symbols[attr.name], Explicit<bool> { attr.value->boolean() });
break;
case nInt: {
auto intValue = attr.value->integer().value;
if (intValue < 0) {
state.error<EvalError>("negative value given for flake input attribute %1%: %2%", state.symbols[attr.name], intValue).debugThrow();
}
attrs.emplace(state.symbols[attr.name], uint64_t(intValue));
break;
}
default:
if (attr.name == state.symbols.create("publicKeys")) {
experimentalFeatureSettings.require(Xp::VerifiedFetches);
NixStringContext emptyContext = {};
attrs.emplace(state.symbols[attr.name], printValueAsJSON(state, true, *attr.value, pos, emptyContext).dump());
} else
state.error<TypeError>("flake input attribute '%s' is %s while a string, Boolean, or integer is expected",
state.symbols[attr.name], showType(*attr.value)).debugThrow();
}
#pragma GCC diagnostic pop
}
} else
parseFlakeInputAttr(state, attr, attrs);
} catch (Error & e) {
e.addTrace(
state.positions[attr.pos],
@ -216,28 +235,39 @@ static FlakeInput parseFlakeInput(
return input;
}
static std::map<FlakeId, FlakeInput> parseFlakeInputs(
static std::pair<std::map<FlakeId, FlakeInput>, fetchers::Attrs> parseFlakeInputs(
EvalState & state,
Value * value,
const PosIdx pos,
const InputPath & lockRootPath,
const SourcePath & flakeDir)
const InputAttrPath & lockRootAttrPath,
const SourcePath & flakeDir,
bool allowSelf)
{
std::map<FlakeId, FlakeInput> inputs;
fetchers::Attrs selfAttrs;
expectType(state, nAttrs, *value, pos);
for (auto & inputAttr : *value->attrs()) {
inputs.emplace(state.symbols[inputAttr.name],
parseFlakeInput(state,
state.symbols[inputAttr.name],
inputAttr.value,
inputAttr.pos,
lockRootPath,
flakeDir));
auto inputName = state.symbols[inputAttr.name];
if (inputName == "self") {
if (!allowSelf)
throw Error("'self' input attribute not allowed at %s", state.positions[inputAttr.pos]);
expectType(state, nAttrs, *inputAttr.value, inputAttr.pos);
for (auto & attr : *inputAttr.value->attrs())
parseFlakeInputAttr(state, attr, selfAttrs);
} else {
inputs.emplace(inputName,
parseFlakeInput(state,
inputName,
inputAttr.value,
inputAttr.pos,
lockRootAttrPath,
flakeDir));
}
}
return inputs;
return {inputs, selfAttrs};
}
static Flake readFlake(
@ -246,7 +276,7 @@ static Flake readFlake(
const FlakeRef & resolvedRef,
const FlakeRef & lockedRef,
const SourcePath & rootDir,
const InputPath & lockRootPath)
const InputAttrPath & lockRootAttrPath)
{
auto flakeDir = rootDir / CanonPath(resolvedRef.subdir);
auto flakePath = flakeDir / "flake.nix";
@ -269,8 +299,11 @@ static Flake readFlake(
auto sInputs = state.symbols.create("inputs");
if (auto inputs = vInfo.attrs()->get(sInputs))
flake.inputs = parseFlakeInputs(state, inputs->value, inputs->pos, lockRootPath, flakeDir);
if (auto inputs = vInfo.attrs()->get(sInputs)) {
auto [flakeInputs, selfAttrs] = parseFlakeInputs(state, inputs->value, inputs->pos, lockRootAttrPath, flakeDir, true);
flake.inputs = std::move(flakeInputs);
flake.selfAttrs = std::move(selfAttrs);
}
auto sOutputs = state.symbols.create("outputs");
@ -301,10 +334,10 @@ static Flake readFlake(
state.symbols[setting.name],
std::string(state.forceStringNoCtx(*setting.value, setting.pos, "")));
else if (setting.value->type() == nPath) {
NixStringContext emptyContext = {};
auto storePath = fetchToStore(*state.store, setting.value->path(), FetchMode::Copy);
flake.config.settings.emplace(
state.symbols[setting.name],
state.coerceToString(setting.pos, *setting.value, emptyContext, "", false, true, true).toOwned());
state.store->printStorePath(storePath));
}
else if (setting.value->type() == nInt)
flake.config.settings.emplace(
@ -342,17 +375,55 @@ static Flake readFlake(
return flake;
}
static FlakeRef applySelfAttrs(
const FlakeRef & ref,
const Flake & flake)
{
auto newRef(ref);
std::set<std::string> allowedAttrs{"submodules", "lfs"};
for (auto & attr : flake.selfAttrs) {
if (!allowedAttrs.contains(attr.first))
throw Error("flake 'self' attribute '%s' is not supported", attr.first);
newRef.input.attrs.insert_or_assign(attr.first, attr.second);
}
return newRef;
}
static Flake getFlake(
EvalState & state,
const FlakeRef & originalRef,
bool useRegistries,
FlakeCache & flakeCache,
const InputPath & lockRootPath)
const InputAttrPath & lockRootAttrPath)
{
auto [storePath, resolvedRef, lockedRef] = fetchOrSubstituteTree(
// Fetch a lazy tree first.
auto [accessor, resolvedRef, lockedRef] = fetchOrSubstituteTree(
state, originalRef, useRegistries, flakeCache);
return readFlake(state, originalRef, resolvedRef, lockedRef, state.rootPath(state.store->toRealPath(storePath)), lockRootPath);
// Parse/eval flake.nix to get at the input.self attributes.
auto flake = readFlake(state, originalRef, resolvedRef, lockedRef, {accessor}, lockRootAttrPath);
// Re-fetch the tree if necessary.
auto newLockedRef = applySelfAttrs(lockedRef, flake);
if (lockedRef != newLockedRef) {
debug("refetching input '%s' due to self attribute", newLockedRef);
// FIXME: need to remove attrs that are invalidated by the changed input attrs, such as 'narHash'.
newLockedRef.input.attrs.erase("narHash");
auto [accessor2, resolvedRef2, lockedRef2] = fetchOrSubstituteTree(
state, newLockedRef, false, flakeCache);
accessor = accessor2;
lockedRef = lockedRef2;
}
// Copy the tree to the store.
auto storePath = copyInputToStore(state, lockedRef.input, originalRef.input, accessor);
// Re-parse flake.nix from the store.
return readFlake(state, originalRef, resolvedRef, lockedRef, state.storePath(storePath), lockRootAttrPath);
}
Flake getFlake(EvalState & state, const FlakeRef & originalRef, bool useRegistries)
@ -405,12 +476,12 @@ LockedFlake lockFlake(
{
FlakeInput input;
SourcePath sourcePath;
std::optional<InputPath> parentInputPath; // FIXME: rename to inputPathPrefix?
std::optional<InputAttrPath> parentInputAttrPath; // FIXME: rename to inputAttrPathPrefix?
};
std::map<InputPath, OverrideTarget> overrides;
std::set<InputPath> explicitCliOverrides;
std::set<InputPath> overridesUsed, updatesUsed;
std::map<InputAttrPath, OverrideTarget> overrides;
std::set<InputAttrPath> explicitCliOverrides;
std::set<InputAttrPath> overridesUsed, updatesUsed;
std::map<ref<Node>, SourcePath> nodePaths;
for (auto & i : lockFlags.inputOverrides) {
@ -434,9 +505,9 @@ LockedFlake lockFlake(
std::function<void(
const FlakeInputs & flakeInputs,
ref<Node> node,
const InputPath & inputPathPrefix,
const InputAttrPath & inputAttrPathPrefix,
std::shared_ptr<const Node> oldNode,
const InputPath & followsPrefix,
const InputAttrPath & followsPrefix,
const SourcePath & sourcePath,
bool trustLock)>
computeLocks;
@ -448,7 +519,7 @@ LockedFlake lockFlake(
/* The node whose locks are to be updated.*/
ref<Node> node,
/* The path to this node in the lock file graph. */
const InputPath & inputPathPrefix,
const InputAttrPath & inputAttrPathPrefix,
/* The old node, if any, from which locks can be
copied. */
std::shared_ptr<const Node> oldNode,
@ -456,59 +527,59 @@ LockedFlake lockFlake(
interpreted. When a node is initially locked, it's
relative to the node's flake; when it's already locked,
it's relative to the root of the lock file. */
const InputPath & followsPrefix,
const InputAttrPath & followsPrefix,
/* The source path of this node's flake. */
const SourcePath & sourcePath,
bool trustLock)
{
debug("computing lock file node '%s'", printInputPath(inputPathPrefix));
debug("computing lock file node '%s'", printInputAttrPath(inputAttrPathPrefix));
/* Get the overrides (i.e. attributes of the form
'inputs.nixops.inputs.nixpkgs.url = ...'). */
for (auto & [id, input] : flakeInputs) {
for (auto & [idOverride, inputOverride] : input.overrides) {
auto inputPath(inputPathPrefix);
inputPath.push_back(id);
inputPath.push_back(idOverride);
overrides.emplace(inputPath,
auto inputAttrPath(inputAttrPathPrefix);
inputAttrPath.push_back(id);
inputAttrPath.push_back(idOverride);
overrides.emplace(inputAttrPath,
OverrideTarget {
.input = inputOverride,
.sourcePath = sourcePath,
.parentInputPath = inputPathPrefix
.parentInputAttrPath = inputAttrPathPrefix
});
}
}
/* Check whether this input has overrides for a
non-existent input. */
for (auto [inputPath, inputOverride] : overrides) {
auto inputPath2(inputPath);
auto follow = inputPath2.back();
inputPath2.pop_back();
if (inputPath2 == inputPathPrefix && !flakeInputs.count(follow))
for (auto [inputAttrPath, inputOverride] : overrides) {
auto inputAttrPath2(inputAttrPath);
auto follow = inputAttrPath2.back();
inputAttrPath2.pop_back();
if (inputAttrPath2 == inputAttrPathPrefix && !flakeInputs.count(follow))
warn(
"input '%s' has an override for a non-existent input '%s'",
printInputPath(inputPathPrefix), follow);
printInputAttrPath(inputAttrPathPrefix), follow);
}
/* Go over the flake inputs, resolve/fetch them if
necessary (i.e. if they're new or the flakeref changed
from what's in the lock file). */
for (auto & [id, input2] : flakeInputs) {
auto inputPath(inputPathPrefix);
inputPath.push_back(id);
auto inputPathS = printInputPath(inputPath);
debug("computing input '%s'", inputPathS);
auto inputAttrPath(inputAttrPathPrefix);
inputAttrPath.push_back(id);
auto inputAttrPathS = printInputAttrPath(inputAttrPath);
debug("computing input '%s'", inputAttrPathS);
try {
/* Do we have an override for this input from one of the
ancestors? */
auto i = overrides.find(inputPath);
auto i = overrides.find(inputAttrPath);
bool hasOverride = i != overrides.end();
bool hasCliOverride = explicitCliOverrides.contains(inputPath);
bool hasCliOverride = explicitCliOverrides.contains(inputAttrPath);
if (hasOverride)
overridesUsed.insert(inputPath);
overridesUsed.insert(inputAttrPath);
auto input = hasOverride ? i->second.input : input2;
/* Resolve relative 'path:' inputs relative to
@ -523,11 +594,11 @@ LockedFlake lockFlake(
/* Resolve 'follows' later (since it may refer to an input
path we haven't processed yet. */
if (input.follows) {
InputPath target;
InputAttrPath target;
target.insert(target.end(), input.follows->begin(), input.follows->end());
debug("input '%s' follows '%s'", inputPathS, printInputPath(target));
debug("input '%s' follows '%s'", inputAttrPathS, printInputAttrPath(target));
node->inputs.insert_or_assign(id, target);
continue;
}
@ -536,7 +607,7 @@ LockedFlake lockFlake(
auto overridenParentPath =
input.ref->input.isRelative()
? std::optional<InputPath>(hasOverride ? i->second.parentInputPath : inputPathPrefix)
? std::optional<InputAttrPath>(hasOverride ? i->second.parentInputAttrPath : inputAttrPathPrefix)
: std::nullopt;
auto resolveRelativePath = [&]() -> std::optional<SourcePath>
@ -555,9 +626,9 @@ LockedFlake lockFlake(
auto getInputFlake = [&](const FlakeRef & ref)
{
if (auto resolvedPath = resolveRelativePath()) {
return readFlake(state, ref, ref, ref, *resolvedPath, inputPath);
return readFlake(state, ref, ref, ref, *resolvedPath, inputAttrPath);
} else {
return getFlake(state, ref, useRegistries, flakeCache, inputPath);
return getFlake(state, ref, useRegistries, flakeCache, inputAttrPath);
}
};
@ -565,19 +636,19 @@ LockedFlake lockFlake(
And the input is not in updateInputs? */
std::shared_ptr<LockedNode> oldLock;
updatesUsed.insert(inputPath);
updatesUsed.insert(inputAttrPath);
if (oldNode && !lockFlags.inputUpdates.count(inputPath))
if (oldNode && !lockFlags.inputUpdates.count(inputAttrPath))
if (auto oldLock2 = get(oldNode->inputs, id))
if (auto oldLock3 = std::get_if<0>(&*oldLock2))
oldLock = *oldLock3;
if (oldLock
&& oldLock->originalRef == *input.ref
&& oldLock->parentPath == overridenParentPath
&& oldLock->parentInputAttrPath == overridenParentPath
&& !hasCliOverride)
{
debug("keeping existing input '%s'", inputPathS);
debug("keeping existing input '%s'", inputAttrPathS);
/* Copy the input from the old lock since its flakeref
didn't change and there is no override from a
@ -586,18 +657,18 @@ LockedFlake lockFlake(
oldLock->lockedRef,
oldLock->originalRef,
oldLock->isFlake,
oldLock->parentPath);
oldLock->parentInputAttrPath);
node->inputs.insert_or_assign(id, childNode);
/* If we have this input in updateInputs, then we
must fetch the flake to update it. */
auto lb = lockFlags.inputUpdates.lower_bound(inputPath);
auto lb = lockFlags.inputUpdates.lower_bound(inputAttrPath);
auto mustRefetch =
lb != lockFlags.inputUpdates.end()
&& lb->size() > inputPath.size()
&& std::equal(inputPath.begin(), inputPath.end(), lb->begin());
&& lb->size() > inputAttrPath.size()
&& std::equal(inputAttrPath.begin(), inputAttrPath.end(), lb->begin());
FlakeInputs fakeInputs;
@ -616,7 +687,7 @@ LockedFlake lockFlake(
if (!trustLock) {
// It is possible that the flake has changed,
// so we must confirm all the follows that are in the lock file are also in the flake.
auto overridePath(inputPath);
auto overridePath(inputAttrPath);
overridePath.push_back(i.first);
auto o = overrides.find(overridePath);
// If the override disappeared, we have to refetch the flake,
@ -640,21 +711,21 @@ LockedFlake lockFlake(
if (mustRefetch) {
auto inputFlake = getInputFlake(oldLock->lockedRef);
nodePaths.emplace(childNode, inputFlake.path.parent());
computeLocks(inputFlake.inputs, childNode, inputPath, oldLock, followsPrefix,
computeLocks(inputFlake.inputs, childNode, inputAttrPath, oldLock, followsPrefix,
inputFlake.path, false);
} else {
computeLocks(fakeInputs, childNode, inputPath, oldLock, followsPrefix, sourcePath, true);
computeLocks(fakeInputs, childNode, inputAttrPath, oldLock, followsPrefix, sourcePath, true);
}
} else {
/* We need to create a new lock file entry. So fetch
this input. */
debug("creating new input '%s'", inputPathS);
debug("creating new input '%s'", inputAttrPathS);
if (!lockFlags.allowUnlocked
&& !input.ref->input.isLocked()
&& !input.ref->input.isRelative())
throw Error("cannot update unlocked flake input '%s' in pure mode", inputPathS);
throw Error("cannot update unlocked flake input '%s' in pure mode", inputAttrPathS);
/* Note: in case of an --override-input, we use
the *original* ref (input2.ref) for the
@ -663,7 +734,7 @@ LockedFlake lockFlake(
nuked the next time we update the lock
file. That is, overrides are sticky unless you
use --no-write-lock-file. */
auto ref = (input2.ref && explicitCliOverrides.contains(inputPath)) ? *input2.ref : *input.ref;
auto ref = (input2.ref && explicitCliOverrides.contains(inputAttrPath)) ? *input2.ref : *input.ref;
if (input.isFlake) {
auto inputFlake = getInputFlake(*input.ref);
@ -689,11 +760,11 @@ LockedFlake lockFlake(
own lock file. */
nodePaths.emplace(childNode, inputFlake.path.parent());
computeLocks(
inputFlake.inputs, childNode, inputPath,
inputFlake.inputs, childNode, inputAttrPath,
oldLock
? std::dynamic_pointer_cast<const Node>(oldLock)
: readLockFile(state.fetchSettings, inputFlake.lockFilePath()).root.get_ptr(),
oldLock ? followsPrefix : inputPath,
oldLock ? followsPrefix : inputAttrPath,
inputFlake.path,
false);
}
@ -705,9 +776,13 @@ LockedFlake lockFlake(
if (auto resolvedPath = resolveRelativePath()) {
return {*resolvedPath, *input.ref};
} else {
auto [storePath, resolvedRef, lockedRef] = fetchOrSubstituteTree(
auto [accessor, resolvedRef, lockedRef] = fetchOrSubstituteTree(
state, *input.ref, useRegistries, flakeCache);
return {state.rootPath(state.store->toRealPath(storePath)), lockedRef};
// FIXME: allow input to be lazy.
auto storePath = copyInputToStore(state, lockedRef.input, input.ref->input, accessor);
return {state.storePath(storePath), lockedRef};
}
}();
@ -720,7 +795,7 @@ LockedFlake lockFlake(
}
} catch (Error & e) {
e.addTrace({}, "while updating the flake input '%s'", inputPathS);
e.addTrace({}, "while updating the flake input '%s'", inputAttrPathS);
throw;
}
}
@ -740,11 +815,11 @@ LockedFlake lockFlake(
for (auto & i : lockFlags.inputOverrides)
if (!overridesUsed.count(i.first))
warn("the flag '--override-input %s %s' does not match any input",
printInputPath(i.first), i.second);
printInputAttrPath(i.first), i.second);
for (auto & i : lockFlags.inputUpdates)
if (!updatesUsed.count(i))
warn("'%s' does not match any input of this flake", printInputPath(i));
warn("'%s' does not match any input of this flake", printInputAttrPath(i));
/* Check 'follows' inputs. */
newLockFile.check();
@ -844,21 +919,6 @@ LockedFlake lockFlake(
}
}
std::pair<StorePath, Path> sourcePathToStorePath(
ref<Store> store,
const SourcePath & _path)
{
auto path = _path.path.abs();
if (auto store2 = store.dynamic_pointer_cast<LocalFSStore>()) {
auto realStoreDir = store2->getRealStoreDir();
if (isInDir(path, realStoreDir))
path = store2->storeDir + path.substr(realStoreDir.size());
}
return store->toStorePath(path);
}
void callFlake(EvalState & state,
const LockedFlake & lockedFlake,
Value & vRes)
@ -874,7 +934,7 @@ void callFlake(EvalState & state,
auto lockedNode = node.dynamic_pointer_cast<const LockedNode>();
auto [storePath, subdir] = sourcePathToStorePath(state.store, sourcePath);
auto [storePath, subdir] = state.store->toStorePath(sourcePath.path.abs());
emitTreeAttrs(
state,