sculpt: add button for restarting a component

Fixes #3885
This commit is contained in:
Norman Feske 2020-09-10 15:21:56 +02:00
parent c9f2847420
commit 5dc8e330b6
8 changed files with 176 additions and 33 deletions

View File

@ -108,8 +108,43 @@ struct Sculpt::Deploy
*/ */
deploy.for_each_sub_node("start", [&] (Xml_node node) { deploy.for_each_sub_node("start", [&] (Xml_node node) {
Start_name const name = node.attribute_value("name", Start_name()); Start_name const name = node.attribute_value("name", Start_name());
if (!_runtime_info.abandoned_by_user(name)) if (_runtime_info.abandoned_by_user(name))
append_xml_node(node); return;
xml.node("start", [&] () {
/*
* Copy attributes
*/
xml.attribute("name", name);
/* override version with restarted version, after restart */
using Version = Child_state::Version;
Version version = _runtime_info.restarted_version(name);
if (version.value == 0)
version = Version { node.attribute_value("version", 0U) };
if (version.value > 0)
xml.attribute("version", version.value);
auto copy_attribute = [&] (auto attr)
{
if (node.has_attribute(attr)) {
using Value = String<128>;
xml.attribute(attr, node.attribute_value(attr, Value()));
}
};
copy_attribute("caps");
copy_attribute("ram");
copy_attribute("cpu");
copy_attribute("pkg");
/* copy start-node content */
node.with_raw_content([&] (char const *start, size_t length) {
xml.append(start, length); });
});
}); });
/* /*

View File

@ -24,13 +24,16 @@ void Graph::_gen_selected_node_content(Xml_generator &xml, Start_name const &nam
if (removable) { if (removable) {
gen_named_node(xml, "frame", "operations", [&] () { gen_named_node(xml, "frame", "operations", [&] () {
xml.node("vbox", [&] () { xml.node("hbox", [&] () {
gen_named_node(xml, "button", "remove", [&] () { gen_named_node(xml, "button", "remove", [&] () {
_remove_item.gen_button_attr(xml, "remove"); _action_item.gen_button_attr(xml, "remove");
xml.node("label", [&] () { xml.node("label", [&] () {
xml.attribute("text", "Remove"); xml.attribute("text", "Remove"); }); });
});
}); gen_named_node(xml, "button", "restart", [&] () {
_action_item.gen_button_attr(xml, "restart");
xml.node("label", [&] () {
xml.attribute("text", "Restart"); }); });
}); });
}); });
} }
@ -276,8 +279,8 @@ Dialog::Hover_result Graph::hover(Xml_node hover)
_ram_fs_dialog.match_sub_dialog(hover, "depgraph", "frame", "vbox", "frame", "vbox"), _ram_fs_dialog.match_sub_dialog(hover, "depgraph", "frame", "vbox", "frame", "vbox"),
_node_button_item.match(hover, "depgraph", "frame", "vbox", "button", "name"), _node_button_item.match(hover, "depgraph", "frame", "vbox", "button", "name"),
_add_button_item .match(hover, "depgraph", "button", "name"), _add_button_item .match(hover, "depgraph", "button", "name"),
_remove_item .match(hover, "depgraph", "frame", "vbox", _action_item .match(hover, "depgraph", "frame", "vbox",
"frame", "vbox", "button", "name")); "frame", "hbox", "button", "name"));
if (_add_button_item.hovered("global+")) { if (_add_button_item.hovered("global+")) {
@ -335,11 +338,11 @@ void Graph::click(Action &action)
_runtime_state.toggle_selection(_node_button_item._hovered, _runtime_state.toggle_selection(_node_button_item._hovered,
_runtime_config); _runtime_config);
_remove_item.reset(); _action_item.reset();
} }
if (_remove_item.hovered("remove")) if (_action_item.hovered("remove") || _action_item.hovered("restart"))
_remove_item.propose_activation_on_click(); _action_item.propose_activation_on_click();
} }
@ -352,11 +355,11 @@ void Graph::clack(Action &action, Ram_fs_dialog::Action &ram_fs_action)
if (_storage_dialog->clack(action) == Clack_result::CONSUMED) if (_storage_dialog->clack(action) == Clack_result::CONSUMED)
return; return;
if (_remove_item.hovered("remove")) { if (_action_item.hovered("remove")) {
_remove_item.confirm_activation_on_clack(); _action_item.confirm_activation_on_clack();
if (_remove_item.activated("remove")) { if (_action_item.activated("remove")) {
action.remove_deployed_component(_runtime_state.selected()); action.remove_deployed_component(_runtime_state.selected());
/* /*
@ -366,8 +369,16 @@ void Graph::clack(Action &action, Ram_fs_dialog::Action &ram_fs_action)
_runtime_state.toggle_selection(_runtime_state.selected(), _runtime_state.toggle_selection(_runtime_state.selected(),
_runtime_config); _runtime_config);
} }
} else { }
_remove_item.reset();
} if (_action_item.hovered("restart")) {
_action_item.confirm_activation_on_clack();
if (_action_item.activated("restart"))
action.restart_deployed_component(_runtime_state.selected());
}
_action_item.reset();
} }

View File

@ -52,7 +52,7 @@ struct Sculpt::Graph : Dialog
Hoverable_item _node_button_item { }; Hoverable_item _node_button_item { };
Hoverable_item _add_button_item { }; Hoverable_item _add_button_item { };
Activatable_item _remove_item { }; Activatable_item _action_item { };
/* /*
* Defined when '+' button is hovered * Defined when '+' button is hovered
@ -106,6 +106,7 @@ struct Sculpt::Graph : Dialog
struct Action : Storage_dialog::Action struct Action : Storage_dialog::Action
{ {
virtual void remove_deployed_component(Start_name const &) = 0; virtual void remove_deployed_component(Start_name const &) = 0;
virtual void restart_deployed_component(Start_name const &) = 0;
virtual void toggle_launcher_selector(Rect) = 0; virtual void toggle_launcher_selector(Rect) = 0;
}; };

View File

@ -642,6 +642,17 @@ struct Sculpt::Main : Input_event_handler,
_deploy.update_managed_deploy_config(_manual_deploy_rom.xml()); _deploy.update_managed_deploy_config(_manual_deploy_rom.xml());
} }
/*
* Graph::Action interface
*/
void restart_deployed_component(Start_name const &name) override
{
_runtime_state.restart(name);
/* update config/managed/deploy with the component 'name' removed */
_deploy.update_managed_deploy_config(_manual_deploy_rom.xml());
}
/* /*
* Graph::Action interface * Graph::Action interface
*/ */

