diff --git a/doc/manual/command-ref/conf-file.xml b/doc/manual/command-ref/conf-file.xml
index 42906ddff..c14a4d206 100644
--- a/doc/manual/command-ref/conf-file.xml
+++ b/doc/manual/command-ref/conf-file.xml
@@ -757,9 +757,10 @@ builtins.fetchurl {
plugins may construct static instances of RegisterPrimOp to
add new primops or constants to the expression language,
RegisterStoreImplementation to add new store implementations,
- and RegisterCommand to add new subcommands to the
- nix command. See the constructors for those
- types for more details.
+ RegisterCommand to add new subcommands to the
+ nix command, and RegisterSetting to add new
+ nix config settings. See the constructors for those types for
+ more details.
Since these files are loaded into the same address space as
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index c6b508cbe..c5a4536ef 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -161,6 +161,22 @@ void initPlugins()
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) {
+ for (auto & registration : *RegisterSetting::settingRegistrations)
+ settings.addSetting(registration);
+ delete RegisterSetting::settingRegistrations;
+ }
+ settings.handleUnknownSettings();
+}
+
+RegisterSetting::SettingRegistrations * RegisterSetting::settingRegistrations;
+
+RegisterSetting::RegisterSetting(AbstractSetting * s)
+{
+ if (!settingRegistrations)
+ settingRegistrations = new SettingRegistrations;
+ settingRegistrations->emplace_back(s);
}
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 508084d08..1d019aab9 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -383,5 +383,12 @@ void initPlugins();
extern const string nixVersion;
+struct RegisterSetting
+{
+ typedef std::vector SettingRegistrations;
+ static SettingRegistrations * settingRegistrations;
+ RegisterSetting(AbstractSetting * s);
+};
+
}
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 4d43ef082..8830edcc3 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -839,7 +839,7 @@ ref openStore(const std::string & uri_,
for (auto fun : *RegisterStoreImplementation::implementations) {
auto store = fun(uri, params);
if (store) {
- store->warnUnknownSettings();
+ store->handleUnknownSettings();
return ref(store);
}
}
diff --git a/src/libutil/config.cc b/src/libutil/config.cc
index 0e502769e..cdd1e0a15 100644
--- a/src/libutil/config.cc
+++ b/src/libutil/config.cc
@@ -7,10 +7,12 @@ namespace nix {
void Config::set(const std::string & name, const std::string & value)
{
auto i = _settings.find(name);
- if (i == _settings.end())
- throw UsageError("unknown setting '%s'", name);
- i->second.setting->set(value);
- i->second.setting->overriden = true;
+ if (i == _settings.end()) {
+ extras.emplace(name, value);
+ } else {
+ i->second.setting->set(value);
+ i->second.setting->overriden = true;
+ }
}
void Config::addSetting(AbstractSetting * setting)
@@ -21,34 +23,37 @@ void Config::addSetting(AbstractSetting * setting)
bool set = false;
- auto i = initials.find(setting->name);
- if (i != initials.end()) {
+ auto i = extras.find(setting->name);
+ if (i != extras.end()) {
setting->set(i->second);
setting->overriden = true;
- initials.erase(i);
+ extras.erase(i);
set = true;
}
for (auto & alias : setting->aliases) {
- auto i = initials.find(alias);
- if (i != initials.end()) {
+ auto i = extras.find(alias);
+ if (i != extras.end()) {
if (set)
warn("setting '%s' is set, but it's an alias of '%s' which is also set",
alias, setting->name);
else {
setting->set(i->second);
setting->overriden = true;
- initials.erase(i);
+ extras.erase(i);
set = true;
}
}
}
}
-void Config::warnUnknownSettings()
+void Config::handleUnknownSettings(bool fatal)
{
- for (auto & i : initials)
- warn("unknown setting '%s'", i.first);
+ for (auto & s : extras)
+ if (fatal)
+ throw UsageError("unknown setting '%s%'", s.first);
+ else
+ warn("unknown setting '%s'", s.first);
}
StringMap Config::getSettings(bool overridenOnly)
@@ -60,7 +65,7 @@ StringMap Config::getSettings(bool overridenOnly)
return res;
}
-void Config::applyConfigFile(const Path & path, bool fatal)
+void Config::applyConfigFile(const Path & path)
{
try {
string contents = readFile(path);
@@ -97,7 +102,7 @@ void Config::applyConfigFile(const Path & path, bool fatal)
throw UsageError("illegal configuration line '%1%' in '%2%'", line, path);
auto p = absPath(tokens[1], dirOf(path));
if (pathExists(p)) {
- applyConfigFile(p, fatal);
+ applyConfigFile(p);
} else if (!ignoreMissing) {
throw Error("file '%1%' included from '%2%' not found", p, path);
}
@@ -112,12 +117,7 @@ void Config::applyConfigFile(const Path & path, bool fatal)
vector::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());
- }
+ set(name, concatStringsSep(" ", Strings(i, tokens.end()))); // FIXME: slow
};
} catch (SysError &) { }
}
diff --git a/src/libutil/config.hh b/src/libutil/config.hh
index 9a32af528..c6783e13c 100644
--- a/src/libutil/config.hh
+++ b/src/libutil/config.hh
@@ -48,25 +48,25 @@ private:
Settings _settings;
- StringMap initials;
+ StringMap extras;
public:
Config(const StringMap & initials)
- : initials(initials)
+ : extras(initials)
{ }
void set(const std::string & name, const std::string & value);
void addSetting(AbstractSetting * setting);
- void warnUnknownSettings();
+ void handleUnknownSettings(bool fatal = false);
StringMap getSettings(bool overridenOnly = false);
const Settings & _getSettings() { return _settings; }
- void applyConfigFile(const Path & path, bool fatal = false);
+ void applyConfigFile(const Path & path);
void resetOverriden();
diff --git a/tests/plugins.sh b/tests/plugins.sh
index 0fad4f773..4b1baeddc 100644
--- a/tests/plugins.sh
+++ b/tests/plugins.sh
@@ -2,6 +2,6 @@ source common.sh
set -o pipefail
-res=$(nix eval '(builtins.anotherNull)' --option plugin-files $PWD/plugins/libplugintest*)
+res=$(nix eval '(builtins.anotherNull)' --option setting-set true --option plugin-files $PWD/plugins/libplugintest*)
[ "$res"x = "nullx" ]
diff --git a/tests/plugins/plugintest.cc b/tests/plugins/plugintest.cc
index 6b5e6d7cd..8da15ebab 100644
--- a/tests/plugins/plugintest.cc
+++ b/tests/plugins/plugintest.cc
@@ -1,10 +1,19 @@
+#include "globals.hh"
#include "primops.hh"
using namespace nix;
+static BaseSetting settingSet{false, "setting-set",
+ "Whether the plugin-defined setting was set"};
+
+static RegisterSetting rs(&settingSet);
+
static void prim_anotherNull (EvalState & state, const Pos & pos, Value ** args, Value & v)
{
- mkNull(v);
+ if (settingSet)
+ mkNull(v);
+ else
+ mkBool(v, false);
}
-static RegisterPrimOp r("anotherNull", 0, prim_anotherNull);
+static RegisterPrimOp rp("anotherNull", 0, prim_anotherNull);