diff --git a/doc/manual/change-authors.yml b/doc/manual/change-authors.yml index a60452eed..4ff388599 100644 --- a/doc/manual/change-authors.yml +++ b/doc/manual/change-authors.yml @@ -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 diff --git a/doc/manual/rl-next/nix-copy-closure-include-outputs.md b/doc/manual/rl-next/nix-copy-closure-include-outputs.md new file mode 100644 index 000000000..422b05a13 --- /dev/null +++ b/doc/manual/rl-next/nix-copy-closure-include-outputs.md @@ -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. diff --git a/lix/legacy/nix-copy-closure.cc b/lix/legacy/nix-copy-closure.cc index b027b53fa..0f67fb0d7 100644 --- a/lix/legacy/nix-copy-closure.cc +++ b/lix/legacy/nix-copy-closure.cc @@ -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; } diff --git a/lix/libstore/realisation.cc b/lix/libstore/realisation.cc index e4a7bf0db..42489079d 100644 --- a/lix/libstore/realisation.cc +++ b/lix/libstore/realisation.cc @@ -91,14 +91,15 @@ StorePath RealisedPath::path() const { kj::Promise> 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(); diff --git a/lix/libstore/realisation.hh b/lix/libstore/realisation.hh index 6359e4e90..e2bb0dc1c 100644 --- a/lix/libstore/realisation.hh +++ b/lix/libstore/realisation.hh @@ -125,7 +125,7 @@ struct RealisedPath { */ StorePath path() const; - static kj::Promise> closure(Store & store, const Set & startPaths, Set & ret); + static kj::Promise> closure(Store & store, const Set & startPaths, Set & ret, bool includeOutputs = false); GENERATE_CMP(RealisedPath, me->raw); }; diff --git a/lix/libstore/store-api.cc b/lix/libstore/store-api.cc index 1e2cf35e3..d2f57ff26 100644 --- a/lix/libstore/store-api.cc +++ b/lix/libstore/store-api.cc @@ -1256,12 +1256,13 @@ kj::Promise> 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> 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 (...) { diff --git a/lix/libstore/store-api.hh b/lix/libstore/store-api.hh index b2348841b..c2b0bbaaa 100644 --- a/lix/libstore/store-api.hh +++ b/lix/libstore/store-api.hh @@ -987,14 +987,16 @@ kj::Promise> copyClosure( const RealisedPath::Set & paths, RepairFlag repair = NoRepair, CheckSigsFlag checkSigs = CheckSigs, - SubstituteFlag substitute = NoSubstitute); + SubstituteFlag substitute = NoSubstitute, + bool includeOutputs = false); kj::Promise> 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 diff --git a/tests/nixos/nix-copy-closure.nix b/tests/nixos/nix-copy-closure.nix index d6d4ae4f3..bdde1cd79 100644 --- a/tests/nixos/nix-copy-closure.nix +++ b/tests/nixos/nix-copy-closure.nix @@ -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(