mirror of
https://github.com/flatpak/flatpak.git
synced 2026-07-01 03:37:39 -04:00
app: Remove EOL unused runtimes in update command
In case a runtime becomes unused and then later becomes End-Of-Life, it is currently not removed. So this commit removes such runtimes in the update command, as discussed in #2639. A unit test is included. I am planning to propose to use the FlatpakTransaction API added here in gnome-software, so that users don't have to use the CLI at all for runtimes to be cleaned up. KDE Discover already removes unused runtimes periodically.
This commit is contained in:
@@ -147,6 +147,8 @@ flatpak_builtin_update (int argc,
|
||||
flatpak_transaction_set_disable_static_deltas (transaction, opt_no_static_deltas);
|
||||
flatpak_transaction_set_disable_dependencies (transaction, opt_no_deps);
|
||||
flatpak_transaction_set_disable_related (transaction, opt_no_related);
|
||||
if (opt_arch)
|
||||
flatpak_transaction_set_default_arch (transaction, opt_arch);
|
||||
|
||||
for (int i = 0; opt_sideload_repos != NULL && opt_sideload_repos[i] != NULL; i++)
|
||||
flatpak_transaction_add_sideload_repo (transaction, opt_sideload_repos[i]);
|
||||
@@ -275,6 +277,23 @@ flatpak_builtin_update (int argc,
|
||||
}
|
||||
}
|
||||
|
||||
/* Add uninstall operations for any runtimes that are unused and EOL.
|
||||
* Strictly speaking these are not updates but "update" is the command people
|
||||
* run to keep their system maintained. It would be possible to do this in
|
||||
* the transaction that updates them to being EOL, but doing it here seems
|
||||
* more future-proof since we may want to use additional conditions to
|
||||
* determine if something is unused. See
|
||||
* https://github.com/flatpak/flatpak/issues/3799
|
||||
*/
|
||||
if ((kinds & FLATPAK_KINDS_RUNTIME) && n_prefs == 0 && !opt_no_deps)
|
||||
{
|
||||
for (k = 0; k < dirs->len; k++)
|
||||
{
|
||||
FlatpakTransaction *transaction = g_ptr_array_index (transactions, k);
|
||||
flatpak_transaction_set_include_unused_uninstall_ops (transaction, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
has_updates = FALSE;
|
||||
|
||||
for (k = 0; k < dirs->len; k++)
|
||||
|
||||
@@ -185,6 +185,7 @@ struct _FlatpakTransactionPrivate
|
||||
gboolean reinstall;
|
||||
gboolean force_uninstall;
|
||||
gboolean can_run;
|
||||
gboolean include_unused_uninstall_ops;
|
||||
char *default_arch;
|
||||
guint max_op;
|
||||
|
||||
@@ -1672,6 +1673,50 @@ flatpak_transaction_set_default_arch (FlatpakTransaction *self,
|
||||
priv->default_arch = g_strdup (arch);
|
||||
}
|
||||
|
||||
/**
|
||||
* flatpak_transaction_set_include_unused_uninstall_ops:
|
||||
* @self: a #FlatpakTransaction
|
||||
* @include_unused_uninstall_ops: whether to include unused uninstall ops
|
||||
*
|
||||
* When this is set to %TRUE, Flatpak will add uninstall operations to the
|
||||
* transaction for each runtime it considers unused. This is used by the
|
||||
* "update" CLI command to garbage collect runtimes and free disk space.
|
||||
*
|
||||
* No guarantees are made about the exact hueristic used; e.g. only end-of-life
|
||||
* unused runtimes may be uninstalled with this set. To see the full list of
|
||||
* unused runtimes in an installation, use
|
||||
* flatpak_installation_list_unused_refs().
|
||||
*
|
||||
* Since: 1.9.0
|
||||
*/
|
||||
void
|
||||
flatpak_transaction_set_include_unused_uninstall_ops (FlatpakTransaction *self,
|
||||
gboolean include_unused_uninstall_ops)
|
||||
{
|
||||
FlatpakTransactionPrivate *priv = flatpak_transaction_get_instance_private (self);
|
||||
|
||||
priv->include_unused_uninstall_ops = include_unused_uninstall_ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* flatpak_transaction_get_include_unused_uninstall_ops:
|
||||
* @self: a #FlatpakTransaction
|
||||
*
|
||||
* Gets the value set by
|
||||
* flatpak_transaction_set_include_unused_uninstall_ops().
|
||||
*
|
||||
* Returns: %TRUE if include_unused_uninstall_ops is set, %FALSE otherwise
|
||||
*
|
||||
* Since: 1.9.0
|
||||
*/
|
||||
gboolean
|
||||
flatpak_transaction_get_include_unused_uninstall_ops (FlatpakTransaction *self)
|
||||
{
|
||||
FlatpakTransactionPrivate *priv = flatpak_transaction_get_instance_private (self);
|
||||
|
||||
return priv->include_unused_uninstall_ops;
|
||||
}
|
||||
|
||||
static FlatpakTransactionOperation *
|
||||
flatpak_transaction_get_last_op_for_ref (FlatpakTransaction *self,
|
||||
const char *ref)
|
||||
@@ -4184,6 +4229,41 @@ prune_maybe_unused_list (FlatpakTransaction *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
populate_maybe_unused_list (FlatpakTransaction *self,
|
||||
GHashTable *maybe_unused_runtimes,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
FlatpakTransactionPrivate *priv = flatpak_transaction_get_instance_private (self);
|
||||
GVariantBuilder builder;
|
||||
g_autoptr(GVariant) list_unused_options = NULL;
|
||||
g_autoptr(GPtrArray) unused_refs = NULL;
|
||||
int i;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
|
||||
g_variant_builder_add (&builder, "{s@v}", "filter-by-eol",
|
||||
g_variant_new_variant (g_variant_new_boolean (TRUE)));
|
||||
list_unused_options = g_variant_ref_sink (g_variant_builder_end (&builder));
|
||||
|
||||
unused_refs = flatpak_installation_list_unused_refs_with_options (priv->installation,
|
||||
NULL, /* arch */
|
||||
list_unused_options,
|
||||
cancellable, error);
|
||||
if (unused_refs == NULL)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < unused_refs->len; i++)
|
||||
{
|
||||
FlatpakInstalledRef *iref = g_ptr_array_index (unused_refs, i);
|
||||
g_hash_table_replace (maybe_unused_runtimes,
|
||||
flatpak_ref_format_ref (FLATPAK_REF (iref)),
|
||||
NULL);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
add_uninstall_unused_ops (FlatpakTransaction *self,
|
||||
GCancellable *cancellable,
|
||||
@@ -4202,7 +4282,9 @@ add_uninstall_unused_ops (FlatpakTransaction *self,
|
||||
|
||||
/* This is the set of runtimes which are no longer needed by something in the
|
||||
* transaction (an uninstall or update). The values are either the relevant
|
||||
* remote name or %NULL. */
|
||||
* remote name or %NULL. In case priv->include_unused_uninstall_ops is set,
|
||||
* this is initialized to the set of unused runtimes at the start of the
|
||||
* transaction.*/
|
||||
maybe_unused_runtimes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
|
||||
/* This is the set of runtimes being used by an install or update operation
|
||||
@@ -4218,6 +4300,10 @@ add_uninstall_unused_ops (FlatpakTransaction *self,
|
||||
* uninstall operations added by this function. */
|
||||
run_after_ops = g_ptr_array_new ();
|
||||
|
||||
if (priv->include_unused_uninstall_ops &&
|
||||
!populate_maybe_unused_list (self, maybe_unused_runtimes, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
for (l = priv->ops; l != NULL; l = next)
|
||||
{
|
||||
FlatpakTransactionOperation *op = l->data;
|
||||
@@ -4346,6 +4432,15 @@ add_uninstall_unused_ops (FlatpakTransaction *self,
|
||||
g_autofree char *resolved_remote = NULL;
|
||||
FlatpakTransactionOperation *unused_op = NULL;
|
||||
|
||||
if (priv->default_arch)
|
||||
{
|
||||
g_auto(GStrv) parts = flatpak_decompose_ref (runtime_ref, error);
|
||||
if (parts == NULL)
|
||||
return FALSE;
|
||||
if (g_strcmp0 (parts[2], priv->default_arch) != 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (remote == NULL)
|
||||
g_assert (dir_ref_is_installed (priv->dir, runtime_ref, &resolved_remote, NULL));
|
||||
else
|
||||
|
||||
@@ -238,6 +238,11 @@ void flatpak_transaction_set_parent_window (FlatpakTransaction *s
|
||||
FLATPAK_EXTERN
|
||||
const char * flatpak_transaction_get_parent_window (FlatpakTransaction *self);
|
||||
FLATPAK_EXTERN
|
||||
void flatpak_transaction_set_include_unused_uninstall_ops (FlatpakTransaction *self,
|
||||
gboolean include_unused_uninstall_ops);
|
||||
FLATPAK_EXTERN
|
||||
gboolean flatpak_transaction_get_include_unused_uninstall_ops (FlatpakTransaction *self);
|
||||
FLATPAK_EXTERN
|
||||
void flatpak_transaction_add_dependency_source (FlatpakTransaction *self,
|
||||
FlatpakInstallation *installation);
|
||||
FLATPAK_EXTERN
|
||||
|
||||
@@ -24,7 +24,7 @@ set -euo pipefail
|
||||
skip_without_bwrap
|
||||
skip_revokefs_without_fuse
|
||||
|
||||
echo "1..40"
|
||||
echo "1..41"
|
||||
|
||||
#Regular repo
|
||||
setup_repo
|
||||
@@ -470,6 +470,27 @@ update_repo
|
||||
|
||||
ok "eol runtime uninstalled on app update to different runtime"
|
||||
|
||||
${FLATPAK} ${U} install -y test-repo org.test.Hello
|
||||
|
||||
# Runtime isn't EOL at time of app uninstall, so it's left alone
|
||||
${FLATPAK} ${U} uninstall -y org.test.Hello
|
||||
assert_has_dir $FL_DIR/runtime/org.test.Platform/$ARCH/master/active/files
|
||||
|
||||
EXPORT_ARGS="--end-of-life=Reason4" make_updated_runtime
|
||||
${FLATPAK} ${U} update -y org.test.Platform
|
||||
${FLATPAK} ${U} info org.test.Platform > info-log
|
||||
assert_file_has_content info-log "End-of-life: Reason4"
|
||||
|
||||
# Now that the runtime is EOL and unused it should be uninstalled by the update command
|
||||
${FLATPAK} ${U} update -y
|
||||
assert_not_has_dir $FL_DIR/runtime/org.test.Platform/$ARCH/master/active/files
|
||||
|
||||
# Revert things for future tests
|
||||
EXPORT_ARGS="" make_updated_runtime
|
||||
${FLATPAK} ${U} uninstall -y --all
|
||||
|
||||
ok "eol runtime uninstalled during update run"
|
||||
|
||||
${FLATPAK} ${U} install -y test-repo org.test.Platform
|
||||
|
||||
port=$(cat httpd-port)
|
||||
|
||||
Reference in New Issue
Block a user