diff options
-rw-r--r-- | doc/guix.texi | 4 | ||||
-rw-r--r-- | nix/libstore/build.cc | 45 |
2 files changed, 42 insertions, 7 deletions
diff --git a/doc/guix.texi b/doc/guix.texi index cd4e550ef3..4222e011e5 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -998,6 +998,10 @@ consecutive build results are not bit-for-bit identical. Note that this setting can be overridden by clients such as @command{guix build} (@pxref{Invoking guix build}). +When used in conjunction with @option{--keep-failed}, the differing +output is kept in the store, under @file{/gnu/store/@dots{}-check}. +This makes it easy to look for differences between the two results. + @item --debug Produce debugging output. diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc index d51705b48f..2d3960bf89 100644 --- a/nix/libstore/build.cc +++ b/nix/libstore/build.cc @@ -2320,6 +2320,8 @@ void DerivationGoal::registerOutputs() outputs to allow hard links between outputs. */ InodesSeen inodesSeen; + Path checkSuffix = "-check"; + /* Check whether the output paths were created, and grep each output path to determine what other paths it references. Also make all output paths read-only. */ @@ -2433,7 +2435,7 @@ void DerivationGoal::registerOutputs() ValidPathInfo info = worker.store.queryPathInfo(path); if (hash.first != info.hash) { if (settings.keepFailed) { - Path dst = path + "-check"; + Path dst = path + checkSuffix; if (pathExists(dst)) deletePath(dst); if (rename(actualPath.c_str(), dst.c_str())) throw SysError(format("renaming `%1%' to `%2%'") % actualPath % dst); @@ -2487,9 +2489,11 @@ void DerivationGoal::registerOutputs() checkRefs("disallowedReferences", false, false); checkRefs("disallowedRequisites", false, true); - worker.store.optimisePath(path); // FIXME: combine with scanForReferences() + if (curRound == nrRounds) { + worker.store.optimisePath(path); // FIXME: combine with scanForReferences() - worker.store.markContentsGood(path); + worker.store.markContentsGood(path); + } ValidPathInfo info; info.path = path; @@ -2502,10 +2506,37 @@ void DerivationGoal::registerOutputs() if (buildMode == bmCheck) return; - if (curRound > 1 && prevInfos != infos) - throw NotDeterministic( - format("result of ‘%1%’ differs from previous round; rejecting as non-deterministic") - % drvPath); + /* Compare the result with the previous round, and report which + path is different, if any.*/ + if (curRound > 1 && prevInfos != infos) { + assert(prevInfos.size() == infos.size()); + for (auto i = prevInfos.begin(), j = infos.begin(); i != prevInfos.end(); ++i, ++j) + if (!(*i == *j)) { + Path prev = i->path + checkSuffix; + if (pathExists(prev)) + throw NotDeterministic( + format("output ‘%1%’ of ‘%2%’ differs from ‘%3%’ from previous round") + % i->path % drvPath % prev); + else + throw NotDeterministic( + format("output ‘%1%’ of ‘%2%’ differs from previous round") + % i->path % drvPath); + } + assert(false); // shouldn't happen + } + + if (settings.keepFailed) { + for (auto & i : drv.outputs) { + Path prev = i.second.path + checkSuffix; + if (pathExists(prev)) deletePath(prev); + if (curRound < nrRounds) { + Path dst = i.second.path + checkSuffix; + if (rename(i.second.path.c_str(), dst.c_str())) + throw SysError(format("renaming ‘%1%’ to ‘%2%’") % i.second.path % dst); + } + } + + } if (curRound < nrRounds) { prevInfos = infos; |