mirror of
https://github.com/NixOS/nix
synced 2025-06-27 08:31:16 +02:00
Convert Settings to the new config system
This makes all config options self-documenting. Unknown or unparseable config settings and --option flags now cause a warning.
This commit is contained in:
parent
6bd9576aeb
commit
ba9ad29fdb
18 changed files with 348 additions and 546 deletions
|
@ -11,7 +11,7 @@ void Config::set(const std::string & name, const std::string & value)
|
|||
i->second.setting->set(value);
|
||||
}
|
||||
|
||||
void Config::add(AbstractSetting * setting)
|
||||
void Config::addSetting(AbstractSetting * setting)
|
||||
{
|
||||
_settings.emplace(setting->name, Config::SettingData{false, setting});
|
||||
for (auto & alias : setting->aliases)
|
||||
|
@ -41,21 +41,59 @@ void Config::add(AbstractSetting * setting)
|
|||
}
|
||||
}
|
||||
|
||||
void Config::warnUnused()
|
||||
void Config::warnUnknownSettings()
|
||||
{
|
||||
for (auto & i : initials)
|
||||
warn("unknown setting '%s'", i.first);
|
||||
}
|
||||
|
||||
std::string Config::dump()
|
||||
StringMap Config::getSettings()
|
||||
{
|
||||
std::string res;
|
||||
StringMap res;
|
||||
for (auto & opt : _settings)
|
||||
if (!opt.second.isAlias)
|
||||
res += opt.first + " = " + opt.second.setting->to_string() + "\n";
|
||||
res.emplace(opt.first, opt.second.setting->to_string());
|
||||
return res;
|
||||
}
|
||||
|
||||
void Config::applyConfigFile(const Path & path, bool fatal)
|
||||
{
|
||||
try {
|
||||
string contents = readFile(path);
|
||||
|
||||
unsigned int pos = 0;
|
||||
|
||||
while (pos < contents.size()) {
|
||||
string line;
|
||||
while (pos < contents.size() && contents[pos] != '\n')
|
||||
line += contents[pos++];
|
||||
pos++;
|
||||
|
||||
string::size_type hash = line.find('#');
|
||||
if (hash != string::npos)
|
||||
line = string(line, 0, hash);
|
||||
|
||||
vector<string> tokens = tokenizeString<vector<string> >(line);
|
||||
if (tokens.empty()) continue;
|
||||
|
||||
if (tokens.size() < 2 || tokens[1] != "=")
|
||||
throw UsageError("illegal configuration line ‘%1%’ in ‘%2%’", line, path);
|
||||
|
||||
string name = tokens[0];
|
||||
|
||||
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());
|
||||
}
|
||||
};
|
||||
} catch (SysError &) { }
|
||||
}
|
||||
|
||||
AbstractSetting::AbstractSetting(
|
||||
const std::string & name,
|
||||
const std::string & description,
|
||||
|
@ -74,41 +112,65 @@ template<> std::string Setting<std::string>::to_string()
|
|||
return value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Setting<T>::set(const std::string & str)
|
||||
template<typename T, typename Tag>
|
||||
void Setting<T, Tag>::set(const std::string & str)
|
||||
{
|
||||
static_assert(std::is_integral<T>::value, "Integer required.");
|
||||
try {
|
||||
auto i = std::stoll(str);
|
||||
if (i < std::numeric_limits<T>::min() ||
|
||||
i > std::numeric_limits<T>::max())
|
||||
throw UsageError("setting '%s' has out-of-range value %d", name, i);
|
||||
value = i;
|
||||
} catch (std::logic_error&) {
|
||||
if (!string2Int(str, value))
|
||||
throw UsageError("setting '%s' has invalid value '%s'", name, str);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::string Setting<T>::to_string()
|
||||
template<typename T, typename Tag>
|
||||
std::string Setting<T, Tag>::to_string()
|
||||
{
|
||||
static_assert(std::is_integral<T>::value, "Integer required.");
|
||||
return std::to_string(value);
|
||||
}
|
||||
|
||||
template<> void Setting<bool>::set(const std::string & str)
|
||||
bool AbstractSetting::parseBool(const std::string & str)
|
||||
{
|
||||
if (str == "true" || str == "yes" || str == "1")
|
||||
value = true;
|
||||
return true;
|
||||
else if (str == "false" || str == "no" || str == "0")
|
||||
value = false;
|
||||
return false;
|
||||
else
|
||||
throw UsageError("Boolean setting '%s' has invalid value '%s'", name, str);
|
||||
}
|
||||
|
||||
template<> void Setting<bool>::set(const std::string & str)
|
||||
{
|
||||
value = parseBool(str);
|
||||
}
|
||||
|
||||
std::string AbstractSetting::printBool(bool b)
|
||||
{
|
||||
return b ? "true" : "false";
|
||||
}
|
||||
|
||||
|
||||
template<> std::string Setting<bool>::to_string()
|
||||
{
|
||||
return value ? "true" : "false";
|
||||
return printBool(value);
|
||||
}
|
||||
|
||||
template<> void Setting<Strings>::set(const std::string & str)
|
||||
{
|
||||
value = tokenizeString<Strings>(str);
|
||||
}
|
||||
|
||||
template<> std::string Setting<Strings>::to_string()
|
||||
{
|
||||
return concatStringsSep(" ", value);
|
||||
}
|
||||
|
||||
template<> void Setting<StringSet>::set(const std::string & str)
|
||||
{
|
||||
value = tokenizeString<StringSet>(str);
|
||||
}
|
||||
|
||||
template<> std::string Setting<StringSet>::to_string()
|
||||
{
|
||||
return concatStringsSep(" ", value);
|
||||
}
|
||||
|
||||
template class Setting<int>;
|
||||
|
|
|
@ -47,11 +47,13 @@ public:
|
|||
|
||||
void set(const std::string & name, const std::string & value);
|
||||
|
||||
void add(AbstractSetting * setting);
|
||||
void addSetting(AbstractSetting * setting);
|
||||
|
||||
void warnUnused();
|
||||
void warnUnknownSettings();
|
||||
|
||||
std::string dump();
|
||||
StringMap getSettings();
|
||||
|
||||
void applyConfigFile(const Path & path, bool fatal = false);
|
||||
};
|
||||
|
||||
class AbstractSetting
|
||||
|
@ -83,10 +85,15 @@ protected:
|
|||
virtual void set(const std::string & value) = 0;
|
||||
|
||||
virtual std::string to_string() = 0;
|
||||
|
||||
bool parseBool(const std::string & str);
|
||||
std::string printBool(bool b);
|
||||
};
|
||||
|
||||
struct DefaultSettingTag { };
|
||||
|
||||
/* A setting of type T. */
|
||||
template<typename T>
|
||||
template<typename T, typename Tag = DefaultSettingTag>
|
||||
class Setting : public AbstractSetting
|
||||
{
|
||||
protected:
|
||||
|
@ -103,10 +110,12 @@ public:
|
|||
: AbstractSetting(name, description, aliases)
|
||||
, value(def)
|
||||
{
|
||||
options->add(this);
|
||||
options->addSetting(this);
|
||||
}
|
||||
|
||||
operator const T &() const { return value; }
|
||||
operator T &() { return value; }
|
||||
const T & get() const { return value; }
|
||||
bool operator ==(const T & v2) const { return value == v2; }
|
||||
bool operator !=(const T & v2) const { return value != v2; }
|
||||
void operator =(const T & v) { value = v; }
|
||||
|
@ -123,6 +132,9 @@ std::ostream & operator <<(std::ostream & str, const Setting<T> & opt)
|
|||
return str;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool operator ==(const T & v1, const Setting<T> & v2) { return v1 == (const T &) v2; }
|
||||
|
||||
/* A special setting for Paths. These are automatically canonicalised
|
||||
(e.g. "/foo//bar/" becomes "/foo/bar"). */
|
||||
class PathSetting : public Setting<Path>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue