Thread ApplyConfigOptions through config parsing

This makes no changes to logic but makes the `ApplyConfigOptions` value
available to consumers.

Change-Id: I88cf53d38faac8472c556aee55c13d0acbd1e5db
This commit is contained in:
Rebecca Turner 2024-08-25 11:58:10 -07:00
parent b6884388a1
commit 5fc6fcb310
No known key found for this signature in database
8 changed files with 99 additions and 104 deletions

View file

@ -7,7 +7,7 @@
namespace nix { namespace nix {
template<> AcceptFlakeConfig BaseSetting<AcceptFlakeConfig>::parse(const std::string & str) const template<> AcceptFlakeConfig BaseSetting<AcceptFlakeConfig>::parse(const std::string & str, const ApplyConfigOptions & options) const
{ {
if (str == "true") return AcceptFlakeConfig::True; if (str == "true") return AcceptFlakeConfig::True;
else if (str == "ask") return AcceptFlakeConfig::Ask; else if (str == "ask") return AcceptFlakeConfig::Ask;

View file

@ -116,14 +116,15 @@ Settings::Settings()
void loadConfFile() void loadConfFile()
{ {
auto applyConfigFile = [&](const Path & path) { auto applyConfigFile = [&](const ApplyConfigOptions & options) {
try { try {
std::string contents = readFile(path); std::string contents = readFile(*options.path);
globalConfig.applyConfig(contents, path); globalConfig.applyConfig(contents, options);
} catch (SysError &) { } } catch (SysError &) {
}
}; };
applyConfigFile(settings.nixConfDir + "/nix.conf"); applyConfigFile(ApplyConfigOptions{.path = settings.nixConfDir + "/nix.conf"});
/* We only want to send overrides to the daemon, i.e. stuff from /* We only want to send overrides to the daemon, i.e. stuff from
~/.nix/nix.conf or the command line. */ ~/.nix/nix.conf or the command line. */
@ -131,14 +132,13 @@ void loadConfFile()
auto files = settings.nixUserConfFiles; auto files = settings.nixUserConfFiles;
for (auto file = files.rbegin(); file != files.rend(); file++) { for (auto file = files.rbegin(); file != files.rend(); file++) {
applyConfigFile(*file); applyConfigFile(ApplyConfigOptions{.path = *file});
} }
auto nixConfEnv = getEnv("NIX_CONFIG"); auto nixConfEnv = getEnv("NIX_CONFIG");
if (nixConfEnv.has_value()) { if (nixConfEnv.has_value()) {
globalConfig.applyConfig(nixConfEnv.value(), "NIX_CONFIG"); globalConfig.applyConfig(nixConfEnv.value(), ApplyConfigOptions{.fromEnvVar = true});
} }
} }
std::vector<Path> getUserConfigFiles() std::vector<Path> getUserConfigFiles()
@ -264,7 +264,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM(SandboxMode, {
{SandboxMode::smDisabled, false}, {SandboxMode::smDisabled, false},
}); });
template<> SandboxMode BaseSetting<SandboxMode>::parse(const std::string & str) const template<> SandboxMode BaseSetting<SandboxMode>::parse(const std::string & str, const ApplyConfigOptions & options) const
{ {
if (str == "true") return smEnabled; if (str == "true") return smEnabled;
else if (str == "relaxed") return smRelaxed; else if (str == "relaxed") return smRelaxed;
@ -307,7 +307,7 @@ template<> void BaseSetting<SandboxMode>::convertToArg(Args & args, const std::s
}); });
} }
unsigned int MaxBuildJobsSetting::parse(const std::string & str) const unsigned int MaxBuildJobsSetting::parse(const std::string & str, const ApplyConfigOptions & options) const
{ {
if (str == "auto") return std::max(1U, std::thread::hardware_concurrency()); if (str == "auto") return std::max(1U, std::thread::hardware_concurrency());
else { else {
@ -315,15 +315,15 @@ unsigned int MaxBuildJobsSetting::parse(const std::string & str) const
return *n; return *n;
else else
throw UsageError("configuration setting '%s' should be 'auto' or an integer", name); throw UsageError("configuration setting '%s' should be 'auto' or an integer", name);
}
} }
}
Paths PluginFilesSetting::parse(const std::string & str) const Paths PluginFilesSetting::parse(const std::string & str, const ApplyConfigOptions & options) const
{ {
if (pluginsLoaded) if (pluginsLoaded)
throw UsageError("plugin-files set after plugins were loaded, you may need to move the flag before the subcommand"); throw UsageError("plugin-files set after plugins were loaded, you may need to move the flag before the subcommand");
return BaseSetting<Paths>::parse(str); return BaseSetting<Paths>::parse(str, options);
} }

