From bed6da2c6fefce1081f3f448aa1becc779996f9c Mon Sep 17 00:00:00 2001 From: Josh Heinrichs Date: Fri, 12 Jun 2026 12:42:33 -0400 Subject: [PATCH] Adapt outputChecks fix from Lix Got bit by this with postgresql_18. Lix addressed this early last year[1]. [1] https://gerrit.lix.systems/c/lix/+/2346 --- src/libstore/build/derivation-check.cc | 13 ++++++++----- src/libstore/build/derivation-check.hh | 3 ++- src/libstore/unix/build/derivation-builder.cc | 5 ++++- tests/functional/meson.build | 1 + tests/functional/regression-reference-checks.nix | 15 +++++++++++++++ tests/functional/regression-reference-checks.sh | 13 +++++++++++++ 6 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 tests/functional/regression-reference-checks.nix create mode 100644 tests/functional/regression-reference-checks.sh diff --git a/src/libstore/build/derivation-check.cc b/src/libstore/build/derivation-check.cc index d132b24649..b2a2fef6f7 100644 --- a/src/libstore/build/derivation-check.cc +++ b/src/libstore/build/derivation-check.cc @@ -12,14 +12,15 @@ void checkOutputs( const StorePath & drvPath, const decltype(Derivation::outputs) & drvOutputs, const decltype(DerivationOptions::outputChecks) & outputChecks, - const std::map & outputs, + const std::map & newlyBuiltOutputs, + const std::map & alreadyRegisteredOutputs, Activity & act) { std::map outputsByPath; - for (auto & output : outputs) + for (auto & output : newlyBuiltOutputs) outputsByPath.emplace(output.second.path, output.second); - for (auto & pair : outputs) { + for (auto & pair : newlyBuiltOutputs) { // We can't use auto destructuring here because // clang-tidy seems to complain about it. const std::string & outputName = pair.first; @@ -123,11 +124,13 @@ void checkOutputs( overloaded{ [&](const StorePath & path) { spec.insert(path); }, [&](const OutputName & refOutputName) { - if (auto output = get(outputs, refOutputName)) + if (auto output = get(newlyBuiltOutputs, refOutputName)) spec.insert(output->path); + else if (auto storePath = get(alreadyRegisteredOutputs, refOutputName)) + spec.insert(*storePath); else { std::string outputsListing = - concatMapStringsSep(", ", outputs, [](auto & o) { return o.first; }); + concatMapStringsSep(", ", newlyBuiltOutputs, [](auto & o) { return o.first; }); throw BuildError( BuildResult::Failure::OutputRejected, "derivation '%s' output check for '%s' contains output name '%s'," diff --git a/src/libstore/build/derivation-check.hh b/src/libstore/build/derivation-check.hh index ee2d012295..d0acb39a3e 100644 --- a/src/libstore/build/derivation-check.hh +++ b/src/libstore/build/derivation-check.hh @@ -22,7 +22,8 @@ void checkOutputs( const StorePath & drvPath, const decltype(Derivation::outputs) & drvOutputs, const decltype(DerivationOptions::outputChecks) & drvOptions, - const std::map & outputs, + const std::map & newlyBuiltOutputs, + const std::map & alreadyRegisteredOutputs, Activity & act); } // namespace nix diff --git a/src/libstore/unix/build/derivation-builder.cc b/src/libstore/unix/build/derivation-builder.cc index 44ee4f87bb..8aff9e8e6b 100644 --- a/src/libstore/unix/build/derivation-builder.cc +++ b/src/libstore/unix/build/derivation-builder.cc @@ -1654,6 +1654,8 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs() OutputPathMap finalOutputs; + std::map alreadyRegisteredOutputs; + for (auto & outputName : sortedOutputNames) { auto output = get(drv.outputs, outputName); auto scratchPath = get(scratchOutputs, outputName); @@ -1684,6 +1686,7 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs() overloaded{ [&](const AlreadyRegistered & skippedFinalPath) -> std::optional { finish(skippedFinalPath.path); + alreadyRegisteredOutputs.insert_or_assign(outputName, skippedFinalPath.path); return std::nullopt; }, [&](const PerhapsNeedToRegister & r) -> std::optional { return r.refs; }, @@ -2030,7 +2033,7 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs() /* Apply output checks. This includes checking of the wanted vs got hash of fixed-outputs. */ - checkOutputs(store, drvPath, drv.outputs, drvOptions.outputChecks, infos, *act); + checkOutputs(store, drvPath, drv.outputs, drvOptions.outputChecks, infos, alreadyRegisteredOutputs, *act); if (buildMode == bmCheck) { return {}; diff --git a/tests/functional/meson.build b/tests/functional/meson.build index f0ad01017c..af67280fed 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -175,6 +175,7 @@ suites = [ 'impure-env.sh', 'debugger.sh', 'extra-sandbox-profile.sh', + 'regression-reference-checks.sh', 'help.sh', 'symlinks.sh', 'external-builders.sh', diff --git a/tests/functional/regression-reference-checks.nix b/tests/functional/regression-reference-checks.nix new file mode 100644 index 0000000000..354abbc76e --- /dev/null +++ b/tests/functional/regression-reference-checks.nix @@ -0,0 +1,15 @@ +with import ./config.nix; +mkDerivation { + name = "test"; + __structuredAttrs = true; + outputs = [ + "out" + "man" + ]; + outputChecks.out.disallowedReferences = [ "man" ]; + buildCommand = '' + source $NIX_ATTRS_SH_FILE + mkdir ''${outputs[out]} + mkdir ''${outputs[man]} + ''; +} diff --git a/tests/functional/regression-reference-checks.sh b/tests/functional/regression-reference-checks.sh new file mode 100644 index 0000000000..5c89e11e6f --- /dev/null +++ b/tests/functional/regression-reference-checks.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +source common.sh + +TODO_NixOS + +clearStore + +outpath="$(nix-build regression-reference-checks.nix -A out --no-out-link)" +nix-build regression-reference-checks.nix -A man --no-out-link + +nix-store --delete "$outpath" +nix-build regression-reference-checks.nix -A out --no-out-link