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) {
try {
setDefaultsFromEnvironment();
settings.processEnvironment();
store = openStore();
} catch (Error & e) {
croak(e.what());

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -10,38 +10,63 @@
namespace nix {
string nixStore = "/UNINIT";
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;
Settings settings;
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. */
Settings settingsCmdline;
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, ":");
}
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();
if (!pathExists(settingsFile)) return;
@ -80,104 +105,88 @@ static void readSettings()
Strings::iterator i = tokens.begin();
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::iterator i = settings.find(name);
return i == settings.end() ? def : i->second;
settings[name] = value;
}
string querySetting(const string & name, const string & def)
void Settings::update()
{
Strings defs;
defs.push_back(def);
Strings value = querySetting(name, defs);
if (value.size() != 1)
throw Error(format("configuration option `%1%' should not be a list") % name);
return value.front();
get(thisSystem, "system");
get(maxBuildJobs, "build-max-jobs");
get(buildCores, "build-cores");
get(maxSilentTime, "build-max-silent-time");
get(buildTimeout, "build-timeout");
get(reservedSize, "gc-reserved-space");
get(fsyncMetadata, "fsync-metadata");
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");
if (v == "true") return true;
else if (v == "false") return false;
SettingsMap::iterator i = settings.find(name);
if (i == settings.end()) return;
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%'")
% name % v);
% name % i->second);
}
unsigned int queryIntSetting(const string & name, unsigned int def)
void Settings::get(PathSet & res, const string & name)
{
int n;
if (!string2Int(querySetting(name, int2String(def)), n) || n < 0)
SettingsMap::iterator i = settings.find(name);
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);
return n;
}
void overrideSetting(const string & name, const Strings & value)
{
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 Settings::pack()
{
string s;
if (!settingsRead) readSettings();
foreach (Settings::iterator, i, settings) {
s += i->first; s += '='; s += concatStringsSep(" ", i->second); s += '\n';
foreach (SettingsMap::iterator, i, settings) {
s += i->first; s += '='; s += i->second; s += '\n';
}
return s;
}

View file

@ -2,120 +2,189 @@
#include "types.hh"
#include <map>
namespace nix {
/* Path names. */
struct Settings {
/* nixStore is the directory where we generally store atomic and
derived files. */
extern string nixStore;
Settings();
extern string nixDataDir; /* !!! fix */
void processEnvironment();
/* nixLogDir is the directory where we log various operations. */
extern string nixLogDir;
void loadConfFile();
/* nixStateDir is the directory where state is stored. */
extern string nixStateDir;
void set(const string & name, const string & value);
/* nixDBPath is the path name of our Berkeley DB environment. */
extern string nixDBPath;
void update();
/* nixConfDir is the directory where configuration files are
stored. */
extern string nixConfDir;
string pack();
/* nixLibexecDir is the directory where internal helper programs are
stored. */
extern string nixLibexecDir;
/* The directory where we store sources and derived files. */
Path nixStore;
/* nixBinDir is the directory where the main programs are stored. */
extern string nixBinDir;
Path nixDataDir; /* !!! fix */
/* 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. */
/* 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();
// FIXME: don't use a global variable.
extern Settings settings;
}

View file

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

View file

@ -75,7 +75,7 @@ struct SQLiteStmt
void bind64(long long value);
void bind();
};
class LocalStore : public StoreAPI
{
@ -84,7 +84,7 @@ private:
RunningSubstituters runningSubstituters;
Path linksDir;
public:
/* Initialise the local store, upgrading the schema if
@ -92,15 +92,15 @@ public:
LocalStore(bool reserveSpace = true);
~LocalStore();
/* Implementations of abstract store API methods. */
bool isValidPath(const Path & path);
PathSet queryValidPaths(const PathSet & paths);
PathSet queryAllValidPaths();
ValidPathInfo queryPathInfo(const Path & path);
Hash queryPathHash(const Path & path);
@ -120,17 +120,17 @@ public:
PathSet queryDerivationOutputs(const Path & path);
StringSet queryDerivationOutputNames(const Path & path);
Path queryPathFromHashPart(const string & hashPart);
PathSet querySubstitutablePaths(const PathSet & paths);
void querySubstitutablePathInfos(const Path & substituter,
PathSet & paths, SubstitutablePathInfos & infos);
void querySubstitutablePathInfos(const PathSet & paths,
SubstitutablePathInfos & infos);
Path addToStore(const Path & srcPath,
bool recursive = true, HashType hashAlgo = htSHA256,
PathFilter & filter = defaultPathFilter);
@ -149,7 +149,7 @@ public:
Sink & sink);
Paths importPaths(bool requireSignature, Source & source);
void buildPaths(const PathSet & paths);
void ensurePath(const Path & path);
@ -157,7 +157,7 @@ public:
void addTempRoot(const Path & path);
void addIndirectRoot(const Path & path);
void syncWithGC();
Roots findRoots();
@ -170,7 +170,7 @@ public:
/* Optimise a single store path. */
void optimisePath(const Path & path);
/* Check the integrity of the Nix store. */
void verifyStore(bool checkContents);
@ -229,18 +229,18 @@ private:
unsigned long long queryValidPathId(const Path & path);
unsigned long long addValidPath(const ValidPathInfo & info, bool checkOutputs = true);
void addReference(unsigned long long referrer, unsigned long long reference);
void appendReferrer(const Path & from, const Path & to, bool lock);
void rewriteReferrers(const Path & path, bool purge, PathSet referrers);
void invalidatePath(const Path & path);
/* Delete a path from the Nix store. */
void invalidatePathChecked(const Path & path);
void verifyPath(const Path & path, const PathSet & store,
PathSet & done, PathSet & validPaths);
@ -253,14 +253,14 @@ private:
struct GCState;
void deleteGarbage(GCState & state, const Path & path);
bool tryToDelete(GCState & state, const Path & path);
bool isActiveTempFile(const GCState & state,
const Path & path, const string & suffix);
int openGCLock(LockType lockType);
void removeUnusedLinks();
void startSubstituter(const Path & substituter,
@ -269,7 +269,7 @@ private:
Path createTempDirInStore();
Path importPath(bool requireSignature, Source & source);
void checkDerivationOutputs(const Path & drvPath, const Derivation & drv);
void optimisePath_(OptimiseStats & stats, const Path & path);
@ -290,9 +290,6 @@ void canonicalisePathMetaData(const Path & path, bool recurse);
MakeError(PathInUse, Error);
/* Whether we are in build users mode. */
bool haveBuildUsers();
/* Whether we are root. */
bool amPrivileged();
@ -305,5 +302,5 @@ void deletePathWrapped(const Path & path,
unsigned long long & bytesFreed, unsigned long long & blocksFreed);
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)
{
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
cache substituter. Thus it's essential to do substitute
@ -77,7 +75,7 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
*/
while (!todo.empty()) {
PathSet query, todoDrv, todoNonDrv;
foreach (PathSet::iterator, i, todo) {
@ -96,9 +94,9 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
foreach (DerivationOutputs::iterator, j, drv.outputs)
if (!store.isValidPath(j->second.path)) invalid.insert(j->second.path);
if (invalid.empty()) continue;
todoDrv.insert(*i);
if (useSubstitutes) query.insert(invalid.begin(), invalid.end());
if (settings.useSubstitutes) query.insert(invalid.begin(), invalid.end());
}
else {
@ -109,7 +107,7 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
}
todo.clear();
SubstitutablePathInfos infos;
store.querySubstitutablePathInfos(query, infos);
@ -118,7 +116,7 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
Derivation drv = derivationFromPath(store, *i);
bool mustBuild = false;
if (useSubstitutes) {
if (settings.useSubstitutes) {
foreach (DerivationOutputs::iterator, j, drv.outputs)
if (!store.isValidPath(j->second.path) &&
infos.find(j->second.path) == infos.end())
@ -135,7 +133,7 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
foreach (DerivationOutputs::iterator, i, drv.outputs)
todoNonDrv.insert(i->second.path);
}
foreach (PathSet::iterator, i, todoNonDrv) {
done.insert(*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,
const Path & path, PathSet & visited, Paths & sorted,
PathSet & parents)
{
if (parents.find(path) != parents.end())
throw BuildError(format("cycle detected in the references of `%1%'") % path);
if (visited.find(path) != visited.end()) return;
visited.insert(path);
parents.insert(path);
PathSet references;
if (store.isValidPath(path))
store.queryReferences(path, references);
foreach (PathSet::iterator, i, references)
/* Don't traverse into paths that don't exist. That can
happen due to substitutes for non-existent paths. */

View file

@ -17,7 +17,7 @@ static void makeWritable(const Path & path)
{
struct stat 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 (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1)
throw SysError(format("changing writability of `%1%'") % path);
@ -53,15 +53,15 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path)
{
struct stat 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)) {
Strings names = readDirectory(path);
foreach (Strings::iterator, i, names)
optimisePath_(stats, path + "/" + *i);
foreach (Strings::iterator, i, names)
optimisePath_(stats, path + "/" + *i);
return;
}
/* We can hard link regular files and maybe symlinks. */
if (!S_ISREG(st.st_mode)
#if CAN_LINK_SYMLINK
@ -69,7 +69,7 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path)
&& !S_ISLNK(st.st_mode)
#endif
) return;
/* Sometimes SNAFUs can cause files in the Nix store to be
modified, in particular when running programs as root under
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. */
struct stat 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++;
if (st.st_ino == stLink.st_ino) {
printMsg(lvlDebug, format("`%1%' is already linked to `%2%'") % path % linkPath);
return;
}
printMsg(lvlTalkative, format("linking `%1%' to `%2%'") % path % linkPath);
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
the store itself (we don't want or need to mess with its
permissions). */
bool mustToggle = !isStorePath(path);
if (mustToggle) makeWritable(dirOf(path));
/* When we're done, make the directory read-only again and reset
its timestamp back to 0. */
MakeReadOnly makeReadOnly(mustToggle ? dirOf(path) : "");
@ -192,10 +192,8 @@ void LocalStore::optimiseStore(OptimiseStats & stats)
void LocalStore::optimisePath(const Path & path)
{
if (queryBoolSetting("auto-optimise-store", true)) {
OptimiseStats stats;
optimisePath_(stats, path);
}
OptimiseStats stats;
if (settings.autoOptimiseStore) optimisePath_(stats, path);
}

View file

@ -100,7 +100,7 @@ void RemoteStore::forkSlave()
/* Start the worker. */
Path worker = getEnv("NIX_WORKER");
if (worker == "")
worker = nixBinDir + "/nix-worker";
worker = settings.nixBinDir + "/nix-worker";
child = fork();
@ -142,7 +142,7 @@ void RemoteStore::connectToDaemon()
if (fdSocket == -1)
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
chdir to the socket directory so that we can pass a relative
@ -184,23 +184,23 @@ RemoteStore::~RemoteStore()
void RemoteStore::setOptions()
{
writeInt(wopSetOptions, to);
writeInt(keepFailed, to);
writeInt(keepGoing, to);
writeInt(tryFallback, to);
writeInt(settings.keepFailed, to);
writeInt(settings.keepGoing, to);
writeInt(settings.tryFallback, to);
writeInt(verbosity, to);
writeInt(maxBuildJobs, to);
writeInt(maxSilentTime, to);
writeInt(settings.maxBuildJobs, to);
writeInt(settings.maxSilentTime, to);
if (GET_PROTOCOL_MINOR(daemonVersion) >= 2)
writeInt(useBuildHook, to);
writeInt(settings.useBuildHook, to);
if (GET_PROTOCOL_MINOR(daemonVersion) >= 4) {
writeInt(buildVerbosity, to);
writeInt(settings.buildVerbosity, to);
writeInt(logType, to);
writeInt(printBuildTrace, to);
writeInt(settings.printBuildTrace, to);
}
if (GET_PROTOCOL_MINOR(daemonVersion) >= 6)
writeInt(buildCores, to);
writeInt(settings.buildCores, to);
if (GET_PROTOCOL_MINOR(daemonVersion) >= 10)
writeInt(queryBoolSetting("build-use-substitutes", true), to);
writeInt(settings.useSubstitutes, to);
processStderr();
}

View file

@ -19,16 +19,16 @@ GCOptions::GCOptions()
bool isInStore(const Path & path)
{
return path[0] == '/'
&& string(path, 0, nixStore.size()) == nixStore
&& path.size() >= nixStore.size() + 2
&& path[nixStore.size()] == '/';
&& string(path, 0, settings.nixStore.size()) == settings.nixStore
&& path.size() >= settings.nixStore.size() + 2
&& path[settings.nixStore.size()] == '/';
}
bool isStorePath(const Path & 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))
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)
return path;
else
@ -74,7 +74,7 @@ Path followLinksToStorePath(const Path & path)
string storePathToName(const Path & 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" */
string s = type + ":sha256:" + printHash(hash) + ":"
+ nixStore + ":" + name;
+ settings.nixStore + ":" + name;
checkStoreName(name);
return nixStore + "/"
return settings.nixStore + "/"
+ printHash32(compressHash(hashString(htSHA256, s), 20))
+ "-" + name;
}

View file

@ -55,7 +55,6 @@ struct Globals
EvalState state;
bool dryRun;
bool preserveInstalled;
bool keepDerivations;
string forceName;
bool prebuiltOnly;
};
@ -266,8 +265,8 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems,
if (k != newest.end()) {
d = j->first.system == k->second.first.system ? 0 :
j->first.system == thisSystem ? 1 :
k->second.first.system == thisSystem ? -1 : 0;
j->first.system == settings.thisSystem ? 1 :
k->second.first.system == settings.thisSystem ? -1 : 0;
if (d == 0)
d = comparePriorities(state, j->first, k->second.first);
if (d == 0)
@ -498,7 +497,7 @@ static void installDerivations(Globals & globals,
if (globals.dryRun) return;
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 (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. */
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 (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;
readOnlyMode = true; /* makes evaluation a bit faster */
settings.readOnlyMode = true; /* makes evaluation a bit faster */
for (Strings::iterator i = args.begin(); i != args.end(); ) {
string arg = *i++;
@ -1262,9 +1261,6 @@ void run(Strings args)
globals.preserveInstalled = false;
globals.prebuiltOnly = false;
globals.keepDerivations =
queryBoolSetting("env-keep-derivations", false);
for (Strings::iterator i = args.begin(); i != args.end(); ) {
string arg = *i++;
@ -1331,7 +1327,7 @@ void run(Strings args)
Path profileLink = getHomeDir() + "/.nix-profile";
globals.profile = pathExists(profileLink)
? absPath(readLink(profileLink), dirOf(profileLink))
: canonPath(nixStateDir + "/profiles/default");
: canonPath(settings.nixStateDir + "/profiles/default");
}
store = openStore();

View file

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

View file

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

View file

@ -527,27 +527,23 @@ static void performOp(unsigned int clientVersion,
}
case wopSetOptions: {
keepFailed = readInt(from) != 0;
keepGoing = readInt(from) != 0;
tryFallback = readInt(from) != 0;
settings.keepFailed = readInt(from) != 0;
settings.keepGoing = readInt(from) != 0;
settings.tryFallback = readInt(from) != 0;
verbosity = (Verbosity) readInt(from);
maxBuildJobs = readInt(from);
maxSilentTime = readInt(from);
settings.maxBuildJobs = readInt(from);
settings.maxSilentTime = readInt(from);
if (GET_PROTOCOL_MINOR(clientVersion) >= 2)
useBuildHook = readInt(from) != 0;
settings.useBuildHook = readInt(from) != 0;
if (GET_PROTOCOL_MINOR(clientVersion) >= 4) {
buildVerbosity = (Verbosity) readInt(from);
settings.buildVerbosity = (Verbosity) readInt(from);
logType = (LogType) readInt(from);
printBuildTrace = readInt(from) != 0;
settings.printBuildTrace = readInt(from) != 0;
}
if (GET_PROTOCOL_MINOR(clientVersion) >= 6)
buildCores = readInt(from);
if (GET_PROTOCOL_MINOR(clientVersion) >= 10) {
int x = readInt(from);
Strings ss;
ss.push_back(x == 0 ? "false" : "true");
overrideSetting("build-use-substitutes", ss);
}
settings.buildCores = readInt(from);
if (GET_PROTOCOL_MINOR(clientVersion) >= 10)
settings.useSubstitutes = readInt(from) != 0;
startWork();
stopWork();
break;
@ -768,7 +764,7 @@ static void daemonLoop()
if (fdSocket == -1)
throw SysError("cannot create Unix domain socket");
string socketPath = nixStateDir + DEFAULT_SOCKET_PATH;
string socketPath = settings.nixStateDir + DEFAULT_SOCKET_PATH;
createDirs(dirOf(socketPath));
@ -867,10 +863,6 @@ static void daemonLoop()
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. */
from.fd = remote;
to.fd = remote;