Allow plugins to define new settings.
This commit is contained in:
parent
3fe9767dd3
commit
de4934ab3b
8 changed files with 65 additions and 32 deletions
|
@ -757,9 +757,10 @@ builtins.fetchurl {
|
||||||
plugins may construct static instances of RegisterPrimOp to
|
plugins may construct static instances of RegisterPrimOp to
|
||||||
add new primops or constants to the expression language,
|
add new primops or constants to the expression language,
|
||||||
RegisterStoreImplementation to add new store implementations,
|
RegisterStoreImplementation to add new store implementations,
|
||||||
and RegisterCommand to add new subcommands to the
|
RegisterCommand to add new subcommands to the
|
||||||
<literal>nix</literal> command. See the constructors for those
|
<literal>nix</literal> command, and RegisterSetting to add new
|
||||||
types for more details.
|
nix config settings. See the constructors for those types for
|
||||||
|
more details.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Since these files are loaded into the same address space as
|
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());
|
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;
|
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) {
|
for (auto fun : *RegisterStoreImplementation::implementations) {
|
||||||
auto store = fun(uri, params);
|
auto store = fun(uri, params);
|
||||||
if (store) {
|
if (store) {
|
||||||
store->warnUnknownSettings();
|
store->handleUnknownSettings();
|
||||||
return ref<Store>(store);
|
return ref<Store>(store);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,12 @@ namespace nix {
|
||||||
void Config::set(const std::string & name, const std::string & value)
|
void 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()) {
|
||||||
throw UsageError("unknown setting '%s'", name);
|
extras.emplace(name, value);
|
||||||
i->second.setting->set(value);
|
} else {
|
||||||
i->second.setting->overriden = true;
|
i->second.setting->set(value);
|
||||||
|
i->second.setting->overriden = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::addSetting(AbstractSetting * setting)
|
void Config::addSetting(AbstractSetting * setting)
|
||||||
|
@ -21,34 +23,37 @@ void Config::addSetting(AbstractSetting * setting)
|
||||||
|
|
||||||
bool set = false;
|
bool set = false;
|
||||||
|
|
||||||
auto i = initials.find(setting->name);
|
auto i = extras.find(setting->name);
|
||||||
if (i != initials.end()) {
|
if (i != extras.end()) {
|
||||||
setting->set(i->second);
|
setting->set(i->second);
|
||||||
setting->overriden = true;
|
setting->overriden = true;
|
||||||
initials.erase(i);
|
extras.erase(i);
|
||||||
set = true;
|
set = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto & alias : setting->aliases) {
|
for (auto & alias : setting->aliases) {
|
||||||
auto i = initials.find(alias);
|
auto i = extras.find(alias);
|
||||||
if (i != initials.end()) {
|
if (i != extras.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;
|
||||||
initials.erase(i);
|
extras.erase(i);
|
||||||
set = true;
|
set = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::warnUnknownSettings()
|
void Config::handleUnknownSettings(bool fatal)
|
||||||
{
|
{
|
||||||
for (auto & i : initials)
|
for (auto & s : extras)
|
||||||
warn("unknown setting '%s'", i.first);
|
if (fatal)
|
||||||
|
throw UsageError("unknown setting '%s%'", s.first);
|
||||||
|
else
|
||||||
|
warn("unknown setting '%s'", s.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringMap Config::getSettings(bool overridenOnly)
|
StringMap Config::getSettings(bool overridenOnly)
|
||||||
|
@ -60,7 +65,7 @@ StringMap Config::getSettings(bool overridenOnly)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::applyConfigFile(const Path & path, bool fatal)
|
void Config::applyConfigFile(const Path & path)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
string contents = readFile(path);
|
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);
|
throw UsageError("illegal configuration line '%1%' in '%2%'", line, path);
|
||||||
auto p = absPath(tokens[1], dirOf(path));
|
auto p = absPath(tokens[1], dirOf(path));
|
||||||
if (pathExists(p)) {
|
if (pathExists(p)) {
|
||||||
applyConfigFile(p, fatal);
|
applyConfigFile(p);
|
||||||
} else if (!ignoreMissing) {
|
} else if (!ignoreMissing) {
|
||||||
throw Error("file '%1%' included from '%2%' not found", p, path);
|
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();
|
vector<string>::iterator i = tokens.begin();
|
||||||
advance(i, 2);
|
advance(i, 2);
|
||||||
|
|
||||||
try {
|
set(name, concatStringsSep(" ", Strings(i, tokens.end()))); // FIXME: slow
|
||||||
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 &) { }
|
} catch (SysError &) { }
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,25 +48,25 @@ private:
|
||||||
|
|
||||||
Settings _settings;
|
Settings _settings;
|
||||||
|
|
||||||
StringMap initials;
|
StringMap extras;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Config(const StringMap & initials)
|
Config(const StringMap & initials)
|
||||||
: initials(initials)
|
: extras(initials)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void set(const std::string & name, const std::string & value);
|
void set(const std::string & name, const std::string & value);
|
||||||
|
|
||||||
void addSetting(AbstractSetting * setting);
|
void addSetting(AbstractSetting * setting);
|
||||||
|
|
||||||
void warnUnknownSettings();
|
void handleUnknownSettings(bool fatal = false);
|
||||||
|
|
||||||
StringMap getSettings(bool overridenOnly = false);
|
StringMap getSettings(bool overridenOnly = false);
|
||||||
|
|
||||||
const Settings & _getSettings() { return _settings; }
|
const Settings & _getSettings() { return _settings; }
|
||||||
|
|
||||||
void applyConfigFile(const Path & path, bool fatal = false);
|
void applyConfigFile(const Path & path);
|
||||||
|
|
||||||
void resetOverriden();
|
void resetOverriden();
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,6 @@ source common.sh
|
||||||
|
|
||||||
set -o pipefail
|
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" ]
|
[ "$res"x = "nullx" ]
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
|
#include "globals.hh"
|
||||||
#include "primops.hh"
|
#include "primops.hh"
|
||||||
|
|
||||||
using namespace nix;
|
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)
|
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