summaryrefslogtreecommitdiff
path: root/nix/libstore/build.cc
diff options
context:
space:
mode:
Diffstat (limited to 'nix/libstore/build.cc')
-rw-r--r--nix/libstore/build.cc80
1 files changed, 66 insertions, 14 deletions
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index f9fd61adde..ae78e65199 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -1106,8 +1106,10 @@ void DerivationGoal::repairClosure()
/* Get the output closure. */
PathSet outputClosure;
- foreach (DerivationOutputs::iterator, i, drv.outputs)
+ foreach (DerivationOutputs::iterator, i, drv.outputs) {
+ if (!wantOutput(i->first, wantedOutputs)) continue;
computeFSClosure(worker.store, i->second.path, outputClosure);
+ }
/* Filter out our own outputs (which we have already checked). */
foreach (DerivationOutputs::iterator, i, drv.outputs)
@@ -1289,7 +1291,6 @@ void DerivationGoal::tryToBuild()
now hold the locks on the output paths, no other process can
build this derivation, so no further checks are necessary. */
validPaths = checkPathValidity(true, buildMode == bmRepair);
- assert(buildMode != bmCheck || validPaths.size() == drv.outputs.size());
if (buildMode != bmCheck && validPaths.size() == drv.outputs.size()) {
debug(format("skipping build of derivation `%1%', someone beat us to it") % drvPath);
outputLocks.setDeletion(true);
@@ -1717,7 +1718,7 @@ void DerivationGoal::startBuilder()
/* In a sandbox, for determinism, always use the same temporary
directory. */
- tmpDirInSandbox = useChroot ? "/tmp/guix-build-" + drvName + "-0" : tmpDir;
+ tmpDirInSandbox = useChroot ? canonPath("/tmp", true) + "/guix-build-" + drvName + "-0" : tmpDir;
/* For convenience, set an environment pointing to the top build
directory. */
@@ -2319,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. */
@@ -2344,7 +2347,7 @@ void DerivationGoal::registerOutputs()
&& redirectedBadOutputs.find(path) != redirectedBadOutputs.end()
&& pathExists(redirected))
replaceValidPath(path, redirected);
- if (buildMode == bmCheck)
+ if (buildMode == bmCheck && redirected != "")
actualPath = redirected;
}
@@ -2428,9 +2431,20 @@ void DerivationGoal::registerOutputs()
PathSet references = scanForReferences(actualPath, allPaths, hash);
if (buildMode == bmCheck) {
+ if (!store->isValidPath(path)) continue;
ValidPathInfo info = worker.store.queryPathInfo(path);
- if (hash.first != info.hash)
- throw Error(format("derivation `%1%' may not be deterministic: hash mismatch in output `%2%'") % drvPath % path);
+ if (hash.first != info.hash) {
+ if (settings.keepFailed) {
+ 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);
+ throw Error(format("derivation `%1%' may not be deterministic: output `%2%' differs from ‘%3%’")
+ % drvPath % path % dst);
+ } else
+ throw Error(format("derivation `%1%' may not be deterministic: output `%2%' differs")
+ % drvPath % path);
+ }
continue;
}
@@ -2475,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;
@@ -2490,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;
@@ -3480,8 +3523,17 @@ void LocalStore::repairPath(const Path & path)
worker.run(goals);
- if (goal->getExitCode() != Goal::ecSuccess)
- throw Error(format("cannot repair path `%1%'") % path, worker.exitStatus());
+ if (goal->getExitCode() != Goal::ecSuccess) {
+ /* Since substituting the path didn't work, if we have a valid
+ deriver, then rebuild the deriver. */
+ Path deriver = queryDeriver(path);
+ if (deriver != "" && isValidPath(deriver)) {
+ goals.clear();
+ goals.insert(worker.makeDerivationGoal(deriver, StringSet(), bmRepair));
+ worker.run(goals);
+ } else
+ throw Error(format("cannot repair path `%1%'") % path, worker.exitStatus());
+ }
}