From fed123724679de89d3f56a4c01b5c4c96f93e584 Mon Sep 17 00:00:00 2001
From: John Ericson <John.Ericson@Obsidian.Systems>
Date: Sun, 20 Dec 2020 19:55:21 +0000
Subject: [PATCH] Test nix-build with non-local-store --store

Just a few small things needed fixing!
---
 src/libstore/build/derivation-goal.cc | 20 +++++++++++++++++---
 tests/binary-cache-build-remote.sh    | 13 +++++++++++++
 tests/local.mk                        |  4 +++-
 3 files changed, 33 insertions(+), 4 deletions(-)
 create mode 100644 tests/binary-cache-build-remote.sh

diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc
index de32f60db..17f39a86e 100644
--- a/src/libstore/build/derivation-goal.cc
+++ b/src/libstore/build/derivation-goal.cc
@@ -592,9 +592,17 @@ void DerivationGoal::tryToBuild()
     PathSet lockFiles;
     /* FIXME: Should lock something like the drv itself so we don't build same
        CA drv concurrently */
-    for (auto & i : drv->outputsAndOptPaths(worker.store))
-        if (i.second.second)
-            lockFiles.insert(worker.store.Store::toRealPath(*i.second.second));
+    if (dynamic_cast<LocalStore *>(&worker.store))
+        /* If we aren't a local store, we might need to use the local store as
+           a build remote, but that would cause a deadlock. */
+        /* FIXME: Make it so we can use ourselves as a build remote even if we
+           are the local store (separate locking for building vs scheduling? */
+        /* FIXME: find some way to lock for scheduling for the other stores so
+           a forking daemon with --store still won't farm out redundant builds.
+           */
+        for (auto & i : drv->outputsAndOptPaths(worker.store))
+            if (i.second.second)
+                lockFiles.insert(worker.store.Store::toRealPath(*i.second.second));
 
     if (!outputLocks.lockPaths(lockFiles, "", false)) {
         if (!actLock)
@@ -680,6 +688,12 @@ void DerivationGoal::tryLocalBuild() {
     /* Make sure that we are allowed to start a build.  If this
        derivation prefers to be done locally, do it even if
        maxBuildJobs is 0. */
+    if (!dynamic_cast<LocalStore *>(&worker.store)) {
+        throw Error(
+            "unable to build with a primary store that isn't a local store; "
+            "either pass a different '--store' or enable remote builds."
+            "\nhttps://nixos.org/nix/manual/#chap-distributed-builds");
+    }
     unsigned int curBuilds = worker.getNrLocalBuilds();
     if (curBuilds >= settings.maxBuildJobs && !(buildLocally && curBuilds == 0)) {
         worker.waitForBuildSlot(shared_from_this());
diff --git a/tests/binary-cache-build-remote.sh b/tests/binary-cache-build-remote.sh
new file mode 100644
index 000000000..ed51164a4
--- /dev/null
+++ b/tests/binary-cache-build-remote.sh
@@ -0,0 +1,13 @@
+source common.sh
+
+clearStore
+clearCacheCache
+
+# Fails without remote builders
+(! nix-build --store "file://$cacheDir" dependencies.nix)
+
+# Succeeds with default store as build remote.
+nix-build --store "file://$cacheDir" --builders 'auto - - 1 1' -j0 dependencies.nix
+
+# Succeeds without any build capability because no-op
+nix-build --store "file://$cacheDir" -j0 dependencies.nix
diff --git a/tests/local.mk b/tests/local.mk
index ce94ec80e..aa8b4f9bf 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -9,7 +9,9 @@ nix_tests = \
   local-store.sh remote-store.sh export.sh export-graph.sh \
   timeout.sh secure-drv-outputs.sh nix-channel.sh \
   multiple-outputs.sh import-derivation.sh fetchurl.sh optimise-store.sh \
-  binary-cache.sh nix-profile.sh repair.sh dump-db.sh case-hack.sh \
+  binary-cache.sh \
+  binary-cache-build-remote.sh \
+  nix-profile.sh repair.sh dump-db.sh case-hack.sh \
   check-reqs.sh pass-as-file.sh tarball.sh restricted.sh \
   placeholders.sh nix-shell.sh \
   linux-sandbox.sh \