aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2016-12-07 17:57:35 +0100
committerEelco Dolstra <edolstra@gmail.com>2016-12-07 17:57:35 +0100
commit9a313469a4bdea2d1e8df24d16289dc2a172a169 (patch)
tree1674c3189b76b751f4e9c2b03486e59e8849c701
parentb07060688a298abe765bca4258de4c675b24a364 (diff)
Add a hook to run diffoscope when non-determinism is detected
-rw-r--r--src/libstore/build.cc39
-rw-r--r--src/nix-store/nix-store.cc1
2 files changed, 33 insertions, 7 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index 8442f1f61..bbf3c8bc9 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -2688,6 +2688,8 @@ void DerivationGoal::registerOutputs()
InodesSeen inodesSeen;
Path checkSuffix = "-check";
+ bool runDiffHook = settings.get("run-diff-hook", false);
+ bool keepPreviousRound = settings.keepFailed || runDiffHook;
/* Check whether the output paths were created, and grep each
output path to determine what other paths it references. Also make all
@@ -2919,25 +2921,39 @@ void DerivationGoal::registerOutputs()
if (!(*i == *j)) {
result.isNonDeterministic = true;
Path prev = i->path + checkSuffix;
- auto msg = pathExists(prev)
+ bool prevExists = keepPreviousRound && pathExists(prev);
+ auto msg = prevExists
? fmt("output ‘%1%’ of ‘%2%’ differs from ‘%3%’ from previous round", i->path, drvPath, prev)
: fmt("output ‘%1%’ of ‘%2%’ differs from previous round", i->path, drvPath);
+
+ auto diffHook = settings.get("diff-hook", std::string(""));
+ if (prevExists && diffHook != "" && runDiffHook) {
+ try {
+ auto diff = runProgram(diffHook, true, {prev, i->path});
+ if (diff != "")
+ printError(chomp(diff));
+ } catch (Error & error) {
+ printError("diff hook execution failed: %s", error.what());
+ }
+ }
+
if (settings.get("enforce-determinism", true))
throw NotDeterministic(msg);
+
printError(msg);
curRound = nrRounds; // we know enough, bail out early
}
}
- if (settings.keepFailed) {
+ /* If this is the first round of several, then move the output out
+ of the way. */
+ if (nrRounds > 1 && curRound == 1 && curRound < nrRounds && keepPreviousRound) {
for (auto & i : drv->outputs) {
Path prev = i.second.path + checkSuffix;
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);
- }
+ 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);
}
}
@@ -2946,6 +2962,15 @@ void DerivationGoal::registerOutputs()
return;
}
+ /* Remove the -check directories if we're done. FIXME: keep them
+ if the result was not determistic? */
+ if (curRound == nrRounds) {
+ for (auto & i : drv->outputs) {
+ Path prev = i.second.path + checkSuffix;
+ deletePath(prev);
+ }
+ }
+
/* Register each output path as valid, and register the sets of
paths referenced by each of them. If there are cycles in the
outputs, this will fail. */
diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc
index f81cff4ac..c1e6afef0 100644
--- a/src/nix-store/nix-store.cc
+++ b/src/nix-store/nix-store.cc
@@ -843,6 +843,7 @@ static void opServe(Strings opFlags, Strings opArgs)
if (GET_PROTOCOL_MINOR(clientVersion) >= 3) {
settings.set("build-repeat", std::to_string(readInt(in)));
settings.set("enforce-determinism", readInt(in) != 0 ? "true" : "false");
+ settings.set("run-diff-hook", "true");
}
settings.printRepeatedBuilds = false;
};