Convert Settings to the new config system

This makes all config options self-documenting.

Unknown or unparseable config settings and --option flags now cause a
warning.
This commit is contained in:
Eelco Dolstra 2017-04-13 20:53:23 +02:00
parent 6bd9576aeb
commit ba9ad29fdb
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
18 changed files with 348 additions and 546 deletions

View file

@ -334,16 +334,6 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
</varlistentry> </varlistentry>
<varlistentry><term><literal>use-binary-caches</literal></term>
<listitem><para>If set to <literal>true</literal> (the default),
Nix will check the binary caches specified by
<option>binary-caches</option> and related options to obtain
binary substitutes.</para></listitem>
</varlistentry>
<varlistentry><term><literal>binary-caches</literal></term> <varlistentry><term><literal>binary-caches</literal></term>
<listitem><para>A list of URLs of binary caches, separated by <listitem><para>A list of URLs of binary caches, separated by

View file

@ -20,12 +20,6 @@ $useBindings = 1;
%config = (); %config = ();
sub readConfig { sub readConfig {
if (defined $ENV{'_NIX_OPTIONS'}) {
foreach my $s (split '\n', $ENV{'_NIX_OPTIONS'}) {
my ($n, $v) = split '=', $s, 2;
$config{$n} = $v;
}
} else {
my $config = "$confDir/nix.conf"; my $config = "$confDir/nix.conf";
return unless -f $config; return unless -f $config;
@ -35,7 +29,6 @@ sub readConfig {
$config{$1} = $2; $config{$1} = $2;
} }
close CONFIG; close CONFIG;
}
} }
return 1; return 1;

View file

@ -22,7 +22,11 @@ MixCommonArgs::MixCommonArgs(const string & programName)
[](Strings ss) { [](Strings ss) {
auto name = ss.front(); ss.pop_front(); auto name = ss.front(); ss.pop_front();
auto value = ss.front(); auto value = ss.front();
try {
settings.set(name, value); settings.set(name, value);
} catch (UsageError & e) {
warn(e.what());
}
}); });
} }

View file

