[gnome-software] Add a plugin that uses librpm to get the package versions on an OSTree system



commit 5c20c0508109a39d4c5d9db1783dcee6826a1799
Author: Richard Hughes <richard hughsie com>
Date:   Fri Mar 25 16:47:17 2016 +0000

    Add a plugin that uses librpm to get the package versions on an OSTree system
    
    On OSTree we have no PackageKit available, so we have to skip a layer.

 configure.ac                              |   23 ++++
 contrib/gnome-software.spec.in            |    1 +
 src/plugins/Makefile.am                   |   12 ++
 src/plugins/gs-appstream.c                |    3 +
 src/plugins/gs-plugin-packagekit-refine.c |   12 ++
 src/plugins/gs-plugin-rpm.c               |  196 +++++++++++++++++++++++++++++
 6 files changed, 247 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 28f4e5f..24ad5b3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -223,6 +223,28 @@ AS_IF([test "x$have_limba" = "xyes"], [
 ])
 AM_CONDITIONAL(HAVE_LIMBA, test x$enable_limba = xyes)
 
+# RPM
+AC_ARG_ENABLE(rpm,
+              [AS_HELP_STRING([--enable-rpm],
+                              [enable RPM support [default=auto]])],,
+              enable_rpm=maybe)
+AS_IF([test "x$enable_rpm" != "xno"], [
+    PKG_CHECK_MODULES(RPM,
+                      rpm,
+                      [have_rpm=yes],
+                      [have_rpm=no])
+], [
+    have_rpm=no
+])
+AS_IF([test "x$have_rpm" = "xyes"], [
+    AC_DEFINE(HAVE_RPM, 1, [Build RPM support])
+], [
+    AS_IF([test "x$enable_rpm" = "xyes"], [
+          AC_MSG_ERROR([RPM support requested but 'rpm' was not found])
+    ])
+])
+AM_CONDITIONAL(HAVE_RPM, test x$have_rpm = xyes)
+
 # Steam
 AC_ARG_ENABLE(steam,
               [AS_HELP_STRING([--enable-steam],
@@ -308,6 +330,7 @@ echo "
         Limba support:             ${have_limba}
         XDG-APP support:           ${have_xdg_app}
         OSTree support:            ${have_ostree}
+        RPM support:               ${have_rpm}
         Steam support:             ${enable_steam}
         GNOME Shell ext. support:  ${enable_shell_extensions}
         ODRS support:              ${enable_odrs}
diff --git a/contrib/gnome-software.spec.in b/contrib/gnome-software.spec.in
index 8b7e866..03e98b1 100644
--- a/contrib/gnome-software.spec.in
+++ b/contrib/gnome-software.spec.in
@@ -32,6 +32,7 @@ BuildRequires: gsettings-desktop-schemas-devel
 BuildRequires: libappstream-glib-devel
 BuildRequires: fwupd-devel
 BuildRequires: json-glib-devel
+BuildRequires: rpm-devel
 
 # this is not a library version
 %define gs_plugin_version               9
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index d0ddf85..85a7f0d 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -14,6 +14,7 @@ AM_CPPFLAGS =                                         \
        $(LIMBA_CFLAGS)                                 \
        $(OSTREE_CFLAGS)                                \
        $(XDG_APP_CFLAGS)                               \
+       $(RPM_CFLAGS)                                   \
        -DBINDIR=\"$(bindir)\"                          \
        -DDATADIR=\"$(datadir)\"                        \
        -DGS_MODULESETDIR=\"$(datadir)/gnome-software/modulesets.d\" \
@@ -84,6 +85,10 @@ if HAVE_ODRS
 plugin_LTLIBRARIES += libgs_plugin_odrs.la
 endif
 
+if HAVE_RPM
+plugin_LTLIBRARIES += libgs_plugin_rpm.la
+endif
+
 libgs_plugin_dummy_la_SOURCES = gs-plugin-dummy.c
 libgs_plugin_dummy_la_LIBADD = $(GS_PLUGIN_LIBS)
 libgs_plugin_dummy_la_LDFLAGS = -module -avoid-version
@@ -162,6 +167,13 @@ libgs_plugin_odrs_la_LDFLAGS = -module -avoid-version
 libgs_plugin_odrs_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
 endif
 
+if HAVE_RPM
+libgs_plugin_rpm_la_SOURCES = gs-plugin-rpm.c
+libgs_plugin_rpm_la_LIBADD = $(GS_PLUGIN_LIBS) $(RPM_LIBS)
+libgs_plugin_rpm_la_LDFLAGS = -module -avoid-version
+libgs_plugin_rpm_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
+endif
+
 if HAVE_STEAM
 libgs_plugin_steam_la_SOURCES = gs-plugin-steam.c
 libgs_plugin_steam_la_LIBADD = $(GS_PLUGIN_LIBS)
diff --git a/src/plugins/gs-appstream.c b/src/plugins/gs-appstream.c
index d5ca7f0..a8f2f40 100644
--- a/src/plugins/gs-appstream.c
+++ b/src/plugins/gs-appstream.c
@@ -409,6 +409,9 @@ gs_appstream_refine_app (GsPlugin *plugin,
        if (as_app_get_id (item) != NULL && gs_app_get_id (app) == NULL)
                gs_app_set_id (app, as_app_get_id (item));
 
+       /* set source */
+       gs_app_set_metadata (app, "appstream::source-file", as_app_get_source_file (item));
+
        /* set name */
        tmp = as_app_get_name (item, NULL);
        if (tmp != NULL) {
diff --git a/src/plugins/gs-plugin-packagekit-refine.c b/src/plugins/gs-plugin-packagekit-refine.c
index 714c340..5f71b9f 100644
--- a/src/plugins/gs-plugin-packagekit-refine.c
+++ b/src/plugins/gs-plugin-packagekit-refine.c
@@ -56,6 +56,18 @@ gs_plugin_get_name (void)
 }
 
 /**
+ * gs_plugin_get_conflicts:
+ */
+const gchar **
+gs_plugin_get_conflicts (GsPlugin *plugin)
+{
+       static const gchar *deps[] = {
+               "rpm",
+               NULL };
+       return deps;
+}
+
+/**
  * gs_plugin_initialize:
  */
 static void
diff --git a/src/plugins/gs-plugin-rpm.c b/src/plugins/gs-plugin-rpm.c
new file mode 100644
index 0000000..602bdc2
--- /dev/null
+++ b/src/plugins/gs-plugin-rpm.c
@@ -0,0 +1,196 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 Richard Hughes <richard hughsie 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 <fcntl.h>
+#include <rpm/rpmdb.h>
+#include <rpm/rpmlib.h>
+#include <rpm/rpmts.h>
+
+#include <gs-plugin.h>
+
+struct GsPluginPrivate {
+       rpmts                    ts;
+       gboolean                 loaded;
+};
+
+/**
+ * gs_plugin_get_name:
+ */
+const gchar *
+gs_plugin_get_name (void)
+{
+       return "rpm";
+}
+
+/**
+ * gs_plugin_get_deps:
+ */
+const gchar **
+gs_plugin_get_deps (GsPlugin *plugin)
+{
+       static const gchar *deps[] = {
+               "appstream",    /* need application IDs */
+               NULL };
+       return deps;
+}
+
+/**
+ * gs_plugin_initialize:
+ */
+void
+gs_plugin_initialize (GsPlugin *plugin)
+{
+       plugin->priv = GS_PLUGIN_GET_PRIVATE (GsPluginPrivate);
+
+       /* only works with an rpmdb */
+       if (!g_file_test ("/var/lib/rpm/Packages", G_FILE_TEST_EXISTS)) {
+               gs_plugin_set_enabled (plugin, FALSE);
+               return;
+       }
+
+       /* open transaction */
+       rpmReadConfigFiles(NULL, NULL);
+       plugin->priv->ts = rpmtsCreate();
+}
+
+/**
+ * gs_plugin_destroy:
+ */
+void
+gs_plugin_destroy (GsPlugin *plugin)
+{
+       if (plugin->priv->ts != NULL) {
+               rpmtsCloseDB (plugin->priv->ts);
+               rpmtsFree (plugin->priv->ts);
+       }
+}
+
+/**
+ * gs_plugin_startup:
+ */
+static gboolean
+gs_plugin_startup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
+{
+       gint rc;
+
+       /* already started */
+       if (plugin->priv->loaded)
+               return TRUE;
+
+       /* open db readonly */
+       rpmtsSetRootDir (plugin->priv->ts, NULL);
+       rc = rpmtsOpenDB (plugin->priv->ts, O_RDONLY);
+       if (rc != 0) {
+               g_set_error (error,
+                            GS_PLUGIN_ERROR,
+                            GS_PLUGIN_ERROR_FAILED,
+                            "Failed to open rpmdb: %i", rc);
+               return FALSE;
+       }
+       plugin->priv->loaded = TRUE;
+       return TRUE;
+}
+
+/**
+ * gs_plugin_refine_app:
+ */
+gboolean
+gs_plugin_refine_app (GsPlugin *plugin,
+                     GsApp *app,
+                     GsPluginRefineFlags flags,
+                     GCancellable *cancellable,
+                     GError **error)
+{
+       Header h;
+       const gchar *fn;
+       rpmdbMatchIterator mi;
+
+       /* required */
+       if ((flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION) == 0 &&
+           (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SETUP_ACTION) == 0)
+               return TRUE;
+
+       /* ensure database open */
+       if (!gs_plugin_startup (plugin, cancellable, error))
+               return FALSE;
+
+       /* no need to run the plugin */
+       if (gs_app_get_source_default (app) != NULL &&
+           gs_app_get_source_id_default (app) != NULL)
+               return TRUE;
+
+       /* look for a specific file */
+       fn = gs_app_get_metadata_item (app, "appstream::source-file");
+       if (fn == NULL)
+               return TRUE;
+       if (!g_str_has_prefix (fn, "/usr"))
+               return TRUE;
+       mi = rpmtsInitIterator(plugin->priv->ts, RPMDBI_INSTFILENAMES, fn, 0);
+       if (mi == NULL) {
+               g_debug ("rpm: no search results for %s", fn);
+               return TRUE;
+       }
+
+       /* process any results */
+       g_debug ("rpm: querying with %s", fn);
+       while ((h = rpmdbNextIterator(mi)) != NULL) {
+               guint64 epoch;
+               const gchar *name;
+               const gchar *version;
+               const gchar *arch;
+               const gchar *release;
+               g_autofree gchar *tmp = NULL;
+
+               /* add default source */
+               name = headerGetString (h, RPMTAG_NAME);
+               if (gs_app_get_source_default (app) == NULL) {
+                       g_debug ("rpm: setting source to %s", name);
+                       gs_app_add_source (app, name);
+               }
+
+               /* add version */
+               version = headerGetString (h, RPMTAG_VERSION);
+               if (gs_app_get_version (app) == NULL) {
+                       g_debug ("rpm: setting version to %s", version);
+                       gs_app_set_version (app, version);
+               }
+
+               /* add source-id */
+               if (gs_app_get_source_id_default (app) == NULL) {
+                       release = headerGetString (h, RPMTAG_RELEASE);
+                       arch = headerGetString (h, RPMTAG_ARCH);
+                       epoch = headerGetNumber (h, RPMTAG_EPOCH);
+                       if (epoch > 0) {
+                               tmp = g_strdup_printf ("%s;%" G_GUINT64_FORMAT ":%s-%s;%s;installed",
+                                                      name, epoch, version, release, arch);
+                       } else {
+                               tmp = g_strdup_printf ("%s;%s-%s;%s;installed",
+                                                      name, version, release, arch);
+                       }
+                       g_debug ("rpm: setting source-id to %s", tmp);
+                       gs_app_add_source_id (app, tmp);
+               }
+       }
+       rpmdbFreeIterator (mi);
+       return TRUE;
+}


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