1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-07-07 01:51:47 +02:00

Make nix flake metadata|update|lock lazy

These don't need to evaluate anything (except for the flake metadata
in flake.nix) so we can make these commands operate on lazy trees
without risk of any semantic change in the evaluator.

However, `nix flake metadata` now no longer prints the store path,
which is a breaking change (but unavoidable if we want lazy trees).
This commit is contained in:
Eelco Dolstra 2025-02-06 22:39:01 +01:00
parent 3751c06fe1
commit f24ff056cb
4 changed files with 37 additions and 23 deletions

View file

@ -397,7 +397,8 @@ static Flake getFlake(
const FlakeRef & originalRef,
bool useRegistries,
FlakeCache & flakeCache,
const InputAttrPath & lockRootAttrPath)
const InputAttrPath & lockRootAttrPath,
bool forceLazy)
{
// Fetch a lazy tree first.
auto [accessor, resolvedRef, lockedRef] = fetchOrSubstituteTree(
@ -419,17 +420,22 @@ static Flake getFlake(
lockedRef = lockedRef2;
}
// Copy the tree to the store.
auto storePath = copyInputToStore(state, lockedRef.input, originalRef.input, accessor);
// Re-parse flake.nix from the store.
return readFlake(state, originalRef, resolvedRef, lockedRef, state.rootPath(state.store->toRealPath(storePath)), lockRootAttrPath);
return readFlake(
state, originalRef, resolvedRef, lockedRef,
forceLazy && lockedRef.input.isLocked()
? SourcePath(accessor)
: // Copy the tree to the store.
state.rootPath(
state.store->toRealPath(
copyInputToStore(state, lockedRef.input, originalRef.input, accessor))),
lockRootAttrPath);
}
Flake getFlake(EvalState & state, const FlakeRef & originalRef, bool useRegistries)
Flake getFlake(EvalState & state, const FlakeRef & originalRef, bool useRegistries, bool forceLazy)
{
FlakeCache flakeCache;
return getFlake(state, originalRef, useRegistries, flakeCache, {});
return getFlake(state, originalRef, useRegistries, flakeCache, {}, forceLazy);
}
static LockFile readLockFile(
@ -455,7 +461,7 @@ LockedFlake lockFlake(
auto useRegistries = lockFlags.useRegistries.value_or(settings.useRegistries);
auto flake = getFlake(state, topRef, useRegistries, flakeCache, {});
auto flake = getFlake(state, topRef, useRegistries, flakeCache, {}, lockFlags.forceLazy);
if (lockFlags.applyNixConfig) {
flake.config.apply(settings);
@ -630,7 +636,7 @@ LockedFlake lockFlake(
if (auto resolvedPath = resolveRelativePath()) {
return readFlake(state, *input.ref, *input.ref, *input.ref, *resolvedPath, inputAttrPath);
} else {
return getFlake(state, *input.ref, useRegistries, flakeCache, inputAttrPath);
return getFlake(state, *input.ref, useRegistries, flakeCache, inputAttrPath, lockFlags.forceLazy);
}
};
@ -781,10 +787,14 @@ LockedFlake lockFlake(
auto [accessor, resolvedRef, lockedRef] = fetchOrSubstituteTree(
state, *input.ref, useRegistries, flakeCache);
// FIXME: allow input to be lazy.
auto storePath = copyInputToStore(state, lockedRef.input, input.ref->input, accessor);
return {state.rootPath(state.store->toRealPath(storePath)), lockedRef};
return {
lockFlags.forceLazy && lockedRef.input.isLocked()
? SourcePath(accessor)
: state.rootPath(
state.store->toRealPath(
copyInputToStore(state, lockedRef.input, input.ref->input, accessor))),
lockedRef
};
}
}();
@ -894,7 +904,7 @@ LockedFlake lockFlake(
repo, so we should re-read it. FIXME: we could
also just clear the 'rev' field... */
auto prevLockedRef = flake.lockedRef;
flake = getFlake(state, topRef, useRegistries);
flake = getFlake(state, topRef, useRegistries, lockFlags.forceLazy);
if (lockFlags.commitLockFile &&
flake.lockedRef.input.getRev() &&

View file

@ -123,7 +123,11 @@ struct Flake
}
};
Flake getFlake(EvalState & state, const FlakeRef & flakeRef, bool useRegistries);
Flake getFlake(
EvalState & state,
const FlakeRef & flakeRef,
bool useRegistries,
bool forceLazy = false);
/**
* Fingerprint of a locked flake; used as a cache key.
@ -221,6 +225,11 @@ struct LockFlags
* for those inputs will be ignored.
*/
std::set<InputAttrPath> inputUpdates;
/**
* If set, do not copy the flake to the Nix store.
*/
bool forceLazy = false;
};
LockedFlake lockFlake(

View file

@ -133,6 +133,7 @@ public:
lockFlags.recreateLockFile = updateAll;
lockFlags.writeLockFile = true;
lockFlags.applyNixConfig = true;
lockFlags.forceLazy = true;
lockFlake();
}
@ -165,6 +166,7 @@ struct CmdFlakeLock : FlakeCommand
lockFlags.writeLockFile = true;
lockFlags.failOnUnlocked = true;
lockFlags.applyNixConfig = true;
lockFlags.forceLazy = true;
lockFlake();
}
@ -211,12 +213,10 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
void run(nix::ref<nix::Store> store) override
{
lockFlags.forceLazy = true;
auto lockedFlake = lockFlake();
auto & flake = lockedFlake.flake;
// Currently, all flakes are in the Nix store via the rootFS accessor.
auto storePath = store->printStorePath(sourcePathToStorePath(store, flake.path).first);
if (json) {
nlohmann::json j;
if (flake.description)
@ -237,7 +237,6 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
j["revCount"] = *revCount;
if (auto lastModified = flake.lockedRef.input.getLastModified())
j["lastModified"] = *lastModified;
j["path"] = storePath;
j["locks"] = lockedFlake.lockFile.toJSON().first;
if (auto fingerprint = lockedFlake.getFingerprint(store, fetchSettings))
j["fingerprint"] = fingerprint->to_string(HashFormat::Base16, false);
@ -254,9 +253,6 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
logger->cout(
ANSI_BOLD "Description:" ANSI_NORMAL " %s",
*flake.description);
logger->cout(
ANSI_BOLD "Path:" ANSI_NORMAL " %s",
storePath);
if (auto rev = flake.lockedRef.input.getRev())
logger->cout(
ANSI_BOLD "Revision:" ANSI_NORMAL " %s",

View file

@ -69,7 +69,6 @@ nix flake metadata "$flake1Dir" | grepQuiet 'URL:.*flake1.*'
# Test 'nix flake metadata --json'.
json=$(nix flake metadata flake1 --json | jq .)
[[ $(echo "$json" | jq -r .description) = 'Bla bla' ]]
[[ -d $(echo "$json" | jq -r .path) ]]
[[ $(echo "$json" | jq -r .lastModified) = $(git -C "$flake1Dir" log -n1 --format=%ct) ]]
hash1=$(echo "$json" | jq -r .revision)
[[ -n $(echo "$json" | jq -r .fingerprint) ]]