@ -138,9 +138,6 @@ void initNix()
struct timeval tv; struct timeval tv;
gettimeofday(&tv, 0); gettimeofday(&tv, 0);
srandom(tv.tv_usec); srandom(tv.tv_usec);
if (char *pack = getenv("_NIX_OPTIONS"))
settings.unpack(pack);
} }
@ -156,10 +153,10 @@ struct LegacyArgs : public MixCommonArgs
&settings.verboseBuild, false); &settings.verboseBuild, false);
mkFlag('K', "keep-failed", "keep temporary directories of failed builds", mkFlag('K', "keep-failed", "keep temporary directories of failed builds",
&settings.keepFailed); &(bool&) settings.keepFailed);
mkFlag('k', "keep-going", "keep going after a build fails", mkFlag('k', "keep-going", "keep going after a build fails",
&settings.keepGoing); &(bool&) settings.keepGoing);
mkFlag(0, "fallback", "build from source if substitution fails", []() { mkFlag(0, "fallback", "build from source if substitution fails", []() {
settings.set("build-fallback", "true"); settings.set("build-fallback", "true");
@ -184,7 +181,7 @@ struct LegacyArgs : public MixCommonArgs
&settings.readOnlyMode); &settings.readOnlyMode);
mkFlag(0, "no-build-hook", "disable use of the build hook mechanism", mkFlag(0, "no-build-hook", "disable use of the build hook mechanism",
&settings.useBuildHook, false); &(bool&) settings.useBuildHook, false);
mkFlag(0, "show-trace", "show Nix expression stack trace in evaluation errors", mkFlag(0, "show-trace", "show Nix expression stack trace in evaluation errors",
&settings.showTrace); &settings.showTrace);
@ -218,7 +215,6 @@ void parseCmdLine(int argc, char * * argv,
std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg) std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
{ {
LegacyArgs(baseNameOf(argv[0]), parseArg).parseCmdline(argvToStrings(argc, argv)); LegacyArgs(baseNameOf(argv[0]), parseArg).parseCmdline(argvToStrings(argc, argv));
settings.update();
} }

View file

@ -462,7 +462,7 @@ UserLock::UserLock()
assert(settings.buildUsersGroup != ""); assert(settings.buildUsersGroup != "");
/* Get the members of the build-users-group. */ /* Get the members of the build-users-group. */
struct group * gr = getgrnam(settings.buildUsersGroup.c_str()); struct group * gr = getgrnam(settings.buildUsersGroup.get().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")
% settings.buildUsersGroup); % settings.buildUsersGroup);
@ -1690,10 +1690,7 @@ void DerivationGoal::startBuilder()
/* Are we doing a chroot build? */ /* Are we doing a chroot build? */
{ {
string x = settings.useSandbox; if (settings.sandboxMode == smEnabled) {
if (x != "true" && x != "false" && x != "relaxed")
throw Error("option build-use-sandbox must be set to one of true, false or relaxed");
if (x == "true") {
if (get(drv->env, "__noChroot") == "1") if (get(drv->env, "__noChroot") == "1")
throw Error(format("derivation %1% has __noChroot set, " throw Error(format("derivation %1% has __noChroot set, "
"but that's not allowed when build-use-sandbox is true") % drvPath); "but that's not allowed when build-use-sandbox is true") % drvPath);
@ -1704,9 +1701,9 @@ void DerivationGoal::startBuilder()
#endif #endif
useChroot = true; useChroot = true;
} }
else if (x == "false") else if (settings.sandboxMode == smDisabled)
useChroot = false; useChroot = false;
else if (x == "relaxed") else if (settings.sandboxMode == smRelaxed)
useChroot = !fixedOutput && get(drv->env, "__noChroot") != "1"; useChroot = !fixedOutput && get(drv->env, "__noChroot") != "1";
} }

View file

@ -105,12 +105,12 @@ PublicKeys getDefaultPublicKeys()
// FIXME: filter duplicates // FIXME: filter duplicates
for (auto s : settings.binaryCachePublicKeys) { for (auto s : settings.binaryCachePublicKeys.get()) {
PublicKey key(s); PublicKey key(s);
publicKeys.emplace(key.name, key); publicKeys.emplace(key.name, key);
} }
for (auto secretKeyFile : settings.secretKeyFiles) { for (auto secretKeyFile : settings.secretKeyFiles.get()) {
try { try {
SecretKey secretKey(readFile(secretKeyFile)); SecretKey secretKey(readFile(secretKeyFile));
publicKeys.emplace(secretKey.name, secretKey.toPublicKey()); publicKeys.emplace(secretKey.name, secretKey.toPublicKey());

View file

@ -251,7 +251,7 @@ struct CurlDownloader : public Downloader
/* If no file exist in the specified path, curl continues to work /* If no file exist in the specified path, curl continues to work
anyway as if netrc support was disabled. */ anyway as if netrc support was disabled. */
curl_easy_setopt(req, CURLOPT_NETRC_FILE, settings.netrcFile.c_str()); curl_easy_setopt(req, CURLOPT_NETRC_FILE, settings.netrcFile.get().c_str());
curl_easy_setopt(req, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); curl_easy_setopt(req, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
result.data = std::make_shared<std::string>(); result.data = std::make_shared<std::string>();

View file

@ -1,6 +1,7 @@
#include "globals.hh" #include "globals.hh"
#include "util.hh" #include "util.hh"
#include "archive.hh" #include "archive.hh"
#include "args.hh"
#include <algorithm> #include <algorithm>
#include <map> #include <map>
@ -26,329 +27,89 @@ namespace nix {
Settings settings; Settings settings;
Settings::Settings() Settings::Settings()
: Config({})
, nixPrefix(NIX_PREFIX)
, 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)))
, 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)))
, nixDaemonSocketFile(canonPath(nixStateDir + DEFAULT_SOCKET_PATH))
{ {
deprecatedOptions = StringSet({
"build-use-chroot", "build-chroot-dirs", "build-extra-chroot-dirs",
"this-option-never-existed-but-who-will-know"
});
nixPrefix = NIX_PREFIX;
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));
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));
nixDaemonSocketFile = canonPath(nixStateDir + DEFAULT_SOCKET_PATH);
// should be set with the other config options, but depends on nixLibexecDir
#ifdef __APPLE__
preBuildHook = nixLibexecDir + "/nix/resolve-system-dependencies";
#endif
keepFailed = false;
keepGoing = false;
tryFallback = false;
maxBuildJobs = 1;
buildCores = std::max(1U, std::thread::hardware_concurrency());
readOnlyMode = false;
thisSystem = SYSTEM;
maxSilentTime = 0;
buildTimeout = 0;
useBuildHook = true;
reservedSize = 8 * 1024 * 1024;
fsyncMetadata = true;
useSQLiteWAL = true;
syncBeforeRegistering = false;
useSubstitutes = true;
buildUsersGroup = getuid() == 0 ? "nixbld" : ""; buildUsersGroup = getuid() == 0 ? "nixbld" : "";
useSshSubstituter = true;
impersonateLinux26 = false;
keepLog = true;
compressLog = true;
maxLogSize = 0;
pollInterval = 5;
checkRootReachability = false;
gcKeepOutputs = false;
gcKeepDerivations = true;
autoOptimiseStore = false;
envKeepDerivations = false;
lockCPU = getEnv("NIX_AFFINITY_HACK", "1") == "1"; lockCPU = getEnv("NIX_AFFINITY_HACK", "1") == "1";
showTrace = false;
enableNativeCode = false;
netrcFile = fmt("%s/%s", nixConfDir, "netrc");
caFile = getEnv("NIX_SSL_CERT_FILE", getEnv("SSL_CERT_FILE", "/etc/ssl/certs/ca-certificates.crt")); caFile = getEnv("NIX_SSL_CERT_FILE", getEnv("SSL_CERT_FILE", "/etc/ssl/certs/ca-certificates.crt"));
enableImportFromDerivation = true;
useSandbox = "false"; // TODO: make into an enum
#if __linux__ #if __linux__
sandboxPaths = tokenizeString<StringSet>("/bin/sh=" BASH_PATH); sandboxPaths = tokenizeString<StringSet>("/bin/sh=" BASH_PATH);
#endif #endif
restrictEval = false;
buildRepeat = 0;
allowedImpureHostPrefixes = tokenizeString<StringSet>(DEFAULT_ALLOWED_IMPURE_PREFIXES); allowedImpureHostPrefixes = tokenizeString<StringSet>(DEFAULT_ALLOWED_IMPURE_PREFIXES);
sandboxShmSize = "50%";
darwinLogSandboxViolations = false;
runDiffHook = false;
diffHook = "";
enforceDeterminism = true;
binaryCachePublicKeys = Strings{"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="};
secretKeyFiles = Strings();
binaryCachesParallelConnections = 25;
enableHttp2 = true;
tarballTtl = 60 * 60;
signedBinaryCaches = "";
substituters = Strings();
binaryCaches = nixStore == "/nix/store" ? Strings{"https://cache.nixos.org/"} : Strings();
extraBinaryCaches = Strings();
trustedUsers = Strings({"root"});
allowedUsers = Strings({"*"});
printMissing = true;
} }
void Settings::loadConfFile() void Settings::loadConfFile()
{ {
Path settingsFile = (format("%1%/%2%") % nixConfDir % "nix.conf").str(); applyConfigFile(nixConfDir + "/nix.conf");
if (!pathExists(settingsFile)) return;
string contents = readFile(settingsFile);
unsigned int pos = 0;
while (pos < contents.size()) {
string line;
while (pos < contents.size() && contents[pos] != '\n')
line += contents[pos++];
pos++;
string::size_type hash = line.find('#');
if (hash != string::npos)
line = string(line, 0, hash);
vector<string> tokens = tokenizeString<vector<string> >(line);
if (tokens.empty()) continue;
if (tokens.size() < 2 || tokens[1] != "=")
throw Error(format("illegal configuration line %1% in %2%") % line % settingsFile);
string name = tokens[0];
vector<string>::iterator i = tokens.begin();
advance(i, 2);
settings[name] = concatStringsSep(" ", Strings(i, tokens.end())); // FIXME: slow
};
} }
void Settings::set(const string & name, const string & value) void Settings::set(const string & name, const string & value)
{ {
settings[name] = value;
overrides[name] = value; overrides[name] = value;
Config::set(name, value);
} }
void Settings::update() StringMap Settings::getOverrides()
{
_get(tryFallback, "build-fallback");
std::string s = "1";
_get(s, "build-max-jobs");
if (s == "auto")
maxBuildJobs = std::max(1U, std::thread::hardware_concurrency());
else
if (!string2Int(s, maxBuildJobs))
throw Error("configuration setting build-max-jobs should be auto or an integer");
_get(buildCores, "build-cores");
_get(thisSystem, "system");
_get(maxSilentTime, "build-max-silent-time");
_get(buildTimeout, "build-timeout");
_get(reservedSize, "gc-reserved-space");
_get(fsyncMetadata, "fsync-metadata");
_get(useSQLiteWAL, "use-sqlite-wal");
_get(syncBeforeRegistering, "sync-before-registering");
_get(useSubstitutes, "build-use-substitutes");
_get(buildUsersGroup, "build-users-group");
_get(impersonateLinux26, "build-impersonate-linux-26");
_get(keepLog, "build-keep-log");
_get(compressLog, "build-compress-log");
_get(maxLogSize, "build-max-log-size");
_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");
_get(sshSubstituterHosts, "ssh-substituter-hosts");
_get(useSshSubstituter, "use-ssh-substituter");
_get(enableNativeCode, "allow-unsafe-native-code-during-evaluation");
_get(useCaseHack, "use-case-hack");
_get(preBuildHook, "pre-build-hook");
_get(keepGoing, "keep-going");
_get(keepFailed, "keep-failed");
_get(netrcFile, "netrc-file");
_get(enableImportFromDerivation, "allow-import-from-derivation");
_get(useSandbox, "build-use-sandbox", "build-use-chroot");
_get(sandboxPaths, "build-sandbox-paths", "build-chroot-dirs");
_get(extraSandboxPaths, "build-extra-sandbox-paths", "build-extra-chroot-dirs");
_get(restrictEval, "restrict-eval");
_get(buildRepeat, "build-repeat");
_get(allowedImpureHostPrefixes, "allowed-impure-host-deps");
_get(sandboxShmSize, "sandbox-dev-shm-size");
_get(darwinLogSandboxViolations, "darwin-log-sandbox-violations");
_get(runDiffHook, "run-diff-hook");
_get(diffHook, "diff-hook");
_get(enforceDeterminism, "enforce-determinism");
_get(binaryCachePublicKeys, "binary-cache-public-keys");
_get(secretKeyFiles, "secret-key-files");
_get(binaryCachesParallelConnections, "binary-caches-parallel-connections");
_get(enableHttp2, "enable-http2");
_get(tarballTtl, "tarball-ttl");
_get(signedBinaryCaches, "signed-binary-caches");
_get(substituters, "substituters");
_get(binaryCaches, "binary-caches");
_get(extraBinaryCaches, "extra-binary-caches");
_get(trustedUsers, "trusted-users");
_get(allowedUsers, "allowed-users");
_get(printMissing, "print-missing");
/* Clear out any deprecated options that might be left, so users know we recognize the option
but aren't processing it anymore */
for (auto &i : deprecatedOptions) {
if (settings.find(i) != settings.end()) {
printError(format("warning: deprecated option '%1%' is no longer supported and will be ignored") % i);
settings.erase(i);
}
}
if (settings.size() != 0) {
string bad;
for (auto &i : settings)
bad += "'" + i.first + "', ";
bad.pop_back();
bad.pop_back();
throw Error(format("unrecognized options: %s") % bad);
}
}
void Settings::checkDeprecated(const string & name)
{
if (deprecatedOptions.find(name) != deprecatedOptions.end())
printError(format("warning: deprecated option '%1%' will soon be unsupported") % name);
}
void Settings::_get(string & res, const string & name)
{
SettingsMap::iterator i = settings.find(name);
if (i == settings.end()) return;
checkDeprecated(i->first);
settings.erase(i);
res = i->second;
}
void Settings::_get(string & res, const string & name1, const string & name2)
{
SettingsMap::iterator i = settings.find(name1);
if (i == settings.end()) i = settings.find(name2);
if (i == settings.end()) return;
checkDeprecated(i->first);
settings.erase(i);
res = i->second;
}
void Settings::_get(bool & res, const string & name)
{
SettingsMap::iterator i = settings.find(name);
if (i == settings.end()) return;
checkDeprecated(i->first);
settings.erase(i);
if (i->second == "true") res = true;
else if (i->second == "false") res = false;
else throw Error(format("configuration option %1% should be either true or false, not %2%")
% name % i->second);
}
void Settings::_get(StringSet & res, const string & name)
{
SettingsMap::iterator i = settings.find(name);
if (i == settings.end()) return;
checkDeprecated(i->first);
settings.erase(i);
res.clear();
Strings ss = tokenizeString<Strings>(i->second);
res.insert(ss.begin(), ss.end());
}
void Settings::_get(StringSet & res, const string & name1, const string & name2)
{
SettingsMap::iterator i = settings.find(name1);
if (i == settings.end()) i = settings.find(name2);
if (i == settings.end()) return;
checkDeprecated(i->first);
settings.erase(i);
res.clear();
Strings ss = tokenizeString<Strings>(i->second);
res.insert(ss.begin(), ss.end());
}
void Settings::_get(Strings & res, const string & name)
{
SettingsMap::iterator i = settings.find(name);
if (i == settings.end()) return;
checkDeprecated(i->first);
settings.erase(i);
res = tokenizeString<Strings>(i->second);
}
template<class N> void Settings::_get(N & res, const string & name)
{
SettingsMap::iterator i = settings.find(name);
if (i == settings.end()) return;
checkDeprecated(i->first);
settings.erase(i);
if (!string2Int(i->second, res))
throw Error(format("configuration setting %1% should have an integer value") % name);
}
string Settings::pack()
{
string s;
for (auto & i : settings) {
if (i.first.find('\n') != string::npos ||
i.first.find('=') != string::npos ||
i.second.find('\n') != string::npos)
throw Error("illegal option name/value");
s += i.first; s += '='; s += i.second; s += '\n';
}
return s;
}
void Settings::unpack(const string & pack) {
Strings lines = tokenizeString<Strings>(pack, "\n");
for (auto & i : lines) {
string::size_type eq = i.find('=');
if (eq == string::npos)
throw Error("illegal option name/value");
set(i.substr(0, eq), i.substr(eq + 1));
}
}
Settings::SettingsMap Settings::getOverrides()
{ {
return overrides; return overrides;
} }
unsigned int Settings::getDefaultCores()
{
return std::max(1U, std::thread::hardware_concurrency());
}
const string nixVersion = PACKAGE_VERSION; const string nixVersion = PACKAGE_VERSION;
template<> void Setting<SandboxMode>::set(const std::string & str)
{
if (str == "true") value = smEnabled;
else if (str == "relaxed") value = smRelaxed;
else if (str == "false") value = smDisabled;
else throw UsageError("option '%s' has invalid value '%s'", name, str);
}
template<> std::string Setting<SandboxMode>::to_string()
{
if (value == smEnabled) return "true";
else if (value == smRelaxed) return "relaxed";
else if (value == smDisabled) return "false";
else abort();
}
template<> void Setting<unsigned int, Settings::MaxBuildJobsTag>::set(const std::string & str)
{
if (str == "auto") value = std::max(1U, std::thread::hardware_concurrency());
else if (!string2Int(str, value))
throw UsageError("configuration setting %s should be auto or an integer", name);
}
template<> std::string Setting<unsigned int, Settings::MaxBuildJobsTag>::to_string()
{
return std::to_string(value);
}
template<> void Setting<bool, Settings::CaseHackTag>::set(const std::string & str)
{
value = parseBool(str);
nix::useCaseHack = true;
}
template<> std::string Setting<bool, Settings::CaseHackTag>::to_string()
{
return printBool(value);
}
} }

