Unverified Commit d8c9e70b authored by Dominik Charousset's avatar Dominik Charousset Committed by GitHub

Merge pull request #1338

Generate valid config syntax from --dump-config
parents 2cfdc177 3ddfd00d
...@@ -22,6 +22,7 @@ is based on [Keep a Changelog](https://keepachangelog.com). ...@@ -22,6 +22,7 @@ is based on [Keep a Changelog](https://keepachangelog.com).
### Changed ### Changed
- Remote spawning of actors is no longer considered experimental. - Remote spawning of actors is no longer considered experimental.
- The output of `--dump-config` now prints valid config file syntax.
### Deprecated ### Deprecated
......
...@@ -238,27 +238,100 @@ std::ostream& operator<<(std::ostream& out, indentation indent) { ...@@ -238,27 +238,100 @@ std::ostream& operator<<(std::ostream& out, indentation indent) {
return out; return out;
} }
void print(const config_value::dictionary& xs, indentation indent) { // Fakes a buffer interface but really prints to std::cout.
struct out_buf {
int end() {
return 0;
}
void push_back(char c) {
std::cout << c;
}
template <class Iterator, class Sentinel>
void insert(int, Iterator i, Sentinel e) {
while (i != e)
std::cout << *i++;
}
};
void print(const config_value::dictionary& xs, indentation indent);
void print_val(const config_value& val, indentation indent) {
out_buf out;
using std::cout; using std::cout;
for (const auto& kvp : xs) { switch (val.get_data().index()) {
if (kvp.first == "dump-config") default: // none
continue; // omit
if (auto submap = get_if<config_value::dictionary>(&kvp.second)) { break;
cout << indent << kvp.first << " {\n"; case 1: // integer
print(*submap, indent + 2); detail::print(out, get<config_value::integer>(val));
cout << indent << "}\n"; break;
} else if (auto lst = get_if<config_value::list>(&kvp.second)) { case 2: // boolean
if (lst->empty()) { detail::print(out, get<config_value::boolean>(val));
cout << indent << kvp.first << " = []\n"; break;
case 3: // real
detail::print(out, get<config_value::real>(val));
break;
case 4: // timespan
detail::print(out, get<timespan>(val));
break;
case 5: // uri
cout << '<' << get<uri>(val).str() << '>';
break;
case 6: // string
detail::print_escaped(out, get<std::string>(val));
break;
case 7: { // list
auto& xs = get<config_value::list>(val);
if (xs.empty()) {
cout << "[]";
} else { } else {
cout << indent << kvp.first << " = [\n";
auto list_indent = indent + 2; auto list_indent = indent + 2;
for (auto& x : *lst) cout << "[\n";
cout << list_indent << to_string(x) << ",\n"; for (auto& x : xs) {
cout << indent << "]\n"; cout << list_indent;
print_val(x, list_indent);
cout << ",\n";
}
cout << indent << ']';
}
break;
}
case 8: { // dictionary
print(get<config_value::dictionary>(val), indent + 2);
}
} }
}
bool needs_quotes(const std::string& key) {
auto is_alnum_or_dash = [](char x) {
return isalnum(x) || x == '-' || x == '_';
};
return key.empty() || !std::all_of(key.begin(), key.end(), is_alnum_or_dash);
}
void print(const config_value::dictionary& xs, indentation indent) {
out_buf out;
using std::cout;
bool top_level = indent.size == 0;
for (const auto& [key, val] : xs) {
if (!top_level || (key != "dump-config" && key != "config-file")) {
cout << indent;
if (!needs_quotes(key)) {
cout << key;
} else {
detail::print_escaped(out, key);
}
if (!holds_alternative<config_value::dictionary>(val)) {
cout << " = ";
print_val(val, indent);
cout << '\n';
} else if (auto xs = get<config_value::dictionary>(val); xs.empty()) {
cout << "{}\n";
} else { } else {
cout << indent << kvp.first << " = " << to_string(kvp.second) << '\n'; cout << " {\n";
print(get<config_value::dictionary>(val), indent + 2);
cout << indent << "}\n";
}
} }
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment