forked from lix-project/lix
Modularize config settings
Allow global config settings to be defined in multiple Config classes. For example, this means that libutil can have settings and evaluator settings can be moved out of libstore. The Config classes are registered in a new GlobalConfig class to which config files etc. are applied. Relevant to https://github.com/NixOS/nix/issues/2009 in that it removes the need for ad hoc handling of useCaseHack, which was the underlying cause of that issue.
This commit is contained in:
parent
e606cd412f
commit
737ed88f35
|
@ -27,7 +27,7 @@ static ref<Store> store()
|
||||||
static std::shared_ptr<Store> _store;
|
static std::shared_ptr<Store> _store;
|
||||||
if (!_store) {
|
if (!_store) {
|
||||||
try {
|
try {
|
||||||
settings.loadConfFile();
|
loadConfFile();
|
||||||
settings.lockCPU = false;
|
settings.lockCPU = false;
|
||||||
_store = openStore();
|
_store = openStore();
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
|
|
|
@ -29,14 +29,14 @@ MixCommonArgs::MixCommonArgs(const string & programName)
|
||||||
.arity(2)
|
.arity(2)
|
||||||
.handler([](std::vector<std::string> ss) {
|
.handler([](std::vector<std::string> ss) {
|
||||||
try {
|
try {
|
||||||
settings.set(ss[0], ss[1]);
|
globalConfig.set(ss[0], ss[1]);
|
||||||
} catch (UsageError & e) {
|
} catch (UsageError & e) {
|
||||||
warn(e.what());
|
warn(e.what());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
std::string cat = "config";
|
std::string cat = "config";
|
||||||
settings.convertToArgs(*this, cat);
|
globalConfig.convertToArgs(*this, cat);
|
||||||
|
|
||||||
// Backward compatibility hack: nix-env already had a --system flag.
|
// Backward compatibility hack: nix-env already had a --system flag.
|
||||||
if (programName == "nix-env") longFlags.erase("system");
|
if (programName == "nix-env") longFlags.erase("system");
|
||||||
|
|
|
@ -109,7 +109,7 @@ void initNix()
|
||||||
opensslLocks = std::vector<std::mutex>(CRYPTO_num_locks());
|
opensslLocks = std::vector<std::mutex>(CRYPTO_num_locks());
|
||||||
CRYPTO_set_locking_callback(opensslLockCallback);
|
CRYPTO_set_locking_callback(opensslLockCallback);
|
||||||
|
|
||||||
settings.loadConfFile();
|
loadConfFile();
|
||||||
|
|
||||||
startSignalHandlerThread();
|
startSignalHandlerThread();
|
||||||
|
|
||||||
|
|
|
@ -672,8 +672,10 @@ HookInstance::HookInstance()
|
||||||
toHook.readSide = -1;
|
toHook.readSide = -1;
|
||||||
|
|
||||||
sink = FdSink(toHook.writeSide.get());
|
sink = FdSink(toHook.writeSide.get());
|
||||||
for (auto & setting : settings.getSettings())
|
std::map<std::string, Config::SettingInfo> settings;
|
||||||
sink << 1 << setting.first << setting.second;
|
globalConfig.getSettings(settings);
|
||||||
|
for (auto & setting : settings)
|
||||||
|
sink << 1 << setting.first << setting.second.value;
|
||||||
sink << 0;
|
sink << 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,9 +28,10 @@ namespace nix {
|
||||||
|
|
||||||
Settings settings;
|
Settings settings;
|
||||||
|
|
||||||
|
static GlobalConfig::Register r1(&settings);
|
||||||
|
|
||||||
Settings::Settings()
|
Settings::Settings()
|
||||||
: Config({})
|
: nixPrefix(NIX_PREFIX)
|
||||||
, nixPrefix(NIX_PREFIX)
|
|
||||||
, nixStore(canonPath(getEnv("NIX_STORE_DIR", getEnv("NIX_STORE", NIX_STORE_DIR))))
|
, nixStore(canonPath(getEnv("NIX_STORE_DIR", getEnv("NIX_STORE", NIX_STORE_DIR))))
|
||||||
, nixDataDir(canonPath(getEnv("NIX_DATA_DIR", NIX_DATA_DIR)))
|
, nixDataDir(canonPath(getEnv("NIX_DATA_DIR", NIX_DATA_DIR)))
|
||||||
, nixLogDir(canonPath(getEnv("NIX_LOG_DIR", NIX_LOG_DIR)))
|
, nixLogDir(canonPath(getEnv("NIX_LOG_DIR", NIX_LOG_DIR)))
|
||||||
|
@ -69,20 +70,15 @@ Settings::Settings()
|
||||||
allowedImpureHostPrefixes = tokenizeString<StringSet>(DEFAULT_ALLOWED_IMPURE_PREFIXES);
|
allowedImpureHostPrefixes = tokenizeString<StringSet>(DEFAULT_ALLOWED_IMPURE_PREFIXES);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::loadConfFile()
|
void loadConfFile()
|
||||||
{
|
{
|
||||||
applyConfigFile(nixConfDir + "/nix.conf");
|
globalConfig.applyConfigFile(settings.nixConfDir + "/nix.conf");
|
||||||
|
|
||||||
/* We only want to send overrides to the daemon, i.e. stuff from
|
/* We only want to send overrides to the daemon, i.e. stuff from
|
||||||
~/.nix/nix.conf or the command line. */
|
~/.nix/nix.conf or the command line. */
|
||||||
resetOverriden();
|
globalConfig.resetOverriden();
|
||||||
|
|
||||||
applyConfigFile(getConfigDir() + "/nix/nix.conf");
|
globalConfig.applyConfigFile(getConfigDir() + "/nix/nix.conf");
|
||||||
}
|
|
||||||
|
|
||||||
void Settings::set(const string & name, const string & value)
|
|
||||||
{
|
|
||||||
Config::set(name, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Settings::getDefaultCores()
|
unsigned int Settings::getDefaultCores()
|
||||||
|
@ -162,23 +158,11 @@ void initPlugins()
|
||||||
throw Error("could not dynamically open plugin file '%s': %s", file, dlerror());
|
throw Error("could not dynamically open plugin file '%s': %s", file, dlerror());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* We handle settings registrations here, since plugins can add settings */
|
|
||||||
if (RegisterSetting::settingRegistrations) {
|
/* Since plugins can add settings, try to re-apply previously
|
||||||
for (auto & registration : *RegisterSetting::settingRegistrations)
|
unknown settings. */
|
||||||
settings.addSetting(registration);
|
globalConfig.reapplyUnknownSettings();
|
||||||
delete RegisterSetting::settingRegistrations;
|
globalConfig.warnUnknownSettings();
|
||||||
}
|
|
||||||
settings.handleUnknownSettings();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterSetting::SettingRegistrations * RegisterSetting::settingRegistrations;
|
|
||||||
|
|
||||||
RegisterSetting::RegisterSetting(AbstractSetting * s)
|
|
||||||
{
|
|
||||||
if (!settingRegistrations)
|
|
||||||
settingRegistrations = new SettingRegistrations;
|
|
||||||
settingRegistrations->emplace_back(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,26 +13,6 @@ namespace nix {
|
||||||
|
|
||||||
typedef enum { smEnabled, smRelaxed, smDisabled } SandboxMode;
|
typedef enum { smEnabled, smRelaxed, smDisabled } SandboxMode;
|
||||||
|
|
||||||
extern bool useCaseHack; // FIXME
|
|
||||||
|
|
||||||
struct CaseHackSetting : public BaseSetting<bool>
|
|
||||||
{
|
|
||||||
CaseHackSetting(Config * options,
|
|
||||||
const std::string & name,
|
|
||||||
const std::string & description,
|
|
||||||
const std::set<std::string> & aliases = {})
|
|
||||||
: BaseSetting<bool>(useCaseHack, name, description, aliases)
|
|
||||||
{
|
|
||||||
options->addSetting(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set(const std::string & str) override
|
|
||||||
{
|
|
||||||
BaseSetting<bool>::set(str);
|
|
||||||
nix::useCaseHack = value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MaxBuildJobsSetting : public BaseSetting<unsigned int>
|
struct MaxBuildJobsSetting : public BaseSetting<unsigned int>
|
||||||
{
|
{
|
||||||
MaxBuildJobsSetting(Config * options,
|
MaxBuildJobsSetting(Config * options,
|
||||||
|
@ -56,10 +36,6 @@ public:
|
||||||
|
|
||||||
Settings();
|
Settings();
|
||||||
|
|
||||||
void loadConfFile();
|
|
||||||
|
|
||||||
void set(const string & name, const string & value);
|
|
||||||
|
|
||||||
Path nixPrefix;
|
Path nixPrefix;
|
||||||
|
|
||||||
/* The directory where we store sources and derived files. */
|
/* The directory where we store sources and derived files. */
|
||||||
|
@ -353,9 +329,6 @@ public:
|
||||||
Setting<bool> enableImportFromDerivation{this, true, "allow-import-from-derivation",
|
Setting<bool> enableImportFromDerivation{this, true, "allow-import-from-derivation",
|
||||||
"Whether the evaluator allows importing the result of a derivation."};
|
"Whether the evaluator allows importing the result of a derivation."};
|
||||||
|
|
||||||
CaseHackSetting useCaseHack{this, "use-case-hack",
|
|
||||||
"Whether to enable a Darwin-specific hack for dealing with file name collisions."};
|
|
||||||
|
|
||||||
Setting<unsigned long> connectTimeout{this, 0, "connect-timeout",
|
Setting<unsigned long> connectTimeout{this, 0, "connect-timeout",
|
||||||
"Timeout for connecting to servers during downloads. 0 means use curl's builtin default."};
|
"Timeout for connecting to servers during downloads. 0 means use curl's builtin default."};
|
||||||
|
|
||||||
|
@ -398,15 +371,8 @@ extern Settings settings;
|
||||||
anything else */
|
anything else */
|
||||||
void initPlugins();
|
void initPlugins();
|
||||||
|
|
||||||
|
void loadConfFile();
|
||||||
|
|
||||||
extern const string nixVersion;
|
extern const string nixVersion;
|
||||||
|
|
||||||
struct RegisterSetting
|
|
||||||
{
|
|
||||||
typedef std::vector<AbstractSetting *> SettingRegistrations;
|
|
||||||
static SettingRegistrations * settingRegistrations;
|
|
||||||
RegisterSetting(AbstractSetting * s);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,10 +187,11 @@ void RemoteStore::setOptions(Connection & conn)
|
||||||
<< settings.useSubstitutes;
|
<< settings.useSubstitutes;
|
||||||
|
|
||||||
if (GET_PROTOCOL_MINOR(conn.daemonVersion) >= 12) {
|
if (GET_PROTOCOL_MINOR(conn.daemonVersion) >= 12) {
|
||||||
auto overrides = settings.getSettings(true);
|
std::map<std::string, Config::SettingInfo> overrides;
|
||||||
|
globalConfig.getSettings(overrides, true);
|
||||||
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.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.processStderr();
|
conn.processStderr();
|
||||||
|
|
|
@ -849,7 +849,7 @@ ref<Store> openStore(const std::string & uri_,
|
||||||
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->handleUnknownSettings();
|
store->warnUnknownSettings();
|
||||||
return ref<Store>(store);
|
return ref<Store>(store);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,17 +13,25 @@
|
||||||
|
|
||||||
#include "archive.hh"
|
#include "archive.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
#include "config.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
struct ArchiveSettings : Config
|
||||||
|
{
|
||||||
|
Setting<bool> useCaseHack{this,
|
||||||
|
#if __APPLE__
|
||||||
|
true,
|
||||||
|
#else
|
||||||
|
false,
|
||||||
|
#endif
|
||||||
|
"use-case-hack",
|
||||||
|
"Whether to enable a Darwin-specific hack for dealing with file name collisions."};
|
||||||
|
};
|
||||||
|
|
||||||
bool useCaseHack =
|
static ArchiveSettings archiveSettings;
|
||||||
#if __APPLE__
|
|
||||||
true;
|
static GlobalConfig::Register r1(&archiveSettings);
|
||||||
#else
|
|
||||||
false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const std::string narVersionMagic1 = "nix-archive-1";
|
const std::string narVersionMagic1 = "nix-archive-1";
|
||||||
|
|
||||||
|
@ -78,7 +86,7 @@ static void dump(const Path & path, Sink & sink, PathFilter & filter)
|
||||||
the case hack applied by restorePath(). */
|
the case hack applied by restorePath(). */
|
||||||
std::map<string, string> unhacked;
|
std::map<string, string> unhacked;
|
||||||
for (auto & i : readDirectory(path))
|
for (auto & i : readDirectory(path))
|
||||||
if (useCaseHack) {
|
if (archiveSettings.useCaseHack) {
|
||||||
string name(i.name);
|
string name(i.name);
|
||||||
size_t pos = i.name.find(caseHackSuffix);
|
size_t pos = i.name.find(caseHackSuffix);
|
||||||
if (pos != string::npos) {
|
if (pos != string::npos) {
|
||||||
|
@ -243,7 +251,7 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
|
||||||
if (name <= prevName)
|
if (name <= prevName)
|
||||||
throw Error("NAR directory is not sorted");
|
throw Error("NAR directory is not sorted");
|
||||||
prevName = name;
|
prevName = name;
|
||||||
if (useCaseHack) {
|
if (archiveSettings.useCaseHack) {
|
||||||
auto i = names.find(name);
|
auto i = names.find(name);
|
||||||
if (i != names.end()) {
|
if (i != names.end()) {
|
||||||
debug(format("case collision between '%1%' and '%2%'") % i->first % name);
|
debug(format("case collision between '%1%' and '%2%'") % i->first % name);
|
||||||
|
|
|
@ -78,10 +78,6 @@ void restorePath(const Path & path, Source & source);
|
||||||
void copyNAR(Source & source, Sink & sink);
|
void copyNAR(Source & source, Sink & sink);
|
||||||
|
|
||||||
|
|
||||||
// FIXME: global variables are bad m'kay.
|
|
||||||
extern bool useCaseHack;
|
|
||||||
|
|
||||||
|
|
||||||
extern const std::string narVersionMagic1;
|
extern const std::string narVersionMagic1;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,15 +4,13 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
void Config::set(const std::string & name, const std::string & value)
|
bool Config::set(const std::string & name, const std::string & value)
|
||||||
{
|
{
|
||||||
auto i = _settings.find(name);
|
auto i = _settings.find(name);
|
||||||
if (i == _settings.end()) {
|
if (i == _settings.end()) return false;
|
||||||
extras.emplace(name, value);
|
|
||||||
} else {
|
|
||||||
i->second.setting->set(value);
|
i->second.setting->set(value);
|
||||||
i->second.setting->overriden = true;
|
i->second.setting->overriden = true;
|
||||||
}
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::addSetting(AbstractSetting * setting)
|
void Config::addSetting(AbstractSetting * setting)
|
||||||
|
@ -23,46 +21,51 @@ void Config::addSetting(AbstractSetting * setting)
|
||||||
|
|
||||||
bool set = false;
|
bool set = false;
|
||||||
|
|
||||||
auto i = extras.find(setting->name);
|
auto i = unknownSettings.find(setting->name);
|
||||||
if (i != extras.end()) {
|
if (i != unknownSettings.end()) {
|
||||||
setting->set(i->second);
|
setting->set(i->second);
|
||||||
setting->overriden = true;
|
setting->overriden = true;
|
||||||
extras.erase(i);
|
unknownSettings.erase(i);
|
||||||
set = true;
|
set = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto & alias : setting->aliases) {
|
for (auto & alias : setting->aliases) {
|
||||||
auto i = extras.find(alias);
|
auto i = unknownSettings.find(alias);
|
||||||
if (i != extras.end()) {
|
if (i != unknownSettings.end()) {
|
||||||
if (set)
|
if (set)
|
||||||
warn("setting '%s' is set, but it's an alias of '%s' which is also set",
|
warn("setting '%s' is set, but it's an alias of '%s' which is also set",
|
||||||
alias, setting->name);
|
alias, setting->name);
|
||||||
else {
|
else {
|
||||||
setting->set(i->second);
|
setting->set(i->second);
|
||||||
setting->overriden = true;
|
setting->overriden = true;
|
||||||
extras.erase(i);
|
unknownSettings.erase(i);
|
||||||
set = true;
|
set = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::handleUnknownSettings()
|
void AbstractConfig::warnUnknownSettings()
|
||||||
{
|
{
|
||||||
for (auto & s : extras)
|
for (auto & s : unknownSettings)
|
||||||
warn("unknown setting '%s'", s.first);
|
warn("unknown setting '%s'", s.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringMap Config::getSettings(bool overridenOnly)
|
void AbstractConfig::reapplyUnknownSettings()
|
||||||
{
|
{
|
||||||
StringMap res;
|
auto unknownSettings2 = std::move(unknownSettings);
|
||||||
for (auto & opt : _settings)
|
for (auto & s : unknownSettings2)
|
||||||
if (!opt.second.isAlias && (!overridenOnly || opt.second.setting->overriden))
|
set(s.first, s.second);
|
||||||
res.emplace(opt.first, opt.second.setting->to_string());
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::applyConfigFile(const Path & path)
|
void Config::getSettings(std::map<std::string, SettingInfo> & res, bool overridenOnly)
|
||||||
|
{
|
||||||
|
for (auto & opt : _settings)
|
||||||
|
if (!opt.second.isAlias && (!overridenOnly || opt.second.setting->overriden))
|
||||||
|
res.emplace(opt.first, SettingInfo{opt.second.setting->to_string(), opt.second.setting->description});
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractConfig::applyConfigFile(const Path & path)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
string contents = readFile(path);
|
string contents = readFile(path);
|
||||||
|
@ -287,4 +290,49 @@ void PathSetting::set(const std::string & str)
|
||||||
value = canonPath(str);
|
value = canonPath(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GlobalConfig::set(const std::string & name, const std::string & value)
|
||||||
|
{
|
||||||
|
for (auto & config : *configRegistrations)
|
||||||
|
if (config->set(name, value)) return true;
|
||||||
|
|
||||||
|
unknownSettings.emplace(name, value);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalConfig::getSettings(std::map<std::string, SettingInfo> & res, bool overridenOnly)
|
||||||
|
{
|
||||||
|
for (auto & config : *configRegistrations)
|
||||||
|
config->getSettings(res, overridenOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalConfig::resetOverriden()
|
||||||
|
{
|
||||||
|
for (auto & config : *configRegistrations)
|
||||||
|
config->resetOverriden();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalConfig::toJSON(JSONObject & out)
|
||||||
|
{
|
||||||
|
for (auto & config : *configRegistrations)
|
||||||
|
config->toJSON(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalConfig::convertToArgs(Args & args, const std::string & category)
|
||||||
|
{
|
||||||
|
for (auto & config : *configRegistrations)
|
||||||
|
config->convertToArgs(args, category);
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalConfig globalConfig;
|
||||||
|
|
||||||
|
GlobalConfig::ConfigRegistrations * GlobalConfig::configRegistrations;
|
||||||
|
|
||||||
|
GlobalConfig::Register::Register(Config * config)
|
||||||
|
{
|
||||||
|
if (!configRegistrations)
|
||||||
|
configRegistrations = new ConfigRegistrations;
|
||||||
|
configRegistrations->emplace_back(config);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,40 @@ class AbstractSetting;
|
||||||
class JSONPlaceholder;
|
class JSONPlaceholder;
|
||||||
class JSONObject;
|
class JSONObject;
|
||||||
|
|
||||||
|
class AbstractConfig
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
StringMap unknownSettings;
|
||||||
|
|
||||||
|
AbstractConfig(const StringMap & initials = {})
|
||||||
|
: unknownSettings(initials)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual bool set(const std::string & name, const std::string & value) = 0;
|
||||||
|
|
||||||
|
struct SettingInfo
|
||||||
|
{
|
||||||
|
std::string value;
|
||||||
|
std::string description;
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void getSettings(std::map<std::string, SettingInfo> & res, bool overridenOnly = false) = 0;
|
||||||
|
|
||||||
|
void applyConfigFile(const Path & path);
|
||||||
|
|
||||||
|
virtual void resetOverriden() = 0;
|
||||||
|
|
||||||
|
virtual void toJSON(JSONObject & out) = 0;
|
||||||
|
|
||||||
|
virtual void convertToArgs(Args & args, const std::string & category) = 0;
|
||||||
|
|
||||||
|
void warnUnknownSettings();
|
||||||
|
|
||||||
|
void reapplyUnknownSettings();
|
||||||
|
};
|
||||||
|
|
||||||
/* A class to simplify providing configuration settings. The typical
|
/* A class to simplify providing configuration settings. The typical
|
||||||
use is to inherit Config and add Setting<T> members:
|
use is to inherit Config and add Setting<T> members:
|
||||||
|
|
||||||
|
@ -27,7 +61,7 @@ class JSONObject;
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Config
|
class Config : public AbstractConfig
|
||||||
{
|
{
|
||||||
friend class AbstractSetting;
|
friend class AbstractSetting;
|
||||||
|
|
||||||
|
@ -48,31 +82,23 @@ private:
|
||||||
|
|
||||||
Settings _settings;
|
Settings _settings;
|
||||||
|
|
||||||
StringMap extras;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Config(const StringMap & initials)
|
Config(const StringMap & initials = {})
|
||||||
: extras(initials)
|
: AbstractConfig(initials)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void set(const std::string & name, const std::string & value);
|
bool set(const std::string & name, const std::string & value) override;
|
||||||
|
|
||||||
void addSetting(AbstractSetting * setting);
|
void addSetting(AbstractSetting * setting);
|
||||||
|
|
||||||
void handleUnknownSettings();
|
void getSettings(std::map<std::string, SettingInfo> & res, bool overridenOnly = false) override;
|
||||||
|
|
||||||
StringMap getSettings(bool overridenOnly = false);
|
void resetOverriden() override;
|
||||||
|
|
||||||
const Settings & _getSettings() { return _settings; }
|
void toJSON(JSONObject & out) override;
|
||||||
|
|
||||||
void applyConfigFile(const Path & path);
|
void convertToArgs(Args & args, const std::string & category) override;
|
||||||
|
|
||||||
void resetOverriden();
|
|
||||||
|
|
||||||
void toJSON(JSONObject & out);
|
|
||||||
|
|
||||||
void convertToArgs(Args & args, const std::string & category);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class AbstractSetting
|
class AbstractSetting
|
||||||
|
@ -209,4 +235,27 @@ public:
|
||||||
void operator =(const Path & v) { this->assign(v); }
|
void operator =(const Path & v) { this->assign(v); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GlobalConfig : public AbstractConfig
|
||||||
|
{
|
||||||
|
typedef std::vector<Config*> ConfigRegistrations;
|
||||||
|
static ConfigRegistrations * configRegistrations;
|
||||||
|
|
||||||
|
bool set(const std::string & name, const std::string & value) override;
|
||||||
|
|
||||||
|
void getSettings(std::map<std::string, SettingInfo> & res, bool overridenOnly = false) override;
|
||||||
|
|
||||||
|
void resetOverriden() override;
|
||||||
|
|
||||||
|
void toJSON(JSONObject & out) override;
|
||||||
|
|
||||||
|
void convertToArgs(Args & args, const std::string & category) override;
|
||||||
|
|
||||||
|
struct Register
|
||||||
|
{
|
||||||
|
Register(Config * config);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
extern GlobalConfig globalConfig;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,9 +34,10 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
|
||||||
.handler([&]() {
|
.handler([&]() {
|
||||||
std::cout << "The following configuration options are available:\n\n";
|
std::cout << "The following configuration options are available:\n\n";
|
||||||
Table2 tbl;
|
Table2 tbl;
|
||||||
for (const auto & s : settings._getSettings())
|
std::map<std::string, Config::SettingInfo> settings;
|
||||||
if (!s.second.isAlias)
|
globalConfig.getSettings(settings);
|
||||||
tbl.emplace_back(s.first, s.second.setting->description);
|
for (const auto & s : settings)
|
||||||
|
tbl.emplace_back(s.first, s.second.description);
|
||||||
printTable(std::cout, tbl);
|
printTable(std::cout, tbl);
|
||||||
throw Exit();
|
throw Exit();
|
||||||
});
|
});
|
||||||
|
|
|
@ -27,10 +27,12 @@ struct CmdShowConfig : Command, MixJSON
|
||||||
if (json) {
|
if (json) {
|
||||||
// FIXME: use appropriate JSON types (bool, ints, etc).
|
// FIXME: use appropriate JSON types (bool, ints, etc).
|
||||||
JSONObject jsonObj(std::cout);
|
JSONObject jsonObj(std::cout);
|
||||||
settings.toJSON(jsonObj);
|
globalConfig.toJSON(jsonObj);
|
||||||
} else {
|
} else {
|
||||||
for (auto & s : settings.getSettings())
|
std::map<std::string, Config::SettingInfo> settings;
|
||||||
std::cout << s.first + " = " + s.second + "\n";
|
globalConfig.getSettings(settings);
|
||||||
|
for (auto & s : settings)
|
||||||
|
std::cout << s.first + " = " + s.second.value + "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,16 +1,21 @@
|
||||||
#include "globals.hh"
|
#include "config.hh"
|
||||||
#include "primops.hh"
|
#include "primops.hh"
|
||||||
|
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
|
||||||
static BaseSetting<bool> settingSet{false, "setting-set",
|
struct MySettings : Config
|
||||||
|
{
|
||||||
|
Setting<bool> settingSet{this, false, "setting-set",
|
||||||
"Whether the plugin-defined setting was set"};
|
"Whether the plugin-defined setting was set"};
|
||||||
|
};
|
||||||
|
|
||||||
static RegisterSetting rs(&settingSet);
|
MySettings mySettings;
|
||||||
|
|
||||||
|
static GlobalConfig::Register rs(&mySettings);
|
||||||
|
|
||||||
static void prim_anotherNull (EvalState & state, const Pos & pos, Value ** args, Value & v)
|
static void prim_anotherNull (EvalState & state, const Pos & pos, Value ** args, Value & v)
|
||||||
{
|
{
|
||||||
if (settingSet)
|
if (mySettings.settingSet)
|
||||||
mkNull(v);
|
mkNull(v);
|
||||||
else
|
else
|
||||||
mkBool(v, false);
|
mkBool(v, false);
|
||||||
|
|
Loading…
Reference in a new issue