View file

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "types.hh" #include "types.hh"
#include "logging.hh" #include "config.hh"
#include <map> #include <map>
#include <sys/types.h> #include <sys/types.h>
@ -9,10 +9,17 @@
namespace nix { namespace nix {
typedef enum { smEnabled, smRelaxed, smDisabled } SandboxMode;
struct Settings { extern bool useCaseHack; // FIXME
typedef std::map<string, string> SettingsMap; class Settings : public Config {
StringMap overrides;
unsigned int getDefaultCores();
public:
Settings(); Settings();
@ -20,25 +27,15 @@ struct Settings {
void set(const string & name, const string & value); void set(const string & name, const string & value);
void update(); StringMap getOverrides();
string pack(); Path nixPrefix;
void unpack(const string & pack);
SettingsMap getOverrides();
/* TODO: the comments below should be strings and exposed via a nice command-line UI or similar.
We should probably replace it with some sort of magic template or macro to minimize the amount
of duplication and pain here. */
/* The directory where we store sources and derived files. */ /* The directory where we store sources and derived files. */
Path nixStore; Path nixStore;
Path nixDataDir; /* !!! fix */ Path nixDataDir; /* !!! fix */
Path nixPrefix;
/* The directory where we log various operations. */ /* The directory where we log various operations. */
Path nixLogDir; Path nixLogDir;
@ -57,17 +54,14 @@ struct Settings {
/* File name of the socket the daemon listens to. */ /* File name of the socket the daemon listens to. */
Path nixDaemonSocketFile; Path nixDaemonSocketFile;
/* Whether to keep temporary directories of failed builds. */ Setting<bool> keepFailed{this, false, "keep-failed",
bool keepFailed; "Whether to keep temporary directories of failed builds."};
/* Whether to keep building subgoals when a sibling (another Setting<bool> keepGoing{this, false, "keep-going",
subgoal of the same goal) fails. */ "Whether to keep building derivations when another build fails."};
bool keepGoing;
/* Whether, if we cannot realise the known closure corresponding Setting<bool> tryFallback{this, tryFallback, "build-fallback",
to a derivation, we should try to normalise the derivation "Whether to fall back to building when substitution fails."};
instead. */
bool tryFallback;
/* Whether to show build log output in real time. */ /* Whether to show build log output in real time. */
bool verboseBuild = true; bool verboseBuild = true;
@ -76,206 +70,206 @@ struct Settings {
the log to show if a build fails. */ the log to show if a build fails. */
size_t logLines = 10; size_t logLines = 10;
/* Maximum number of parallel build jobs. 0 means unlimited. */ struct MaxBuildJobsTag { };
unsigned int maxBuildJobs; Setting<unsigned int, MaxBuildJobsTag> maxBuildJobs{this, 1, "build-max-jobs",
"Maximum number of parallel build jobs. \"auto\" means use number of cores."};
/* Number of CPU cores to utilize in parallel within a build, Setting<unsigned int> buildCores{this, getDefaultCores(), "build-cores",
i.e. by passing this number to Make via '-j'. 0 means that the "Number of CPU cores to utilize in parallel within a build, "
number of actual CPU cores on the local host ought to be "i.e. by passing this number to Make via '-j'. 0 means that the "
auto-detected. */ "number of actual CPU cores on the local host ought to be "
unsigned int buildCores; "auto-detected."};
/* Read-only mode. Don't copy stuff to the store, don't change /* Read-only mode. Don't copy stuff to the store, don't change
the database. */ the database. */
bool readOnlyMode; bool readOnlyMode = false;
/* The canonical system name, as returned by config.guess. */ Setting<std::string> thisSystem{this, SYSTEM, "system",
string thisSystem; "The canonical Nix system name."};
/* The maximum time in seconds that a builer can go without Setting<time_t> maxSilentTime{this, 0, "build-max-silent-time",
producing any output on stdout/stderr before it is killed. 0 "The maximum time in seconds that a builer can go without "
means infinity. */ "producing any output on stdout/stderr before it is killed. "
time_t maxSilentTime; "0 means infinity."};
/* The maximum duration in seconds that a builder can run. 0 Setting<time_t> buildTimeout{this, 0, "build-timeout",
means infinity. */ "The maximum duration in seconds that a builder can run. "
time_t buildTimeout; "0 means infinity."};
/* Whether to use build hooks (for distributed builds). Sometimes Setting<bool> useBuildHook{this, true, "remote-builds",
users want to disable this from the command-line. */ "Whether to use build hooks (for distributed builds)."};
bool useBuildHook;
/* Amount of reserved space for the garbage collector Setting<off_t> reservedSize{this, 8 * 1024 * 1024, "gc-reserved-space",
(/nix/var/nix/db/reserved). */ "Amount of reserved disk space for the garbage collector."};
off_t reservedSize;
/* Whether SQLite should use fsync. */ Setting<bool> fsyncMetadata{this, true, "fsync-metadata",
bool fsyncMetadata; "Whether SQLite should use fsync()."};
/* Whether SQLite should use WAL mode. */ Setting<bool> useSQLiteWAL{this, true, "use-sqlite-wal",
bool useSQLiteWAL; "Whether SQLite should use WAL mode."};
/* Whether to call sync() before registering a path as valid. */ Setting<bool> syncBeforeRegistering{this, false, "sync-before-registering",
bool syncBeforeRegistering; "Whether to call sync() before registering a path as valid."};
/* Whether to use substitutes. */ Setting<bool> useSubstitutes{this, true, "build-use-substitutes",
bool useSubstitutes; "Whether to use substitutes."};
/* The Unix group that contains the build users. */ Setting<std::string> buildUsersGroup{this, "", "build-users-group",
string buildUsersGroup; "The Unix group that contains the build users."};
/* Set of ssh connection strings for the ssh substituter */ Setting<bool> impersonateLinux26{this, false, "build-impersonate-linux-26",
Strings sshSubstituterHosts; "Whether to impersonate a Linux 2.6 machine on newer kernels."};
/* Whether to use the ssh substituter at all */ Setting<bool> keepLog{this, true, "build-keep-log",
bool useSshSubstituter; "Whether to store build logs."};
/* Whether to impersonate a Linux 2.6 machine on newer kernels. */ Setting<bool> compressLog{this, true, "build-compress-log",
bool impersonateLinux26; "Whether to compress logs."};
/* Whether to store build logs. */ Setting<unsigned long> maxLogSize{this, 0, "build-max-log-size",
bool keepLog; "Maximum number of bytes a builder can write to stdout/stderr "
"before being killed (0 means no limit)."};
/* Whether to compress logs. */
bool compressLog;
/* Maximum number of bytes a builder can write to stdout/stderr
before being killed (0 means no limit). */
unsigned long maxLogSize;
/* When build-repeat > 0 and verboseBuild == true, whether to /* When build-repeat > 0 and verboseBuild == true, whether to
print repeated builds (i.e. builds other than the first one) to print repeated builds (i.e. builds other than the first one) to
stderr. Hack to prevent Hydra logs from being polluted. */ stderr. Hack to prevent Hydra logs from being polluted. */
bool printRepeatedBuilds = true; bool printRepeatedBuilds = true;
/* How often (in seconds) to poll for locks. */ Setting<unsigned int> pollInterval{this, 5, "build-poll-interval",
unsigned int pollInterval; "How often (in seconds) to poll for locks."};
/* Whether to check if new GC roots can in fact be found by the Setting<bool> checkRootReachability{this, false, "gc-check-reachability",
garbage collector. */ "Whether to check if new GC roots can in fact be found by the "
bool checkRootReachability; "garbage collector."};
/* Whether the garbage collector should keep outputs of live Setting<bool> gcKeepOutputs{this, false, "gc-keep-outputs",
derivations. */ "Whether the garbage collector should keep outputs of live derivations."};
bool gcKeepOutputs;
/* Whether the garbage collector should keep derivers of live Setting<bool> gcKeepDerivations{this, true, "gc-keep-derivations",
paths. */ "Whether the garbage collector should keep derivers of live paths."};
bool gcKeepDerivations;
/* Whether to automatically replace files with identical contents Setting<bool> autoOptimiseStore{this, false, "auto-optimise-store",
with hard links. */ "Whether to automatically replace files with identical contents with hard links."};
bool autoOptimiseStore;
/* Whether to add derivations as a dependency of user environments Setting<bool> envKeepDerivations{this, false, "env-keep-derivations",
(to prevent them from being GCed). */ "Whether to add derivations as a dependency of user environments "
bool envKeepDerivations; "(to prevent them from being GCed)."};
/* Whether to lock the Nix client and worker to the same CPU. */ /* Whether to lock the Nix client and worker to the same CPU. */
bool lockCPU; bool lockCPU;
/* Whether to show a stack trace if Nix evaluation fails. */ /* Whether to show a stack trace if Nix evaluation fails. */
bool showTrace; bool showTrace = false;
/* Whether native-code enabling primops should be enabled */ Setting<bool> enableNativeCode{this, false, "allow-unsafe-native-code-during-evaluation",
bool enableNativeCode; "Whether builtin functions that allow executing native code should be enabled."};
/* Whether to enable sandboxed builds (string until we get an enum for true/false/relaxed) */ Setting<SandboxMode> sandboxMode{this, smDisabled, "build-use-sandbox",
string useSandbox; "Whether to enable sandboxed builds. Can be \"true\", \"false\" or \"relaxed\".",
{"build-use-chroot"}};
/* The basic set of paths to expose in a sandbox */ Setting<PathSet> sandboxPaths{this, {}, "build-sandbox-paths",
PathSet sandboxPaths; "The paths to make available inside the build sandbox.",
{"build-chroot-dirs"}};
/* Any extra sandbox paths to expose */ Setting<PathSet> extraSandboxPaths{this, {}, "build-extra-sandbox-paths",
PathSet extraSandboxPaths; "Additional paths to make available inside the build sandbox.",
{"build-extra-chroot-dirs"}};
/* Whether to allow certain questionable operations (like fetching) during evaluation */ Setting<bool> restrictEval{this, false, "restrict-eval",
bool restrictEval; "Whether to restrict file system access to paths in $NIX_PATH, "
"and to disallow fetching files from the network."};
/* The number of times to repeat a build to check for determinism */ Setting<size_t> buildRepeat{this, 0, "build-repeat",
int buildRepeat; "The number of times to repeat a build in order to verify determinism."};
/* Which prefixes to allow derivations to ask for access to (primarily for Darwin) */ #if __linux__
PathSet allowedImpureHostPrefixes; Setting<std::string> sandboxShmSize{this, "50%", "sandbox-dev-shm-size",
"The size of /dev/shm in the build sandbox."};
#endif
/* The size of /dev/shm in the build sandbox (for Linux) */ Setting<PathSet> allowedImpureHostPrefixes{this, {}, "allowed-impure-host-deps",
string sandboxShmSize; "Which prefixes to allow derivations to ask for access to (primarily for Darwin)."};
/* Whether to log Darwin sandbox access violations to the system log */ #if __APPLE__
bool darwinLogSandboxViolations; Setting<bool> darwinLogSandboxViolations{this, false, "darwin-log-sandbox-violations",
"Whether to log Darwin sandbox access violations to the system log."};
#endif
/* ??? */ Setting<bool> runDiffHook{this, false, "run-diff-hook",
bool runDiffHook; "Whether to run the program specified by the diff-hook setting "
"repeated builds produce a different result. Typically used to "
"plug in diffoscope."};
/* ??? */ PathSetting diffHook{this, true, "", "diff-hook",
string diffHook; "A program that prints out the differences between the two paths "
"specified on its command line."};
/* Whether to fail if repeated builds produce different output */ Setting<bool> enforceDeterminism{this, true, "enforce-determinism",
bool enforceDeterminism; "Whether to fail if repeated builds produce different output."};
/* The known public keys for a binary cache */ Setting<Strings> binaryCachePublicKeys{this,
Strings binaryCachePublicKeys; {"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="},
"binary-cache-public-keys",
"Trusted public keys for secure substitution."};
/* Secret keys to use for build output signing */ Setting<Strings> secretKeyFiles{this, {}, "secret-key-files",
Strings secretKeyFiles; "Secret keys with which to sign local builds."};
/* Number of parallel connections to hit a binary cache with when finding out if it contains hashes */ Setting<size_t> binaryCachesParallelConnections{this, 25, "binary-caches-parallel-connections",
int binaryCachesParallelConnections; "Number of parallel connections to binary caches."};
/* Whether to enable HTTP2 */ Setting<bool> enableHttp2{this, true, "enable-http2",
bool enableHttp2; "Whether to enable HTTP/2 support."};
/* How soon to expire tarballs like builtins.fetchTarball and (ugh, bad name) builtins.fetchurl */ Setting<unsigned int> tarballTtl{this, 60 * 60, "tarball-ttl",
int tarballTtl; "How soon to expire files fetched by builtins.fetchTarball and builtins.fetchurl."};
/* ??? */ Setting<std::string> signedBinaryCaches{this, "*", "signed-binary-caches",
string signedBinaryCaches; "Obsolete."};
/* ??? */ Setting<Strings> substituters{this,
Strings substituters; nixStore == "/nix/store" ? Strings{"https://cache.nixos.org/"} : Strings(),
"substituters",
"The URIs of substituters (such as https://cache.nixos.org/).",
{"binary-caches"}};
/* ??? */ // FIXME: provide a way to add to option values.
Strings binaryCaches; Setting<Strings> extraSubstituters{this, {}, "extra-substituters",
"Additional URIs of substituters.",
{"extra-binary-caches"}};
/* ??? */ Setting<Strings> trustedUsers{this, {"root"}, "trusted-users",
Strings extraBinaryCaches; "Which users or groups are trusted to ask the daemon to do unsafe things."};
/* Who we trust to ask the daemon to do unsafe things */
Strings trustedUsers;
/* ?Who we trust to use the daemon in safe ways */ /* ?Who we trust to use the daemon in safe ways */
Strings allowedUsers; Setting<Strings> allowedUsers{this, {"*"}, "allowed-users",
"Which users or groups are allowed to connect to the daemon."};
/* ??? */ Setting<bool> printMissing{this, true, "print-missing",
bool printMissing; "Whether to print what paths need to be built or downloaded."};
/* The hook to run just before a build to set derivation-specific Setting<std::string> preBuildHook{this,
build settings */ #if __APPLE__
Path preBuildHook; nixLibexecDir + "/nix/resolve-system-dependencies",
#else
"",
#endif
"pre-build-hook",
"A program to run just before a build to set derivation-specific build settings."};
/* Path to the netrc file used to obtain usernames/passwords for Setting<std::string> netrcFile{this, fmt("%s/%s", nixConfDir, "netrc"), "netrc-file",
downloads. */ "Path to the netrc file used to obtain usernames/passwords for downloads."};
Path netrcFile;
/* Path to the SSL CA file used */ /* Path to the SSL CA file used */
Path caFile; Path caFile;
/* Whether we allow import-from-derivation */ Setting<bool> enableImportFromDerivation{this, true, "allow-import-from-derivation",
bool enableImportFromDerivation; "Whether the evaluator allows importing the result of a derivation."};
private: struct CaseHackTag { };
StringSet deprecatedOptions; Setting<bool, CaseHackTag> useCaseHack{this, nix::useCaseHack, "use-case-hack",
SettingsMap settings, overrides; "Whether to enable a Darwin-specific hack for dealing with file name collisions."};
void checkDeprecated(const string & name);
void _get(string & res, const string & name);
void _get(string & res, const string & name1, const string & name2);
void _get(bool & res, const string & name);
void _get(StringSet & res, const string & name);
void _get(StringSet & res, const string & name1, const string & name2);
void _get(Strings & res, const string & name);
template<class N> void _get(N & res, const string & name);
}; };

