Skip to content

Commit

Permalink
Make nix flake metadata|update|lock lazy
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
edolstra committed Feb 6, 2025
1 parent aeac193 commit 304a244
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 23 deletions.
38 changes: 24 additions & 14 deletions src/libflake/flake/flake.cc
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,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(
Expand All @@ -420,17 +421,22 @@ static Flake getFlake(
lockedRef = lockedRef2;
}

// Copy the tree to the store.
auto storePath = copyInputToStore(state, lockedRef.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, 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(
Expand All @@ -456,7 +462,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);
Expand Down Expand Up @@ -632,7 +638,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);
}
};

Expand Down Expand Up @@ -783,10 +789,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, 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, accessor))),
lockedRef
};
}
}();

Expand Down Expand Up @@ -896,7 +906,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() &&
Expand Down
11 changes: 10 additions & 1 deletion src/libflake/flake/flake.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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(
Expand Down
10 changes: 3 additions & 7 deletions src/nix/flake.cc
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ struct CmdFlakeUpdate : FlakeCommand
lockFlags.recreateLockFile = updateAll;
lockFlags.writeLockFile = true;
lockFlags.applyNixConfig = true;
lockFlags.forceLazy = true;

lockFlake();
}
Expand Down Expand Up @@ -165,6 +166,7 @@ struct CmdFlakeLock : FlakeCommand
lockFlags.writeLockFile = true;
lockFlags.failOnUnlocked = true;
lockFlags.applyNixConfig = true;
lockFlags.forceLazy = true;

lockFlake();
}
Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand All @@ -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",
Expand Down
1 change: 0 additions & 1 deletion tests/functional/flakes/flakes.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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) ]]
Expand Down

0 comments on commit 304a244

Please sign in to comment.