diff --git a/app/flatpak-builtins-ps.c b/app/flatpak-builtins-ps.c index 28edd861..c151a181 100644 --- a/app/flatpak-builtins-ps.c +++ b/app/flatpak-builtins-ps.c @@ -35,11 +35,75 @@ #include "flatpak-table-printer.h" #include "flatpak-run-private.h" +static gboolean opt_show_cols; +static const char **opt_cols; static GOptionEntry options[] = { + { "show-columns", 0, 0, G_OPTION_ARG_NONE, &opt_show_cols, N_("Show available columns"), NULL }, + { "columns", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_cols, N_("What information to show"), N_("FIELD,…") }, { NULL } }; +static struct { + const char *name; + const char *title; + const char *desc; +} all_columns[] = { + { "application", N_("Application"), N_("Show the application ID") }, + { "arch", N_("Architecture"), N_("Show the architecture") }, + { "branch", N_("Branch"), N_("Show the application branch") }, + { "runtime", N_("Runtime"), N_("Show the runtime ID") }, + { "runtime-branch", N_("Runtime Branch"), N_("Show the runtime branch") }, + { "pid", N_("PID"), N_("Show the PID of the main process") }, +}; + +#define ALL_COLUMNS "pid,application,arch,branch,runtime,runtime-branch" +#define DEFAULT_COLUMNS "pid,application,runtime" + +static int +find_column (const char *name) +{ + int i; + + for (i = 0; i < G_N_ELEMENTS(all_columns); i++) + { + if (strcmp (name, all_columns[i].name) == 0) + return i; + } + + return -1; +} + +static char * +column_help (void) +{ + GString *s = g_string_new (""); + int len; + int i; + + g_string_append (s, _("Available columns:\n")); + + len = 0; + for (i = 0; i < G_N_ELEMENTS(all_columns); i++) + len = MAX (len, strlen (all_columns[i].name)); + + len += 4; + for (i = 0; i < G_N_ELEMENTS(all_columns); i++) + g_string_append_printf (s, " %-*s %s\n", len, all_columns[i].name, all_columns[i].desc); + + g_string_append_printf (s, " %-*s %s\n", len, "all", _("Show all columns")); + g_string_append_printf (s, " %-*s %s\n", len, "help", _("Show available columns")); + + return g_string_free (s, FALSE); +} + +static void +show_columns (void) +{ + g_autofree char *col_help = column_help (); + g_print ("%s", col_help); +} + static char * get_instance_pid (const char *instance) { @@ -52,18 +116,17 @@ get_instance_pid (const char *instance) if (!g_file_get_contents (path, &pid, NULL, &error)) { g_debug ("Failed to load pid file for instance '%s': %s", instance, error->message); - return g_strdup ("?"); + return NULL; } return pid; } -static char * -get_instance_app_id (const char *instance) +static GKeyFile * +get_instance_info (const char *instance) { g_autofree char *path = NULL; - g_autoptr(GKeyFile) key_file = NULL; - char *app_id = NULL; + GKeyFile *key_file = NULL; g_autoptr(GError) error = NULL; path = g_build_filename (g_get_user_runtime_dir (), ".flatpak", instance, "info", NULL); @@ -72,53 +135,102 @@ get_instance_app_id (const char *instance) if (!g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error)) { g_debug ("Failed to load info file for instance '%s': %s", instance, error->message); - goto out; + return NULL; } - app_id = g_key_file_get_string (key_file, "Application", "name", &error); - if (error) + return key_file; +} + +static char * +get_instance_column (GKeyFile *info, + const char *name) +{ + if (info == NULL) + return NULL; + + if (strcmp (name, "application") == 0) + return g_key_file_get_string (info, "Application", "name", NULL); + if (strcmp (name, "arch") == 0) + return g_key_file_get_string (info, "Instance", "arch", NULL); + if (strcmp (name, "branch") == 0) + return g_key_file_get_string (info, "Instance", "branch", NULL); + else if (strcmp (name, "runtime") == 0) { - g_debug ("Failed to get app ID for instance '%s': %s", instance, error->message); + g_autofree char *full_ref = g_key_file_get_string (info, "Application", "runtime", NULL); + g_auto(GStrv) ref = flatpak_decompose_ref (full_ref, NULL); + return g_strdup (ref[1]); + } + else if (strcmp (name, "runtime-branch") == 0) + { + g_autofree char *full_ref = g_key_file_get_string (info, "Application", "runtime", NULL); + g_auto(GStrv) ref = flatpak_decompose_ref (full_ref, NULL); + return g_strdup (ref[3]); } -out: - return app_id ? app_id : g_strdup ("?"); + return NULL; } static gboolean -enumerate_instances (GError **error) +enumerate_instances (const char *columns, + GError **error) { g_autofree char *base_dir = NULL; g_autoptr(GFile) file = NULL; g_autoptr(GFileEnumerator) enumerator = NULL; - GFileInfo *info; + GFileInfo *dir_info; FlatpakTablePrinter *printer; + g_auto(GStrv) cols = NULL; + g_autofree int *col_idx = NULL; + int n_cols; + int i; + + cols = g_strsplit (columns, ",", 0); + n_cols = g_strv_length (cols); + col_idx = g_new (int, n_cols); + for (i = 0; i < n_cols; i++) + { + col_idx[i] = find_column (cols[i]); + if (col_idx[i] == -1) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Unknown colum: %s"), cols[i]); + return FALSE; + } + } printer = flatpak_table_printer_new (); flatpak_table_printer_set_column_title (printer, 0, _("Instance")); - flatpak_table_printer_set_column_title (printer, 1, _("Application")); - flatpak_table_printer_set_column_title (printer, 2, _("PID")); - - flatpak_run_gc_ids (); + for (i = 0; i < n_cols; i++) + flatpak_table_printer_set_column_title (printer, i + 1, all_columns[col_idx[i]].title); + base_dir = g_build_filename (g_get_user_runtime_dir (), ".flatpak", NULL); file = g_file_new_for_path (base_dir); enumerator = g_file_enumerate_children (file, "standard::name", G_FILE_QUERY_INFO_NONE, NULL, error); if (enumerator == NULL) return FALSE; - while ((info = g_file_enumerator_next_file (enumerator, NULL, error)) != NULL) + while ((dir_info = g_file_enumerator_next_file (enumerator, NULL, error)) != NULL) { - g_autofree char *instance = g_file_info_get_attribute_as_string (info, "standard::name"); - g_autofree char *app_id = get_instance_app_id (instance); - g_autofree char *pid = get_instance_pid (instance); + g_autofree char *instance = g_file_info_get_attribute_as_string (dir_info, "standard::name"); + g_autoptr(GKeyFile) info = get_instance_info (instance); flatpak_table_printer_add_column (printer, instance); - flatpak_table_printer_add_column (printer, app_id); - flatpak_table_printer_add_column (printer, pid); + + for (i = 0; i < n_cols; i++) + { + g_autofree char *col = NULL; + + if (strcmp (all_columns[col_idx[i]].name, "pid") == 0) + col = get_instance_pid (instance); + else + col = get_instance_column (info, all_columns[col_idx[i]].name); + + flatpak_table_printer_add_column (printer, col ? col : ""); + } + flatpak_table_printer_finish_row (printer); - g_object_unref (info); + g_object_unref (dir_info); } flatpak_table_printer_print (printer); @@ -137,9 +249,13 @@ flatpak_builtin_ps (int argc, GError **error) { g_autoptr(GOptionContext) context = NULL; + g_autofree char *col_help = NULL; + g_autofree char *cols = NULL; context = g_option_context_new (_(" - Enumerate running sandboxes")); g_option_context_set_translation_domain (context, GETTEXT_PACKAGE); + col_help = column_help (); + g_option_context_set_description (context, col_help); if (!flatpak_option_context_parse (context, options, &argc, &argv, FLATPAK_BUILTIN_FLAG_NO_DIR, NULL, cancellable, error)) return FALSE; @@ -150,7 +266,60 @@ flatpak_builtin_ps (int argc, return FALSE; } - return enumerate_instances (error); + flatpak_run_gc_ids (); + + if (opt_show_cols) + { + show_columns (); + return TRUE; + } + + if (opt_cols) + { + gboolean show_help = FALSE; + gboolean show_all = FALSE; + int i; + + for (i = 0; opt_cols[i]; i++) + { + const char *p; + p = strstr (opt_cols[i], "help"); + if (p && + (p == opt_cols[i] || p[-1] == ',') && + (p[strlen("help")] == '\0' || p[strlen("help")] == ',')) + { + show_help = TRUE; + break; + } + + p = strstr (opt_cols[i], "all"); + if (p && + (p == opt_cols[i] || p[-1] == ',') && + (p[strlen("all")] == '\0' || p[strlen("all")] == ',')) + { + show_all = TRUE; + break; + } + } + + if (show_help) + { + show_columns (); + return TRUE; + } + else if (show_all) + { + cols = g_strdup (ALL_COLUMNS); + } + else + { + cols = g_strjoinv (",", (char **)opt_cols); + } + } + else + cols = g_strdup (DEFAULT_COLUMNS); + + return enumerate_instances (cols, error); } gboolean