View file

@ -75,7 +75,7 @@ LocalStore::LocalStore(const Params & params)
mode_t perm = 01775; mode_t perm = 01775;
struct group * gr = getgrnam(settings.buildUsersGroup.c_str()); struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str());
if (!gr) if (!gr)
printError(format("warning: the group %1% specified in build-users-group does not exist") printError(format("warning: the group %1% specified in build-users-group does not exist")
% settings.buildUsersGroup); % settings.buildUsersGroup);
@ -1335,7 +1335,7 @@ void LocalStore::signPathInfo(ValidPathInfo & info)
auto secretKeyFiles = settings.secretKeyFiles; auto secretKeyFiles = settings.secretKeyFiles;
for (auto & secretKeyFile : secretKeyFiles) { for (auto & secretKeyFile : secretKeyFiles.get()) {
SecretKey secretKey(readFile(secretKeyFile)); SecretKey secretKey(readFile(secretKeyFile));
info.sign(secretKey); info.sign(secretKey);
} }

View file

@ -166,9 +166,7 @@ void RemoteStore::setOptions(Connection & conn)
<< settings.useSubstitutes; << settings.useSubstitutes;
if (GET_PROTOCOL_MINOR(conn.daemonVersion) >= 12) { if (GET_PROTOCOL_MINOR(conn.daemonVersion) >= 12) {
Settings::SettingsMap overrides = settings.getOverrides(); StringMap overrides = settings.getOverrides();
if (overrides["ssh-auth-sock"] == "")
overrides["ssh-auth-sock"] = getEnv("SSH_AUTH_SOCK");
conn.to << overrides.size(); conn.to << overrides.size();
for (auto & i : overrides) for (auto & i : overrides)
conn.to << i.first << i.second; conn.to << i.first << i.second;

View file

@ -719,7 +719,7 @@ ref<Store> openStore(const std::string & uri, const Store::Params & params)
for (auto fun : *RegisterStoreImplementation::implementations) { for (auto fun : *RegisterStoreImplementation::implementations) {
auto store = fun(uri, params); auto store = fun(uri, params);
if (store) { if (store) {
store->warnUnused(); store->warnUnknownSettings();
return ref<Store>(store); return ref<Store>(store);
} }
} }
@ -782,13 +782,10 @@ std::list<ref<Store>> getDefaultSubstituters()
state->stores.push_back(openStore(uri)); state->stores.push_back(openStore(uri));
}; };
for (auto uri : settings.substituters) for (auto uri : settings.substituters.get())
addStore(uri); addStore(uri);
for (auto uri : settings.binaryCaches) for (auto uri : settings.extraSubstituters.get())
addStore(uri);
for (auto uri : settings.extraBinaryCaches)
addStore(uri); addStore(uri);
state->done = true; state->done = true;

