Allow plugins to define new settings.
This commit is contained in:
parent
3fe9767dd3
commit
de4934ab3b
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -383,5 +383,12 @@ void initPlugins();
|
|||
|
||||
extern const string nixVersion;
|
||||
|
||||
struct RegisterSetting
|
||||
{
|
||||
typedef std::vector<AbstractSetting *> SettingRegistrations;
|
||||
static SettingRegistrations * settingRegistrations;
|
||||
RegisterSetting(AbstractSetting * s);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 &) { }
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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" ]
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue