[gnome-software] flatpak: Do not try to install a duplicate RuntimeRepo



commit dd45ff4f1fcda072c4e2b669373b501224cbccc4
Author: Richard Hughes <richard hughsie com>
Date:   Fri Jul 14 16:56:59 2017 +0100

    flatpak: Do not try to install a duplicate RuntimeRepo
    
    Check if the runtime is available in an already-installed remote before
    attempting to install the new source.
    
    Based on a patch by Joaquim Rocha <jrocha endlessm com>, many thanks.

 plugins/flatpak/gs-flatpak.c        |   62 +++++++++++--
 plugins/flatpak/gs-plugin-flatpak.c |   13 +--
 plugins/flatpak/gs-self-test.c      |  178 ++++++++++++++++++++++++++++++++++-
 3 files changed, 237 insertions(+), 16 deletions(-)
---
diff --git a/plugins/flatpak/gs-flatpak.c b/plugins/flatpak/gs-flatpak.c
index 42a3c4c..e6768fb 100644
--- a/plugins/flatpak/gs-flatpak.c
+++ b/plugins/flatpak/gs-flatpak.c
@@ -915,6 +915,7 @@ gs_flatpak_find_app_by_name_branch (GsFlatpak *self,
                                    GCancellable *cancellable,
                                    GError **error)
 {
+       g_autoptr(GPtrArray) xremotes = NULL;
        g_autoptr(GPtrArray) xrefs = NULL;
 
        g_return_val_if_fail (name != NULL, FALSE);
@@ -940,6 +941,49 @@ gs_flatpak_find_app_by_name_branch (GsFlatpak *self,
                        gs_app_list_add (list, app);
                }
        }
+
+       /* look at each remote xref */
+       xremotes = flatpak_installation_list_remotes (self->installation, cancellable, error);
+       if (xremotes == NULL) {
+               gs_flatpak_error_convert (error);
+               return FALSE;
+       }
+       for (guint i = 0; i < xremotes->len; i++) {
+               FlatpakRemote *xremote = g_ptr_array_index (xremotes, i);
+               g_autoptr(GPtrArray) refs_remote = NULL;
+               refs_remote = flatpak_installation_list_remote_refs_sync (self->installation,
+                                                                         flatpak_remote_get_name (xremote),
+                                                                         cancellable, error);
+               if (refs_remote == NULL) {
+                       gs_flatpak_error_convert (error);
+                       return FALSE;
+               }
+               for (guint j = 0; j < refs_remote->len; j++) {
+                       FlatpakRef *xref = g_ptr_array_index (refs_remote, j);
+                       if (g_strcmp0 (flatpak_ref_get_name (xref), name) == 0 &&
+                           g_strcmp0 (flatpak_ref_get_branch (xref), branch) == 0) {
+                               g_autoptr(GsApp) app = gs_flatpak_create_app (self, xref);
+
+                               /* don't 'overwrite' installed apps */
+                               if (gs_app_list_lookup (list, gs_app_get_unique_id (app)) != NULL) {
+                                       g_debug ("ignoring installed %s",
+                                                gs_app_get_unique_id (app));
+                                       continue;
+                               }
+
+                               /* if we added a LOCAL runtime, and then we found
+                                * an already installed remote that provides the
+                                * exact same thing */
+                               if (gs_app_get_state (app) == AS_APP_STATE_AVAILABLE_LOCAL)
+                                       gs_app_set_state (app, AS_APP_STATE_UNKNOWN);
+                               gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
+
+                               gs_app_set_origin (app, flatpak_remote_get_name (xremote));
+                               gs_app_list_add (list, app);
+                       }
+               }
+       }
+
        return TRUE;
 }
 
