diff options
author | Eelco Dolstra <edolstra@gmail.com> | 2016-12-07T12·16+0100 |
---|---|---|
committer | Eelco Dolstra <edolstra@gmail.com> | 2016-12-07T12·16+0100 |
commit | 8bdf83f936adae6f2c907a6d2541e80d4120f051 (patch) | |
tree | 17b49383bec8578c307ed3e47fe27db24c3f4171 /src | |
parent | ceeedb58d23950f0ae3944484bca331e5cbb8053 (diff) |
Add an option to make non-determinism non-fatal
That is, when build-repeat > 0, and the output of two rounds differ, then print a warning rather than fail the build. This is primarily to let Hydra check reproducibility of all packages.
Diffstat (limited to 'src')
-rw-r--r-- | src/libstore/build.cc | 24 | ||||
-rw-r--r-- | src/libstore/store-api.hh | 11 |
2 files changed, 24 insertions, 11 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 300f6ac00fcb..84fbf1c18dab 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -1272,6 +1272,8 @@ void DerivationGoal::inputsRealised() build hook. */ state = &DerivationGoal::tryToBuild; worker.wakeUp(shared_from_this()); + + result = BuildResult(); } @@ -1421,6 +1423,8 @@ void DerivationGoal::buildDone() debug(format("builder process for ‘%1%’ finished") % drvPath); + result.timesBuilt++; + /* So the child is gone now. */ worker.childTerminated(this); @@ -2909,17 +2913,15 @@ void DerivationGoal::registerOutputs() assert(prevInfos.size() == infos.size()); for (auto i = prevInfos.begin(), j = infos.begin(); i != prevInfos.end(); ++i, ++j) if (!(*i == *j)) { + result.isNonDeterministic = true; 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); + auto msg = pathExists(prev) + ? 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); + if (settings.get("enforce-determinism", true)) + throw NotDeterministic(msg); + printError(msg); } - abort(); // shouldn't happen } if (settings.keepFailed) { @@ -2932,7 +2934,6 @@ void DerivationGoal::registerOutputs() throw SysError(format("renaming ‘%1%’ to ‘%2%’") % i.second.path % dst); } } - } if (curRound < nrRounds) { @@ -3792,12 +3793,13 @@ void LocalStore::buildPaths(const PathSet & drvPaths, BuildMode buildMode) worker.run(goals); PathSet failed; - for (auto & i : goals) + for (auto & i : goals) { if (i->getExitCode() != Goal::ecSuccess) { DerivationGoal * i2 = dynamic_cast<DerivationGoal *>(i.get()); if (i2) failed.insert(i2->getDrvPath()); else failed.insert(dynamic_cast<SubstitutionGoal *>(i.get())->getStorePath()); } + } if (!failed.empty()) throw Error(worker.exitStatus(), "build of %s failed", showPaths(failed)); diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 2ea74d90e78e..ee2b6b2862b6 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -208,7 +208,18 @@ struct BuildResult NotDeterministic, } status = MiscFailure; std::string errorMsg; + + /* How many times this build was performed. */ + unsigned int timesBuilt = 0; + + /* If timesBuilt > 1, whether some builds did not produce the same + result. (Note that 'isNonDeterministic = false' does not mean + the build is deterministic, just that we don't have evidence of + non-determinism.) */ + bool isNonDeterministic = false; + //time_t startTime = 0, stopTime = 0; + bool success() { return status == Built || status == Substituted || status == AlreadyValid; } |