aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--flake.lock17
-rw-r--r--flake.nix14
-rw-r--r--src/libexpr/flake/flake.cc544
-rw-r--r--src/libexpr/primops.cc3
-rw-r--r--src/libfetchers/fetchers.cc9
-rw-r--r--src/libmain/shared.cc14
-rw-r--r--src/libstore/filetransfer.cc2
-rw-r--r--src/libutil/args.hh21
-rw-r--r--src/nix/eval.cc6
-rw-r--r--src/nix/hash.cc43
-rw-r--r--src/nix/ls.cc23
-rw-r--r--src/nix/path-info.cc30
-rw-r--r--src/nix/verify.cc13
13 files changed, 402 insertions, 337 deletions
diff --git a/flake.lock b/flake.lock
index 9f8c788ac..6fe52fbfd 100644
--- a/flake.lock
+++ b/flake.lock
@@ -1,21 +1,5 @@
{
"nodes": {
- "lowdown-src": {
- "flake": false,
- "locked": {
- "lastModified": 1598695561,
- "narHash": "sha256-gyH/5j+h/nWw0W8AcR2WKvNBUsiQ7QuxqSJNXAwV+8E=",
- "owner": "kristapsdz",
- "repo": "lowdown",
- "rev": "1705b4a26fbf065d9574dce47a94e8c7c79e052f",
- "type": "github"
- },
- "original": {
- "owner": "kristapsdz",
- "repo": "lowdown",
- "type": "github"
- }
- },
"nixpkgs": {
"locked": {
"lastModified": 1602702596,
@@ -33,7 +17,6 @@
},
"root": {
"inputs": {
- "lowdown-src": "lowdown-src",
"nixpkgs": "nixpkgs"
}
}
diff --git a/flake.nix b/flake.nix
index 9addccd63..fedd0e381 100644
--- a/flake.nix
+++ b/flake.nix
@@ -2,9 +2,9 @@
description = "The purely functional package manager";
inputs.nixpkgs.url = "nixpkgs/nixos-20.09-small";
- inputs.lowdown-src = { url = "github:kristapsdz/lowdown"; flake = false; };
+ #inputs.lowdown-src = { url = "github:kristapsdz/lowdown"; flake = false; };
- outputs = { self, nixpkgs, lowdown-src }:
+ outputs = { self, nixpkgs }:
let
@@ -200,16 +200,14 @@
};
lowdown = with final; stdenv.mkDerivation {
- name = "lowdown-0.7.1";
+ name = "lowdown-0.7.9";
- /*
src = fetchurl {
- url = https://kristaps.bsd.lv/lowdown/snapshots/lowdown-0.7.1.tar.gz;
- hash = "sha512-1daoAQfYD0LdhK6aFhrSQvadjc5GsSPBZw0fJDb+BEHYMBLjqiUl2A7H8N+l0W4YfGKqbsPYSrCy4vct+7U6FQ==";
+ url = https://kristaps.bsd.lv/lowdown/snapshots/lowdown-0.7.9.tar.gz;
+ hash = "sha512-7GQrKFICyTI5T4SinATfohiCq9TC0OgN8NmVfG3B3BZJM9J00DT8llAco8kNykLIKtl/AXuS4X8fETiCFEWEUQ==";
};
- */
- src = lowdown-src;
+ #src = lowdown-src;
outputs = [ "out" "bin" "dev" ];
diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc
index 0786fef3d..2e94490d4 100644
--- a/src/libexpr/flake/flake.cc
+++ b/src/libexpr/flake/flake.cc
@@ -298,284 +298,298 @@ LockedFlake lockFlake(
auto flake = getFlake(state, topRef, lockFlags.useRegistries, flakeCache);
- // FIXME: symlink attack
- auto oldLockFile = LockFile::read(
- flake.sourceInfo->actualPath + "/" + flake.lockedRef.subdir + "/flake.lock");
-
- debug("old lock file: %s", oldLockFile);
-
- // FIXME: check whether all overrides are used.
- std::map<InputPath, FlakeInput> overrides;
- std::set<InputPath> overridesUsed, updatesUsed;
-
- for (auto & i : lockFlags.inputOverrides)
- overrides.insert_or_assign(i.first, FlakeInput { .ref = i.second });
-
- LockFile newLockFile;
-
- std::vector<FlakeRef> parents;
-
- std::function<void(
- const FlakeInputs & flakeInputs,
- std::shared_ptr<Node> node,
- const InputPath & inputPathPrefix,
- std::shared_ptr<const Node> oldNode)>
- computeLocks;
-
- computeLocks = [&](
- const FlakeInputs & flakeInputs,
- std::shared_ptr<Node> node,
- const InputPath & inputPathPrefix,
- std::shared_ptr<const Node> oldNode)
- {
- debug("computing lock file node '%s'", printInputPath(inputPathPrefix));
-
- /* Get the overrides (i.e. attributes of the form
- 'inputs.nixops.inputs.nixpkgs.url = ...'). */
- // FIXME: check this
- for (auto & [id, input] : flake.inputs) {
- for (auto & [idOverride, inputOverride] : input.overrides) {
- auto inputPath(inputPathPrefix);
- inputPath.push_back(id);
- inputPath.push_back(idOverride);
- overrides.insert_or_assign(inputPath, inputOverride);
- }
- }
-
- /* 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);
-
- /* Do we have an override for this input from one of the
- ancestors? */
- auto i = overrides.find(inputPath);
- bool hasOverride = i != overrides.end();
- if (hasOverride) overridesUsed.insert(inputPath);
- auto & input = hasOverride ? i->second : input2;
-
- /* Resolve 'follows' later (since it may refer to an input
- path we haven't processed yet. */
- if (input.follows) {
- InputPath target;
- if (hasOverride || input.absolute)
- /* 'follows' from an override is relative to the
- root of the graph. */
- target = *input.follows;
- else {
- /* Otherwise, it's relative to the current flake. */
- target = inputPathPrefix;
- for (auto & i : *input.follows) target.push_back(i);
+ try {
+
+ // FIXME: symlink attack
+ auto oldLockFile = LockFile::read(
+ flake.sourceInfo->actualPath + "/" + flake.lockedRef.subdir + "/flake.lock");
+
+ debug("old lock file: %s", oldLockFile);
+
+ // FIXME: check whether all overrides are used.
+ std::map<InputPath, FlakeInput> overrides;
+ std::set<InputPath> overridesUsed, updatesUsed;
+
+ for (auto & i : lockFlags.inputOverrides)
+ overrides.insert_or_assign(i.first, FlakeInput { .ref = i.second });
+
+ LockFile newLockFile;
+
+ std::vector<FlakeRef> parents;
+
+ std::function<void(
+ const FlakeInputs & flakeInputs,
+ std::shared_ptr<Node> node,
+ const InputPath & inputPathPrefix,
+ std::shared_ptr<const Node> oldNode)>
+ computeLocks;
+
+ computeLocks = [&](
+ const FlakeInputs & flakeInputs,
+ std::shared_ptr<Node> node,
+ const InputPath & inputPathPrefix,
+ std::shared_ptr<const Node> oldNode)
+ {
+ debug("computing lock file node '%s'", printInputPath(inputPathPrefix));
+
+ /* Get the overrides (i.e. attributes of the form
+ 'inputs.nixops.inputs.nixpkgs.url = ...'). */
+ // FIXME: check this
+ for (auto & [id, input] : flake.inputs) {
+ for (auto & [idOverride, inputOverride] : input.overrides) {
+ auto inputPath(inputPathPrefix);
+ inputPath.push_back(id);
+ inputPath.push_back(idOverride);
+ overrides.insert_or_assign(inputPath, inputOverride);
}
- debug("input '%s' follows '%s'", inputPathS, printInputPath(target));
- node->inputs.insert_or_assign(id, target);
- continue;
}
- assert(input.ref);
-
- /* Do we have an entry in the existing lock file? And we
- don't have a --update-input flag for this input? */
- std::shared_ptr<LockedNode> oldLock;
-
- updatesUsed.insert(inputPath);
-
- if (oldNode && !lockFlags.inputUpdates.count(inputPath))
- if (auto oldLock2 = get(oldNode->inputs, id))
- if (auto oldLock3 = std::get_if<0>(&*oldLock2))
- oldLock = *oldLock3;
-
- if (oldLock
- && oldLock->originalRef == *input.ref
- && !hasOverride)
- {
- debug("keeping existing input '%s'", inputPathS);
-
- /* Copy the input from the old lock since its flakeref
- didn't change and there is no override from a
- higher level flake. */
- auto childNode = std::make_shared<LockedNode>(
- oldLock->lockedRef, oldLock->originalRef, oldLock->isFlake);
-
- node->inputs.insert_or_assign(id, childNode);
-
- /* If we have an --update-input flag for an input
- of this input, then we must fetch the flake to
- update it. */
- auto lb = lockFlags.inputUpdates.lower_bound(inputPath);
-
- auto hasChildUpdate =
- lb != lockFlags.inputUpdates.end()
- && lb->size() > inputPath.size()
- && std::equal(inputPath.begin(), inputPath.end(), lb->begin());
-
- if (hasChildUpdate) {
- auto inputFlake = getFlake(
- state, oldLock->lockedRef, false, flakeCache);
- computeLocks(inputFlake.inputs, childNode, inputPath, oldLock);
- } else {
- /* No need to fetch this flake, we can be
- lazy. However there may be new overrides on the
- inputs of this flake, so we need to check
- those. */
- FlakeInputs fakeInputs;
-
- for (auto & i : oldLock->inputs) {
- if (auto lockedNode = std::get_if<0>(&i.second)) {
- fakeInputs.emplace(i.first, FlakeInput {
- .ref = (*lockedNode)->originalRef,
- .isFlake = (*lockedNode)->isFlake,
- });
- } else if (auto follows = std::get_if<1>(&i.second)) {
- fakeInputs.emplace(i.first, FlakeInput {
- .follows = *follows,
- .absolute = true
- });
+ /* 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);
+
+ try {
+
+ /* Do we have an override for this input from one of the
+ ancestors? */
+ auto i = overrides.find(inputPath);
+ bool hasOverride = i != overrides.end();
+ if (hasOverride) overridesUsed.insert(inputPath);
+ auto & input = hasOverride ? i->second : input2;
+
+ /* Resolve 'follows' later (since it may refer to an input
+ path we haven't processed yet. */
+ if (input.follows) {
+ InputPath target;
+ if (hasOverride || input.absolute)
+ /* 'follows' from an override is relative to the
+ root of the graph. */
+ target = *input.follows;
+ else {
+ /* Otherwise, it's relative to the current flake. */
+ target = inputPathPrefix;
+ for (auto & i : *input.follows) target.push_back(i);
}
+ debug("input '%s' follows '%s'", inputPathS, printInputPath(target));
+ node->inputs.insert_or_assign(id, target);
+ continue;
}
- computeLocks(fakeInputs, childNode, inputPath, oldLock);
- }
+ assert(input.ref);
+
+ /* Do we have an entry in the existing lock file? And we
+ don't have a --update-input flag for this input? */
+ std::shared_ptr<LockedNode> oldLock;
+
+ updatesUsed.insert(inputPath);
+
+ if (oldNode && !lockFlags.inputUpdates.count(inputPath))
+ if (auto oldLock2 = get(oldNode->inputs, id))
+ if (auto oldLock3 = std::get_if<0>(&*oldLock2))
+ oldLock = *oldLock3;
+
+ if (oldLock
+ && oldLock->originalRef == *input.ref
+ && !hasOverride)
+ {
+ debug("keeping existing input '%s'", inputPathS);
+
+ /* Copy the input from the old lock since its flakeref
+ didn't change and there is no override from a
+ higher level flake. */
+ auto childNode = std::make_shared<LockedNode>(
+ oldLock->lockedRef, oldLock->originalRef, oldLock->isFlake);
+
+ node->inputs.insert_or_assign(id, childNode);
+
+ /* If we have an --update-input flag for an input
+ of this input, then we must fetch the flake to
+ update it. */
+ auto lb = lockFlags.inputUpdates.lower_bound(inputPath);
+
+ auto hasChildUpdate =
+ lb != lockFlags.inputUpdates.end()
+ && lb->size() > inputPath.size()
+ && std::equal(inputPath.begin(), inputPath.end(), lb->begin());
+
+ if (hasChildUpdate) {
+ auto inputFlake = getFlake(
+ state, oldLock->lockedRef, false, flakeCache);
+ computeLocks(inputFlake.inputs, childNode, inputPath, oldLock);
+ } else {
+ /* No need to fetch this flake, we can be
+ lazy. However there may be new overrides on the
+ inputs of this flake, so we need to check
+ those. */
+ FlakeInputs fakeInputs;
+
+ for (auto & i : oldLock->inputs) {
+ if (auto lockedNode = std::get_if<0>(&i.second)) {
+ fakeInputs.emplace(i.first, FlakeInput {
+ .ref = (*lockedNode)->originalRef,
+ .isFlake = (*lockedNode)->isFlake,
+ });
+ } else if (auto follows = std::get_if<1>(&i.second)) {
+ fakeInputs.emplace(i.first, FlakeInput {
+ .follows = *follows,
+ .absolute = true
+ });
+ }
+ }
+
+ computeLocks(fakeInputs, childNode, inputPath, oldLock);
+ }
- } else {
- /* We need to create a new lock file entry. So fetch
- this input. */
- debug("creating new input '%s'", inputPathS);
-
- 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);
-
- /* Note: in case of an --override-input, we use
- the *original* ref (input2.ref) for the
- "original" field, rather than the
- override. This ensures that the override isn't
- nuked the next time we update the lock
- file. That is, overrides are sticky unless you
- use --no-write-lock-file. */
- auto childNode = std::make_shared<LockedNode>(
- inputFlake.lockedRef, input2.ref ? *input2.ref : *input.ref);
-
- node->inputs.insert_or_assign(id, childNode);
-
- /* Guard against circular flake imports. */
- for (auto & parent : parents)
- if (parent == *input.ref)
- throw Error("found circular import of flake '%s'", parent);
- parents.push_back(*input.ref);
- Finally cleanup([&]() { parents.pop_back(); });
-
- /* Recursively process the inputs of this
- flake. Also, unless we already have this flake
- in the top-level lock file, use this flake's
- own lock file. */
- computeLocks(
- inputFlake.inputs, childNode, inputPath,
- oldLock
- ? std::dynamic_pointer_cast<const Node>(oldLock)
- : LockFile::read(
- inputFlake.sourceInfo->actualPath + "/" + inputFlake.lockedRef.subdir + "/flake.lock").root);
- }
+ } else {
+ /* We need to create a new lock file entry. So fetch
+ this input. */
+ debug("creating new input '%s'", inputPathS);
+
+ 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);
+
+ /* Note: in case of an --override-input, we use
+ the *original* ref (input2.ref) for the
+ "original" field, rather than the
+ override. This ensures that the override isn't
+ nuked the next time we update the lock
+ file. That is, overrides are sticky unless you
+ use --no-write-lock-file. */
+ auto childNode = std::make_shared<LockedNode>(
+ inputFlake.lockedRef, input2.ref ? *input2.ref : *input.ref);
+
+ node->inputs.insert_or_assign(id, childNode);
+
+ /* Guard against circular flake imports. */
+ for (auto & parent : parents)
+ if (parent == *input.ref)
+ throw Error("found circular import of flake '%s'", parent);
+ parents.push_back(*input.ref);
+ Finally cleanup([&]() { parents.pop_back(); });
+
+ /* Recursively process the inputs of this
+ flake. Also, unless we already have this flake
+ in the top-level lock file, use this flake's
+ own lock file. */
+ computeLocks(
+ inputFlake.inputs, childNode, inputPath,
+ oldLock
+ ? std::dynamic_pointer_cast<const Node>(oldLock)
+ : LockFile::read(
+ inputFlake.sourceInfo->actualPath + "/" + inputFlake.lockedRef.subdir + "/flake.lock").root);
+ }
+
+ else {
+ auto [sourceInfo, resolvedRef, lockedRef] = fetchOrSubstituteTree(
+ state, *input.ref, lockFlags.useRegistries, flakeCache);
+ node->inputs.insert_or_assign(id,
+ std::make_shared<LockedNode>(lockedRef, *input.ref, false));
+ }
+ }
- else {
- auto [sourceInfo, resolvedRef, lockedRef] = fetchOrSubstituteTree(
- state, *input.ref, lockFlags.useRegistries, flakeCache);
- node->inputs.insert_or_assign(id,
- std::make_shared<LockedNode>(lockedRef, *input.ref, false));
+ } catch (Error & e) {
+ e.addTrace({}, "while updating the flake input '%s'", inputPathS);
+ throw;
}
}
+ };
+
+ computeLocks(
+ flake.inputs, newLockFile.root, {},
+ lockFlags.recreateLockFile ? nullptr : oldLockFile.root);
+
+ 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);
+
+ for (auto & i : lockFlags.inputUpdates)
+ if (!updatesUsed.count(i))
+ warn("the flag '--update-input %s' does not match any input", printInputPath(i));
+
+ /* Check 'follows' inputs. */
+ newLockFile.check();
+
+ debug("new lock file: %s", newLockFile);
+
+ /* Check whether we need to / can write the new lock file. */
+ if (!(newLockFile == oldLockFile)) {
+
+ auto diff = LockFile::diff(oldLockFile, newLockFile);
+
+ if (lockFlags.writeLockFile) {
+ 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);
+ } else {
+ if (!lockFlags.updateLockFile)
+ throw Error("flake '%s' requires lock file changes but they're not allowed due to '--no-update-lock-file'", topRef);
+
+ auto relPath = (topRef.subdir == "" ? "" : topRef.subdir + "/") + "flake.lock";
+
+ auto path = *sourcePath + "/" + relPath;
+
+ bool lockFileExists = pathExists(path);
+
+ if (lockFileExists) {
+ auto s = chomp(diff);
+ if (s.empty())
+ warn("updating lock file '%s'", path);
+ else
+ warn("updating lock file '%s':\n%s", path, s);
+ } else
+ warn("creating lock file '%s'", path);
+
+ newLockFile.write(path);
+
+ 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",
+ relPath, lockFileExists ? "Update" : "Add", diff))
+ : std::nullopt);
+
+ /* Rewriting the lockfile changed the top-level
+ repo, so we should re-read it. FIXME: we could
+ also just clear the 'rev' field... */
+ auto prevLockedRef = flake.lockedRef;
+ FlakeCache 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());
+
+ /* 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())
+ throw Error("'%s' did not change after I updated its 'flake.lock' file; is 'flake.lock' under version control?", flake.originalRef);
+ }
+ } else
+ throw Error("cannot write modified lock file of flake '%s' (use '--no-write-lock-file' to ignore)", topRef);
+ } else
+ warn("not writing modified lock file of flake '%s':\n%s", topRef, chomp(diff));
}
- };
- computeLocks(
- flake.inputs, newLockFile.root, {},
- lockFlags.recreateLockFile ? nullptr : oldLockFile.root);
-
- 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);
-
- for (auto & i : lockFlags.inputUpdates)
- if (!updatesUsed.count(i))
- warn("the flag '--update-input %s' does not match any input", printInputPath(i));
-
- /* Check 'follows' inputs. */
- newLockFile.check();
-
- debug("new lock file: %s", newLockFile);
-
- /* Check whether we need to / can write the new lock file. */
- if (!(newLockFile == oldLockFile)) {
-
- auto diff = LockFile::diff(oldLockFile, newLockFile);
-
- if (lockFlags.writeLockFile) {
- 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);
- } else {
- if (!lockFlags.updateLockFile)
- throw Error("flake '%s' requires lock file changes but they're not allowed due to '--no-update-lock-file'", topRef);
-
- auto relPath = (topRef.subdir == "" ? "" : topRef.subdir + "/") + "flake.lock";
-
- auto path = *sourcePath + "/" + relPath;
-
- bool lockFileExists = pathExists(path);
-
- if (lockFileExists) {
- auto s = chomp(diff);
- if (s.empty())
- warn("updating lock file '%s'", path);
- else
- warn("updating lock file '%s':\n%s", path, s);
- } else
- warn("creating lock file '%s'", path);
-
- newLockFile.write(path);
-
- 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",
- relPath, lockFileExists ? "Update" : "Add", diff))
- : std::nullopt);
-
- /* Rewriting the lockfile changed the top-level
- repo, so we should re-read it. FIXME: we could
- also just clear the 'rev' field... */
- auto prevLockedRef = flake.lockedRef;
- FlakeCache 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());
-
- /* 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())
- throw Error("'%s' did not change after I updated its 'flake.lock' file; is 'flake.lock' under version control?", flake.originalRef);
- }
- } else
- throw Error("cannot write modified lock file of flake '%s' (use '--no-write-lock-file' to ignore)", topRef);
- } else
- warn("not writing modified lock file of flake '%s':\n%s", topRef, chomp(diff));
- }
+ return LockedFlake { .flake = std::move(flake), .lockFile = std::move(newLockFile) };
- return LockedFlake { .flake = std::move(flake), .lockFile = std::move(newLockFile) };
+ } catch (Error & e) {
+ e.addTrace({}, "while updating the lock file of flake '%s'", flake.lockedRef.to_string());
+ throw;
+ }
}
void callFlake(EvalState & state,
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index a470ed6df..13565b950 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -118,6 +118,9 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS
.msg = hintfmt("cannot import '%1%', since path '%2%' is not valid", path, e.path),
.errPos = pos
});
+ } catch (Error & e) {
+ e.addTrace(pos, "while importing '%s'", path);
+ throw e;
}
Path realPath = state.checkSourcePath(state.toRealPath(path, context));
diff --git a/src/libfetchers/fetchers.cc b/src/libfetchers/fetchers.cc
index e6741a451..916e0a8e8 100644
--- a/src/libfetchers/fetchers.cc
+++ b/src/libfetchers/fetchers.cc
@@ -132,7 +132,14 @@ std::pair<Tree, Input> Input::fetch(ref<Store> store) const
}
}
- auto [tree, input] = scheme->fetch(store, *this);
+ auto [tree, input] = [&]() -> std::pair<Tree, Input> {
+ try {
+ return scheme->fetch(store, *this);
+ } catch (Error & e) {
+ e.addTrace({}, "while fetching the input '%s'", to_string());
+ throw;
+ }
+ }();
if (tree.actualPath == "")
tree.actualPath = store->toRealPath(tree.storePath);
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index 7e27e95c2..5baaff3e9 100644
--- a/src/libmain/shared.cc
+++ b/src/libmain/shared.cc
@@ -229,11 +229,17 @@ LegacyArgs::LegacyArgs(const std::string & programName,
intSettingAlias(0, "max-silent-time", "Number of seconds of silence before a build is killed.", "max-silent-time");
intSettingAlias(0, "timeout", "Number of seconds before a build is killed.", "timeout");
- mkFlag(0, "readonly-mode", "Do not write to the Nix store.",
- &settings.readOnlyMode);
+ addFlag({
+ .longName = "readonly-mode",
+ .description = "Do not write to the Nix store.",
+ .handler = {&settings.readOnlyMode, true},
+ });
- mkFlag(0, "no-gc-warning", "Disable warnings about not using `--add-root`.",
- &gcWarning, false);
+ addFlag({
+ .longName = "no-gc-warning",
+ .description = "Disable warnings about not using `--add-root`.",
+ .handler = {&gcWarning, true},
+ });
addFlag({
.longName = "store",
diff --git a/src/libstore/filetransfer.cc b/src/libstore/filetransfer.cc
index 563f49170..8ea5cdc9d 100644
--- a/src/libstore/filetransfer.cc
+++ b/src/libstore/filetransfer.cc
@@ -856,7 +856,7 @@ FileTransferError::FileTransferError(FileTransfer::Error error, std::shared_ptr<
// to print different messages for different verbosity levels. For now
// we add some heuristics for detecting when we want to show the response.
if (response && (response->size() < 1024 || response->find("<html>") != string::npos))
- err.msg = hintfmt("%1%\n\nresponse body:\n\n%2%", normaltxt(hf.str()), *response);
+ err.msg = hintfmt("%1%\n\nresponse body:\n\n%2%", normaltxt(hf.str()), chomp(*response));
else
err.msg = hf;
}
diff --git a/src/libutil/args.hh b/src/libutil/args.hh
index b1020b101..42d8515ef 100644
--- a/src/libutil/args.hh
+++ b/src/libutil/args.hh
@@ -135,27 +135,6 @@ public:
void addFlag(Flag && flag);
- /* Helper functions for constructing flags / positional
- arguments. */
-
- void mkFlag(char shortName, const std::string & name,
- const std::string & description, bool * dest)
- {
- mkFlag(shortName, name, description, dest, true);
- }
-
- template<class T>
- void mkFlag(char shortName, const std::string & longName, const std::string & description,
- T * dest, const T & value)
- {
- addFlag({
- .longName = longName,
- .shortName = shortName,
- .description = description,
- .handler = {[=]() { *dest = value; }}
- });
- }
-
void expectArgs(ExpectedArg && arg)
{
expectedArgs.emplace_back(std::move(arg));
diff --git a/src/nix/eval.cc b/src/nix/eval.cc
index b5049ac65..65d61e005 100644
--- a/src/nix/eval.cc
+++ b/src/nix/eval.cc
@@ -18,7 +18,11 @@ struct CmdEval : MixJSON, InstallableCommand
CmdEval()
{
- mkFlag(0, "raw", "Print strings without quotes or escaping.", &raw);
+ addFlag({
+ .longName = "raw",
+ .description = "Print strings without quotes or escaping.",
+ .handler = {&raw, true},
+ });
addFlag({
.longName = "apply",
diff --git a/src/nix/hash.cc b/src/nix/hash.cc
index 79d506ace..4535e4ab0 100644
--- a/src/nix/hash.cc
+++ b/src/nix/hash.cc
@@ -19,18 +19,41 @@ struct CmdHashBase : Command
CmdHashBase(FileIngestionMethod mode) : mode(mode)
{
- mkFlag(0, "sri", "Print the hash in SRI format.", &base, SRI);
- mkFlag(0, "base64", "Print the hash in base-64 format.", &base, Base64);
- mkFlag(0, "base32", "Print the hash in base-32 (Nix-specific) format.", &base, Base32);
- mkFlag(0, "base16", "Print the hash in base-16 format.", &base, Base16);
+ addFlag({
+ .longName = "sri",
+ .description = "Print the hash in SRI format.",
+ .handler = {&base, SRI},
+ });
+
+ addFlag({
+ .longName = "base64",
+ .description = "Print the hash in base-64 format.",
+ .handler = {&base, Base64},
+ });
+
+ addFlag({
+ .longName = "base32",
+ .description = "Print the hash in base-32 (Nix-specific) format.",
+ .handler = {&base, Base32},
+ });
+
+ addFlag({
+ .longName = "base16",
+ .description = "Print the hash in base-16 format.",
+ .handler = {&base, Base16},
+ });
+
addFlag(Flag::mkHashTypeFlag("type", &ht));
+
#if 0
- mkFlag()
- .longName("modulo")
- .description("Compute the hash modulo specified the string.")
- .labels({"modulus"})
- .dest(&modulus);
- #endif
+ addFlag({
+ .longName = "modulo",
+ .description = "Compute the hash modulo the specified string.",
+ .labels = {"modulus"},
+ .handler = {&modulus},
+ });
+ #endif\
+
expectArgs({
.label = "paths",
.handler = {&paths},
diff --git a/src/nix/ls.cc b/src/nix/ls.cc
index c0b1ecb32..c1dc9a95b 100644
--- a/src/nix/ls.cc
+++ b/src/nix/ls.cc
@@ -17,9 +17,26 @@ struct MixLs : virtual Args, MixJSON
MixLs()
{
- mkFlag('R', "recursive", "List subdirectories recursively.", &recursive);
- mkFlag('l', "long", "Show detailed file information.", &verbose);
- mkFlag('d', "directory", "Show directories rather than their contents.", &showDirectory);
+ addFlag({
+ .longName = "recursive",
+ .shortName = 'R',
+ .description = "List subdirectories recursively.",
+ .handler = {&recursive, true},
+ });
+
+ addFlag({
+ .longName = "long",
+ .shortName = 'l',
+ .description = "Show detailed file information.",
+ .handler = {&verbose, true},
+ });
+
+ addFlag({
+ .longName = "directory",
+ .shortName = 'd',
+ .description = "Show directories rather than their contents.",
+ .handler = {&showDirectory, true},
+ });
}
void listText(ref<FSAccessor> accessor)
diff --git a/src/nix/path-info.cc b/src/nix/path-info.cc
index 0fa88f1bf..518cd5568 100644
--- a/src/nix/path-info.cc
+++ b/src/nix/path-info.cc
@@ -18,10 +18,32 @@ struct CmdPathInfo : StorePathsCommand, MixJSON
CmdPathInfo()
{
- mkFlag('s', "size", "Print the size of the NAR serialisation of each path.", &showSize);
- mkFlag('S', "closure-size", "Print the sum of the sizes of the NAR serialisations of the closure of each path.", &showClosureSize);
- mkFlag('h', "human-readable", "With `-s` and `-S`, print sizes in a human-friendly format such as `5.67G`.", &humanReadable);
- mkFlag(0, "sigs", "Show signatures.", &showSigs);
+ addFlag({
+ .longName = "size",
+ .shortName = 's',
+ .description = "Print the size of the NAR serialisation of each path.",
+ .handler = {&showSize, true},
+ });
+
+ addFlag({
+ .longName = "closure-size",
+ .shortName = 'S',
+ .description = "Print the sum of the sizes of the NAR serialisations of the closure of each path.",
+ .handler = {&showClosureSize, true},
+ });
+
+ addFlag({
+ .longName = "human-readable",
+ .shortName = 'h',
+ .description = "With `-s` and `-S`, print sizes in a human-friendly format such as `5.67G`.",
+ .handler = {&humanReadable, true},
+ });
+
+ addFlag({
+ .longName = "sigs",
+ .description = "Show signatures.",
+ .handler = {&showSigs, true},
+ });
}
std::string description() override
diff --git a/src/nix/verify.cc b/src/nix/verify.cc
index 9b04e032a..1721c7f16 100644
--- a/src/nix/verify.cc
+++ b/src/nix/verify.cc
@@ -18,8 +18,17 @@ struct CmdVerify : StorePathsCommand
CmdVerify()
{
- mkFlag(0, "no-contents", "Do not verify the contents of each store path.", &noContents);
- mkFlag(0, "no-trust", "Do not verify whether each store path is trusted.", &noTrust);
+ addFlag({
+ .longName = "no-contents",
+ .description = "Do not verify the contents of each store path.",
+ .handler = {&noContents, true},
+ });
+
+ addFlag({
+ .longName = "no-trust",
+ .description = "Do not verify whether each store path is trusted.",
+ .handler = {&noTrust, true},
+ });
addFlag({
.longName = "substituter",