diff options
Diffstat (limited to 'nix/libstore/build.cc')
-rw-r--r-- | nix/libstore/build.cc | 80 |
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()); + } } |