about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--src/libstore/build.cc61
-rw-r--r--src/libstore/local-store.cc4
3 files changed, 55 insertions, 12 deletions
diff --git a/configure.ac b/configure.ac
index 1b99702fedff..3a24053bb6a1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -55,6 +55,8 @@ if test "$sys_name" = sunos; then
 fi
 
 
+CFLAGS=
+CXXFLAGS=
 AC_PROG_CC
 AC_PROG_CXX
 
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index 284d781b4434..af068fc59ad1 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -1326,7 +1326,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);
@@ -2638,6 +2637,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. */
@@ -2663,7 +2664,7 @@ void DerivationGoal::registerOutputs()
                 && redirectedBadOutputs.find(path) != redirectedBadOutputs.end()
                 && pathExists(redirected))
                 replaceValidPath(path, redirected);
-            if (buildMode == bmCheck)
+            if (buildMode == bmCheck && redirected != "")
                 actualPath = redirected;
         }
 
@@ -2747,9 +2748,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;
         }
 
@@ -2794,9 +2806,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;
@@ -2809,10 +2823,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;
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index d7cd0b088d98..9199b12063a0 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -602,10 +602,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());