[gnome-software/mwleeds/fix-deprecated-install] WIP: flatpak: Migrate flatpakref handling to FlatpakTransaction




commit e078256e1864a479b708b77a96e65e4977dc2907
Author: Phaedrus Leeds <mwleeds protonmail com>
Date:   Mon Oct 11 12:30:02 2021 -0700

    WIP: flatpak: Migrate flatpakref handling to FlatpakTransaction
    
    Currently we use flatpak_installation_install_ref_file() when parsing a
    .flatpakref file for displaying it to the user, but that function is
    deprecated in favor of flatpak_transaction_add_install_flatpakref(). So,
    migrate to the replacement function.
    
    This is unfortunately not a simple migration, mainly because while the
    deprecated function only adds the appropriate remote but doesn't install
    the thing, by default a FlatpakTransaction will execute the install
    operation unless aborted. So, abort the transaction so that we have
    enough information to display the app to the user and let them decide
    whether to install it.

 plugins/flatpak/gs-flatpak.c | 148 +++++++++++++++++++++++++++++++++++++------
 1 file changed, 130 insertions(+), 18 deletions(-)
---
diff --git a/plugins/flatpak/gs-flatpak.c b/plugins/flatpak/gs-flatpak.c
index 88bb69a72..fd3ea8521 100644
--- a/plugins/flatpak/gs-flatpak.c
+++ b/plugins/flatpak/gs-flatpak.c
@@ -3438,6 +3438,33 @@ gs_flatpak_file_to_app_bundle (GsFlatpak *self,
        return g_steal_pointer (&app);
 }
 
