Pass all settings to build-remote

This ensures that command line flags such as --builders get passed
correctly.
This commit is contained in:
Eelco Dolstra 2017-10-23 20:43:04 +02:00
parent f32cdc4fab
commit 37fbfffd8e
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
7 changed files with 75 additions and 82 deletions

View file

@ -46,16 +46,23 @@ int main (int argc, char * * argv)
unsetenv("DISPLAY"); unsetenv("DISPLAY");
unsetenv("SSH_ASKPASS"); unsetenv("SSH_ASKPASS");
if (argc != 6) if (argc != 2)
throw UsageError("called without required arguments"); throw UsageError("called without required arguments");
auto store = openStore().cast<LocalStore>(); verbosity = (Verbosity) std::stoll(argv[1]);
auto localSystem = argv[1]; FdSource source(STDIN_FILENO);
settings.maxSilentTime = std::stoll(argv[2]);
settings.buildTimeout = std::stoll(argv[3]); /* Read the parent's settings. */
verbosity = (Verbosity) std::stoll(argv[4]); while (readInt(source)) {
settings.builders = argv[5]; auto name = readString(source);
auto value = readString(source);
settings.set(name, value);
}
settings.maxBuildJobs.set("1"); // hack to make tests with local?root= work
auto store = openStore().cast<LocalStore>();
/* It would be more appropriate to use $XDG_RUNTIME_DIR, since /* It would be more appropriate to use $XDG_RUNTIME_DIR, since
that gets cleared on reboot, but it wouldn't work on macOS. */ that gets cleared on reboot, but it wouldn't work on macOS. */
@ -74,18 +81,20 @@ int main (int argc, char * * argv)
string drvPath; string drvPath;
string storeUri; string storeUri;
for (string line; getline(cin, line);) {
auto tokens = tokenizeString<std::vector<string>>(line); while (true) {
auto sz = tokens.size();
if (sz != 3 && sz != 4) try {
throw Error("invalid build hook line '%1%'", line); auto s = readString(source);
auto amWilling = tokens[0] == "1"; if (s != "try") return;
auto neededSystem = tokens[1]; } catch (EndOfFile &) { return; }
drvPath = tokens[2];
auto requiredFeatures = sz == 3 ? auto amWilling = readInt(source);
std::set<string>{} : auto neededSystem = readString(source);
tokenizeString<std::set<string>>(tokens[3], ","); source >> drvPath;
auto canBuildLocally = amWilling && (neededSystem == localSystem); auto requiredFeatures = readStrings<std::set<std::string>>(source);
auto canBuildLocally = amWilling && (neededSystem == settings.thisSystem);
/* Error ignored here, will be caught later */ /* Error ignored here, will be caught later */
mkdir(currentLoad.c_str(), 0777); mkdir(currentLoad.c_str(), 0777);
@ -100,7 +109,7 @@ int main (int argc, char * * argv)
Machine * bestMachine = nullptr; Machine * bestMachine = nullptr;
unsigned long long bestLoad = 0; unsigned long long bestLoad = 0;
for (auto & m : machines) { for (auto & m : machines) {
debug("considering building on '%s'", m.storeUri); debug("considering building on remote machine '%s'", m.storeUri);
if (m.enabled && std::find(m.systemTypes.begin(), if (m.enabled && std::find(m.systemTypes.begin(),
m.systemTypes.end(), m.systemTypes.end(),
@ -184,15 +193,9 @@ int main (int argc, char * * argv)
connected: connected:
std::cerr << "# accept\n"; std::cerr << "# accept\n";
string line;
if (!getline(cin, line))
throw Error("hook caller didn't send inputs");
auto inputs = tokenizeString<PathSet>(line); auto inputs = readStrings<PathSet>(source);
if (!getline(cin, line)) auto outputs = readStrings<PathSet>(source);
throw Error("hook caller didn't send outputs");
auto outputs = tokenizeString<PathSet>(line);
AutoCloseFD uploadLock = openLockFile(currentLoad + "/" + escapeUri(storeUri) + ".upload-lock", true); AutoCloseFD uploadLock = openLockFile(currentLoad + "/" + escapeUri(storeUri) + ".upload-lock", true);

View file

@ -606,6 +606,8 @@ struct HookInstance
/* The process ID of the hook. */ /* The process ID of the hook. */
Pid pid; Pid pid;
FdSink sink;
HookInstance(); HookInstance();
~HookInstance(); ~HookInstance();
@ -642,11 +644,7 @@ HookInstance::HookInstance()
Strings args = { Strings args = {
baseNameOf(settings.buildHook), baseNameOf(settings.buildHook),
settings.thisSystem,
std::to_string(settings.maxSilentTime),
std::to_string(settings.buildTimeout),
std::to_string(verbosity), std::to_string(verbosity),
settings.builders
}; };
execv(settings.buildHook.get().c_str(), stringsToCharPtrs(args).data()); execv(settings.buildHook.get().c_str(), stringsToCharPtrs(args).data());
@ -657,6 +655,11 @@ HookInstance::HookInstance()
pid.setSeparatePG(true); pid.setSeparatePG(true);
fromHook.writeSide = -1; fromHook.writeSide = -1;
toHook.readSide = -1; toHook.readSide = -1;
sink = FdSink(toHook.writeSide.get());
for (auto & setting : settings.getSettings())
sink << 1 << setting.first << setting.second;
sink << 0;
} }
@ -1633,9 +1636,13 @@ HookReply DerivationGoal::tryBuildHook()
for (auto & i : features) checkStoreName(i); /* !!! abuse */ for (auto & i : features) checkStoreName(i); /* !!! abuse */
/* Send the request to the hook. */ /* Send the request to the hook. */
writeLine(worker.hook->toHook.writeSide.get(), (format("%1% %2% %3% %4%") worker.hook->sink
% (worker.getNrLocalBuilds() < settings.maxBuildJobs ? "1" : "0") << "try"
% drv->platform % drvPath % concatStringsSep(",", features)).str()); << (worker.getNrLocalBuilds() < settings.maxBuildJobs ? 1 : 0)
<< drv->platform
<< drvPath
<< features;
worker.hook->sink.flush();
/* Read the first line of input, which should be a word indicating /* Read the first line of input, which should be a word indicating
whether the hook wishes to perform the build. */ whether the hook wishes to perform the build. */
@ -1680,12 +1687,13 @@ HookReply DerivationGoal::tryBuildHook()
/* Tell the hook all the inputs that have to be copied to the /* Tell the hook all the inputs that have to be copied to the
remote system. */ remote system. */
writeLine(hook->toHook.writeSide.get(), concatStringsSep(" ", inputPaths)); hook->sink << inputPaths;
/* Tell the hooks the missing outputs that have to be copied back /* Tell the hooks the missing outputs that have to be copied back
from the remote system. */ from the remote system. */
writeLine(hook->toHook.writeSide.get(), concatStringsSep(" ", missingPaths)); hook->sink << missingPaths;
hook->sink = FdSink();
hook->toHook.writeSide = -1; hook->toHook.writeSide = -1;
/* Create the log file and pipe. */ /* Create the log file and pipe. */
@ -3986,7 +3994,7 @@ void Worker::run(const Goals & _topGoals)
else { else {
if (awake.empty() && 0 == settings.maxBuildJobs) throw Error( if (awake.empty() && 0 == settings.maxBuildJobs) throw Error(
"unable to start any build; either increase '--max-jobs' " "unable to start any build; either increase '--max-jobs' "
"or enable distributed builds"); "or enable remote builds");
assert(!awake.empty()); assert(!awake.empty());
} }
} }

View file

@ -92,7 +92,17 @@ struct FdSink : BufferedSink
FdSink() : fd(-1) { } FdSink() : fd(-1) { }
FdSink(int fd) : fd(fd) { } FdSink(int fd) : fd(fd) { }
FdSink(FdSink&&) = default; FdSink(FdSink&&) = default;
FdSink& operator=(FdSink&&) = default;
FdSink& operator=(FdSink && s)
{
flush();
fd = s.fd;
s.fd = -1;
warn = s.warn;
written = s.written;
return *this;
}
~FdSink(); ~FdSink();
void write(const unsigned char * data, size_t len) override; void write(const unsigned char * data, size_t len) override;
@ -112,6 +122,16 @@ struct FdSource : BufferedSource
FdSource() : fd(-1) { } FdSource() : fd(-1) { }
FdSource(int fd) : fd(fd) { } FdSource(int fd) : fd(fd) { }
FdSource(FdSource&&) = default;
FdSource& operator=(FdSource && s)
{
fd = s.fd;
s.fd = -1;
read = s.read;
return *this;
}
size_t readUnbuffered(unsigned char * data, size_t len) override; size_t readUnbuffered(unsigned char * data, size_t len) override;
bool good() override; bool good() override;
private: private:

View file

@ -1,23 +0,0 @@
#! /bin/sh
#set -x
while read x y drv rest; do
echo "HOOK for $drv" >&2
outPath=`sed 's/Derive(\[("out",\"\([^\"]*\)\".*/\1/' $drv`
echo "output path is $outPath" >&2
if `echo $outPath | grep -q input-1`; then
echo "# accept" >&2
read inputs
read outputs
mkdir $outPath
echo "BAR" > $outPath/foo
else
echo "# decline" >&2
fi
done

View file

@ -1,10 +0,0 @@
source common.sh
clearStore
outPath=$(nix-build build-hook.nix --no-out-link --option build-hook $(pwd)/build-hook.hook.sh)
echo "output path is $outPath"
text=$(cat "$outPath"/foobar)
if test "$text" != "BARBAR"; then exit 1; fi

View file

@ -9,16 +9,11 @@ chmod -R u+w $TEST_ROOT/store0 || true
chmod -R u+w $TEST_ROOT/store1 || true chmod -R u+w $TEST_ROOT/store1 || true
rm -rf $TEST_ROOT/store0 $TEST_ROOT/store1 rm -rf $TEST_ROOT/store0 $TEST_ROOT/store1
# FIXME: --option is not passed to build-remote, so have to create a config file. nix build -f build-hook.nix -o $TEST_ROOT/result --max-jobs 0 \
export NIX_CONF_DIR=$TEST_ROOT/etc2 --sandbox-paths /nix/store --sandbox-build-dir /build-tmp \
mkdir -p $NIX_CONF_DIR --builders "local?root=$TEST_ROOT/store0; local?root=$TEST_ROOT/store1 - - 1 1 foo"
echo "
sandbox-paths = /nix/store
sandbox-build-dir = /build-tmp
" > $NIX_CONF_DIR/nix.conf
outPath=$(nix-build build-hook.nix --no-out-link -j0 \ outPath=$TEST_ROOT/result
--option builders "local?root=$TEST_ROOT/store0; local?root=$TEST_ROOT/store1 - - 1 1 foo")
cat $outPath/foobar | grep FOOBAR cat $outPath/foobar | grep FOOBAR

View file

@ -3,7 +3,7 @@ check:
nix_tests = \ nix_tests = \
init.sh hash.sh lang.sh add.sh simple.sh dependencies.sh \ init.sh hash.sh lang.sh add.sh simple.sh dependencies.sh \
build-hook.sh gc.sh gc-concurrent.sh \ gc.sh gc-concurrent.sh \
referrers.sh user-envs.sh logging.sh nix-build.sh misc.sh fixed.sh \ referrers.sh user-envs.sh logging.sh nix-build.sh misc.sh fixed.sh \
gc-runtime.sh check-refs.sh filter-source.sh \ gc-runtime.sh check-refs.sh filter-source.sh \
remote-store.sh export.sh export-graph.sh \ remote-store.sh export.sh export-graph.sh \