View File

@ -25,6 +25,10 @@ namespace Sculpt { struct Child_state; }
struct Sculpt::Child_state : Noncopyable struct Sculpt::Child_state : Noncopyable
{ {
public:
struct Version { unsigned value; };
private: private:
Registry<Child_state>::Element _element; Registry<Child_state>::Element _element;
@ -37,7 +41,7 @@ struct Sculpt::Child_state : Noncopyable
Ram_quota _ram_quota = _initial_ram_quota; Ram_quota _ram_quota = _initial_ram_quota;
Cap_quota _cap_quota = _initial_cap_quota; Cap_quota _cap_quota = _initial_cap_quota;
struct Version { unsigned value; } _version { 0 }; Version _version { 0 };
public: public:

View File

@ -30,6 +30,8 @@ class Sculpt::Runtime_state : public Runtime_info
{ {
public: public:
using Version = Child_state::Version;
struct Info struct Info
{ {
bool selected; bool selected;
@ -45,6 +47,8 @@ class Sculpt::Runtime_state : public Runtime_info
unsigned long assigned_caps; unsigned long assigned_caps;
unsigned long avail_caps; unsigned long avail_caps;
Version version;
}; };
private: private:
@ -60,8 +64,11 @@ class Sculpt::Runtime_state : public Runtime_info
Info info { .selected = false, Info info { .selected = false,
.tcb = false, .tcb = false,
.tcb_updated = false, .tcb_updated = false,
.assigned_ram = 0, .avail_ram = 0, .assigned_ram = 0,
.assigned_caps = 0, .avail_caps = 0 }; .avail_ram = 0,
.assigned_caps = 0,
.avail_caps = 0,
.version = { 0 }};
bool abandoned_by_user = false; bool abandoned_by_user = false;
@ -79,11 +86,27 @@ class Sculpt::Runtime_state : public Runtime_info
struct Abandoned_child : Interface struct Abandoned_child : Interface
{ {
Start_name const name; Start_name const name;
Abandoned_child(Start_name const &name) : name(name) { }; Abandoned_child(Start_name const &name) : name(name) { };
}; };
Registry<Registered<Abandoned_child> > _abandoned_children { }; Registry<Registered<Abandoned_child> > _abandoned_children { };
/**
* Child that was interactively restarted
*/
struct Restarted_child : Interface
{
Start_name const name;
Version version;
Restarted_child(Start_name const &name, Version const &version)
: name(name), version(version) { };
};
Registry<Registered<Restarted_child> > _restarted_children { };
/** /**
* Child that was interactively launched * Child that was interactively launched
*/ */
@ -115,13 +138,18 @@ class Sculpt::Runtime_state : public Runtime_info
construction.construct(alloc, pkg_path, info, space); construction.construct(alloc, pkg_path, info, space);
} }
void gen_deploy_start_node(Xml_generator &xml) const void gen_deploy_start_node(Xml_generator &xml, Runtime_state const &state) const
{ {
if (!launched) if (!launched)
return; return;
gen_named_node(xml, "start", name, [&] () { gen_named_node(xml, "start", name, [&] () {
Version const version = state.restarted_version(name);
if (version.value > 0)
xml.attribute("version", version.value);
/* interactively constructed */ /* interactively constructed */
if (construction.constructed()) { if (construction.constructed()) {
xml.attribute("pkg", construction->path); xml.attribute("pkg", construction->path);
@ -187,6 +215,8 @@ class Sculpt::Runtime_state : public Runtime_info
caps.attribute_value("quota", 0UL)); caps.attribute_value("quota", 0UL));
child.info.avail_caps = caps.attribute_value("avail", 0UL); child.info.avail_caps = caps.attribute_value("avail", 0UL);
} }
child.info.version.value = node.attribute_value("version", 0U);
} }
static bool element_matches_xml_node(Child const &elem, Xml_node node) static bool element_matches_xml_node(Child const &elem, Xml_node node)
@ -240,9 +270,28 @@ class Sculpt::Runtime_state : public Runtime_info
bool abandoned_by_user(Start_name const &name) const override bool abandoned_by_user(Start_name const &name) const override
{ {
bool result = false; bool result = false;
_abandoned_children.for_each([&] (Abandoned_child const &child) { _abandoned_children.for_each([&] (Abandoned_child const &child) {
if (!result && child.name == name) if (!result && child.name == name)
result = true; }); result = true; });
return result;
}
/**
* Return version of restarted child
*
* If the returned value is version 0, the child has not been
* restarted.
*/
Version restarted_version(Start_name const &name) const override
{
Version result { 0 };
_restarted_children.for_each([&] (Restarted_child const &child) {
if (!result.value && child.name == name)
result = child.version; });
return result; return result;
} }
@ -252,7 +301,7 @@ class Sculpt::Runtime_state : public Runtime_info
void gen_launched_deploy_start_nodes(Xml_generator &xml) const override void gen_launched_deploy_start_nodes(Xml_generator &xml) const override
{ {
_launched_children.for_each([&] (Launched_child const &child) { _launched_children.for_each([&] (Launched_child const &child) {
child.gen_deploy_start_node(xml); }); child.gen_deploy_start_node(xml, *this); });
} }
Info info(Start_name const &name) const Info info(Start_name const &name) const
@ -363,6 +412,30 @@ class Sculpt::Runtime_state : public Runtime_info
new (_alloc) Registered<Abandoned_child>(_abandoned_children, name); new (_alloc) Registered<Abandoned_child>(_abandoned_children, name);
} }
void restart(Start_name const &name)
{
/* determin current version from most recent state report */
Version current_version { 0 };
_children.for_each([&] (Child const &child) {
if (child.name == name)
current_version = child.info.version; });
Version const next_version { current_version.value + 1 };
bool already_restarted = false;
_restarted_children.for_each([&] (Restarted_child &child) {
if (child.name == name) {
already_restarted = true;
child.version = next_version;
}
});
if (!already_restarted)
new (_alloc)
Registered<Restarted_child>(_restarted_children, name, next_version);
}
void launch(Start_name const &name, Path const &launcher) void launch(Start_name const &name, Path const &launcher)
{ {
new (_alloc) Registered<Launched_child>(_launched_children, name, launcher); new (_alloc) Registered<Launched_child>(_launched_children, name, launcher);
@ -431,6 +504,9 @@ class Sculpt::Runtime_state : public Runtime_info
_launched_children.for_each([&] (Launched_child &child) { _launched_children.for_each([&] (Launched_child &child) {
destroy(_alloc, &child); }); destroy(_alloc, &child); });
_restarted_children.for_each([&] (Restarted_child &child) {
destroy(_alloc, &child); });
} }
}; };

