[gnome-software] Add a new packagekit-refine-repos plugin for mapping repos to package IDs



commit ace99c1760bdafb553ff423d12b2fcec2b2881e9
Author: Kalev Lember <klember redhat com>
Date:   Tue Feb 27 12:50:34 2018 +0100

    Add a new packagekit-refine-repos plugin for mapping repos to package IDs
    
    We need a separate plugin so that we can order it to run after the
    "repos" plugin; regular packagekit-refine plugin is currently ordered to
    run before the repos plugin.
    
    The way it works is that first the repos plugin sets
    repos::repo-filename metadata key, and then in the next pass
    packagekit-refine-repos uses the key to figure out what packages these
    belong to.

 .../packagekit/gs-plugin-packagekit-refine-repos.c | 136 +++++++++++++++++++++
 plugins/packagekit/meson.build                     |  16 +++
 plugins/repos/gs-plugin-repos.c                    |  24 ++++
 3 files changed, 176 insertions(+)
---
diff --git a/plugins/packagekit/gs-plugin-packagekit-refine-repos.c 
b/plugins/packagekit/gs-plugin-packagekit-refine-repos.c
new file mode 100644
index 00000000..b8bf1115
--- /dev/null
+++ b/plugins/packagekit/gs-plugin-packagekit-refine-repos.c
@@ -0,0 +1,136 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2018 Kalev Lember <klember redhat com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <config.h>
+
+#include <packagekit-glib2/packagekit.h>
+#include <gnome-software.h>
+
+#include "packagekit-common.h"
+
+/*
+ * SECTION:
+ * Uses the system PackageKit instance to return convert repo filenames to
+ * package-ids.
+ *
+ * Requires:    | [repos::repo-filename]
+ * Refines:     | [source-id]
+ */
+
+struct GsPluginData {
+       PkClient        *client;
+};
+
+void
+gs_plugin_initialize (GsPlugin *plugin)
+{
+       GsPluginData *priv = gs_plugin_alloc_data (plugin, sizeof(GsPluginData));
+       priv->client = pk_client_new ();
+       pk_client_set_background (priv->client, FALSE);
+       pk_client_set_cache_age (priv->client, G_MAXUINT);
+
+       /* need repos::repo-filename */
+       gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_RUN_AFTER, "repos");
+}
+
+void
+gs_plugin_destroy (GsPlugin *plugin)
+{
+       GsPluginData *priv = gs_plugin_get_data (plugin);
+       g_object_unref (priv->client);
+}
+
+static gboolean
+gs_plugin_packagekit_refine_repo_from_filename (GsPlugin *plugin,
+                                                GsApp *app,
+                                                const gchar *filename,
+                                                GCancellable *cancellable,
+                                                GError **error)
+{
+       GsPluginData *priv = gs_plugin_get_data (plugin);
+       const gchar *to_array[] = { NULL, NULL };
+       ProgressData data = { 0 };
+       g_autoptr(PkResults) results = NULL;
+       g_autoptr(GPtrArray) packages = NULL;
+
+       data.app = app;
+       data.plugin = plugin;
+
+       to_array[0] = filename;
+       results = pk_client_search_files (priv->client,
+                                         pk_bitfield_from_enums (PK_FILTER_ENUM_INSTALLED, -1),
+                                         (gchar **) to_array,
+                                         cancellable,
+                                         gs_plugin_packagekit_progress_cb, &data,
+                                         error);
+       if (!gs_plugin_packagekit_results_valid (results, error)) {
+               g_prefix_error (error, "failed to search file %s: ", filename);
+               return FALSE;
+       }
+
+       /* get results */
+       packages = pk_results_get_package_array (results);
+       if (packages->len == 1) {
+               PkPackage *package = g_ptr_array_index (packages, 0);
+               gs_app_add_source (app, pk_package_get_name (package));
+               gs_app_add_source_id (app, pk_package_get_id (package));
+       } else {
+               g_debug ("failed to find one package for repo %s, %s, [%u]",
+                        gs_app_get_id (app), filename, packages->len);
+       }
+       return TRUE;
+}
+
+gboolean
+gs_plugin_refine (GsPlugin *plugin,
+                  GsAppList *list,
+                  GsPluginRefineFlags flags,
+                  GCancellable *cancellable,
+                  GError **error)
+{
+       g_autoptr(AsProfileTask) ptask = NULL;
+
+       ptask = as_profile_start_literal (gs_plugin_get_profile (plugin),
+                                         "packagekit-refine-repos[repo-filename->id]");
+       for (guint i = 0; i < gs_app_list_length (list); i++) {
+               GsApp *app = gs_app_list_index (list, i);
+               const gchar *fn;
+               if (gs_app_has_quirk (app, AS_APP_QUIRK_MATCH_ANY_PREFIX))
+                       continue;
+               if (gs_app_get_kind (app) != AS_APP_KIND_SOURCE)
+                       continue;
+               if (g_strcmp0 (gs_app_get_management_plugin (app), "packagekit") != 0)
+                       continue;
+               fn = gs_app_get_metadata_item (app, "repos::repo-filename");
+               if (fn == NULL)
+                       continue;
+               /* set the source package name for an installed .repo file */
+               if (!gs_plugin_packagekit_refine_repo_from_filename (plugin,
+                                                                    app,
+                                                                    fn,
+                                                                    cancellable,
+                                                                    error))
+                       return FALSE;
+       }
+
+       /* success */
+       return TRUE;
+}
diff --git a/plugins/packagekit/meson.build b/plugins/packagekit/meson.build
index b2cfc297..ac36d629 100644
--- a/plugins/packagekit/meson.build
+++ b/plugins/packagekit/meson.build
@@ -50,6 +50,22 @@ shared_module(
   dependencies : [ plugin_libs, packagekit ]
 )
 
