diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index ea10d4c55..f972a65bd 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -2807,11 +2807,15 @@ static void addPath( const NixStringContext & context) { try { - if (path.accessor == state.rootFS && state.store->isInStore(path.path.abs())) { + StorePathSet refs; + + if (path.accessor == state.rootFS && state.store->isInStore(path.path.abs()) && !context.empty()) { // FIXME: handle CA derivation outputs (where path needs to // be rewritten to the actual output). auto rewrites = state.realiseContext(context); path = {path.accessor, CanonPath(rewriteStrings(path.path.abs(), rewrites))}; + auto [storePath, subPath] = state.store->toStorePath(path.path.abs()); + refs = state.store->queryPathInfo(storePath)->references; } std::unique_ptr filter; @@ -2824,18 +2828,27 @@ static void addPath( std::optional expectedStorePath; if (expectedHash) expectedStorePath = state.store->makeFixedOutputPathFromCA( - name, ContentAddressWithReferences::fromParts(method, *expectedHash, {})); + name, ContentAddressWithReferences::fromParts(method, *expectedHash, {refs})); if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) { - auto dstPath = fetchToStore( - state.fetchSettings, - *state.store, - path.resolveSymlinks(), - settings.readOnlyMode ? FetchMode::DryRun : FetchMode::Copy, - name, - method, - filter.get(), - state.repair); + // FIXME: support refs in fetchToStore()? + auto dstPath = refs.empty() ? fetchToStore( + state.fetchSettings, + *state.store, + path.resolveSymlinks(), + settings.readOnlyMode ? FetchMode::DryRun : FetchMode::Copy, + name, + method, + filter.get(), + state.repair) + : state.store->addToStore( + name, + path.resolveSymlinks(), + method, + HashAlgorithm::SHA256, + refs, + filter ? *filter.get() : defaultPathFilter, + state.repair); if (expectedHash && expectedStorePath != dstPath) state.error("store path mismatch in (possibly filtered) path added from '%s'", path) .atPos(pos) diff --git a/tests/functional/import-from-derivation.nix b/tests/functional/import-from-derivation.nix index 600f448a6..ac38d250d 100644 --- a/tests/functional/import-from-derivation.nix +++ b/tests/functional/import-from-derivation.nix @@ -46,4 +46,24 @@ rec { }; importAddPathExpr = import addPathExpr; + + symlink = mkDerivation { + name = "symlink"; + buildCommand = '' + mkdir $out + echo hello world > $out/text + ln -s $out/text $out/symlink + ln -s ${step1} $out/symlink2 + ''; + }; + + pathFromDerivation = builtins.path { + name = "path-from-derivation"; + path = "${symlink}/"; + }; + + pathFromDerivation2 = builtins.path { + name = "path-from-derivation"; + path = "${symlink}/text"; + }; } diff --git a/tests/functional/import-from-derivation.sh b/tests/functional/import-from-derivation.sh index a00761235..2970a830e 100755 --- a/tests/functional/import-from-derivation.sh +++ b/tests/functional/import-from-derivation.sh @@ -29,6 +29,15 @@ fi outPath2=$(nix-build ./import-from-derivation.nix -A addPath --no-out-link) [[ "$(cat "$outPath2")" = BLAFOO579 ]] +# Test that applying builtins.path to the result of a derivation propagates all references +for attr in pathFromDerivation pathFromDerivation2; do + outPath3=$(nix eval --raw -f ./import-from-derivation.nix "$attr") + refs=$(nix path-info --json "$outPath3" | jq -r '.[].references.[]') + [[ $(printf "%s" "$refs" | wc -w) = 2 ]] + [[ $refs =~ -step1 ]] + [[ $refs =~ -symlink ]] +done + # Test that IFD works with a chroot store. if canUseSandbox; then