Refactor settings processing

Put all Nix configuration flags in a Settings object.
This commit is contained in:
Eelco Dolstra 2012-07-30 19:55:41 -04:00
parent d50d7a2874
commit 97421eb5ec
19 changed files with 596 additions and 552 deletions

View file

@ -19,7 +19,7 @@ void doInit()
{ {
if (!store) { if (!store) {
try { try {
setDefaultsFromEnvironment(); settings.processEnvironment();
store = openStore(); store = openStore();
} catch (Error & e) { } catch (Error & e) {
croak(e.what()); croak(e.what());

View file

@ -179,7 +179,7 @@ EvalState::EvalState()
searchPathInsertionPoint = searchPath.end(); searchPathInsertionPoint = searchPath.end();
Strings paths = tokenizeString(getEnv("NIX_PATH", ""), ":"); Strings paths = tokenizeString(getEnv("NIX_PATH", ""), ":");
foreach (Strings::iterator, i, paths) addToSearchPath(*i); foreach (Strings::iterator, i, paths) addToSearchPath(*i);
addToSearchPath("nix=" + nixDataDir + "/nix/corepkgs"); addToSearchPath("nix=" + settings.nixDataDir + "/nix/corepkgs");
searchPathInsertionPoint = searchPath.begin(); searchPathInsertionPoint = searchPath.begin();
createBaseEnv(); createBaseEnv();
@ -1058,7 +1058,7 @@ string EvalState::coerceToString(Value & v, PathSet & context,
if (srcToStore[path] != "") if (srcToStore[path] != "")
dstPath = srcToStore[path]; dstPath = srcToStore[path];
else { else {
dstPath = readOnlyMode dstPath = settings.readOnlyMode
? computeStorePathForPath(path).first ? computeStorePathForPath(path).first
: store->addToStore(path); : store->addToStore(path);
srcToStore[path] = dstPath; srcToStore[path] = dstPath;

View file

@ -623,7 +623,7 @@ static void prim_toFile(EvalState & state, Value * * args, Value & v)
refs.insert(path); refs.insert(path);
} }
Path storePath = readOnlyMode Path storePath = settings.readOnlyMode
? computeStorePathForText(name, contents, refs) ? computeStorePathForText(name, contents, refs)
: store->addTextToStore(name, contents, refs); : store->addTextToStore(name, contents, refs);
@ -687,7 +687,7 @@ static void prim_filterSource(EvalState & state, Value * * args, Value & v)
FilterFromExpr filter(state, *args[0]); FilterFromExpr filter(state, *args[0]);
Path dstPath = readOnlyMode Path dstPath = settings.readOnlyMode
? computeStorePathForPath(path, true, htSHA256, filter).first ? computeStorePathForPath(path, true, htSHA256, filter).first
: store->addToStore(path, true, htSHA256, filter); : store->addToStore(path, true, htSHA256, filter);
@ -1079,7 +1079,7 @@ void EvalState::createBaseEnv()
mkInt(v, time(0)); mkInt(v, time(0));
addConstant("__currentTime", v); addConstant("__currentTime", v);
mkString(v, thisSystem.c_str()); mkString(v, settings.thisSystem.c_str());
addConstant("__currentSystem", v); addConstant("__currentSystem", v);
// Miscellaneous // Miscellaneous

View file

@ -74,7 +74,7 @@ void printMissing(StoreAPI & store, const PathSet & paths)
if (!unknown.empty()) { if (!unknown.empty()) {
printMsg(lvlInfo, format("don't know how to build these paths%1%:") printMsg(lvlInfo, format("don't know how to build these paths%1%:")
% (readOnlyMode ? " (may be caused by read-only store access)" : "")); % (settings.readOnlyMode ? " (may be caused by read-only store access)" : ""));
foreach (PathSet::iterator, i, unknown) foreach (PathSet::iterator, i, unknown)
printMsg(lvlInfo, format(" %1%") % *i); printMsg(lvlInfo, format(" %1%") % *i);
} }
@ -93,11 +93,20 @@ static void setLogType(string lt)
static bool showTrace = false; static bool showTrace = false;
string getArg(const string & opt,
Strings::iterator & i, const Strings::iterator & end)
{
++i;
if (i == end) throw UsageError(format("`%1%' requires an argument") % opt);
return *i;
}
/* Initialize and reorder arguments, then call the actual argument /* Initialize and reorder arguments, then call the actual argument
processor. */ processor. */
static void initAndRun(int argc, char * * argv) static void initAndRun(int argc, char * * argv)
{ {
setDefaultsFromEnvironment(); settings.processEnvironment();
settings.loadConfFile();
/* Catch SIGINT. */ /* Catch SIGINT. */
struct sigaction act; struct sigaction act;
@ -156,20 +165,19 @@ static void initAndRun(int argc, char * * argv)
remaining.clear(); remaining.clear();
/* Process default options. */ /* Process default options. */
int verbosityDelta = 0; int verbosityDelta = lvlInfo;
for (Strings::iterator i = args.begin(); i != args.end(); ++i) { for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
string arg = *i; string arg = *i;
if (arg == "--verbose" || arg == "-v") verbosityDelta++; if (arg == "--verbose" || arg == "-v") verbosityDelta++;
else if (arg == "--quiet") verbosityDelta--; else if (arg == "--quiet") verbosityDelta--;
else if (arg == "--log-type") { else if (arg == "--log-type") {
++i; string s = getArg(arg, i, args.end());
if (i == args.end()) throw UsageError("`--log-type' requires an argument"); setLogType(s);
setLogType(*i);
} }
else if (arg == "--no-build-output" || arg == "-Q") else if (arg == "--no-build-output" || arg == "-Q")
buildVerbosity = lvlVomit; settings.buildVerbosity = lvlVomit;
else if (arg == "--print-build-trace") else if (arg == "--print-build-trace")
printBuildTrace = true; settings.printBuildTrace = true;
else if (arg == "--help") { else if (arg == "--help") {
printHelp(); printHelp();
return; return;
@ -179,23 +187,23 @@ static void initAndRun(int argc, char * * argv)
return; return;
} }
else if (arg == "--keep-failed" || arg == "-K") else if (arg == "--keep-failed" || arg == "-K")
keepFailed = true; settings.keepFailed = true;
else if (arg == "--keep-going" || arg == "-k") else if (arg == "--keep-going" || arg == "-k")
keepGoing = true; settings.keepGoing = true;
else if (arg == "--fallback") else if (arg == "--fallback")
tryFallback = true; settings.tryFallback = true;
else if (arg == "--max-jobs" || arg == "-j") else if (arg == "--max-jobs" || arg == "-j")
maxBuildJobs = getIntArg<unsigned int>(arg, i, args.end()); settings.set("build-max-jobs", getArg(arg, i, args.end()));
else if (arg == "--cores") else if (arg == "--cores")
buildCores = getIntArg<unsigned int>(arg, i, args.end()); settings.set("build-cores", getArg(arg, i, args.end()));
else if (arg == "--readonly-mode") else if (arg == "--readonly-mode")
readOnlyMode = true; settings.readOnlyMode = true;
else if (arg == "--max-silent-time") else if (arg == "--max-silent-time")
maxSilentTime = getIntArg<unsigned int>(arg, i, args.end()); settings.set("build-max-silent-time", getArg(arg, i, args.end()));
else if (arg == "--timeout") else if (arg == "--timeout")
buildTimeout = getIntArg<unsigned int>(arg, i, args.end()); settings.set("build-timeout", getArg(arg, i, args.end()));
else if (arg == "--no-build-hook") else if (arg == "--no-build-hook")
useBuildHook = false; settings.useBuildHook = false;
else if (arg == "--show-trace") else if (arg == "--show-trace")
showTrace = true; showTrace = true;
else if (arg == "--option") { else if (arg == "--option") {
@ -203,14 +211,15 @@ static void initAndRun(int argc, char * * argv)
string name = *i; string name = *i;
++i; if (i == args.end()) throw UsageError("`--option' requires two arguments"); ++i; if (i == args.end()) throw UsageError("`--option' requires two arguments");
string value = *i; string value = *i;
overrideSetting(name, tokenizeString(value)); settings.set(name, value);
} }
else remaining.push_back(arg); else remaining.push_back(arg);
} }
verbosityDelta += queryIntSetting("verbosity", lvlInfo);
verbosity = (Verbosity) (verbosityDelta < 0 ? 0 : verbosityDelta); verbosity = (Verbosity) (verbosityDelta < 0 ? 0 : verbosityDelta);
settings.update();
run(remaining); run(remaining);
/* Close the Nix database. */ /* Close the Nix database. */

View file

@ -229,8 +229,6 @@ private:
public: public:
bool cacheFailure;
/* Set if at least one derivation had a BuildError (i.e. permanent /* Set if at least one derivation had a BuildError (i.e. permanent
failure). */ failure). */
bool permanentFailure; bool permanentFailure;
@ -314,7 +312,7 @@ void Goal::waiteeDone(GoalPtr waitee, ExitCode result)
if (result == ecNoSubstituters) ++nrNoSubstituters; if (result == ecNoSubstituters) ++nrNoSubstituters;
if (waitees.empty() || (result == ecFailed && !keepGoing)) { if (waitees.empty() || (result == ecFailed && !settings.keepGoing)) {
/* If we failed and keepGoing is not set, we remove all /* If we failed and keepGoing is not set, we remove all
remaining waitees. */ remaining waitees. */
@ -466,14 +464,13 @@ void UserLock::acquire()
{ {
assert(uid == 0); assert(uid == 0);
string buildUsersGroup = querySetting("build-users-group", ""); assert(settings.buildUsersGroup != "");
assert(buildUsersGroup != "");
/* Get the members of the build-users-group. */ /* Get the members of the build-users-group. */
struct group * gr = getgrnam(buildUsersGroup.c_str()); struct group * gr = getgrnam(settings.buildUsersGroup.c_str());
if (!gr) if (!gr)
throw Error(format("the group `%1%' specified in `build-users-group' does not exist") throw Error(format("the group `%1%' specified in `build-users-group' does not exist")
% buildUsersGroup); % settings.buildUsersGroup);
gid = gr->gr_gid; gid = gr->gr_gid;
/* Copy the result of getgrnam. */ /* Copy the result of getgrnam. */
@ -485,7 +482,7 @@ void UserLock::acquire()
if (users.empty()) if (users.empty())
throw Error(format("the build users group `%1%' has no members") throw Error(format("the build users group `%1%' has no members")
% buildUsersGroup); % settings.buildUsersGroup);
/* Find a user account that isn't currently in use for another /* Find a user account that isn't currently in use for another
build. */ build. */
@ -495,11 +492,11 @@ void UserLock::acquire()
struct passwd * pw = getpwnam(i->c_str()); struct passwd * pw = getpwnam(i->c_str());
if (!pw) if (!pw)
throw Error(format("the user `%1%' in the group `%2%' does not exist") throw Error(format("the user `%1%' in the group `%2%' does not exist")
% *i % buildUsersGroup); % *i % settings.buildUsersGroup);
createDirs(nixStateDir + "/userpool"); createDirs(settings.nixStateDir + "/userpool");
fnUserLock = (format("%1%/userpool/%2%") % nixStateDir % pw->pw_uid).str(); fnUserLock = (format("%1%/userpool/%2%") % settings.nixStateDir % pw->pw_uid).str();
if (lockedPaths.find(fnUserLock) != lockedPaths.end()) if (lockedPaths.find(fnUserLock) != lockedPaths.end())
/* We already have a lock on this one. */ /* We already have a lock on this one. */
@ -519,7 +516,7 @@ void UserLock::acquire()
/* Sanity check... */ /* Sanity check... */
if (uid == getuid() || uid == geteuid()) if (uid == getuid() || uid == geteuid())
throw Error(format("the Nix user should not be a member of `%1%'") throw Error(format("the Nix user should not be a member of `%1%'")
% buildUsersGroup); % settings.buildUsersGroup);
return; return;
} }
@ -527,7 +524,7 @@ void UserLock::acquire()
throw Error(format("all build users are currently in use; " throw Error(format("all build users are currently in use; "
"consider creating additional users and adding them to the `%1%' group") "consider creating additional users and adding them to the `%1%' group")
% buildUsersGroup); % settings.buildUsersGroup);
} }
@ -546,7 +543,7 @@ static void runSetuidHelper(const string & command,
const string & arg) const string & arg)
{ {
Path program = getEnv("NIX_SETUID_HELPER", Path program = getEnv("NIX_SETUID_HELPER",
nixLibexecDir + "/nix-setuid-helper"); settings.nixLibexecDir + "/nix-setuid-helper");
/* Fork. */ /* Fork. */
Pid pid; Pid pid;
@ -601,12 +598,6 @@ bool amPrivileged()
} }
bool haveBuildUsers()
{
return querySetting("build-users-group", "") != "";
}
void getOwnership(const Path & path) void getOwnership(const Path & path)
{ {
runSetuidHelper("get-ownership", path); runSetuidHelper("get-ownership", path);
@ -622,7 +613,7 @@ void deletePathWrapped(const Path & path,
} catch (SysError & e) { } catch (SysError & e) {
/* If this failed due to a permission error, then try it with /* If this failed due to a permission error, then try it with
the setuid helper. */ the setuid helper. */
if (haveBuildUsers() && !amPrivileged()) { if (settings.buildUsersGroup != "" && !amPrivileged()) {
getOwnership(path); getOwnership(path);
deletePath(path, bytesFreed, blocksFreed); deletePath(path, bytesFreed, blocksFreed);
} else } else
@ -701,9 +692,9 @@ HookInstance::HookInstance()
throw SysError("dupping builder's stdout/stderr"); throw SysError("dupping builder's stdout/stderr");
/* XXX: Pass `buildTimeout' to the hook? */ /* XXX: Pass `buildTimeout' to the hook? */
execl(buildHook.c_str(), buildHook.c_str(), thisSystem.c_str(), execl(buildHook.c_str(), buildHook.c_str(), settings.thisSystem.c_str(),
(format("%1%") % maxSilentTime).str().c_str(), (format("%1%") % settings.maxSilentTime).str().c_str(),
(format("%1%") % printBuildTrace).str().c_str(), (format("%1%") % settings.printBuildTrace).str().c_str(),
NULL); NULL);
throw SysError(format("executing `%1%'") % buildHook); throw SysError(format("executing `%1%'") % buildHook);
@ -943,7 +934,7 @@ void DerivationGoal::init()
{ {
trace("init"); trace("init");
if (readOnlyMode) if (settings.readOnlyMode)
throw Error(format("cannot build derivation `%1%' - no write access to the Nix store") % drvPath); throw Error(format("cannot build derivation `%1%' - no write access to the Nix store") % drvPath);
/* The first thing to do is to make sure that the derivation /* The first thing to do is to make sure that the derivation
@ -995,7 +986,7 @@ void DerivationGoal::haveDerivation()
/* We are first going to try to create the invalid output paths /* We are first going to try to create the invalid output paths
through substitutes. If that doesn't work, we'll build through substitutes. If that doesn't work, we'll build
them. */ them. */
if (queryBoolSetting("build-use-substitutes", true)) if (settings.useSubstitutes)
foreach (PathSet::iterator, i, invalidOutputs) foreach (PathSet::iterator, i, invalidOutputs)
addWaitee(worker.makeSubstitutionGoal(*i)); addWaitee(worker.makeSubstitutionGoal(*i));
@ -1010,7 +1001,7 @@ void DerivationGoal::outputsSubstituted()
{ {
trace("all outputs substituted (maybe)"); trace("all outputs substituted (maybe)");
if (nrFailed > 0 && nrFailed > nrNoSubstituters && !tryFallback) if (nrFailed > 0 && nrFailed > nrNoSubstituters && !settings.tryFallback)
throw Error(format("some substitutes for the outputs of derivation `%1%' failed; try `--fallback'") % drvPath); throw Error(format("some substitutes for the outputs of derivation `%1%' failed; try `--fallback'") % drvPath);
nrFailed = nrNoSubstituters = 0; nrFailed = nrNoSubstituters = 0;
@ -1109,9 +1100,9 @@ PathSet outputPaths(const DerivationOutputs & outputs)
static bool canBuildLocally(const string & platform) static bool canBuildLocally(const string & platform)
{ {
return platform == thisSystem return platform == settings.thisSystem
#ifdef CAN_DO_LINUX32_BUILDS #ifdef CAN_DO_LINUX32_BUILDS
|| (platform == "i686-linux" && thisSystem == "x86_64-linux") || (platform == "i686-linux" && settings.thisSystem == "x86_64-linux")
#endif #endif
; ;
} }
@ -1213,7 +1204,7 @@ void DerivationGoal::tryToBuild()
derivation prefers to be done locally, do it even if derivation prefers to be done locally, do it even if
maxBuildJobs is 0. */ maxBuildJobs is 0. */
unsigned int curBuilds = worker.getNrLocalBuilds(); unsigned int curBuilds = worker.getNrLocalBuilds();
if (curBuilds >= maxBuildJobs && !(preferLocalBuild && curBuilds == 0)) { if (curBuilds >= settings.maxBuildJobs && !(preferLocalBuild && curBuilds == 0)) {
worker.waitForBuildSlot(shared_from_this()); worker.waitForBuildSlot(shared_from_this());
outputLocks.unlock(); outputLocks.unlock();
return; return;
@ -1228,7 +1219,7 @@ void DerivationGoal::tryToBuild()
printMsg(lvlError, e.msg()); printMsg(lvlError, e.msg());
outputLocks.unlock(); outputLocks.unlock();
buildUser.release(); buildUser.release();
if (printBuildTrace) if (settings.printBuildTrace)
printMsg(lvlError, format("@ build-failed %1% %2% %3% %4%") printMsg(lvlError, format("@ build-failed %1% %2% %3% %4%")
% drvPath % drv.outputs["out"].path % 0 % e.msg()); % drvPath % drv.outputs["out"].path % 0 % e.msg());
worker.permanentFailure = true; worker.permanentFailure = true;
@ -1360,7 +1351,7 @@ void DerivationGoal::buildDone()
bool hookError = hook && bool hookError = hook &&
(!WIFEXITED(status) || WEXITSTATUS(status) != 100); (!WIFEXITED(status) || WEXITSTATUS(status) != 100);
if (printBuildTrace) { if (settings.printBuildTrace) {
if (hook && hookError) if (hook && hookError)
printMsg(lvlError, format("@ hook-failed %1% %2% %3% %4%") printMsg(lvlError, format("@ hook-failed %1% %2% %3% %4%")
% drvPath % drv.outputs["out"].path % status % e.msg()); % drvPath % drv.outputs["out"].path % status % e.msg());
@ -1376,7 +1367,7 @@ void DerivationGoal::buildDone()
able to access the network). Hook errors (like able to access the network). Hook errors (like
communication problems with the remote machine) shouldn't communication problems with the remote machine) shouldn't
be cached either. */ be cached either. */
if (worker.cacheFailure && !hookError && !fixedOutput) if (settings.cacheFailure && !hookError && !fixedOutput)
foreach (DerivationOutputs::iterator, i, drv.outputs) foreach (DerivationOutputs::iterator, i, drv.outputs)
worker.store.registerFailedPath(i->second.path); worker.store.registerFailedPath(i->second.path);
@ -1388,7 +1379,7 @@ void DerivationGoal::buildDone()
/* Release the build user, if applicable. */ /* Release the build user, if applicable. */
buildUser.release(); buildUser.release();
if (printBuildTrace) { if (settings.printBuildTrace) {
printMsg(lvlError, format("@ build-succeeded %1% %2%") printMsg(lvlError, format("@ build-succeeded %1% %2%")
% drvPath % drv.outputs["out"].path); % drvPath % drv.outputs["out"].path);
} }
@ -1399,7 +1390,7 @@ void DerivationGoal::buildDone()
HookReply DerivationGoal::tryBuildHook() HookReply DerivationGoal::tryBuildHook()
{ {
if (!useBuildHook || getEnv("NIX_BUILD_HOOK") == "") return rpDecline; if (!settings.useBuildHook || getEnv("NIX_BUILD_HOOK") == "") return rpDecline;
if (!worker.hook) if (!worker.hook)
worker.hook = boost::shared_ptr<HookInstance>(new HookInstance); worker.hook = boost::shared_ptr<HookInstance>(new HookInstance);
@ -1412,7 +1403,7 @@ HookReply DerivationGoal::tryBuildHook()
/* Send the request to the hook. */ /* Send the request to the hook. */
writeLine(worker.hook->toHook.writeSide, (format("%1% %2% %3% %4%") writeLine(worker.hook->toHook.writeSide, (format("%1% %2% %3% %4%")
% (worker.getNrLocalBuilds() < maxBuildJobs ? "1" : "0") % (worker.getNrLocalBuilds() < settings.maxBuildJobs ? "1" : "0")
% drv.platform % drvPath % concatStringsSep(",", features)).str()); % drv.platform % drvPath % concatStringsSep(",", features)).str());
/* Read the first line of input, which should be a word indicating /* Read the first line of input, which should be a word indicating
@ -1471,7 +1462,7 @@ HookReply DerivationGoal::tryBuildHook()
fds.insert(hook->builderOut.readSide); fds.insert(hook->builderOut.readSide);
worker.childStarted(shared_from_this(), hook->pid, fds, false, false); worker.childStarted(shared_from_this(), hook->pid, fds, false, false);
if (printBuildTrace) if (settings.printBuildTrace)
printMsg(lvlError, format("@ build-started %1% %2% %3% %4%") printMsg(lvlError, format("@ build-started %1% %2% %3% %4%")
% drvPath % drv.outputs["out"].path % drv.platform % logFile); % drvPath % drv.outputs["out"].path % drv.platform % logFile);
@ -1502,7 +1493,7 @@ void DerivationGoal::startBuilder()
if (!canBuildLocally(drv.platform)) if (!canBuildLocally(drv.platform))
throw Error( throw Error(
format("a `%1%' is required to build `%3%', but I am a `%2%'") format("a `%1%' is required to build `%3%', but I am a `%2%'")
% drv.platform % thisSystem % drvPath); % drv.platform % settings.thisSystem % drvPath);
/* Construct the environment passed to the builder. */ /* Construct the environment passed to the builder. */
@ -1523,10 +1514,10 @@ void DerivationGoal::startBuilder()
shouldn't care, but this is useful for purity checking (e.g., shouldn't care, but this is useful for purity checking (e.g.,
the compiler or linker might only want to accept paths to files the compiler or linker might only want to accept paths to files
in the store or in the build directory). */ in the store or in the build directory). */
env["NIX_STORE"] = nixStore; env["NIX_STORE"] = settings.nixStore;
/* The maximum number of cores to utilize for parallel building. */ /* The maximum number of cores to utilize for parallel building. */
env["NIX_BUILD_CORES"] = (format("%d") % buildCores).str(); env["NIX_BUILD_CORES"] = (format("%d") % settings.buildCores).str();
/* Add all bindings specified in the derivation. */ /* Add all bindings specified in the derivation. */
foreach (StringPairs::iterator, i, drv.env) foreach (StringPairs::iterator, i, drv.env)
@ -1618,7 +1609,7 @@ void DerivationGoal::startBuilder()
/* If `build-users-group' is not empty, then we have to build as /* If `build-users-group' is not empty, then we have to build as
one of the members of that group. */ one of the members of that group. */
if (haveBuildUsers()) { if (settings.buildUsersGroup != "") {
buildUser.acquire(); buildUser.acquire();
assert(buildUser.getUID() != 0); assert(buildUser.getUID() != 0);
assert(buildUser.getGID() != 0); assert(buildUser.getGID() != 0);
@ -1640,15 +1631,15 @@ void DerivationGoal::startBuilder()
the builder can create its output but not mess with the the builder can create its output but not mess with the
outputs of other processes). */ outputs of other processes). */
struct stat st; struct stat st;
if (stat(nixStore.c_str(), &st) == -1) if (stat(settings.nixStore.c_str(), &st) == -1)
throw SysError(format("cannot stat `%1%'") % nixStore); throw SysError(format("cannot stat `%1%'") % settings.nixStore);
if (!(st.st_mode & S_ISVTX) || if (!(st.st_mode & S_ISVTX) ||
((st.st_mode & S_IRWXG) != S_IRWXG) || ((st.st_mode & S_IRWXG) != S_IRWXG) ||
(st.st_gid != buildUser.getGID())) (st.st_gid != buildUser.getGID()))
throw Error(format( throw Error(format(
"builder does not have write permission to `%2%'; " "builder does not have write permission to `%2%'; "
"try `chgrp %1% %2%; chmod 1775 %2%'") "try `chgrp %1% %2%; chmod 1775 %2%'")
% buildUser.getGID() % nixStore); % buildUser.getGID() % settings.nixStore);
} }
@ -1657,7 +1648,7 @@ void DerivationGoal::startBuilder()
functions like fetchurl (which needs a proper /etc/resolv.conf) functions like fetchurl (which needs a proper /etc/resolv.conf)
work properly. Purity checking for fixed-output derivations work properly. Purity checking for fixed-output derivations
is somewhat pointless anyway. */ is somewhat pointless anyway. */
useChroot = queryBoolSetting("build-use-chroot", false); useChroot = settings.useChroot;
if (fixedOutput) useChroot = false; if (fixedOutput) useChroot = false;
@ -1707,16 +1698,8 @@ void DerivationGoal::startBuilder()
writeFile(chrootRootDir + "/etc/hosts", "127.0.0.1 localhost\n"); writeFile(chrootRootDir + "/etc/hosts", "127.0.0.1 localhost\n");
/* Bind-mount a user-configurable set of directories from the /* Bind-mount a user-configurable set of directories from the
host file system. The `/dev/pts' directory must be mounted host file system. */
separately so that newly-created pseudo-terminals show dirsInChroot = settings.dirsInChroot;
up. */
Paths defaultDirs;
defaultDirs.push_back("/dev");
defaultDirs.push_back("/dev/pts");
Paths dirsInChroot_ = querySetting("build-chroot-dirs", defaultDirs);
dirsInChroot.insert(dirsInChroot_.begin(), dirsInChroot_.end());
dirsInChroot.insert(tmpDir); dirsInChroot.insert(tmpDir);
/* Make the closure of the inputs available in the chroot, /* Make the closure of the inputs available in the chroot,
@ -1726,8 +1709,8 @@ void DerivationGoal::startBuilder()
can be bind-mounted). !!! As an extra security can be bind-mounted). !!! As an extra security
precaution, make the fake Nix store only writable by the precaution, make the fake Nix store only writable by the
build user. */ build user. */
createDirs(chrootRootDir + nixStore); createDirs(chrootRootDir + settings.nixStore);
chmod(chrootRootDir + nixStore, 01777); chmod(chrootRootDir + settings.nixStore, 01777);
foreach (PathSet::iterator, i, inputPaths) { foreach (PathSet::iterator, i, inputPaths) {
struct stat st; struct stat st;
@ -1827,7 +1810,7 @@ void DerivationGoal::startBuilder()
worker.childStarted(shared_from_this(), pid, worker.childStarted(shared_from_this(), pid,
singleton<set<int> >(builderOut.readSide), true, true); singleton<set<int> >(builderOut.readSide), true, true);
if (printBuildTrace) { if (settings.printBuildTrace) {
printMsg(lvlError, format("@ build-started %1% %2% %3% %4%") printMsg(lvlError, format("@ build-started %1% %2% %3% %4%")
% drvPath % drv.outputs["out"].path % drv.platform % logFile); % drvPath % drv.outputs["out"].path % drv.platform % logFile);
} }
@ -1907,16 +1890,14 @@ void DerivationGoal::initChild()
#ifdef CAN_DO_LINUX32_BUILDS #ifdef CAN_DO_LINUX32_BUILDS
/* Change the personality to 32-bit if we're doing an /* Change the personality to 32-bit if we're doing an
i686-linux build on an x86_64-linux machine. */ i686-linux build on an x86_64-linux machine. */
if (drv.platform == "i686-linux" && thisSystem == "x86_64-linux") { if (drv.platform == "i686-linux" && settings.thisSystem == "x86_64-linux") {
if (personality(0x0008 | 0x8000000 /* == PER_LINUX32_3GB */) == -1) if (personality(0x0008 | 0x8000000 /* == PER_LINUX32_3GB */) == -1)
throw SysError("cannot set i686-linux personality"); throw SysError("cannot set i686-linux personality");
} }
/* Impersonate a Linux 2.6 machine to get some determinism in /* Impersonate a Linux 2.6 machine to get some determinism in
builds that depend on the kernel version. */ builds that depend on the kernel version. */
if ((drv.platform == "i686-linux" || drv.platform == "x86_64-linux") && if ((drv.platform == "i686-linux" || drv.platform == "x86_64-linux") && settings.impersonateLinux26) {
queryBoolSetting("build-impersonate-linux-26", true))
{
int cur = personality(0xffffffff); int cur = personality(0xffffffff);
if (cur != -1) personality(cur | 0x0020000 /* == UNAME26 */); if (cur != -1) personality(cur | 0x0020000 /* == UNAME26 */);
} }
@ -1958,7 +1939,7 @@ void DerivationGoal::initChild()
} else { } else {
/* Let the setuid helper take care of it. */ /* Let the setuid helper take care of it. */
program = nixLibexecDir + "/nix-setuid-helper"; program = settings.nixLibexecDir + "/nix-setuid-helper";
args.push_back(program.c_str()); args.push_back(program.c_str());
args.push_back("run-builder"); args.push_back("run-builder");
user = buildUser.getUser().c_str(); user = buildUser.getUser().c_str();
@ -2126,13 +2107,13 @@ string drvsLogDir = "drvs";
Path DerivationGoal::openLogFile() Path DerivationGoal::openLogFile()
{ {
if (!queryBoolSetting("build-keep-log", true)) return ""; if (!settings.keepLog) return "";
/* Create a log file. */ /* Create a log file. */
Path dir = (format("%1%/%2%") % nixLogDir % drvsLogDir).str(); Path dir = (format("%1%/%2%") % settings.nixLogDir % drvsLogDir).str();
createDirs(dir); createDirs(dir);
if (queryBoolSetting("build-compress-log", true)) { if (settings.compressLog) {
Path logFileName = (format("%1%/%2%.bz2") % dir % baseNameOf(drvPath)).str(); Path logFileName = (format("%1%/%2%.bz2") % dir % baseNameOf(drvPath)).str();
AutoCloseFD fd = open(logFileName.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0666); AutoCloseFD fd = open(logFileName.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0666);
@ -2179,7 +2160,7 @@ void DerivationGoal::closeLogFile()
void DerivationGoal::deleteTmpDir(bool force) void DerivationGoal::deleteTmpDir(bool force)
{ {
if (tmpDir != "") { if (tmpDir != "") {
if (keepFailed && !force) { if (settings.keepFailed && !force) {
printMsg(lvlError, printMsg(lvlError,
format("builder for `%1%' failed; keeping build directory `%2%'") format("builder for `%1%' failed; keeping build directory `%2%'")
% drvPath % tmpDir); % drvPath % tmpDir);
@ -2199,7 +2180,7 @@ void DerivationGoal::handleChildOutput(int fd, const string & data)
if ((hook && fd == hook->builderOut.readSide) || if ((hook && fd == hook->builderOut.readSide) ||
(!hook && fd == builderOut.readSide)) (!hook && fd == builderOut.readSide))
{ {
if (verbosity >= buildVerbosity) if (verbosity >= settings.buildVerbosity)
writeToStderr((unsigned char *) data.data(), data.size()); writeToStderr((unsigned char *) data.data(), data.size());
if (bzLogFile) { if (bzLogFile) {
int err; int err;
@ -2235,13 +2216,13 @@ PathSet DerivationGoal::checkPathValidity(bool returnValid)
bool DerivationGoal::pathFailed(const Path & path) bool DerivationGoal::pathFailed(const Path & path)
{ {
if (!worker.cacheFailure) return false; if (!settings.cacheFailure) return false;
if (!worker.store.hasPathFailed(path)) return false; if (!worker.store.hasPathFailed(path)) return false;
printMsg(lvlError, format("builder for `%1%' failed previously (cached)") % path); printMsg(lvlError, format("builder for `%1%' failed previously (cached)") % path);
if (printBuildTrace) if (settings.printBuildTrace)
printMsg(lvlError, format("@ build-failed %1% %2% cached") % drvPath % path); printMsg(lvlError, format("@ build-failed %1% %2% cached") % drvPath % path);
worker.permanentFailure = true; worker.permanentFailure = true;
@ -2362,10 +2343,10 @@ void SubstitutionGoal::init()
return; return;
} }
if (readOnlyMode) if (settings.readOnlyMode)
throw Error(format("cannot substitute path `%1%' - no write access to the Nix store") % storePath); throw Error(format("cannot substitute path `%1%' - no write access to the Nix store") % storePath);
subs = substituters; subs = settings.substituters;
tryNext(); tryNext();
} }
@ -2437,7 +2418,7 @@ void SubstitutionGoal::tryToRun()
is maxBuildJobs == 0 (no local builds allowed), we still allow is maxBuildJobs == 0 (no local builds allowed), we still allow
a substituter to run. This is because substitutions cannot be a substituter to run. This is because substitutions cannot be
distributed to another machine via the build hook. */ distributed to another machine via the build hook. */
if (worker.getNrLocalBuilds() >= (maxBuildJobs == 0 ? 1 : maxBuildJobs)) { if (worker.getNrLocalBuilds() >= (settings.maxBuildJobs == 0 ? 1 : settings.maxBuildJobs)) {
worker.waitForBuildSlot(shared_from_this()); worker.waitForBuildSlot(shared_from_this());
return; return;
} }
@ -2496,7 +2477,7 @@ void SubstitutionGoal::tryToRun()
/* Pass configuration options (including those overriden /* Pass configuration options (including those overriden
with --option) to the substituter. */ with --option) to the substituter. */
setenv("_NIX_OPTIONS", packSettings().c_str(), 1); setenv("_NIX_OPTIONS", settings.pack().c_str(), 1);
/* Fill in the arguments. */ /* Fill in the arguments. */
Strings args; Strings args;
@ -2525,7 +2506,7 @@ void SubstitutionGoal::tryToRun()
state = &SubstitutionGoal::finished; state = &SubstitutionGoal::finished;
if (printBuildTrace) { if (settings.printBuildTrace) {
printMsg(lvlError, format("@ substituter-started %1% %2%") printMsg(lvlError, format("@ substituter-started %1% %2%")
% storePath % sub); % storePath % sub);
} }
@ -2583,7 +2564,7 @@ void SubstitutionGoal::finished()
printMsg(lvlInfo, e.msg()); printMsg(lvlInfo, e.msg());
if (printBuildTrace) { if (settings.printBuildTrace) {
printMsg(lvlError, format("@ substituter-failed %1% %2% %3%") printMsg(lvlError, format("@ substituter-failed %1% %2% %3%")
% storePath % status % e.msg()); % storePath % status % e.msg());
} }
@ -2611,7 +2592,7 @@ void SubstitutionGoal::finished()
printMsg(lvlChatty, printMsg(lvlChatty,
format("substitution of path `%1%' succeeded") % storePath); format("substitution of path `%1%' succeeded") % storePath);
if (printBuildTrace) { if (settings.printBuildTrace) {
printMsg(lvlError, format("@ substituter-succeeded %1%") % storePath); printMsg(lvlError, format("@ substituter-succeeded %1%") % storePath);
} }
@ -2622,7 +2603,7 @@ void SubstitutionGoal::finished()
void SubstitutionGoal::handleChildOutput(int fd, const string & data) void SubstitutionGoal::handleChildOutput(int fd, const string & data)
{ {
assert(fd == logPipe.readSide); assert(fd == logPipe.readSide);
if (verbosity >= buildVerbosity) if (verbosity >= settings.buildVerbosity)
writeToStderr((unsigned char *) data.data(), data.size()); writeToStderr((unsigned char *) data.data(), data.size());
/* Don't write substitution output to a log file for now. We /* Don't write substitution output to a log file for now. We
probably should, though. */ probably should, though. */
@ -2650,7 +2631,6 @@ Worker::Worker(LocalStore & store)
working = true; working = true;
nrLocalBuilds = 0; nrLocalBuilds = 0;
lastWokenUp = 0; lastWokenUp = 0;
cacheFailure = queryBoolSetting("build-cache-failure", false);
permanentFailure = false; permanentFailure = false;
} }
@ -2715,7 +2695,7 @@ void Worker::removeGoal(GoalPtr goal)
topGoals.erase(goal); topGoals.erase(goal);
/* If a top-level goal failed, then kill all other goals /* If a top-level goal failed, then kill all other goals
(unless keepGoing was set). */ (unless keepGoing was set). */
if (goal->getExitCode() == Goal::ecFailed && !keepGoing) if (goal->getExitCode() == Goal::ecFailed && !settings.keepGoing)
topGoals.clear(); topGoals.clear();
} }
@ -2787,7 +2767,7 @@ void Worker::childTerminated(pid_t pid, bool wakeSleepers)
void Worker::waitForBuildSlot(GoalPtr goal) void Worker::waitForBuildSlot(GoalPtr goal)
{ {
debug("wait for build slot"); debug("wait for build slot");
if (getNrLocalBuilds() < maxBuildJobs) if (getNrLocalBuilds() < settings.maxBuildJobs)
wakeUp(goal); /* we can do it right away */ wakeUp(goal); /* we can do it right away */
else else
wantingToBuild.insert(goal); wantingToBuild.insert(goal);
@ -2836,7 +2816,7 @@ void Worker::run(const Goals & _topGoals)
if (!children.empty() || !waitingForAWhile.empty()) if (!children.empty() || !waitingForAWhile.empty())
waitForInput(); waitForInput();
else { else {
if (awake.empty() && maxBuildJobs == 0) throw Error( if (awake.empty() && settings.maxBuildJobs == 0) 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 distributed builds");
assert(!awake.empty()); assert(!awake.empty());
@ -2846,9 +2826,9 @@ void Worker::run(const Goals & _topGoals)
/* If --keep-going is not set, it's possible that the main goal /* If --keep-going is not set, it's possible that the main goal
exited while some of its subgoals were still active. But if exited while some of its subgoals were still active. But if
--keep-going *is* set, then they must all be finished now. */ --keep-going *is* set, then they must all be finished now. */
assert(!keepGoing || awake.empty()); assert(!settings.keepGoing || awake.empty());
assert(!keepGoing || wantingToBuild.empty()); assert(!settings.keepGoing || wantingToBuild.empty());
assert(!keepGoing || children.empty()); assert(!settings.keepGoing || children.empty());
} }
@ -2868,15 +2848,15 @@ void Worker::waitForInput()
time_t before = time(0); time_t before = time(0);
/* If a global timeout has been set, sleep until it's done. */ /* If a global timeout has been set, sleep until it's done. */
if (buildTimeout != 0) { if (settings.buildTimeout != 0) {
useTimeout = true; useTimeout = true;
if (lastWait == 0 || lastWait > before) lastWait = before; if (lastWait == 0 || lastWait > before) lastWait = before;
timeout.tv_sec = std::max((time_t) 0, lastWait + buildTimeout - before); timeout.tv_sec = std::max((time_t) 0, lastWait + settings.buildTimeout - before);
} }
/* If we're monitoring for silence on stdout/stderr, sleep until /* If we're monitoring for silence on stdout/stderr, sleep until
the first deadline for any child. */ the first deadline for any child. */
if (maxSilentTime != 0) { if (settings.maxSilentTime != 0) {
time_t oldest = 0; time_t oldest = 0;
foreach (Children::iterator, i, children) { foreach (Children::iterator, i, children) {
if (i->second.monitorForSilence) { if (i->second.monitorForSilence) {
@ -2885,7 +2865,7 @@ void Worker::waitForInput()
} }
} }
if (oldest) { if (oldest) {
time_t silenceTimeout = std::max((time_t) 0, oldest + maxSilentTime - before); time_t silenceTimeout = std::max((time_t) 0, oldest + settings.maxSilentTime - before);
timeout.tv_sec = useTimeout timeout.tv_sec = useTimeout
? std::min(silenceTimeout, timeout.tv_sec) ? std::min(silenceTimeout, timeout.tv_sec)
: silenceTimeout; : silenceTimeout;
@ -2896,14 +2876,12 @@ void Worker::waitForInput()
/* If we are polling goals that are waiting for a lock, then wake /* If we are polling goals that are waiting for a lock, then wake
up after a few seconds at most. */ up after a few seconds at most. */
int wakeUpInterval = queryIntSetting("build-poll-interval", 5);
if (!waitingForAWhile.empty()) { if (!waitingForAWhile.empty()) {
useTimeout = true; useTimeout = true;
if (lastWokenUp == 0) if (lastWokenUp == 0)
printMsg(lvlError, "waiting for locks or build slots..."); printMsg(lvlError, "waiting for locks or build slots...");
if (lastWokenUp == 0 || lastWokenUp > before) lastWokenUp = before; if (lastWokenUp == 0 || lastWokenUp > before) lastWokenUp = before;
timeout.tv_sec = std::max((time_t) 0, lastWokenUp + wakeUpInterval - before); timeout.tv_sec = std::max((time_t) 0, lastWokenUp + settings.pollInterval - before);
} else lastWokenUp = 0; } else lastWokenUp = 0;
using namespace std; using namespace std;
@ -2969,27 +2947,27 @@ void Worker::waitForInput()
} }
} }
if (maxSilentTime != 0 && if (settings.maxSilentTime != 0 &&
j->second.monitorForSilence && j->second.monitorForSilence &&
after - j->second.lastOutput >= (time_t) maxSilentTime) after - j->second.lastOutput >= (time_t) settings.maxSilentTime)
{ {
printMsg(lvlError, printMsg(lvlError,
format("%1% timed out after %2% seconds of silence") format("%1% timed out after %2% seconds of silence")
% goal->getName() % maxSilentTime); % goal->getName() % settings.maxSilentTime);
goal->cancel(); goal->cancel();
} }
if (buildTimeout != 0 && if (settings.buildTimeout != 0 &&
after - before >= (time_t) buildTimeout) after - before >= (time_t) settings.buildTimeout)
{ {
printMsg(lvlError, printMsg(lvlError,
format("%1% timed out after %2% seconds of activity") format("%1% timed out after %2% seconds of activity")
% goal->getName() % buildTimeout); % goal->getName() % settings.buildTimeout);
goal->cancel(); goal->cancel();
} }
} }
if (!waitingForAWhile.empty() && lastWokenUp + wakeUpInterval <= after) { if (!waitingForAWhile.empty() && lastWokenUp + settings.pollInterval <= after) {
lastWokenUp = after; lastWokenUp = after;
foreach (WeakGoals::iterator, i, waitingForAWhile) { foreach (WeakGoals::iterator, i, waitingForAWhile) {
GoalPtr goal = i->lock(); GoalPtr goal = i->lock();

View file

@ -12,7 +12,7 @@ void DerivationOutput::parseHashInfo(bool & recursive, HashType & hashType, Hash
{ {
recursive = false; recursive = false;
string algo = hashAlgo; string algo = hashAlgo;
if (string(algo, 0, 2) == "r:") { if (string(algo, 0, 2) == "r:") {
recursive = true; recursive = true;
algo = string(algo, 2); algo = string(algo, 2);
@ -21,7 +21,7 @@ void DerivationOutput::parseHashInfo(bool & recursive, HashType & hashType, Hash
hashType = parseHashType(algo); hashType = parseHashType(algo);
if (hashType == htUnknown) if (hashType == htUnknown)
throw Error(format("unknown hash algorithm `%1%'") % algo); throw Error(format("unknown hash algorithm `%1%'") % algo);
hash = parseHash(hashType, this->hash); hash = parseHash(hashType, this->hash);
} }
@ -38,7 +38,7 @@ Path writeDerivation(StoreAPI & store,
held during a garbage collection). */ held during a garbage collection). */
string suffix = name + drvExtension; string suffix = name + drvExtension;
string contents = unparseDerivation(drv); string contents = unparseDerivation(drv);
return readOnlyMode return settings.readOnlyMode
? computeStorePathForText(suffix, contents, references) ? computeStorePathForText(suffix, contents, references)
: store.addTextToStore(suffix, contents, references); : store.addTextToStore(suffix, contents, references);
} }
@ -51,7 +51,7 @@ static Path parsePath(std::istream & str)
throw Error(format("bad path `%1%' in derivation") % s); throw Error(format("bad path `%1%' in derivation") % s);
return s; return s;
} }
static StringSet parseStrings(std::istream & str, bool arePaths) static StringSet parseStrings(std::istream & str, bool arePaths)
{ {
@ -60,7 +60,7 @@ static StringSet parseStrings(std::istream & str, bool arePaths)
res.insert(arePaths ? parsePath(str) : parseString(str)); res.insert(arePaths ? parsePath(str) : parseString(str));
return res; return res;
} }
Derivation parseDerivation(const string & s) Derivation parseDerivation(const string & s)
{ {
@ -106,7 +106,7 @@ Derivation parseDerivation(const string & s)
expect(str, ")"); expect(str, ")");
drv.env[name] = value; drv.env[name] = value;
} }
expect(str, ")"); expect(str, ")");
return drv; return drv;
} }
@ -165,7 +165,7 @@ string unparseDerivation(const Derivation & drv)
s += "],"; s += "],";
printStrings(s, drv.inputSrcs.begin(), drv.inputSrcs.end()); printStrings(s, drv.inputSrcs.begin(), drv.inputSrcs.end());
s += ','; printString(s, drv.platform); s += ','; printString(s, drv.platform);
s += ','; printString(s, drv.builder); s += ','; printString(s, drv.builder);
s += ','; printStrings(s, drv.args.begin(), drv.args.end()); s += ','; printStrings(s, drv.args.begin(), drv.args.end());
@ -178,9 +178,9 @@ string unparseDerivation(const Derivation & drv)
s += ','; printString(s, i->second); s += ','; printString(s, i->second);
s += ')'; s += ')';
} }
s += "])"; s += "])";
return s; return s;
} }
@ -190,7 +190,7 @@ bool isDerivation(const string & fileName)
return hasSuffix(fileName, drvExtension); return hasSuffix(fileName, drvExtension);
} }
bool isFixedOutputDrv(const Derivation & drv) bool isFixedOutputDrv(const Derivation & drv)
{ {
return drv.outputs.size() == 1 && return drv.outputs.size() == 1 &&
@ -247,7 +247,7 @@ Hash hashDerivationModulo(StoreAPI & store, Derivation drv)
inputs2[printHash(h)] = i->second; inputs2[printHash(h)] = i->second;
} }
drv.inputDrvs = inputs2; drv.inputDrvs = inputs2;
return hashString(htSHA256, unparseDerivation(drv)); return hashString(htSHA256, unparseDerivation(drv));
} }

View file

@ -34,10 +34,10 @@ static const int defaultGcLevel = 1000;
int LocalStore::openGCLock(LockType lockType) int LocalStore::openGCLock(LockType lockType)
{ {
Path fnGCLock = (format("%1%/%2%") Path fnGCLock = (format("%1%/%2%")
% nixStateDir % gcLockName).str(); % settings.nixStateDir % gcLockName).str();
debug(format("acquiring global GC lock `%1%'") % fnGCLock); debug(format("acquiring global GC lock `%1%'") % fnGCLock);
AutoCloseFD fdGCLock = open(fnGCLock.c_str(), O_RDWR | O_CREAT, 0600); AutoCloseFD fdGCLock = open(fnGCLock.c_str(), O_RDWR | O_CREAT, 0600);
if (fdGCLock == -1) if (fdGCLock == -1)
throw SysError(format("opening global GC lock `%1%'") % fnGCLock); throw SysError(format("opening global GC lock `%1%'") % fnGCLock);
@ -51,7 +51,7 @@ int LocalStore::openGCLock(LockType lockType)
/* !!! Restrict read permission on the GC root. Otherwise any /* !!! Restrict read permission on the GC root. Otherwise any
process that can open the file for reading can DoS the process that can open the file for reading can DoS the
collector. */ collector. */
return fdGCLock.borrow(); return fdGCLock.borrow();
} }
@ -85,7 +85,7 @@ void LocalStore::addIndirectRoot(const Path & path)
{ {
string hash = printHash32(hashString(htSHA1, path)); string hash = printHash32(hashString(htSHA1, path));
Path realRoot = canonPath((format("%1%/%2%/auto/%3%") Path realRoot = canonPath((format("%1%/%2%/auto/%3%")
% nixStateDir % gcRootsDir % hash).str()); % settings.nixStateDir % gcRootsDir % hash).str());
createSymlink(realRoot, path); createSymlink(realRoot, path);
} }
@ -113,15 +113,15 @@ Path addPermRoot(StoreAPI & store, const Path & _storePath,
else { else {
if (!allowOutsideRootsDir) { if (!allowOutsideRootsDir) {
Path rootsDir = canonPath((format("%1%/%2%") % nixStateDir % gcRootsDir).str()); Path rootsDir = canonPath((format("%1%/%2%") % settings.nixStateDir % gcRootsDir).str());
if (string(gcRoot, 0, rootsDir.size() + 1) != rootsDir + "/") if (string(gcRoot, 0, rootsDir.size() + 1) != rootsDir + "/")
throw Error(format( throw Error(format(
"path `%1%' is not a valid garbage collector root; " "path `%1%' is not a valid garbage collector root; "
"it's not in the directory `%2%'") "it's not in the directory `%2%'")
% gcRoot % rootsDir); % gcRoot % rootsDir);
} }
createSymlink(gcRoot, storePath); createSymlink(gcRoot, storePath);
} }
@ -130,10 +130,10 @@ Path addPermRoot(StoreAPI & store, const Path & _storePath,
Instead of reading all the roots, it would be more efficient to Instead of reading all the roots, it would be more efficient to
check if the root is in a directory in or linked from the check if the root is in a directory in or linked from the
gcroots directory. */ gcroots directory. */
if (queryBoolSetting("gc-check-reachability", false)) { if (settings.checkRootReachability) {
Roots roots = store.findRoots(); Roots roots = store.findRoots();
if (roots.find(gcRoot) == roots.end()) if (roots.find(gcRoot) == roots.end())
printMsg(lvlError, printMsg(lvlError,
format( format(
"warning: `%1%' is not in a directory where the garbage collector looks for roots; " "warning: `%1%' is not in a directory where the garbage collector looks for roots; "
"therefore, `%2%' might be removed by the garbage collector") "therefore, `%2%' might be removed by the garbage collector")
@ -144,7 +144,7 @@ Path addPermRoot(StoreAPI & store, const Path & _storePath,
progress. This prevents the set of permanent roots from progress. This prevents the set of permanent roots from
increasing while a GC is in progress. */ increasing while a GC is in progress. */
store.syncWithGC(); store.syncWithGC();
return gcRoot; return gcRoot;
} }
@ -160,23 +160,23 @@ void LocalStore::addTempRoot(const Path & path)
if (fdTempRoots == -1) { if (fdTempRoots == -1) {
while (1) { while (1) {
Path dir = (format("%1%/%2%") % nixStateDir % tempRootsDir).str(); Path dir = (format("%1%/%2%") % settings.nixStateDir % tempRootsDir).str();
createDirs(dir); createDirs(dir);
fnTempRoots = (format("%1%/%2%") fnTempRoots = (format("%1%/%2%")
% dir % getpid()).str(); % dir % getpid()).str();
AutoCloseFD fdGCLock = openGCLock(ltRead); AutoCloseFD fdGCLock = openGCLock(ltRead);
if (pathExists(fnTempRoots)) if (pathExists(fnTempRoots))
/* It *must* be stale, since there can be no two /* It *must* be stale, since there can be no two
processes with the same pid. */ processes with the same pid. */
unlink(fnTempRoots.c_str()); unlink(fnTempRoots.c_str());
fdTempRoots = openLockFile(fnTempRoots, true); fdTempRoots = openLockFile(fnTempRoots, true);
fdGCLock.close(); fdGCLock.close();
debug(format("acquiring read lock on `%1%'") % fnTempRoots); debug(format("acquiring read lock on `%1%'") % fnTempRoots);
lockFile(fdTempRoots, ltRead, true); lockFile(fdTempRoots, ltRead, true);
@ -186,7 +186,7 @@ void LocalStore::addTempRoot(const Path & path)
if (fstat(fdTempRoots, &st) == -1) if (fstat(fdTempRoots, &st) == -1)
throw SysError(format("statting `%1%'") % fnTempRoots); throw SysError(format("statting `%1%'") % fnTempRoots);
if (st.st_size == 0) break; if (st.st_size == 0) break;
/* The garbage collector deleted this file before we could /* The garbage collector deleted this file before we could
get a lock. (It won't delete the file after we get a get a lock. (It won't delete the file after we get a
lock.) Try again. */ lock.) Try again. */
@ -218,7 +218,7 @@ void removeTempRoots()
/* Automatically clean up the temporary roots file when we exit. */ /* Automatically clean up the temporary roots file when we exit. */
struct RemoveTempRoots struct RemoveTempRoots
{ {
~RemoveTempRoots() ~RemoveTempRoots()
{ {
@ -238,10 +238,10 @@ static void readTempRoots(PathSet & tempRoots, FDs & fds)
/* Read the `temproots' directory for per-process temporary root /* Read the `temproots' directory for per-process temporary root
files. */ files. */
Strings tempRootFiles = readDirectory( Strings tempRootFiles = readDirectory(
(format("%1%/%2%") % nixStateDir % tempRootsDir).str()); (format("%1%/%2%") % settings.nixStateDir % tempRootsDir).str());
foreach (Strings::iterator, i, tempRootFiles) { foreach (Strings::iterator, i, tempRootFiles) {
Path path = (format("%1%/%2%/%3%") % nixStateDir % tempRootsDir % *i).str(); Path path = (format("%1%/%2%/%3%") % settings.nixStateDir % tempRootsDir % *i).str();
debug(format("reading temporary root file `%1%'") % path); debug(format("reading temporary root file `%1%'") % path);
FDPtr fd(new AutoCloseFD(open(path.c_str(), O_RDWR, 0666))); FDPtr fd(new AutoCloseFD(open(path.c_str(), O_RDWR, 0666)));
@ -295,7 +295,7 @@ static void findRoots(StoreAPI & store, const Path & path,
bool recurseSymlinks, bool deleteStale, Roots & roots) bool recurseSymlinks, bool deleteStale, Roots & roots)
{ {
try { try {
struct stat st; struct stat st;
if (lstat(path.c_str(), &st) == -1) if (lstat(path.c_str(), &st) == -1)
throw SysError(format("statting `%1%'") % path); throw SysError(format("statting `%1%'") % path);
@ -315,7 +315,7 @@ static void findRoots(StoreAPI & store, const Path & path,
debug(format("found root `%1%' in `%2%'") debug(format("found root `%1%' in `%2%'")
% target % path); % target % path);
Path storePath = toStorePath(target); Path storePath = toStorePath(target);
if (store.isValidPath(storePath)) if (store.isValidPath(storePath))
roots[path] = storePath; roots[path] = storePath;
else else
printMsg(lvlInfo, format("skipping invalid root from `%1%' to `%2%'") printMsg(lvlInfo, format("skipping invalid root from `%1%' to `%2%'")
@ -350,7 +350,7 @@ static void findRoots(StoreAPI & store, const Path & path,
static Roots findRoots(StoreAPI & store, bool deleteStale) static Roots findRoots(StoreAPI & store, bool deleteStale)
{ {
Roots roots; Roots roots;
Path rootsDir = canonPath((format("%1%/%2%") % nixStateDir % gcRootsDir).str()); Path rootsDir = canonPath((format("%1%/%2%") % settings.nixStateDir % gcRootsDir).str());
findRoots(store, rootsDir, true, deleteStale, roots); findRoots(store, rootsDir, true, deleteStale, roots);
return roots; return roots;
} }
@ -365,16 +365,16 @@ Roots LocalStore::findRoots()
static void addAdditionalRoots(StoreAPI & store, PathSet & roots) static void addAdditionalRoots(StoreAPI & store, PathSet & roots)
{ {
Path rootFinder = getEnv("NIX_ROOT_FINDER", Path rootFinder = getEnv("NIX_ROOT_FINDER",
nixLibexecDir + "/nix/find-runtime-roots.pl"); settings.nixLibexecDir + "/nix/find-runtime-roots.pl");
if (rootFinder.empty()) return; if (rootFinder.empty()) return;
debug(format("executing `%1%' to find additional roots") % rootFinder); debug(format("executing `%1%' to find additional roots") % rootFinder);
string result = runProgram(rootFinder); string result = runProgram(rootFinder);
Strings paths = tokenizeString(result, "\n"); Strings paths = tokenizeString(result, "\n");
foreach (Strings::iterator, i, paths) { foreach (Strings::iterator, i, paths) {
if (isInStore(*i)) { if (isInStore(*i)) {
Path path = toStorePath(*i); Path path = toStorePath(*i);
@ -557,7 +557,7 @@ bool LocalStore::tryToDelete(GCState & state, const Path & path)
} else } else
printMsg(lvlTalkative, format("would delete `%1%'") % path); printMsg(lvlTalkative, format("would delete `%1%'") % path);
state.deleted.insert(path); state.deleted.insert(path);
if (state.options.action != GCOptions::gcReturnLive) if (state.options.action != GCOptions::gcReturnLive)
state.results.paths.insert(path); state.results.paths.insert(path);
@ -605,10 +605,10 @@ void LocalStore::removeUnusedLinks()
void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
{ {
GCState state(results); GCState state(results);
state.options = options; state.options = options;
state.gcKeepOutputs = queryBoolSetting("gc-keep-outputs", false); state.gcKeepOutputs = settings.gcKeepOutputs;
state.gcKeepDerivations = queryBoolSetting("gc-keep-derivations", true); state.gcKeepDerivations = settings.gcKeepDerivations;
/* Using `--ignore-liveness' with `--delete' can have unintended /* Using `--ignore-liveness' with `--delete' can have unintended
consequences if `gc-keep-outputs' or `gc-keep-derivations' are consequences if `gc-keep-outputs' or `gc-keep-derivations' are
@ -618,7 +618,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
state.gcKeepOutputs = false; state.gcKeepOutputs = false;
state.gcKeepDerivations = false; state.gcKeepDerivations = false;
} }
/* Acquire the global GC root. This prevents /* Acquire the global GC root. This prevents
a) New roots from being added. a) New roots from being added.
b) Processes from creating new temporary root files. */ b) Processes from creating new temporary root files. */
@ -659,18 +659,18 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
if (!tryToDelete(state, *i)) if (!tryToDelete(state, *i))
throw Error(format("cannot delete path `%1%' since it is still alive") % *i); throw Error(format("cannot delete path `%1%' since it is still alive") % *i);
} }
} else { } else {
if (shouldDelete(state.options.action)) if (shouldDelete(state.options.action))
printMsg(lvlError, format("deleting garbage...")); printMsg(lvlError, format("deleting garbage..."));
else else
printMsg(lvlError, format("determining live/dead paths...")); printMsg(lvlError, format("determining live/dead paths..."));
try { try {
AutoCloseDir dir = opendir(nixStore.c_str()); AutoCloseDir dir = opendir(settings.nixStore.c_str());
if (!dir) throw SysError(format("opening directory `%1%'") % nixStore); if (!dir) throw SysError(format("opening directory `%1%'") % settings.nixStore);
/* Read the store and immediately delete all paths that /* Read the store and immediately delete all paths that
aren't valid. When using --max-freed etc., deleting aren't valid. When using --max-freed etc., deleting
@ -684,14 +684,14 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
checkInterrupt(); checkInterrupt();
string name = dirent->d_name; string name = dirent->d_name;
if (name == "." || name == "..") continue; if (name == "." || name == "..") continue;
Path path = nixStore + "/" + name; Path path = settings.nixStore + "/" + name;
if (isValidPath(path)) if (isValidPath(path))
entries.push_back(path); entries.push_back(path);
else else
tryToDelete(state, path); tryToDelete(state, path);
} }
dir.close(); dir.close();
/* Now delete the unreachable valid paths. Randomise the /* Now delete the unreachable valid paths. Randomise the
order in which we delete entries to make the collector order in which we delete entries to make the collector

View file

@ -10,38 +10,63 @@
namespace nix { namespace nix {
string nixStore = "/UNINIT"; Settings settings;
string nixDataDir = "/UNINIT";
string nixLogDir = "/UNINIT";
string nixStateDir = "/UNINIT";
string nixDBPath = "/UNINIT";
string nixConfDir = "/UNINIT";
string nixLibexecDir = "/UNINIT";
string nixBinDir = "/UNINIT";
bool keepFailed = false;
bool keepGoing = false;
bool tryFallback = false;
Verbosity buildVerbosity = lvlError;
unsigned int maxBuildJobs = 1;
unsigned int buildCores = 1;
bool readOnlyMode = false;
string thisSystem = "unset";
time_t maxSilentTime = 0;
time_t buildTimeout = 0;
Paths substituters;
bool useBuildHook = true;
bool printBuildTrace = false;
static bool settingsRead = false; Settings::Settings()
{
keepFailed = false;
keepGoing = false;
tryFallback = false;
buildVerbosity = lvlError;
maxBuildJobs = 1;
buildCores = 1;
readOnlyMode = false;
thisSystem = SYSTEM;
maxSilentTime = 0;
buildTimeout = 0;
useBuildHook = true;
printBuildTrace = false;
reservedSize = 1024 * 1024;
fsyncMetadata = true;
useSQLiteWAL = true;
syncBeforeRegistering = false;
useSubstitutes = true;
useChroot = false;
dirsInChroot.insert("/dev");
dirsInChroot.insert("/dev/pts");
impersonateLinux26 = false;
keepLog = true;
compressLog = true;
cacheFailure = false;
pollInterval = 5;
checkRootReachability = false;
gcKeepOutputs = false;
gcKeepDerivations = true;
autoOptimiseStore = true;
envKeepDerivations = false;
}
typedef std::map<string, Strings> Settings;
static Settings settings; void Settings::processEnvironment()
{
nixStore = canonPath(getEnv("NIX_STORE_DIR", getEnv("NIX_STORE", NIX_STORE_DIR)));
nixDataDir = canonPath(getEnv("NIX_DATA_DIR", NIX_DATA_DIR));
nixLogDir = canonPath(getEnv("NIX_LOG_DIR", NIX_LOG_DIR));
nixStateDir = canonPath(getEnv("NIX_STATE_DIR", NIX_STATE_DIR));
nixDBPath = getEnv("NIX_DB_DIR", nixStateDir + "/db");
nixConfDir = canonPath(getEnv("NIX_CONF_DIR", NIX_CONF_DIR));
nixLibexecDir = canonPath(getEnv("NIX_LIBEXEC_DIR", NIX_LIBEXEC_DIR));
nixBinDir = canonPath(getEnv("NIX_BIN_DIR", NIX_BIN_DIR));
/* Overriden settings. */ string subs = getEnv("NIX_SUBSTITUTERS", "default");
Settings settingsCmdline; if (subs == "default") {
substituters.push_back(nixLibexecDir + "/nix/substituters/copy-from-other-stores.pl");
substituters.push_back(nixLibexecDir + "/nix/substituters/download-using-manifests.pl");
substituters.push_back(nixLibexecDir + "/nix/substituters/download-from-binary-cache.pl");
} else
substituters = tokenizeString(subs, ":");
}
string & at(Strings & ss, unsigned int n) string & at(Strings & ss, unsigned int n)
@ -52,7 +77,7 @@ string & at(Strings & ss, unsigned int n)
} }
static void readSettings() void Settings::loadConfFile()
{ {
Path settingsFile = (format("%1%/%2%") % nixConfDir % "nix.conf").str(); Path settingsFile = (format("%1%/%2%") % nixConfDir % "nix.conf").str();
if (!pathExists(settingsFile)) return; if (!pathExists(settingsFile)) return;
@ -80,104 +105,88 @@ static void readSettings()
Strings::iterator i = tokens.begin(); Strings::iterator i = tokens.begin();
advance(i, 2); advance(i, 2);
settings[name] = Strings(i, tokens.end()); settings[name] = concatStringsSep(" ", Strings(i, tokens.end())); // FIXME: slow
}; };
settings.insert(settingsCmdline.begin(), settingsCmdline.end());
settingsRead = true;
} }
Strings querySetting(const string & name, const Strings & def) void Settings::set(const string & name, const string & value)
{ {
if (!settingsRead) readSettings(); settings[name] = value;
Settings::iterator i = settings.find(name);
return i == settings.end() ? def : i->second;
} }
string querySetting(const string & name, const string & def) void Settings::update()
{ {
Strings defs; get(thisSystem, "system");
defs.push_back(def); get(maxBuildJobs, "build-max-jobs");
get(buildCores, "build-cores");
Strings value = querySetting(name, defs); get(maxSilentTime, "build-max-silent-time");
if (value.size() != 1) get(buildTimeout, "build-timeout");
throw Error(format("configuration option `%1%' should not be a list") % name); get(reservedSize, "gc-reserved-space");
get(fsyncMetadata, "fsync-metadata");
return value.front(); get(useSQLiteWAL, "use-sqlite-wal");
get(syncBeforeRegistering, "sync-before-registering");
get(useSubstitutes, "build-use-substitutes");
get(buildUsersGroup, "build-users-group");
get(useChroot, "build-use-chroot");
get(dirsInChroot, "build-chroot-dirs");
get(impersonateLinux26, "build-impersonate-linux-26");
get(keepLog, "build-keep-log");
get(compressLog, "build-compress-log");
get(cacheFailure, "build-cache-failure");
get(pollInterval, "build-poll-interval");
get(checkRootReachability, "gc-check-reachability");
get(gcKeepOutputs, "gc-keep-outputs");
get(gcKeepDerivations, "gc-keep-derivations");
get(autoOptimiseStore, "auto-optimise-store");
get(envKeepDerivations, "env-keep-derivations");
} }
bool queryBoolSetting(const string & name, bool def) void Settings::get(string & res, const string & name)
{ {
string v = querySetting(name, def ? "true" : "false"); SettingsMap::iterator i = settings.find(name);
if (v == "true") return true; if (i == settings.end()) return;
else if (v == "false") return false; res = i->second;
}
void Settings::get(bool & res, const string & name)
{
SettingsMap::iterator i = settings.find(name);
if (i == settings.end()) return;
if (i->second == "true") res = true;
else if (i->second == "false") res = false;
else throw Error(format("configuration option `%1%' should be either `true' or `false', not `%2%'") else throw Error(format("configuration option `%1%' should be either `true' or `false', not `%2%'")
% name % v); % name % i->second);
} }
unsigned int queryIntSetting(const string & name, unsigned int def) void Settings::get(PathSet & res, const string & name)
{ {
int n; SettingsMap::iterator i = settings.find(name);
if (!string2Int(querySetting(name, int2String(def)), n) || n < 0) if (i == settings.end()) return;
res.clear();
Strings ss = tokenizeString(i->second);
res.insert(ss.begin(), ss.end());
}
template<class N> void Settings::get(N & res, const string & name)
{
SettingsMap::iterator i = settings.find(name);
if (i == settings.end()) return;
if (!string2Int(i->second, res))
throw Error(format("configuration setting `%1%' should have an integer value") % name); throw Error(format("configuration setting `%1%' should have an integer value") % name);
return n;
} }
void overrideSetting(const string & name, const Strings & value) string Settings::pack()
{
if (settingsRead) settings[name] = value;
settingsCmdline[name] = value;
}
void reloadSettings()
{
settingsRead = false;
settings.clear();
}
void setDefaultsFromEnvironment()
{
/* Setup Nix paths. */
nixStore = canonPath(getEnv("NIX_STORE_DIR", getEnv("NIX_STORE", NIX_STORE_DIR)));
nixDataDir = canonPath(getEnv("NIX_DATA_DIR", NIX_DATA_DIR));
nixLogDir = canonPath(getEnv("NIX_LOG_DIR", NIX_LOG_DIR));
nixStateDir = canonPath(getEnv("NIX_STATE_DIR", NIX_STATE_DIR));
nixDBPath = getEnv("NIX_DB_DIR", nixStateDir + "/db");
nixConfDir = canonPath(getEnv("NIX_CONF_DIR", NIX_CONF_DIR));
nixLibexecDir = canonPath(getEnv("NIX_LIBEXEC_DIR", NIX_LIBEXEC_DIR));
nixBinDir = canonPath(getEnv("NIX_BIN_DIR", NIX_BIN_DIR));
string subs = getEnv("NIX_SUBSTITUTERS", "default");
if (subs == "default") {
substituters.push_back(nixLibexecDir + "/nix/substituters/copy-from-other-stores.pl");
substituters.push_back(nixLibexecDir + "/nix/substituters/download-using-manifests.pl");
substituters.push_back(nixLibexecDir + "/nix/substituters/download-from-binary-cache.pl");
} else
substituters = tokenizeString(subs, ":");
/* Get some settings from the configuration file. */
thisSystem = querySetting("system", SYSTEM);
maxBuildJobs = queryIntSetting("build-max-jobs", 1);
buildCores = queryIntSetting("build-cores", 1);
maxSilentTime = queryIntSetting("build-max-silent-time", 0);
buildTimeout = queryIntSetting("build-timeout", 0);
}
string packSettings()
{ {
string s; string s;
if (!settingsRead) readSettings(); foreach (SettingsMap::iterator, i, settings) {
foreach (Settings::iterator, i, settings) { s += i->first; s += '='; s += i->second; s += '\n';
s += i->first; s += '='; s += concatStringsSep(" ", i->second); s += '\n';
} }
return s; return s;
} }

View file

@ -2,120 +2,189 @@
#include "types.hh" #include "types.hh"
#include <map>
namespace nix { namespace nix {
/* Path names. */ struct Settings {
/* nixStore is the directory where we generally store atomic and Settings();
derived files. */
extern string nixStore;
extern string nixDataDir; /* !!! fix */ void processEnvironment();
/* nixLogDir is the directory where we log various operations. */ void loadConfFile();
extern string nixLogDir;
/* nixStateDir is the directory where state is stored. */ void set(const string & name, const string & value);
extern string nixStateDir;
/* nixDBPath is the path name of our Berkeley DB environment. */ void update();
extern string nixDBPath;
/* nixConfDir is the directory where configuration files are string pack();
stored. */
extern string nixConfDir;
/* nixLibexecDir is the directory where internal helper programs are /* The directory where we store sources and derived files. */
stored. */ Path nixStore;
extern string nixLibexecDir;
/* nixBinDir is the directory where the main programs are stored. */ Path nixDataDir; /* !!! fix */
extern string nixBinDir;
/* The directory where we log various operations. */
Path nixLogDir;
/* The directory where state is stored. */
Path nixStateDir;
/* The directory where we keep the SQLite database. */
Path nixDBPath;
/* The directory where configuration files are stored. */
Path nixConfDir;
/* The directory where internal helper programs are stored. */
Path nixLibexecDir;
/* The directory where the main programs are stored. */
Path nixBinDir;
/* Whether to keep temporary directories of failed builds. */
bool keepFailed;
/* Whether to keep building subgoals when a sibling (another
subgoal of the same goal) fails. */
bool keepGoing;
/* Whether, if we cannot realise the known closure corresponding
to a derivation, we should try to normalise the derivation
instead. */
bool tryFallback;
/* Verbosity level for build output. */
Verbosity buildVerbosity;
/* Maximum number of parallel build jobs. 0 means unlimited. */
unsigned int maxBuildJobs;
/* Number of CPU cores to utilize in parallel within a build,
i.e. by passing this number to Make via '-j'. 0 means that the
number of actual CPU cores on the local host ought to be
auto-detected. */
unsigned int buildCores;
/* Read-only mode. Don't copy stuff to the store, don't change
the database. */
bool readOnlyMode;
/* The canonical system name, as returned by config.guess. */
string thisSystem;
/* The maximum time in seconds that a builer can go without
producing any output on stdout/stderr before it is killed. 0
means infinity. */
time_t maxSilentTime;
/* The maximum duration in seconds that a builder can run. 0
means infinity. */
time_t buildTimeout;
/* The substituters. There are programs that can somehow realise
a store path without building, e.g., by downloading it or
copying it from a CD. */
Paths substituters;
/* Whether to use build hooks (for distributed builds). Sometimes
users want to disable this from the command-line. */
bool useBuildHook;
/* Whether buildDerivations() should print out lines on stderr in
a fixed format to allow its progress to be monitored. Each
line starts with a "@". The following are defined:
@ build-started <drvpath> <outpath> <system> <logfile>
@ build-failed <drvpath> <outpath> <exitcode> <error text>
@ build-succeeded <drvpath> <outpath>
@ substituter-started <outpath> <substituter>
@ substituter-failed <outpath> <exitcode> <error text>
@ substituter-succeeded <outpath>
Best combined with --no-build-output, otherwise stderr might
conceivably contain lines in this format printed by the
builders. */
bool printBuildTrace;
/* Amount of reserved space for the garbage collector
(/nix/var/nix/db/reserved). */
off_t reservedSize;
/* Whether SQLite should use fsync. */
bool fsyncMetadata;
/* Whether SQLite should use WAL mode. */
bool useSQLiteWAL;
/* Whether to call sync() before registering a path as valid. */
bool syncBeforeRegistering;
/* Whether to use substitutes. */
bool useSubstitutes;
/* The Unix group that contains the build users. */
string buildUsersGroup;
/* Whether to build in chroot. */
bool useChroot;
/* The directories from the host filesystem to be included in the
chroot. */
PathSet dirsInChroot;
/* Whether to impersonate a Linux 2.6 machine on newer kernels. */
bool impersonateLinux26;
/* Whether to store build logs. */
bool keepLog;
/* Whether to compress logs. */
bool compressLog;
/* Whether to cache build failures. */
bool cacheFailure;
/* How often (in seconds) to poll for locks. */
unsigned int pollInterval;
/* Whether to check if new GC roots can in fact be found by the
garbage collector. */
bool checkRootReachability;
/* Whether the garbage collector should keep outputs of live
derivations. */
bool gcKeepOutputs;
/* Whether the garbage collector should keep derivers of live
paths. */
bool gcKeepDerivations;
/* Whether to automatically replace files with identical contents
with hard links. */
bool autoOptimiseStore;
/* Whether to add derivations as a dependency of user environments
(to prevent them from being GCed). */
bool envKeepDerivations;
private:
typedef std::map<string, string> SettingsMap;
SettingsMap settings;
void get(string & res, const string & name);
void get(bool & res, const string & name);
void get(PathSet & res, const string & name);
template<class N> void get(N & res, const string & name);
};
/* Misc. global flags. */ // FIXME: don't use a global variable.
extern Settings settings;
/* Whether to keep temporary directories of failed builds. */
extern bool keepFailed;
/* Whether to keep building subgoals when a sibling (another subgoal
of the same goal) fails. */
extern bool keepGoing;
/* Whether, if we cannot realise the known closure corresponding to a
derivation, we should try to normalise the derivation instead. */
extern bool tryFallback;
/* Verbosity level for build output. */
extern Verbosity buildVerbosity;
/* Maximum number of parallel build jobs. 0 means unlimited. */
extern unsigned int maxBuildJobs;
/* Number of CPU cores to utilize in parallel within a build, i.e. by passing
this number to Make via '-j'. 0 means that the number of actual CPU cores on
the local host ought to be auto-detected. */
extern unsigned int buildCores;
/* Read-only mode. Don't copy stuff to the store, don't change the
database. */
extern bool readOnlyMode;
/* The canonical system name, as returned by config.guess. */
extern string thisSystem;
/* The maximum time in seconds that a builer can go without producing
any output on stdout/stderr before it is killed. 0 means
infinity. */
extern time_t maxSilentTime;
/* The maximum duration in seconds that a builder can run. 0 means
infinity. */
extern time_t buildTimeout;
/* The substituters. There are programs that can somehow realise a
store path without building, e.g., by downloading it or copying it
from a CD. */
extern Paths substituters;
/* Whether to use build hooks (for distributed builds). Sometimes
users want to disable this from the command-line. */
extern bool useBuildHook;
/* Whether buildDerivations() should print out lines on stderr in a
fixed format to allow its progress to be monitored. Each line
starts with a "@". The following are defined:
@ build-started <drvpath> <outpath> <system> <logfile>
@ build-failed <drvpath> <outpath> <exitcode> <error text>
@ build-succeeded <drvpath> <outpath>
@ substituter-started <outpath> <substituter>
@ substituter-failed <outpath> <exitcode> <error text>
@ substituter-succeeded <outpath>
Best combined with --no-build-output, otherwise stderr might
conceivably contain lines in this format printed by the builders.
*/
extern bool printBuildTrace;
Strings querySetting(const string & name, const Strings & def);
string querySetting(const string & name, const string & def);
bool queryBoolSetting(const string & name, bool def);
unsigned int queryIntSetting(const string & name, unsigned int def);
void overrideSetting(const string & name, const Strings & value);
void reloadSettings();
void setDefaultsFromEnvironment();
string packSettings();
} }

View file

@ -181,7 +181,7 @@ struct SQLiteTxn
void checkStoreNotSymlink() void checkStoreNotSymlink()
{ {
if (getEnv("NIX_IGNORE_SYMLINK_STORE") == "1") return; if (getEnv("NIX_IGNORE_SYMLINK_STORE") == "1") return;
Path path = nixStore; Path path = settings.nixStore;
struct stat st; struct stat st;
while (path != "/") { while (path != "/") {
if (lstat(path.c_str(), &st)) if (lstat(path.c_str(), &st))
@ -198,21 +198,21 @@ void checkStoreNotSymlink()
LocalStore::LocalStore(bool reserveSpace) LocalStore::LocalStore(bool reserveSpace)
{ {
schemaPath = nixDBPath + "/schema"; schemaPath = settings.nixDBPath + "/schema";
if (readOnlyMode) { if (settings.readOnlyMode) {
openDB(false); openDB(false);
return; return;
} }
/* Create missing state directories if they don't already exist. */ /* Create missing state directories if they don't already exist. */
createDirs(nixStore); createDirs(settings.nixStore);
createDirs(linksDir = nixStore + "/.links"); createDirs(linksDir = settings.nixStore + "/.links");
Path profilesDir = nixStateDir + "/profiles"; Path profilesDir = settings.nixStateDir + "/profiles";
createDirs(nixStateDir + "/profiles"); createDirs(settings.nixStateDir + "/profiles");
createDirs(nixStateDir + "/temproots"); createDirs(settings.nixStateDir + "/temproots");
createDirs(nixDBPath); createDirs(settings.nixDBPath);
Path gcRootsDir = nixStateDir + "/gcroots"; Path gcRootsDir = settings.nixStateDir + "/gcroots";
if (!pathExists(gcRootsDir)) { if (!pathExists(gcRootsDir)) {
createDirs(gcRootsDir); createDirs(gcRootsDir);
if (symlink(profilesDir.c_str(), (gcRootsDir + "/profiles").c_str()) == -1) if (symlink(profilesDir.c_str(), (gcRootsDir + "/profiles").c_str()) == -1)
@ -226,13 +226,12 @@ LocalStore::LocalStore(bool reserveSpace)
needed, we reserve some dummy space that we can free just needed, we reserve some dummy space that we can free just
before doing a garbage collection. */ before doing a garbage collection. */
try { try {
Path reservedPath = nixDBPath + "/reserved"; Path reservedPath = settings.nixDBPath + "/reserved";
if (reserveSpace) { if (reserveSpace) {
int reservedSize = queryIntSetting("gc-reserved-space", 1024 * 1024);
struct stat st; struct stat st;
if (stat(reservedPath.c_str(), &st) == -1 || if (stat(reservedPath.c_str(), &st) == -1 ||
st.st_size != reservedSize) st.st_size != settings.reservedSize)
writeFile(reservedPath, string(reservedSize, 'X')); writeFile(reservedPath, string(settings.reservedSize, 'X'));
} }
else else
deletePath(reservedPath); deletePath(reservedPath);
@ -242,11 +241,11 @@ LocalStore::LocalStore(bool reserveSpace)
/* Acquire the big fat lock in shared mode to make sure that no /* Acquire the big fat lock in shared mode to make sure that no
schema upgrade is in progress. */ schema upgrade is in progress. */
try { try {
Path globalLockPath = nixDBPath + "/big-lock"; Path globalLockPath = settings.nixDBPath + "/big-lock";
globalLock = openLockFile(globalLockPath.c_str(), true); globalLock = openLockFile(globalLockPath.c_str(), true);
} catch (SysError & e) { } catch (SysError & e) {
if (e.errNo != EACCES) throw; if (e.errNo != EACCES) throw;
readOnlyMode = true; settings.readOnlyMode = true;
openDB(false); openDB(false);
return; return;
} }
@ -325,7 +324,7 @@ int LocalStore::getSchema()
void LocalStore::openDB(bool create) void LocalStore::openDB(bool create)
{ {
/* Open the Nix database. */ /* Open the Nix database. */
if (sqlite3_open_v2((nixDBPath + "/db.sqlite").c_str(), &db.db, if (sqlite3_open_v2((settings.nixDBPath + "/db.sqlite").c_str(), &db.db,
SQLITE_OPEN_READWRITE | (create ? SQLITE_OPEN_CREATE : 0), 0) != SQLITE_OK) SQLITE_OPEN_READWRITE | (create ? SQLITE_OPEN_CREATE : 0), 0) != SQLITE_OK)
throw Error("cannot open SQLite database"); throw Error("cannot open SQLite database");
@ -342,13 +341,13 @@ void LocalStore::openDB(bool create)
should be safe enough. If the user asks for it, don't sync at should be safe enough. If the user asks for it, don't sync at
all. This can cause database corruption if the system all. This can cause database corruption if the system
crashes. */ crashes. */
string syncMode = queryBoolSetting("fsync-metadata", true) ? "normal" : "off"; string syncMode = settings.fsyncMetadata ? "normal" : "off";
if (sqlite3_exec(db, ("pragma synchronous = " + syncMode + ";").c_str(), 0, 0, 0) != SQLITE_OK) if (sqlite3_exec(db, ("pragma synchronous = " + syncMode + ";").c_str(), 0, 0, 0) != SQLITE_OK)
throwSQLiteError(db, "setting synchronous mode"); throwSQLiteError(db, "setting synchronous mode");
/* Set the SQLite journal mode. WAL mode is fastest, so it's the /* Set the SQLite journal mode. WAL mode is fastest, so it's the
default. */ default. */
string mode = queryBoolSetting("use-sqlite-wal", true) ? "wal" : "truncate"; string mode = settings.useSQLiteWAL ? "wal" : "truncate";
string prevMode; string prevMode;
{ {
SQLiteStmt stmt; SQLiteStmt stmt;
@ -890,7 +889,7 @@ Path LocalStore::queryPathFromHashPart(const string & hashPart)
SQLiteTxn txn(db); SQLiteTxn txn(db);
Path prefix = nixStore + "/" + hashPart; Path prefix = settings.nixStore + "/" + hashPart;
SQLiteStmtUse use(stmtQueryPathFromHashPart); SQLiteStmtUse use(stmtQueryPathFromHashPart);
stmtQueryPathFromHashPart.bind(prefix); stmtQueryPathFromHashPart.bind(prefix);
@ -933,7 +932,7 @@ void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter &
/* Pass configuration options (including those overriden /* Pass configuration options (including those overriden
with --option) to the substituter. */ with --option) to the substituter. */
setenv("_NIX_OPTIONS", packSettings().c_str(), 1); setenv("_NIX_OPTIONS", settings.pack().c_str(), 1);
fromPipe.readSide.close(); fromPipe.readSide.close();
toPipe.writeSide.close(); toPipe.writeSide.close();
@ -969,7 +968,7 @@ template<class T> T getIntLine(int fd)
PathSet LocalStore::querySubstitutablePaths(const PathSet & paths) PathSet LocalStore::querySubstitutablePaths(const PathSet & paths)
{ {
PathSet res; PathSet res;
foreach (Paths::iterator, i, substituters) { foreach (Paths::iterator, i, settings.substituters) {
if (res.size() == paths.size()) break; if (res.size() == paths.size()) break;
RunningSubstituter & run(runningSubstituters[*i]); RunningSubstituter & run(runningSubstituters[*i]);
startSubstituter(*i, run); startSubstituter(*i, run);
@ -1023,7 +1022,7 @@ void LocalStore::querySubstitutablePathInfos(const PathSet & paths,
SubstitutablePathInfos & infos) SubstitutablePathInfos & infos)
{ {
PathSet todo = paths; PathSet todo = paths;
foreach (Paths::iterator, i, substituters) { foreach (Paths::iterator, i, settings.substituters) {
if (todo.empty()) break; if (todo.empty()) break;
querySubstitutablePathInfos(*i, todo, infos); querySubstitutablePathInfos(*i, todo, infos);
} }
@ -1046,11 +1045,10 @@ void LocalStore::registerValidPath(const ValidPathInfo & info)
void LocalStore::registerValidPaths(const ValidPathInfos & infos) void LocalStore::registerValidPaths(const ValidPathInfos & infos)
{ {
/* sqlite will fsync by default, but the new valid paths may not be fsync-ed. /* SQLite will fsync by default, but the new valid paths may not be fsync-ed.
* So some may want to fsync them before registering the validity, at the * So some may want to fsync them before registering the validity, at the
* expense of some speed of the path registering operation. */ * expense of some speed of the path registering operation. */
if (queryBoolSetting("sync-before-registering", false)) if (settings.syncBeforeRegistering) sync();
sync();
while (1) { while (1) {
try { try {
@ -1294,7 +1292,7 @@ void LocalStore::exportPath(const Path & path, bool sign,
Path hashFile = tmpDir + "/hash"; Path hashFile = tmpDir + "/hash";
writeFile(hashFile, printHash(hash)); writeFile(hashFile, printHash(hash));
Path secretKey = nixConfDir + "/signing-key.sec"; Path secretKey = settings.nixConfDir + "/signing-key.sec";
checkSecrecy(secretKey); checkSecrecy(secretKey);
Strings args; Strings args;
@ -1340,7 +1338,7 @@ Path LocalStore::createTempDirInStore()
/* There is a slight possibility that `tmpDir' gets deleted by /* There is a slight possibility that `tmpDir' gets deleted by
the GC between createTempDir() and addTempRoot(), so repeat the GC between createTempDir() and addTempRoot(), so repeat
until `tmpDir' exists. */ until `tmpDir' exists. */
tmpDir = createTempDir(nixStore); tmpDir = createTempDir(settings.nixStore);
addTempRoot(tmpDir); addTempRoot(tmpDir);
} while (!pathExists(tmpDir)); } while (!pathExists(tmpDir));
return tmpDir; return tmpDir;
@ -1392,7 +1390,7 @@ Path LocalStore::importPath(bool requireSignature, Source & source)
args.push_back("rsautl"); args.push_back("rsautl");
args.push_back("-verify"); args.push_back("-verify");
args.push_back("-inkey"); args.push_back("-inkey");
args.push_back(nixConfDir + "/signing-key.pub"); args.push_back(settings.nixConfDir + "/signing-key.pub");
args.push_back("-pubin"); args.push_back("-pubin");
args.push_back("-in"); args.push_back("-in");
args.push_back(sigFile); args.push_back(sigFile);
@ -1501,7 +1499,7 @@ void LocalStore::verifyStore(bool checkContents)
/* Acquire the global GC lock to prevent a garbage collection. */ /* Acquire the global GC lock to prevent a garbage collection. */
AutoCloseFD fdGCLock = openGCLock(ltWrite); AutoCloseFD fdGCLock = openGCLock(ltWrite);
Paths entries = readDirectory(nixStore); Paths entries = readDirectory(settings.nixStore);
PathSet store(entries.begin(), entries.end()); PathSet store(entries.begin(), entries.end());
/* Check whether all valid paths actually exist. */ /* Check whether all valid paths actually exist. */
@ -1611,9 +1609,9 @@ void LocalStore::verifyPath(const Path & path, const PathSet & store,
PathSet LocalStore::queryValidPathsOld() PathSet LocalStore::queryValidPathsOld()
{ {
PathSet paths; PathSet paths;
Strings entries = readDirectory(nixDBPath + "/info"); Strings entries = readDirectory(settings.nixDBPath + "/info");
foreach (Strings::iterator, i, entries) foreach (Strings::iterator, i, entries)
if (i->at(0) != '.') paths.insert(nixStore + "/" + *i); if (i->at(0) != '.') paths.insert(settings.nixStore + "/" + *i);
return paths; return paths;
} }
@ -1625,7 +1623,7 @@ ValidPathInfo LocalStore::queryPathInfoOld(const Path & path)
/* Read the info file. */ /* Read the info file. */
string baseName = baseNameOf(path); string baseName = baseNameOf(path);
Path infoFile = (format("%1%/info/%2%") % nixDBPath % baseName).str(); Path infoFile = (format("%1%/info/%2%") % settings.nixDBPath % baseName).str();
if (!pathExists(infoFile)) if (!pathExists(infoFile))
throw Error(format("path `%1%' is not valid") % path); throw Error(format("path `%1%' is not valid") % path);
string info = readFile(infoFile); string info = readFile(infoFile);

View file

@ -75,7 +75,7 @@ struct SQLiteStmt
void bind64(long long value); void bind64(long long value);
void bind(); void bind();
}; };
class LocalStore : public StoreAPI class LocalStore : public StoreAPI
{ {
@ -84,7 +84,7 @@ private:
RunningSubstituters runningSubstituters; RunningSubstituters runningSubstituters;
Path linksDir; Path linksDir;
public: public:
/* Initialise the local store, upgrading the schema if /* Initialise the local store, upgrading the schema if
@ -92,15 +92,15 @@ public:
LocalStore(bool reserveSpace = true); LocalStore(bool reserveSpace = true);
~LocalStore(); ~LocalStore();
/* Implementations of abstract store API methods. */ /* Implementations of abstract store API methods. */
bool isValidPath(const Path & path); bool isValidPath(const Path & path);
PathSet queryValidPaths(const PathSet & paths); PathSet queryValidPaths(const PathSet & paths);
PathSet queryAllValidPaths(); PathSet queryAllValidPaths();
ValidPathInfo queryPathInfo(const Path & path); ValidPathInfo queryPathInfo(const Path & path);
Hash queryPathHash(const Path & path); Hash queryPathHash(const Path & path);
@ -120,17 +120,17 @@ public:
PathSet queryDerivationOutputs(const Path & path); PathSet queryDerivationOutputs(const Path & path);
StringSet queryDerivationOutputNames(const Path & path); StringSet queryDerivationOutputNames(const Path & path);
Path queryPathFromHashPart(const string & hashPart); Path queryPathFromHashPart(const string & hashPart);
PathSet querySubstitutablePaths(const PathSet & paths); PathSet querySubstitutablePaths(const PathSet & paths);
void querySubstitutablePathInfos(const Path & substituter, void querySubstitutablePathInfos(const Path & substituter,
PathSet & paths, SubstitutablePathInfos & infos); PathSet & paths, SubstitutablePathInfos & infos);
void querySubstitutablePathInfos(const PathSet & paths, void querySubstitutablePathInfos(const PathSet & paths,
SubstitutablePathInfos & infos); SubstitutablePathInfos & infos);
Path addToStore(const Path & srcPath, Path addToStore(const Path & srcPath,
bool recursive = true, HashType hashAlgo = htSHA256, bool recursive = true, HashType hashAlgo = htSHA256,
PathFilter & filter = defaultPathFilter); PathFilter & filter = defaultPathFilter);
@ -149,7 +149,7 @@ public:
Sink & sink); Sink & sink);
Paths importPaths(bool requireSignature, Source & source); Paths importPaths(bool requireSignature, Source & source);
void buildPaths(const PathSet & paths); void buildPaths(const PathSet & paths);
void ensurePath(const Path & path); void ensurePath(const Path & path);
@ -157,7 +157,7 @@ public:
void addTempRoot(const Path & path); void addTempRoot(const Path & path);
void addIndirectRoot(const Path & path); void addIndirectRoot(const Path & path);
void syncWithGC(); void syncWithGC();
Roots findRoots(); Roots findRoots();
@ -170,7 +170,7 @@ public:
/* Optimise a single store path. */ /* Optimise a single store path. */
void optimisePath(const Path & path); void optimisePath(const Path & path);
/* Check the integrity of the Nix store. */ /* Check the integrity of the Nix store. */
void verifyStore(bool checkContents); void verifyStore(bool checkContents);
@ -229,18 +229,18 @@ private:
unsigned long long queryValidPathId(const Path & path); unsigned long long queryValidPathId(const Path & path);
unsigned long long addValidPath(const ValidPathInfo & info, bool checkOutputs = true); unsigned long long addValidPath(const ValidPathInfo & info, bool checkOutputs = true);
void addReference(unsigned long long referrer, unsigned long long reference); void addReference(unsigned long long referrer, unsigned long long reference);
void appendReferrer(const Path & from, const Path & to, bool lock); void appendReferrer(const Path & from, const Path & to, bool lock);
void rewriteReferrers(const Path & path, bool purge, PathSet referrers); void rewriteReferrers(const Path & path, bool purge, PathSet referrers);
void invalidatePath(const Path & path); void invalidatePath(const Path & path);
/* Delete a path from the Nix store. */ /* Delete a path from the Nix store. */
void invalidatePathChecked(const Path & path); void invalidatePathChecked(const Path & path);
void verifyPath(const Path & path, const PathSet & store, void verifyPath(const Path & path, const PathSet & store,
PathSet & done, PathSet & validPaths); PathSet & done, PathSet & validPaths);
@ -253,14 +253,14 @@ private:
struct GCState; struct GCState;
void deleteGarbage(GCState & state, const Path & path); void deleteGarbage(GCState & state, const Path & path);
bool tryToDelete(GCState & state, const Path & path); bool tryToDelete(GCState & state, const Path & path);
bool isActiveTempFile(const GCState & state, bool isActiveTempFile(const GCState & state,
const Path & path, const string & suffix); const Path & path, const string & suffix);
int openGCLock(LockType lockType); int openGCLock(LockType lockType);
void removeUnusedLinks(); void removeUnusedLinks();
void startSubstituter(const Path & substituter, void startSubstituter(const Path & substituter,
@ -269,7 +269,7 @@ private:
Path createTempDirInStore(); Path createTempDirInStore();
Path importPath(bool requireSignature, Source & source); Path importPath(bool requireSignature, Source & source);
void checkDerivationOutputs(const Path & drvPath, const Derivation & drv); void checkDerivationOutputs(const Path & drvPath, const Derivation & drv);
void optimisePath_(OptimiseStats & stats, const Path & path); void optimisePath_(OptimiseStats & stats, const Path & path);
@ -290,9 +290,6 @@ void canonicalisePathMetaData(const Path & path, bool recurse);
MakeError(PathInUse, Error); MakeError(PathInUse, Error);
/* Whether we are in build users mode. */
bool haveBuildUsers();
/* Whether we are root. */ /* Whether we are root. */
bool amPrivileged(); bool amPrivileged();
@ -305,5 +302,5 @@ void deletePathWrapped(const Path & path,
unsigned long long & bytesFreed, unsigned long long & blocksFreed); unsigned long long & bytesFreed, unsigned long long & blocksFreed);
void deletePathWrapped(const Path & path); void deletePathWrapped(const Path & path);
} }

View file

@ -52,10 +52,8 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
unsigned long long & downloadSize, unsigned long long & narSize) unsigned long long & downloadSize, unsigned long long & narSize)
{ {
downloadSize = narSize = 0; downloadSize = narSize = 0;
PathSet todo(targets.begin(), targets.end()), done;
bool useSubstitutes = queryBoolSetting("build-use-substitutes", true); PathSet todo(targets.begin(), targets.end()), done;
/* Getting substitute info has high latency when using the binary /* Getting substitute info has high latency when using the binary
cache substituter. Thus it's essential to do substitute cache substituter. Thus it's essential to do substitute
@ -77,7 +75,7 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
*/ */
while (!todo.empty()) { while (!todo.empty()) {
PathSet query, todoDrv, todoNonDrv; PathSet query, todoDrv, todoNonDrv;
foreach (PathSet::iterator, i, todo) { foreach (PathSet::iterator, i, todo) {
@ -96,9 +94,9 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
foreach (DerivationOutputs::iterator, j, drv.outputs) foreach (DerivationOutputs::iterator, j, drv.outputs)
if (!store.isValidPath(j->second.path)) invalid.insert(j->second.path); if (!store.isValidPath(j->second.path)) invalid.insert(j->second.path);
if (invalid.empty()) continue; if (invalid.empty()) continue;
todoDrv.insert(*i); todoDrv.insert(*i);
if (useSubstitutes) query.insert(invalid.begin(), invalid.end()); if (settings.useSubstitutes) query.insert(invalid.begin(), invalid.end());
} }
else { else {
@ -109,7 +107,7 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
} }
todo.clear(); todo.clear();
SubstitutablePathInfos infos; SubstitutablePathInfos infos;
store.querySubstitutablePathInfos(query, infos); store.querySubstitutablePathInfos(query, infos);
@ -118,7 +116,7 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
Derivation drv = derivationFromPath(store, *i); Derivation drv = derivationFromPath(store, *i);
bool mustBuild = false; bool mustBuild = false;
if (useSubstitutes) { if (settings.useSubstitutes) {
foreach (DerivationOutputs::iterator, j, drv.outputs) foreach (DerivationOutputs::iterator, j, drv.outputs)
if (!store.isValidPath(j->second.path) && if (!store.isValidPath(j->second.path) &&
infos.find(j->second.path) == infos.end()) infos.find(j->second.path) == infos.end())
@ -135,7 +133,7 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
foreach (DerivationOutputs::iterator, i, drv.outputs) foreach (DerivationOutputs::iterator, i, drv.outputs)
todoNonDrv.insert(i->second.path); todoNonDrv.insert(i->second.path);
} }
foreach (PathSet::iterator, i, todoNonDrv) { foreach (PathSet::iterator, i, todoNonDrv) {
done.insert(*i); done.insert(*i);
SubstitutablePathInfos::iterator info = infos.find(*i); SubstitutablePathInfos::iterator info = infos.find(*i);
@ -150,22 +148,22 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
} }
} }
static void dfsVisit(StoreAPI & store, const PathSet & paths, static void dfsVisit(StoreAPI & store, const PathSet & paths,
const Path & path, PathSet & visited, Paths & sorted, const Path & path, PathSet & visited, Paths & sorted,
PathSet & parents) PathSet & parents)
{ {
if (parents.find(path) != parents.end()) if (parents.find(path) != parents.end())
throw BuildError(format("cycle detected in the references of `%1%'") % path); throw BuildError(format("cycle detected in the references of `%1%'") % path);
if (visited.find(path) != visited.end()) return; if (visited.find(path) != visited.end()) return;
visited.insert(path); visited.insert(path);
parents.insert(path); parents.insert(path);
PathSet references; PathSet references;
if (store.isValidPath(path)) if (store.isValidPath(path))
store.queryReferences(path, references); store.queryReferences(path, references);
foreach (PathSet::iterator, i, references) foreach (PathSet::iterator, i, references)
/* Don't traverse into paths that don't exist. That can /* Don't traverse into paths that don't exist. That can
happen due to substitutes for non-existent paths. */ happen due to substitutes for non-existent paths. */

View file

@ -17,7 +17,7 @@ static void makeWritable(const Path & path)
{ {
struct stat st; struct stat st;
if (lstat(path.c_str(), &st)) if (lstat(path.c_str(), &st))
throw SysError(format("getting attributes of path `%1%'") % path); throw SysError(format("getting attributes of path `%1%'") % path);
if (S_ISDIR(st.st_mode) || S_ISREG(st.st_mode)) makeMutable(path); if (S_ISDIR(st.st_mode) || S_ISREG(st.st_mode)) makeMutable(path);
if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1) if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1)
throw SysError(format("changing writability of `%1%'") % path); throw SysError(format("changing writability of `%1%'") % path);
@ -53,15 +53,15 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path)
{ {
struct stat st; struct stat st;
if (lstat(path.c_str(), &st)) if (lstat(path.c_str(), &st))
throw SysError(format("getting attributes of path `%1%'") % path); throw SysError(format("getting attributes of path `%1%'") % path);
if (S_ISDIR(st.st_mode)) { if (S_ISDIR(st.st_mode)) {
Strings names = readDirectory(path); Strings names = readDirectory(path);
foreach (Strings::iterator, i, names) foreach (Strings::iterator, i, names)
optimisePath_(stats, path + "/" + *i); optimisePath_(stats, path + "/" + *i);
return; return;
} }
/* We can hard link regular files and maybe symlinks. */ /* We can hard link regular files and maybe symlinks. */
if (!S_ISREG(st.st_mode) if (!S_ISREG(st.st_mode)
#if CAN_LINK_SYMLINK #if CAN_LINK_SYMLINK
@ -69,7 +69,7 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path)
&& !S_ISLNK(st.st_mode) && !S_ISLNK(st.st_mode)
#endif #endif
) return; ) return;
/* Sometimes SNAFUs can cause files in the Nix store to be /* Sometimes SNAFUs can cause files in the Nix store to be
modified, in particular when running programs as root under modified, in particular when running programs as root under
NixOS (example: $fontconfig/var/cache being modified). Skip NixOS (example: $fontconfig/var/cache being modified). Skip
@ -110,25 +110,25 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path)
current file with a hard link to that file. */ current file with a hard link to that file. */
struct stat stLink; struct stat stLink;
if (lstat(linkPath.c_str(), &stLink)) if (lstat(linkPath.c_str(), &stLink))
throw SysError(format("getting attributes of path `%1%'") % linkPath); throw SysError(format("getting attributes of path `%1%'") % linkPath);
stats.sameContents++; stats.sameContents++;
if (st.st_ino == stLink.st_ino) { if (st.st_ino == stLink.st_ino) {
printMsg(lvlDebug, format("`%1%' is already linked to `%2%'") % path % linkPath); printMsg(lvlDebug, format("`%1%' is already linked to `%2%'") % path % linkPath);
return; return;
} }
printMsg(lvlTalkative, format("linking `%1%' to `%2%'") % path % linkPath); printMsg(lvlTalkative, format("linking `%1%' to `%2%'") % path % linkPath);
Path tempLink = (format("%1%/.tmp-link-%2%-%3%") Path tempLink = (format("%1%/.tmp-link-%2%-%3%")
% nixStore % getpid() % rand()).str(); % settings.nixStore % getpid() % rand()).str();
/* Make the containing directory writable, but only if it's not /* Make the containing directory writable, but only if it's not
the store itself (we don't want or need to mess with its the store itself (we don't want or need to mess with its
permissions). */ permissions). */
bool mustToggle = !isStorePath(path); bool mustToggle = !isStorePath(path);
if (mustToggle) makeWritable(dirOf(path)); if (mustToggle) makeWritable(dirOf(path));
/* When we're done, make the directory read-only again and reset /* When we're done, make the directory read-only again and reset
its timestamp back to 0. */ its timestamp back to 0. */
MakeReadOnly makeReadOnly(mustToggle ? dirOf(path) : ""); MakeReadOnly makeReadOnly(mustToggle ? dirOf(path) : "");
@ -192,10 +192,8 @@ void LocalStore::optimiseStore(OptimiseStats & stats)
void LocalStore::optimisePath(const Path & path) void LocalStore::optimisePath(const Path & path)
{ {
if (queryBoolSetting("auto-optimise-store", true)) { OptimiseStats stats;
OptimiseStats stats; if (settings.autoOptimiseStore) optimisePath_(stats, path);
optimisePath_(stats, path);
}
} }

View file

@ -100,7 +100,7 @@ void RemoteStore::forkSlave()
/* Start the worker. */ /* Start the worker. */
Path worker = getEnv("NIX_WORKER"); Path worker = getEnv("NIX_WORKER");
if (worker == "") if (worker == "")
worker = nixBinDir + "/nix-worker"; worker = settings.nixBinDir + "/nix-worker";
child = fork(); child = fork();
@ -142,7 +142,7 @@ void RemoteStore::connectToDaemon()
if (fdSocket == -1) if (fdSocket == -1)
throw SysError("cannot create Unix domain socket"); throw SysError("cannot create Unix domain socket");
string socketPath = nixStateDir + DEFAULT_SOCKET_PATH; string socketPath = settings.nixStateDir + DEFAULT_SOCKET_PATH;
/* Urgh, sockaddr_un allows path names of only 108 characters. So /* Urgh, sockaddr_un allows path names of only 108 characters. So
chdir to the socket directory so that we can pass a relative chdir to the socket directory so that we can pass a relative
@ -184,23 +184,23 @@ RemoteStore::~RemoteStore()
void RemoteStore::setOptions() void RemoteStore::setOptions()
{ {
writeInt(wopSetOptions, to); writeInt(wopSetOptions, to);
writeInt(keepFailed, to); writeInt(settings.keepFailed, to);
writeInt(keepGoing, to); writeInt(settings.keepGoing, to);
writeInt(tryFallback, to); writeInt(settings.tryFallback, to);
writeInt(verbosity, to); writeInt(verbosity, to);
writeInt(maxBuildJobs, to); writeInt(settings.maxBuildJobs, to);
writeInt(maxSilentTime, to); writeInt(settings.maxSilentTime, to);
if (GET_PROTOCOL_MINOR(daemonVersion) >= 2) if (GET_PROTOCOL_MINOR(daemonVersion) >= 2)
writeInt(useBuildHook, to); writeInt(settings.useBuildHook, to);
if (GET_PROTOCOL_MINOR(daemonVersion) >= 4) { if (GET_PROTOCOL_MINOR(daemonVersion) >= 4) {
writeInt(buildVerbosity, to); writeInt(settings.buildVerbosity, to);
writeInt(logType, to); writeInt(logType, to);
writeInt(printBuildTrace, to); writeInt(settings.printBuildTrace, to);
} }
if (GET_PROTOCOL_MINOR(daemonVersion) >= 6) if (GET_PROTOCOL_MINOR(daemonVersion) >= 6)
writeInt(buildCores, to); writeInt(settings.buildCores, to);
if (GET_PROTOCOL_MINOR(daemonVersion) >= 10) if (GET_PROTOCOL_MINOR(daemonVersion) >= 10)
writeInt(queryBoolSetting("build-use-substitutes", true), to); writeInt(settings.useSubstitutes, to);
processStderr(); processStderr();
} }

View file

@ -19,16 +19,16 @@ GCOptions::GCOptions()
bool isInStore(const Path & path) bool isInStore(const Path & path)
{ {
return path[0] == '/' return path[0] == '/'
&& string(path, 0, nixStore.size()) == nixStore && string(path, 0, settings.nixStore.size()) == settings.nixStore
&& path.size() >= nixStore.size() + 2 && path.size() >= settings.nixStore.size() + 2
&& path[nixStore.size()] == '/'; && path[settings.nixStore.size()] == '/';
} }
bool isStorePath(const Path & path) bool isStorePath(const Path & path)
{ {
return isInStore(path) return isInStore(path)
&& path.find('/', nixStore.size() + 1) == Path::npos; && path.find('/', settings.nixStore.size() + 1) == Path::npos;
} }
@ -43,7 +43,7 @@ Path toStorePath(const Path & path)
{ {
if (!isInStore(path)) if (!isInStore(path))
throw Error(format("path `%1%' is not in the Nix store") % path); throw Error(format("path `%1%' is not in the Nix store") % path);
Path::size_type slash = path.find('/', nixStore.size() + 1); Path::size_type slash = path.find('/', settings.nixStore.size() + 1);
if (slash == Path::npos) if (slash == Path::npos)
return path; return path;
else else
@ -74,7 +74,7 @@ Path followLinksToStorePath(const Path & path)
string storePathToName(const Path & path) string storePathToName(const Path & path)
{ {
assertStorePath(path); assertStorePath(path);
return string(path, nixStore.size() + 34); return string(path, settings.nixStore.size() + 34);
} }
@ -173,11 +173,11 @@ Path makeStorePath(const string & type,
{ {
/* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */ /* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */
string s = type + ":sha256:" + printHash(hash) + ":" string s = type + ":sha256:" + printHash(hash) + ":"
+ nixStore + ":" + name; + settings.nixStore + ":" + name;
checkStoreName(name); checkStoreName(name);
return nixStore + "/" return settings.nixStore + "/"
+ printHash32(compressHash(hashString(htSHA256, s), 20)) + printHash32(compressHash(hashString(htSHA256, s), 20))
+ "-" + name; + "-" + name;
} }

View file

@ -55,7 +55,6 @@ struct Globals
EvalState state; EvalState state;
bool dryRun; bool dryRun;
bool preserveInstalled; bool preserveInstalled;
bool keepDerivations;
string forceName; string forceName;
bool prebuiltOnly; bool prebuiltOnly;
}; };
@ -266,8 +265,8 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems,
if (k != newest.end()) { if (k != newest.end()) {
d = j->first.system == k->second.first.system ? 0 : d = j->first.system == k->second.first.system ? 0 :
j->first.system == thisSystem ? 1 : j->first.system == settings.thisSystem ? 1 :
k->second.first.system == thisSystem ? -1 : 0; k->second.first.system == settings.thisSystem ? -1 : 0;
if (d == 0) if (d == 0)
d = comparePriorities(state, j->first, k->second.first); d = comparePriorities(state, j->first, k->second.first);
if (d == 0) if (d == 0)
@ -498,7 +497,7 @@ static void installDerivations(Globals & globals,
if (globals.dryRun) return; if (globals.dryRun) return;
if (createUserEnv(globals.state, allElems, if (createUserEnv(globals.state, allElems,
profile, globals.keepDerivations, lockToken)) break; profile, settings.envKeepDerivations, lockToken)) break;
} }
} }
@ -605,7 +604,7 @@ static void upgradeDerivations(Globals & globals,
if (globals.dryRun) return; if (globals.dryRun) return;
if (createUserEnv(globals.state, newElems, if (createUserEnv(globals.state, newElems,
globals.profile, globals.keepDerivations, lockToken)) break; globals.profile, settings.envKeepDerivations, lockToken)) break;
} }
} }
@ -672,7 +671,7 @@ static void opSetFlag(Globals & globals,
/* Write the new user environment. */ /* Write the new user environment. */
if (createUserEnv(globals.state, installedElems, if (createUserEnv(globals.state, installedElems,
globals.profile, globals.keepDerivations, lockToken)) break; globals.profile, settings.envKeepDerivations, lockToken)) break;
} }
} }
@ -740,7 +739,7 @@ static void uninstallDerivations(Globals & globals, Strings & selectors,
if (globals.dryRun) return; if (globals.dryRun) return;
if (createUserEnv(globals.state, newElems, if (createUserEnv(globals.state, newElems,
profile, globals.keepDerivations, lockToken)) break; profile, settings.envKeepDerivations, lockToken)) break;
} }
} }
@ -869,7 +868,7 @@ static void opQuery(Globals & globals,
enum { sInstalled, sAvailable } source = sInstalled; enum { sInstalled, sAvailable } source = sInstalled;
readOnlyMode = true; /* makes evaluation a bit faster */ settings.readOnlyMode = true; /* makes evaluation a bit faster */
for (Strings::iterator i = args.begin(); i != args.end(); ) { for (Strings::iterator i = args.begin(); i != args.end(); ) {
string arg = *i++; string arg = *i++;
@ -1262,9 +1261,6 @@ void run(Strings args)
globals.preserveInstalled = false; globals.preserveInstalled = false;
globals.prebuiltOnly = false; globals.prebuiltOnly = false;
globals.keepDerivations =
queryBoolSetting("env-keep-derivations", false);
for (Strings::iterator i = args.begin(); i != args.end(); ) { for (Strings::iterator i = args.begin(); i != args.end(); ) {
string arg = *i++; string arg = *i++;
@ -1331,7 +1327,7 @@ void run(Strings args)
Path profileLink = getHomeDir() + "/.nix-profile"; Path profileLink = getHomeDir() + "/.nix-profile";
globals.profile = pathExists(profileLink) globals.profile = pathExists(profileLink)
? absPath(readLink(profileLink), dirOf(profileLink)) ? absPath(readLink(profileLink), dirOf(profileLink))
: canonPath(nixStateDir + "/profiles/default"); : canonPath(settings.nixStateDir + "/profiles/default");
} }
store = openStore(); store = openStore();

View file

@ -94,11 +94,11 @@ void run(Strings args)
if (arg == "-") if (arg == "-")
readStdin = true; readStdin = true;
else if (arg == "--eval-only") { else if (arg == "--eval-only") {
readOnlyMode = true; settings.readOnlyMode = true;
evalOnly = true; evalOnly = true;
} }
else if (arg == "--parse-only") { else if (arg == "--parse-only") {
readOnlyMode = true; settings.readOnlyMode = true;
parseOnly = evalOnly = true; parseOnly = evalOnly = true;
} }
else if (arg == "--find-file") else if (arg == "--find-file")

View file

@ -47,7 +47,7 @@ LocalStore & ensureLocalStore()
static Path useDeriver(Path path) static Path useDeriver(Path path)
{ {
if (!isDerivation(path)) { if (!isDerivation(path)) {
path = store->queryDeriver(path); path = store->queryDeriver(path);
if (path == "") if (path == "")
@ -89,18 +89,18 @@ static PathSet realisePath(const Path & path)
static void opRealise(Strings opFlags, Strings opArgs) static void opRealise(Strings opFlags, Strings opArgs)
{ {
bool dryRun = false; bool dryRun = false;
foreach (Strings::iterator, i, opFlags) foreach (Strings::iterator, i, opFlags)
if (*i == "--dry-run") dryRun = true; if (*i == "--dry-run") dryRun = true;
else throw UsageError(format("unknown flag `%1%'") % *i); else throw UsageError(format("unknown flag `%1%'") % *i);
foreach (Strings::iterator, i, opArgs) foreach (Strings::iterator, i, opArgs)
*i = followLinksToStorePath(*i); *i = followLinksToStorePath(*i);
printMissing(*store, PathSet(opArgs.begin(), opArgs.end())); printMissing(*store, PathSet(opArgs.begin(), opArgs.end()));
if (dryRun) return; if (dryRun) return;
/* Build all paths at the same time to exploit parallelism. */ /* Build all paths at the same time to exploit parallelism. */
PathSet paths(opArgs.begin(), opArgs.end()); PathSet paths(opArgs.begin(), opArgs.end());
store->buildPaths(paths); store->buildPaths(paths);
@ -128,7 +128,7 @@ static void opAdd(Strings opFlags, Strings opArgs)
static void opAddFixed(Strings opFlags, Strings opArgs) static void opAddFixed(Strings opFlags, Strings opArgs)
{ {
bool recursive = false; bool recursive = false;
for (Strings::iterator i = opFlags.begin(); for (Strings::iterator i = opFlags.begin();
i != opFlags.end(); ++i) i != opFlags.end(); ++i)
if (*i == "--recursive") recursive = true; if (*i == "--recursive") recursive = true;
@ -136,7 +136,7 @@ static void opAddFixed(Strings opFlags, Strings opArgs)
if (opArgs.empty()) if (opArgs.empty())
throw UsageError("first argument must be hash algorithm"); throw UsageError("first argument must be hash algorithm");
HashType hashAlgo = parseHashType(opArgs.front()); HashType hashAlgo = parseHashType(opArgs.front());
opArgs.pop_front(); opArgs.pop_front();
@ -149,7 +149,7 @@ static void opAddFixed(Strings opFlags, Strings opArgs)
static void opPrintFixedPath(Strings opFlags, Strings opArgs) static void opPrintFixedPath(Strings opFlags, Strings opArgs)
{ {
bool recursive = false; bool recursive = false;
for (Strings::iterator i = opFlags.begin(); for (Strings::iterator i = opFlags.begin();
i != opFlags.end(); ++i) i != opFlags.end(); ++i)
if (*i == "--recursive") recursive = true; if (*i == "--recursive") recursive = true;
@ -157,7 +157,7 @@ static void opPrintFixedPath(Strings opFlags, Strings opArgs)
if (opArgs.size() != 3) if (opArgs.size() != 3)
throw UsageError(format("`--print-fixed-path' requires three arguments")); throw UsageError(format("`--print-fixed-path' requires three arguments"));
Strings::iterator i = opArgs.begin(); Strings::iterator i = opArgs.begin();
HashType hashAlgo = parseHashType(*i++); HashType hashAlgo = parseHashType(*i++);
string hash = *i++; string hash = *i++;
@ -205,12 +205,12 @@ static void printTree(const Path & path,
PathSet references; PathSet references;
store->queryReferences(path, references); store->queryReferences(path, references);
#if 0 #if 0
for (PathSet::iterator i = drv.inputSrcs.begin(); for (PathSet::iterator i = drv.inputSrcs.begin();
i != drv.inputSrcs.end(); ++i) i != drv.inputSrcs.end(); ++i)
cout << format("%1%%2%\n") % (tailPad + treeConn) % *i; cout << format("%1%%2%\n") % (tailPad + treeConn) % *i;
#endif #endif
/* Topologically sort under the relation A < B iff A \in /* Topologically sort under the relation A < B iff A \in
closure(B). That is, if derivation A is an (possibly indirect) closure(B). That is, if derivation A is an (possibly indirect)
@ -266,7 +266,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
else throw UsageError(format("unknown flag `%1%'") % *i); else throw UsageError(format("unknown flag `%1%'") % *i);
switch (query) { switch (query) {
case qOutputs: { case qOutputs: {
foreach (Strings::iterator, i, opArgs) { foreach (Strings::iterator, i, opArgs) {
*i = followLinksToStorePath(*i); *i = followLinksToStorePath(*i);
@ -293,7 +293,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
} }
} }
Paths sorted = topoSortPaths(*store, paths); Paths sorted = topoSortPaths(*store, paths);
for (Paths::reverse_iterator i = sorted.rbegin(); for (Paths::reverse_iterator i = sorted.rbegin();
i != sorted.rend(); ++i) i != sorted.rend(); ++i)
cout << format("%s\n") % *i; cout << format("%s\n") % *i;
break; break;
@ -328,7 +328,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
if (query == qHash) { if (query == qHash) {
assert(info.hash.type == htSHA256); assert(info.hash.type == htSHA256);
cout << format("sha256:%1%\n") % printHash32(info.hash); cout << format("sha256:%1%\n") % printHash32(info.hash);
} else if (query == qSize) } else if (query == qSize)
cout << format("%1%\n") % info.narSize; cout << format("%1%\n") % info.narSize;
} }
} }
@ -340,7 +340,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
printTree(followLinksToStorePath(*i), "", "", done); printTree(followLinksToStorePath(*i), "", "", done);
break; break;
} }
case qGraph: { case qGraph: {
PathSet roots; PathSet roots;
foreach (Strings::iterator, i, opArgs) { foreach (Strings::iterator, i, opArgs) {
@ -366,7 +366,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
cout << format("%1%\n") % followLinksToStorePath(*i); cout << format("%1%\n") % followLinksToStorePath(*i);
break; break;
} }
case qRoots: { case qRoots: {
PathSet referrers; PathSet referrers;
foreach (Strings::iterator, i, opArgs) { foreach (Strings::iterator, i, opArgs) {
@ -380,7 +380,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
cout << format("%1%\n") % i->first; cout << format("%1%\n") % i->first;
break; break;
} }
default: default:
abort(); abort();
} }
@ -426,9 +426,9 @@ static void opReadLog(Strings opFlags, Strings opArgs)
foreach (Strings::iterator, i, opArgs) { foreach (Strings::iterator, i, opArgs) {
Path path = useDeriver(followLinksToStorePath(*i)); Path path = useDeriver(followLinksToStorePath(*i));
Path logPath = (format("%1%/%2%/%3%") % Path logPath = (format("%1%/%2%/%3%") %
nixLogDir % drvsLogDir % baseNameOf(path)).str(); settings.nixLogDir % drvsLogDir % baseNameOf(path)).str();
Path logBz2Path = logPath + ".bz2"; Path logBz2Path = logPath + ".bz2";
if (pathExists(logPath)) { if (pathExists(logPath)) {
@ -454,7 +454,7 @@ static void opReadLog(Strings opFlags, Strings opArgs)
} while (err != BZ_STREAM_END); } while (err != BZ_STREAM_END);
BZ2_bzReadClose(&err, bz); BZ2_bzReadClose(&err, bz);
} }
else throw Error(format("build log of derivation `%1%' is not available") % path); else throw Error(format("build log of derivation `%1%' is not available") % path);
} }
} }
@ -474,7 +474,7 @@ static void opDumpDB(Strings opFlags, Strings opArgs)
static void registerValidity(bool reregister, bool hashGiven, bool canonicalise) static void registerValidity(bool reregister, bool hashGiven, bool canonicalise)
{ {
ValidPathInfos infos; ValidPathInfos infos;
while (1) { while (1) {
ValidPathInfo info = decodeValidPathInfo(cin, hashGiven); ValidPathInfo info = decodeValidPathInfo(cin, hashGiven);
if (info.path == "") break; if (info.path == "") break;
@ -508,7 +508,7 @@ static void opRegisterValidity(Strings opFlags, Strings opArgs)
{ {
bool reregister = false; // !!! maybe this should be the default bool reregister = false; // !!! maybe this should be the default
bool hashGiven = false; bool hashGiven = false;
for (Strings::iterator i = opFlags.begin(); for (Strings::iterator i = opFlags.begin();
i != opFlags.end(); ++i) i != opFlags.end(); ++i)
if (*i == "--reregister") reregister = true; if (*i == "--reregister") reregister = true;
@ -524,7 +524,7 @@ static void opRegisterValidity(Strings opFlags, Strings opArgs)
static void opCheckValidity(Strings opFlags, Strings opArgs) static void opCheckValidity(Strings opFlags, Strings opArgs)
{ {
bool printInvalid = false; bool printInvalid = false;
for (Strings::iterator i = opFlags.begin(); for (Strings::iterator i = opFlags.begin();
i != opFlags.end(); ++i) i != opFlags.end(); ++i)
if (*i == "--print-invalid") printInvalid = true; if (*i == "--print-invalid") printInvalid = true;
@ -551,13 +551,13 @@ static string showBytes(unsigned long long bytes, unsigned long long blocks)
} }
struct PrintFreed struct PrintFreed
{ {
bool show; bool show;
const GCResults & results; const GCResults & results;
PrintFreed(bool show, const GCResults & results) PrintFreed(bool show, const GCResults & results)
: show(show), results(results) { } : show(show), results(results) { }
~PrintFreed() ~PrintFreed()
{ {
if (show) if (show)
cout << format("%1% store paths deleted, %2% freed\n") cout << format("%1% store paths deleted, %2% freed\n")
@ -572,9 +572,9 @@ static void opGC(Strings opFlags, Strings opArgs)
bool printRoots = false; bool printRoots = false;
GCOptions options; GCOptions options;
options.action = GCOptions::gcDeleteDead; options.action = GCOptions::gcDeleteDead;
GCResults results; GCResults results;
/* Do what? */ /* Do what? */
foreach (Strings::iterator, i, opFlags) foreach (Strings::iterator, i, opFlags)
if (*i == "--print-roots") printRoots = true; if (*i == "--print-roots") printRoots = true;
@ -613,14 +613,14 @@ static void opDelete(Strings opFlags, Strings opArgs)
{ {
GCOptions options; GCOptions options;
options.action = GCOptions::gcDeleteSpecific; options.action = GCOptions::gcDeleteSpecific;
foreach (Strings::iterator, i, opFlags) foreach (Strings::iterator, i, opFlags)
if (*i == "--ignore-liveness") options.ignoreLiveness = true; if (*i == "--ignore-liveness") options.ignoreLiveness = true;
else throw UsageError(format("unknown flag `%1%'") % *i); else throw UsageError(format("unknown flag `%1%'") % *i);
foreach (Strings::iterator, i, opArgs) foreach (Strings::iterator, i, opArgs)
options.pathsToDelete.insert(followLinksToStorePath(*i)); options.pathsToDelete.insert(followLinksToStorePath(*i));
GCResults results; GCResults results;
PrintFreed freed(true, results); PrintFreed freed(true, results);
store->collectGarbage(options, results); store->collectGarbage(options, results);
@ -671,9 +671,9 @@ static void opImport(Strings opFlags, Strings opArgs)
foreach (Strings::iterator, i, opFlags) foreach (Strings::iterator, i, opFlags)
if (*i == "--require-signature") requireSignature = true; if (*i == "--require-signature") requireSignature = true;
else throw UsageError(format("unknown flag `%1%'") % *i); else throw UsageError(format("unknown flag `%1%'") % *i);
if (!opArgs.empty()) throw UsageError("no arguments expected"); if (!opArgs.empty()) throw UsageError("no arguments expected");
FdSource source(STDIN_FILENO); FdSource source(STDIN_FILENO);
Paths paths = store->importPaths(requireSignature, source); Paths paths = store->importPaths(requireSignature, source);
@ -700,12 +700,12 @@ static void opVerify(Strings opFlags, Strings opArgs)
throw UsageError("no arguments expected"); throw UsageError("no arguments expected");
bool checkContents = false; bool checkContents = false;
for (Strings::iterator i = opFlags.begin(); for (Strings::iterator i = opFlags.begin();
i != opFlags.end(); ++i) i != opFlags.end(); ++i)
if (*i == "--check-contents") checkContents = true; if (*i == "--check-contents") checkContents = true;
else throw UsageError(format("unknown flag `%1%'") % *i); else throw UsageError(format("unknown flag `%1%'") % *i);
ensureLocalStore().verifyStore(checkContents); ensureLocalStore().verifyStore(checkContents);
} }
@ -844,7 +844,7 @@ void run(Strings args)
} }
else if (arg == "--indirect") else if (arg == "--indirect")
indirectRoot = true; indirectRoot = true;
else if (arg[0] == '-') { else if (arg[0] == '-') {
opFlags.push_back(arg); opFlags.push_back(arg);
if (arg == "--max-freed" || arg == "--max-links" || arg == "--max-atime") { /* !!! hack */ if (arg == "--max-freed" || arg == "--max-links" || arg == "--max-atime") { /* !!! hack */
if (i != args.end()) opFlags.push_back(*i++); if (i != args.end()) opFlags.push_back(*i++);

View file

@ -527,27 +527,23 @@ static void performOp(unsigned int clientVersion,
} }
case wopSetOptions: { case wopSetOptions: {
keepFailed = readInt(from) != 0; settings.keepFailed = readInt(from) != 0;
keepGoing = readInt(from) != 0; settings.keepGoing = readInt(from) != 0;
tryFallback = readInt(from) != 0; settings.tryFallback = readInt(from) != 0;
verbosity = (Verbosity) readInt(from); verbosity = (Verbosity) readInt(from);
maxBuildJobs = readInt(from); settings.maxBuildJobs = readInt(from);
maxSilentTime = readInt(from); settings.maxSilentTime = readInt(from);
if (GET_PROTOCOL_MINOR(clientVersion) >= 2) if (GET_PROTOCOL_MINOR(clientVersion) >= 2)
useBuildHook = readInt(from) != 0; settings.useBuildHook = readInt(from) != 0;
if (GET_PROTOCOL_MINOR(clientVersion) >= 4) { if (GET_PROTOCOL_MINOR(clientVersion) >= 4) {
buildVerbosity = (Verbosity) readInt(from); settings.buildVerbosity = (Verbosity) readInt(from);
logType = (LogType) readInt(from); logType = (LogType) readInt(from);
printBuildTrace = readInt(from) != 0; settings.printBuildTrace = readInt(from) != 0;
} }
if (GET_PROTOCOL_MINOR(clientVersion) >= 6) if (GET_PROTOCOL_MINOR(clientVersion) >= 6)
buildCores = readInt(from); settings.buildCores = readInt(from);
if (GET_PROTOCOL_MINOR(clientVersion) >= 10) { if (GET_PROTOCOL_MINOR(clientVersion) >= 10)
int x = readInt(from); settings.useSubstitutes = readInt(from) != 0;
Strings ss;
ss.push_back(x == 0 ? "false" : "true");
overrideSetting("build-use-substitutes", ss);
}
startWork(); startWork();
stopWork(); stopWork();
break; break;
@ -768,7 +764,7 @@ static void daemonLoop()
if (fdSocket == -1) if (fdSocket == -1)
throw SysError("cannot create Unix domain socket"); throw SysError("cannot create Unix domain socket");
string socketPath = nixStateDir + DEFAULT_SOCKET_PATH; string socketPath = settings.nixStateDir + DEFAULT_SOCKET_PATH;
createDirs(dirOf(socketPath)); createDirs(dirOf(socketPath));
@ -867,10 +863,6 @@ static void daemonLoop()
strncpy(argvSaved[1], processName.c_str(), strlen(argvSaved[1])); strncpy(argvSaved[1], processName.c_str(), strlen(argvSaved[1]));
} }
/* Since the daemon can be long-running, the
settings may have changed. So force a reload. */
reloadSettings();
/* Handle the connection. */ /* Handle the connection. */
from.fd = remote; from.fd = remote;
to.fd = remote; to.fd = remote;