Commit 39ab7641 authored by Dan Guest's avatar Dan Guest Committed by Dan Guest
Browse files

Clean up the logic in fragment merging

parent 0ce6d8c6
Pipeline #3543973 passed with stages
in 10 minutes and 38 seconds
......@@ -17,39 +17,42 @@
namespace {
// Merging lists is just appending them for now
void merge_lists(
nlohmann::ordered_json& oldtree,
const nlohmann::ordered_json& newtree) {
if (!oldtree.is_array() || !newtree.is_array()) {
nlohmann::ordered_json& local,
const nlohmann::ordered_json& fragment) {
if (!local.is_array() || !fragment.is_array()) {
std::string err = "list merge error: "
+ oldtree.dump() + " + " + newtree.dump();
+ local.dump() + " + " + fragment.dump();
throw std::logic_error(err);
}
for (const auto& item: newtree) {
oldtree.push_back(item);
for (const auto& item: fragment) {
local.push_back(item);
}
}
void merge_trees(nlohmann::ordered_json& oldtree,
const nlohmann::ordered_json& newtree) {
// Merge a new tree into the existing one
//
void merge_trees(nlohmann::ordered_json& local,
const nlohmann::ordered_json& fragment) {
// trees without structure are primative types, assign and return
if (!oldtree.is_structured()) {
oldtree = newtree;
return;
}
// for lists, just append the new values
if (oldtree.is_array()) {
merge_lists(oldtree, newtree);
// For primative types there's nothing to do: the local one takes
// precedence over any fragment.
// For lists, just append the new values.
if (local.is_array()) {
merge_lists(local, fragment);
return;
}
// if we got here it's an object
for (auto& [key, value]: newtree.items()) {
// add new entries
if (!oldtree.count(key)) {
oldtree[key] = value;
} else {
// if both trees have this object, try to merge them
merge_trees(oldtree.at(key), value);
} else if (local.is_object()) {
// Objects are slightly more complicated: if the fragment
// contains anything that isn't in the local tree, we add
// it. Otherwise we attempt to merge it.
for (auto& [key, value]: fragment.items()) {
// Add new entries, only if they don't currently exist
if (!local.count(key)) {
local[key] = value;
} else {
// If both trees have this object, try to merge them
merge_trees(local.at(key), value);
}
}
}
}
......@@ -59,31 +62,45 @@ namespace {
namespace ConfigFileTools {
// if any of the variable lists have a node called "file" we read in
// that file and replace the node with the contents.
void combine_files(nlohmann::ordered_json& node,
// Expand file fragments
//
void combine_files(nlohmann::ordered_json& local,
std::filesystem::path config_path) {
namespace fs = std::filesystem;
for (auto& sub: node) {
// magic key for file fragments
const std::string fragment_key = "file";
// Start by building the local tree recursively.
for (auto& sub: local) {
if (sub.is_structured()) combine_files(sub, config_path);
}
if (!node.count("file")) return;
nlohmann::ordered_json local = node;
fs::path file_path(node.at("file"));
// if the file doesn't exist in this directory, check the one
// where the root configuration file was stored
if (!fs::exists(file_path)) {
file_path = config_path.parent_path() / file_path;
// if there's no fragment at this level we're done
if (!local.count(fragment_key)) return;
// If we find a file fragment, we expand it. We look in two
// places: the path relative to the working directory takes
// precedence, but we'll also look relative to the configuration
// path.
fs::path fragment_path(local.at(fragment_key));
if (!fs::exists(fragment_path)) {
fragment_path = config_path / fragment_path;
}
std::ifstream file_stream(file_path.string());
nlohmann::ordered_json file = nlohmann::json::parse(file_stream);
combine_files(file, file_path);
node = file;
// now add in anything else that was specified after the file
merge_trees(node, local);
node.erase("file");
std::ifstream stream(fragment_path.string());
nlohmann::ordered_json fragment = nlohmann::json::parse(stream);
// Recursively fill out the fragment, in case it has its own
// sub-fragments. The search path for sub-fragments should include
// the directory where this fragment lives.
combine_files(fragment, fragment_path.parent_path());
// Now we merge the fragment into the local tree. The local tree
// will take precedence.
merge_trees(local, fragment);
// We're done with the fragment, get rid of any reference to it.
local.erase(fragment_key);
}
// converter to ptree, eventually we should migrate everything to
......
......@@ -19,8 +19,26 @@ namespace ConfigFileTools {
typedef std::map<std::string,std::vector<std::string>> MapOfLists;
// file combination function
void combine_files(nlohmann::ordered_json& node,
// Expand file fragments
//
// If the local json tree has an entry called "file" we merge
// anything defined in that "fragment" to the local tree.
//
// - The merge is recursive, and fragments can have sub-fragments.
//
// - When merging objects, local values take precidence.
//
// - Lists are merged by concatenating them. Trying to merge a list
// with anything else will throw an exception.
//
// - The first argument is the base json object. If no fragments are
// found it won't be altered.
//
// - The second argument points to a root directory to search for
// fragments. This path is only used if the fragment path relative
// to the working directory is invalid.
//
void combine_files(nlohmann::ordered_json& local,
std::filesystem::path config_path);
// workaround while we migrate the remaining code to nlohmann
......
......@@ -143,7 +143,7 @@ SingleBTagConfig get_singlebtag_config(const std::string& config_file_name) {
}
std::ifstream cfg_stream(cfg_path.string());
auto nlocfg = nlohmann::ordered_json::parse(cfg_stream);
cft::combine_files(nlocfg, cfg_path);
cft::combine_files(nlocfg, cfg_path.parent_path());
// convert back to ptree for now, but new code should use nlocfg if
// possible!
......
......@@ -19,7 +19,7 @@ HbbConfig get_hbb_config(const std::string& config_file_name) {
}
std::ifstream cfg_stream(cfg_path.string());
auto nlocfg = nlohmann::ordered_json::parse(cfg_stream);
cft::combine_files(nlocfg, cfg_path);
cft::combine_files(nlocfg, cfg_path.parent_path());
// convert back to ptree for now, but new code should use nlocfg if
// possible!
......
......@@ -18,8 +18,8 @@ int main(int narg, char* argv[]) {
if (!fs::exists(config_path)) return 2;
std::ifstream config_stream(config_path.string());
auto nlotree = nlohmann::ordered_json::parse(config_stream);
ConfigFileTools::combine_files(nlotree, config_path);
std::cout << nlotree.dump(2);
ConfigFileTools::combine_files(nlotree, config_path.parent_path());
std::cout << nlotree.dump(2) << std::endl;
return 0;
}
Supports Markdown
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