summaryrefslogtreecommitdiff
path: root/nix/libstore
diff options
context:
space:
mode:
Diffstat (limited to 'nix/libstore')
-rw-r--r--nix/libstore/build.cc80
-rw-r--r--nix/libstore/local-store.cc9
-rw-r--r--nix/libstore/pathlocks.cc6
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();
+ }
}