uninstall: Support multiple REFs

This commit is contained in:
Alexander Larsson
2016-10-17 17:27:16 +02:00
parent 5b11c03adc
commit ee0ffbcb35
2 changed files with 98 additions and 84 deletions

View File

@@ -49,79 +49,105 @@ static GOptionEntry options[] = {
{ NULL }
};
static gboolean
looks_like_branch (const char *branch)
{
/* In particular, / is not a valid branch char, so
this lets us distinguish full or partial refs as
non-branches. */
if (!flatpak_is_valid_branch (branch, NULL))
return FALSE;
/* Dots are allowed in branches, but not really used much, while
they are required for app ids, so thats a good check to
distinguish the two */
if (strchr (branch, '.') != NULL)
return FALSE;
return TRUE;
}
gboolean
flatpak_builtin_uninstall (int argc, char **argv, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
const char *pref = NULL;
char **prefs = NULL;
int i, j, n_prefs;
const char *default_branch = NULL;
g_autofree char *ref = NULL;
FlatpakHelperUninstallFlags flags = 0;
g_autoptr(GPtrArray) related = NULL;
FlatpakKinds kinds;
FlatpakKinds kind;
g_autofree char *id = NULL;
g_autofree char *arch = NULL;
g_autofree char *branch = NULL;
int i;
g_autoptr(GHashTable) uninstall_refs_hash = NULL;
g_autoptr(GPtrArray) uninstall_refs = NULL;
context = g_option_context_new (_("NAME [BRANCH] - Uninstall an application"));
context = g_option_context_new (_("REF... - Uninstall an application"));
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
if (!flatpak_option_context_parse (context, options, &argc, &argv, 0, &dir, cancellable, error))
return FALSE;
if (argc < 2)
return usage_error (context, _("NAME must be specified"), error);
return usage_error (context, _("Must specify at least one REF"), error);
if (argc > 3)
return usage_error (context, _("Too many arguments"), error);
prefs = &argv[1];
n_prefs = argc - 1;
pref = argv[1];
if (argc > 2)
default_branch = argv[2];
/* Backwards compat for old "REPOSITORY NAME [BRANCH]" argument version */
if (argc == 3 && looks_like_branch (argv[2]))
{
default_branch = argv[2];
n_prefs = 1;
}
kinds = flatpak_kinds_from_bools (opt_app, opt_runtime);
uninstall_refs = g_ptr_array_new_with_free_func (g_free);
uninstall_refs_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
if (!flatpak_split_partial_ref_arg (pref, kinds, opt_arch, default_branch,
&kinds, &id, &arch, &branch, error))
return FALSE;
ref = flatpak_dir_find_installed_ref (dir, id, branch, arch,
kinds, &kind, error);
if (ref == NULL)
return FALSE;
/* TODO: when removing runtimes, look for apps that use it, require --force */
if (opt_keep_ref)
flags |= FLATPAK_HELPER_UNINSTALL_FLAGS_KEEP_REF;
if (opt_force_remove)
flags |= FLATPAK_HELPER_UNINSTALL_FLAGS_FORCE_REMOVE;
if (!opt_no_related)
for (j = 0; j < n_prefs; j++)
{
const char *pref = NULL;
FlatpakKinds matched_kinds;
g_autofree char *id = NULL;
g_autofree char *arch = NULL;
g_autofree char *branch = NULL;
g_autoptr(GError) local_error = NULL;
g_autofree char *origin = NULL;
pref = prefs[j];
if (!flatpak_split_partial_ref_arg (pref, kinds, opt_arch, default_branch,
&matched_kinds, &id, &arch, &branch, error))
return FALSE;
ref = flatpak_dir_find_installed_ref (dir, id, branch, arch,
kinds, &kind, error);
if (ref == NULL)
return FALSE;
if (g_hash_table_insert (uninstall_refs_hash, g_strdup (ref), NULL))
g_ptr_array_add (uninstall_refs, g_strdup (ref));
/* TODO: when removing runtimes, look for apps that use it, require --force */
if (opt_no_related)
continue;
origin = flatpak_dir_get_origin (dir, ref, NULL, NULL);
if (origin)
if (origin == NULL)
continue;
related = flatpak_dir_find_local_related (dir, ref, origin,
NULL, &local_error);
if (related == NULL)
{
related = flatpak_dir_find_local_related (dir, ref, origin,
NULL, &local_error);
if (related == NULL)
g_printerr (_("Warning: Problem looking for related refs: %s\n"),
local_error->message);
g_printerr (_("Warning: Problem looking for related refs: %s\n"),
local_error->message);
continue;
}
}
if (!flatpak_dir_uninstall (dir, ref, flags,
cancellable, error))
return FALSE;
if (related != NULL)
{
for (i = 0; i < related->len; i++)
{
FlatpakRelated *rel = g_ptr_array_index (related, i);
@@ -132,15 +158,26 @@ flatpak_builtin_uninstall (int argc, char **argv, GCancellable *cancellable, GEr
continue;
parts = g_strsplit (rel->ref, "/", 0);
g_print (_("Uninstalling related: %s\n"), parts[1]);
if (!flatpak_dir_uninstall (dir, rel->ref, flags,
cancellable, &local_error))
g_printerr (_("Warning: Failed to uninstall related ref: %s\n"),
rel->ref);
if (g_hash_table_insert (uninstall_refs_hash, g_strdup (rel->ref), NULL))
g_ptr_array_add (uninstall_refs, g_strdup (rel->ref));
}
}
if (opt_keep_ref)
flags |= FLATPAK_HELPER_UNINSTALL_FLAGS_KEEP_REF;
if (opt_force_remove)
flags |= FLATPAK_HELPER_UNINSTALL_FLAGS_FORCE_REMOVE;
for (i = 0; i < uninstall_refs->len; i++)
{
const char *ref = (char *)g_ptr_array_index (uninstall_refs, i);
g_print ("uninstalling %s\n", ref);
if (!flatpak_dir_uninstall (dir, ref, flags,
cancellable, error))
return FALSE;
}
return TRUE;
}
@@ -152,7 +189,6 @@ flatpak_complete_uninstall (FlatpakCompletion *completion)
g_autoptr(GError) error = NULL;
g_auto(GStrv) refs = NULL;
FlatpakKinds kinds;
int i;
context = g_option_context_new ("");
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv, 0, &dir, NULL, NULL))
@@ -163,37 +199,11 @@ flatpak_complete_uninstall (FlatpakCompletion *completion)
switch (completion->argc)
{
case 0:
case 1: /* NAME */
default: /* REF */
flatpak_complete_options (completion, global_entries);
flatpak_complete_options (completion, options);
flatpak_complete_options (completion, user_entries);
refs = flatpak_dir_find_installed_refs (dir, NULL, NULL, opt_arch,
kinds, &error);
if (refs == NULL)
flatpak_completion_debug ("find installed refs error: %s", error->message);
for (i = 0; refs != NULL && refs[i] != NULL; i++)
{
g_auto(GStrv) parts = flatpak_decompose_ref (refs[i], NULL);
if (parts)
flatpak_complete_word (completion, "%s ", parts[1]);
}
break;
case 2: /* Branch */
refs = flatpak_dir_find_installed_refs (dir, completion->argv[1], NULL, opt_arch,
kinds, &error);
if (refs == NULL)
flatpak_completion_debug ("find installed refs error: %s", error->message);
for (i = 0; refs != NULL && refs[i] != NULL; i++)
{
g_auto(GStrv) parts = flatpak_decompose_ref (refs[i], NULL);
if (parts)
flatpak_complete_word (completion, "%s ", parts[3]);
}
break;
default:
flatpak_complete_partial_ref (completion, kinds, opt_arch, dir, NULL);
break;
}

View File

@@ -32,8 +32,7 @@
<cmdsynopsis>
<command>flatpak uninstall</command>
<arg choice="opt" rep="repeat">OPTION</arg>
<arg choice="plain">NAME</arg>
<arg choice="opt">BRANCH</arg>
<arg choice="opt" rep="repeat">REF</arg>
</cmdsynopsis>
</refsynopsisdiv>
@@ -41,12 +40,17 @@
<title>Description</title>
<para>
Uninstalls an application or runtime. The <arg choice="plain">NAME</arg>,
<arg choice="plain">ARCH</arg> and <arg choice="plain">BRANCH</arg>
arguments must identify an installed application.
If <arg choice="plain">BRANCH</arg> is not specified, it defaults
to whatever is installed, unless there are multiple versions, then you
have to specify a branch.
Uninstalls an application or runtime. <arg choice="plain">REF</arg> is a reference to the
application or runtime to install. If no <arg choice="plain">REF</arg> is given, everything
is updated.
</para>
<para>
Each <arg choice="plain">REF</arg> arguments is a full or partial indentifier in the
flatpak ref format, which looks like "(app|runtime)/ID/ARCH/BRANCH". All elements
except ID are optional and can be left out, including the slashes,
so most of the time you need only specify ID. Any part left out will be matched
against what is installed, and if there are multiple matches an error message
will list the alternatives.
</para>
<para>
By default this looks for both installed apps and runtime