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:
parent
ceeedb58d2
commit
8bdf83f936
2 changed files with 24 additions and 11 deletions
|
@ -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));
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue