summaryrefslogtreecommitdiff
path: root/app/flatpak-builtins-uninstall.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/flatpak-builtins-uninstall.c')
-rw-r--r--app/flatpak-builtins-uninstall.c129
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))