forked from lix-project/lix
Add traces to errors while updating flake lock file
Example: $ nix build --show-trace error: unable to download 'https://api.github.com/repos/NixOS/nixpkgs/commits/no-such-branch': HTTP error 422 ('') response body: { "message": "No commit found for SHA: no-such-branch", "documentation_url": "https://docs.github.com/rest/reference/repos#get-a-commit" } … while fetching the input 'github:NixOS/nixpkgs/no-such-branch' … while updating the flake input 'nixpkgs' … while updating the lock file of flake 'git+file:///home/eelco/Dev/nix'
This commit is contained in:
parent
8e758d402b
commit
c03f41055d
|
@ -298,284 +298,298 @@ LockedFlake lockFlake(
|
||||||
|
|
||||||
auto flake = getFlake(state, topRef, lockFlags.useRegistries, flakeCache);
|
auto flake = getFlake(state, topRef, lockFlags.useRegistries, flakeCache);
|
||||||
|
|
||||||
// FIXME: symlink attack
|
try {
|
||||||
auto oldLockFile = LockFile::read(
|
|
||||||
flake.sourceInfo->actualPath + "/" + flake.lockedRef.subdir + "/flake.lock");
|
|
||||||
|
|
||||||
debug("old lock file: %s", oldLockFile);
|
// FIXME: symlink attack
|
||||||
|
auto oldLockFile = LockFile::read(
|
||||||
|
flake.sourceInfo->actualPath + "/" + flake.lockedRef.subdir + "/flake.lock");
|
||||||
|
|
||||||
// FIXME: check whether all overrides are used.
|
debug("old lock file: %s", oldLockFile);
|
||||||
std::map<InputPath, FlakeInput> overrides;
|
|
||||||
std::set<InputPath> overridesUsed, updatesUsed;
|
|
||||||
|
|
||||||
for (auto & i : lockFlags.inputOverrides)
|
// FIXME: check whether all overrides are used.
|
||||||
overrides.insert_or_assign(i.first, FlakeInput { .ref = i.second });
|
std::map<InputPath, FlakeInput> overrides;
|
||||||
|
std::set<InputPath> overridesUsed, updatesUsed;
|
||||||
|
|
||||||
LockFile newLockFile;
|
for (auto & i : lockFlags.inputOverrides)
|
||||||
|
overrides.insert_or_assign(i.first, FlakeInput { .ref = i.second });
|
||||||
|
|
||||||
std::vector<FlakeRef> parents;
|
LockFile newLockFile;
|
||||||
|
|
||||||
std::function<void(
|
std::vector<FlakeRef> parents;
|
||||||
const FlakeInputs & flakeInputs,
|
|
||||||
std::shared_ptr<Node> node,
|
|
||||||
const InputPath & inputPathPrefix,
|
|
||||||
std::shared_ptr<const Node> oldNode)>
|
|
||||||
computeLocks;
|
|
||||||
|
|
||||||
computeLocks = [&](
|
std::function<void(
|
||||||
const FlakeInputs & flakeInputs,
|
const FlakeInputs & flakeInputs,
|
||||||
std::shared_ptr<Node> node,
|
std::shared_ptr<Node> node,
|
||||||
const InputPath & inputPathPrefix,
|
const InputPath & inputPathPrefix,
|
||||||
std::shared_ptr<const Node> oldNode)
|
std::shared_ptr<const Node> oldNode)>
|
||||||
{
|
computeLocks;
|
||||||
debug("computing lock file node '%s'", printInputPath(inputPathPrefix));
|
|
||||||
|
|
||||||
/* Get the overrides (i.e. attributes of the form
|
computeLocks = [&](
|
||||||
'inputs.nixops.inputs.nixpkgs.url = ...'). */
|
const FlakeInputs & flakeInputs,
|
||||||
// FIXME: check this
|
std::shared_ptr<Node> node,
|
||||||
for (auto & [id, input] : flake.inputs) {
|
const InputPath & inputPathPrefix,
|
||||||
for (auto & [idOverride, inputOverride] : input.overrides) {
|
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);
|
auto inputPath(inputPathPrefix);
|
||||||
inputPath.push_back(id);
|
inputPath.push_back(id);
|
||||||
inputPath.push_back(idOverride);
|
auto inputPathS = printInputPath(inputPath);
|
||||||
overrides.insert_or_assign(inputPath, inputOverride);
|
debug("computing input '%s'", inputPathS);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Go over the flake inputs, resolve/fetch them if
|
try {
|
||||||
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
|
/* Do we have an override for this input from one of the
|
||||||
ancestors? */
|
ancestors? */
|
||||||
auto i = overrides.find(inputPath);
|
auto i = overrides.find(inputPath);
|
||||||
bool hasOverride = i != overrides.end();
|
bool hasOverride = i != overrides.end();
|
||||||
if (hasOverride) overridesUsed.insert(inputPath);
|
if (hasOverride) overridesUsed.insert(inputPath);
|
||||||
auto & input = hasOverride ? i->second : input2;
|
auto & input = hasOverride ? i->second : input2;
|
||||||
|
|
||||||
/* 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;
|
InputPath target;
|
||||||
if (hasOverride || input.absolute)
|
if (hasOverride || input.absolute)
|
||||||
/* 'follows' from an override is relative to the
|
/* 'follows' from an override is relative to the
|
||||||
root of the graph. */
|
root of the graph. */
|
||||||
target = *input.follows;
|
target = *input.follows;
|
||||||
else {
|
else {
|
||||||
/* Otherwise, it's relative to the current flake. */
|
/* Otherwise, it's relative to the current flake. */
|
||||||
target = inputPathPrefix;
|
target = inputPathPrefix;
|
||||||
for (auto & i : *input.follows) target.push_back(i);
|
for (auto & i : *input.follows) target.push_back(i);
|
||||||
}
|
}
|
||||||
debug("input '%s' follows '%s'", inputPathS, printInputPath(target));
|
debug("input '%s' follows '%s'", inputPathS, printInputPath(target));
|
||||||
node->inputs.insert_or_assign(id, target);
|
node->inputs.insert_or_assign(id, target);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(input.ref);
|
assert(input.ref);
|
||||||
|
|
||||||
/* Do we have an entry in the existing lock file? And we
|
/* Do we have an entry in the existing lock file? And we
|
||||||
don't have a --update-input flag for this input? */
|
don't have a --update-input flag for this input? */
|
||||||
std::shared_ptr<LockedNode> oldLock;
|
std::shared_ptr<LockedNode> oldLock;
|
||||||
|
|
||||||
updatesUsed.insert(inputPath);
|
updatesUsed.insert(inputPath);
|
||||||
|
|
||||||
if (oldNode && !lockFlags.inputUpdates.count(inputPath))
|
if (oldNode && !lockFlags.inputUpdates.count(inputPath))
|
||||||
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
|
||||||
&& !hasOverride)
|
&& !hasOverride)
|
||||||
{
|
{
|
||||||
debug("keeping existing input '%s'", inputPathS);
|
debug("keeping existing input '%s'", inputPathS);
|
||||||
|
|
||||||
/* 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
|
||||||
higher level flake. */
|
higher level flake. */
|
||||||
auto childNode = std::make_shared<LockedNode>(
|
auto childNode = std::make_shared<LockedNode>(
|
||||||
oldLock->lockedRef, oldLock->originalRef, oldLock->isFlake);
|
oldLock->lockedRef, oldLock->originalRef, oldLock->isFlake);
|
||||||
|
|
||||||
node->inputs.insert_or_assign(id, childNode);
|
node->inputs.insert_or_assign(id, childNode);
|
||||||
|
|
||||||
/* If we have an --update-input flag for an input
|
/* If we have an --update-input flag for an input
|
||||||
of this input, then we must fetch the flake to
|
of this input, then we must fetch the flake to
|
||||||
update it. */
|
update it. */
|
||||||
auto lb = lockFlags.inputUpdates.lower_bound(inputPath);
|
auto lb = lockFlags.inputUpdates.lower_bound(inputPath);
|
||||||
|
|
||||||
auto hasChildUpdate =
|
auto hasChildUpdate =
|
||||||
lb != lockFlags.inputUpdates.end()
|
lb != lockFlags.inputUpdates.end()
|
||||||
&& lb->size() > inputPath.size()
|
&& lb->size() > inputPath.size()
|
||||||
&& std::equal(inputPath.begin(), inputPath.end(), lb->begin());
|
&& std::equal(inputPath.begin(), inputPath.end(), lb->begin());
|
||||||
|
|
||||||
if (hasChildUpdate) {
|
if (hasChildUpdate) {
|
||||||
auto inputFlake = getFlake(
|
auto inputFlake = getFlake(
|
||||||
state, oldLock->lockedRef, false, flakeCache);
|
state, oldLock->lockedRef, false, flakeCache);
|
||||||
computeLocks(inputFlake.inputs, childNode, inputPath, oldLock);
|
computeLocks(inputFlake.inputs, childNode, inputPath, oldLock);
|
||||||
} else {
|
} else {
|
||||||
/* No need to fetch this flake, we can be
|
/* No need to fetch this flake, we can be
|
||||||
lazy. However there may be new overrides on the
|
lazy. However there may be new overrides on the
|
||||||
inputs of this flake, so we need to check
|
inputs of this flake, so we need to check
|
||||||
those. */
|
those. */
|
||||||
FlakeInputs fakeInputs;
|
FlakeInputs fakeInputs;
|
||||||
|
|
||||||
for (auto & i : oldLock->inputs) {
|
for (auto & i : oldLock->inputs) {
|
||||||
if (auto lockedNode = std::get_if<0>(&i.second)) {
|
if (auto lockedNode = std::get_if<0>(&i.second)) {
|
||||||
fakeInputs.emplace(i.first, FlakeInput {
|
fakeInputs.emplace(i.first, FlakeInput {
|
||||||
.ref = (*lockedNode)->originalRef,
|
.ref = (*lockedNode)->originalRef,
|
||||||
.isFlake = (*lockedNode)->isFlake,
|
.isFlake = (*lockedNode)->isFlake,
|
||||||
});
|
});
|
||||||
} else if (auto follows = std::get_if<1>(&i.second)) {
|
} else if (auto follows = std::get_if<1>(&i.second)) {
|
||||||
fakeInputs.emplace(i.first, FlakeInput {
|
fakeInputs.emplace(i.first, FlakeInput {
|
||||||
.follows = *follows,
|
.follows = *follows,
|
||||||
.absolute = true
|
.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 {
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
computeLocks(fakeInputs, childNode, inputPath, oldLock);
|
} catch (Error & e) {
|
||||||
}
|
e.addTrace({}, "while updating the flake input '%s'", inputPathS);
|
||||||
|
throw;
|
||||||
} 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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
computeLocks(
|
computeLocks(
|
||||||
flake.inputs, newLockFile.root, {},
|
flake.inputs, newLockFile.root, {},
|
||||||
lockFlags.recreateLockFile ? nullptr : oldLockFile.root);
|
lockFlags.recreateLockFile ? nullptr : oldLockFile.root);
|
||||||
|
|
||||||
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);
|
printInputPath(i.first), i.second);
|
||||||
|
|
||||||
for (auto & i : lockFlags.inputUpdates)
|
for (auto & i : lockFlags.inputUpdates)
|
||||||
if (!updatesUsed.count(i))
|
if (!updatesUsed.count(i))
|
||||||
warn("the flag '--update-input %s' does not match any input", printInputPath(i));
|
warn("the flag '--update-input %s' does not match any input", printInputPath(i));
|
||||||
|
|
||||||
/* Check 'follows' inputs. */
|
/* Check 'follows' inputs. */
|
||||||
newLockFile.check();
|
newLockFile.check();
|
||||||
|
|
||||||
debug("new lock file: %s", newLockFile);
|
debug("new lock file: %s", newLockFile);
|
||||||
|
|
||||||
/* Check whether we need to / can write the new lock file. */
|
/* Check whether we need to / can write the new lock file. */
|
||||||
if (!(newLockFile == oldLockFile)) {
|
if (!(newLockFile == oldLockFile)) {
|
||||||
|
|
||||||
auto diff = LockFile::diff(oldLockFile, newLockFile);
|
auto diff = LockFile::diff(oldLockFile, newLockFile);
|
||||||
|
|
||||||
if (lockFlags.writeLockFile) {
|
if (lockFlags.writeLockFile) {
|
||||||
if (auto sourcePath = topRef.input.getSourcePath()) {
|
if (auto sourcePath = topRef.input.getSourcePath()) {
|
||||||
if (!newLockFile.isImmutable()) {
|
if (!newLockFile.isImmutable()) {
|
||||||
if (settings.warnDirty)
|
if (settings.warnDirty)
|
||||||
warn("will not write lock file of flake '%s' because it has a mutable input", topRef);
|
warn("will not write lock file of flake '%s' because it has a mutable input", topRef);
|
||||||
} else {
|
} else {
|
||||||
if (!lockFlags.updateLockFile)
|
if (!lockFlags.updateLockFile)
|
||||||
throw Error("flake '%s' requires lock file changes but they're not allowed due to '--no-update-lock-file'", topRef);
|
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 relPath = (topRef.subdir == "" ? "" : topRef.subdir + "/") + "flake.lock";
|
||||||
|
|
||||||
auto path = *sourcePath + "/" + relPath;
|
auto path = *sourcePath + "/" + relPath;
|
||||||
|
|
||||||
bool lockFileExists = pathExists(path);
|
bool lockFileExists = pathExists(path);
|
||||||
|
|
||||||
if (lockFileExists) {
|
if (lockFileExists) {
|
||||||
auto s = chomp(diff);
|
auto s = chomp(diff);
|
||||||
if (s.empty())
|
if (s.empty())
|
||||||
warn("updating lock file '%s'", path);
|
warn("updating lock file '%s'", path);
|
||||||
else
|
else
|
||||||
warn("updating lock file '%s':\n%s", path, s);
|
warn("updating lock file '%s':\n%s", path, s);
|
||||||
} else
|
} else
|
||||||
warn("creating lock file '%s'", path);
|
warn("creating lock file '%s'", path);
|
||||||
|
|
||||||
newLockFile.write(path);
|
newLockFile.write(path);
|
||||||
|
|
||||||
topRef.input.markChangedFile(
|
topRef.input.markChangedFile(
|
||||||
(topRef.subdir == "" ? "" : topRef.subdir + "/") + "flake.lock",
|
(topRef.subdir == "" ? "" : topRef.subdir + "/") + "flake.lock",
|
||||||
lockFlags.commitLockFile
|
lockFlags.commitLockFile
|
||||||
? std::optional<std::string>(fmt("%s: %s\n\nFlake input changes:\n\n%s",
|
? std::optional<std::string>(fmt("%s: %s\n\nFlake input changes:\n\n%s",
|
||||||
relPath, lockFileExists ? "Update" : "Add", diff))
|
relPath, lockFileExists ? "Update" : "Add", diff))
|
||||||
: std::nullopt);
|
: std::nullopt);
|
||||||
|
|
||||||
/* Rewriting the lockfile changed the top-level
|
/* Rewriting the lockfile changed the top-level
|
||||||
repo, so we should re-read it. FIXME: we could
|
repo, so we should re-read it. FIXME: we could
|
||||||
also just clear the 'rev' field... */
|
also just clear the 'rev' field... */
|
||||||
auto prevLockedRef = flake.lockedRef;
|
auto prevLockedRef = flake.lockedRef;
|
||||||
FlakeCache dummyCache;
|
FlakeCache dummyCache;
|
||||||
flake = getFlake(state, topRef, lockFlags.useRegistries, dummyCache);
|
flake = getFlake(state, topRef, lockFlags.useRegistries, dummyCache);
|
||||||
|
|
||||||
if (lockFlags.commitLockFile &&
|
if (lockFlags.commitLockFile &&
|
||||||
flake.lockedRef.input.getRev() &&
|
flake.lockedRef.input.getRev() &&
|
||||||
prevLockedRef.input.getRev() != flake.lockedRef.input.getRev())
|
prevLockedRef.input.getRev() != flake.lockedRef.input.getRev())
|
||||||
warn("committed new revision '%s'", flake.lockedRef.input.getRev()->gitRev());
|
warn("committed new revision '%s'", flake.lockedRef.input.getRev()->gitRev());
|
||||||
|
|
||||||
/* Make sure that we picked up the change,
|
/* Make sure that we picked up the change,
|
||||||
i.e. the tree should usually be dirty
|
i.e. the tree should usually be dirty
|
||||||
now. Corner case: we could have reverted from a
|
now. Corner case: we could have reverted from a
|
||||||
dirty to a clean tree! */
|
dirty to a clean tree! */
|
||||||
if (flake.lockedRef.input == prevLockedRef.input
|
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);
|
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
|
} else
|
||||||
throw Error("cannot write modified lock file of flake '%s' (use '--no-write-lock-file' to ignore)", topRef);
|
warn("not writing modified lock file of flake '%s':\n%s", topRef, chomp(diff));
|
||||||
} 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,
|
void callFlake(EvalState & state,
|
||||||
|
|
|
@ -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 == "")
|
if (tree.actualPath == "")
|
||||||
tree.actualPath = store->toRealPath(tree.storePath);
|
tree.actualPath = store->toRealPath(tree.storePath);
|
||||||
|
|
Loading…
Reference in a new issue