1
0
Fork 0

added @include

This commit is contained in:
Frank Celler 2016-06-09 14:19:54 +02:00
parent 887093bbb9
commit cb05777f32
3 changed files with 88 additions and 42 deletions

View File

@ -24,9 +24,9 @@
#include <iostream> #include <iostream>
#include "Logger/Logger.h"
#include "Basics/FileUtils.h" #include "Basics/FileUtils.h"
#include "Basics/StringUtils.h" #include "Basics/StringUtils.h"
#include "Logger/Logger.h"
#include "ProgramOptions/IniFileParser.h" #include "ProgramOptions/IniFileParser.h"
#include "ProgramOptions/ProgramOptions.h" #include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h" #include "ProgramOptions/Section.h"
@ -51,99 +51,127 @@ void ConfigFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
options->addOption("--configuration,-c", "the configuration file or 'none'", options->addOption("--configuration,-c", "the configuration file or 'none'",
new StringParameter(&_file)); new StringParameter(&_file));
// add --config as an alias for --configuration. both point to the same variable! // add --config as an alias for --configuration. both point to the same
// variable!
options->addHiddenOption("--config", "the configuration file or 'none'", options->addHiddenOption("--config", "the configuration file or 'none'",
new StringParameter(&_file)); new StringParameter(&_file));
options->addOption("--check-configuration", "check the configuration and exists", options->addOption("--check-configuration",
"check the configuration and exists",
new BooleanParameter(&_checkConfiguration)); new BooleanParameter(&_checkConfiguration));
} }
void ConfigFeature::loadOptions(std::shared_ptr<ProgramOptions> options) { void ConfigFeature::loadOptions(std::shared_ptr<ProgramOptions> options) {
loadConfigFile(options); loadConfigFile(options, _progname);
if (_checkConfiguration) { if (_checkConfiguration) {
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
} }
void ConfigFeature::loadConfigFile(std::shared_ptr<ProgramOptions> options) { void ConfigFeature::loadConfigFile(std::shared_ptr<ProgramOptions> options,
std::string const& progname) {
if (StringUtils::tolower(_file) == "none") { if (StringUtils::tolower(_file) == "none") {
LOG_TOPIC(DEBUG, Logger::CONFIG) << "use no config file at all"; LOG_TOPIC(DEBUG, Logger::CONFIG) << "use no config file at all";
return; return;
} }
IniFileParser parser(options.get()); std::vector<std::string> files;
std::set<std::string> seen;
// always prefer an explicitly given config file // always prefer an explicitly given config file
if (!_file.empty()) { if (_file.empty()) {
files.emplace_back(progname);
} else {
LOG_TOPIC(DEBUG, Logger::CONFIG) << "using user supplied conifg file '" LOG_TOPIC(DEBUG, Logger::CONFIG) << "using user supplied conifg file '"
<< _file << "'"; << _file << "'";
IniFileParser parser(options.get());
if (!parser.parse(_file)) { if (!parser.parse(_file)) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
return; auto includes = parser.includes();
files.insert(files.end(), includes.begin(), includes.end());
LOG_TOPIC(DEBUG, Logger::CONFIG) << "seen @includes: " << includes;
} }
// clang-format off for (size_t i = 0; i < files.size(); ++i) {
// auto name = files[i];
// check in order:
//
// <PRGNAME>.conf
// ./etc/relative/<PRGNAME>.conf
// ${HOME}/.arangodb/<PRGNAME>.conf
// /etc/arangodb/<PRGNAME>.conf
//
// clang-format on
std::string basename = _progname + ".conf"; if (seen.find(name) != seen.end()) {
std::string filename = LOG(FATAL) << "circluar includes, seen '" << name << "' twice";
FileUtils::buildFilename(FileUtils::currentDirectory(), basename); FATAL_ERROR_EXIT();
}
LOG_TOPIC(DEBUG, Logger::CONFIG) << "checking '" << filename << "'"; seen.insert(name);
if (!FileUtils::exists(filename)) { // clang-format off
filename = FileUtils::buildFilename(FileUtils::currentDirectory(), //
"etc/relative/" + basename); // check in order:
//
// <PRGNAME>.conf
// ./etc/relative/<PRGNAME>.conf
// ${HOME}/.arangodb/<PRGNAME>.conf
// /etc/arangodb/<PRGNAME>.conf
//
// clang-format on
std::string basename = name + ".conf";
std::string filename =
FileUtils::buildFilename(FileUtils::currentDirectory(), basename);
LOG_TOPIC(DEBUG, Logger::CONFIG) << "checking '" << filename << "'"; LOG_TOPIC(DEBUG, Logger::CONFIG) << "checking '" << filename << "'";
if (!FileUtils::exists(filename)) { if (!FileUtils::exists(filename)) {
filename = FileUtils::buildFilename(FileUtils::homeDirectory(), basename); filename = FileUtils::buildFilename(FileUtils::currentDirectory(),
"etc/relative/" + basename);
LOG_TOPIC(DEBUG, Logger::CONFIG) << "checking '" << filename << "'"; LOG_TOPIC(DEBUG, Logger::CONFIG) << "checking '" << filename << "'";
if (!FileUtils::exists(filename)) { if (!FileUtils::exists(filename)) {
filename = filename =
FileUtils::buildFilename(FileUtils::configDirectory(), basename); FileUtils::buildFilename(FileUtils::homeDirectory(), basename);
LOG_TOPIC(DEBUG, Logger::CONFIG) << "checking '" << filename << "'"; LOG_TOPIC(DEBUG, Logger::CONFIG) << "checking '" << filename << "'";
if (!FileUtils::exists(filename)) { if (!FileUtils::exists(filename)) {
LOG_TOPIC(DEBUG, Logger::CONFIG) << "cannot find any config file"; filename =
return; FileUtils::buildFilename(FileUtils::configDirectory(), basename);
LOG_TOPIC(DEBUG, Logger::CONFIG) << "checking '" << filename << "'";
if (!FileUtils::exists(filename)) {
LOG_TOPIC(DEBUG, Logger::CONFIG) << "cannot find any config file";
return;
}
} }
} }
} }
}
std::string local = filename + ".local"; IniFileParser parser(options.get());
LOG_TOPIC(DEBUG, Logger::CONFIG) << "checking override '" << local << "'"; std::string local = filename + ".local";
if (FileUtils::exists(local)) { LOG_TOPIC(DEBUG, Logger::CONFIG) << "checking override '" << local << "'";
LOG_TOPIC(DEBUG, Logger::CONFIG) << "loading '" << local << "'";
if (!parser.parse(local)) { if (FileUtils::exists(local)) {
LOG_TOPIC(DEBUG, Logger::CONFIG) << "loading '" << local << "'";
if (!parser.parse(local)) {
exit(EXIT_FAILURE);
}
}
LOG_TOPIC(DEBUG, Logger::CONFIG) << "loading '" << filename << "'";
if (!parser.parse(filename)) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
}
LOG_TOPIC(DEBUG, Logger::CONFIG) << "loading '" << filename << "'"; auto includes = parser.includes();
files.insert(files.end(), includes.begin(), includes.end());
if (!parser.parse(filename)) {
exit(EXIT_FAILURE);
} }
} }

View File

@ -40,7 +40,8 @@ class ConfigFeature final : public application_features::ApplicationFeature {
bool _checkConfiguration; bool _checkConfiguration;
private: private:
void loadConfigFile(std::shared_ptr<options::ProgramOptions>); void loadConfigFile(std::shared_ptr<options::ProgramOptions>,
std::string const& progname);
private: private:
std::string _progname; std::string _progname;

View File

@ -47,6 +47,10 @@ class IniFileParser {
_matchers.assignment = std::regex( _matchers.assignment = std::regex(
"^[ \t]*(([-_A-Za-z0-9]*\\.)?[-_A-Za-z0-9]*)[ \t]*=[ \t]*(.*?)?[ \t]*$", "^[ \t]*(([-_A-Za-z0-9]*\\.)?[-_A-Za-z0-9]*)[ \t]*=[ \t]*(.*?)?[ \t]*$",
std::regex::ECMAScript); std::regex::ECMAScript);
// an include line
_matchers.include = std::regex(
"^[ \t]*@include[ \t]*([-_A-Za-z0-9]*)[ \t]*$",
std::regex::ECMAScript);
} }
// parse a config file. returns true if all is well, false otherwise // parse a config file. returns true if all is well, false otherwise
@ -80,6 +84,12 @@ class IniFileParser {
if (std::regex_match(line, match, _matchers.section)) { if (std::regex_match(line, match, _matchers.section)) {
// found section // found section
currentSection = match[1].str(); currentSection = match[1].str();
} else if (std::regex_match(line, match, _matchers.include)) {
// found include
std::string option;
std::string value(match[1].str());
_includes.emplace_back(value);
} else if (std::regex_match(line, match, _matchers.assignment)) { } else if (std::regex_match(line, match, _matchers.assignment)) {
// found assignment // found assignment
std::string option; std::string option;
@ -107,13 +117,20 @@ class IniFileParser {
return true; return true;
} }
// seen includes
std::vector<std::string> const& includes() const {
return _includes;
}
private: private:
ProgramOptions* _options; ProgramOptions* _options;
std::vector<std::string> _includes;
struct { struct {
std::regex comment; std::regex comment;
std::regex section; std::regex section;
std::regex assignment; std::regex assignment;
std::regex include;
} _matchers; } _matchers;
}; };
} }