[gnome-software] Add an AppStream plugin
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Add an AppStream plugin
- Date: Sun, 1 Sep 2013 15:37:24 +0000 (UTC)
commit c6cefe6a510d36458792f4d1c4813ed828294e2f
Author: Richard Hughes <richard hughsie com>
Date: Sun Sep 1 16:35:33 2013 +0100
Add an AppStream plugin
This allows offline applications to be shown in the software center.
src/gs-application.c | 3 +-
src/plugins/Makefile.am | 6 +
src/plugins/README.md | 9 +
src/plugins/gs-plugin-appstream.c | 729 +++++++++++++++++++++++++++++++++++++
4 files changed, 746 insertions(+), 1 deletions(-)
---
diff --git a/src/gs-application.c b/src/gs-application.c
index 6817610..7a42056 100644
--- a/src/gs-application.c
+++ b/src/gs-application.c
@@ -158,7 +158,8 @@ gs_application_startup (GApplication *application)
gs_plugin_loader_set_enabled (app->plugin_loader, "hardcoded-menu-spec", TRUE);
gs_plugin_loader_set_enabled (app->plugin_loader, "local-ratings", TRUE);
gs_plugin_loader_set_enabled (app->plugin_loader, "packagekit", TRUE);
- gs_plugin_loader_set_enabled (app->plugin_loader, "packagekit-refine", TRUE);
+// gs_plugin_loader_set_enabled (app->plugin_loader, "packagekit-refine", TRUE);
+ gs_plugin_loader_set_enabled (app->plugin_loader, "appstream", TRUE);
gs_plugin_loader_set_enabled (app->plugin_loader, "desktopdb", TRUE);
gs_plugin_loader_set_enabled (app->plugin_loader, "datadir-apps", TRUE);
gs_plugin_loader_set_enabled (app->plugin_loader, "datadir-filename", TRUE);
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 47da7a5..348d081 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -26,6 +26,7 @@ dist_resources_DATA = \
plugindir = $(libdir)/gs-plugins
plugin_LTLIBRARIES = \
+ libgs_plugin_appstream.la \
libgs_plugin_datadir_apps.la \
libgs_plugin_datadir_filename.la \
libgs_plugin_desktopdb.la \
@@ -46,6 +47,11 @@ libgs_plugin_dummy_la_LIBADD = $(GS_PLUGIN_LIBS)
libgs_plugin_dummy_la_LDFLAGS = -module -avoid-version
libgs_plugin_dummy_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARNINGFLAGS_C)
+libgs_plugin_appstream_la_SOURCES = gs-plugin-appstream.c
+libgs_plugin_appstream_la_LIBADD = $(GS_PLUGIN_LIBS)
+libgs_plugin_appstream_la_LDFLAGS = -module -avoid-version
+libgs_plugin_appstream_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARNINGFLAGS_C)
+
libgs_plugin_hardcoded_kind_la_SOURCES = gs-plugin-hardcoded-kind.c
libgs_plugin_hardcoded_kind_la_LIBADD = $(GS_PLUGIN_LIBS)
libgs_plugin_hardcoded_kind_la_LDFLAGS = -module -avoid-version
diff --git a/src/plugins/README.md b/src/plugins/README.md
index 8b80a20..ddcc1c8 100644
--- a/src/plugins/README.md
+++ b/src/plugins/README.md
@@ -128,6 +128,15 @@ Methods: | `nothing`
Requires: | `nothing`
Refines: | `{package-name}->{datadir-desktop-filename}`
+### appstream ###
+Uses offline AppStream data to refine package results.
+
+Overview: | <p>
+-------------|---
+Methods: | `AddCategoryApps`
+Requires: | `nothing`
+Refines: | `{package-name}->[name,summary,pixbuf,id,kind]`
+
### datadir-apps ###
Uses the files in /usr/share/applications to provide icons and, translations for
installed applications.
diff --git a/src/plugins/gs-plugin-appstream.c b/src/plugins/gs-plugin-appstream.c
new file mode 100644
index 0000000..95cf783
--- /dev/null
+++ b/src/plugins/gs-plugin-appstream.c
@@ -0,0 +1,729 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 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 <gs-plugin.h>
+
+typedef enum {
+ GS_APPSTREAM_XML_SECTION_UNKNOWN,
+ GS_APPSTREAM_XML_SECTION_APPLICATIONS,
+ GS_APPSTREAM_XML_SECTION_APPLICATION,
+ GS_APPSTREAM_XML_SECTION_ID,
+ GS_APPSTREAM_XML_SECTION_PKGNAME,
+ GS_APPSTREAM_XML_SECTION_NAME,
+ GS_APPSTREAM_XML_SECTION_SUMMARY,
+ GS_APPSTREAM_XML_SECTION_ICON,
+ GS_APPSTREAM_XML_SECTION_APPCATEGORIES,
+ GS_APPSTREAM_XML_SECTION_APPCATEGORY,
+ GS_APPSTREAM_XML_SECTION_LAST
+} GsAppstreamXmlSection;
+
+typedef struct {
+ gchar *id;
+ gchar *pkgname;
+ gchar *name;
+ gchar *summary;
+ gchar *icon;
+} GsAppstreamItem;
+
+struct GsPluginPrivate {
+ GMutex mutex;
+ gchar *cachedir;
+ GsAppstreamXmlSection section;
+ GsAppstreamItem *item_temp;
+ GPtrArray *array; /* of GsAppstreamItem */
+ GHashTable *hash_id; /* of GsAppstreamItem{id} */
+ GHashTable *hash_pkgname; /* of GsAppstreamItem{pkgname} */
+ gboolean done_init;
+};
+
+/**
+ * gs_appstream_item_free:
+ */
+static void
+gs_appstream_item_free (gpointer data)
+{
+ GsAppstreamItem *item = (GsAppstreamItem *) data;
+ g_free (item->id);
+ g_free (item->pkgname);
+ g_free (item->name);
+ g_free (item->summary);
+ g_free (item->icon);
+ g_free (item);
+}
+
+/**
+ * gs_plugin_get_name:
+ */
+const gchar *
+gs_plugin_get_name (void)
+{
+ return "appstream";
+}
+
+/**
+ * gs_plugin_decompress_icons:
+ */
+static gboolean
+gs_plugin_decompress_icons (GsPlugin *plugin, GError **error)
+{
+ const gchar *argv[6];
+ gboolean ret = TRUE;
+ gint exit_status = 0;
+
+ /* cache already exists [FIXME: How to test for new enough...] */
+ if (g_file_test (plugin->priv->cachedir, G_FILE_TEST_EXISTS))
+ goto out;
+
+ /* create directory */
+ exit_status = g_mkdir_with_parents (plugin->priv->cachedir, 0700);
+ if (exit_status != 0) {
+ ret = FALSE;
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "Failed to create %s",
+ plugin->priv->cachedir);
+ goto out;
+ }
+
+ /* decompress */
+ argv[0] = "tar";
+ argv[1] = "-zxvf";
+ argv[2] = DATADIR "/gnome-software/appstream-icons.tar.gz";
+ argv[3] = "-C";
+ argv[4] = plugin->priv->cachedir;
+ argv[5] = NULL;
+ g_debug ("Decompressing %s to %s", argv[2], plugin->priv->cachedir);
+ ret = g_spawn_sync (NULL,
+ (gchar **) argv,
+ NULL,
+ G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL,
+ NULL, NULL,
+ NULL,
+ NULL,
+ &exit_status,
+ error);
+ if (!ret)
+ goto out;
+ if (exit_status != 0) {
+ ret = FALSE;
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "Failed to extract icon data to %s [%i]",
+ plugin->priv->cachedir, exit_status);
+ goto out;
+ }
+out:
+ return ret;
+}
+
+/**
+ * gs_plugin_decompress_xml:
+ */
+static gboolean
+gs_plugin_decompress_xml (GsPlugin *plugin, GError **error)
+{
+ const gchar *argv[6];
+ const gchar *tmpdir = "/tmp";
+ gboolean ret = TRUE;
+ gint exit_status = 0;
+ gchar *data = NULL;
+ gsize len;
+
+ /* already exists */
+ if (g_file_test ("/tmp/appstream.xml.gz", G_FILE_TEST_EXISTS))
+ goto out;
+
+ /* copy to /tmp */
+ ret = g_file_get_contents (DATADIR "/gnome-software/appstream.xml.gz",
+ &data,
+ &len,
+ error);
+ if (!ret)
+ goto out;
+ ret = g_file_set_contents ("/tmp/appstream.xml.gz",
+ data,
+ len,
+ error);
+ if (!ret)
+ goto out;
+
+ /* decompress */
+ argv[0] = "gunzip";
+ argv[1] = "/tmp/appstream.xml.gz";
+ argv[2] = NULL;
+ g_debug ("Decompressing %s to %s", argv[2], tmpdir);
+ ret = g_spawn_sync (tmpdir,
+ (gchar **) argv,
+ NULL,
+ G_SPAWN_SEARCH_PATH,
+ NULL, NULL,
+ NULL,
+ NULL,
+ &exit_status,
+ error);
+ if (!ret)
+ goto out;
+ if (exit_status != 0) {
+ ret = FALSE;
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "Failed to unzip XML data to %s [%i]",
+ tmpdir, exit_status);
+ goto out;
+ }
+out:
+ g_free (data);
+ return ret;
+}
+
+/**
+ * gs_appstream_selection_from_text:
+ */
+static GsAppstreamXmlSection
+gs_appstream_selection_from_text (const gchar *element_name)
+{
+ if (g_strcmp0 (element_name, "applications") == 0)
+ return GS_APPSTREAM_XML_SECTION_APPLICATIONS;
+ if (g_strcmp0 (element_name, "application") == 0)
+ return GS_APPSTREAM_XML_SECTION_APPLICATION;
+ if (g_strcmp0 (element_name, "id") == 0)
+ return GS_APPSTREAM_XML_SECTION_ID;
+ if (g_strcmp0 (element_name, "pkgname") == 0)
+ return GS_APPSTREAM_XML_SECTION_PKGNAME;
+ if (g_strcmp0 (element_name, "name") == 0)
+ return GS_APPSTREAM_XML_SECTION_NAME;
+ if (g_strcmp0 (element_name, "summary") == 0)
+ return GS_APPSTREAM_XML_SECTION_SUMMARY;
+ if (g_strcmp0 (element_name, "icon") == 0)
+ return GS_APPSTREAM_XML_SECTION_ICON;
+ if (g_strcmp0 (element_name, "appcategories") == 0)
+ return GS_APPSTREAM_XML_SECTION_APPCATEGORIES;
+ if (g_strcmp0 (element_name, "appcategory") == 0)
+ return GS_APPSTREAM_XML_SECTION_APPCATEGORY;
+ return GS_APPSTREAM_XML_SECTION_UNKNOWN;
+}
+
+/**
+ * gs_appstream_selection_to_text:
+ */
+static const gchar *
+gs_appstream_selection_to_text (GsAppstreamXmlSection section)
+{
+ if (section == GS_APPSTREAM_XML_SECTION_APPLICATIONS)
+ return "applications";
+ if (section == GS_APPSTREAM_XML_SECTION_APPLICATION)
+ return "application";
+ if (section == GS_APPSTREAM_XML_SECTION_ID)
+ return "id";
+ if (section == GS_APPSTREAM_XML_SECTION_PKGNAME)
+ return "pkgname";
+ if (section == GS_APPSTREAM_XML_SECTION_NAME)
+ return "name";
+ if (section == GS_APPSTREAM_XML_SECTION_SUMMARY)
+ return "summary";
+ if (section == GS_APPSTREAM_XML_SECTION_ICON)
+ return "icon";
+ if (section == GS_APPSTREAM_XML_SECTION_APPCATEGORIES)
+ return "appcategories";
+ if (section == GS_APPSTREAM_XML_SECTION_APPCATEGORY)
+ return "appcategory";
+ return NULL;
+}
+
+/**
+ * gs_appstream_start_element_cb:
+ */
+static void
+gs_appstream_start_element_cb (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error)
+{
+ GsPlugin *plugin = (GsPlugin *) user_data;
+ GsAppstreamXmlSection section_new;
+
+ /* process tag start */
+ section_new = gs_appstream_selection_from_text (element_name);
+ switch (section_new) {
+ case GS_APPSTREAM_XML_SECTION_APPLICATIONS:
+ case GS_APPSTREAM_XML_SECTION_APPCATEGORIES:
+ case GS_APPSTREAM_XML_SECTION_APPCATEGORY:
+ /* ignore */
+ break;
+ case GS_APPSTREAM_XML_SECTION_APPLICATION:
+ if (plugin->priv->item_temp != NULL ||
+ plugin->priv->section != GS_APPSTREAM_XML_SECTION_APPLICATIONS) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "XML start %s invalid, section %s",
+ element_name,
+ gs_appstream_selection_to_text (plugin->priv->section));
+ return;
+ }
+ plugin->priv->item_temp = g_new0 (GsAppstreamItem, 1);
+ break;
+ case GS_APPSTREAM_XML_SECTION_ID:
+ case GS_APPSTREAM_XML_SECTION_PKGNAME:
+ case GS_APPSTREAM_XML_SECTION_NAME:
+ case GS_APPSTREAM_XML_SECTION_SUMMARY:
+ case GS_APPSTREAM_XML_SECTION_ICON:
+ if (plugin->priv->item_temp == NULL ||
+ plugin->priv->section != GS_APPSTREAM_XML_SECTION_APPLICATION) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "XML start %s invalid, section %s",
+ element_name,
+ gs_appstream_selection_to_text (plugin->priv->section));
+ return;
+ }
+ break;
+ default:
+ /* ignore unknown entries */
+ break;
+ }
+
+ /* save */
+ plugin->priv->section = section_new;
+}
+
+/**
+ * gs_appstream_end_element_cb:
+ */
+static void
+gs_appstream_end_element_cb (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ GsPlugin *plugin = (GsPlugin *) user_data;
+ GsAppstreamXmlSection section_new;
+
+ section_new = gs_appstream_selection_from_text (element_name);
+ switch (section_new) {
+ case GS_APPSTREAM_XML_SECTION_APPLICATIONS:
+ case GS_APPSTREAM_XML_SECTION_APPCATEGORIES:
+ case GS_APPSTREAM_XML_SECTION_APPCATEGORY:
+ /* ignore */
+ break;
+ case GS_APPSTREAM_XML_SECTION_APPLICATION:
+ /* save */
+ g_ptr_array_add (plugin->priv->array, plugin->priv->item_temp);
+ g_hash_table_insert (plugin->priv->hash_id,
+ (gpointer) plugin->priv->item_temp->id,
+ plugin->priv->item_temp);
+ g_hash_table_insert (plugin->priv->hash_pkgname,
+ (gpointer) plugin->priv->item_temp->pkgname,
+ plugin->priv->item_temp);
+ plugin->priv->item_temp = NULL;
+ plugin->priv->section = GS_APPSTREAM_XML_SECTION_APPLICATIONS;
+ break;
+ case GS_APPSTREAM_XML_SECTION_ID:
+ case GS_APPSTREAM_XML_SECTION_PKGNAME:
+ case GS_APPSTREAM_XML_SECTION_NAME:
+ case GS_APPSTREAM_XML_SECTION_ICON:
+ case GS_APPSTREAM_XML_SECTION_SUMMARY:
+ plugin->priv->section = GS_APPSTREAM_XML_SECTION_APPLICATION;
+ break;
+ default:
+ /* ignore unknown entries */
+ break;
+ }
+}
+
+/**
+ * gs_appstream_text_cb:
+ */
+static void
+gs_appstream_text_cb (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ GsPlugin *plugin = (GsPlugin *) user_data;
+
+ switch (plugin->priv->section) {
+ case GS_APPSTREAM_XML_SECTION_UNKNOWN:
+ case GS_APPSTREAM_XML_SECTION_APPLICATIONS:
+ case GS_APPSTREAM_XML_SECTION_APPLICATION:
+ case GS_APPSTREAM_XML_SECTION_APPCATEGORIES:
+ case GS_APPSTREAM_XML_SECTION_APPCATEGORY:
+ /* ignore */
+ break;
+ case GS_APPSTREAM_XML_SECTION_ID:
+ if (plugin->priv->item_temp == NULL ||
+ plugin->priv->item_temp->id != NULL) {
+ g_set_error_literal (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "item_temp id invalid");
+ return;
+ }
+ if (text_len < 9) {
+ g_set_error_literal (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "desktop id invalid");
+ return;
+ }
+ plugin->priv->item_temp->id = g_strndup (text, text_len - 8);
+ break;
+ case GS_APPSTREAM_XML_SECTION_PKGNAME:
+ if (plugin->priv->item_temp == NULL ||
+ plugin->priv->item_temp->pkgname != NULL) {
+ g_set_error_literal (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "item_temp pkgname invalid");
+ return;
+ }
+ plugin->priv->item_temp->pkgname = g_strndup (text, text_len);
+ break;
+ case GS_APPSTREAM_XML_SECTION_NAME:
+ if (plugin->priv->item_temp == NULL ||
+ plugin->priv->item_temp->name != NULL) {
+ g_set_error_literal (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "item_temp name invalid");
+ return;
+ }
+ plugin->priv->item_temp->name = g_strndup (text, text_len);
+ break;
+ case GS_APPSTREAM_XML_SECTION_SUMMARY:
+ if (plugin->priv->item_temp == NULL ||
+ plugin->priv->item_temp->summary != NULL) {
+ g_set_error_literal (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "item_temp summary invalid");
+ return;
+ }
+ plugin->priv->item_temp->summary = g_strndup (text, text_len);
+ break;
+ case GS_APPSTREAM_XML_SECTION_ICON:
+ if (plugin->priv->item_temp == NULL ||
+ plugin->priv->item_temp->icon != NULL) {
+ g_set_error_literal (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "item_temp icon invalid");
+ return;
+ }
+ plugin->priv->item_temp->icon = g_strndup (text, text_len);
+ break;
+ default:
+ /* ignore unknown entries */
+ break;
+ }
+}
+
+/**
+ * gs_plugin_parse_xml:
+ */
+static gboolean
+gs_plugin_parse_xml (GsPlugin *plugin, GError **error)
+{
+ gboolean ret;
+ GMarkupParseContext *ctx;
+ gchar *data;
+ gsize len;
+ const GMarkupParser parser = {
+ gs_appstream_start_element_cb,
+ gs_appstream_end_element_cb,
+ gs_appstream_text_cb,
+ NULL /* passthrough */,
+ NULL /* error */ };
+ ctx = g_markup_parse_context_new (&parser,
+ G_MARKUP_PREFIX_ERROR_POSITION,
+ plugin,
+ NULL);
+ ret = g_file_get_contents ("/tmp/appstream.xml", &data, &len, error);
+ if (!ret)
+ goto out;
+ ret = g_markup_parse_context_parse (ctx, data, len, error);
+ if (!ret)
+ goto out;
+out:
+ g_markup_parse_context_free (ctx);
+ g_free (data);
+ return ret;
+}
+
+/**
+ * gs_plugin_initialize:
+ */
+void
+gs_plugin_initialize (GsPlugin *plugin)
+{
+ /* create private area */
+ plugin->priv = GS_PLUGIN_GET_PRIVATE (GsPluginPrivate);
+ plugin->priv->array = g_ptr_array_new_with_free_func (gs_appstream_item_free);
+ plugin->priv->hash_id = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ NULL,
+ NULL);
+ plugin->priv->hash_pkgname = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ NULL,
+ NULL);
+
+ /* this is per-user */
+ plugin->priv->cachedir = g_build_filename (g_get_user_cache_dir(),
+ "gnome-software",
+ NULL);
+
+ /* can only load from one thread */
+ g_mutex_init (&plugin->priv->mutex);
+}
+
+/**
+ * gs_plugin_get_priority:
+ */
+gdouble
+gs_plugin_get_priority (GsPlugin *plugin)
+{
+ return 1.0f;
+}
+
+/**
+ * gs_plugin_destroy:
+ */
+void
+gs_plugin_destroy (GsPlugin *plugin)
+{
+ g_free (plugin->priv->cachedir);
+ g_ptr_array_unref (plugin->priv->array);
+ g_hash_table_unref (plugin->priv->hash_id);
+ g_hash_table_unref (plugin->priv->hash_pkgname);
+ g_mutex_clear (&plugin->priv->mutex);
+}
+
+
+/**
+ * gs_plugin_startup:
+ */
+static gboolean
+gs_plugin_startup (GsPlugin *plugin, GError **error)
+{
+ gboolean ret = TRUE;
+ GTimer *timer = NULL;
+
+ /* protect */
+ g_mutex_lock (&plugin->priv->mutex);
+
+ /* already done */
+ if (plugin->priv->done_init)
+ goto out;
+
+ /* get the icons ready for use */
+ timer = g_timer_new ();
+ ret = gs_plugin_decompress_icons (plugin, error);
+ if (!ret)
+ goto out;
+ g_debug ("Decompressing icons\t:%.1fms", g_timer_elapsed (timer, NULL) * 1000);
+
+ /* Decompress the XML ready for use */
+ g_timer_reset (timer);
+ ret = gs_plugin_decompress_xml (plugin, error);
+ if (!ret)
+ goto out;
+ g_debug ("Decompressing XML\t:%.1fms",
+ g_timer_elapsed (timer, NULL) * 1000);
+
+ /* Parse the XML */
+ g_timer_reset (timer);
+ ret = gs_plugin_parse_xml (plugin, error);
+ if (!ret)
+ goto out;
+ g_debug ("Parsed %i entries of XML\t:%.1fms",
+ plugin->priv->array->len,
+ g_timer_elapsed (timer, NULL) * 1000);
+
+ /* done */
+ plugin->priv->done_init = TRUE;
+out:
+ if (timer != NULL)
+ g_timer_destroy (timer);
+ g_mutex_unlock (&plugin->priv->mutex);
+ return ret;
+}
+
+/**
+ * gs_plugin_refine_item:
+ */
+static gboolean
+gs_plugin_refine_item (GsPlugin *plugin,
+ GsApp *app,
+ GsAppstreamItem *item,
+ GError **error)
+{
+ gboolean ret = TRUE;
+ gchar *icon_path = NULL;
+ GdkPixbuf *pixbuf = NULL;
+
+ g_debug ("AppStream: Refining %s", gs_app_get_id (app));
+
+ /* is an app */
+ if (gs_app_get_kind (app) == GS_APP_KIND_UNKNOWN ||
+ gs_app_get_kind (app) == GS_APP_KIND_PACKAGE)
+ gs_app_set_kind (app, GS_APP_KIND_NORMAL);
+
+ /* set id */
+ if (item->id != NULL && gs_app_get_id (app) == NULL)
+ gs_app_set_id (app, item->id);
+
+ /* set name */
+ if (item->name != NULL && gs_app_get_name (app) == NULL)
+ gs_app_set_name (app, item->name);
+
+ /* set summary */
+ if (item->summary != NULL && gs_app_get_summary (app) == NULL)
+ gs_app_set_summary (app, item->summary);
+
+ /* set icon */
+ if (item->icon != NULL && gs_app_get_pixbuf (app) == NULL) {
+ icon_path = g_strdup_printf ("%s/%s.png",
+ plugin->priv->cachedir,
+ item->icon);
+ pixbuf = gdk_pixbuf_new_from_file_at_size (icon_path,
+ plugin->pixbuf_size,
+ plugin->pixbuf_size,
+ error);
+ if (pixbuf == NULL) {
+ ret = FALSE;
+ goto out;
+ }
+ gs_app_set_pixbuf (app, pixbuf);
+ }
+
+ /* set package name */
+ if (item->pkgname != NULL && gs_app_get_metadata_item (app, "package-name") == NULL)
+ gs_app_set_metadata (app, "package-name", item->pkgname);
+out:
+ g_free (icon_path);
+ if (pixbuf != NULL)
+ g_object_unref (pixbuf);
+ return ret;
+}
+
+/**
+ * gs_plugin_refine_from_id:
+ */
+static gboolean
+gs_plugin_refine_from_id (GsPlugin *plugin,
+ GsApp *app,
+ GError **error)
+{
+ const gchar *id;
+ gboolean ret = TRUE;
+ GsAppstreamItem *item;
+
+ /* find anything that matches the ID */
+ id = gs_app_get_id (app);
+ if (id == NULL)
+ goto out;
+ item = g_hash_table_lookup (plugin->priv->hash_id, id);
+ if (item == NULL) {
+ g_debug ("no AppStream match for [id] %s", id);
+ goto out;
+ }
+
+ /* set new properties */
+ ret = gs_plugin_refine_item (plugin, app, item, error);
+ if (!ret)
+ goto out;
+out:
+ return ret;
+}
+
+/**
+ * gs_plugin_refine_from_pkgname:
+ */
+static gboolean
+gs_plugin_refine_from_pkgname (GsPlugin *plugin,
+ GsApp *app,
+ GError **error)
+{
+ const gchar *pkgname;
+ gboolean ret = TRUE;
+ GsAppstreamItem *item;
+
+ /* find anything that matches the ID */
+ pkgname = gs_app_get_metadata_item (app, "package-name");
+ if (pkgname == NULL)
+ goto out;
+ item = g_hash_table_lookup (plugin->priv->hash_pkgname, pkgname);
+ if (item == NULL) {
+ g_debug ("no AppStream match for {pkgname} %s", pkgname);
+ goto out;
+ }
+
+ /* set new properties */
+ ret = gs_plugin_refine_item (plugin, app, item, error);
+ if (!ret)
+ goto out;
+out:
+ return ret;
+}
+
+/**
+ * gs_plugin_refine:
+ */
+gboolean
+gs_plugin_refine (GsPlugin *plugin,
+ GList *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret;
+ GList *l;
+ GsApp *app;
+
+ /* load XML files */
+ ret = gs_plugin_startup (plugin, error);
+ if (!ret)
+ goto out;
+
+ for (l = list; l != NULL; l = l->next) {
+ app = GS_APP (l->data);
+ ret = gs_plugin_refine_from_id (plugin, app, error);
+ if (!ret)
+ goto out;
+ ret = gs_plugin_refine_from_pkgname (plugin, app, error);
+ if (!ret)
+ goto out;
+ }
+
+ /* sucess */
+ ret = TRUE;
+out:
+ return ret;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]