diff options
author | Phaedrus Leeds <matthew.leeds@endlessm.com> | 2020-08-24 07:49:26 -0700 |
---|---|---|
committer | Phaedrus Leeds <matthew.leeds@endlessm.com> | 2020-08-31 09:14:47 -0700 |
commit | b92f99182afd0b1553e90d38ffefc3baeeb298a7 (patch) | |
tree | 366291eb16cad189271c6edc7a806dcf6c57fa96 | |
parent | 59c542f5d95f80ec7bb5d6a88b31c2296ff28018 (diff) | |
download | flatpak-auto-remove-unused.tar.gz |
app: Remove EOL unused runtimes in update commandauto-remove-unused
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.
-rw-r--r-- | app/flatpak-builtins-update.c | 19 | ||||
-rw-r--r-- | common/flatpak-transaction.c | 97 | ||||
-rw-r--r-- | common/flatpak-transaction.h | 5 | ||||
-rw-r--r-- | tests/test-repo.sh | 23 |
4 files changed, 142 insertions, 2 deletions
diff --git a/app/flatpak-builtins-update.c b/app/flatpak-builtins-update.c index b7ca37ec..7bc340aa 100644 --- a/app/flatpak-builtins-update.c +++ b/app/flatpak-builtins-update.c @@ -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++) diff --git a/common/flatpak-transaction.c b/common/flatpak-transaction.c index 8cb232ca..d2312490 100644 --- a/common/flatpak-transaction.c +++ b/common/flatpak-transaction.c @@ -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) @@ -4185,6 +4230,41 @@ prune_maybe_unused_list (FlatpakTransaction *self, } 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, GError **error) @@ -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 diff --git a/common/flatpak-transaction.h b/common/flatpak-transaction.h index 8b9d4024..06efba46 100644 --- a/common/flatpak-transaction.h +++ b/common/flatpak-transaction.h @@ -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 diff --git a/tests/test-repo.sh b/tests/test-repo.sh index 86647005..e0eb56a1 100644 --- a/tests/test-repo.sh +++ b/tests/test-repo.sh @@ -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) |