View file

@ -11,7 +11,7 @@ void Config::set(const std::string & name, const std::string & value)
i->second.setting->set(value); i->second.setting->set(value);
} }
void Config::add(AbstractSetting * setting) void Config::addSetting(AbstractSetting * setting)
{ {
_settings.emplace(setting->name, Config::SettingData{false, setting}); _settings.emplace(setting->name, Config::SettingData{false, setting});
for (auto & alias : setting->aliases) for (auto & alias : setting->aliases)
@ -41,21 +41,59 @@ void Config::add(AbstractSetting * setting)
} }
} }
void Config::warnUnused() void Config::warnUnknownSettings()
{ {
for (auto & i : initials) for (auto & i : initials)
warn("unknown setting '%s'", i.first); warn("unknown setting '%s'", i.first);
} }
std::string Config::dump() StringMap Config::getSettings()
{ {
std::string res; StringMap res;
for (auto & opt : _settings) for (auto & opt : _settings)
if (!opt.second.isAlias) if (!opt.second.isAlias)
res += opt.first + " = " + opt.second.setting->to_string() + "\n"; res.emplace(opt.first, opt.second.setting->to_string());
return res; return res;
} }
void Config::applyConfigFile(const Path & path, bool fatal)
{
try {
string contents = readFile(path);
unsigned int pos = 0;
while (pos < contents.size()) {
string line;
while (pos < contents.size() && contents[pos] != '\n')
line += contents[pos++];
pos++;
string::size_type hash = line.find('#');
if (hash != string::npos)
line = string(line, 0, hash);
vector<string> tokens = tokenizeString<vector<string> >(line);
if (tokens.empty()) continue;
if (tokens.size() < 2 || tokens[1] != "=")
throw UsageError("illegal configuration line %1% in %2%", line, path);
string name = tokens[0];
vector<string>::iterator i = tokens.begin();
advance(i, 2);
try {
set(name, concatStringsSep(" ", Strings(i, tokens.end()))); // FIXME: slow
} catch (UsageError & e) {
if (fatal) throw;
warn("in configuration file '%s': %s", path, e.what());
}
};
} catch (SysError &) { }
}
AbstractSetting::AbstractSetting( AbstractSetting::AbstractSetting(
const std::string & name, const std::string & name,
const std::string & description, const std::string & description,
@ -74,41 +112,65 @@ template<> std::string Setting<std::string>::to_string()
return value; return value;
} }
template<typename T> template<typename T, typename Tag>
void Setting<T>::set(const std::string & str) void Setting<T, Tag>::set(const std::string & str)
{ {
static_assert(std::is_integral<T>::value, "Integer required."); static_assert(std::is_integral<T>::value, "Integer required.");
try { if (!string2Int(str, value))
auto i = std::stoll(str);
if (i < std::numeric_limits<T>::min() ||
i > std::numeric_limits<T>::max())
throw UsageError("setting '%s' has out-of-range value %d", name, i);
value = i;
} catch (std::logic_error&) {
throw UsageError("setting '%s' has invalid value '%s'", name, str); throw UsageError("setting '%s' has invalid value '%s'", name, str);
}
} }
template<typename T> template<typename T, typename Tag>
std::string Setting<T>::to_string() std::string Setting<T, Tag>::to_string()
{ {
static_assert(std::is_integral<T>::value, "Integer required."); static_assert(std::is_integral<T>::value, "Integer required.");
return std::to_string(value); return std::to_string(value);
} }
template<> void Setting<bool>::set(const std::string & str) bool AbstractSetting::parseBool(const std::string & str)
{ {
if (str == "true" || str == "yes" || str == "1") if (str == "true" || str == "yes" || str == "1")
value = true; return true;
else if (str == "false" || str == "no" || str == "0") else if (str == "false" || str == "no" || str == "0")
value = false; return false;
else else
throw UsageError("Boolean setting '%s' has invalid value '%s'", name, str); throw UsageError("Boolean setting '%s' has invalid value '%s'", name, str);
} }
template<> void Setting<bool>::set(const std::string & str)
{
value = parseBool(str);
}
std::string AbstractSetting::printBool(bool b)
{
return b ? "true" : "false";
}
template<> std::string Setting<bool>::to_string() template<> std::string Setting<bool>::to_string()
{ {
return value ? "true" : "false"; return printBool(value);
}
template<> void Setting<Strings>::set(const std::string & str)
{
value = tokenizeString<Strings>(str);
}
template<> std::string Setting<Strings>::to_string()
{
return concatStringsSep(" ", value);
}
template<> void Setting<StringSet>::set(const std::string & str)
{
value = tokenizeString<StringSet>(str);
}
template<> std::string Setting<StringSet>::to_string()
{
return concatStringsSep(" ", value);
} }
template class Setting<int>; template class Setting<int>;

View file

@ -47,11 +47,13 @@ public:
void set(const std::string & name, const std::string & value); void set(const std::string & name, const std::string & value);
void add(AbstractSetting * setting); void addSetting(AbstractSetting * setting);
void warnUnused(); void warnUnknownSettings();
std::string dump(); StringMap getSettings();
void applyConfigFile(const Path & path, bool fatal = false);
}; };
class AbstractSetting class AbstractSetting
@ -83,10 +85,15 @@ protected:
virtual void set(const std::string & value) = 0; virtual void set(const std::string & value) = 0;
virtual std::string to_string() = 0; virtual std::string to_string() = 0;
bool parseBool(const std::string & str);
std::string printBool(bool b);
}; };
struct DefaultSettingTag { };
/* A setting of type T. */ /* A setting of type T. */
template<typename T> template<typename T, typename Tag = DefaultSettingTag>
class Setting : public AbstractSetting class Setting : public AbstractSetting
{ {
protected: protected:
@ -103,10 +110,12 @@ public:
: AbstractSetting(name, description, aliases) : AbstractSetting(name, description, aliases)
, value(def) , value(def)
{ {
options->add(this); options->addSetting(this);
} }
operator const T &() const { return value; } operator const T &() const { return value; }
operator T &() { return value; }
const T & get() const { return value; }
bool operator ==(const T & v2) const { return value == v2; } bool operator ==(const T & v2) const { return value == v2; }
bool operator !=(const T & v2) const { return value != v2; } bool operator !=(const T & v2) const { return value != v2; }
void operator =(const T & v) { value = v; } void operator =(const T & v) { value = v; }
@ -123,6 +132,9 @@ std::ostream & operator <<(std::ostream & str, const Setting<T> & opt)
return str; return str;
} }
template<typename T>
bool operator ==(const T & v1, const Setting<T> & v2) { return v1 == (const T &) v2; }
/* A special setting for Paths. These are automatically canonicalised /* A special setting for Paths. These are automatically canonicalised
(e.g. "/foo//bar/" becomes "/foo/bar"). */ (e.g. "/foo//bar/" becomes "/foo/bar"). */
class PathSetting : public Setting<Path> class PathSetting : public Setting<Path>