View file

@ -26,7 +26,7 @@ struct MaxBuildJobsSetting : public BaseSetting<unsigned int>
options->addSetting(this); options->addSetting(this);
} }
unsigned int parse(const std::string & str) const override; unsigned int parse(const std::string & str, const ApplyConfigOptions & options) const override;
}; };
struct PluginFilesSetting : public BaseSetting<Paths> struct PluginFilesSetting : public BaseSetting<Paths>
@ -43,7 +43,7 @@ struct PluginFilesSetting : public BaseSetting<Paths>
options->addSetting(this); options->addSetting(this);
} }
Paths parse(const std::string & str) const override; Paths parse(const std::string & str, const ApplyConfigOptions & options) const override;
}; };
const uint32_t maxIdsPerBuild = const uint32_t maxIdsPerBuild =
@ -1088,6 +1088,7 @@ void loadConfFile();
// Used by the Settings constructor // Used by the Settings constructor
std::vector<Path> getUserConfigFiles(); std::vector<Path> getUserConfigFiles();
std::vector<Path> getHomeConfigFile();
extern const std::string nixVersion; extern const std::string nixVersion;

View file

@ -51,14 +51,14 @@ bool BaseSetting<T>::isAppendable()
return trait::appendable; return trait::appendable;
} }
template<> void BaseSetting<Strings>::appendOrSet(Strings newValue, bool append); template<> void BaseSetting<Strings>::appendOrSet(Strings newValue, bool append, const ApplyConfigOptions & options);
template<> void BaseSetting<StringSet>::appendOrSet(StringSet newValue, bool append); template<> void BaseSetting<StringSet>::appendOrSet(StringSet newValue, bool append, const ApplyConfigOptions & options);
template<> void BaseSetting<StringMap>::appendOrSet(StringMap newValue, bool append); template<> void BaseSetting<StringMap>::appendOrSet(StringMap newValue, bool append, const ApplyConfigOptions & options);
template<> void BaseSetting<ExperimentalFeatures>::appendOrSet(ExperimentalFeatures newValue, bool append); template<> void BaseSetting<ExperimentalFeatures>::appendOrSet(ExperimentalFeatures newValue, bool append, const ApplyConfigOptions & options);
template<> void BaseSetting<DeprecatedFeatures>::appendOrSet(DeprecatedFeatures newValue, bool append); template<> void BaseSetting<DeprecatedFeatures>::appendOrSet(DeprecatedFeatures newValue, bool append, const ApplyConfigOptions & options);
template<typename T> template<typename T>
void BaseSetting<T>::appendOrSet(T newValue, bool append) void BaseSetting<T>::appendOrSet(T newValue, bool append, const ApplyConfigOptions & options)
{ {
static_assert( static_assert(
!trait::appendable, !trait::appendable,
@ -69,14 +69,14 @@ void BaseSetting<T>::appendOrSet(T newValue, bool append)
} }
template<typename T> template<typename T>
void BaseSetting<T>::set(const std::string & str, bool append) void BaseSetting<T>::set(const std::string & str, bool append, const ApplyConfigOptions & options)
{ {
if (experimentalFeatureSettings.isEnabled(experimentalFeature)) { if (experimentalFeatureSettings.isEnabled(experimentalFeature)) {
auto parsed = parse(str); auto parsed = parse(str, options);
if (deprecated && (append || parsed != value)) { if (deprecated && (append || parsed != value)) {
warn("deprecated setting '%s' found (set to '%s')", name, str); warn("deprecated setting '%s' found (set to '%s')", name, str);
} }
appendOrSet(std::move(parsed), append); appendOrSet(std::move(parsed), append, options);
} else { } else {
assert(experimentalFeature); assert(experimentalFeature);
warn("Ignoring setting '%s' because experimental feature '%s' is not enabled", warn("Ignoring setting '%s' because experimental feature '%s' is not enabled",
@ -111,7 +111,7 @@ void BaseSetting<T>::convertToArg(Args & args, const std::string & category)
} }
#define DECLARE_CONFIG_SERIALISER(TY) \ #define DECLARE_CONFIG_SERIALISER(TY) \
template<> TY BaseSetting< TY >::parse(const std::string & str) const; \ template<> TY BaseSetting< TY >::parse(const std::string & str, const ApplyConfigOptions & options) const; \
template<> std::string BaseSetting< TY >::to_string() const; template<> std::string BaseSetting< TY >::to_string() const;
DECLARE_CONFIG_SERIALISER(std::string) DECLARE_CONFIG_SERIALISER(std::string)
@ -124,7 +124,7 @@ DECLARE_CONFIG_SERIALISER(ExperimentalFeatures)
DECLARE_CONFIG_SERIALISER(DeprecatedFeatures) DECLARE_CONFIG_SERIALISER(DeprecatedFeatures)
template<typename T> template<typename T>
T BaseSetting<T>::parse(const std::string & str) const T BaseSetting<T>::parse(const std::string & str, const ApplyConfigOptions & options) const
{ {
static_assert(std::is_integral<T>::value, "Integer required."); static_assert(std::is_integral<T>::value, "Integer required.");

View file

@ -1,4 +1,5 @@
#include "config.hh" #include "config.hh"
#include "apply-config-options.hh"
#include "args.hh" #include "args.hh"
#include "abstract-setting-to-json.hh" #include "abstract-setting-to-json.hh"
#include "experimental-features.hh" #include "experimental-features.hh"
@ -17,7 +18,7 @@ Config::Config(StringMap initials)
: AbstractConfig(std::move(initials)) : AbstractConfig(std::move(initials))
{ } { }
bool Config::set(const std::string & name, const std::string & value) bool Config::set(const std::string & name, const std::string & value, const ApplyConfigOptions & options)
{ {
bool append = false; bool append = false;
auto i = _settings.find(name); auto i = _settings.find(name);
@ -30,7 +31,7 @@ bool Config::set(const std::string & name, const std::string & value)
} else } else
return false; return false;
} }
i->second.setting->set(value, append); i->second.setting->set(value, append, options);
i->second.setting->overridden = true; i->second.setting->overridden = true;
return true; return true;
} }
@ -91,7 +92,7 @@ void Config::getSettings(std::map<std::string, SettingInfo> & res, bool overridd
} }
static void applyConfigInner(const std::string & contents, const std::string & path, std::vector<std::pair<std::string, std::string>> & parsedContents) { static void applyConfigInner(const std::string & contents, const ApplyConfigOptions & options, std::vector<std::pair<std::string, std::string>> & parsedContents) {
unsigned int pos = 0; unsigned int pos = 0;
while (pos < contents.size()) { while (pos < contents.size()) {
@ -107,7 +108,7 @@ static void applyConfigInner(const std::string & contents, const std::string & p
if (tokens.empty()) continue; if (tokens.empty()) continue;
if (tokens.size() < 2) if (tokens.size() < 2)
throw UsageError("illegal configuration line '%1%' in '%2%'", line, path); throw UsageError("illegal configuration line '%1%' in '%2%'", line, options.relativeDisplay());
auto include = false; auto include = false;
auto ignoreMissing = false; auto ignoreMissing = false;
@ -119,24 +120,32 @@ static void applyConfigInner(const std::string & contents, const std::string & p
} }
if (include) { if (include) {
if (tokens.size() != 2) if (tokens.size() != 2) {
throw UsageError("illegal configuration line '%1%' in '%2%'", line, path); throw UsageError("illegal configuration line '%1%' in '%2%'", line, options.relativeDisplay());
auto p = absPath(tokens[1], dirOf(path)); }
if (pathExists(p)) { if (!options.path) {
throw UsageError("can only include configuration '%1%' from files", tokens[1]);
}
auto pathToInclude = absPath(tokens[1], dirOf(*options.path));
if (pathExists(pathToInclude)) {
auto includeOptions = ApplyConfigOptions {
.path = pathToInclude,
.home = options.home,
};
try { try {
std::string includedContents = readFile(path); std::string includedContents = readFile(pathToInclude);
applyConfigInner(includedContents, p, parsedContents); applyConfigInner(includedContents, includeOptions, parsedContents);
} catch (SysError &) { } catch (SysError &) {
// TODO: Do we actually want to ignore this? Or is it better to fail? // TODO: Do we actually want to ignore this? Or is it better to fail?
} }
} 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", pathToInclude, *options.path);
} }
continue; continue;
} }
if (tokens[1] != "=") if (tokens[1] != "=")
throw UsageError("illegal configuration line '%1%' in '%2%'", line, path); throw UsageError("illegal configuration line '%1%' in '%2%'", line, options.relativeDisplay());
std::string name = std::move(tokens[0]); std::string name = std::move(tokens[0]);
@ -150,20 +159,20 @@ static void applyConfigInner(const std::string & contents, const std::string & p
}; };
} }
void AbstractConfig::applyConfig(const std::string & contents, const std::string & path) { void AbstractConfig::applyConfig(const std::string & contents, const ApplyConfigOptions & options) {
std::vector<std::pair<std::string, std::string>> parsedContents; std::vector<std::pair<std::string, std::string>> parsedContents;
applyConfigInner(contents, path, parsedContents); applyConfigInner(contents, options, parsedContents);
// First apply experimental-feature related settings // First apply experimental-feature related settings
for (const auto & [name, value] : parsedContents) for (const auto & [name, value] : parsedContents)
if (name == "experimental-features" || name == "extra-experimental-features") if (name == "experimental-features" || name == "extra-experimental-features")
set(name, value); set(name, value, options);
// Then apply other settings // Then apply other settings
for (const auto & [name, value] : parsedContents) for (const auto & [name, value] : parsedContents)
if (name != "experimental-features" && name != "extra-experimental-features") if (name != "experimental-features" && name != "extra-experimental-features")
set(name, value); set(name, value, options);
} }
void Config::resetOverridden() void Config::resetOverridden()
@ -241,7 +250,7 @@ void AbstractSetting::convertToArg(Args & args, const std::string & category)
bool AbstractSetting::isOverridden() const { return overridden; } bool AbstractSetting::isOverridden() const { return overridden; }
template<> std::string BaseSetting<std::string>::parse(const std::string & str) const template<> std::string BaseSetting<std::string>::parse(const std::string & str, const ApplyConfigOptions & options) const
{ {
return str; return str;
} }
@ -251,7 +260,7 @@ template<> std::string BaseSetting<std::string>::to_string() const
return value; return value;
} }
template<> std::optional<std::string> BaseSetting<std::optional<std::string>>::parse(const std::string & str) const template<> std::optional<std::string> BaseSetting<std::optional<std::string>>::parse(const std::string & str, const ApplyConfigOptions & options) const
{ {
if (str == "") if (str == "")
return std::nullopt; return std::nullopt;
@ -264,7 +273,7 @@ template<> std::string BaseSetting<std::optional<std::string>>::to_string() cons
return value ? *value : ""; return value ? *value : "";
} }
template<> bool BaseSetting<bool>::parse(const std::string & str) const template<> bool BaseSetting<bool>::parse(const std::string & str, const ApplyConfigOptions & options) const
{ {
if (str == "true" || str == "yes" || str == "1") if (str == "true" || str == "yes" || str == "1")
return true; return true;
@ -297,12 +306,12 @@ template<> void BaseSetting<bool>::convertToArg(Args & args, const std::string &
}); });
} }
template<> Strings BaseSetting<Strings>::parse(const std::string & str) const template<> Strings BaseSetting<Strings>::parse(const std::string & str, const ApplyConfigOptions & options) const
{ {
return tokenizeString<Strings>(str); return tokenizeString<Strings>(str);
} }
template<> void BaseSetting<Strings>::appendOrSet(Strings newValue, bool append) template<> void BaseSetting<Strings>::appendOrSet(Strings newValue, bool append, const ApplyConfigOptions & options)
{ {
if (!append) value.clear(); if (!append) value.clear();
value.insert(value.end(), std::make_move_iterator(newValue.begin()), value.insert(value.end(), std::make_move_iterator(newValue.begin()),
@ -314,12 +323,12 @@ template<> std::string BaseSetting<Strings>::to_string() const
return concatStringsSep(" ", value); return concatStringsSep(" ", value);
} }
template<> StringSet BaseSetting<StringSet>::parse(const std::string & str) const template<> StringSet BaseSetting<StringSet>::parse(const std::string & str, const ApplyConfigOptions & options) const
{ {
return tokenizeString<StringSet>(str); return tokenizeString<StringSet>(str);
} }
template<> void BaseSetting<StringSet>::appendOrSet(StringSet newValue, bool append) template<> void BaseSetting<StringSet>::appendOrSet(StringSet newValue, bool append, const ApplyConfigOptions & options)
{ {
if (!append) value.clear(); if (!append) value.clear();
value.insert(std::make_move_iterator(newValue.begin()), std::make_move_iterator(newValue.end())); value.insert(std::make_move_iterator(newValue.begin()), std::make_move_iterator(newValue.end()));
@ -330,7 +339,7 @@ template<> std::string BaseSetting<StringSet>::to_string() const
return concatStringsSep(" ", value); return concatStringsSep(" ", value);
} }
template<> ExperimentalFeatures BaseSetting<ExperimentalFeatures>::parse(const std::string & str) const template<> ExperimentalFeatures BaseSetting<ExperimentalFeatures>::parse(const std::string & str, const ApplyConfigOptions & options) const
{ {
ExperimentalFeatures res{}; ExperimentalFeatures res{};
for (auto & s : tokenizeString<StringSet>(str)) { for (auto & s : tokenizeString<StringSet>(str)) {
@ -342,7 +351,7 @@ template<> ExperimentalFeatures BaseSetting<ExperimentalFeatures>::parse(const s
return res; return res;
} }
template<> void BaseSetting<ExperimentalFeatures>::appendOrSet(ExperimentalFeatures newValue, bool append) template<> void BaseSetting<ExperimentalFeatures>::appendOrSet(ExperimentalFeatures newValue, bool append, const ApplyConfigOptions & options)
{ {
if (append) if (append)
value = value | newValue; value = value | newValue;
@ -359,7 +368,7 @@ template<> std::string BaseSetting<ExperimentalFeatures>::to_string() const
return concatStringsSep(" ", stringifiedXpFeatures); return concatStringsSep(" ", stringifiedXpFeatures);
} }
template<> DeprecatedFeatures BaseSetting<DeprecatedFeatures>::parse(const std::string & str) const template<> DeprecatedFeatures BaseSetting<DeprecatedFeatures>::parse(const std::string & str, const ApplyConfigOptions & options) const
{ {
DeprecatedFeatures res{}; DeprecatedFeatures res{};
for (auto & s : tokenizeString<StringSet>(str)) { for (auto & s : tokenizeString<StringSet>(str)) {
@ -371,7 +380,7 @@ template<> DeprecatedFeatures BaseSetting<DeprecatedFeatures>::parse(const std::
return res; return res;
} }
template<> void BaseSetting<DeprecatedFeatures>::appendOrSet(DeprecatedFeatures newValue, bool append) template<> void BaseSetting<DeprecatedFeatures>::appendOrSet(DeprecatedFeatures newValue, bool append, const ApplyConfigOptions & options)
{ {
if (append) if (append)
value = value | newValue; value = value | newValue;
@ -388,7 +397,7 @@ template<> std::string BaseSetting<DeprecatedFeatures>::to_string() const
return concatStringsSep(" ", stringifiedDpFeatures); return concatStringsSep(" ", stringifiedDpFeatures);
} }
template<> StringMap BaseSetting<StringMap>::parse(const std::string & str) const template<> StringMap BaseSetting<StringMap>::parse(const std::string & str, const ApplyConfigOptions & options) const
{ {
StringMap res; StringMap res;
for (const auto & s : tokenizeString<Strings>(str)) { for (const auto & s : tokenizeString<Strings>(str)) {
@ -399,7 +408,7 @@ template<> StringMap BaseSetting<StringMap>::parse(const std::string & str) cons
return res; return res;
} }
template<> void BaseSetting<StringMap>::appendOrSet(StringMap newValue, bool append) template<> void BaseSetting<StringMap>::appendOrSet(StringMap newValue, bool append, const ApplyConfigOptions & options)
{ {
if (!append) value.clear(); if (!append) value.clear();
value.insert(std::make_move_iterator(newValue.begin()), std::make_move_iterator(newValue.end())); value.insert(std::make_move_iterator(newValue.begin()), std::make_move_iterator(newValue.end()));
@ -426,7 +435,7 @@ template class BaseSetting<StringMap>;
template class BaseSetting<ExperimentalFeatures>; template class BaseSetting<ExperimentalFeatures>;
template class BaseSetting<DeprecatedFeatures>; template class BaseSetting<DeprecatedFeatures>;
static Path parsePath(const AbstractSetting & s, const std::string & str) static Path parsePath(const AbstractSetting & s, const std::string & str, const ApplyConfigOptions & options)
{ {
if (str == "") if (str == "")
throw UsageError("setting '%s' is a path and paths cannot be empty", s.name); throw UsageError("setting '%s' is a path and paths cannot be empty", s.name);
@ -434,26 +443,26 @@ static Path parsePath(const AbstractSetting & s, const std::string & str)
return canonPath(str); return canonPath(str);
} }
template<> Path PathsSetting<Path>::parse(const std::string & str) const template<> Path PathsSetting<Path>::parse(const std::string & str, const ApplyConfigOptions & options) const
{ {
return parsePath(*this, str); return parsePath(*this, str, options);
} }
template<> std::optional<Path> PathsSetting<std::optional<Path>>::parse(const std::string & str) const template<> std::optional<Path> PathsSetting<std::optional<Path>>::parse(const std::string & str, const ApplyConfigOptions & options) const
{ {
if (str == "") if (str == "")
return std::nullopt; return std::nullopt;
else else
return parsePath(*this, str); return parsePath(*this, str, options);
} }
template<> Paths PathsSetting<Paths>::parse(const std::string & str) const template<> Paths PathsSetting<Paths>::parse(const std::string & str, const ApplyConfigOptions & options) const
{ {
auto strings = tokenizeString<Strings>(str); auto strings = tokenizeString<Strings>(str);
Paths parsed; Paths parsed;
for (auto str : strings) { for (auto str : strings) {
parsed.push_back(canonPath(str)); parsed.push_back(parsePath(*this, str, options));
} }
return parsed; return parsed;
@ -464,10 +473,10 @@ template class PathsSetting<std::optional<Path>>;
template class PathsSetting<Paths>; template class PathsSetting<Paths>;
bool GlobalConfig::set(const std::string & name, const std::string & value) bool GlobalConfig::set(const std::string & name, const std::string & value, const ApplyConfigOptions & options)
{ {
for (auto & config : *configRegistrations) for (auto & config : *configRegistrations)
if (config->set(name, value)) return true; if (config->set(name, value, options)) return true;
unknownSettings.emplace(name, value); unknownSettings.emplace(name, value);

View file

@ -10,6 +10,7 @@
#include "types.hh" #include "types.hh"
#include "experimental-features.hh" #include "experimental-features.hh"
#include "deprecated-features.hh" #include "deprecated-features.hh"
#include "apply-config-options.hh"
namespace nix { namespace nix {
@ -61,7 +62,7 @@ public:
* Sets the value referenced by `name` to `value`. Returns true if the * Sets the value referenced by `name` to `value`. Returns true if the
* setting is known, false otherwise. * setting is known, false otherwise.
*/ */
virtual bool set(const std::string & name, const std::string & value) = 0; virtual bool set(const std::string & name, const std::string & value, const ApplyConfigOptions & options = {}) = 0;
struct SettingInfo struct SettingInfo
{ {
@ -81,7 +82,7 @@ public:
* - contents: configuration contents to be parsed and applied * - contents: configuration contents to be parsed and applied
* - path: location of the configuration file * - path: location of the configuration file
*/ */
void applyConfig(const std::string & contents, const std::string & path = "<unknown>"); void applyConfig(const std::string & contents, const ApplyConfigOptions & options = {});
/** /**
* Resets the `overridden` flag of all Settings * Resets the `overridden` flag of all Settings
@ -155,7 +156,7 @@ public:
Config(StringMap initials = {}); Config(StringMap initials = {});
bool set(const std::string & name, const std::string & value) override; bool set(const std::string & name, const std::string & value, const ApplyConfigOptions & options = {}) override;
void addSetting(AbstractSetting * setting); void addSetting(AbstractSetting * setting);
@ -200,7 +201,7 @@ protected:
virtual ~AbstractSetting(); virtual ~AbstractSetting();
virtual void set(const std::string & value, bool append = false) = 0; virtual void set(const std::string & value, bool append = false, const ApplyConfigOptions & options = {}) = 0;
/** /**
* Whether the type is appendable; i.e. whether the `append` * Whether the type is appendable; i.e. whether the `append`
@ -237,7 +238,7 @@ protected:
* *
* Used by `set()`. * Used by `set()`.
*/ */
virtual T parse(const std::string & str) const; virtual T parse(const std::string & str, const ApplyConfigOptions & options) const;
/** /**
* Append or overwrite `value` with `newValue`. * Append or overwrite `value` with `newValue`.
@ -247,7 +248,7 @@ protected:
* *
* @param append Whether to append or overwrite. * @param append Whether to append or overwrite.
*/ */
virtual void appendOrSet(T newValue, bool append); virtual void appendOrSet(T newValue, bool append, const ApplyConfigOptions & options);
public: public:
@ -284,7 +285,7 @@ public:
* Uses `parse()` to get the value from `str`, and `appendOrSet()` * Uses `parse()` to get the value from `str`, and `appendOrSet()`
* to set it. * to set it.
*/ */
void set(const std::string & str, bool append = false) override final; void set(const std::string & str, bool append = false, const ApplyConfigOptions & options = {}) override final;
/** /**
* C++ trick; This is template-specialized to compile-time indicate whether * C++ trick; This is template-specialized to compile-time indicate whether
@ -373,7 +374,7 @@ public:
options->addSetting(this); options->addSetting(this);
} }
T parse(const std::string & str) const override; T parse(const std::string & str, const ApplyConfigOptions & options) const override;
void operator =(const T & v) { this->assign(v); } void operator =(const T & v) { this->assign(v); }
}; };
@ -384,7 +385,7 @@ struct GlobalConfig : public AbstractConfig
typedef std::vector<Config*> ConfigRegistrations; typedef std::vector<Config*> ConfigRegistrations;
static ConfigRegistrations * configRegistrations; static ConfigRegistrations * configRegistrations;
bool set(const std::string & name, const std::string & value) override; bool set(const std::string & name, const std::string & value, const ApplyConfigOptions & options = {}) override;
void getSettings(std::map<std::string, SettingInfo> & res, bool overriddenOnly = false) override; void getSettings(std::map<std::string, SettingInfo> & res, bool overriddenOnly = false) override;

View file

@ -80,7 +80,7 @@ namespace nix {
class TestSetting : public AbstractSetting { class TestSetting : public AbstractSetting {
public: public:
TestSetting() : AbstractSetting("test", "test", {}) {} TestSetting() : AbstractSetting("test", "test", {}) {}
void set(const std::string & value, bool append) override {} void set(const std::string & value, bool append, const ApplyConfigOptions & options) override {}
std::string to_string() const override { return {}; } std::string to_string() const override { return {}; }
bool isAppendable() override { return false; } bool isAppendable() override { return false; }
}; };

View file

@ -11,14 +11,13 @@ namespace nix {
class PathsSettingTestConfig : public Config class PathsSettingTestConfig : public Config
{ {
public: public:
PathsSettingTestConfig() PathsSettingTestConfig() : Config() {}
: Config()
{ }
PathsSetting<Paths> paths{this, Paths(), "paths", "documentation"}; PathsSetting<Paths> paths{this, Paths(), "paths", "documentation"};
}; };
struct PathsSettingTest : public ::testing::Test { struct PathsSettingTest : public ::testing::Test
{
public: public:
PathsSettingTestConfig mkConfig() PathsSettingTestConfig mkConfig()
{ {
@ -26,33 +25,27 @@ public:
} }
}; };
TEST_F(PathsSettingTest, parse) { TEST_F(PathsSettingTest, parse)
{
auto config = mkConfig(); auto config = mkConfig();
// Not an absolute path: // Not an absolute path:
ASSERT_THROW(config.paths.parse("puppy.nix"), Error); ASSERT_THROW(config.paths.parse("puppy.nix", {}), Error);
ASSERT_THAT( ASSERT_THAT(config.paths.parse("/puppy.nix", {}), Eq<Paths>({"/puppy.nix"}));
config.paths.parse("/puppy.nix"),
Eq<Paths>({"/puppy.nix"})
);
// Splits on whitespace: // Splits on whitespace:
ASSERT_THAT( ASSERT_THAT(
config.paths.parse("/puppy.nix /doggy.nix"), config.paths.parse("/puppy.nix /doggy.nix", {}), Eq<Paths>({"/puppy.nix", "/doggy.nix"})
Eq<Paths>({"/puppy.nix", "/doggy.nix"})
); );
// Splits on _any_ whitespace: // Splits on _any_ whitespace:
ASSERT_THAT( ASSERT_THAT(
config.paths.parse("/puppy.nix \t /doggy.nix\n\n\n/borzoi.nix\r/goldie.nix"), config.paths.parse("/puppy.nix \t /doggy.nix\n\n\n/borzoi.nix\r/goldie.nix", {}),
Eq<Paths>({"/puppy.nix", "/doggy.nix", "/borzoi.nix", "/goldie.nix"}) Eq<Paths>({"/puppy.nix", "/doggy.nix", "/borzoi.nix", "/goldie.nix"})
); );
// Canonicizes paths: // Canonicizes paths:
ASSERT_THAT( ASSERT_THAT(config.paths.parse("/puppy/../doggy.nix", {}), Eq<Paths>({"/doggy.nix"}));
config.paths.parse("/puppy/../doggy.nix"),
Eq<Paths>({"/doggy.nix"})
);
} }
TEST_F(PathsSettingTest, append) { TEST_F(PathsSettingTest, append) {
@ -61,26 +54,17 @@ TEST_F(PathsSettingTest, append) {
ASSERT_TRUE(config.paths.isAppendable()); ASSERT_TRUE(config.paths.isAppendable());
// Starts with no paths: // Starts with no paths:
ASSERT_THAT( ASSERT_THAT(config.paths.get(), Eq<Paths>({}));
config.paths.get(),
Eq<Paths>({})
);
// Can append a path: // Can append a path:
config.paths.set("/puppy.nix", true); config.paths.set("/puppy.nix", true);
ASSERT_THAT( ASSERT_THAT(config.paths.get(), Eq<Paths>({"/puppy.nix"}));
config.paths.get(),
Eq<Paths>({"/puppy.nix"})
);
// Can append multiple paths: // Can append multiple paths:
config.paths.set("/silly.nix /doggy.nix", true); config.paths.set("/silly.nix /doggy.nix", true);
ASSERT_THAT( ASSERT_THAT(config.paths.get(), Eq<Paths>({"/puppy.nix", "/silly.nix", "/doggy.nix"}));
config.paths.get(),
Eq<Paths>({"/puppy.nix", "/silly.nix", "/doggy.nix"})
);
} }
} // namespace nix } // namespace nix