sculpt: allow for removal of index files

By clicking on a yellow checkbox in the depot selection dialog, the
corresponding index files are removed. This way, index files can
be update by removing and downloading them again.

This patch also filters out sculpt-managed components from the graph to
avoid erratic graph-position changes while the '+' menu is open.

Fixes #3193
This commit is contained in:
Norman Feske 2019-03-12 15:58:32 +01:00 committed by Christian Helmuth
parent f3d4ee4d4c
commit 1ead0ea3a7
11 changed files with 245 additions and 1 deletions

View File

@ -46,3 +46,4 @@ _/src/menu_view
_/src/gpt_write
_/src/sculpt_manager
_/src/fs_query
_/src/fs_tool

View File

@ -135,6 +135,10 @@ struct Sculpt::Graph
/* omit sculpt's helpers from the graph */
bool const blacklisted = (name == "runtime_view"
|| name == "launcher_query"
|| name == "update"
|| name == "fs_tool"
|| name == "depot_rw"
|| name == "public_rw"
|| name == "depot_rom"
|| name == "dynamic_depot_rom"
|| name == "depot_query");

View File

@ -24,6 +24,7 @@
/* local includes */
#include <model/runtime_state.h>
#include <model/child_exit_state.h>
#include <model/file_operation_queue.h>
#include <view/download_status.h>
#include <view/popup_dialog.h>
#include <gui.h>
@ -50,6 +51,8 @@ struct Sculpt::Main : Input_event_handler,
Heap _heap { _env.ram(), _env.rm() };
Sculpt_version const _sculpt_version { _env };
Constructible<Nitpicker::Connection> _nitpicker { };
Signal_handler<Main> _input_handler {
@ -188,6 +191,10 @@ struct Sculpt::Main : Input_event_handler,
Download_queue _download_queue { _heap };
File_operation_queue _file_operation_queue { _heap };
Fs_tool_version _fs_tool_version { 0 };
/*****************
** Depot query **
@ -597,6 +604,21 @@ struct Sculpt::Main : Input_event_handler,
generate_runtime_config();
}
void remove_index(Depot::Archive::User const &user) override
{
auto remove = [&] (Path const &path) {
_file_operation_queue.remove_file(path); };
remove(Path("/rw/depot/", user, "/index/", _sculpt_version));
remove(Path("/rw/public/", user, "/index/", _sculpt_version, ".xz"));
remove(Path("/rw/public/", user, "/index/", _sculpt_version, ".xz.sig"));
if (!_file_operation_queue.any_operation_in_progress())
_file_operation_queue.schedule_next_operations();
generate_runtime_config();
}
/**
* Popup_dialog::Construction_info interface
*/
@ -1146,6 +1168,30 @@ void Sculpt::Main::_handle_runtime_state()
}
}
/* schedule pending file operations to new fs_tool instance */
{
Child_exit_state exit_state(state, "fs_tool");
if (exit_state.exited) {
Child_exit_state::Version const expected_version(_fs_tool_version.value);
if (exit_state.version == expected_version) {
_file_operation_queue.schedule_next_operations();
_fs_tool_version.value++;
reconfigure_runtime = true;
/*
* The removal of an index file may have completed, re-query index
* files to reflect this change at the depot selection menu.
*/
if (_popup_dialog.interested_in_file_operations())
trigger_depot_query();
}
}
}
/* upgrade RAM and cap quota on demand */
state.for_each_sub_node("child", [&] (Xml_node child) {
@ -1243,6 +1289,13 @@ void Sculpt::Main::_generate_runtime_config(Xml_generator &xml) const
chroot("depot", "/depot", READ_ONLY);
}
/* execute file operations */
if (_storage._sculpt_partition.valid())
if (_file_operation_queue.any_operation_in_progress())
xml.node("start", [&] () {
gen_fs_tool_start_content(xml, _fs_tool_version,
_file_operation_queue); });
_network.gen_runtime_start_nodes(xml);
if (_update_running())

View File

@ -29,12 +29,16 @@ struct Sculpt::Child_exit_state
int code = 0;
typedef String<64> Name;
typedef String<16> Version;
Version version { };
Child_exit_state(Xml_node init_state, Name const &name)
{
init_state.for_each_sub_node("child", [&] (Xml_node child) {
if (child.attribute_value("name", Name()) == name) {
exists = true;
version = child.attribute_value("version", Version());
if (child.has_attribute("exited")) {
exited = true;
code = child.attribute_value("exited", 0L);

View File

@ -122,4 +122,4 @@ struct Sculpt::Download_queue : Noncopyable
}
};
#endif /* _MODEL__ROUTE_H_ */
#endif /* _MODEL__DOWNLOAD_QUEUE_H_ */

View File

@ -0,0 +1,107 @@
/*
* \brief List of file operations that are currently in flight
* \author Norman Feske
* \date 2019-03-12
*/
/*
* Copyright (C) 2019 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__FILE_OPERATION_QUEUE_H_
#define _MODEL__FILE_OPERATION_QUEUE_H_
#include <base/registry.h>
#include <types.h>
namespace Sculpt { struct File_operation_queue; }
struct Sculpt::File_operation_queue : Noncopyable
{
struct Operation : Interface
{
enum class State {
PENDING, /* scheduled for next fs_tool instance */
IN_PROGRESS /* processed by current fs_tool instance */
};
State state { State::PENDING };
enum class Type { REMOVE_FILE } type;
Path const path;
Operation(Type type, Path const &path) : type(type), path(path) { }
void gen_fs_tool_config(Xml_generator &xml) const
{
if (state != State::IN_PROGRESS)
return;
xml.node("remove-file", [&] () {
xml.attribute("path", path); });
}
};
Allocator &_alloc;
Registry<Registered<Operation> > _operations { };
File_operation_queue(Allocator &alloc) : _alloc(alloc) { }
void remove_file(Path const &path)
{
bool already_exists = false;
_operations.for_each([&] (Operation const &operation) {
if (operation.type == Operation::Type::REMOVE_FILE && operation.path == path)
already_exists = true; });
if (already_exists)
return;
new (_alloc) Registered<Operation>(_operations, Operation::Type::REMOVE_FILE, path);
}
bool any_operation_in_progress() const
{
bool any_in_progress = false;
_operations.for_each([&] (Operation const &operation) {
if (operation.state == Operation::State::IN_PROGRESS)
any_in_progress = true; });
return any_in_progress;
}
void schedule_next_operations()
{
/*
* All operations that were in progress are complete. So they can
* be removed from the queue. All pending operations become the
* operations-in-progress in the next iteration.
*/
_operations.for_each([&] (Registered<Operation> &operation) {
switch (operation.state) {
case Operation::State::IN_PROGRESS:
destroy(_alloc, &operation);
break;
case Operation::State::PENDING:
operation.state = Operation::State::IN_PROGRESS;
break;
}
});
}
void gen_fs_tool_config(Xml_generator &xml) const
{
_operations.for_each([&] (Operation const &operation) {
operation.gen_fs_tool_config(xml); });
}
};
#endif /* _MODEL__FILE_OPERATION_QUEUE_H_ */

View File

@ -29,3 +29,4 @@
#include <runtime/runtime_view.cc>
#include <runtime/update.cc>
#include <runtime/wifi_drv.cc>
#include <runtime/fs_tool.cc>

View File

@ -73,6 +73,11 @@ namespace Sculpt {
struct Prepare_version { unsigned value; };
void gen_prepare_start_content(Xml_generator &, Prepare_version);
struct Fs_tool_version { unsigned value; };
struct File_operation_queue;
void gen_fs_tool_start_content(Xml_generator &, Fs_tool_version,
File_operation_queue const &);
void gen_ram_fs_start_content(Xml_generator &, Ram_fs_state const &);
void gen_update_start_content(Xml_generator &);

View File

@ -0,0 +1,61 @@
/*
* \brief XML configuration for fs_tool
* \author Norman Feske
* \date 2018-05-08
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <model/file_operation_queue.h>
#include <runtime.h>
void Sculpt::gen_fs_tool_start_content(Xml_generator &xml, Fs_tool_version version,
File_operation_queue const &operations)
{
xml.attribute("version", version.value);
gen_common_start_content(xml, "fs_tool", Cap_quota{200}, Ram_quota{5*1024*1024});
gen_named_node(xml, "binary", "fs_tool");
xml.node("config", [&] () {
xml.attribute("exit", "yes");
xml.attribute("verbose", "yes");
xml.node("vfs", [&] () {
gen_named_node(xml, "dir", "rw", [&] () {
xml.node("fs", [&] () { xml.attribute("label", "target"); }); });
gen_named_node(xml, "dir", "config", [&] () {
xml.node("fs", [&] () { xml.attribute("label", "config"); }); });
});
operations.gen_fs_tool_config(xml);
});
xml.node("route", [&] () {
gen_service_node<::File_system::Session>(xml, [&] () {
xml.attribute("label", "target");
gen_named_node(xml, "child", "default_fs_rw"); });
gen_parent_rom_route(xml, "fs_tool");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_rom_route(xml, "vfs.lib.so");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Rom_session> (xml);
gen_service_node<::File_system::Session>(xml, [&] () {
xml.attribute("label", "config");
xml.node("parent", [&] () { xml.attribute("label", "config"); }); });
});
}

View File

@ -307,6 +307,8 @@ void Popup_dialog::click(Action &action)
if (!_index_avail(clicked))
action.trigger_download(_index_path(clicked));
else
action.remove_index(clicked);
}
}

View File

@ -98,6 +98,7 @@ struct Sculpt::Popup_dialog
virtual void launch_construction() = 0;
virtual void trigger_download(Path const &) = 0;
virtual void remove_index(Depot::Archive::User const &) = 0;
};
Construction_info const &_construction_info;
@ -481,6 +482,11 @@ struct Sculpt::Popup_dialog
return _state >= PKG_REQUESTED && _pkg_missing;
}
bool interested_in_file_operations() const
{
return _state == DEPOT_SELECTION;
}
};
#endif /* _VIEW__POPUP_DIALOG_H_ */