View file

@ -436,30 +436,29 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
} }
case wopSetOptions: { case wopSetOptions: {
from >> settings.keepFailed; settings.keepFailed = readInt(from);
from >> settings.keepGoing; settings.keepGoing = readInt(from);
settings.set("build-fallback", readInt(from) ? "true" : "false"); settings.tryFallback = readInt(from);
verbosity = (Verbosity) readInt(from); verbosity = (Verbosity) readInt(from);
settings.set("build-max-jobs", std::to_string(readInt(from))); settings.set("build-max-jobs", std::to_string(readInt(from)));
settings.set("build-max-silent-time", std::to_string(readInt(from))); settings.maxSilentTime = readInt(from);
settings.useBuildHook = readInt(from) != 0; settings.useBuildHook = readInt(from) != 0;
settings.verboseBuild = lvlError == (Verbosity) readInt(from); settings.verboseBuild = lvlError == (Verbosity) readInt(from);
readInt(from); // obsolete logType readInt(from); // obsolete logType
readInt(from); // obsolete printBuildTrace readInt(from); // obsolete printBuildTrace
settings.set("build-cores", std::to_string(readInt(from))); settings.set("build-cores", std::to_string(readInt(from)));
settings.set("build-use-substitutes", readInt(from) ? "true" : "false"); settings.useSubstitutes = readInt(from);
if (GET_PROTOCOL_MINOR(clientVersion) >= 12) { if (GET_PROTOCOL_MINOR(clientVersion) >= 12) {
unsigned int n = readInt(from); unsigned int n = readInt(from);
for (unsigned int i = 0; i < n; i++) { for (unsigned int i = 0; i < n; i++) {
string name = readString(from); string name = readString(from);
string value = readString(from); string value = readString(from);
if (name == "build-timeout" || name == "use-ssh-substituter") if (name == "build-timeout")
settings.set(name, value); settings.set(name, value);
else else
settings.set(trusted ? name : "untrusted-" + name, value); settings.set(trusted ? name : "untrusted-" + name, value);
} }
} }
settings.update();
startWork(); startWork();
stopWork(); stopWork();
break; break;

View file

@ -795,11 +795,11 @@ static void opServe(Strings opFlags, Strings opArgs)
settings.maxSilentTime = readInt(in); settings.maxSilentTime = readInt(in);
settings.buildTimeout = readInt(in); settings.buildTimeout = readInt(in);
if (GET_PROTOCOL_MINOR(clientVersion) >= 2) if (GET_PROTOCOL_MINOR(clientVersion) >= 2)
in >> settings.maxLogSize; settings.maxLogSize = readNum<unsigned long>(in);
if (GET_PROTOCOL_MINOR(clientVersion) >= 3) { if (GET_PROTOCOL_MINOR(clientVersion) >= 3) {
settings.set("build-repeat", std::to_string(readInt(in))); settings.buildRepeat = readInt(in);
settings.set("enforce-determinism", readInt(in) != 0 ? "true" : "false"); settings.enforceDeterminism = readInt(in);
settings.set("run-diff-hook", "true"); settings.runDiffHook = readInt(in);
} }
settings.printRepeatedBuilds = false; settings.printRepeatedBuilds = false;
}; };

View file

@ -42,7 +42,6 @@ void mainWrapped(int argc, char * * argv)
NixArgs args; NixArgs args;
args.parseCmdline(argvToStrings(argc, argv)); args.parseCmdline(argvToStrings(argc, argv));
settings.update();
assert(args.command); assert(args.command);

View file

@ -1,4 +1,4 @@
#! @ENV_PROG@ nix-shell #! @ENV_PROG@ nix-shell
#! nix-shell -I nixpkgs=shell.nix --option use-binary-caches false #! nix-shell -I nixpkgs=shell.nix --option build-use-substitutes false
#! nix-shell --pure -i bash -p foo bar #! nix-shell --pure -i bash -p foo bar
echo "$(foo) $(bar) $@" echo "$(foo) $(bar) $@"