1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-12-10 11:01:03 +01:00

builtins.path: Propagate references from derivation outputs

This restores compatibility with Nix 2.18, which behaved this
way. Note that this doesn't scan for the actually visible references.

Unlike in Nix 2.18, we only do this for paths with context, i.e. it
applies to `builtins.storePath "/nix/store/bla..."` but not
`"/nix/store/bla..."`. We don't want the latter because it shouldn't
matter whether a source file happens to be in the Nix store.
This commit is contained in:
Eelco Dolstra 2025-12-02 15:38:41 +01:00
parent 26bf932e41
commit c080c4ca56
3 changed files with 53 additions and 11 deletions

View file

@ -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<PathFilter> filter;
@ -2824,18 +2828,27 @@ static void addPath(
std::optional<StorePath> 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<EvalError>("store path mismatch in (possibly filtered) path added from '%s'", path)
.atPos(pos)

View file

@ -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";
};
}

View file

@ -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