Fix nix-copy-closure --include-outputs

The option has been broken since Nix 2.4. The flag was accepted, but not
used. This change plumbs it through to computeFSClosure.

Change-Id: Id6adee8ea8a6a4f457b24b650660f319e3daa2b2
This commit is contained in:
Erik Jensen
2026-05-26 19:40:07 +00:00
parent 8edb857248
commit eef57410d7
8 changed files with 43 additions and 13 deletions
+5
View File
@@ -248,6 +248,11 @@ raito:
forgejo: raito
github: RaitoBezarius
rkjnsn:
display_name: Erik Jensen
forgejo: rkjnsn
github: rkjnsn
roberth:
display_name: Robert Hensing
github: roberth
@@ -0,0 +1,10 @@
---
synopsis: "Fix `nix-copy-closure --include-outputs`"
issues: [gh#5105]
cls: [5588]
category: "Fixes"
credits: [rkjnsn]
---
The `--include-outputs` flag for `nix-copy-closure` now works as intended.
Previously, the option was accepted but silently ignored.
+1 -1
View File
@@ -55,7 +55,7 @@ static int main_nix_copy_closure(AsyncIoRoot & aio, std::string programName, Str
for (auto & path : storePaths)
storePaths2.insert(from->followLinksToStorePath(path));
aio.blockOn(copyClosure(*from, *to, storePaths2, NoRepair, NoCheckSigs, useSubstitutes));
aio.blockOn(copyClosure(*from, *to, storePaths2, NoRepair, NoCheckSigs, useSubstitutes, includeOutputs));
return 0;
}
+3 -2
View File
@@ -91,14 +91,15 @@ StorePath RealisedPath::path() const {
kj::Promise<Result<void>> RealisedPath::closure(
Store& store,
const RealisedPath::Set& startPaths,
RealisedPath::Set& ret)
RealisedPath::Set& ret,
bool includeOutputs)
try {
// FIXME: This only builds the store-path closure, not the real realisation
// closure
StorePathSet initialStorePaths, pathsClosure;
for (auto& path : startPaths)
initialStorePaths.insert(path.path());
TRY_AWAIT(store.computeFSClosure(initialStorePaths, pathsClosure));
TRY_AWAIT(store.computeFSClosure(initialStorePaths, pathsClosure, false, includeOutputs));
ret.insert(startPaths.begin(), startPaths.end());
ret.insert(pathsClosure.begin(), pathsClosure.end());
co_return result::success();
+1 -1
View File
@@ -125,7 +125,7 @@ struct RealisedPath {
*/
StorePath path() const;
static kj::Promise<Result<void>> closure(Store & store, const Set & startPaths, Set & ret);
static kj::Promise<Result<void>> closure(Store & store, const Set & startPaths, Set & ret, bool includeOutputs = false);
GENERATE_CMP(RealisedPath, me->raw);
};
+6 -4
View File
@@ -1256,12 +1256,13 @@ kj::Promise<Result<void>> copyClosure(
const RealisedPath::Set & paths,
RepairFlag repair,
CheckSigsFlag checkSigs,
SubstituteFlag substitute)
SubstituteFlag substitute,
bool includeOutputs)
try {
if (&srcStore == &dstStore) co_return result::success();
RealisedPath::Set closure;
TRY_AWAIT(RealisedPath::closure(srcStore, paths, closure));
TRY_AWAIT(RealisedPath::closure(srcStore, paths, closure, includeOutputs));
TRY_AWAIT(copyPaths(srcStore, dstStore, closure, repair, checkSigs, substitute));
co_return result::success();
@@ -1275,12 +1276,13 @@ kj::Promise<Result<void>> copyClosure(
const StorePathSet & storePaths,
RepairFlag repair,
CheckSigsFlag checkSigs,
SubstituteFlag substitute)
SubstituteFlag substitute,
bool includeOutputs)
try {
if (&srcStore == &dstStore) co_return result::success();
StorePathSet closure;
TRY_AWAIT(srcStore.computeFSClosure(storePaths, closure));
TRY_AWAIT(srcStore.computeFSClosure(storePaths, closure, false, includeOutputs));
TRY_AWAIT(copyPaths(srcStore, dstStore, closure, repair, checkSigs, substitute));
co_return result::success();
} catch (...) {
+4 -2
View File
@@ -987,14 +987,16 @@ kj::Promise<Result<void>> copyClosure(
const RealisedPath::Set & paths,
RepairFlag repair = NoRepair,
CheckSigsFlag checkSigs = CheckSigs,
SubstituteFlag substitute = NoSubstitute);
SubstituteFlag substitute = NoSubstitute,
bool includeOutputs = false);
kj::Promise<Result<void>> copyClosure(
Store & srcStore, Store & dstStore,
const StorePathSet & paths,
RepairFlag repair = NoRepair,
CheckSigsFlag checkSigs = CheckSigs,
SubstituteFlag substitute = NoSubstitute);
SubstituteFlag substitute = NoSubstitute,
bool includeOutputs = false);
/**
* Remove the temporary roots file for this process. Any temporary
+13 -3
View File
@@ -9,6 +9,7 @@ let
pkgB = pkgs.wget;
pkgC = pkgs.hello;
pkgD = pkgs.tmux;
pkgE = pkgs.tree;
in {
name = "nix-copy-closure";
@@ -17,7 +18,7 @@ in {
{ client =
{ config, lib, pkgs, ... }:
{ virtualisation.writableStore = true;
virtualisation.additionalPaths = [ pkgA pkgD.drvPath ];
virtualisation.additionalPaths = [ pkgA pkgD.drvPath pkgE.drvPath ];
nix.settings.substituters = lib.mkForce [ ];
};
@@ -25,7 +26,10 @@ in {
{ config, pkgs, ... }:
{ services.openssh.enable = true;
virtualisation.writableStore = true;
virtualisation.additionalPaths = [ pkgB pkgC ];
# Including pkgsC.drvPath (versus just pkgsC) so common build deps
# are already in the store, limiting what the --include-outputs test
# needs to copy.
virtualisation.additionalPaths = [ pkgB pkgC.drvPath ];
};
};
@@ -68,10 +72,16 @@ in {
# Copy the closure of package C via the SSH substituter.
client.fail("nix-store -r ${pkgC}")
# Copy the derivation of package D's derivation from the client to the server.
# Copy the derivation of package D from the client to the server.
server.fail("nix-store --check-validity ${pkgD.drvPath}")
client.succeed("nix-copy-closure --to server --gzip ${pkgD.drvPath} >&2")
server.succeed("nix-store --check-validity ${pkgD.drvPath}")
server.fail("nix-store --check-validity ${pkgD}")
# Copy the derivation and outputs of package E from client to server.
server.fail("nix-store --check-validity ${pkgE}")
client.succeed("nix-copy-closure --to server --gzip --include-outputs ${pkgE.drvPath} >&2")
server.succeed("nix-store --check-validity ${pkgE}")
# FIXME
# client.succeed(