diff --git a/src/libstore-c/nix_api_store.cc b/src/libstore-c/nix_api_store.cc index 024ed97858a..6fd3bb6f588 100644 --- a/src/libstore-c/nix_api_store.cc +++ b/src/libstore-c/nix_api_store.cc @@ -251,7 +251,7 @@ nix_err nix_store_copy_closure(nix_c_context * context, Store * srcStore, Store if (context) context->last_err_code = NIX_OK; try { - nix::RealisedPath::Set paths; + nix::StorePathSet paths; paths.insert(path->path); nix::copyClosure(*srcStore->ptr, *dstStore->ptr, paths); } diff --git a/src/libstore/include/nix/store/legacy-ssh-store.hh b/src/libstore/include/nix/store/legacy-ssh-store.hh index 994918f90f0..47e505ba1d6 100644 --- a/src/libstore/include/nix/store/legacy-ssh-store.hh +++ b/src/libstore/include/nix/store/legacy-ssh-store.hh @@ -175,7 +175,8 @@ public: StorePathSet & out, bool flipDirection = false, bool includeOutputs = false, - bool includeDerivers = false) override; + bool includeDerivers = false, + std::function pathCallback = nullptr) override; StorePathSet queryValidPaths(const StorePathSet & paths, SubstituteFlag maybeSubstitute = NoSubstitute) override; diff --git a/src/libstore/include/nix/store/store-api.hh b/src/libstore/include/nix/store/store-api.hh index 4c0b156faaa..80c03f170d6 100644 --- a/src/libstore/include/nix/store/store-api.hh +++ b/src/libstore/include/nix/store/store-api.hh @@ -802,13 +802,19 @@ public: * `storePath` is returned; that is, the closures under the * `referrers` relation instead of the `references` relation is * returned. + * + * @param onPathDiscovered A callback invoked on each discovered store + * path. Returning `false` from the callback will stop recursion on + * that path. Returning `true` will continue recursion. A `nullptr` is + * equivalent to a callback which always returns `true`. */ virtual void computeFSClosure( const StorePathSet & paths, StorePathSet & out, bool flipDirection = false, bool includeOutputs = false, - bool includeDerivers = false); + bool includeDerivers = false, + std::function onPathDiscovered = nullptr); void computeFSClosure( const StorePath & path, diff --git a/src/libstore/legacy-ssh-store.cc b/src/libstore/legacy-ssh-store.cc index 3b466c9bb8b..cbf5955b4a0 100644 --- a/src/libstore/legacy-ssh-store.cc +++ b/src/libstore/legacy-ssh-store.cc @@ -252,10 +252,15 @@ void LegacySSHStore::buildPaths( } void LegacySSHStore::computeFSClosure( - const StorePathSet & paths, StorePathSet & out, bool flipDirection, bool includeOutputs, bool includeDerivers) + const StorePathSet & paths, + StorePathSet & out, + bool flipDirection, + bool includeOutputs, + bool includeDerivers, + std::function onPathDiscovered) { - if (flipDirection || includeDerivers) { - Store::computeFSClosure(paths, out, flipDirection, includeOutputs, includeDerivers); + if (flipDirection || includeDerivers || onPathDiscovered) { + Store::computeFSClosure(paths, out, flipDirection, includeOutputs, includeDerivers, onPathDiscovered); return; } diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc index ca2458302d6..8ff4a2bf5f4 100644 --- a/src/libstore/misc.cc +++ b/src/libstore/misc.cc @@ -21,7 +21,8 @@ void Store::computeFSClosure( StorePathSet & paths_, bool flipDirection, bool includeOutputs, - bool includeDerivers) + bool includeDerivers, + std::function onPathDiscovered) { std::function(const StorePath & path, std::future> &)> queryDeps; if (flipDirection) @@ -65,6 +66,12 @@ void Store::computeFSClosure( startPaths, paths_, [&](const StorePath & path, std::function> &)> processEdges) { + if (onPathDiscovered && !onPathDiscovered(path)) { + std::promise> promise; + promise.set_value({}); + processEdges(promise); + return; + } std::promise> promise; std::function>)> getDependencies = [&](std::future> fut) { diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index c292e2e431d..ef1ecf970ea 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -1072,9 +1072,16 @@ void copyClosure( if (&srcStore == &dstStore) return; - StorePathSet closure; - srcStore.computeFSClosure(storePaths, closure); - copyPaths(srcStore, dstStore, closure, repair, checkSigs, substitute); + StorePathSet pathsToCopy; + + auto onPathDiscovered = [&](const StorePath & path) -> bool { + // Only recurse if the path does not already exist in `dstStore` + return repair || !dstStore.isValidPath(path); + }; + srcStore.computeFSClosure(storePaths, pathsToCopy, false, false, false, onPathDiscovered); + pathsToCopy.insert(storePaths.begin(), storePaths.end()); + + copyPaths(srcStore, dstStore, pathsToCopy, repair, checkSigs, substitute); } std::optional