Merge "libstore: report all differing outputs rather than just the first" into main
This commit is contained in:
commit
c95b73d8a1
|
@ -85,6 +85,10 @@ kloenk:
|
||||||
forgejo: kloenk
|
forgejo: kloenk
|
||||||
github: kloenk
|
github: kloenk
|
||||||
|
|
||||||
|
lheckemann:
|
||||||
|
forgejo: lheckemann
|
||||||
|
github: lheckemann
|
||||||
|
|
||||||
lovesegfault:
|
lovesegfault:
|
||||||
github: lovesegfault
|
github: lovesegfault
|
||||||
|
|
||||||
|
|
22
doc/manual/rl-next/report-differing-outputs.md
Normal file
22
doc/manual/rl-next/report-differing-outputs.md
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
---
|
||||||
|
synopsis: "Reproducibility check builds now report all differing outputs"
|
||||||
|
cls: [2069]
|
||||||
|
category: Improvements
|
||||||
|
credits: [lheckemann]
|
||||||
|
---
|
||||||
|
|
||||||
|
`nix-build --check` allows rerunning the build of an already-built derivation to check that it produces the same output again.
|
||||||
|
|
||||||
|
If a multiple-output derivation with impure behaviour is built with `--check`, only the first output would be shown in the resulting error message (and kept for comparison):
|
||||||
|
|
||||||
|
```
|
||||||
|
error: derivation '/nix/store/4spy3nz1661zm15gkybsy1h5f36aliwx-python3.11-test-1.0.0.drv' may not be deterministic: output '/nix/store/ccqcp01zg18wp9iadzmzimqzdi3ll08d-python3.11-test
|
||||||
|
-1.0.0-dist' differs from '/nix/store/ccqcp01zg18wp9iadzmzimqzdi3ll08d-python3.11-test-1.0.0-dist.check'
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, all differing outputs are kept and reported:
|
||||||
|
```
|
||||||
|
error: derivation '4spy3nz1661zm15gkybsy1h5f36aliwx-python3.11-test-1.0.0.drv' may not be deterministic: outputs differ
|
||||||
|
output differs: output '/nix/store/ccqcp01zg18wp9iadzmzimqzdi3ll08d-python3.11-test-1.0.0-dist' differs from '/nix/store/ccqcp01zg18wp9iadzmzimqzdi3ll08d-python3.11-test-1.0.0-dist.check'
|
||||||
|
output differs: output '/nix/store/yl59v08356i841c560alb0zmk7q16klb-python3.11-test-1.0.0' differs from '/nix/store/yl59v08356i841c560alb0zmk7q16klb-python3.11-test-1.0.0.check'
|
||||||
|
```
|
|
@ -2021,6 +2021,8 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
|
||||||
|
|
||||||
OutputPathMap finalOutputs;
|
OutputPathMap finalOutputs;
|
||||||
|
|
||||||
|
std::vector<std::pair<Path, std::optional<Path>>> nondeterministic;
|
||||||
|
|
||||||
for (auto & outputName : sortedOutputNames) {
|
for (auto & outputName : sortedOutputNames) {
|
||||||
auto output = get(drv->outputs, outputName);
|
auto output = get(drv->outputs, outputName);
|
||||||
auto scratchPath = get(scratchOutputs, outputName);
|
auto scratchPath = get(scratchOutputs, outputName);
|
||||||
|
@ -2307,20 +2309,20 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
|
||||||
buildUser ? buildUser->getGID() : getgid(),
|
buildUser ? buildUser->getGID() : getgid(),
|
||||||
finalDestPath, dst, worker.store.printStorePath(drvPath), tmpDir);
|
finalDestPath, dst, worker.store.printStorePath(drvPath), tmpDir);
|
||||||
|
|
||||||
throw NotDeterministic("derivation '%s' may not be deterministic: output '%s' differs from '%s'",
|
nondeterministic.push_back(std::make_pair(worker.store.toRealPath(finalDestPath), dst));
|
||||||
worker.store.printStorePath(drvPath), worker.store.toRealPath(finalDestPath), dst);
|
|
||||||
} else
|
} else
|
||||||
throw NotDeterministic("derivation '%s' may not be deterministic: output '%s' differs",
|
nondeterministic.push_back(std::make_pair(worker.store.toRealPath(finalDestPath), std::nullopt));
|
||||||
worker.store.printStorePath(drvPath), worker.store.toRealPath(finalDestPath));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Since we verified the build, it's now ultimately trusted. */
|
/* Since we verified the build, it's now ultimately trusted. */
|
||||||
if (!oldInfo.ultimate) {
|
else if (!oldInfo.ultimate) {
|
||||||
oldInfo.ultimate = true;
|
oldInfo.ultimate = true;
|
||||||
localStore.signPathInfo(oldInfo);
|
localStore.signPathInfo(oldInfo);
|
||||||
localStore.registerValidPaths({{oldInfo.path, oldInfo}});
|
localStore.registerValidPaths({{oldInfo.path, oldInfo}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Don't register anything, since we already have the
|
||||||
|
previous versions which we're comparing. */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2351,6 +2353,18 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buildMode == bmCheck) {
|
if (buildMode == bmCheck) {
|
||||||
|
if (!nondeterministic.empty()) {
|
||||||
|
std::ostringstream msg;
|
||||||
|
msg << HintFmt("derivation '%s' may not be deterministic: outputs differ", drvPath.to_string());
|
||||||
|
for (auto [oldPath, newPath]: nondeterministic) {
|
||||||
|
if (newPath) {
|
||||||
|
msg << HintFmt("\n output differs: output '%s' differs from '%s'", oldPath.c_str(), *newPath);
|
||||||
|
} else {
|
||||||
|
msg << HintFmt("\n output '%s' differs", oldPath.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw NotDeterministic(msg.str());
|
||||||
|
}
|
||||||
/* In case of fixed-output derivations, if there are
|
/* In case of fixed-output derivations, if there are
|
||||||
mismatches on `--check` an error must be thrown as this is
|
mismatches on `--check` an error must be thrown as this is
|
||||||
also a source for non-determinism. */
|
also a source for non-determinism. */
|
||||||
|
|
|
@ -6,10 +6,12 @@ with import ./config.nix;
|
||||||
nondeterministic = mkDerivation {
|
nondeterministic = mkDerivation {
|
||||||
inherit checkBuildId;
|
inherit checkBuildId;
|
||||||
name = "nondeterministic";
|
name = "nondeterministic";
|
||||||
|
outputs = ["a" "b"];
|
||||||
buildCommand =
|
buildCommand =
|
||||||
''
|
''
|
||||||
mkdir $out
|
mkdir $a $b
|
||||||
date +%s.%N > $out/date
|
date +%s.%N > $a/date
|
||||||
|
date +%s.%N > $b/date
|
||||||
echo "CHECK_TMPDIR=$TMPDIR"
|
echo "CHECK_TMPDIR=$TMPDIR"
|
||||||
echo "checkBuildId=$checkBuildId"
|
echo "checkBuildId=$checkBuildId"
|
||||||
echo "$checkBuildId" > $TMPDIR/checkBuildId
|
echo "$checkBuildId" > $TMPDIR/checkBuildId
|
||||||
|
@ -19,10 +21,12 @@ with import ./config.nix;
|
||||||
deterministic = mkDerivation {
|
deterministic = mkDerivation {
|
||||||
inherit checkBuildId;
|
inherit checkBuildId;
|
||||||
name = "deterministic";
|
name = "deterministic";
|
||||||
|
outputs = ["a" "b"];
|
||||||
buildCommand =
|
buildCommand =
|
||||||
''
|
''
|
||||||
mkdir $out
|
mkdir $a $b
|
||||||
echo date > $out/date
|
echo date > $a/date
|
||||||
|
echo date > $b/date
|
||||||
echo "CHECK_TMPDIR=$TMPDIR"
|
echo "CHECK_TMPDIR=$TMPDIR"
|
||||||
echo "checkBuildId=$checkBuildId"
|
echo "checkBuildId=$checkBuildId"
|
||||||
echo "$checkBuildId" > $TMPDIR/checkBuildId
|
echo "$checkBuildId" > $TMPDIR/checkBuildId
|
||||||
|
@ -32,10 +36,12 @@ with import ./config.nix;
|
||||||
failed = mkDerivation {
|
failed = mkDerivation {
|
||||||
inherit checkBuildId;
|
inherit checkBuildId;
|
||||||
name = "failed";
|
name = "failed";
|
||||||
|
outputs = ["a" "b"];
|
||||||
buildCommand =
|
buildCommand =
|
||||||
''
|
''
|
||||||
mkdir $out
|
mkdir $a $b
|
||||||
echo date > $out/date
|
echo date > $a/date
|
||||||
|
echo date > $b/date
|
||||||
echo "CHECK_TMPDIR=$TMPDIR"
|
echo "CHECK_TMPDIR=$TMPDIR"
|
||||||
echo "checkBuildId=$checkBuildId"
|
echo "checkBuildId=$checkBuildId"
|
||||||
echo "$checkBuildId" > $TMPDIR/checkBuildId
|
echo "$checkBuildId" > $TMPDIR/checkBuildId
|
||||||
|
|
|
@ -65,6 +65,8 @@ checkBuildTempDirRemoved $TEST_ROOT/log
|
||||||
nix-build check.nix -A nondeterministic --argstr checkBuildId $checkBuildId \
|
nix-build check.nix -A nondeterministic --argstr checkBuildId $checkBuildId \
|
||||||
--no-out-link --check 2> $TEST_ROOT/log || status=$?
|
--no-out-link --check 2> $TEST_ROOT/log || status=$?
|
||||||
grep 'may not be deterministic' $TEST_ROOT/log
|
grep 'may not be deterministic' $TEST_ROOT/log
|
||||||
|
# the differences in both outputs should be reported
|
||||||
|
[[ $(grep -c 'differs' $TEST_ROOT/log) = 2 ]]
|
||||||
[ "$status" = "104" ]
|
[ "$status" = "104" ]
|
||||||
checkBuildTempDirRemoved $TEST_ROOT/log
|
checkBuildTempDirRemoved $TEST_ROOT/log
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue