Skip to content

Commit

Permalink
directvt#330 WIP: Enable setting inheritance
Browse files Browse the repository at this point in the history
  • Loading branch information
o-sdn-o committed Sep 26, 2024
1 parent 72f796d commit 3eddc05
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 78 deletions.
106 changes: 73 additions & 33 deletions src/netxs/desktopio/application.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -462,30 +462,11 @@ namespace netxs::app::shared
};
namespace load
{
template<bool Print = faux>
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<Print>(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);
Expand All @@ -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<Print>(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<bool Print = faux>
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<Print>(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<Print>(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 <config>' 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;
}
}
Expand Down
102 changes: 59 additions & 43 deletions src/netxs/desktopio/xml.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,13 @@ namespace netxs::xml
back{ data }
{ }

void init(view filename = {})
{
data = ptr::shared<literal>(type::na);
fail = faux;
file = filename;
back = data;
}
template<class ...Args>
auto append(type kind, Args&&... args)
{
Expand Down Expand Up @@ -403,6 +410,7 @@ namespace netxs::xml
~elem()
{
hive.clear();
if (from) //todo revise
if (auto prev = from->prev.lock())
{
auto next = upto->next;
Expand Down Expand Up @@ -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<elem>()}
{
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<elem>();
read(data);
}
template<bool WithTemplate = faux>
auto take(view path)
Expand Down Expand Up @@ -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<true>(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;
Expand Down Expand Up @@ -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());
}
};

Expand Down Expand Up @@ -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<true>(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);
}
Expand Down
4 changes: 2 additions & 2 deletions src/vtm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ R"==(<shell> <!-- App prerequisites. -->
<cwd=""/> <!-- Current working directory. -->
<!-- Ordered list of paths to settings files. The settings (the <config> subsection only) will be overlayed in the specified order. -->
<cfg*/> <!-- Clear previously defined sources. Start a new list. -->
<cfg="/etc/vtm/settings.xml"/> <!-- Global settings source. The "/etc/..." path will be auto converted to the "%PROGRAMDATA%\..." on Windows. -->
<cfg="~/.config/vtm/settings.xml"/> <!-- User wise settings source. -->
<cfg="/etc/vtm/settings.xml"/> <!-- System-wide settings source. The "/etc/..." path will be auto converted to the "%PROGRAMDATA%\..." on Windows. -->
<cfg="~/.config/vtm/settings.xml"/> <!-- User-wise settings source. -->
</shell>
<config> <!-- App configuration. -->
<simple=0/> <!-- For internal use. -->
Expand Down

0 comments on commit 3eddc05

Please sign in to comment.