From 3eddc056267e8395a15f4668a1a361bd902b25af Mon Sep 17 00:00:00 2001 From: Dmitry Sapozhnikov <11535558+o-sdn-o@users.noreply.github.com> Date: Fri, 27 Sep 2024 01:10:51 +0500 Subject: [PATCH] #330 WIP: Enable setting inheritance --- src/netxs/desktopio/application.hpp | 106 +++++++++++++++++++--------- src/netxs/desktopio/xml.hpp | 102 +++++++++++++++----------- src/vtm.xml | 4 +- 3 files changed, 134 insertions(+), 78 deletions(-) diff --git a/src/netxs/desktopio/application.hpp b/src/netxs/desktopio/application.hpp index 669c65aa3b..509968a0b5 100644 --- a/src/netxs/desktopio/application.hpp +++ b/src/netxs/desktopio/application.hpp @@ -462,30 +462,11 @@ namespace netxs::app::shared }; namespace load { - template - auto settings(view defaults, qiew cli_config_path, view patch) + auto load_from_file(xml::document& config, qiew file_path) { - auto conf = xmls{ defaults }; - auto load = [&](qiew shadow) + auto [config_path, config_path_str] = os::path::expand(file_path); + if (!config_path.empty()) { - if (shadow.empty()) return faux; - if (shadow.starts_with(":")) // Receive configuration via memory mapping. - { - shadow.remove_prefix(1); - auto utf8 = os::process::memory::get(shadow); - if (utf8.size()) - { - conf.fuse(utf8); - return true; - } - else - { - log(prompt::apps, "Failed to get settings from :", shadow); - return faux; - } - } - auto [config_path, config_path_str] = os::path::expand(shadow); - if (config_path.empty()) return faux; log("%%Loading settings from %path%...", prompt::apps, config_path_str); auto ec = std::error_code{}; auto config_file = fs::directory_entry(config_path, ec); @@ -499,25 +480,84 @@ namespace netxs::app::shared auto buff = text((size_t)size, '\0'); file.seekg(0, std::ios::beg); file.read(buff.data(), size); - conf.fuse(buff, config_path_str); + config.load(buff, config_path_str); return true; } } log(prompt::pads, "Not found"); - return faux; - }; - auto frag = cli_config_path.starts_with("<"); // The configuration fragment could be specified directly in place of the configuration file path. - if (frag || !load(cli_config_path)) // Merge explicitly specified settings. + } + return faux; + } + template + auto settings(qiew default_config, qiew cli_opt_config, qiew xmitted_config) + { + auto conf = xmls{ default_config }; + auto& defcfg = *conf.document; + auto dvtcfg = xml::document{}; + auto clicfg = xml::document{}; + + if (xmitted_config.size()) // Load and overlay prerequisites from directvt. { - load(app::shared::sys_config); // Merge system-wide settings. - load(app::shared::usr_config); // Merge user-wise settings. + dvtcfg.load(xmitted_config, "dtvt"); + auto directvt_patch = dvtcfg.take("/shell/"); + if (directvt_patch.size()) defcfg.overlay(directvt_patch.front(), "/"); } - conf.fuse(patch); // Apply dtvt patch. - if (frag) + + if (cli_opt_config.size()) // Load and overlay prerequisites from cli opt. { - log("%%Apply the specified configuration fragment:\n%body%", prompt::apps, ansi::hi(cli_config_path)); - conf.fuse(cli_config_path); + auto loaded = faux; + if (cli_opt_config.starts_with("<")) // The configuration fragment could be specified directly in place of the configuration file path. + { + clicfg.load(cli_opt_config, "cli"); + loaded = true; + } + else if (cli_opt_config.starts_with(":")) // Receive configuration via memory mapping. + { + cli_opt_config.remove_prefix(1); + auto utf8 = os::process::memory::get(cli_opt_config); + if (utf8.size()) + { + clicfg.load(utf8, cli_opt_config); + loaded = true; + } + else log("%%Failed to get settings from :%hash%", prompt::apps, cli_opt_config); + } + else + { + loaded = load_from_file(clicfg, cli_opt_config); + } + if (loaded) // Overlay prerequisites from cli opt. + { + auto cli_data_patch = clicfg.take("/shell/"); + if (cli_data_patch.size()) defcfg.overlay(cli_data_patch.front(), "/"); + } + else cli_opt_config = {}; } + + auto config_sources = defcfg.take("/shell/cfg"); + for (auto& cfg : config_sources) if (cfg) // Overlay configs from the specified sources if it is. + { + auto src_file = cfg->take_value(); + auto src_conf = xml::document{}; + if (load_from_file(src_conf, src_file)) + { + auto config_data = src_conf.take("/config/"); + if (config_data.size()) defcfg.overlay(config_data.front(), "/"); + } + } + + if (xmitted_config) // Overlay directvt packet config from parent. + { + auto config_data = dvtcfg.take("/config/"); + if (config_data.size()) defcfg.overlay(config_data.front(), "/"); + } + if (cli_opt_config) // Overlay '-c ' plain data config. + { + auto config_data = clicfg.take("/config/"); + if (config_data.size()) defcfg.overlay(config_data.front(), "/"); + } + + conf.homelist = conf.document->take(conf.homepath); return conf; } } diff --git a/src/netxs/desktopio/xml.hpp b/src/netxs/desktopio/xml.hpp index acd55cd6cd..51aaba8729 100644 --- a/src/netxs/desktopio/xml.hpp +++ b/src/netxs/desktopio/xml.hpp @@ -244,6 +244,13 @@ namespace netxs::xml back{ data } { } + void init(view filename = {}) + { + data = ptr::shared(type::na); + fail = faux; + file = filename; + back = data; + } template auto append(type kind, Args&&... args) { @@ -403,6 +410,7 @@ namespace netxs::xml ~elem() { hive.clear(); + if (from) //todo revise if (auto prev = from->prev.lock()) { auto next = upto->next; @@ -607,13 +615,20 @@ namespace netxs::xml suit page; sptr root; + document() = default; document(document&&) = default; document(view data, view file = {}) : page{ file }, root{ ptr::shared()} { read(data); - if (page.fail) log("%%Inconsistent xml data from %file%:\n%config%\n", prompt::xml, file.empty() ? "memory"sv : file, page.show()); + } + + void load(view data, view file = {}) + { + page.init(file); + root = ptr::shared(); + read(data); } template auto take(view path) @@ -668,6 +683,47 @@ namespace netxs::xml } else log("%%Destination path not found '%parent_path%'", prompt::xml, parent_path); } + void overlay(sptr node_ptr, text path) + { + auto& node = *node_ptr; + auto& name = node.name->utf8; + path += "/" + name; + auto dest_list = take(path); + auto is_dest_list = (dest_list.size() && dest_list.front()->fake) + || dest_list.size() > 1; + if (is_dest_list) + { + join(path, { node_ptr }); + } + else + { + if (dest_list.size()) + { + auto& dest = dest_list.front(); + dest->sync_value(node); + for (auto& [sub_name, sub_list] : node.hive) // Proceed subelements. + { + auto count = sub_list.size(); + if (count == 1 && sub_list.front()->fake == faux) + { + overlay(sub_list.front(), path); + } + else if (count) // It is a list. + { + //todo Clang 13.0.0 don't get it. + //auto rewrite = sub_list.end() != std::ranges::find_if(sub_list, [](auto& a){ return a->base; }); + auto rewrite = sub_list.end() != std::find_if(sub_list.begin(), sub_list.end(), [](auto& a){ return a->base; }); + join(path + "/" + sub_name, sub_list, rewrite); + } + else log("%%Unexpected tag without data: %tag%", prompt::xml, sub_name); + } + } + else + { + join(path, { node_ptr }); + } + } + } private: vect compacted; @@ -1155,6 +1211,7 @@ namespace netxs::xml read_subsections(root, data, what, last, deep, defs); seal(root); } + if (page.fail) log("%%Inconsistent xml data from %file%:\n%config%\n", prompt::xml, page.file.empty() ? "memory"sv : page.file, page.show()); } }; @@ -1340,49 +1397,8 @@ namespace netxs::xml { log("%%Settings from %file%:\n%config%", prompt::xml, filepath.empty() ? "memory"sv : filepath, run_config.page.show()); } - auto proc = [&](auto node_ptr, auto path, auto proc) -> void - { - auto& node = *node_ptr; - auto& name = node.name->utf8; - path += "/" + name; - auto dest_list = list(path); - auto is_dest_list = (dest_list.size() && dest_list.front()->fake) - || dest_list.size() > 1; - if (is_dest_list) - { - document->join(path, { node_ptr }); - } - else - { - if (dest_list.size()) - { - auto& dest = dest_list.front(); - dest->sync_value(node); - for (auto& [sub_name, sub_list] : node.hive) // Proceed subelements. - { - auto count = sub_list.size(); - if (count == 1 && sub_list.front()->fake == faux) - { - proc(sub_list.front(), path, proc); - } - else if (count) // It is a list. - { - //todo Clang 13.0.0 don't get it. - //auto rewrite = sub_list.end() != std::ranges::find_if(sub_list, [](auto& a){ return a->base; }); - auto rewrite = sub_list.end() != std::find_if(sub_list.begin(), sub_list.end(), [](auto& a){ return a->base; }); - document->join(path + "/" + sub_name, sub_list, rewrite); - } - else log("%%Unexpected tag without data: %tag%", prompt::xml, sub_name); - } - } - else - { - document->join(path, { node_ptr }); - } - } - }; auto path = text{}; - proc(run_config.root, path, proc); + document->overlay(run_config.root, path); homepath = "/"; homelist = document->take(homepath); } diff --git a/src/vtm.xml b/src/vtm.xml index 3c3429f1b7..1beb1dc633 100644 --- a/src/vtm.xml +++ b/src/vtm.xml @@ -8,8 +8,8 @@ R"==( - - + +