+static gboolean
+_txn_abort_on_ready (FlatpakTransaction *transaction)
+{
+       return FALSE;
+}
+
+static gboolean
+_txn_add_new_remote (FlatpakTransaction *transaction,
+                    FlatpakTransactionRemoteReason reason,
+                    const char *from_id,
+                    const char *remote_name,
+                    const char *url)
+{
+       return TRUE;
+}
+
+static int
+_txn_choose_remote_for_ref (FlatpakTransaction *transaction,
+                           const char *for_ref,
+                           const char *runtime_ref,
+                           const char * const *remotes)
+{
+       /* This transaction is just for displaying the app not installing it so
+        * this choice shouldn't matter */
+       return 0;
+}
+
 GsApp *
 gs_flatpak_file_to_app_ref (GsFlatpak *self,
                            GFile *file,
@@ -3447,9 +3474,13 @@ gs_flatpak_file_to_app_ref (GsFlatpak *self,
        GsApp *runtime;
        const gchar *const *locales = g_get_language_names ();
        const gchar *remote_name;
+       gboolean is_runtime;
        gsize len = 0;
+       GList *txn_ops;
        g_autofree gchar *contents = NULL;
-       g_autoptr(FlatpakRemoteRef) xref = NULL;
+       g_autoptr(FlatpakTransaction) transaction = NULL;
+       g_autoptr(FlatpakRef) parsed_ref = NULL;
+       g_autoptr(FlatpakRemoteRef) remote_ref = NULL;
        g_autoptr(FlatpakRemote) xremote = NULL;
        g_autoptr(GBytes) ref_file_data = NULL;
        g_autoptr(GError) error_local = NULL;
@@ -3464,6 +3495,7 @@ gs_flatpak_file_to_app_ref (GsFlatpak *self,
        g_autofree gchar *ref_icon = NULL;
        g_autofree gchar *ref_title = NULL;
        g_autofree gchar *ref_name = NULL;
+       g_autofree gchar *ref_branch = NULL;
 
        /* add current locales */
        for (guint i = 0; locales[i] != NULL; i++)
@@ -3499,35 +3531,118 @@ gs_flatpak_file_to_app_ref (GsFlatpak *self,
                }
        }
 
-       /* get name */
+       /* get name, branch, kind */
        ref_name = g_key_file_get_string (kf, "Flatpak Ref", "Name", error);
        if (ref_name == NULL) {
                gs_utils_error_convert_gio (error);
                return NULL;
        }
+       ref_branch = g_key_file_get_string (kf, "Flatpak Ref", "Branch", error);
+       if (ref_branch == NULL) {
+               gs_utils_error_convert_gio (error);
+               return NULL;
+       }
+       is_runtime = g_key_file_get_boolean (kf, "Flatpak Ref", "IsRuntime", error);
+       if (error != NULL && *error != NULL) {
+               gs_utils_error_convert_gio (error);
+               return NULL;
+       }
 
-       /* install the remote, but not the app */
+       /* install the remote, but not the app by aborting the transaction at the "ready" signal */
+       transaction = flatpak_transaction_new_for_installation (self->installation, cancellable, error);
+       if (transaction == NULL) {
+               gs_flatpak_error_convert (error);
+               return NULL;
+       }
+       flatpak_transaction_set_no_interaction (transaction, TRUE);
+       g_signal_connect (transaction, "ready", G_CALLBACK (_txn_abort_on_ready), NULL);
+       g_signal_connect (transaction, "add-new-remote", G_CALLBACK (_txn_add_new_remote), NULL);
+       g_signal_connect (transaction, "choose-remote-for-ref", G_CALLBACK (_txn_choose_remote_for_ref), 
NULL);
        ref_file_data = g_bytes_new (contents, len);
-       xref = flatpak_installation_install_ref_file (self->installation,
-                                                     ref_file_data,
-                                                     cancellable,
-                                                     error);
-       if (xref == NULL) {
+       if (!flatpak_transaction_add_install_flatpakref (transaction, ref_file_data, error)) {
                gs_flatpak_error_convert (error);
                return NULL;
        }
+       g_assert (!flatpak_transaction_run (transaction, cancellable, &error_local));
 
-       /* load metadata */
-       app = gs_flatpak_create_app (self, NULL /* origin */, FLATPAK_REF (xref), NULL, cancellable);
-       if (gs_app_get_state (app) == GS_APP_STATE_INSTALLED) {
-               if (gs_flatpak_app_get_ref_name (app) == NULL)
-                       gs_flatpak_set_metadata (self, app, FLATPAK_REF (xref));
-               return g_steal_pointer (&app);
+       if (!g_error_matches (error_local, FLATPAK_ERROR, FLATPAK_ERROR_ALREADY_INSTALLED) &&
+           !g_error_matches (error_local, FLATPAK_ERROR, FLATPAK_ERROR_ABORTED)) {
+               g_propagate_error (error, g_steal_pointer (&error_local));
+               gs_flatpak_error_convert (error);
+               return NULL;
        }
+
+       /* handle the already installed case */
+       if (g_error_matches (error_local, FLATPAK_ERROR, FLATPAK_ERROR_ALREADY_INSTALLED)) {
+               g_autoptr(FlatpakInstalledRef) installed_ref = NULL;
+               installed_ref = flatpak_installation_get_installed_ref (self->installation,
+                                                                       is_runtime ? FLATPAK_REF_KIND_RUNTIME 
: FLATPAK_REF_KIND_APP,
+                                                                       ref_name,
+                                                                       NULL, /* arch */
+                                                                       ref_branch,
+                                                                       cancellable,
+                                                                       error);
+               if (installed_ref == NULL) {
+                       gs_flatpak_error_convert (error);
+                       return NULL;
+               }
+               app = gs_flatpak_create_app (self, NULL /* origin */, FLATPAK_REF (installed_ref), NULL, 
cancellable);
+               if (gs_app_get_state (app) == GS_APP_STATE_INSTALLED) {
+                       if (gs_flatpak_app_get_ref_name (app) == NULL)
+                               gs_flatpak_set_metadata (self, app, FLATPAK_REF (installed_ref));
+                       return g_steal_pointer (&app);
+               } else {
+                       g_set_error (error,
+                                    GS_PLUGIN_ERROR,
+                                    GS_PLUGIN_ERROR_FAILED,
+                                    "cannot find installed app %s", ref_name);
+                       return NULL;
+               }
+       }
+
+       g_clear_error (&error_local);
+
+       /* find the operation for the flatpakref */
+       txn_ops = flatpak_transaction_get_operations (transaction);
+       for (GList *l = txn_ops; l != NULL; l = l->next) {
+               FlatpakTransactionOperation *op = l->data;
+               const char *op_ref = flatpak_transaction_operation_get_ref (op);
+               parsed_ref = flatpak_ref_parse (op_ref, error);
+               if (parsed_ref == NULL) {
+                       gs_flatpak_error_convert (error);
+                       return NULL;
+               }
+               if (g_strcmp0 (flatpak_ref_get_name (parsed_ref), ref_name) != 0) {
+                       g_clear_object (&parsed_ref);
+               } else {
+                       remote_name = flatpak_transaction_operation_get_remote (op);
+                       g_debug ("auto-created remote name: %s", remote_name);
+                       break;
+               }
+       }
+       g_assert (parsed_ref != NULL);
+       g_list_free_full (g_steal_pointer (&txn_ops), g_object_unref);
+
+       /* fetch remote ref */
+       remote_ref = flatpak_installation_fetch_remote_ref_sync (self->installation,
+                                                          remote_name,
+                                                          flatpak_ref_get_kind (parsed_ref),
+                                                          flatpak_ref_get_name (parsed_ref),
+                                                          flatpak_ref_get_arch (parsed_ref),
+                                                          flatpak_ref_get_branch (parsed_ref),
+                                                          cancellable,
+                                                          error);
+       if (remote_ref == NULL) {
+               gs_flatpak_error_convert (error);
+               return NULL;
+       }
+
+       /* load metadata */
+       app = gs_flatpak_create_app (self, remote_name, FLATPAK_REF (remote_ref), NULL, cancellable);
        gs_app_add_quirk (app, GS_APP_QUIRK_HAS_SOURCE);
        gs_flatpak_app_set_file_kind (app, GS_FLATPAK_APP_FILE_KIND_REF);
        gs_app_set_state (app, GS_APP_STATE_AVAILABLE_LOCAL);
-       gs_flatpak_set_metadata (self, app, FLATPAK_REF (xref));
+       gs_flatpak_set_metadata (self, app, FLATPAK_REF (remote_ref));
 
        /* use the data from the flatpakref file as a fallback */
        ref_title = g_key_file_get_string (kf, "Flatpak Ref", "Title", NULL);
@@ -3551,8 +3666,6 @@ gs_flatpak_file_to_app_ref (GsFlatpak *self,
        }
 
        /* set the origin data */
-       remote_name = flatpak_remote_ref_get_remote_name (xref);
-       g_debug ("auto-created remote name: %s", remote_name);
        xremote = flatpak_installation_get_remote_by_name (self->installation,
                                                           remote_name,
                                                           cancellable,
@@ -3570,7 +3683,6 @@ gs_flatpak_file_to_app_ref (GsFlatpak *self,
                             flatpak_remote_get_name (xremote));
                return NULL;
        }
-       gs_flatpak_set_app_origin (self, app, remote_name, xremote, cancellable);
        gs_app_set_origin_hostname (app, origin_url);
 
        /* get the new appstream data (nonfatal for failure) */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]