diff options
Diffstat (limited to 'app/flatpak-builtins-uninstall.c')
-rw-r--r-- | app/flatpak-builtins-uninstall.c | 129 |
1 files changed, 125 insertions, 4 deletions
diff --git a/app/flatpak-builtins-uninstall.c b/app/flatpak-builtins-uninstall.c index bbe82e04..78143908 100644 --- a/app/flatpak-builtins-uninstall.c +++ b/app/flatpak-builtins-uninstall.c @@ -1,4 +1,4 @@ -/* +/* vi:set et sw=2 sts=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e-s: * Copyright © 2014 Red Hat, Inc * * This program is free software; you can redistribute it and/or @@ -69,6 +69,8 @@ typedef struct { FlatpakDir *dir; GHashTable *refs_hash; + GHashTable *runtime_app_map; + GHashTable *extension_app_map; GPtrArray *refs; } UninstallDir; @@ -89,18 +91,28 @@ uninstall_dir_free (UninstallDir *udir) { g_object_unref (udir->dir); g_hash_table_unref (udir->refs_hash); + g_clear_pointer (&udir->runtime_app_map, g_hash_table_unref); + g_clear_pointer (&udir->extension_app_map, g_hash_table_unref); g_ptr_array_unref (udir->refs); g_free (udir); } static void uninstall_dir_add_ref (UninstallDir *udir, - FlatpakDecomposed*ref) + FlatpakDecomposed *ref) { if (g_hash_table_insert (udir->refs_hash, flatpak_decomposed_ref (ref), NULL)) g_ptr_array_add (udir->refs, flatpak_decomposed_ref (ref)); } +static void +uninstall_dir_remove_ref (UninstallDir *udir, + FlatpakDecomposed *ref) +{ + g_hash_table_remove (udir->refs_hash, ref); + g_ptr_array_remove (udir->refs, ref); +} + static UninstallDir * uninstall_dir_ensure (GHashTable *uninstall_dirs, FlatpakDir *dir) @@ -141,6 +153,94 @@ flatpak_delete_data (gboolean yes_opt, return TRUE; } +static gboolean +confirm_runtime_removal (gboolean yes_opt, + UninstallDir *udir, + FlatpakDecomposed *ref) +{ + g_autoptr(GPtrArray) apps = NULL; + g_autoptr(GError) local_error = NULL; + g_autofree char *ref_name = NULL; + const char *ref_branch; + const char *on = ""; + const char *off = ""; + gboolean is_extension; + + if (flatpak_fancy_output ()) + { + on = FLATPAK_ANSI_BOLD_ON; + off = FLATPAK_ANSI_BOLD_OFF; + } + + is_extension = flatpak_dir_is_runtime_extension (udir->dir, ref); + if (is_extension) + { + apps = flatpak_dir_list_app_refs_with_runtime_extension (udir->dir, + &udir->runtime_app_map, + &udir->extension_app_map, + ref, NULL, &local_error); + if (apps == NULL) + g_info ("Unable to list apps using extension %s: %s\n", + flatpak_decomposed_get_ref (ref), local_error->message); + } + else + { + apps = flatpak_dir_list_app_refs_with_runtime (udir->dir, + &udir->runtime_app_map, + ref, NULL, &local_error); + if (apps == NULL) + g_info ("Unable to list apps using runtime %s: %s\n", + flatpak_decomposed_get_ref (ref), local_error->message); + } + + if (apps == NULL || apps->len == 0) + return TRUE; + + /* Exclude any apps that will be removed by the current transaction */ + for (guint i = 0; i < udir->refs->len; i++) + { + FlatpakDecomposed *uninstall_ref = g_ptr_array_index (udir->refs, i); + guint j; + + if (flatpak_decomposed_is_runtime (uninstall_ref)) + continue; + + if (g_ptr_array_find_with_equal_func (apps, uninstall_ref, + (GEqualFunc)flatpak_decomposed_equal, &j)) + g_ptr_array_remove_index_fast (apps, j); + } + + if (apps->len == 0) + return TRUE; + + ref_name = flatpak_decomposed_dup_id (ref); + ref_branch = flatpak_decomposed_get_branch (ref); + + if (is_extension) + g_print (_("Info: applications using the extension %s%s%s branch %s%s%s:\n"), + on, ref_name, off, on, ref_branch, off); + else + g_print (_("Info: applications using the runtime %s%s%s branch %s%s%s:\n"), + on, ref_name, off, on, ref_branch, off); + + g_print (" "); + for (guint i = 0; i < apps->len; i++) + { + FlatpakDecomposed *app_ref = g_ptr_array_index (apps, i); + g_autofree char *id = flatpak_decomposed_dup_id (app_ref); + if (i != 0) + g_print (", "); + g_print ("%s", id); + } + g_print ("\n"); + + if (!yes_opt && + !flatpak_yes_no_prompt (FALSE, _("Really remove?"))) + return FALSE; + + return TRUE; +} + gboolean flatpak_builtin_uninstall (int argc, char **argv, GCancellable *cancellable, GError **error) { @@ -169,6 +269,9 @@ flatpak_builtin_uninstall (int argc, char **argv, GCancellable *cancellable, GEr if (argc >= 2 && opt_unused) return usage_error (context, _("Must not specify REFs when using --unused"), error); + if (opt_noninteractive) + opt_yes = TRUE; /* Implied */ + prefs = &argv[1]; n_prefs = argc - 1; @@ -406,14 +509,32 @@ flatpak_builtin_uninstall (int argc, char **argv, GCancellable *cancellable, GEr /* This disables the remote metadata update, since uninstall is a local-only op */ flatpak_transaction_set_no_pull (transaction, TRUE); - for (i = 0; i < udir->refs->len; i++) + /* Walk through the array backwards so we can safely remove */ + for (i = udir->refs->len; i > 0; i--) { - FlatpakDecomposed *ref = g_ptr_array_index (udir->refs, i); + FlatpakDecomposed *ref = g_ptr_array_index (udir->refs, i - 1); + + /* In case it's a runtime for an installed app or an optional runtime + * extension of an installed app, prompt the user for confirmation (in + * the former case the transaction will error out if executed). This + * is limited to checking within the same installation; it won't + * prompt for a user app depending on a system runtime. + */ + if (!opt_force_remove && + !confirm_runtime_removal (opt_yes, udir, ref)) + { + uninstall_dir_remove_ref (udir, ref); + continue; + } if (!flatpak_transaction_add_uninstall (transaction, flatpak_decomposed_get_ref (ref), error)) return FALSE; } + /* These caches may no longer be valid once the transaction runs */ + g_clear_pointer (&udir->runtime_app_map, g_hash_table_unref); + g_clear_pointer (&udir->extension_app_map, g_hash_table_unref); + if (!flatpak_transaction_run (transaction, cancellable, error)) { if (g_error_matches (*error, FLATPAK_ERROR, FLATPAK_ERROR_ABORTED)) |