RSC  0.16.0
Configuration.cpp
Go to the documentation of this file.
1 /* ============================================================
2  *
3  * This file is part of the RSC project
4  *
5  * Copyright (C) 2012, 2013, 2016 Jan Moringen <jmoringe@techfak.uni-bielefeld.de>
6  *
7  * This file may be licensed under the terms of the
8  * GNU Lesser General Public License Version 3 (the ``LGPL''),
9  * or (at your option) any later version.
10  *
11  * Software distributed under the License is distributed
12  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
13  * express or implied. See the LGPL for the specific language
14  * governing rights and limitations.
15  *
16  * You should have received a copy of the LGPL along with this
17  * program. If not, go to http://www.gnu.org/licenses/lgpl.html
18  * or write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  * The development of this software was supported by:
22  * CoR-Lab, Research Institute for Cognition and Robotics
23  * Bielefeld University
24  *
25  * ============================================================ */
26 
27 #include "Configuration.h"
28 
29 #include <stdexcept>
30 
31 #include <boost/tuple/tuple.hpp> // for boost::tie
32 #include <boost/lexical_cast.hpp>
33 #include <boost/format.hpp>
34 #include <boost/filesystem/fstream.hpp>
35 
36 #include "../logging/Logger.h"
37 #include "../logging/LoggerFactory.h"
38 
39 #include "Environment.h"
40 #include "ConfigFileSource.h"
42 
43 #include "Utility.h"
44 
45 using namespace std;
46 
47 using namespace rsc::logging;
48 
49 namespace rsc {
50 namespace config {
51 
52 const std::string DEFAULT_DEBUG_VARIABLE_NAME = "__CONFIG_DEBUG";
53 
54 const std::string DEFAULT_FILE_VARIABLE_NAME = "__CONFIG_FILES";
55 
56 const std::string CONFIG_FILE_KEY_PREFIX = "%prefix";
57 const std::string CONFIG_FILE_KEY_USER = "%user";
58 const std::string CONFIG_FILE_KEY_PWD = "%pwd";
59 
61  static LoggerPtr logger
62  = logging::LoggerFactory::getInstance().getLogger("rsc.config.configure()");
63  return logger;
64 }
65 
66 std::vector<std::string>
67 defaultConfigurationFiles(const std::string& fileVariableName) {
68  boost::shared_ptr<std::string> files;
69  if ((files = getEnvironmentVariable(fileVariableName))) {
70  return splitSequenceValue(*files);
71  } else {
72  std::vector<std::string> result;
73  result.push_back(CONFIG_FILE_KEY_PREFIX);
74  result.push_back(CONFIG_FILE_KEY_USER);
75  result.push_back(CONFIG_FILE_KEY_PWD);
76  return result;
77  }
78 }
79 
80 std::pair<boost::filesystem::path, std::string>
81 resolveConfigurationFile(const std::string& spec,
82  const boost::filesystem::path& prefix,
83  const std::string& configFileName) {
84  if (spec == CONFIG_FILE_KEY_PREFIX) {
86  / configFileName,
87  "Prefix wide config file");
88  } else if (spec == CONFIG_FILE_KEY_USER) {
90  / configFileName,
91  "User config file");
92  } else if (spec == CONFIG_FILE_KEY_PWD) {
93  return std::make_pair(configFileName,
94  "Current directory file");
95  } else {
96  return std::make_pair(boost::filesystem::path(spec),
97  "User specified config file");
98  }
99 }
100 
101 void describeFileStream(const std::string& label,
102  const boost::filesystem::path& path,
103  const istream& stream) {
104  cerr << " " << label << " " << path << " "
105  << (stream ? "exists" : "does not exist") << endl;
106 }
107 
108 void processConfigFile(unsigned int index,
109  const std::string& spec,
110  const boost::filesystem::path& prefix,
111  const std::string& configFileName,
112  bool debug,
114  boost::filesystem::path file;
115  std::string description;
116  try {
117  boost::tie(file, description)
118  = resolveConfigurationFile(spec, prefix, configFileName);
119  } catch (const runtime_error& e) {
120  RSCWARN(getLogger(),
121  "Failed to resolve configuration file designated by "
122  << spec << "': " << e.what());
123  return;
124  }
125  try {
126 
127  boost::filesystem::ifstream stream(file);
128  if (debug) {
129  describeFileStream(" " + boost::lexical_cast<string>(index) + ". "
130  + description,
131  file, stream);
132  }
133  if (stream) {
134  ConfigFileSource source(stream);
135  source.provideOptions(handler);
136  }
137  } catch (const runtime_error& e) {
138  RSCWARN(getLogger(),
139  "Failed to process " << description << " `"
140  << file << "': " << e.what());
141  }
142 }
143 
145  const string& configFileName,
146  const string& environmentVariablePrefix,
147  int argc,
148  const char** argv,
149  bool stripEnvironmentVariablePrefix,
150  const boost::filesystem::path& prefix,
151  const std::string& debugVariableName,
152  const std::vector<std::string>& configurationFiles) {
153  bool debug = getEnvironmentVariable(debugVariableName).get();
154 
155  // 0) In debug mode, header first.
156  if (debug) {
157  cerr << "Configuring with sources (lowest priority first)" << endl;
158  }
159 
160  // 1) Configuration files
161  // (lowest priority)
162  if (debug) {
163  cerr << " 1. Configuration files" << endl;
164  }
165  unsigned int index = 1;
166  for (std::vector<std::string>::const_iterator it = configurationFiles.begin();
167  it != configurationFiles.end(); ++it) {
168  processConfigFile(index++, *it, prefix, configFileName, debug, handler);
169  }
170 
171  // 2) Add environment Variables
172  {
173  EnvironmentVariableSource source(environmentVariablePrefix,
174  stripEnvironmentVariablePrefix);
175  if (debug) {
176  cerr << " 2. Environment variables with prefix "
177  << environmentVariablePrefix << endl;
179  if (!matches.empty()) {
180  for (EnvironmentVariableSource::Matches::const_iterator it
181  = matches.begin(); it != matches.end(); ++it) {
182  cerr << " "
183  << it->getRawName();
184  if (it->getRawName() != it->getTransformedName()) {
185  cerr << " (mapped to "
186  << it->getTransformedName()
187  << ")";
188  }
189  cerr << " -> " << it->getValue()
190  << endl;
191  }
192  } else {
193  cerr << " <none>" << endl;
194  }
195  }
196  source.provideOptions(handler);
197  }
198 
199  // 3) Command line
200  // (highest priority)
201  if (debug) {
202  cerr << " 3. Commandline options" << endl;
203  }
204  if (argc > 0) {
205  if (debug){
206  for (int i = 0; i < argc; ++i) {
207  cerr << " " << argv[i] << endl;
208  }
209  }
210  CommandLinePropertySource source(argc, argv);
211  source.provideOptions(handler);
212  } else {
213  if (debug) {
214  cerr << " <none>" << endl;
215  }
216  }
217 
218 }
219 
220 }
221 }
void provideOptions(OptionHandler &handler)
Implementations should pass all configuration options to handler.
path userConfigDirectory()
Return the canonical directory for configuration files of the user associated with the current proces...
const std::string CONFIG_FILE_KEY_PWD
void describeFileStream(const std::string &label, const boost::filesystem::path &path, const istream &stream)
Matches getMatches()
Return matching environment variables.
Objects of this class analyze the environment of the current process, finding environment variables w...
Definition: Environment.h:115
Objects of this class parse streams that contain configuration information in "ini-file" syntax...
A source for options from the command line using a -D java properties-like syntax.
vector< string > splitSequenceValue(const string &value)
Definition: Utility.cpp:39
void processConfigFile(unsigned int index, const std::string &spec, const boost::filesystem::path &prefix, const std::string &configFileName, bool debug, OptionHandler &handler)
void provideOptions(OptionHandler &handler)
Implementations should pass all configuration options to handler.
const std::string DEFAULT_DEBUG_VARIABLE_NAME
Implementations of this interface receive options from ConfigSource objects.
Definition: OptionHandler.h:43
STL namespace.
pair< _T1, _T2 > make_pair(_T1 __x, _T2 __y)
A convenience wrapper for creating a pair from two objects.
std::pair< boost::filesystem::path, std::string > resolveConfigurationFile(const std::string &spec, const boost::filesystem::path &prefix, const std::string &configFileName)
Return a pair of configuration file path and description derived from spec.
boost::shared_ptr< std::string > getEnvironmentVariable(const std::string &name)
Return the value of the environment value name or an empty pointer.
path prefixConfigDirectory(const path &prefix)
Definition: Environment.cpp:64
std::vector< std::string > defaultConfigurationFiles(const std::string &fileVariableName)
#define RSCWARN(logger, msg)
Definition: Logger.h:231
LoggerPtr getLogger()
const std::string DEFAULT_FILE_VARIABLE_NAME
const std::string CONFIG_FILE_KEY_PREFIX
Provides a hierarchical logging system with the possibility to install different backends, which are instances of LoggingSystem.
const std::string CONFIG_FILE_KEY_USER
void handler(int signal)
void configure(OptionHandler &handler, const string &configFileName, const string &environmentVariablePrefix, int argc, const char **argv, bool stripEnvironmentVariablePrefix, const boost::filesystem::path &prefix, const std::string &debugVariableName, const std::vector< std::string > &configurationFiles)
Pass configuration options in from configuration files derived from configFileName and environment va...
void provideOptions(OptionHandler &handler)
Implementations should pass all configuration options to handler.
boost::shared_ptr< Logger > LoggerPtr
Definition: Logger.h:41