Skip to content

Commit

Permalink
Merge pull request #3631 from andir/libutil-config-tests
Browse files Browse the repository at this point in the history
Add unit tests for config.cc
  • Loading branch information
edolstra authored May 28, 2020
2 parents de141fc + fc137d2 commit f60ce4f
Show file tree
Hide file tree
Showing 3 changed files with 383 additions and 46 deletions.
95 changes: 49 additions & 46 deletions src/libutil/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,60 +65,63 @@ void Config::getSettings(std::map<std::string, SettingInfo> & res, bool override
res.emplace(opt.first, SettingInfo{opt.second.setting->to_string(), opt.second.setting->description});
}

void AbstractConfig::applyConfigFile(const Path & path)
{
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;
void AbstractConfig::applyConfig(const std::string & contents, const std::string & 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)
throw UsageError("illegal configuration line '%1%' in '%2%'", line, path);

auto include = false;
auto ignoreMissing = false;
if (tokens[0] == "include")
include = true;
else if (tokens[0] == "!include") {
include = true;
ignoreMissing = true;
}

if (tokens.size() < 2)
if (include) {
if (tokens.size() != 2)
throw UsageError("illegal configuration line '%1%' in '%2%'", line, path);

auto include = false;
auto ignoreMissing = false;
if (tokens[0] == "include")
include = true;
else if (tokens[0] == "!include") {
include = true;
ignoreMissing = true;
auto p = absPath(tokens[1], dirOf(path));
if (pathExists(p)) {
applyConfigFile(p);
} else if (!ignoreMissing) {
throw Error("file '%1%' included from '%2%' not found", p, path);
}
continue;
}

if (include) {
if (tokens.size() != 2)
throw UsageError("illegal configuration line '%1%' in '%2%'", line, path);
auto p = absPath(tokens[1], dirOf(path));
if (pathExists(p)) {
applyConfigFile(p);
} else if (!ignoreMissing) {
throw Error("file '%1%' included from '%2%' not found", p, path);
}
continue;
}
if (tokens[1] != "=")
throw UsageError("illegal configuration line '%1%' in '%2%'", line, path);

if (tokens[1] != "=")
throw UsageError("illegal configuration line '%1%' in '%2%'", line, path);
string name = tokens[0];

string name = tokens[0];
vector<string>::iterator i = tokens.begin();
advance(i, 2);

vector<string>::iterator i = tokens.begin();
advance(i, 2);
set(name, concatStringsSep(" ", Strings(i, tokens.end()))); // FIXME: slow
};
}

set(name, concatStringsSep(" ", Strings(i, tokens.end()))); // FIXME: slow
};
void AbstractConfig::applyConfigFile(const Path & path)
{
try {
string contents = readFile(path);
applyConfig(contents, path);
} catch (SysError &) { }
}

Expand Down
70 changes: 70 additions & 0 deletions src/libutil/config.hh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,38 @@

namespace nix {

/**
* The Config class provides Nix runtime configurations.
*
* What is a Configuration?
* A collection of uniquely named Settings.
*
* What is a Setting?
* Each property that you can set in a configuration corresponds to a
* `Setting`. A setting records value and description of a property
* with a default and optional aliases.
*
* A valid configuration consists of settings that are registered to a
* `Config` object instance:
*
* Config config;
* Setting<std::string> systemSetting{&config, "x86_64-linux", "system", "the current system"};
*
* The above creates a `Config` object and registers a setting called "system"
* via the variable `systemSetting` with it. The setting defaults to the string
* "x86_64-linux", it's description is "the current system". All of the
* registered settings can then be accessed as shown below:
*
* std::map<std::string, Config::SettingInfo> settings;
* config.getSettings(settings);
* config["system"].description == "the current system"
* config["system"].value == "x86_64-linux"
*
*
* The above retrieves all currently known settings from the `Config` object
* and adds them to the `settings` map.
*/

class Args;
class AbstractSetting;
class JSONPlaceholder;
Expand All @@ -23,6 +55,10 @@ protected:

public:

/**
* Sets the value referenced by `name` to `value`. Returns true if the
* setting is known, false otherwise.
*/
virtual bool set(const std::string & name, const std::string & value) = 0;

struct SettingInfo
Expand All @@ -31,18 +67,52 @@ public:
std::string description;
};

/**
* Adds the currently known settings to the given result map `res`.
* - res: map to store settings in
* - overridenOnly: when set to true only overridden settings will be added to `res`
*/
virtual void getSettings(std::map<std::string, SettingInfo> & res, bool overridenOnly = false) = 0;

/**
* Parses the configuration in `contents` and applies it
* - contents: configuration contents to be parsed and applied
* - path: location of the configuration file
*/
void applyConfig(const std::string & contents, const std::string & path = "<unknown>");

/**
* Applies a nix configuration file
* - path: the location of the config file to apply
*/
void applyConfigFile(const Path & path);

/**
* Resets the `overridden` flag of all Settings
*/
virtual void resetOverriden() = 0;

/**
* Outputs all settings to JSON
* - out: JSONObject to write the configuration to
*/
virtual void toJSON(JSONObject & out) = 0;

/**
* Converts settings to `Args` to be used on the command line interface
* - args: args to write to
* - category: category of the settings
*/
virtual void convertToArgs(Args & args, const std::string & category) = 0;

/**
* Logs a warning for each unregistered setting
*/
void warnUnknownSettings();

/**
* Re-applies all previously attempted changes to unknown settings
*/
void reapplyUnknownSettings();
};

Expand Down
Loading

0 comments on commit f60ce4f

Please sign in to comment.