Vcsn  2.8
Be Rational
configuration.cc
Go to the documentation of this file.
1 #include <boost/filesystem.hpp>
2 #include <boost/algorithm/string.hpp>
3 
4 #include <vcsn/config.hh> // VCSN_DATADIR
6 #include <vcsn/misc/raise.hh>
7 #include <vcsn/misc/stream.hh>
9 
10 namespace vcsn
11 {
12  namespace detail
13  {
14  namespace
15  {
16  config::Node load_file(const boost::filesystem::path& p)
17  {
18  require(boost::filesystem::exists(p),
19  "config file does not exist:", p);
20  return YAML::LoadFile(p.string());
21  }
22 
23  // Templated because node[] gives us rvalues.
24  template <typename T>
25  void merge_recurse(const config::Node& from, T&& out)
26  {
27  if (from.IsScalar() || from.IsSequence())
28  out = from;
29  else if (from.IsMap())
30  for (auto e : from)
31  {
32  auto key = e.first.as<std::string>();
33  if (!out[key])
34  {
35  auto node = config::Node{};
36  merge_recurse(e.second, node);
37  out[key] = node;
38  }
39  else if (out.Tag() != "!StyleList")
40  merge_recurse(e.second, out[key]);
41  else
42  raise("bad config value");
43  }
44  }
45  }
46 
48  : node_{n}
49  {}
50 
52  : node_{other.node_}
53  {}
54 
56  : node_{c.config_tree_}
57  {}
58 
61  {
62  swap(*this, rhs);
63  return *this;
64  }
65 
66  std::string config::value::str() const
67  {
68  return as<std::string>();
69  }
70 
72  config::value::operator[](const std::string& key) const
73  {
74  require(node_.IsMap(),
75  "configuration: requesting a key (", key,
76  ") in a leaf");
77  require(node_[key].IsDefined(),
78  "configuration: invalid key: ", key);
79  return value(node_[key]);
80  }
81 
82  std::vector<std::string> config::value::keys() const
83  {
84  // We generate the key only once for each value
85  if (!keys_)
86  keys_ = gen_keys();
87  return *keys_;
88  }
89 
90  bool config::value::is_valid(const std::string& key) const
91  {
92  return node_[key].IsDefined();
93  }
94 
95  void config::value::remove(const std::string& key)
96  {
97 #if VCSN_YAML_CPP_REMOVE_WORKS
98  node_.remove(key);
99 #else
100  raise("configuration: libyaml-cpp is broken, cannot remove node ", key);
101 #endif
102  }
103 
105  {
106  require(node_.IsSequence(), "configuration: node is not a sequence");
107  return node_.begin();
108  }
109 
111  {
112  return node_.end();
113  }
114 
115  void config::value::merge(const value& from)
116  {
117  auto dest_node = Clone(from.node_);
118  merge_recurse(node_, dest_node);
119  node_ = dest_node;
120  }
121 
122  std::ostream& config::value::print(std::ostream& out) const
123  {
124  return out << node_;
125  }
126 
127  std::unique_ptr<std::vector<std::string>>
129  {
130  auto res = std::make_unique<std::vector<std::string>>();
131  require(node_.IsMap(), "configuration: node is not a map");
132 
133  for (auto e : node_)
134  res->emplace_back(e.first.as<std::string>());
135 
136  // We must sort the keys to have a deterministic output
137  std::sort(res->begin(), res->end());
138  return res;
139  }
140 
141  void swap(config::value& first, config::value& second)
142  {
143  using std::swap;
144  swap(first.node_, second.node_);
145  swap(first.keys_, second.keys_);
146  }
147 
149  {
150  auto path = xgetenv("VCSN_DATA_PATH", VCSN_DATADIR);
151  auto flib = file_library{path, ":"};
152 
153  // Base config.
154  config_tree_ = load_file(flib.find_file("config.yaml"));
155  // Version file.
156  merge_recurse(load_file(flib.find_file("version.yaml")),
157  config_tree_);
158  // User config.
159  if (!std::getenv("VCSN_NO_HOME_CONFIG"))
160  {
161  auto p = expand_tilda("~/.vcsn/config.yaml");
162  if (boost::filesystem::exists(p))
163  merge_recurse(YAML::LoadFile(p), config_tree_);
164  }
165  }
166 
167  config::value config::operator[](const std::string& key)
168  {
169  // We don't return the YAML node directly to make sure to be
170  // able to change the underlying library.
171  return value(config_tree_)[key];
172  }
173  }
174 
175  std::string configuration(const std::string& key)
176  {
177  // We need a unique_pointers because subscripting returns rvalues.
178  auto config = std::make_unique<detail::config::value>(get_config());
179  auto subkeys = std::vector<std::string>{};
180  boost::split(subkeys, key, boost::is_any_of("."));
181 
182  if (subkeys.size() == 2 && subkeys[0] == "configuration")
183  {
184  auto env_var = "VCSN_" + boost::to_upper_copy(subkeys[1]);
185  if (auto res = std::getenv(env_var.c_str()))
186  return res;
187  }
188 
189  for (const auto& subkey : subkeys)
190  config =
191  std::make_unique<detail::config::value>((*config)[subkey]);
192 
193  return config->str();
194  }
195 }
void remove(const std::string &key)
Remove a key.
bool is_valid(const std::string &key) const
Check that this node refers to a key that exists in the tree.
std::string xgetenv(const std::string &var, const std::string &val="")
getenv(var) if defined, otherwise val.
Definition: stream.cc:229
rat::expression_polynomial_t< ExpSet > split(const ExpSet &rs, const typename ExpSet::value_t &e)
Split an expression.
Definition: split.hh:227
auto sort(const Aut &a) -> permutation_automaton< Aut >
Definition: sort.hh:161
config()
Load all the configuration files.
The class returned by [] operators.
friend void swap(value &first, value &second)
std::unique_ptr< std::vector< std::string > > gen_keys() const
std::string expand_tilda(const std::string &res)
Expand initial "~" in res.
Definition: stream.cc:58
Explicit path representation.
Definition: path.hh:16
A YAML configuration.
std::string str() const
Get the node value as a string.
std::string configuration(const std::string &key)
Get the string mapped by key (e.g., "configuration.version", "dot.styles").
Definition: a-star.hh:8
value & operator=(value rhs)
Assign a new value to this key.
std::vector< std::string > keys() const
void swap(config::value &first, config::value &second)
Manage search paths.
Definition: file-library.hh:22
detail::config & get_config()
Get the configuration singleton.
value operator[](const std::string &key) const
value operator[](const std::string &key)
Access a subkey.
Manage sets of inclusion paths.
std::unique_ptr< const std::vector< std::string > > keys_
std::ostream & print(std::ostream &out) const
void require(Bool b, Args &&... args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:87
return res
Definition: multiply.hh:399
void merge(const value &from)
Merge a value into another one - and modify the first.
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.
Definition: automaton.hh:86