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.
This commit is contained in:
Eelco Dolstra 2016-12-07 13:16:06 +01:00
parent ceeedb58d2
commit 8bdf83f936
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
2 changed files with 24 additions and 11 deletions

View file

@ -1272,6 +1272,8 @@ void DerivationGoal::inputsRealised()
build hook. */ build hook. */
state = &DerivationGoal::tryToBuild; state = &DerivationGoal::tryToBuild;
worker.wakeUp(shared_from_this()); worker.wakeUp(shared_from_this());
result = BuildResult();
} }
@ -1421,6 +1423,8 @@ void DerivationGoal::buildDone()
debug(format("builder process for %1% finished") % drvPath); debug(format("builder process for %1% finished") % drvPath);
result.timesBuilt++;
/* So the child is gone now. */ /* So the child is gone now. */
worker.childTerminated(this); worker.childTerminated(this);
@ -2909,17 +2913,15 @@ void DerivationGoal::registerOutputs()
assert(prevInfos.size() == infos.size()); assert(prevInfos.size() == infos.size());
for (auto i = prevInfos.begin(), j = infos.begin(); i != prevInfos.end(); ++i, ++j) for (auto i = prevInfos.begin(), j = infos.begin(); i != prevInfos.end(); ++i, ++j)
if (!(*i == *j)) { if (!(*i == *j)) {
result.isNonDeterministic = true;
Path prev = i->path + checkSuffix; Path prev = i->path + checkSuffix;
if (pathExists(prev)) auto msg = pathExists(prev)
throw NotDeterministic( ? fmt("output %1% of %2% differs from %3% from previous round", i->path, drvPath, prev)
format("output %1% of %2% differs from %3% from previous round") : fmt("output %1% of %2% differs from previous round", i->path, drvPath);
% i->path % drvPath % prev); if (settings.get("enforce-determinism", true))
else throw NotDeterministic(msg);
throw NotDeterministic( printError(msg);
format("output %1% of %2% differs from previous round")
% i->path % drvPath);
} }
abort(); // shouldn't happen
} }
if (settings.keepFailed) { if (settings.keepFailed) {
@ -2932,7 +2934,6 @@ void DerivationGoal::registerOutputs()
throw SysError(format("renaming %1% to %2%") % i.second.path % dst); throw SysError(format("renaming %1% to %2%") % i.second.path % dst);
} }
} }
} }
if (curRound < nrRounds) { if (curRound < nrRounds) {
@ -3792,12 +3793,13 @@ void LocalStore::buildPaths(const PathSet & drvPaths, BuildMode buildMode)
worker.run(goals); worker.run(goals);
PathSet failed; PathSet failed;
for (auto & i : goals) for (auto & i : goals) {
if (i->getExitCode() != Goal::ecSuccess) { if (i->getExitCode() != Goal::ecSuccess) {
DerivationGoal * i2 = dynamic_cast<DerivationGoal *>(i.get()); DerivationGoal * i2 = dynamic_cast<DerivationGoal *>(i.get());
if (i2) failed.insert(i2->getDrvPath()); if (i2) failed.insert(i2->getDrvPath());
else failed.insert(dynamic_cast<SubstitutionGoal *>(i.get())->getStorePath()); else failed.insert(dynamic_cast<SubstitutionGoal *>(i.get())->getStorePath());
} }
}
if (!failed.empty()) if (!failed.empty())
throw Error(worker.exitStatus(), "build of %s failed", showPaths(failed)); throw Error(worker.exitStatus(), "build of %s failed", showPaths(failed));

View file

@ -208,7 +208,18 @@ struct BuildResult
NotDeterministic, NotDeterministic,
} status = MiscFailure; } status = MiscFailure;
std::string errorMsg; 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; //time_t startTime = 0, stopTime = 0;
bool success() { bool success() {
return status == Built || status == Substituted || status == AlreadyValid; return status == Built || status == Substituted || status == AlreadyValid;
} }