View File

@ -19,6 +19,7 @@
#include <model/storage_devices.h> #include <model/storage_devices.h>
#include <model/storage_target.h> #include <model/storage_target.h>
#include <model/nic_target.h> #include <model/nic_target.h>
#include <model/child_state.h>
namespace Sculpt { namespace Sculpt {
@ -29,6 +30,8 @@ namespace Sculpt {
struct Runtime_info : Interface struct Runtime_info : Interface
{ {
using Version = Child_state::Version;
/** /**
* Return true if specified child is present in the runtime subsystem * Return true if specified child is present in the runtime subsystem
*/ */
@ -36,6 +39,8 @@ namespace Sculpt {
virtual bool abandoned_by_user(Start_name const &) const = 0; virtual bool abandoned_by_user(Start_name const &) const = 0;
virtual Version restarted_version(Start_name const &) const = 0;
virtual void gen_launched_deploy_start_nodes(Xml_generator &) const = 0; virtual void gen_launched_deploy_start_nodes(Xml_generator &) const = 0;
}; };

View File

@ -57,7 +57,7 @@ struct Sculpt::Activatable_item : Hoverable_item
if (!_selected.valid() || !_activated.valid()) if (!_selected.valid() || !_activated.valid())
Hoverable_item::gen_button_attr(xml, id); Hoverable_item::gen_button_attr(xml, id);
if (_selected.valid() && _selected == _hovered) if (_selected.valid() && _selected == _hovered && _selected == id)
xml.attribute("selected", "yes"); xml.attribute("selected", "yes");
} }
}; };