forked from lix-project/lix
If we can't write a lock file, pretend the top-level flake is dirty
Alternative to #4639. You can still read flake.lock, but at least in reproducible workflows like NixOS configurations where you require a non-dirty tree, evaluation will fail because there is no rev.
This commit is contained in:
parent
991cc53386
commit
027344ce7e
|
@ -635,8 +635,10 @@ LockedFlake lockFlake(
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
throw Error("cannot write modified lock file of flake '%s' (use '--no-write-lock-file' to ignore)", topRef);
|
throw Error("cannot write modified lock file of flake '%s' (use '--no-write-lock-file' to ignore)", topRef);
|
||||||
} else
|
} else {
|
||||||
warn("not writing modified lock file of flake '%s':\n%s", topRef, chomp(diff));
|
warn("not writing modified lock file of flake '%s':\n%s", topRef, chomp(diff));
|
||||||
|
flake.forceDirty = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return LockedFlake { .flake = std::move(flake), .lockFile = std::move(newLockFile) };
|
return LockedFlake { .flake = std::move(flake), .lockFile = std::move(newLockFile) };
|
||||||
|
@ -659,7 +661,13 @@ void callFlake(EvalState & state,
|
||||||
|
|
||||||
mkString(*vLocks, lockedFlake.lockFile.to_string());
|
mkString(*vLocks, lockedFlake.lockFile.to_string());
|
||||||
|
|
||||||
emitTreeAttrs(state, *lockedFlake.flake.sourceInfo, lockedFlake.flake.lockedRef.input, *vRootSrc);
|
emitTreeAttrs(
|
||||||
|
state,
|
||||||
|
*lockedFlake.flake.sourceInfo,
|
||||||
|
lockedFlake.flake.lockedRef.input,
|
||||||
|
*vRootSrc,
|
||||||
|
false,
|
||||||
|
lockedFlake.flake.forceDirty);
|
||||||
|
|
||||||
mkString(*vRootSubdir, lockedFlake.flake.lockedRef.subdir);
|
mkString(*vRootSubdir, lockedFlake.flake.lockedRef.subdir);
|
||||||
|
|
||||||
|
|
|
@ -58,9 +58,10 @@ struct ConfigFile
|
||||||
/* The contents of a flake.nix file. */
|
/* The contents of a flake.nix file. */
|
||||||
struct Flake
|
struct Flake
|
||||||
{
|
{
|
||||||
FlakeRef originalRef; // the original flake specification (by the user)
|
FlakeRef originalRef; // the original flake specification (by the user)
|
||||||
FlakeRef resolvedRef; // registry references and caching resolved to the specific underlying flake
|
FlakeRef resolvedRef; // registry references and caching resolved to the specific underlying flake
|
||||||
FlakeRef lockedRef; // the specific local store result of invoking the fetcher
|
FlakeRef lockedRef; // the specific local store result of invoking the fetcher
|
||||||
|
bool forceDirty = false; // pretend that 'lockedRef' is dirty
|
||||||
std::optional<std::string> description;
|
std::optional<std::string> description;
|
||||||
std::shared_ptr<const fetchers::Tree> sourceInfo;
|
std::shared_ptr<const fetchers::Tree> sourceInfo;
|
||||||
FlakeInputs inputs;
|
FlakeInputs inputs;
|
||||||
|
@ -140,6 +141,8 @@ void emitTreeAttrs(
|
||||||
EvalState & state,
|
EvalState & state,
|
||||||
const fetchers::Tree & tree,
|
const fetchers::Tree & tree,
|
||||||
const fetchers::Input & input,
|
const fetchers::Input & input,
|
||||||
Value & v, bool emptyRevFallback = false);
|
Value & v,
|
||||||
|
bool emptyRevFallback = false,
|
||||||
|
bool forceDirty = false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,8 @@ void emitTreeAttrs(
|
||||||
const fetchers::Tree & tree,
|
const fetchers::Tree & tree,
|
||||||
const fetchers::Input & input,
|
const fetchers::Input & input,
|
||||||
Value & v,
|
Value & v,
|
||||||
bool emptyRevFallback)
|
bool emptyRevFallback,
|
||||||
|
bool forceDirty)
|
||||||
{
|
{
|
||||||
assert(input.isImmutable());
|
assert(input.isImmutable());
|
||||||
|
|
||||||
|
@ -33,24 +34,28 @@ void emitTreeAttrs(
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("narHash")),
|
mkString(*state.allocAttr(v, state.symbols.create("narHash")),
|
||||||
narHash->to_string(SRI, true));
|
narHash->to_string(SRI, true));
|
||||||
|
|
||||||
if (auto rev = input.getRev()) {
|
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("rev")), rev->gitRev());
|
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), rev->gitShortRev());
|
|
||||||
} else if (emptyRevFallback) {
|
|
||||||
// Backwards compat for `builtins.fetchGit`: dirty repos return an empty sha1 as rev
|
|
||||||
auto emptyHash = Hash(htSHA1);
|
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("rev")), emptyHash.gitRev());
|
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), emptyHash.gitShortRev());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input.getType() == "git")
|
if (input.getType() == "git")
|
||||||
mkBool(*state.allocAttr(v, state.symbols.create("submodules")),
|
mkBool(*state.allocAttr(v, state.symbols.create("submodules")),
|
||||||
fetchers::maybeGetBoolAttr(input.attrs, "submodules").value_or(true));
|
fetchers::maybeGetBoolAttr(input.attrs, "submodules").value_or(true));
|
||||||
|
|
||||||
if (auto revCount = input.getRevCount())
|
if (!forceDirty) {
|
||||||
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), *revCount);
|
|
||||||
else if (emptyRevFallback)
|
if (auto rev = input.getRev()) {
|
||||||
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), 0);
|
mkString(*state.allocAttr(v, state.symbols.create("rev")), rev->gitRev());
|
||||||
|
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), rev->gitShortRev());
|
||||||
|
} else if (emptyRevFallback) {
|
||||||
|
// Backwards compat for `builtins.fetchGit`: dirty repos return an empty sha1 as rev
|
||||||
|
auto emptyHash = Hash(htSHA1);
|
||||||
|
mkString(*state.allocAttr(v, state.symbols.create("rev")), emptyHash.gitRev());
|
||||||
|
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), emptyHash.gitShortRev());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto revCount = input.getRevCount())
|
||||||
|
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), *revCount);
|
||||||
|
else if (emptyRevFallback)
|
||||||
|
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (auto lastModified = input.getLastModified()) {
|
if (auto lastModified = input.getLastModified()) {
|
||||||
mkInt(*state.allocAttr(v, state.symbols.create("lastModified")), *lastModified);
|
mkInt(*state.allocAttr(v, state.symbols.create("lastModified")), *lastModified);
|
||||||
|
@ -167,7 +172,7 @@ static void fetchTree(
|
||||||
if (state.allowedPaths)
|
if (state.allowedPaths)
|
||||||
state.allowedPaths->insert(tree.actualPath);
|
state.allowedPaths->insert(tree.actualPath);
|
||||||
|
|
||||||
emitTreeAttrs(state, tree, input2, v, params.emptyRevFallback);
|
emitTreeAttrs(state, tree, input2, v, params.emptyRevFallback, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
|
|
Loading…
Reference in a new issue