+shared_module(
+  'gs_plugin_packagekit-refine-repos',
+  sources : [
+    'gs-plugin-packagekit-refine-repos.c',
+    'packagekit-common.c',
+  ],
+  include_directories : [
+    include_directories('../..'),
+    include_directories('../../lib'),
+  ],
+  install : true,
+  install_dir: plugin_dir,
+  c_args : cargs,
+  dependencies : [ plugin_libs, packagekit ]
+)
+
 shared_module(
   'gs_plugin_packagekit-refresh',
   sources : [
diff --git a/plugins/repos/gs-plugin-repos.c b/plugins/repos/gs-plugin-repos.c
index 5db2888c..135cecdf 100644
--- a/plugins/repos/gs-plugin-repos.c
+++ b/plugins/repos/gs-plugin-repos.c
@@ -25,6 +25,7 @@
 #include <gnome-software.h>
 
 struct GsPluginData {
+       GHashTable      *fns;           /* origin : filename */
        GHashTable      *urls;          /* origin : url */
        GFileMonitor    *monitor;
        GMutex           mutex;
@@ -51,6 +52,7 @@ gs_plugin_initialize (GsPlugin *plugin)
        }
 
        /* we also watch this for changes */
+       priv->fns = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
        priv->urls = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 
        /* need application IDs */
@@ -62,6 +64,8 @@ gs_plugin_destroy (GsPlugin *plugin)
 {
        GsPluginData *priv = gs_plugin_get_data (plugin);
        g_free (priv->reposdir);
+       if (priv->fns != NULL)
+               g_hash_table_unref (priv->fns);
        if (priv->urls != NULL)
                g_hash_table_unref (priv->urls);
        if (priv->monitor != NULL)
@@ -82,6 +86,7 @@ gs_plugin_repos_setup (GsPlugin *plugin, GCancellable *cancellable, GError **err
                return TRUE;
 
        /* clear existing */
+       g_hash_table_remove_all (priv->fns);
        g_hash_table_remove_all (priv->urls);
 
        /* search all files */
@@ -113,6 +118,11 @@ gs_plugin_repos_setup (GsPlugin *plugin, GCancellable *cancellable, GError **err
                groups = g_key_file_get_groups (kf, NULL);
                for (i = 0; groups[i] != NULL; i++) {
                        g_autofree gchar *tmp = NULL;
+
+                       g_hash_table_insert (priv->fns,
+                                            g_strdup (groups[i]),
+                                            g_strdup (filename));
+
                        tmp = g_key_file_get_string (kf, groups[i], "baseurl", NULL);
                        if (tmp != NULL) {
                                g_hash_table_insert (priv->urls,
@@ -120,6 +130,7 @@ gs_plugin_repos_setup (GsPlugin *plugin, GCancellable *cancellable, GError **err
                                                     g_strdup (tmp));
                                continue;
                        }
+
                        tmp = g_key_file_get_string (kf, groups[i], "metalink", NULL);
                        if (tmp != NULL) {
                                g_hash_table_insert (priv->urls,
@@ -205,5 +216,18 @@ gs_plugin_refine_app (GsPlugin *plugin,
                break;
        }
 
+       /* find filename */
+       switch (gs_app_get_kind (app)) {
+       case AS_APP_KIND_SOURCE:
+               if (gs_app_get_id (app) == NULL)
+                       return TRUE;
+               tmp = g_hash_table_lookup (priv->fns, gs_app_get_id (app));
+               if (tmp != NULL)
+                       gs_app_set_metadata (app, "repos::repo-filename", tmp);
+               break;
+       default:
+               break;
+       }
+
        return TRUE;
 }


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