Allow plugins to define new settings.

This commit is contained in:
Shea Levy 2018-02-13 14:43:32 -05:00
parent 3fe9767dd3
commit de4934ab3b
No known key found for this signature in database
GPG Key ID: 5C0BD6957D86FE27
8 changed files with 65 additions and 32 deletions

View File

@ -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
<literal>nix</literal> command. See the constructors for those
types for more details.
RegisterCommand to add new subcommands to the
<literal>nix</literal> command, and RegisterSetting to add new
nix config settings. See the constructors for those types for
more details.
</para>
<para>
Since these files are loaded into the same address space as

View File

@ -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);
}

View File

@ -383,5 +383,12 @@ void initPlugins();
extern const string nixVersion;
struct RegisterSetting
{
typedef std::vector<AbstractSetting *> SettingRegistrations;
static SettingRegistrations * settingRegistrations;
RegisterSetting(AbstractSetting * s);
};
}

View File

@ -839,7 +839,7 @@ ref<Store> openStore(const std::string & uri_,
for (auto fun : *RegisterStoreImplementation::implementations) {
auto store = fun(uri, params);
if (store) {
store->warnUnknownSettings();
store->handleUnknownSettings();
return ref<Store>(store);
}
}

View File

@ -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<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());
}
set(name, concatStringsSep(" ", Strings(i, tokens.end()))); // FIXME: slow
};
} catch (SysError &) { }
}

View File

@ -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();

View File

@ -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" ]

View File

@ -1,10 +1,19 @@
#include "globals.hh"
#include "primops.hh"
using namespace nix;
static BaseSetting<bool> 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);