forked from lix-project/lix
Refactor settings processing
Put all Nix configuration flags in a Settings object.
This commit is contained in:
parent
d50d7a2874
commit
97421eb5ec
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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++);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue