[RFC,8/8] ui/ncurses: Present plugin commands in nc-plugin

Message ID 20181218041953.8960-9-sam@mendozajonas.com
State New
Headers show
Series
  • Introduce pb-plugin 'commands' & Rust PoC
Related show

Commit Message

Samuel Mendoza-Jonas Dec. 18, 2018, 4:19 a.m.
Update the Plugin screen to present commands and their arguments if
available. The user may modify the arguments and run the commands as
displayed in the same way an executable may have been run previously.
An extra field is also added to provide arbitrary arguments to a given
plugin executable.

Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
 ui/ncurses/nc-plugin.c | 256 ++++++++++++++++++++++++++++++++++++++---
 1 file changed, 237 insertions(+), 19 deletions(-)

Patch

diff --git a/ui/ncurses/nc-plugin.c b/ui/ncurses/nc-plugin.c
index f897cc8e..84e811a4 100644
--- a/ui/ncurses/nc-plugin.c
+++ b/ui/ncurses/nc-plugin.c
@@ -36,12 +36,22 @@ 
 #include "process/process.h"
 #include "system/system.h"
 
-#define N_FIELDS        15
+#define N_FIELDS        17
 
 extern const struct help_text plugin_help_text;
 
 static void plugin_run_command(void *arg);
 
+struct command_option {
+	// TODO If platform doesn't match a) warn, or b) hide?
+	struct nc_widget_label		*name_l;
+	struct nc_widget_button		*cmd_b; /* cmd + args_fmt */
+	unsigned int 			n_args;
+	struct nc_widget_label		**arg_l;
+	struct nc_widget_textbox	**arg_f;
+	struct nc_widget_label		*help_l;
+};
+
 struct plugin_screen {
 	struct nc_scr		scr;
 	struct cui		*cui;
@@ -76,9 +86,13 @@  struct plugin_screen {
 
 		struct nc_widget_label		*commands_l;
 		struct nc_widget_select		*commands_f;
-
+		struct nc_widget_label		*exec_args_l;
+		struct nc_widget_textbox	*exec_args_f;
 		struct nc_widget_button		*run_b;
 	} widgets;
+
+	struct command_option *commands;
+	unsigned int n_commands;
 };
 
 static void plugin_screen_draw(struct plugin_screen *screen,
@@ -203,7 +217,116 @@  static void plugin_screen_resize(struct nc_scr *scr)
 	plugin_screen_post(scr);
 }
 
+static void update_arguments(struct plugin_screen *screen, int cmd_idx)
+{
+	struct command_option *opt;
+	struct command *cmd;
+	unsigned int i;
+	char *field;
+
+	opt = &screen->commands[cmd_idx];
+	cmd = &screen->opt->commands[cmd_idx];
+
+	for (i = 0; i < opt->n_args; i++) {
+		field = widget_textbox_get_value(opt->arg_f[i]);
+
+		switch (cmd->args[i].type) {
+		case ARG_STR:
+			talloc_free(cmd->args[i].arg_str);
+			cmd->args[i].arg_str = talloc_strdup(screen, field);
+			break;
+		case ARG_I64:
+			{
+			int64_t val;
+			val = strtol(field, NULL, 10);
+			if (!errno)
+				cmd->args[i].arg_i64 = val;
+			break;
+			}
+		case ARG_F64:
+			{
+			double val;
+			val = strtod(field, NULL);
+			if (!errno)
+				cmd->args[i].arg_f64 = val;
+			break;
+			}
+		}
+	}
+}
+
 static void plugin_run_command(void *arg)
+{
+	struct plugin_screen *screen = arg;
+	struct nc_widget *current;
+	struct command_option *opt;
+	int result, n_var;
+	unsigned int idx;
+	char *fmt, *args, *var, *cmd_str;
+
+
+	/* Get selected command */
+	current = current_widget(screen->widgetset);
+	if (!current) {
+		pb_log_fn("No command selected!\n");
+		return;
+	}
+
+	opt = NULL;
+	for (idx = 0; idx < screen->n_commands; idx++) {
+		if (widget_button_base(screen->commands[idx].cmd_b) == current) {
+			opt = &screen->commands[idx];
+			break;
+		}
+	}
+
+	if (!opt) {
+		pb_log_fn("Could not find current option\n");
+		return;
+	}
+
+	fmt = talloc_strdup(screen, screen->opt->commands[idx].args_fmt);
+	cmd_str = talloc_asprintf(screen, "%s ", screen->opt->commands[idx].cmd);
+	n_var = 0;
+	args = fmt;
+	while (args) {
+		var = strstr(args, "{}");
+		if (var)
+			*var = '\0';
+		cmd_str = talloc_asprintf_append(cmd_str, "%s%s",
+				args, var ? widget_textbox_get_value(
+					opt->arg_f[n_var++]) : "");
+
+		args = var ? var + 2 : NULL;
+	}
+
+	const char *argv[] = {
+		pb_system_apps.pb_exec,
+		cmd_str,
+		NULL,
+	};
+
+	/* Drop our pad before running plugin */
+	delwin(screen->pad);
+	screen->pad = NULL;
+
+	result = cui_run_cmd(screen->cui, argv);
+
+	if (result)
+		pb_log("Failed to run command option %s\n", argv[1]);
+	else {
+		update_arguments(screen, idx);
+		nc_scr_status_printf(screen->cui->current, _("Finished: %s"),
+				argv[1]);
+	}
+
+	talloc_free(fmt);
+	talloc_free(cmd_str);
+
+	plugin_screen_draw(screen, NULL);
+}
+
+static void plugin_run_command_single(void *arg)
 {
 	struct plugin_screen *screen = arg;
 	char *cmd;
@@ -222,6 +345,7 @@  static void plugin_run_command(void *arg)
 	const char *argv[] = {
 		pb_system_apps.pb_exec,
 		cmd,
+		widget_textbox_get_value(screen->widgets.exec_args_f),
 		NULL
 	};
 
@@ -246,7 +370,7 @@  static void plugin_run_command_check(void *arg)
 	struct plugin_screen *screen = arg;
 
 	if (discover_client_authenticated(screen->cui->client)) {
-		plugin_run_command(screen);
+		plugin_run_command_single(screen);
 		return;
 	}
 
@@ -283,17 +407,81 @@  static void plugin_screen_setup_widgets(struct plugin_screen *screen)
 	screen->widgets.date_l = widget_new_label(set, 0, 0, _("Date"));
 	screen->widgets.date_f = widget_new_label(set, 0, 0, opt->date);
 
-	screen->widgets.commands_l = widget_new_label(set, 0, 0,
-							 _("Commands:"));
 	screen->widgets.commands_f = widget_new_select(set, 0, 0,
 			COLS - screen->field_x - 1);
-	for (i = 0; i < opt->n_executables; i++) {
-		widget_select_add_option(screen->widgets.commands_f, i,
-				basename(opt->executables[i]), i == 0);
+	if (opt->n_executables) {
+		screen->widgets.commands_l = widget_new_label(set, 0, 0,
+				_("Executables:"));
+		for (i = 0; i < opt->n_executables; i++) {
+			widget_select_add_option(screen->widgets.commands_f, i,
+					basename(opt->executables[i]), i == 0);
+		}
+
+		screen->widgets.exec_args_l = widget_new_label(set, 0, 0,
+				_("Arguments:"));
+		screen->widgets.exec_args_f = widget_new_textbox(set, 0, 0, 30,
+				"");
+
+		screen->widgets.run_b = widget_new_button(set, 0, 0, 30,
+				_("Run selected executable"),
+				plugin_run_command_check, screen);
+	}
+
+	screen->n_commands = opt->n_commands;
+	screen->commands = talloc_array(screen, struct command_option,
+			screen->n_commands);
+	for (i = 0; i < opt->n_commands; i++) {
+		unsigned int j;
+		char *label;
+		screen->commands[i].name_l = widget_new_label(set, 0, 0,
+				opt->commands[i].name);
+		label = talloc_asprintf(screen, "%s %s",
+				opt->commands[i].cmd,
+				opt->commands[i].args_fmt);
+		screen->commands[i].cmd_b = widget_new_button(set, 0, 0, 45,
+				label, plugin_run_command, screen);
+		screen->commands[i].n_args = opt->commands[i].n_args;
+		screen->commands[i].arg_l = talloc_zero_array(screen,
+				struct nc_widget_label *,
+				screen->commands[i].n_args);
+		screen->commands[i].arg_f = talloc_zero_array(screen,
+				struct nc_widget_textbox *,
+				screen->commands[i].n_args);
+		for (j = 0; j < screen->commands[i].n_args; j++) {
+			screen->commands[i].arg_l[j] = widget_new_label(set,
+					0, 0,
+					opt->commands[i].args[j].name);
+			switch (opt->commands[i].args[j].type) {
+			case ARG_STR:
+				screen->commands[i].arg_f[j] =
+					widget_new_textbox(set, 0, 0, 20,
+						opt->commands[i].args[j].arg_str);
+				break;
+			case ARG_I64:
+				label = talloc_asprintf(screen, "%ld",
+						opt->commands[i].args[j].arg_i64);
+				screen->commands[i].arg_f[j] =
+					widget_new_textbox(set, 0, 0, 20,
+							label);
+				break;
+			case ARG_F64:
+				label = talloc_asprintf(screen, "%f",
+						opt->commands[i].args[j].arg_f64);
+				screen->commands[i].arg_f[j] =
+					widget_new_textbox(set, 0, 0, 20,
+							label);
+				break;
+			default:
+				label = talloc_asprintf(screen, "<unknown field type>");
+				screen->commands[i].arg_f[j] =
+					widget_new_textbox(set, 0, 0, 20,
+							label);
+			}
+		}
+		screen->commands[i].help_l = widget_new_label(set, 0, 0,
+				opt->commands[i].help);
 	}
 
-	screen->widgets.run_b = widget_new_button(set, 0, 0, 30,
-			_("Run selected command"), plugin_run_command_check, screen);
 }
 
 static int layout_pair(struct plugin_screen *screen, int y,
@@ -308,7 +496,7 @@  static int layout_pair(struct plugin_screen *screen, int y,
 
 static void plugin_screen_layout_widgets(struct plugin_screen *screen)
 {
-	unsigned int y;
+	unsigned int y, i;
 
 	/* list of details (static) */
 
@@ -329,15 +517,45 @@  static void plugin_screen_layout_widgets(struct plugin_screen *screen)
 
 	y += 1;
 
-	/* available commands */
-	widget_move(widget_label_base(screen->widgets.commands_l), y,
-		    screen->label_x);
-	widget_move(widget_select_base(screen->widgets.commands_f), y,
-			screen->field_x);
+	if (widget_select_get_value(screen->widgets.commands_f) != -1) {
+		/* available executables */
+		widget_move(widget_label_base(screen->widgets.commands_l), y,
+			    screen->label_x);
+		widget_move(widget_select_base(screen->widgets.commands_f), y,
+				screen->field_x);
 
-	y += 2;
+		y += 1;
+
+		layout_pair(screen, y++, screen->widgets.exec_args_l,
+				widget_textbox_base(screen->widgets.exec_args_f));
+		widget_move(widget_button_base(screen->widgets.run_b), y++,
+				screen->field_x);
+
+		y += 2;
+	}
+
+
+	for (i = 0; i < screen->n_commands; i++) {
+		unsigned int j;
+		widget_move(widget_label_base(screen->commands[i].name_l), y++,
+			    screen->label_x);
+		widget_move(widget_button_base(screen->commands[i].cmd_b), y++,
+			    screen->field_x);
+
+		for (j = 0; j < screen->commands[i].n_args; j++) {
+			widget_move(widget_label_base(screen->commands[i].arg_l[j]),
+					y, screen->field_x);
+			widget_move(widget_textbox_base(screen->commands[i].arg_f[j]),
+					y, screen->field_x * 2);
+			y += 1;
+		}
+
+		widget_move(widget_label_base(screen->commands[i].help_l), y++,
+			    screen->label_x);
+		y += 1;
+	}
 
-	widget_move(widget_button_base(screen->widgets.run_b), y++, screen->field_x);
+	y += 2;
 
 }
 
@@ -402,7 +620,7 @@  struct plugin_screen *plugin_screen_init(struct cui *cui,
 	screen->cui = cui;
 	screen->on_exit = on_exit;
 	screen->label_x = 2;
-	screen->field_x = 25;
+	screen->field_x = 15;
 
 	screen->scr.frame.ltitle = talloc_strdup(screen,
 			_("Petitboot Plugin"));