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



commit 875013b1aea4109d35e5bae1f1a653d444f06824
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.

 plugins/flatpak/gs-flatpak-transaction.c | 74 +++++++++++++++++++++++++++++++-
 plugins/flatpak/gs-plugin-flatpak.c      |  4 ++
 2 files changed, 77 insertions(+), 1 deletion(-)
---
diff --git a/plugins/flatpak/gs-flatpak-transaction.c b/plugins/flatpak/gs-flatpak-transaction.c
index d1d01025..3af449a3 100644
--- a/plugins/flatpak/gs-flatpak-transaction.c
+++ b/plugins/flatpak/gs-flatpak-transaction.c
@@ -522,13 +522,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 */
@@ -559,6 +627,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 845f289f..81b9433d 100644
--- a/plugins/flatpak/gs-plugin-flatpak.c
+++ b/plugins/flatpak/gs-plugin-flatpak.c
@@ -932,6 +932,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 */


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