diff options
Diffstat (limited to 'nix')
-rw-r--r-- | nix/libstore/build.cc | 97 | ||||
-rw-r--r-- | nix/libstore/remote-store.cc | 639 | ||||
-rw-r--r-- | nix/libstore/remote-store.hh | 106 | ||||
-rw-r--r-- | nix/libstore/store-api.cc | 22 | ||||
-rw-r--r-- | nix/libstore/store-api.hh | 24 | ||||
-rw-r--r-- | nix/nix-daemon/guix-daemon.cc | 15 |
6 files changed, 116 insertions, 787 deletions
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc index 47c7f9728e..f9fd61adde 100644 --- a/nix/libstore/build.cc +++ b/nix/libstore/build.cc @@ -84,6 +84,7 @@ struct HookInstance; /* A pointer to a goal. */ class Goal; +class DerivationGoal; typedef std::shared_ptr<Goal> GoalPtr; typedef std::weak_ptr<Goal> WeakGoalPtr; @@ -174,10 +175,10 @@ public: return exitCode; } - /* Cancel the goal. It should wake up its waiters, get rid of any - running child processes that are being monitored by the worker - (important!), etc. */ - virtual void cancel(bool timeout) = 0; + /* Callback in case of a timeout. It should wake up its waiters, + get rid of any running child processes that are being monitored + by the worker (important!), etc. */ + virtual void timedOut() = 0; virtual string key() = 0; @@ -799,11 +800,13 @@ private: result. */ ValidPathInfos prevInfos; + BuildResult result; + public: DerivationGoal(const Path & drvPath, const StringSet & wantedOutputs, Worker & worker, BuildMode buildMode = bmNormal); ~DerivationGoal(); - void cancel(bool timeout); + void timedOut() override; string key() { @@ -824,6 +827,8 @@ public: /* Add wanted outputs to an already existing derivation goal. */ void addWantedOutputs(const StringSet & outputs); + BuildResult getResult() { return result; } + private: /* The states. */ void init(); @@ -874,6 +879,8 @@ private: Path addHashRewrite(const Path & path); void repairClosure(); + + void done(BuildResult::Status status, const string & msg = ""); }; @@ -933,12 +940,12 @@ void DerivationGoal::killChild() } -void DerivationGoal::cancel(bool timeout) +void DerivationGoal::timedOut() { - if (settings.printBuildTrace && timeout) + if (settings.printBuildTrace) printMsg(lvlError, format("@ build-failed %1% - timeout") % drvPath); killChild(); - amDone(ecFailed); + done(BuildResult::TimedOut); } @@ -991,8 +998,8 @@ void DerivationGoal::haveDerivation() trace("loading derivation"); if (nrFailed != 0) { - printMsg(lvlError, format("cannot build missing derivation `%1%'") % drvPath); - amDone(ecFailed); + printMsg(lvlError, format("cannot build missing derivation ‘%1%’") % drvPath); + done(BuildResult::MiscFailure); return; } @@ -1014,7 +1021,7 @@ void DerivationGoal::haveDerivation() /* If they are all valid, then we're done. */ if (invalidOutputs.size() == 0 && buildMode == bmNormal) { - amDone(ecSuccess); + done(BuildResult::AlreadyValid); return; } @@ -1059,7 +1066,7 @@ void DerivationGoal::outputsSubstituted() unsigned int nrInvalid = checkPathValidity(false, buildMode == bmRepair).size(); if (buildMode == bmNormal && nrInvalid == 0) { - amDone(ecSuccess); + done(BuildResult::Substituted); return; } if (buildMode == bmRepair && nrInvalid == 0) { @@ -1132,7 +1139,7 @@ void DerivationGoal::repairClosure() } if (waitees.empty()) { - amDone(ecSuccess); + done(BuildResult::AlreadyValid); return; } @@ -1144,8 +1151,8 @@ void DerivationGoal::closureRepaired() { trace("closure repaired"); if (nrFailed > 0) - throw Error(format("some paths in the output closure of derivation `%1%' could not be repaired") % drvPath); - amDone(ecSuccess); + throw Error(format("some paths in the output closure of derivation ‘%1%’ could not be repaired") % drvPath); + done(BuildResult::AlreadyValid); } @@ -1157,7 +1164,7 @@ void DerivationGoal::inputsRealised() printMsg(lvlError, format("cannot build derivation `%1%': %2% dependencies couldn't be built") % drvPath % nrFailed); - amDone(ecFailed); + done(BuildResult::DependencyFailed); return; } @@ -1286,7 +1293,7 @@ void DerivationGoal::tryToBuild() if (buildMode != bmCheck && validPaths.size() == drv.outputs.size()) { debug(format("skipping build of derivation `%1%', someone beat us to it") % drvPath); outputLocks.setDeletion(true); - amDone(ecSuccess); + done(BuildResult::AlreadyValid); return; } @@ -1358,7 +1365,7 @@ void DerivationGoal::tryToBuild() printMsg(lvlError, format("@ build-failed %1% - %2% %3%") % drvPath % 0 % e.msg()); worker.permanentFailure = true; - amDone(ecFailed); + done(BuildResult::InputRejected, e.msg()); return; } @@ -1473,7 +1480,7 @@ void DerivationGoal::buildDone() registerOutputs(); if (buildMode == bmCheck) { - amDone(ecSuccess); + done(BuildResult::Built); return; } @@ -1508,10 +1515,12 @@ void DerivationGoal::buildDone() outputLocks.unlock(); buildUser.release(); + BuildResult::Status st = BuildResult::MiscFailure; + if (hook && WIFEXITED(status) && WEXITSTATUS(status) == 101) { if (settings.printBuildTrace) printMsg(lvlError, format("@ build-failed %1% - timeout") % drvPath); - worker.timedOut = true; + st = BuildResult::TimedOut; } else if (hook && (!WIFEXITED(status) || WEXITSTATUS(status) != 100)) { @@ -1524,7 +1533,11 @@ void DerivationGoal::buildDone() if (settings.printBuildTrace) printMsg(lvlError, format("@ build-failed %1% - %2% %3%") % drvPath % 1 % e.msg()); - worker.permanentFailure = !fixedOutput && !diskFull; + + st = + statusOk(status) ? BuildResult::OutputRejected : + fixedOutput || diskFull ? BuildResult::TransientFailure : + BuildResult::PermanentFailure; /* Register the outputs of this build as "failed" so we won't try to build them again (negative caching). @@ -1538,7 +1551,7 @@ void DerivationGoal::buildDone() worker.store.registerFailedPath(i->second.path); } - amDone(ecFailed); + done(st, e.msg()); return; } @@ -1548,7 +1561,7 @@ void DerivationGoal::buildDone() if (settings.printBuildTrace) printMsg(lvlError, format("@ build-succeeded %1% -") % drvPath); - amDone(ecSuccess); + done(BuildResult::Built); } @@ -1700,11 +1713,11 @@ void DerivationGoal::startBuilder() /* Create a temporary directory where the build will take place. */ auto drvName = storePathToName(drvPath); - tmpDir = createTempDir("", "nix-build-" + drvName, false, false, 0700); + tmpDir = createTempDir("", "guix-build-" + drvName, false, false, 0700); /* In a sandbox, for determinism, always use the same temporary directory. */ - tmpDirInSandbox = useChroot ? "/tmp/nix-build-" + drvName + "-0" : tmpDir; + tmpDirInSandbox = useChroot ? "/tmp/guix-build-" + drvName + "-0" : tmpDir; /* For convenience, set an environment pointing to the top build directory. */ @@ -2579,7 +2592,7 @@ void DerivationGoal::handleChildOutput(int fd, const string & data) printMsg(lvlError, format("%1% killed after writing more than %2% bytes of log output") % getName() % settings.maxLogSize); - cancel(true); // not really a timeout, but close enough + timedOut(); // not really a timeout, but close enough return; } if (verbosity >= settings.buildVerbosity) @@ -2628,8 +2641,7 @@ bool DerivationGoal::pathFailed(const Path & path) if (settings.printBuildTrace) printMsg(lvlError, format("@ build-failed %1% - cached") % drvPath); - worker.permanentFailure = true; - amDone(ecFailed); + done(BuildResult::CachedFailure); return true; } @@ -2649,6 +2661,18 @@ Path DerivationGoal::addHashRewrite(const Path & path) } +void DerivationGoal::done(BuildResult::Status status, const string & msg) +{ + result.status = status; + result.errorMsg = msg; + amDone(result.success() ? ecSuccess : ecFailed); + if (result.status == BuildResult::TimedOut) + worker.timedOut = true; + if (result.status == BuildResult::PermanentFailure || result.status == BuildResult::CachedFailure) + worker.permanentFailure = true; +} + + ////////////////////////////////////////////////////////////////////// @@ -2698,7 +2722,7 @@ public: SubstitutionGoal(const Path & storePath, Worker & worker, bool repair = false); ~SubstitutionGoal(); - void cancel(bool timeout); + void timedOut(); string key() { @@ -2743,9 +2767,9 @@ SubstitutionGoal::~SubstitutionGoal() } -void SubstitutionGoal::cancel(bool timeout) +void SubstitutionGoal::timedOut() { - if (settings.printBuildTrace && timeout) + if (settings.printBuildTrace) printMsg(lvlError, format("@ substituter-failed %1% timeout") % storePath); if (pid != -1) { pid_t savedPid = pid; @@ -3066,7 +3090,8 @@ Worker::~Worker() } -GoalPtr Worker::makeDerivationGoal(const Path & path, const StringSet & wantedOutputs, BuildMode buildMode) +GoalPtr Worker::makeDerivationGoal(const Path & path, + const StringSet & wantedOutputs, BuildMode buildMode) { GoalPtr goal = derivationGoals[path].lock(); if (!goal) { @@ -3323,7 +3348,7 @@ void Worker::waitForInput() /* Since goals may be canceled from inside the loop below (causing them go be erased from the `children' map), we have to be careful that we don't keep iterators alive across calls to - cancel(). */ + timedOut(). */ set<pid_t> pids; foreach (Children::iterator, i, children) pids.insert(i->first); @@ -3365,8 +3390,7 @@ void Worker::waitForInput() printMsg(lvlError, format("%1% timed out after %2% seconds of silence") % goal->getName() % settings.maxSilentTime); - goal->cancel(true); - timedOut = true; + goal->timedOut(); } else if (goal->getExitCode() == Goal::ecBusy && @@ -3377,8 +3401,7 @@ void Worker::waitForInput() printMsg(lvlError, format("%1% timed out after %2% seconds") % goal->getName() % settings.buildTimeout); - goal->cancel(true); - timedOut = true; + goal->timedOut(); } } diff --git a/nix/libstore/remote-store.cc b/nix/libstore/remote-store.cc deleted file mode 100644 index 324ef5eb30..0000000000 --- a/nix/libstore/remote-store.cc +++ /dev/null @@ -1,639 +0,0 @@ -#include "serialise.hh" -#include "util.hh" -#include "remote-store.hh" -#include "worker-protocol.hh" -#include "archive.hh" -#include "affinity.hh" -#include "globals.hh" - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <errno.h> -#include <fcntl.h> - -#include <iostream> -#include <unistd.h> -#include <cstring> - -namespace nix { - - -Path readStorePath(Source & from) -{ - Path path = readString(from); - assertStorePath(path); - return path; -} - - -template<class T> T readStorePaths(Source & from) -{ - T paths = readStrings<T>(from); - foreach (typename T::iterator, i, paths) assertStorePath(*i); - return paths; -} - -template PathSet readStorePaths(Source & from); - - -RemoteStore::RemoteStore() -{ - initialised = false; -} - - -void RemoteStore::openConnection(bool reserveSpace) -{ - if (initialised) return; - initialised = true; - - string remoteMode = getEnv("NIX_REMOTE"); - - if (remoteMode == "daemon") - /* Connect to a daemon that does the privileged work for - us. */ - connectToDaemon(); - else - throw Error(format("invalid setting for NIX_REMOTE, `%1%'") % remoteMode); - - from.fd = fdSocket; - to.fd = fdSocket; - - /* Send the magic greeting, check for the reply. */ - try { - writeInt(WORKER_MAGIC_1, to); - to.flush(); - unsigned int magic = readInt(from); - if (magic != WORKER_MAGIC_2) throw Error("protocol mismatch"); - - daemonVersion = readInt(from); - if (GET_PROTOCOL_MAJOR(daemonVersion) != GET_PROTOCOL_MAJOR(PROTOCOL_VERSION)) - throw Error("Nix daemon protocol version not supported"); - writeInt(PROTOCOL_VERSION, to); - - if (GET_PROTOCOL_MINOR(daemonVersion) >= 14) { - int cpu = settings.lockCPU ? lockToCurrentCPU() : -1; - if (cpu != -1) { - writeInt(1, to); - writeInt(cpu, to); - } else - writeInt(0, to); - } - - if (GET_PROTOCOL_MINOR(daemonVersion) >= 11) - writeInt(reserveSpace, to); - - processStderr(); - } - catch (Error & e) { - throw Error(format("cannot start daemon worker: %1%") % e.msg()); - } - - setOptions(); -} - - -void RemoteStore::connectToDaemon() -{ - fdSocket = socket(PF_UNIX, SOCK_STREAM, 0); - if (fdSocket == -1) - throw SysError("cannot create Unix domain socket"); - closeOnExec(fdSocket); - - string socketPath = settings.nixDaemonSocketFile; - - /* Urgh, sockaddr_un allows path names of only 108 characters. So - chdir to the socket directory so that we can pass a relative - path name. !!! this is probably a bad idea in multi-threaded - applications... */ - AutoCloseFD fdPrevDir = open(".", O_RDONLY); - if (fdPrevDir == -1) throw SysError("couldn't open current directory"); - if (chdir(dirOf(socketPath).c_str()) == -1) throw SysError(format("couldn't change to directory of ‘%1%’") % socketPath); - Path socketPathRel = "./" + baseNameOf(socketPath); - - struct sockaddr_un addr; - addr.sun_family = AF_UNIX; - if (socketPathRel.size() >= sizeof(addr.sun_path)) - throw Error(format("socket path `%1%' is too long") % socketPathRel); - using namespace std; - strcpy(addr.sun_path, socketPathRel.c_str()); - - if (connect(fdSocket, (struct sockaddr *) &addr, sizeof(addr)) == -1) - throw SysError(format("cannot connect to daemon at `%1%'") % socketPath); - - if (fchdir(fdPrevDir) == -1) - throw SysError("couldn't change back to previous directory"); -} - - -RemoteStore::~RemoteStore() -{ - try { - to.flush(); - fdSocket.close(); - } catch (...) { - ignoreException(); - } -} - - -void RemoteStore::setOptions() -{ - writeInt(wopSetOptions, to); - - writeInt(settings.keepFailed, to); - writeInt(settings.keepGoing, to); - writeInt(settings.tryFallback, to); - writeInt(verbosity, to); - writeInt(settings.maxBuildJobs, to); - writeInt(settings.maxSilentTime, to); - if (GET_PROTOCOL_MINOR(daemonVersion) >= 2) - writeInt(settings.useBuildHook, to); - if (GET_PROTOCOL_MINOR(daemonVersion) >= 4) { - writeInt(settings.buildVerbosity, to); - writeInt(logType, to); - writeInt(settings.printBuildTrace, to); - } - if (GET_PROTOCOL_MINOR(daemonVersion) >= 6) - writeInt(settings.buildCores, to); - if (GET_PROTOCOL_MINOR(daemonVersion) >= 10) - writeInt(settings.useSubstitutes, to); - - if (GET_PROTOCOL_MINOR(daemonVersion) >= 12) { - Settings::SettingsMap overrides = settings.getOverrides(); - writeInt(overrides.size(), to); - foreach (Settings::SettingsMap::iterator, i, overrides) { - writeString(i->first, to); - writeString(i->second, to); - } - } - - processStderr(); -} - - -bool RemoteStore::isValidPath(const Path & path) -{ - openConnection(); - writeInt(wopIsValidPath, to); - writeString(path, to); - processStderr(); - unsigned int reply = readInt(from); - return reply != 0; -} - - -PathSet RemoteStore::queryValidPaths(const PathSet & paths) -{ - openConnection(); - if (GET_PROTOCOL_MINOR(daemonVersion) < 12) { - PathSet res; - foreach (PathSet::const_iterator, i, paths) - if (isValidPath(*i)) res.insert(*i); - return res; - } else { - writeInt(wopQueryValidPaths, to); - writeStrings(paths, to); - processStderr(); - return readStorePaths<PathSet>(from); - } -} - - -PathSet RemoteStore::queryAllValidPaths() -{ - openConnection(); - writeInt(wopQueryAllValidPaths, to); - processStderr(); - return readStorePaths<PathSet>(from); -} - - -PathSet RemoteStore::querySubstitutablePaths(const PathSet & paths) -{ - openConnection(); - if (GET_PROTOCOL_MINOR(daemonVersion) < 12) { - PathSet res; - foreach (PathSet::const_iterator, i, paths) { - writeInt(wopHasSubstitutes, to); - writeString(*i, to); - processStderr(); - if (readInt(from)) res.insert(*i); - } - return res; - } else { - writeInt(wopQuerySubstitutablePaths, to); - writeStrings(paths, to); - processStderr(); - return readStorePaths<PathSet>(from); - } -} - - -void RemoteStore::querySubstitutablePathInfos(const PathSet & paths, - SubstitutablePathInfos & infos) -{ - if (paths.empty()) return; - - openConnection(); - - if (GET_PROTOCOL_MINOR(daemonVersion) < 3) return; - - if (GET_PROTOCOL_MINOR(daemonVersion) < 12) { - - foreach (PathSet::const_iterator, i, paths) { - SubstitutablePathInfo info; - writeInt(wopQuerySubstitutablePathInfo, to); - writeString(*i, to); - processStderr(); - unsigned int reply = readInt(from); - if (reply == 0) continue; - info.deriver = readString(from); - if (info.deriver != "") assertStorePath(info.deriver); - info.references = readStorePaths<PathSet>(from); - info.downloadSize = readLongLong(from); - info.narSize = GET_PROTOCOL_MINOR(daemonVersion) >= 7 ? readLongLong(from) : 0; - infos[*i] = info; - } - - } else { - - writeInt(wopQuerySubstitutablePathInfos, to); - writeStrings(paths, to); - processStderr(); - unsigned int count = readInt(from); - for (unsigned int n = 0; n < count; n++) { - Path path = readStorePath(from); - SubstitutablePathInfo & info(infos[path]); - info.deriver = readString(from); - if (info.deriver != "") assertStorePath(info.deriver); - info.references = readStorePaths<PathSet>(from); - info.downloadSize = readLongLong(from); - info.narSize = readLongLong(from); - } - - } -} - - -ValidPathInfo RemoteStore::queryPathInfo(const Path & path) -{ - openConnection(); - writeInt(wopQueryPathInfo, to); - writeString(path, to); - processStderr(); - ValidPathInfo info; - info.path = path; - info.deriver = readString(from); - if (info.deriver != "") assertStorePath(info.deriver); - info.hash = parseHash(htSHA256, readString(from)); - info.references = readStorePaths<PathSet>(from); - info.registrationTime = readInt(from); - info.narSize = readLongLong(from); - return info; -} - - -Hash RemoteStore::queryPathHash(const Path & path) -{ - openConnection(); - writeInt(wopQueryPathHash, to); - writeString(path, to); - processStderr(); - string hash = readString(from); - return parseHash(htSHA256, hash); -} - - -void RemoteStore::queryReferences(const Path & path, - PathSet & references) -{ - openConnection(); - writeInt(wopQueryReferences, to); - writeString(path, to); - processStderr(); - PathSet references2 = readStorePaths<PathSet>(from); - references.insert(references2.begin(), references2.end()); -} - - -void RemoteStore::queryReferrers(const Path & path, - PathSet & referrers) -{ - openConnection(); - writeInt(wopQueryReferrers, to); - writeString(path, to); - processStderr(); - PathSet referrers2 = readStorePaths<PathSet>(from); - referrers.insert(referrers2.begin(), referrers2.end()); -} - - -Path RemoteStore::queryDeriver(const Path & path) -{ - openConnection(); - writeInt(wopQueryDeriver, to); - writeString(path, to); - processStderr(); - Path drvPath = readString(from); - if (drvPath != "") assertStorePath(drvPath); - return drvPath; -} - - -PathSet RemoteStore::queryValidDerivers(const Path & path) -{ - openConnection(); - writeInt(wopQueryValidDerivers, to); - writeString(path, to); - processStderr(); - return readStorePaths<PathSet>(from); -} - - -PathSet RemoteStore::queryDerivationOutputs(const Path & path) -{ - openConnection(); - writeInt(wopQueryDerivationOutputs, to); - writeString(path, to); - processStderr(); - return readStorePaths<PathSet>(from); -} - - -PathSet RemoteStore::queryDerivationOutputNames(const Path & path) -{ - openConnection(); - writeInt(wopQueryDerivationOutputNames, to); - writeString(path, to); - processStderr(); - return readStrings<PathSet>(from); -} - - -Path RemoteStore::queryPathFromHashPart(const string & hashPart) -{ - openConnection(); - writeInt(wopQueryPathFromHashPart, to); - writeString(hashPart, to); - processStderr(); - Path path = readString(from); - if (!path.empty()) assertStorePath(path); - return path; -} - - -Path RemoteStore::addToStore(const string & name, const Path & _srcPath, - bool recursive, HashType hashAlgo, PathFilter & filter, bool repair) -{ - if (repair) throw Error("repairing is not supported when building through the Nix daemon"); - - openConnection(); - - Path srcPath(absPath(_srcPath)); - - writeInt(wopAddToStore, to); - writeString(name, to); - /* backwards compatibility hack */ - writeInt((hashAlgo == htSHA256 && recursive) ? 0 : 1, to); - writeInt(recursive ? 1 : 0, to); - writeString(printHashType(hashAlgo), to); - - try { - to.written = 0; - to.warn = true; - dumpPath(srcPath, to, filter); - to.warn = false; - processStderr(); - } catch (SysError & e) { - /* Daemon closed while we were sending the path. Probably OOM - or I/O error. */ - if (e.errNo == EPIPE) - try { - processStderr(); - } catch (EndOfFile & e) { } - throw; - } - - return readStorePath(from); -} - - -Path RemoteStore::addTextToStore(const string & name, const string & s, - const PathSet & references, bool repair) -{ - if (repair) throw Error("repairing is not supported when building through the Nix daemon"); - - openConnection(); - writeInt(wopAddTextToStore, to); - writeString(name, to); - writeString(s, to); - writeStrings(references, to); - - processStderr(); - return readStorePath(from); -} - - -void RemoteStore::exportPath(const Path & path, bool sign, - Sink & sink) -{ - openConnection(); - writeInt(wopExportPath, to); - writeString(path, to); - writeInt(sign ? 1 : 0, to); - processStderr(&sink); /* sink receives the actual data */ - readInt(from); -} - - -Paths RemoteStore::importPaths(bool requireSignature, Source & source) -{ - openConnection(); - writeInt(wopImportPaths, to); - /* We ignore requireSignature, since the worker forces it to true - anyway. */ - processStderr(0, &source); - return readStorePaths<Paths>(from); -} - - -void RemoteStore::buildPaths(const PathSet & drvPaths, BuildMode buildMode) -{ - openConnection(); - writeInt(wopBuildPaths, to); - if (GET_PROTOCOL_MINOR(daemonVersion) >= 13) { - writeStrings(drvPaths, to); - if (GET_PROTOCOL_MINOR(daemonVersion) >= 15) { - writeInt(buildMode, to); - } - /* Old daemons did not take a 'buildMode' parameter, so we need to - validate it here on the client side. */ - else if (buildMode != bmNormal) throw Error("repairing or checking \ -is not supported when building through the Nix daemon"); - } - else { - /* For backwards compatibility with old daemons, strip output - identifiers. */ - PathSet drvPaths2; - foreach (PathSet::const_iterator, i, drvPaths) - drvPaths2.insert(string(*i, 0, i->find('!'))); - writeStrings(drvPaths2, to); - } - processStderr(); - readInt(from); -} - - -void RemoteStore::ensurePath(const Path & path) -{ - openConnection(); - writeInt(wopEnsurePath, to); - writeString(path, to); - processStderr(); - readInt(from); -} - - -void RemoteStore::addTempRoot(const Path & path) -{ - openConnection(); - writeInt(wopAddTempRoot, to); - writeString(path, to); - processStderr(); - readInt(from); -} - - -void RemoteStore::addIndirectRoot(const Path & path) -{ - openConnection(); - writeInt(wopAddIndirectRoot, to); - writeString(path, to); - processStderr(); - readInt(from); -} - - -void RemoteStore::syncWithGC() -{ - openConnection(); - writeInt(wopSyncWithGC, to); - processStderr(); - readInt(from); -} - - -Roots RemoteStore::findRoots() -{ - openConnection(); - writeInt(wopFindRoots, to); - processStderr(); - unsigned int count = readInt(from); - Roots result; - while (count--) { - Path link = readString(from); - Path target = readStorePath(from); - result[link] = target; - } - return result; -} - - -void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results) -{ - openConnection(false); - - writeInt(wopCollectGarbage, to); - writeInt(options.action, to); - writeStrings(options.pathsToDelete, to); - writeInt(options.ignoreLiveness, to); - writeLongLong(options.maxFreed, to); - writeInt(0, to); - if (GET_PROTOCOL_MINOR(daemonVersion) >= 5) { - /* removed options */ - writeInt(0, to); - writeInt(0, to); - } - - processStderr(); - - results.paths = readStrings<PathSet>(from); - results.bytesFreed = readLongLong(from); - readLongLong(from); // obsolete -} - - -PathSet RemoteStore::queryFailedPaths() -{ - openConnection(); - writeInt(wopQueryFailedPaths, to); - processStderr(); - return readStorePaths<PathSet>(from); -} - - -void RemoteStore::clearFailedPaths(const PathSet & paths) -{ - openConnection(); - writeInt(wopClearFailedPaths, to); - writeStrings(paths, to); - processStderr(); - readInt(from); -} - -void RemoteStore::optimiseStore() -{ - openConnection(); - writeInt(wopOptimiseStore, to); - processStderr(); - readInt(from); -} - -bool RemoteStore::verifyStore(bool checkContents, bool repair) -{ - openConnection(); - writeInt(wopVerifyStore, to); - writeInt(checkContents, to); - writeInt(repair, to); - processStderr(); - return readInt(from) != 0; -} - -void RemoteStore::processStderr(Sink * sink, Source * source) -{ - to.flush(); - unsigned int msg; - while ((msg = readInt(from)) == STDERR_NEXT - || msg == STDERR_READ || msg == STDERR_WRITE) { - if (msg == STDERR_WRITE) { - string s = readString(from); - if (!sink) throw Error("no sink"); - (*sink)((const unsigned char *) s.data(), s.size()); - } - else if (msg == STDERR_READ) { - if (!source) throw Error("no source"); - size_t len = readInt(from); - unsigned char * buf = new unsigned char[len]; - AutoDeleteArray<unsigned char> d(buf); - writeString(buf, source->read(buf, len), to); - to.flush(); - } - else { - string s = readString(from); - writeToStderr(s); - } - } - if (msg == STDERR_ERROR) { - string error = readString(from); - unsigned int status = GET_PROTOCOL_MINOR(daemonVersion) >= 8 ? readInt(from) : 1; - throw Error(format("%1%") % error, status); - } - else if (msg != STDERR_LAST) - throw Error("protocol error processing standard error"); -} - - -} diff --git a/nix/libstore/remote-store.hh b/nix/libstore/remote-store.hh deleted file mode 100644 index 030120db40..0000000000 --- a/nix/libstore/remote-store.hh +++ /dev/null @@ -1,106 +0,0 @@ -#pragma once - -#include <string> - -#include "store-api.hh" - - -namespace nix { - - -class Pipe; -class Pid; -struct FdSink; -struct FdSource; - - -class RemoteStore : public StoreAPI -{ -public: - - RemoteStore(); - - ~RemoteStore(); - - /* Implementations of abstract store API methods. */ - - bool isValidPath(const Path & path); - - PathSet queryValidPaths(const PathSet & paths); - - PathSet queryAllValidPaths(); - - ValidPathInfo queryPathInfo(const Path & path); - - Hash queryPathHash(const Path & path); - - void queryReferences(const Path & path, PathSet & references); - - void queryReferrers(const Path & path, PathSet & referrers); - - Path queryDeriver(const Path & path); - - PathSet queryValidDerivers(const Path & path); - - PathSet queryDerivationOutputs(const Path & path); - - StringSet queryDerivationOutputNames(const Path & path); - - Path queryPathFromHashPart(const string & hashPart); - - PathSet querySubstitutablePaths(const PathSet & paths); - - void querySubstitutablePathInfos(const PathSet & paths, - SubstitutablePathInfos & infos); - - Path addToStore(const string & name, const Path & srcPath, - bool recursive = true, HashType hashAlgo = htSHA256, - PathFilter & filter = defaultPathFilter, bool repair = false); - - Path addTextToStore(const string & name, const string & s, - const PathSet & references, bool repair = false); - - void exportPath(const Path & path, bool sign, - Sink & sink); - - Paths importPaths(bool requireSignature, Source & source); - - void buildPaths(const PathSet & paths, BuildMode buildMode); - - void ensurePath(const Path & path); - - void addTempRoot(const Path & path); - - void addIndirectRoot(const Path & path); - - void syncWithGC(); - - Roots findRoots(); - - void collectGarbage(const GCOptions & options, GCResults & results); - - PathSet queryFailedPaths(); - - void clearFailedPaths(const PathSet & paths); - - void optimiseStore(); - - bool verifyStore(bool checkContents, bool repair); -private: - AutoCloseFD fdSocket; - FdSink to; - FdSource from; - unsigned int daemonVersion; - bool initialised; - - void openConnection(bool reserveSpace = true); - - void processStderr(Sink * sink = 0, Source * source = 0); - - void connectToDaemon(); - - void setOptions(); -}; - - -} diff --git a/nix/libstore/store-api.cc b/nix/libstore/store-api.cc index 0238e5b0b6..30af5f5fed 100644 --- a/nix/libstore/store-api.cc +++ b/nix/libstore/store-api.cc @@ -304,13 +304,28 @@ void exportPaths(StoreAPI & store, const Paths & paths, writeInt(0, sink); } +Path readStorePath(Source & from) +{ + Path path = readString(from); + assertStorePath(path); + return path; +} + + +template<class T> T readStorePaths(Source & from) +{ + T paths = readStrings<T>(from); + foreach (typename T::iterator, i, paths) assertStorePath(*i); + return paths; +} + +template PathSet readStorePaths(Source & from); } #include "local-store.hh" #include "serialise.hh" -#include "remote-store.hh" namespace nix { @@ -321,10 +336,7 @@ std::shared_ptr<StoreAPI> store; std::shared_ptr<StoreAPI> openStore(bool reserveSpace) { - if (getEnv("NIX_REMOTE") == "") - return std::shared_ptr<StoreAPI>(new LocalStore(reserveSpace)); - else - return std::shared_ptr<StoreAPI>(new RemoteStore()); + return std::shared_ptr<StoreAPI>(new LocalStore(reserveSpace)); } diff --git a/nix/libstore/store-api.hh b/nix/libstore/store-api.hh index 9403cbee19..3e982f6dd3 100644 --- a/nix/libstore/store-api.hh +++ b/nix/libstore/store-api.hh @@ -106,6 +106,30 @@ typedef list<ValidPathInfo> ValidPathInfos; enum BuildMode { bmNormal, bmRepair, bmCheck }; +struct BuildResult +{ + enum Status { + Built = 0, + Substituted, + AlreadyValid, + PermanentFailure, + InputRejected, + OutputRejected, + TransientFailure, // possibly transient + CachedFailure, + TimedOut, + MiscFailure, + DependencyFailed, + LogLimitExceeded, + NotDeterministic, + } status = MiscFailure; + std::string errorMsg; + //time_t startTime = 0, stopTime = 0; + bool success() { + return status == Built || status == Substituted || status == AlreadyValid; + } +}; + class StoreAPI { diff --git a/nix/nix-daemon/guix-daemon.cc b/nix/nix-daemon/guix-daemon.cc index 1934487d24..20a0732fcb 100644 --- a/nix/nix-daemon/guix-daemon.cc +++ b/nix/nix-daemon/guix-daemon.cc @@ -80,6 +80,7 @@ builds derivations on behalf of its clients."); #define GUIX_OPT_NO_BUILD_HOOK 14 #define GUIX_OPT_GC_KEEP_OUTPUTS 15 #define GUIX_OPT_GC_KEEP_DERIVATIONS 16 +#define GUIX_OPT_BUILD_ROUNDS 17 static const struct argp_option options[] = { @@ -104,6 +105,8 @@ static const struct argp_option options[] = n_("do not use the 'build hook'") }, { "cache-failures", GUIX_OPT_CACHE_FAILURES, 0, 0, n_("cache build failures") }, + { "rounds", GUIX_OPT_BUILD_ROUNDS, "N", 0, + n_("build each derivation N times in a row") }, { "lose-logs", GUIX_OPT_LOSE_LOGS, 0, 0, n_("do not keep build logs") }, { "disable-log-compression", GUIX_OPT_DISABLE_LOG_COMPRESSION, 0, 0, @@ -189,6 +192,18 @@ parse_opt (int key, char *arg, struct argp_state *state) case GUIX_OPT_CACHE_FAILURES: settings.cacheFailure = true; break; + case GUIX_OPT_BUILD_ROUNDS: + { + char *end; + unsigned long n = strtoul (arg, &end, 10); + if (end != arg + strlen (arg)) + { + fprintf (stderr, _("error: %s: invalid number of rounds\n"), arg); + exit (EXIT_FAILURE); + } + settings.set ("build-repeat", std::to_string (std::max (0UL, n - 1))); + break; + } case GUIX_OPT_IMPERSONATE_LINUX_26: settings.impersonateLinux26 = true; break; |