@@ -2657,14 +2701,16 @@ gs_flatpak_app_install (GsFlatpak *self,
                        gs_app_set_state (app_src, AS_APP_STATE_UNKNOWN);
                        gs_app_set_state (app_src, AS_APP_STATE_AVAILABLE);
 
-                       /* install the flatpakrepo */
-                       if (!gs_flatpak_app_install_source (self,
-                                                           app_src,
-                                                           cancellable,
-                                                           error)) {
-                               g_prefix_error (error, "cannot install source from %s: ",
-                                               gs_flatpak_app_get_repo_url (app_src));
-                               return FALSE;
+                       /* install the flatpakrepo if not already installed */
+                       if (gs_app_get_state (app_src) != AS_APP_STATE_INSTALLED) {
+                               if (!gs_flatpak_app_install_source (self,
+                                                                   app_src,
+                                                                   cancellable,
+                                                                   error)) {
+                                       g_prefix_error (error, "cannot install source from %s: ",
+                                                       gs_flatpak_app_get_repo_url (app_src));
+                                       return FALSE;
+                               }
                        }
 
                        /* get the new state */
diff --git a/plugins/flatpak/gs-plugin-flatpak.c b/plugins/flatpak/gs-plugin-flatpak.c
index 3a5efd5..873a80c 100644
--- a/plugins/flatpak/gs-plugin-flatpak.c
+++ b/plugins/flatpak/gs-plugin-flatpak.c
@@ -589,11 +589,9 @@ gs_plugin_flatpak_file_to_app_ref (GsPlugin *plugin,
        runtime_app = gs_app_get_runtime (app_tmp);
        if (runtime_app != NULL &&
            gs_app_get_state (runtime_app) != AS_APP_STATE_INSTALLED) {
-               g_autoptr(GsAppList) list_system_runtimes = gs_app_list_new ();
+               g_autoptr(GsAppList) list_runtimes = gs_app_list_new ();
                for (guint i = 0; i < priv->flatpaks->len; i++) {
                        GsFlatpak *flatpak = g_ptr_array_index (priv->flatpaks, i);
-                       if (gs_flatpak_get_scope (flatpak) != AS_APP_SCOPE_SYSTEM)
-                               continue;
                        g_debug ("looking for %s//%s in %s",
                                 gs_flatpak_app_get_ref_name (runtime_app),
                                 gs_flatpak_app_get_ref_branch (runtime_app),
@@ -601,13 +599,14 @@ gs_plugin_flatpak_file_to_app_ref (GsPlugin *plugin,
                        if (!gs_flatpak_find_app_by_name_branch (flatpak,
                                                                 gs_flatpak_app_get_ref_name (runtime_app),
                                                                 gs_flatpak_app_get_ref_branch (runtime_app),
-                                                                list_system_runtimes,
+                                                                list_runtimes,
                                                                 cancellable, error))
                                return FALSE;
                }
-               for (guint i = 0; i < gs_app_list_length (list_system_runtimes); i++) {
-                       GsApp *runtime_old = gs_app_list_index (list_system_runtimes, i);
-                       if (gs_app_get_state (runtime_old) == AS_APP_STATE_INSTALLED) {
+               for (guint i = 0; i < gs_app_list_length (list_runtimes); i++) {
+                       GsApp *runtime_old = gs_app_list_index (list_runtimes, i);
+                       if (gs_app_get_state (runtime_old) == AS_APP_STATE_INSTALLED ||
+                           gs_app_get_state (runtime_old) == AS_APP_STATE_AVAILABLE) {
                                g_debug ("already have %s, using instead of %s",
                                         gs_app_get_unique_id (runtime_old),
                                         gs_app_get_unique_id (runtime_app));
diff --git a/plugins/flatpak/gs-self-test.c b/plugins/flatpak/gs-self-test.c
index 8455b1b..52105eb 100644
--- a/plugins/flatpak/gs-self-test.c
+++ b/plugins/flatpak/gs-self-test.c
@@ -40,7 +40,7 @@ gs_flatpak_test_write_repo_file (const gchar *fn, const gchar *testdir, GError *
        g_string_append (str, "Comment=Longer one line comment\n");
        g_string_append (str, "Description=Longer multiline comment that "
                              "does into detail.\n");
-       g_string_append (str, "DefaultBranch=stable\n");
+       g_string_append (str, "DefaultBranch=master\n");
        g_string_append_printf (str, "Url=%s\n", testdir_repourl);
        g_string_append (str, "Homepage=http://foo.bar\n";);
        g_string_append (str, "GPGKey=FOOBAR==\n");
@@ -713,6 +713,179 @@ gs_plugins_flatpak_runtime_repo_func (GsPluginLoader *plugin_loader)
        g_assert_cmpint (gs_app_get_state (app_source), ==, AS_APP_STATE_AVAILABLE);
 }
 
+/* same as gs_plugins_flatpak_runtime_repo_func, but this time manually
+ * installing the flatpakrepo BEFORE the flatpakref is installed */
+static void
+gs_plugins_flatpak_runtime_repo_redundant_func (GsPluginLoader *plugin_loader)
+{
+       GsApp *app_source;
+       GsApp *runtime;
+       const gchar *fn_ref = "/var/tmp/self-test/test.flatpakref";
+       const gchar *fn_repo = "/var/tmp/self-test/test.flatpakrepo";
+       gboolean ret;
+       g_autofree gchar *fn_repourl = NULL;
+       g_autofree gchar *testdir2 = NULL;
+       g_autofree gchar *testdir2_repourl = NULL;
+       g_autofree gchar *testdir = NULL;
+       g_autoptr(GError) error = NULL;
+       g_autoptr(GFile) file = NULL;
+       g_autoptr(GFile) file_repo = NULL;
+       g_autoptr(GsApp) app = NULL;
+       g_autoptr(GsApp) app_src = NULL;
+       g_autoptr(GsAppList) sources2 = NULL;
+       g_autoptr(GsAppList) sources = NULL;
+       g_autoptr(GsPluginJob) plugin_job = NULL;
+       g_autoptr(GString) str2 = g_string_new (NULL);
+
+       /* drop all caches */
+       gs_plugin_loader_setup_again (plugin_loader);
+
+       /* write a flatpakrepo file */
+       testdir = gs_test_get_filename (TESTDATADIR, "only-runtime");
+       if (testdir == NULL)
+               return;
+       ret = gs_flatpak_test_write_repo_file (fn_repo, testdir, &error);
+       g_assert_no_error (error);
+       g_assert (ret);
+
+       /* convert it to a GsApp */
+       file_repo = g_file_new_for_path (fn_repo);
+       plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_FILE_TO_APP,
+                                        "file", file_repo,
+                                        "refine-flags", GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION |
+                                                        GS_PLUGIN_REFINE_FLAGS_REQUIRE_RUNTIME,
+                                        NULL);
+       app_src = gs_plugin_loader_job_process_app (plugin_loader, plugin_job, NULL, &error);
+       gs_test_flush_main_context ();
+       g_assert_no_error (error);
+       g_assert (app_src != NULL);
+       g_assert_cmpint (gs_app_get_kind (app_src), ==, AS_APP_KIND_SOURCE);
+       g_assert_cmpint (gs_app_get_state (app_src), ==, AS_APP_STATE_AVAILABLE_LOCAL);
+       g_assert_cmpstr (gs_app_get_id (app_src), ==, "test");
+       g_assert_cmpstr (gs_app_get_unique_id (app_src), ==, "user/*/*/source/test/master");
+       g_assert (gs_app_get_local_file (app_src) != NULL);
+
+       /* install the source manually */
+       g_object_unref (plugin_job);
+       plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_INSTALL,
+                                        "app", app_src,
+                                        NULL);
+       ret = gs_plugin_loader_job_action (plugin_loader, plugin_job, NULL, &error);
+       gs_test_flush_main_context ();
+       g_assert_no_error (error);
+       g_assert (ret);
+       g_assert_cmpint (gs_app_get_state (app_src), ==, AS_APP_STATE_INSTALLED);
+
+       /* write a flatpakref file */
+       fn_repourl = g_strdup_printf ("file://%s", fn_repo);
+       testdir2 = gs_test_get_filename (TESTDATADIR, "app-missing-runtime");
+       if (testdir2 == NULL)
+               return;
+       testdir2_repourl = g_strdup_printf ("file://%s/repo", testdir2);
+       g_string_append (str2, "[Flatpak Ref]\n");
+       g_string_append (str2, "Title=Chiron\n");
+       g_string_append (str2, "Name=org.test.Chiron\n");
+       g_string_append (str2, "Branch=master\n");
+       g_string_append_printf (str2, "Url=%s\n", testdir2_repourl);
+       g_string_append (str2, "IsRuntime=False\n");
+       g_string_append (str2, "Comment=Single line synopsis\n");
+       g_string_append (str2, "Description=A Testing Application\n");
+       g_string_append (str2, "Icon=https://getfedora.org/static/images/fedora-logotext.png\n";);
+       g_string_append_printf (str2, "RuntimeRepo=%s\n", fn_repourl);
+       ret = g_file_set_contents (fn_ref, str2->str, -1, &error);
+       g_assert_no_error (error);
+       g_assert (ret);
+
+       /* convert it to a GsApp */
+       file = g_file_new_for_path (fn_ref);
+       g_object_unref (plugin_job);
+       plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_FILE_TO_APP,
+                                        "file", file,
+                                        "refine-flags", GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION |
+                                                        GS_PLUGIN_REFINE_FLAGS_REQUIRE_RUNTIME,
+                                        NULL);
+       app = gs_plugin_loader_job_process_app (plugin_loader, plugin_job, NULL, &error);
+       gs_test_flush_main_context ();
+       g_assert_no_error (error);
+       g_assert (app != NULL);
+       g_assert_cmpint (gs_app_get_kind (app), ==, AS_APP_KIND_DESKTOP);
+       g_assert_cmpint (gs_app_get_state (app), ==, AS_APP_STATE_AVAILABLE_LOCAL);
+       g_assert_cmpstr (gs_app_get_id (app), ==, "org.test.Chiron.desktop");
+       g_assert (as_utils_unique_id_equal (gs_app_get_unique_id (app),
+                       "user/flatpak/org.test.Chiron-origin/desktop/org.test.Chiron.desktop/master"));
+       g_assert (gs_app_get_local_file (app) != NULL);
+
+       /* get runtime */
+       runtime = gs_app_get_runtime (app);
+       g_assert_cmpstr (gs_app_get_unique_id (runtime), ==, 
"user/flatpak/test/runtime/org.test.Runtime/master");
+       g_assert_cmpint (gs_app_get_state (runtime), ==, AS_APP_STATE_AVAILABLE);
+
+       /* check the number of sources */
+       g_object_unref (plugin_job);
+       plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_GET_SOURCES, NULL);
+       sources = gs_plugin_loader_job_process (plugin_loader, plugin_job,
+                                               NULL, &error);
+       g_assert_no_error (error);
+       g_assert (sources != NULL);
+       g_assert_cmpint (gs_app_list_length (sources), ==, 1); /* repo */
+
+       /* install, which will NOT install the runtime from the RuntimeRemote,
+        * but from the existing test repo */
+       g_object_unref (plugin_job);
+       plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_INSTALL,
+                                        "app", app,
+                                        NULL);
+       ret = gs_plugin_loader_job_action (plugin_loader, plugin_job, NULL, &error);
+       gs_test_flush_main_context ();
+       g_assert_no_error (error);
+       g_assert (ret);
+       g_assert_cmpint (gs_app_get_state (app), ==, AS_APP_STATE_INSTALLED);
+       g_assert_cmpint (gs_app_get_state (runtime), ==, AS_APP_STATE_INSTALLED);
+
+       /* check the number of sources */
+       g_object_unref (plugin_job);
+       plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_GET_SOURCES, NULL);
+       sources2 = gs_plugin_loader_job_process (plugin_loader, plugin_job, NULL, &error);
+       g_assert_no_error (error);
+       g_assert (sources2 != NULL);
+
+       /* remove the app */
+       g_object_unref (plugin_job);
+       plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_REMOVE,
+                                        "app", app,
+                                        NULL);
+       ret = gs_plugin_loader_job_action (plugin_loader, plugin_job, NULL, &error);
+       gs_test_flush_main_context ();
+       g_assert_no_error (error);
+       g_assert (ret);
+       g_assert_cmpint (gs_app_get_state (app), ==, AS_APP_STATE_UNKNOWN);
+
+       /* remove the runtime */
+       g_object_unref (plugin_job);
+       plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_REMOVE,
+                                        "app", runtime,
+                                        NULL);
+       ret = gs_plugin_loader_job_action (plugin_loader, plugin_job, NULL, &error);
+       gs_test_flush_main_context ();
+       g_assert_no_error (error);
+       g_assert (ret);
+       g_assert_cmpint (gs_app_get_state (runtime), ==, AS_APP_STATE_AVAILABLE);
+
+       /* remove the remote */
+       app_source = gs_app_list_index (sources2, 0);
+       g_assert (app_source != NULL);
+       g_assert_cmpstr (gs_app_get_unique_id (app_source), ==, "user/*/*/source/test/*");
+       g_object_unref (plugin_job);
+       plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_REMOVE,
+                                        "app", app_source,
+                                        NULL);
+       ret = gs_plugin_loader_job_action (plugin_loader, plugin_job, NULL, &error);
+       gs_test_flush_main_context ();
+       g_assert_no_error (error);
+       g_assert (ret);
+       g_assert_cmpint (gs_app_get_state (app_source), ==, AS_APP_STATE_AVAILABLE);
+}
+
 static void
 gs_plugins_flatpak_ref_func (GsPluginLoader *plugin_loader)
 {
@@ -1234,6 +1407,9 @@ main (int argc, char **argv)
        g_test_add_data_func ("/gnome-software/plugins/flatpak/runtime-repo",
                              plugin_loader,
                              (GTestDataFunc) gs_plugins_flatpak_runtime_repo_func);
+       g_test_add_data_func ("/gnome-software/plugins/flatpak/runtime-repo-redundant",
+                             plugin_loader,
+                             (GTestDataFunc) gs_plugins_flatpak_runtime_repo_redundant_func);
        g_test_add_data_func ("/gnome-software/plugins/flatpak/app-update-runtime",
                              plugin_loader,
                              (GTestDataFunc) gs_plugins_flatpak_app_update_func);


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