diff options
Diffstat (limited to 'nix/libstore')
-rw-r--r-- | nix/libstore/build.cc | 80 | ||||
-rw-r--r-- | nix/libstore/local-store.cc | 9 | ||||
-rw-r--r-- | nix/libstore/pathlocks.cc | 6 |
3 files changed, 78 insertions, 17 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()); + } } diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc index 11f61ae030..347e8a703f 100644 --- a/nix/libstore/local-store.cc +++ b/nix/libstore/local-store.cc @@ -606,10 +606,10 @@ static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSe users group); we check for this case below. */ if (st.st_uid != geteuid()) { #if HAVE_LCHOWN - if (lchown(path.c_str(), geteuid(), (gid_t) -1) == -1) + if (lchown(path.c_str(), geteuid(), getegid()) == -1) #else if (!S_ISLNK(st.st_mode) && - chown(path.c_str(), geteuid(), (gid_t) -1) == -1) + chown(path.c_str(), geteuid(), getegid()) == -1) #endif throw SysError(format("changing owner of `%1%' to %2%") % path % geteuid()); @@ -1213,6 +1213,9 @@ template<class T> T LocalStore::getIntLineFromSubstituter(RunningSubstituter & r PathSet LocalStore::querySubstitutablePaths(const PathSet & paths) { PathSet res; + + if (!settings.useSubstitutes) return res; + foreach (Paths::iterator, i, settings.substituters) { if (res.size() == paths.size()) break; RunningSubstituter & run(runningSubstituters[*i]); @@ -1239,6 +1242,8 @@ PathSet LocalStore::querySubstitutablePaths(const PathSet & paths) void LocalStore::querySubstitutablePathInfos(const Path & substituter, PathSet & paths, SubstitutablePathInfos & infos) { + if (!settings.useSubstitutes) return; + RunningSubstituter & run(runningSubstituters[substituter]); startSubstituter(substituter, run); if (run.disabled) return; diff --git a/nix/libstore/pathlocks.cc b/nix/libstore/pathlocks.cc index 830858ff8d..9797ddd7ab 100644 --- a/nix/libstore/pathlocks.cc +++ b/nix/libstore/pathlocks.cc @@ -162,7 +162,11 @@ bool PathLocks::lockPaths(const PathSet & _paths, PathLocks::~PathLocks() { - unlock(); + try { + unlock(); + } catch (...) { + ignoreException(); + } } |