1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-25 10:41:16 +02:00

Merge pull request #12338 from DeterminateSystems/input-attr-path

Rename InputPath -> InputAttrPath
This commit is contained in:
Robert Hensing 2025-01-24 12:06:37 +01:00 committed by GitHub
commit 9837affddc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 120 additions and 120 deletions

View file

@ -347,7 +347,7 @@ struct MixEnvironment : virtual Args
void setEnviron(); void setEnviron();
}; };
void completeFlakeInputPath( void completeFlakeInputAttrPath(
AddCompletions & completions, AddCompletions & completions,
ref<EvalState> evalState, ref<EvalState> evalState,
const std::vector<FlakeRef> & flakeRefs, const std::vector<FlakeRef> & flakeRefs,

View file

@ -33,7 +33,7 @@ namespace nix {
namespace fs { using namespace std::filesystem; } namespace fs { using namespace std::filesystem; }
void completeFlakeInputPath( void completeFlakeInputAttrPath(
AddCompletions & completions, AddCompletions & completions,
ref<EvalState> evalState, ref<EvalState> evalState,
const std::vector<FlakeRef> & flakeRefs, const std::vector<FlakeRef> & flakeRefs,
@ -117,10 +117,10 @@ MixFlakeOptions::MixFlakeOptions()
.labels = {"input-path"}, .labels = {"input-path"},
.handler = {[&](std::string s) { .handler = {[&](std::string s) {
warn("'--update-input' is a deprecated alias for 'flake update' and will be removed in a future version."); warn("'--update-input' is a deprecated alias for 'flake update' and will be removed in a future version.");
lockFlags.inputUpdates.insert(flake::parseInputPath(s)); lockFlags.inputUpdates.insert(flake::parseInputAttrPath(s));
}}, }},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) { .completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
completeFlakeInputPath(completions, getEvalState(), getFlakeRefsForCompletion(), prefix); completeFlakeInputAttrPath(completions, getEvalState(), getFlakeRefsForCompletion(), prefix);
}} }}
}); });
@ -129,15 +129,15 @@ MixFlakeOptions::MixFlakeOptions()
.description = "Override a specific flake input (e.g. `dwarffs/nixpkgs`). This implies `--no-write-lock-file`.", .description = "Override a specific flake input (e.g. `dwarffs/nixpkgs`). This implies `--no-write-lock-file`.",
.category = category, .category = category,
.labels = {"input-path", "flake-url"}, .labels = {"input-path", "flake-url"},
.handler = {[&](std::string inputPath, std::string flakeRef) { .handler = {[&](std::string inputAttrPath, std::string flakeRef) {
lockFlags.writeLockFile = false; lockFlags.writeLockFile = false;
lockFlags.inputOverrides.insert_or_assign( lockFlags.inputOverrides.insert_or_assign(
flake::parseInputPath(inputPath), flake::parseInputAttrPath(inputAttrPath),
parseFlakeRef(fetchSettings, flakeRef, absPath(getCommandBaseDir()), true)); parseFlakeRef(fetchSettings, flakeRef, absPath(getCommandBaseDir()), true));
}}, }},
.completer = {[&](AddCompletions & completions, size_t n, std::string_view prefix) { .completer = {[&](AddCompletions & completions, size_t n, std::string_view prefix) {
if (n == 0) { if (n == 0) {
completeFlakeInputPath(completions, getEvalState(), getFlakeRefsForCompletion(), prefix); completeFlakeInputAttrPath(completions, getEvalState(), getFlakeRefsForCompletion(), prefix);
} else if (n == 1) { } else if (n == 1) {
completeFlakeRef(completions, getEvalState()->store, prefix); completeFlakeRef(completions, getEvalState()->store, prefix);
} }

View file

@ -25,7 +25,7 @@ let
then getInputByPath lockFile.root inputSpec then getInputByPath lockFile.root inputSpec
else inputSpec; else inputSpec;
# Follow an input path (e.g. ["dwarffs" "nixpkgs"]) from the # Follow an input attrpath (e.g. ["dwarffs" "nixpkgs"]) from the
# root node, returning the final node. # root node, returning the final node.
getInputByPath = nodeName: path: getInputByPath = nodeName: path:
if path == [] if path == []

View file

@ -105,7 +105,7 @@ static std::map<FlakeId, FlakeInput> parseFlakeInputs(
EvalState & state, EvalState & state,
Value * value, Value * value,
const PosIdx pos, const PosIdx pos,
const InputPath & lockRootPath, const InputAttrPath & lockRootAttrPath,
const SourcePath & flakeDir); const SourcePath & flakeDir);
static FlakeInput parseFlakeInput( static FlakeInput parseFlakeInput(
@ -113,7 +113,7 @@ static FlakeInput parseFlakeInput(
std::string_view inputName, std::string_view inputName,
Value * value, Value * value,
const PosIdx pos, const PosIdx pos,
const InputPath & lockRootPath, const InputAttrPath & lockRootAttrPath,
const SourcePath & flakeDir) const SourcePath & flakeDir)
{ {
expectType(state, nAttrs, *value, pos); expectType(state, nAttrs, *value, pos);
@ -137,7 +137,7 @@ static FlakeInput parseFlakeInput(
else if (attr.value->type() == nPath) { else if (attr.value->type() == nPath) {
auto path = attr.value->path(); auto path = attr.value->path();
if (path.accessor != flakeDir.accessor) 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); path, state.positions[attr.pos], flakeDir);
url = "path:" + flakeDir.path.makeRelative(path.path); url = "path:" + flakeDir.path.makeRelative(path.path);
} }
@ -149,11 +149,11 @@ static FlakeInput parseFlakeInput(
expectType(state, nBool, *attr.value, attr.pos); expectType(state, nBool, *attr.value, attr.pos);
input.isFlake = attr.value->boolean(); input.isFlake = attr.value->boolean();
} else if (attr.name == sInputs) { } 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);
} else if (attr.name == sFollows) { } else if (attr.name == sFollows) {
expectType(state, nString, *attr.value, attr.pos); expectType(state, nString, *attr.value, attr.pos);
auto follows(parseInputPath(attr.value->c_str())); auto follows(parseInputAttrPath(attr.value->c_str()));
follows.insert(follows.begin(), lockRootPath.begin(), lockRootPath.end()); follows.insert(follows.begin(), lockRootAttrPath.begin(), lockRootAttrPath.end());
input.follows = follows; input.follows = follows;
} else { } else {
// Allow selecting a subset of enum values // Allow selecting a subset of enum values
@ -220,7 +220,7 @@ static std::map<FlakeId, FlakeInput> parseFlakeInputs(
EvalState & state, EvalState & state,
Value * value, Value * value,
const PosIdx pos, const PosIdx pos,
const InputPath & lockRootPath, const InputAttrPath & lockRootAttrPath,
const SourcePath & flakeDir) const SourcePath & flakeDir)
{ {
std::map<FlakeId, FlakeInput> inputs; std::map<FlakeId, FlakeInput> inputs;
@ -233,7 +233,7 @@ static std::map<FlakeId, FlakeInput> parseFlakeInputs(
state.symbols[inputAttr.name], state.symbols[inputAttr.name],
inputAttr.value, inputAttr.value,
inputAttr.pos, inputAttr.pos,
lockRootPath, lockRootAttrPath,
flakeDir)); flakeDir));
} }
@ -246,7 +246,7 @@ static Flake readFlake(
const FlakeRef & resolvedRef, const FlakeRef & resolvedRef,
const FlakeRef & lockedRef, const FlakeRef & lockedRef,
const SourcePath & rootDir, const SourcePath & rootDir,
const InputPath & lockRootPath) const InputAttrPath & lockRootAttrPath)
{ {
auto flakeDir = rootDir / CanonPath(resolvedRef.subdir); auto flakeDir = rootDir / CanonPath(resolvedRef.subdir);
auto flakePath = flakeDir / "flake.nix"; auto flakePath = flakeDir / "flake.nix";
@ -270,7 +270,7 @@ static Flake readFlake(
auto sInputs = state.symbols.create("inputs"); auto sInputs = state.symbols.create("inputs");
if (auto inputs = vInfo.attrs()->get(sInputs)) if (auto inputs = vInfo.attrs()->get(sInputs))
flake.inputs = parseFlakeInputs(state, inputs->value, inputs->pos, lockRootPath, flakeDir); flake.inputs = parseFlakeInputs(state, inputs->value, inputs->pos, lockRootAttrPath, flakeDir);
auto sOutputs = state.symbols.create("outputs"); auto sOutputs = state.symbols.create("outputs");
@ -347,12 +347,12 @@ static Flake getFlake(
const FlakeRef & originalRef, const FlakeRef & originalRef,
bool useRegistries, bool useRegistries,
FlakeCache & flakeCache, FlakeCache & flakeCache,
const InputPath & lockRootPath) const InputAttrPath & lockRootAttrPath)
{ {
auto [storePath, resolvedRef, lockedRef] = fetchOrSubstituteTree( auto [storePath, resolvedRef, lockedRef] = fetchOrSubstituteTree(
state, originalRef, useRegistries, flakeCache); state, originalRef, useRegistries, flakeCache);
return readFlake(state, originalRef, resolvedRef, lockedRef, state.rootPath(state.store->toRealPath(storePath)), lockRootPath); return readFlake(state, originalRef, resolvedRef, lockedRef, state.rootPath(state.store->toRealPath(storePath)), lockRootAttrPath);
} }
Flake getFlake(EvalState & state, const FlakeRef & originalRef, bool useRegistries) Flake getFlake(EvalState & state, const FlakeRef & originalRef, bool useRegistries)
@ -407,12 +407,12 @@ LockedFlake lockFlake(
{ {
FlakeInput input; FlakeInput input;
SourcePath sourcePath; SourcePath sourcePath;
std::optional<InputPath> parentInputPath; // FIXME: rename to inputPathPrefix? std::optional<InputAttrPath> parentInputAttrPath; // FIXME: rename to inputAttrPathPrefix?
}; };
std::map<InputPath, OverrideTarget> overrides; std::map<InputAttrPath, OverrideTarget> overrides;
std::set<InputPath> explicitCliOverrides; std::set<InputAttrPath> explicitCliOverrides;
std::set<InputPath> overridesUsed, updatesUsed; std::set<InputAttrPath> overridesUsed, updatesUsed;
std::map<ref<Node>, SourcePath> nodePaths; std::map<ref<Node>, SourcePath> nodePaths;
for (auto & i : lockFlags.inputOverrides) { for (auto & i : lockFlags.inputOverrides) {
@ -436,9 +436,9 @@ LockedFlake lockFlake(
std::function<void( std::function<void(
const FlakeInputs & flakeInputs, const FlakeInputs & flakeInputs,
ref<Node> node, ref<Node> node,
const InputPath & inputPathPrefix, const InputAttrPath & inputAttrPathPrefix,
std::shared_ptr<const Node> oldNode, std::shared_ptr<const Node> oldNode,
const InputPath & followsPrefix, const InputAttrPath & followsPrefix,
const SourcePath & sourcePath, const SourcePath & sourcePath,
bool trustLock)> bool trustLock)>
computeLocks; computeLocks;
@ -450,7 +450,7 @@ LockedFlake lockFlake(
/* The node whose locks are to be updated.*/ /* The node whose locks are to be updated.*/
ref<Node> node, ref<Node> node,
/* The path to this node in the lock file graph. */ /* 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 /* The old node, if any, from which locks can be
copied. */ copied. */
std::shared_ptr<const Node> oldNode, std::shared_ptr<const Node> oldNode,
@ -458,59 +458,59 @@ LockedFlake lockFlake(
interpreted. When a node is initially locked, it's interpreted. When a node is initially locked, it's
relative to the node's flake; when it's already locked, relative to the node's flake; when it's already locked,
it's relative to the root of the lock file. */ it's relative to the root of the lock file. */
const InputPath & followsPrefix, const InputAttrPath & followsPrefix,
/* The source path of this node's flake. */ /* The source path of this node's flake. */
const SourcePath & sourcePath, const SourcePath & sourcePath,
bool trustLock) 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 /* Get the overrides (i.e. attributes of the form
'inputs.nixops.inputs.nixpkgs.url = ...'). */ 'inputs.nixops.inputs.nixpkgs.url = ...'). */
for (auto & [id, input] : flakeInputs) { for (auto & [id, input] : flakeInputs) {
for (auto & [idOverride, inputOverride] : input.overrides) { for (auto & [idOverride, inputOverride] : input.overrides) {
auto inputPath(inputPathPrefix); auto inputAttrPath(inputAttrPathPrefix);
inputPath.push_back(id); inputAttrPath.push_back(id);
inputPath.push_back(idOverride); inputAttrPath.push_back(idOverride);
overrides.emplace(inputPath, overrides.emplace(inputAttrPath,
OverrideTarget { OverrideTarget {
.input = inputOverride, .input = inputOverride,
.sourcePath = sourcePath, .sourcePath = sourcePath,
.parentInputPath = inputPathPrefix .parentInputAttrPath = inputAttrPathPrefix
}); });
} }
} }
/* Check whether this input has overrides for a /* Check whether this input has overrides for a
non-existent input. */ non-existent input. */
for (auto [inputPath, inputOverride] : overrides) { for (auto [inputAttrPath, inputOverride] : overrides) {
auto inputPath2(inputPath); auto inputAttrPath2(inputAttrPath);
auto follow = inputPath2.back(); auto follow = inputAttrPath2.back();
inputPath2.pop_back(); inputAttrPath2.pop_back();
if (inputPath2 == inputPathPrefix && !flakeInputs.count(follow)) if (inputAttrPath2 == inputAttrPathPrefix && !flakeInputs.count(follow))
warn( warn(
"input '%s' has an override for a non-existent input '%s'", "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 /* Go over the flake inputs, resolve/fetch them if
necessary (i.e. if they're new or the flakeref changed necessary (i.e. if they're new or the flakeref changed
from what's in the lock file). */ from what's in the lock file). */
for (auto & [id, input2] : flakeInputs) { for (auto & [id, input2] : flakeInputs) {
auto inputPath(inputPathPrefix); auto inputAttrPath(inputAttrPathPrefix);
inputPath.push_back(id); inputAttrPath.push_back(id);
auto inputPathS = printInputPath(inputPath); auto inputAttrPathS = printInputAttrPath(inputAttrPath);
debug("computing input '%s'", inputPathS); debug("computing input '%s'", inputAttrPathS);
try { try {
/* Do we have an override for this input from one of the /* Do we have an override for this input from one of the
ancestors? */ ancestors? */
auto i = overrides.find(inputPath); auto i = overrides.find(inputAttrPath);
bool hasOverride = i != overrides.end(); bool hasOverride = i != overrides.end();
bool hasCliOverride = explicitCliOverrides.contains(inputPath); bool hasCliOverride = explicitCliOverrides.contains(inputAttrPath);
if (hasOverride) if (hasOverride)
overridesUsed.insert(inputPath); overridesUsed.insert(inputAttrPath);
auto input = hasOverride ? i->second.input : input2; auto input = hasOverride ? i->second.input : input2;
/* Resolve relative 'path:' inputs relative to /* Resolve relative 'path:' inputs relative to
@ -525,11 +525,11 @@ LockedFlake lockFlake(
/* Resolve 'follows' later (since it may refer to an input /* Resolve 'follows' later (since it may refer to an input
path we haven't processed yet. */ path we haven't processed yet. */
if (input.follows) { if (input.follows) {
InputPath target; InputAttrPath target;
target.insert(target.end(), input.follows->begin(), input.follows->end()); 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); node->inputs.insert_or_assign(id, target);
continue; continue;
} }
@ -538,7 +538,7 @@ LockedFlake lockFlake(
auto overridenParentPath = auto overridenParentPath =
input.ref->input.isRelative() input.ref->input.isRelative()
? std::optional<InputPath>(hasOverride ? i->second.parentInputPath : inputPathPrefix) ? std::optional<InputAttrPath>(hasOverride ? i->second.parentInputAttrPath : inputAttrPathPrefix)
: std::nullopt; : std::nullopt;
auto resolveRelativePath = [&]() -> std::optional<SourcePath> auto resolveRelativePath = [&]() -> std::optional<SourcePath>
@ -557,9 +557,9 @@ LockedFlake lockFlake(
auto getInputFlake = [&]() auto getInputFlake = [&]()
{ {
if (auto resolvedPath = resolveRelativePath()) { if (auto resolvedPath = resolveRelativePath()) {
return readFlake(state, *input.ref, *input.ref, *input.ref, *resolvedPath, inputPath); return readFlake(state, *input.ref, *input.ref, *input.ref, *resolvedPath, inputAttrPath);
} else { } else {
return getFlake(state, *input.ref, useRegistries, flakeCache, inputPath); return getFlake(state, *input.ref, useRegistries, flakeCache, inputAttrPath);
} }
}; };
@ -567,19 +567,19 @@ LockedFlake lockFlake(
And the input is not in updateInputs? */ And the input is not in updateInputs? */
std::shared_ptr<LockedNode> oldLock; 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 oldLock2 = get(oldNode->inputs, id))
if (auto oldLock3 = std::get_if<0>(&*oldLock2)) if (auto oldLock3 = std::get_if<0>(&*oldLock2))
oldLock = *oldLock3; oldLock = *oldLock3;
if (oldLock if (oldLock
&& oldLock->originalRef == *input.ref && oldLock->originalRef == *input.ref
&& oldLock->parentPath == overridenParentPath && oldLock->parentInputAttrPath == overridenParentPath
&& !hasCliOverride) && !hasCliOverride)
{ {
debug("keeping existing input '%s'", inputPathS); debug("keeping existing input '%s'", inputAttrPathS);
/* Copy the input from the old lock since its flakeref /* Copy the input from the old lock since its flakeref
didn't change and there is no override from a didn't change and there is no override from a
@ -588,18 +588,18 @@ LockedFlake lockFlake(
oldLock->lockedRef, oldLock->lockedRef,
oldLock->originalRef, oldLock->originalRef,
oldLock->isFlake, oldLock->isFlake,
oldLock->parentPath); oldLock->parentInputAttrPath);
node->inputs.insert_or_assign(id, childNode); node->inputs.insert_or_assign(id, childNode);
/* If we have this input in updateInputs, then we /* If we have this input in updateInputs, then we
must fetch the flake to update it. */ must fetch the flake to update it. */
auto lb = lockFlags.inputUpdates.lower_bound(inputPath); auto lb = lockFlags.inputUpdates.lower_bound(inputAttrPath);
auto mustRefetch = auto mustRefetch =
lb != lockFlags.inputUpdates.end() lb != lockFlags.inputUpdates.end()
&& lb->size() > inputPath.size() && lb->size() > inputAttrPath.size()
&& std::equal(inputPath.begin(), inputPath.end(), lb->begin()); && std::equal(inputAttrPath.begin(), inputAttrPath.end(), lb->begin());
FlakeInputs fakeInputs; FlakeInputs fakeInputs;
@ -618,7 +618,7 @@ LockedFlake lockFlake(
if (!trustLock) { if (!trustLock) {
// It is possible that the flake has changed, // 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. // 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); overridePath.push_back(i.first);
auto o = overrides.find(overridePath); auto o = overrides.find(overridePath);
// If the override disappeared, we have to refetch the flake, // If the override disappeared, we have to refetch the flake,
@ -642,21 +642,21 @@ LockedFlake lockFlake(
if (mustRefetch) { if (mustRefetch) {
auto inputFlake = getInputFlake(); auto inputFlake = getInputFlake();
nodePaths.emplace(childNode, inputFlake.path.parent()); nodePaths.emplace(childNode, inputFlake.path.parent());
computeLocks(inputFlake.inputs, childNode, inputPath, oldLock, followsPrefix, computeLocks(inputFlake.inputs, childNode, inputAttrPath, oldLock, followsPrefix,
inputFlake.path, false); inputFlake.path, false);
} else { } else {
computeLocks(fakeInputs, childNode, inputPath, oldLock, followsPrefix, sourcePath, true); computeLocks(fakeInputs, childNode, inputAttrPath, oldLock, followsPrefix, sourcePath, true);
} }
} else { } else {
/* We need to create a new lock file entry. So fetch /* We need to create a new lock file entry. So fetch
this input. */ this input. */
debug("creating new input '%s'", inputPathS); debug("creating new input '%s'", inputAttrPathS);
if (!lockFlags.allowUnlocked if (!lockFlags.allowUnlocked
&& !input.ref->input.isLocked() && !input.ref->input.isLocked()
&& !input.ref->input.isRelative()) && !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 /* Note: in case of an --override-input, we use
the *original* ref (input2.ref) for the the *original* ref (input2.ref) for the
@ -665,7 +665,7 @@ LockedFlake lockFlake(
nuked the next time we update the lock nuked the next time we update the lock
file. That is, overrides are sticky unless you file. That is, overrides are sticky unless you
use --no-write-lock-file. */ 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) { if (input.isFlake) {
auto inputFlake = getInputFlake(); auto inputFlake = getInputFlake();
@ -691,11 +691,11 @@ LockedFlake lockFlake(
own lock file. */ own lock file. */
nodePaths.emplace(childNode, inputFlake.path.parent()); nodePaths.emplace(childNode, inputFlake.path.parent());
computeLocks( computeLocks(
inputFlake.inputs, childNode, inputPath, inputFlake.inputs, childNode, inputAttrPath,
oldLock oldLock
? std::dynamic_pointer_cast<const Node>(oldLock) ? std::dynamic_pointer_cast<const Node>(oldLock)
: readLockFile(state.fetchSettings, inputFlake.lockFilePath()).root.get_ptr(), : readLockFile(state.fetchSettings, inputFlake.lockFilePath()).root.get_ptr(),
oldLock ? followsPrefix : inputPath, oldLock ? followsPrefix : inputAttrPath,
inputFlake.path, inputFlake.path,
false); false);
} }
@ -722,7 +722,7 @@ LockedFlake lockFlake(
} }
} catch (Error & e) { } catch (Error & e) {
e.addTrace({}, "while updating the flake input '%s'", inputPathS); e.addTrace({}, "while updating the flake input '%s'", inputAttrPathS);
throw; throw;
} }
} }
@ -742,11 +742,11 @@ LockedFlake lockFlake(
for (auto & i : lockFlags.inputOverrides) for (auto & i : lockFlags.inputOverrides)
if (!overridesUsed.count(i.first)) if (!overridesUsed.count(i.first))
warn("the flag '--override-input %s %s' does not match any input", 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) for (auto & i : lockFlags.inputUpdates)
if (!updatesUsed.count(i)) 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. */ /* Check 'follows' inputs. */
newLockFile.check(); newLockFile.check();

View file

@ -57,7 +57,7 @@ struct FlakeInput
* false = (fetched) static source path * false = (fetched) static source path
*/ */
bool isFlake = true; bool isFlake = true;
std::optional<InputPath> follows; std::optional<InputAttrPath> follows;
FlakeInputs overrides; FlakeInputs overrides;
}; };
@ -201,13 +201,13 @@ struct LockFlags
/** /**
* Flake inputs to be overridden. * Flake inputs to be overridden.
*/ */
std::map<InputPath, FlakeRef> inputOverrides; std::map<InputAttrPath, FlakeRef> inputOverrides;
/** /**
* Flake inputs to be updated. This means that any existing lock * Flake inputs to be updated. This means that any existing lock
* for those inputs will be ignored. * for those inputs will be ignored.
*/ */
std::set<InputPath> inputUpdates; std::set<InputAttrPath> inputUpdates;
}; };
LockedFlake lockFlake( LockedFlake lockFlake(

View file

@ -43,7 +43,7 @@ LockedNode::LockedNode(
: lockedRef(getFlakeRef(fetchSettings, json, "locked", "info")) // FIXME: remove "info" : lockedRef(getFlakeRef(fetchSettings, json, "locked", "info")) // FIXME: remove "info"
, originalRef(getFlakeRef(fetchSettings, json, "original", nullptr)) , originalRef(getFlakeRef(fetchSettings, json, "original", nullptr))
, isFlake(json.find("flake") != json.end() ? (bool) json["flake"] : true) , isFlake(json.find("flake") != json.end() ? (bool) json["flake"] : true)
, parentPath(json.find("parent") != json.end() ? (std::optional<InputPath>) json["parent"] : std::nullopt) , parentInputAttrPath(json.find("parent") != json.end() ? (std::optional<InputAttrPath>) json["parent"] : std::nullopt)
{ {
if (!lockedRef.input.isConsideredLocked(fetchSettings) && !lockedRef.input.isRelative()) if (!lockedRef.input.isConsideredLocked(fetchSettings) && !lockedRef.input.isRelative())
throw Error("Lock file contains unlocked input '%s'. Use '--allow-dirty-locks' to accept this lock file.", throw Error("Lock file contains unlocked input '%s'. Use '--allow-dirty-locks' to accept this lock file.",
@ -59,7 +59,7 @@ StorePath LockedNode::computeStorePath(Store & store) const
return lockedRef.input.computeStorePath(store); return lockedRef.input.computeStorePath(store);
} }
static std::shared_ptr<Node> doFind(const ref<Node> & root, const InputPath & path, std::vector<InputPath> & visited) static std::shared_ptr<Node> doFind(const ref<Node> & root, const InputAttrPath & path, std::vector<InputAttrPath> & visited)
{ {
auto pos = root; auto pos = root;
@ -67,8 +67,8 @@ static std::shared_ptr<Node> doFind(const ref<Node> & root, const InputPath & pa
if (found != visited.end()) { if (found != visited.end()) {
std::vector<std::string> cycle; std::vector<std::string> cycle;
std::transform(found, visited.cend(), std::back_inserter(cycle), printInputPath); std::transform(found, visited.cend(), std::back_inserter(cycle), printInputAttrPath);
cycle.push_back(printInputPath(path)); cycle.push_back(printInputAttrPath(path));
throw Error("follow cycle detected: [%s]", concatStringsSep(" -> ", cycle)); throw Error("follow cycle detected: [%s]", concatStringsSep(" -> ", cycle));
} }
visited.push_back(path); visited.push_back(path);
@ -90,9 +90,9 @@ static std::shared_ptr<Node> doFind(const ref<Node> & root, const InputPath & pa
return pos; return pos;
} }
std::shared_ptr<Node> LockFile::findInput(const InputPath & path) std::shared_ptr<Node> LockFile::findInput(const InputAttrPath & path)
{ {
std::vector<InputPath> visited; std::vector<InputAttrPath> visited;
return doFind(root, path, visited); return doFind(root, path, visited);
} }
@ -115,7 +115,7 @@ LockFile::LockFile(
if (jsonNode.find("inputs") == jsonNode.end()) return; if (jsonNode.find("inputs") == jsonNode.end()) return;
for (auto & i : jsonNode["inputs"].items()) { for (auto & i : jsonNode["inputs"].items()) {
if (i.value().is_array()) { // FIXME: remove, obsolete if (i.value().is_array()) { // FIXME: remove, obsolete
InputPath path; InputAttrPath path;
for (auto & j : i.value()) for (auto & j : i.value())
path.push_back(j); path.push_back(j);
node.inputs.insert_or_assign(i.key(), path); node.inputs.insert_or_assign(i.key(), path);
@ -203,8 +203,8 @@ std::pair<nlohmann::json, LockFile::KeyMap> LockFile::toJSON() const
n["locked"].erase("__final"); n["locked"].erase("__final");
if (!lockedNode->isFlake) if (!lockedNode->isFlake)
n["flake"] = false; n["flake"] = false;
if (lockedNode->parentPath) if (lockedNode->parentInputAttrPath)
n["parent"] = *lockedNode->parentPath; n["parent"] = *lockedNode->parentInputAttrPath;
} }
nodes[key] = std::move(n); nodes[key] = std::move(n);
@ -267,36 +267,36 @@ bool LockFile::operator ==(const LockFile & other) const
return toJSON().first == other.toJSON().first; return toJSON().first == other.toJSON().first;
} }
InputPath parseInputPath(std::string_view s) InputAttrPath parseInputAttrPath(std::string_view s)
{ {
InputPath path; InputAttrPath path;
for (auto & elem : tokenizeString<std::vector<std::string>>(s, "/")) { for (auto & elem : tokenizeString<std::vector<std::string>>(s, "/")) {
if (!std::regex_match(elem, flakeIdRegex)) if (!std::regex_match(elem, flakeIdRegex))
throw UsageError("invalid flake input path element '%s'", elem); throw UsageError("invalid flake input attribute path element '%s'", elem);
path.push_back(elem); path.push_back(elem);
} }
return path; return path;
} }
std::map<InputPath, Node::Edge> LockFile::getAllInputs() const std::map<InputAttrPath, Node::Edge> LockFile::getAllInputs() const
{ {
std::set<ref<Node>> done; std::set<ref<Node>> done;
std::map<InputPath, Node::Edge> res; std::map<InputAttrPath, Node::Edge> res;
std::function<void(const InputPath & prefix, ref<Node> node)> recurse; std::function<void(const InputAttrPath & prefix, ref<Node> node)> recurse;
recurse = [&](const InputPath & prefix, ref<Node> node) recurse = [&](const InputAttrPath & prefix, ref<Node> node)
{ {
if (!done.insert(node).second) return; if (!done.insert(node).second) return;
for (auto &[id, input] : node->inputs) { for (auto &[id, input] : node->inputs) {
auto inputPath(prefix); auto inputAttrPath(prefix);
inputPath.push_back(id); inputAttrPath.push_back(id);
res.emplace(inputPath, input); res.emplace(inputAttrPath, input);
if (auto child = std::get_if<0>(&input)) if (auto child = std::get_if<0>(&input))
recurse(inputPath, *child); recurse(inputAttrPath, *child);
} }
}; };
@ -320,7 +320,7 @@ std::ostream & operator <<(std::ostream & stream, const Node::Edge & edge)
if (auto node = std::get_if<0>(&edge)) if (auto node = std::get_if<0>(&edge))
stream << describe((*node)->lockedRef); stream << describe((*node)->lockedRef);
else if (auto follows = std::get_if<1>(&edge)) else if (auto follows = std::get_if<1>(&edge))
stream << fmt("follows '%s'", printInputPath(*follows)); stream << fmt("follows '%s'", printInputAttrPath(*follows));
return stream; return stream;
} }
@ -347,15 +347,15 @@ std::string LockFile::diff(const LockFile & oldLocks, const LockFile & newLocks)
while (i != oldFlat.end() || j != newFlat.end()) { while (i != oldFlat.end() || j != newFlat.end()) {
if (j != newFlat.end() && (i == oldFlat.end() || i->first > j->first)) { if (j != newFlat.end() && (i == oldFlat.end() || i->first > j->first)) {
res += fmt("" ANSI_GREEN "Added input '%s':" ANSI_NORMAL "\n %s\n", res += fmt("" ANSI_GREEN "Added input '%s':" ANSI_NORMAL "\n %s\n",
printInputPath(j->first), j->second); printInputAttrPath(j->first), j->second);
++j; ++j;
} else if (i != oldFlat.end() && (j == newFlat.end() || i->first < j->first)) { } else if (i != oldFlat.end() && (j == newFlat.end() || i->first < j->first)) {
res += fmt("" ANSI_RED "Removed input '%s'" ANSI_NORMAL "\n", printInputPath(i->first)); res += fmt("" ANSI_RED "Removed input '%s'" ANSI_NORMAL "\n", printInputAttrPath(i->first));
++i; ++i;
} else { } else {
if (!equals(i->second, j->second)) { if (!equals(i->second, j->second)) {
res += fmt("" ANSI_BOLD "Updated input '%s':" ANSI_NORMAL "\n %s\n → %s\n", res += fmt("" ANSI_BOLD "Updated input '%s':" ANSI_NORMAL "\n %s\n → %s\n",
printInputPath(i->first), printInputAttrPath(i->first),
i->second, i->second,
j->second); j->second);
} }
@ -371,19 +371,19 @@ void LockFile::check()
{ {
auto inputs = getAllInputs(); auto inputs = getAllInputs();
for (auto & [inputPath, input] : inputs) { for (auto & [inputAttrPath, input] : inputs) {
if (auto follows = std::get_if<1>(&input)) { if (auto follows = std::get_if<1>(&input)) {
if (!follows->empty() && !findInput(*follows)) if (!follows->empty() && !findInput(*follows))
throw Error("input '%s' follows a non-existent input '%s'", throw Error("input '%s' follows a non-existent input '%s'",
printInputPath(inputPath), printInputAttrPath(inputAttrPath),
printInputPath(*follows)); printInputAttrPath(*follows));
} }
} }
} }
void check(); void check();
std::string printInputPath(const InputPath & path) std::string printInputAttrPath(const InputAttrPath & path)
{ {
return concatStringsSep("/", path); return concatStringsSep("/", path);
} }

View file

@ -12,7 +12,7 @@ class StorePath;
namespace nix::flake { namespace nix::flake {
typedef std::vector<FlakeId> InputPath; typedef std::vector<FlakeId> InputAttrPath;
struct LockedNode; struct LockedNode;
@ -23,7 +23,7 @@ struct LockedNode;
*/ */
struct Node : std::enable_shared_from_this<Node> struct Node : std::enable_shared_from_this<Node>
{ {
typedef std::variant<ref<LockedNode>, InputPath> Edge; typedef std::variant<ref<LockedNode>, InputAttrPath> Edge;
std::map<FlakeId, Edge> inputs; std::map<FlakeId, Edge> inputs;
@ -40,17 +40,17 @@ struct LockedNode : Node
/* The node relative to which relative source paths /* The node relative to which relative source paths
(e.g. 'path:../foo') are interpreted. */ (e.g. 'path:../foo') are interpreted. */
std::optional<InputPath> parentPath; std::optional<InputAttrPath> parentInputAttrPath;
LockedNode( LockedNode(
const FlakeRef & lockedRef, const FlakeRef & lockedRef,
const FlakeRef & originalRef, const FlakeRef & originalRef,
bool isFlake = true, bool isFlake = true,
std::optional<InputPath> parentPath = {}) std::optional<InputAttrPath> parentInputAttrPath = {})
: lockedRef(lockedRef) : lockedRef(std::move(lockedRef))
, originalRef(originalRef) , originalRef(std::move(originalRef))
, isFlake(isFlake) , isFlake(isFlake)
, parentPath(parentPath) , parentInputAttrPath(std::move(parentInputAttrPath))
{ } { }
LockedNode( LockedNode(
@ -83,9 +83,9 @@ struct LockFile
bool operator ==(const LockFile & other) const; bool operator ==(const LockFile & other) const;
std::shared_ptr<Node> findInput(const InputPath & path); std::shared_ptr<Node> findInput(const InputAttrPath & path);
std::map<InputPath, Node::Edge> getAllInputs() const; std::map<InputAttrPath, Node::Edge> getAllInputs() const;
static std::string diff(const LockFile & oldLocks, const LockFile & newLocks); static std::string diff(const LockFile & oldLocks, const LockFile & newLocks);
@ -97,8 +97,8 @@ struct LockFile
std::ostream & operator <<(std::ostream & stream, const LockFile & lockFile); std::ostream & operator <<(std::ostream & stream, const LockFile & lockFile);
InputPath parseInputPath(std::string_view s); InputAttrPath parseInputAttrPath(std::string_view s);
std::string printInputPath(const InputPath & path); std::string printInputAttrPath(const InputAttrPath & path);
} }

View file

@ -95,20 +95,20 @@ public:
.optional=true, .optional=true,
.handler={[&](std::vector<std::string> inputsToUpdate){ .handler={[&](std::vector<std::string> inputsToUpdate){
for (const auto & inputToUpdate : inputsToUpdate) { for (const auto & inputToUpdate : inputsToUpdate) {
InputPath inputPath; InputAttrPath inputAttrPath;
try { try {
inputPath = flake::parseInputPath(inputToUpdate); inputAttrPath = flake::parseInputAttrPath(inputToUpdate);
} catch (Error & e) { } catch (Error & e) {
warn("Invalid flake input '%s'. To update a specific flake, use 'nix flake update --flake %s' instead.", inputToUpdate, inputToUpdate); warn("Invalid flake input '%s'. To update a specific flake, use 'nix flake update --flake %s' instead.", inputToUpdate, inputToUpdate);
throw e; throw e;
} }
if (lockFlags.inputUpdates.contains(inputPath)) if (lockFlags.inputUpdates.contains(inputAttrPath))
warn("Input '%s' was specified multiple times. You may have done this by accident."); warn("Input '%s' was specified multiple times. You may have done this by accident.", printInputAttrPath(inputAttrPath));
lockFlags.inputUpdates.insert(inputPath); lockFlags.inputUpdates.insert(inputAttrPath);
} }
}}, }},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) { .completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
completeFlakeInputPath(completions, getEvalState(), getFlakeRefsForCompletion(), prefix); completeFlakeInputAttrPath(completions, getEvalState(), getFlakeRefsForCompletion(), prefix);
}} }}
}); });
@ -304,7 +304,7 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
} else if (auto follows = std::get_if<1>(&input.second)) { } else if (auto follows = std::get_if<1>(&input.second)) {
logger->cout("%s" ANSI_BOLD "%s" ANSI_NORMAL " follows input '%s'", logger->cout("%s" ANSI_BOLD "%s" ANSI_NORMAL " follows input '%s'",
prefix + (last ? treeLast : treeConn), input.first, prefix + (last ? treeLast : treeConn), input.first,
printInputPath(*follows)); printInputAttrPath(*follows));
} }
} }
}; };