From b2c515c73cb68e12740a56810113cc25461ab266 Mon Sep 17 00:00:00 2001 From: Patrick Ziegler Date: Sat, 5 Dec 2020 02:48:18 +0100 Subject: [PATCH] fix(config): Reintroduce multiple inheritance (#2271) Pre 3.5.0, any key starting with 'inherit' was treated as an inherit directive. This allowed for multiple inheritance even though it was never inteded in that way. 3.5.0 removed that bug/feature by doing a strict check against 'inherit' It seems people were relying on this behavior, so we are adding it back. However multiple inheritance with multiple keys is also deprecated in favor of the `inherit` key now supporting multiple space separated sections. This is because the config doesn't have a key order, but inheritance does depend on the order the different section keys are copied over (if multiple inherited sections define the same key). Fixes #2269 --- src/components/config.cpp | 60 +++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/src/components/config.cpp b/src/components/config.cpp index a47050be..a94aaee2 100644 --- a/src/components/config.cpp +++ b/src/components/config.cpp @@ -72,34 +72,58 @@ void config::warn_deprecated(const string& section, const string& key, string re * Look for sections set up to inherit from a base section * and copy the missing parameters * + * Multiple sections can be specified, separated by a space. + * * [sub/section] - * inherit = base/section + * inherit = section1 section2 */ void config::copy_inherited() { for (auto&& section : m_sections) { + std::vector inherit_sections; + + // Collect all sections to be inherited for (auto&& param : section.second) { - if (param.first == "inherit") { - // Get name of base section + string key_name = param.first; + if (key_name == "inherit") { auto inherit = param.second; - if ((inherit = dereference(section.first, param.first, inherit, inherit)).empty()) { - throw value_error("Invalid section \"\" defined for \"" + section.first + ".inherit\""); + inherit = dereference(section.first, key_name, inherit, inherit); + + std::vector sections = string_util::split(std::move(inherit), ' '); + + inherit_sections.insert(inherit_sections.end(), sections.begin(), sections.end()); + + } else if (key_name.find("inherit") == 0) { + // Legacy support for keys that just start with 'inherit' + m_log.warn( + "\"%s.%s\": Using anything other than 'inherit' for inheriting section keys is deprecated. " + "The 'inherit' key supports multiple section names separated by a space.", + section.first, key_name); + + auto inherit = param.second; + inherit = dereference(section.first, key_name, inherit, inherit); + if (inherit.empty() || m_sections.find(inherit) == m_sections.end()) { + throw value_error( + "Invalid section \"" + inherit + "\" defined for \"" + section.first + "." + key_name + "\""); } - // Find and validate base section - auto base_section = m_sections.find(inherit); - if (base_section == m_sections.end()) { - throw value_error("Invalid section \"" + inherit + "\" defined for \"" + section.first + ".inherit\""); - } + inherit_sections.push_back(std::move(inherit)); + } + } - m_log.trace("config: Copying missing params (sub=\"%s\", base=\"%s\")", section.first, inherit); + for (const auto& base_name : inherit_sections) { + const auto base_section = m_sections.find(base_name); + if (base_section == m_sections.end()) { + throw value_error("Invalid section \"" + base_name + "\" defined for \"" + section.first + ".inherit\""); + } - /* - * Iterate the base and copy the parameters that haven't been defined - * for the sub-section - */ - for (auto&& base_param : base_section->second) { - section.second.emplace(base_param.first, base_param.second); - } + m_log.trace("config: Inheriting keys from \"%s\" in \"%s\"", base_name, section.first); + + /* + * Iterate the base and copy the parameters that haven't been defined + * yet. + */ + for (auto&& base_param : base_section->second) { + section.second.emplace(base_param.first, base_param.second); } } }