summary refs log tree commit diff
diff options
context:
space:
mode:
-rwxr-xr-xscripts/build-remote.pl.in27
-rw-r--r--src/libstore/build.cc12
-rw-r--r--src/libutil/util.cc11
-rw-r--r--src/libutil/util.hh5
4 files changed, 43 insertions, 12 deletions
diff --git a/scripts/build-remote.pl.in b/scripts/build-remote.pl.in
index a8f73f2e54..0c8081a0bc 100755
--- a/scripts/build-remote.pl.in
+++ b/scripts/build-remote.pl.in
@@ -36,6 +36,8 @@ sub sendReply {
     print STDERR "# $reply\n";
 }
 
+sub all { $_ || return 0 for @_; 1 }
+
 
 # Initialisation.
 my $loadIncreased = 0;
@@ -64,13 +66,14 @@ if (defined $conf && -e $conf) {
         chomp;
         s/\#.*$//g;
         next if /^\s*$/;
-        /^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\d+)(\s+([0-9\.]+))?\s*$/ or die;
+        my @tokens = split /\s/, $_;
         push @machines,
-            { hostName => $1
-            , systemTypes => [split(/,/, $2)]
-            , sshKeys => $3
-            , maxJobs => $4
-            , speedFactor => 1.0 * ($6 || 1)
+            { hostName => $tokens[0]
+            , systemTypes => [ split(/,/, $tokens[1]) ]
+            , sshKeys => $tokens[2]
+            , maxJobs => int($tokens[3])
+            , speedFactor => 1.0 * (defined $tokens[4] ? int($tokens[4]) : 1)
+            , features => [ split(/,/, $tokens[5] || "") ]
             , enabled => 1
             };
     }
@@ -85,7 +88,8 @@ my ($drvPath, $hostName, $slotLock);
 REQ: while (1) {
     $_ = <STDIN> || exit 0;
     my ($amWilling, $neededSystem);
-    ($amWilling, $neededSystem, $drvPath) = split;
+    ($amWilling, $neededSystem, $drvPath, $requiredFeatures) = split;
+    my @requiredFeatures = split /,/, $requiredFeatures;
 
     my $canBuildLocally = $amWilling && ($localSystem eq $neededSystem);
 
@@ -103,12 +107,15 @@ REQ: while (1) {
     
     while (1) {
         # Find all machine that can execute this build, i.e., that
-        # support builds for the given platform and are not at their
-        # job limit.
+        # support builds for the given platform and features, and are
+        # not at their job limit.
         my $rightType = 0;
         my @available = ();
         LOOP: foreach my $cur (@machines) {
-            if ($cur->{enabled} && grep { $neededSystem eq $_ } @{$cur->{systemTypes}}) {
+            if ($cur->{enabled}
+                && (grep { $neededSystem eq $_ } @{$cur->{systemTypes}})
+                && all(map { my $f = $_; 0 != grep { $f eq $_ } @{$cur->{features}} } @requiredFeatures))
+            {
                 $rightType = 1;
 
                 # We have a machine of the right type.  Determine the load on
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index f2781776c6..f9c9a0a1ea 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -1327,8 +1327,16 @@ HookReply DerivationGoal::tryBuildHook()
     if (!worker.hook)
         worker.hook = boost::shared_ptr<HookInstance>(new HookInstance);
 
-    writeLine(worker.hook->toHook.writeSide, (format("%1% %2% %3%") %
-        (worker.getNrLocalBuilds() < maxBuildJobs ? "1" : "0") % drv.platform % drvPath).str());
+    /* Tell the hook about system features (beyond the system type)
+       required from the build machine.  (The hook could parse the
+       drv file itself, but this is easier.) */
+    Strings features = tokenizeString(drv.env["requiredSystemFeatures"]);
+    foreach (Strings::iterator, i, features) checkStoreName(*i); /* !!! abuse */
+
+    /* Send the request to the hook. */
+    writeLine(worker.hook->toHook.writeSide, (format("%1% %2% %3% %4%")
+        % (worker.getNrLocalBuilds() < maxBuildJobs ? "1" : "0")
+        % drv.platform % drvPath % concatStringsSep(",", features)).str());
 
     /* Read the first line of input, which should be a word indicating
        whether the hook wishes to perform the build. */
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 9540720fe2..2d26fc66da 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -966,6 +966,17 @@ Strings tokenizeString(const string & s, const string & separators)
 }
 
 
+string concatStringsSep(const string & sep, const Strings & ss)
+{
+    string s;
+    foreach (Strings::const_iterator, i, ss) {
+        if (s.size() != 0) s += sep;
+        s += *i;
+    }
+    return s;
+}
+
+
 string statusToString(int status)
 {
     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index c45ebc062f..27ad469049 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -280,6 +280,11 @@ MakeError(Interrupted, BaseError)
 Strings tokenizeString(const string & s, const string & separators = " \t\n\r");
 
 
+/* Concatenate the given strings with a separator between the
+   elements. */
+string concatStringsSep(const string & sep, const Strings & ss);
+
+
 /* Convert the exit status of a child as returned by wait() into an
    error string. */
 string statusToString(int status);