[gnome-software/fix-flatpak-related-progress: 10/11] flatpak: Set app to installed when a related thing is updated



commit 97c0ae040d6163d93794fb03331d9e48e7cd0141
Author: Matthew Leeds <matthew leeds endlessm com>
Date:   Tue Jul 7 19:54:20 2020 -0700

    flatpak: Set app to installed when a related thing is updated
    
    When an app's locale extension is updated but the app is not, we put
    progress updates on the app so they are user visible. However since
    _transaction_operation_done() is only ever called for the locale, the
    app never gets set to AS_APP_STATE_INSTALLED and instead gets frozen in
    the "Preparing..." state when gs_plugin_loader_helper_free() sets the
    progress to GS_APP_PROGRESS_UNKNOWN on it.
    
    So set the app to installed when one of its related refs is updated, if
    the app itself is being skipped.
    
    Relatedly, update the unit test which tests extension updates so it
    succeeds with Flatpak older than 1.7.3, because we'll get the test
    working in subsequent commits.

 plugins/flatpak/gs-flatpak-transaction.c | 74 +++++++++++++++++++++++++++++++-
 plugins/flatpak/gs-plugin-flatpak.c      |  4 ++
 plugins/flatpak/gs-self-test.c           |  7 +++
 3 files changed, 84 insertions(+), 1 deletion(-)
---
diff --git a/plugins/flatpak/gs-flatpak-transaction.c b/plugins/flatpak/gs-flatpak-transaction.c
index 00e35b85..c76e17f7 100644
--- a/plugins/flatpak/gs-flatpak-transaction.c
+++ b/plugins/flatpak/gs-flatpak-transaction.c
@@ -523,13 +523,81 @@ _transaction_new_operation (FlatpakTransaction *transaction,
        }
 }
 
+#if FLATPAK_CHECK_VERSION(1, 7, 3)
+static gboolean
+later_op_also_related (GList                       *ops,
+                      FlatpakTransactionOperation *current_op,
+                      FlatpakTransactionOperation *related_to_current_op)
+{
+       /* Here we're determining if anything in @ops which comes after
+        * @current_op is related to @related_to_current_op and not skipped
+        */
+       gboolean found_later_op = FALSE, seen_current_op = FALSE;
+       for (GList *l = ops; l != NULL; l = l->next) {
+               FlatpakTransactionOperation *op = l->data;
+               GPtrArray *related_to_ops;
+               if (current_op == op) {
+                       seen_current_op = TRUE;
+                       continue;
+               }
+               if (!seen_current_op)
+                       continue;
+
+               related_to_ops = flatpak_transaction_operation_get_related_to_ops (op);
+               for (gsize i = 0; related_to_ops != NULL && i < related_to_ops->len; i++) {
+                       FlatpakTransactionOperation *related_to_op = g_ptr_array_index (related_to_ops, i);
+                       if (related_to_op == related_to_current_op &&
+                           !flatpak_transaction_operation_get_is_skipped (related_to_op))
+                               found_later_op = TRUE;
+               }
+       }
+
+       return found_later_op;
+}
+
+static void
+set_skipped_related_apps_to_installed (GsFlatpakTransaction        *self,
+                                      FlatpakTransaction          *transaction,
+                                      FlatpakTransactionOperation *operation)
+{
+       /* It's possible the thing being updated/installed, @operation, is a
+        * related ref (e.g. extension or runtime) of an app which itself doesn't
+        * need an update and therefore won't have _transaction_operation_done()
+        * called for it directly. So we have to set the main app to installed
+        * here.
+       */
+       g_autolist(GObject) ops = flatpak_transaction_get_operations (transaction);
+       GPtrArray *related_to_ops = flatpak_transaction_operation_get_related_to_ops (operation);
+
+       for (gsize i = 0; related_to_ops != NULL && i < related_to_ops->len; i++) {
+               FlatpakTransactionOperation *related_to_op = g_ptr_array_index (related_to_ops, i);
+               if (flatpak_transaction_operation_get_is_skipped (related_to_op)) {
+                       const gchar *ref;
+                       g_autoptr(GsApp) related_to_app = NULL;
+
+                       /* Check that no later op is also related to related_to_op, in
+                        * which case we want to let that operation finish before setting
+                        * the main app to installed.
+                        */
+                       if (later_op_also_related (ops, operation, related_to_op))
+                               continue;
+
+                       ref = flatpak_transaction_operation_get_ref (related_to_op);
+                       related_to_app = _ref_to_app (self, ref);
+                       if (related_to_app != NULL)
+                               gs_app_set_state (related_to_app, AS_APP_STATE_INSTALLED);
+               }
+       }
+}
+#endif  /* flatpak 1.7.3 */
+
 static void
 _transaction_operation_done (FlatpakTransaction *transaction,
                             FlatpakTransactionOperation *operation,
                             const gchar *commit,
                             FlatpakTransactionResult details)
 {
-#if !FLATPAK_CHECK_VERSION(1,5,1)
+#if !FLATPAK_CHECK_VERSION(1,5,1) || FLATPAK_CHECK_VERSION(1,7,3)
        GsFlatpakTransaction *self = GS_FLATPAK_TRANSACTION (transaction);
 #endif
        /* invalidate */
@@ -560,6 +628,10 @@ _transaction_operation_done (FlatpakTransaction *transaction,
                        gs_app_set_state (app, AS_APP_STATE_UPDATABLE_LIVE);
                else
                        gs_app_set_state (app, AS_APP_STATE_INSTALLED);
+
+#if FLATPAK_CHECK_VERSION(1,7,3)
+               set_skipped_related_apps_to_installed (self, transaction, operation);
+#endif
                break;
        case FLATPAK_TRANSACTION_OPERATION_UNINSTALL:
                /* we don't actually know if this app is re-installable */
diff --git a/plugins/flatpak/gs-plugin-flatpak.c b/plugins/flatpak/gs-plugin-flatpak.c
index 66877616..5b7a5492 100644
--- a/plugins/flatpak/gs-plugin-flatpak.c
+++ b/plugins/flatpak/gs-plugin-flatpak.c
@@ -933,6 +933,10 @@ gs_plugin_flatpak_update (GsPlugin *plugin,
                        gs_flatpak_error_convert (error);
                        return FALSE;
                }
+
+               /* add to the transaction cache for quick look up -- other unrelated
+                * refs will be matched using gs_plugin_flatpak_find_app_by_ref() */
+               gs_flatpak_transaction_add_app (transaction, app);
        }
 
        /* run transaction */
diff --git a/plugins/flatpak/gs-self-test.c b/plugins/flatpak/gs-self-test.c
index d557c6fd..3f37937b 100644
--- a/plugins/flatpak/gs-self-test.c
+++ b/plugins/flatpak/gs-self-test.c
@@ -1758,7 +1758,14 @@ gs_plugins_flatpak_runtime_extension_func (GsPluginLoader *plugin_loader)
                                            loop);
        g_main_loop_run (loop);
        gs_test_flush_main_context ();
+#if !FLATPAK_CHECK_VERSION(1,7,3)
+       /* Older flatpak versions don't have the API we use to propagate state
+        * between extension and app
+        */
+       gs_app_set_state (app, AS_APP_STATE_INSTALLED);
+#else
        g_assert_cmpint (gs_app_get_state (app), ==, AS_APP_STATE_INSTALLED);
+#endif
        g_assert_cmpstr (gs_app_get_version (app), ==, "1.2.3");
        g_assert_true (got_progress_installing);
        g_assert_cmpint (pending_app_changed_cnt, ==, 0);


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