[gnome-software] trivial: Split out core plugins into a new directory
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] trivial: Split out core plugins into a new directory
- Date: Tue, 7 Mar 2017 17:05:35 +0000 (UTC)
commit abca4426be67a3de5562ace8b33af135a7ffa1f3
Author: Richard Hughes <richard hughsie com>
Date: Tue Mar 7 13:33:36 2017 +0000
trivial: Split out core plugins into a new directory
configure.ac | 2 +
plugins/Makefile.am | 89 +--
plugins/core/Makefile.am | 79 ++
plugins/core/gs-appstream.c | 1147 +++++++++++++++++++
plugins/core/gs-appstream.h | 71 ++
plugins/{ => core}/gs-desktop-common.c | 0
plugins/{ => core}/gs-desktop-common.h | 0
plugins/{ => core}/gs-plugin-appstream.c | 0
plugins/{ => core}/gs-plugin-desktop-categories.c | 0
plugins/{ => core}/gs-plugin-desktop-menu-path.c | 0
plugins/{ => core}/gs-plugin-generic-updates.c | 0
plugins/{ => core}/gs-plugin-hardcoded-blacklist.c | 0
plugins/{ => core}/gs-plugin-hardcoded-featured.c | 0
plugins/{ => core}/gs-plugin-hardcoded-popular.c | 0
plugins/{ => core}/gs-plugin-icons.c | 0
plugins/{ => core}/gs-plugin-key-colors.c | 0
plugins/{ => core}/gs-plugin-provenance-license.c | 0
plugins/{ => core}/gs-plugin-provenance.c | 0
plugins/dummy/Makefile.am | 23 +
plugins/{ => dummy}/gs-plugin-dummy.c | 0
plugins/dummy/gs-self-test.c | 715 ++++++++++++
plugins/gs-appstream.c | 1148 +-------------------
plugins/gs-appstream.h | 72 +--
plugins/gs-self-test.c | 533 +---------
po/POTFILES.in | 4 +-
25 files changed, 2048 insertions(+), 1835 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 832564b..8bc54ae 100644
--- a/configure.ac
+++ b/configure.ac
@@ -484,7 +484,9 @@ doc/api/Makefile
lib/Makefile
lib/gnome-software.pc
plugins/Makefile
+plugins/core/Makefile
plugins/dpkg/Makefile
+plugins/dummy/Makefile
plugins/external-appstream/Makefile
plugins/fwupd/Makefile
plugins/limba/Makefile
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index ea9f640..a8b7907 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -2,10 +2,11 @@
AUTOMAKE_OPTIONS = 1.7
# core
-SUBDIRS =
+SUBDIRS = core
# non-core, but no configure option required
SUBDIRS += dpkg
+SUBDIRS += dummy
SUBDIRS += ubuntuone
SUBDIRS += repos
@@ -52,24 +53,13 @@ AM_CPPFLAGS = \
-DLOCALSTATEDIR=\""$(localstatedir)"\" \
-DLOCALEDIR=\""$(localedir)"\" \
-DTESTDATADIR=\""$(top_srcdir)/data"\" \
- -DLOCALPLUGINDIR=\""$(top_builddir)/src/plugins/.libs"\"
+ -DLOCALPLUGINDIR=\""$(top_builddir)/plugins/.libs"\" \
+ -DLOCALPLUGINDIR_CORE=\""$(top_builddir)/plugins/core/.libs"\"
plugindir = $(GS_PLUGIN_DIR)
plugin_LTLIBRARIES = \
- libgs_plugin_appstream.la \
- libgs_plugin_key-colors.la \
- libgs_plugin_desktop-categories.la \
- libgs_plugin_desktop-menu-path.la \
- libgs_plugin_dummy.la \
- libgs_plugin_generic-updates.la \
- libgs_plugin_hardcoded-blacklist.la \
- libgs_plugin_hardcoded-popular.la \
- libgs_plugin_hardcoded-featured.la \
libgs_plugin_fedora-distro-upgrades.la \
- libgs_plugin_provenance.la \
- libgs_plugin_provenance-license.la \
- libgs_plugin_fedora-tagger-usage.la \
- libgs_plugin_icons.la
+ libgs_plugin_fedora-tagger-usage.la
appdata_in_files =
@@ -89,21 +79,6 @@ if HAVE_FLATPAK
plugin_LTLIBRARIES += libgs_plugin_flatpak.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
-libgs_plugin_dummy_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
-
-libgs_plugin_generic_updates_la_SOURCES = gs-plugin-generic-updates.c
-libgs_plugin_generic_updates_la_LIBADD = $(GS_PLUGIN_LIBS)
-libgs_plugin_generic_updates_la_LDFLAGS = -module -avoid-version
-libgs_plugin_generic_updates_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
-
-libgs_plugin_key_colors_la_SOURCES = gs-plugin-key-colors.c
-libgs_plugin_key_colors_la_LIBADD = $(GS_PLUGIN_LIBS)
-libgs_plugin_key_colors_la_LDFLAGS = -module -avoid-version
-libgs_plugin_key_colors_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
-
if HAVE_SHELL_EXTENSIONS
libgs_plugin_shell_extensions_la_SOURCES = gs-plugin-shell-extensions.c
libgs_plugin_shell_extensions_la_LIBADD = $(GS_PLUGIN_LIBS) $(JSON_GLIB_LIBS)
@@ -123,16 +98,6 @@ libgs_plugin_modalias_la_LDFLAGS = -module -avoid-version
libgs_plugin_modalias_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(GUDEV_CFLAGS)
endif
-libgs_plugin_provenance_la_SOURCES = gs-plugin-provenance.c
-libgs_plugin_provenance_la_LIBADD = $(GS_PLUGIN_LIBS)
-libgs_plugin_provenance_la_LDFLAGS = -module -avoid-version
-libgs_plugin_provenance_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
-
-libgs_plugin_provenance_license_la_SOURCES = gs-plugin-provenance-license.c
-libgs_plugin_provenance_license_la_LIBADD = $(GS_PLUGIN_LIBS)
-libgs_plugin_provenance_license_la_LDFLAGS = -module -avoid-version
-libgs_plugin_provenance_license_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
-
libgs_plugin_fedora_tagger_usage_la_SOURCES = gs-plugin-fedora-tagger-usage.c
libgs_plugin_fedora_tagger_usage_la_LIBADD = $(GS_PLUGIN_LIBS) $(SQLITE_LIBS)
libgs_plugin_fedora_tagger_usage_la_LDFLAGS = -module -avoid-version
@@ -144,19 +109,6 @@ libgs_plugin_epiphany_la_LIBADD = $(GS_PLUGIN_LIBS)
libgs_plugin_epiphany_la_LDFLAGS = -module -avoid-version
libgs_plugin_epiphany_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
-libgs_plugin_icons_la_SOURCES = gs-plugin-icons.c
-libgs_plugin_icons_la_LIBADD = $(GS_PLUGIN_LIBS)
-libgs_plugin_icons_la_LDFLAGS = -module -avoid-version
-libgs_plugin_icons_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
-
-libgs_plugin_appstream_la_SOURCES = \
- gs-appstream.c \
- gs-appstream.h \
- gs-plugin-appstream.c
-libgs_plugin_appstream_la_LIBADD = $(GS_PLUGIN_LIBS) $(APPSTREAM_LIBS)
-libgs_plugin_appstream_la_LDFLAGS = -module -avoid-version
-libgs_plugin_appstream_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
-
if HAVE_FLATPAK
appdata_in_files += org.gnome.Software.Plugin.Flatpak.metainfo.xml.in
libgs_plugin_flatpak_la_SOURCES = \
@@ -172,37 +124,6 @@ libgs_plugin_flatpak_la_LDFLAGS = -module -avoid-version
libgs_plugin_flatpak_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(FLATPAK_CFLAGS)
endif
-libgs_plugin_desktop_categories_la_SOURCES = \
- gs-plugin-desktop-categories.c \
- gs-desktop-common.c \
- gs-desktop-common.h
-libgs_plugin_desktop_categories_la_LIBADD = $(GS_PLUGIN_LIBS)
-libgs_plugin_desktop_categories_la_LDFLAGS = -module -avoid-version
-libgs_plugin_desktop_categories_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
-
-libgs_plugin_desktop_menu_path_la_SOURCES = \
- gs-plugin-desktop-menu-path.c \
- gs-desktop-common.c \
- gs-desktop-common.h
-libgs_plugin_desktop_menu_path_la_LIBADD = $(GS_PLUGIN_LIBS)
-libgs_plugin_desktop_menu_path_la_LDFLAGS = -module -avoid-version
-libgs_plugin_desktop_menu_path_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
-
-libgs_plugin_hardcoded_blacklist_la_SOURCES = gs-plugin-hardcoded-blacklist.c
-libgs_plugin_hardcoded_blacklist_la_LIBADD = $(GS_PLUGIN_LIBS)
-libgs_plugin_hardcoded_blacklist_la_LDFLAGS = -module -avoid-version
-libgs_plugin_hardcoded_blacklist_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
-
-libgs_plugin_hardcoded_popular_la_SOURCES = gs-plugin-hardcoded-popular.c
-libgs_plugin_hardcoded_popular_la_LIBADD = $(GS_PLUGIN_LIBS)
-libgs_plugin_hardcoded_popular_la_LDFLAGS = -module -avoid-version
-libgs_plugin_hardcoded_popular_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
-
-libgs_plugin_hardcoded_featured_la_SOURCES = gs-plugin-hardcoded-featured.c
-libgs_plugin_hardcoded_featured_la_LIBADD = $(GS_PLUGIN_LIBS)
-libgs_plugin_hardcoded_featured_la_LDFLAGS = -module -avoid-version
-libgs_plugin_hardcoded_featured_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
-
# MetaInfo files
%.metainfo.xml: %.metainfo.xml.in
$(AM_V_GEN) msgfmt --xml -d $(top_srcdir)/po --template $< -o $@
diff --git a/plugins/core/Makefile.am b/plugins/core/Makefile.am
new file mode 100644
index 0000000..d070e00
--- /dev/null
+++ b/plugins/core/Makefile.am
@@ -0,0 +1,79 @@
+plugindir = $(GS_PLUGIN_DIR)
+plugin_LTLIBRARIES = \
+ libgs_plugin_appstream.la \
+ libgs_plugin_key-colors.la \
+ libgs_plugin_desktop-categories.la \
+ libgs_plugin_desktop-menu-path.la \
+ libgs_plugin_generic-updates.la \
+ libgs_plugin_hardcoded-blacklist.la \
+ libgs_plugin_hardcoded-popular.la \
+ libgs_plugin_hardcoded-featured.la \
+ libgs_plugin_provenance.la \
+ libgs_plugin_provenance-license.la \
+ libgs_plugin_icons.la
+
+libgs_plugin_generic_updates_la_SOURCES = gs-plugin-generic-updates.c
+libgs_plugin_generic_updates_la_LIBADD = $(GS_PLUGIN_LIBS)
+libgs_plugin_generic_updates_la_LDFLAGS = -module -avoid-version
+libgs_plugin_generic_updates_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
+
+libgs_plugin_key_colors_la_SOURCES = gs-plugin-key-colors.c
+libgs_plugin_key_colors_la_LIBADD = $(GS_PLUGIN_LIBS)
+libgs_plugin_key_colors_la_LDFLAGS = -module -avoid-version
+libgs_plugin_key_colors_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
+
+libgs_plugin_provenance_la_SOURCES = gs-plugin-provenance.c
+libgs_plugin_provenance_la_LIBADD = $(GS_PLUGIN_LIBS)
+libgs_plugin_provenance_la_LDFLAGS = -module -avoid-version
+libgs_plugin_provenance_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
+
+libgs_plugin_provenance_license_la_SOURCES = gs-plugin-provenance-license.c
+libgs_plugin_provenance_license_la_LIBADD = $(GS_PLUGIN_LIBS)
+libgs_plugin_provenance_license_la_LDFLAGS = -module -avoid-version
+libgs_plugin_provenance_license_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
+
+libgs_plugin_icons_la_SOURCES = gs-plugin-icons.c
+libgs_plugin_icons_la_LIBADD = $(GS_PLUGIN_LIBS)
+libgs_plugin_icons_la_LDFLAGS = -module -avoid-version
+libgs_plugin_icons_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
+
+libgs_plugin_appstream_la_SOURCES = \
+ gs-appstream.c \
+ gs-appstream.h \
+ gs-plugin-appstream.c
+libgs_plugin_appstream_la_LIBADD = $(GS_PLUGIN_LIBS) $(APPSTREAM_LIBS)
+libgs_plugin_appstream_la_LDFLAGS = -module -avoid-version
+libgs_plugin_appstream_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
+
+libgs_plugin_desktop_categories_la_SOURCES = \
+ gs-plugin-desktop-categories.c \
+ gs-desktop-common.c \
+ gs-desktop-common.h
+libgs_plugin_desktop_categories_la_LIBADD = $(GS_PLUGIN_LIBS)
+libgs_plugin_desktop_categories_la_LDFLAGS = -module -avoid-version
+libgs_plugin_desktop_categories_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
+
+libgs_plugin_desktop_menu_path_la_SOURCES = \
+ gs-plugin-desktop-menu-path.c \
+ gs-desktop-common.c \
+ gs-desktop-common.h
+libgs_plugin_desktop_menu_path_la_LIBADD = $(GS_PLUGIN_LIBS)
+libgs_plugin_desktop_menu_path_la_LDFLAGS = -module -avoid-version
+libgs_plugin_desktop_menu_path_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
+
+libgs_plugin_hardcoded_blacklist_la_SOURCES = gs-plugin-hardcoded-blacklist.c
+libgs_plugin_hardcoded_blacklist_la_LIBADD = $(GS_PLUGIN_LIBS)
+libgs_plugin_hardcoded_blacklist_la_LDFLAGS = -module -avoid-version
+libgs_plugin_hardcoded_blacklist_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
+
+libgs_plugin_hardcoded_popular_la_SOURCES = gs-plugin-hardcoded-popular.c
+libgs_plugin_hardcoded_popular_la_LIBADD = $(GS_PLUGIN_LIBS)
+libgs_plugin_hardcoded_popular_la_LDFLAGS = -module -avoid-version
+libgs_plugin_hardcoded_popular_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
+
+libgs_plugin_hardcoded_featured_la_SOURCES = gs-plugin-hardcoded-featured.c
+libgs_plugin_hardcoded_featured_la_LIBADD = $(GS_PLUGIN_LIBS)
+libgs_plugin_hardcoded_featured_la_LDFLAGS = -module -avoid-version
+libgs_plugin_hardcoded_featured_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
+
+-include $(top_srcdir)/git.mk
diff --git a/plugins/core/gs-appstream.c b/plugins/core/gs-appstream.c
new file mode 100644
index 0000000..673f626
--- /dev/null
+++ b/plugins/core/gs-appstream.c
@@ -0,0 +1,1147 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2015-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 <gnome-software.h>
+
+#include "gs-appstream.h"
+
+#define GS_APPSTREAM_MAX_SCREENSHOTS 5
+
+GsApp *
+gs_appstream_create_app (GsPlugin *plugin, AsApp *item, GError **error)
+{
+ const gchar *unique_id = as_app_get_unique_id (item);
+ GsApp *app = gs_plugin_cache_lookup (plugin, unique_id);
+ if (app == NULL) {
+ app = gs_app_new (as_app_get_id (item));
+ gs_app_set_metadata (app, "GnomeSoftware::Creator",
+ gs_plugin_get_name (plugin));
+ if (!gs_appstream_refine_app (plugin, app, item, error)) {
+ g_object_unref (app);
+ return NULL;
+ }
+ gs_plugin_cache_add (plugin, unique_id, app);
+ }
+ return app;
+}
+
+static AsIcon *
+gs_appstream_get_icon_by_kind (AsApp *app, AsIconKind icon_kind)
+{
+ GPtrArray *icons;
+ guint i;
+
+ icons = as_app_get_icons (app);
+ for (i = 0; i < icons->len; i++) {
+ AsIcon *icon = g_ptr_array_index (icons, i);
+ if (as_icon_get_kind (icon) == icon_kind)
+ return icon;
+ }
+ return NULL;
+}
+
+static AsIcon *
+gs_appstream_get_icon_by_kind_and_size (AsApp *app, AsIconKind icon_kind, guint sz)
+{
+ GPtrArray *icons;
+ guint i;
+
+ icons = as_app_get_icons (app);
+ for (i = 0; i < icons->len; i++) {
+ AsIcon *icon = g_ptr_array_index (icons, i);
+ if (as_icon_get_kind (icon) == icon_kind &&
+ as_icon_get_width (icon) == sz &&
+ as_icon_get_height (icon) == sz)
+ return icon;
+ }
+ return NULL;
+}
+
+static void
+gs_refine_item_icon (GsPlugin *plugin, GsApp *app, AsApp *item)
+{
+ AsIcon *icon;
+
+ /* try a stock icon first */
+ icon = gs_appstream_get_icon_by_kind (item, AS_ICON_KIND_STOCK);
+ if (icon != NULL)
+ gs_app_add_icon (app, icon);
+
+ /* if HiDPI get a 128px cached icon */
+ if (gs_plugin_get_scale (plugin) == 2) {
+ icon = gs_appstream_get_icon_by_kind_and_size (item,
+ AS_ICON_KIND_CACHED,
+ 128);
+ if (icon != NULL)
+ gs_app_add_icon (app, icon);
+ }
+
+ /* non-HiDPI cached icon */
+ icon = gs_appstream_get_icon_by_kind_and_size (item,
+ AS_ICON_KIND_CACHED,
+ 64);
+ if (icon != NULL)
+ gs_app_add_icon (app, icon);
+
+ /* prefer local */
+ icon = gs_appstream_get_icon_by_kind (item, AS_ICON_KIND_LOCAL);
+ if (icon != NULL) {
+ /* does not exist, so try to find using the icon theme */
+ if (as_icon_get_kind (icon) == AS_ICON_KIND_LOCAL &&
+ as_icon_get_filename (icon) == NULL) {
+ g_debug ("converting missing LOCAL icon %s to STOCK",
+ as_icon_get_name (icon));
+ as_icon_set_kind (icon, AS_ICON_KIND_STOCK);
+ }
+ gs_app_add_icon (app, icon);
+ }
+
+ /* remote as a last resort */
+ icon = gs_appstream_get_icon_by_kind (item, AS_ICON_KIND_REMOTE);
+ if (icon != NULL)
+ gs_app_add_icon (app, icon);
+}
+
+static gboolean
+gs_appstream_refine_add_addons (GsPlugin *plugin,
+ GsApp *app,
+ AsApp *item,
+ GError **error)
+{
+ GPtrArray *addons;
+ guint i;
+ g_autoptr(AsProfileTask) ptask = NULL;
+
+ /* we only care about addons to desktop apps */
+ if (gs_app_get_kind (app) != AS_APP_KIND_DESKTOP)
+ return TRUE;
+
+ /* search categories for the search term */
+ ptask = as_profile_start (gs_plugin_get_profile (plugin),
+ "appstream::refine-addons{%s}",
+ gs_app_get_unique_id (app));
+ g_assert (ptask != NULL);
+
+ addons = as_app_get_addons (item);
+ if (addons == NULL)
+ return TRUE;
+
+ for (i = 0; i < addons->len; i++) {
+ AsApp *as_addon = g_ptr_array_index (addons, i);
+ g_autoptr(GsApp) addon = NULL;
+
+ addon = gs_appstream_create_app (plugin, as_addon, error);
+ if (addon == NULL)
+ return FALSE;
+
+ /* add all the data we can */
+ if (!gs_appstream_refine_app (plugin, addon, as_addon, error))
+ return FALSE;
+ gs_app_add_addon (app, addon);
+ }
+ return TRUE;
+}
+
+static void
+gs_appstream_refine_add_screenshots (GsApp *app, AsApp *item)
+{
+ AsScreenshot *ss;
+ GPtrArray *images_as;
+ GPtrArray *screenshots_as;
+ guint i;
+
+ /* do we have any to add */
+ screenshots_as = as_app_get_screenshots (item);
+ if (screenshots_as->len == 0)
+ return;
+
+ /* does the app already have some */
+ gs_app_add_kudo (app, GS_APP_KUDO_HAS_SCREENSHOTS);
+ if (gs_app_get_screenshots(app)->len > 0)
+ return;
+
+ /* add any we know */
+ for (i = 0; i < screenshots_as->len &&
+ i < GS_APPSTREAM_MAX_SCREENSHOTS; i++) {
+ ss = g_ptr_array_index (screenshots_as, i);
+ images_as = as_screenshot_get_images (ss);
+ if (images_as->len == 0)
+ continue;
+ if (as_screenshot_get_kind (ss) == AS_SCREENSHOT_KIND_UNKNOWN)
+ continue;
+ gs_app_add_screenshot (app, ss);
+ }
+}
+
+static void
+gs_appstream_refine_add_reviews (GsApp *app, AsApp *item)
+{
+ AsReview *review;
+ GPtrArray *reviews;
+ guint i;
+
+ /* do we have any to add */
+ if (gs_app_get_reviews(app)->len > 0)
+ return;
+ reviews = as_app_get_reviews (item);
+ for (i = 0; i < reviews->len; i++) {
+ review = g_ptr_array_index (reviews, i);
+ gs_app_add_review (app, review);
+ }
+}
+
+static void
+gs_appstream_refine_add_provides (GsApp *app, AsApp *item)
+{
+ AsProvide *provide;
+ GPtrArray *provides;
+ guint i;
+
+ /* do we have any to add */
+ if (gs_app_get_provides(app)->len > 0)
+ return;
+ provides = as_app_get_provides (item);
+ for (i = 0; i < provides->len; i++) {
+ provide = g_ptr_array_index (provides, i);
+ gs_app_add_provide (app, provide);
+ }
+}
+
+static gboolean
+gs_appstream_is_recent_release (AsApp *app)
+{
+ AsRelease *release;
+ GPtrArray *releases;
+ guint64 secs;
+
+ /* get newest release */
+ releases = as_app_get_releases (app);
+ if (releases->len == 0)
+ return FALSE;
+ release = g_ptr_array_index (releases, 0);
+
+ /* is last build less than one year ago? */
+ secs = ((guint64) g_get_real_time () / G_USEC_PER_SEC) -
+ as_release_get_timestamp (release);
+ return secs / (60 * 60 * 24) < 365;
+}
+
+static gboolean
+gs_appstream_are_screenshots_perfect (AsApp *app)
+{
+ AsImage *image;
+ AsScreenshot *screenshot;
+ GPtrArray *screenshots;
+ guint height;
+ guint i;
+ guint width;
+
+ screenshots = as_app_get_screenshots (app);
+ if (screenshots->len == 0)
+ return FALSE;
+ for (i = 0; i < screenshots->len; i++) {
+
+ /* get the source image as the thumbs will be resized & padded */
+ screenshot = g_ptr_array_index (screenshots, i);
+ image = as_screenshot_get_source (screenshot);
+ if (image == NULL)
+ return FALSE;
+
+ width = as_image_get_width (image);
+ height = as_image_get_height (image);
+
+ /* too small */
+ if (width < AS_IMAGE_LARGE_WIDTH || height < AS_IMAGE_LARGE_HEIGHT)
+ return FALSE;
+
+ /* too large */
+ if (width > AS_IMAGE_LARGE_WIDTH * 2 || height > AS_IMAGE_LARGE_HEIGHT * 2)
+ return FALSE;
+
+ /* not 16:9 */
+ if ((width / 16) * 9 != height)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+gs_appstream_copy_metadata (GsApp *app, AsApp *item)
+{
+ GHashTable *hash;
+ GList *l;
+ g_autoptr(GList) keys = NULL;
+
+ hash = as_app_get_metadata (item);
+ keys = g_hash_table_get_keys (hash);
+ for (l = keys; l != NULL; l = l->next) {
+ const gchar *key = l->data;
+ const gchar *value = g_hash_table_lookup (hash, key);
+ if (gs_app_get_metadata_item (app, key) != NULL)
+ continue;
+ gs_app_set_metadata (app, key, value);
+ }
+}
+
+GsApp *
+gs_appstream_create_runtime (GsPlugin *plugin,
+ GsApp *parent,
+ const gchar *runtime)
+{
+ g_autofree gchar *source = NULL;
+ g_auto(GStrv) split = NULL;
+ g_autoptr(GsApp) app_cache = NULL;
+ g_autoptr(GsApp) app = NULL;
+
+ /* get the name/arch/branch */
+ split = g_strsplit (runtime, "/", -1);
+ if (g_strv_length (split) != 3)
+ return NULL;
+
+ /* create the complete GsApp from the single string */
+ app = gs_app_new (split[0]);
+ source = g_strdup_printf ("runtime/%s", runtime);
+ gs_app_add_source (app, source);
+ gs_app_set_bundle_kind (app, AS_BUNDLE_KIND_FLATPAK);
+ gs_app_set_kind (app, AS_APP_KIND_RUNTIME);
+ gs_app_set_branch (app, split[2]);
+ gs_app_set_scope (app, gs_app_get_scope (parent));
+
+ /* search in the cache */
+ app_cache = gs_plugin_cache_lookup (plugin, gs_app_get_unique_id (app));
+ if (app_cache != NULL) {
+ /* since the cached runtime can have been created somewhere else
+ * (we're using a global cache), we need to make sure that a
+ * source is set */
+ if (gs_app_get_source_default (app_cache) == NULL)
+ gs_app_add_source (app_cache, source);
+ return g_steal_pointer (&app_cache);
+ }
+
+ /* save in the cache */
+ gs_plugin_cache_add (plugin, NULL, app);
+ return g_steal_pointer (&app);
+}
+
+static void
+gs_refine_item_management_plugin (GsPlugin *plugin, GsApp *app, AsApp *item)
+{
+ GPtrArray *bundles;
+ const gchar *management_plugin = NULL;
+ const gchar *runtime = NULL;
+ guint i;
+
+ /* allow override */
+ management_plugin = as_app_get_metadata_item (item, "GnomeSoftware::Plugin");
+ if (management_plugin != NULL)
+ gs_app_set_management_plugin (app, management_plugin);
+
+ /* find the default bundle kind */
+ bundles = as_app_get_bundles (item);
+ for (i = 0; i < bundles->len; i++) {
+ AsBundle *bundle = g_ptr_array_index (bundles, i);
+ AsBundleKind kind = as_bundle_get_kind (bundle);
+
+ gs_app_add_source (app, as_bundle_get_id (bundle));
+
+ /* automatically add runtime */
+ if (kind == AS_BUNDLE_KIND_FLATPAK) {
+ runtime = as_bundle_get_runtime (bundle);
+ if (runtime != NULL) {
+ g_autoptr(GsApp) app2 = NULL;
+ app2 = gs_appstream_create_runtime (plugin, app, runtime);
+ if (app2 != NULL) {
+ if (app == app2) {
+ g_warning ("%s runtime cannot have runtime!",
+ gs_app_get_unique_id (app));
+ break;
+ }
+ g_debug ("runtime for %s is %s",
+ gs_app_get_unique_id (app),
+ runtime);
+ gs_app_set_update_runtime (app, app2);
+ }
+ }
+ break;
+ }
+ }
+}
+
+static gboolean
+gs_appstream_refine_app_updates (GsPlugin *plugin,
+ GsApp *app,
+ AsApp *item,
+ GError **error)
+{
+ AsUrgencyKind urgency_best = AS_URGENCY_KIND_UNKNOWN;
+ GPtrArray *releases;
+ g_autoptr(GPtrArray) updates_list = NULL;
+
+ /* only for UPDATABLE apps */
+ if (!gs_app_is_updatable (app))
+ return TRUE;
+
+ /* make a list of valid updates */
+ updates_list = g_ptr_array_new ();
+ releases = as_app_get_releases (item);
+ for (guint i = 0; i < releases->len; i++) {
+ AsRelease *rel = g_ptr_array_index (releases, i);
+
+ /* already installed */
+ g_debug ("installable update %s [%u]",
+ as_release_get_version (rel),
+ as_release_get_state (rel));
+ if (as_release_get_state (rel) == AS_RELEASE_STATE_INSTALLED)
+ continue;
+
+ /* use the 'worst' urgency, e.g. critical over enhancement */
+ if (as_release_get_urgency (rel) > urgency_best)
+ urgency_best = as_release_get_urgency (rel);
+
+ /* add updates with a description */
+ if (as_release_get_description (rel, NULL) == NULL)
+ continue;
+ g_ptr_array_add (updates_list, rel);
+ }
+
+ /* only set if known */
+ if (urgency_best != AS_URGENCY_KIND_UNKNOWN)
+ gs_app_set_update_urgency (app, urgency_best);
+
+ /* no prefix on each release */
+ if (updates_list->len == 1) {
+ g_autofree gchar *desc = NULL;
+ AsRelease *rel = g_ptr_array_index (updates_list, 0);
+ desc = as_markup_convert (as_release_get_description (rel, NULL),
+ AS_MARKUP_CONVERT_FORMAT_SIMPLE,
+ error);
+ if (desc == NULL) {
+ gs_utils_error_convert_appstream (error);
+ return FALSE;
+ }
+ gs_app_set_update_details (app, desc);
+
+ /* get the descriptions with a version prefix */
+ } else if (updates_list->len > 1) {
+ g_autoptr(GString) update_desc = g_string_new ("");
+ for (guint i = 0; i < updates_list->len; i++) {
+ g_autofree gchar *desc = NULL;
+ AsRelease *rel = g_ptr_array_index (updates_list, i);
+ desc = as_markup_convert (as_release_get_description (rel, NULL),
+ AS_MARKUP_CONVERT_FORMAT_SIMPLE,
+ error);
+ if (desc == NULL) {
+ gs_utils_error_convert_appstream (error);
+ return FALSE;
+ }
+ g_string_append_printf (update_desc,
+ "Version %s:\n%s\n\n",
+ as_release_get_version (rel),
+ desc);
+ }
+
+ /* remove trailing newlines */
+ if (update_desc->len > 2)
+ g_string_truncate (update_desc, update_desc->len - 2);
+ gs_app_set_update_details (app, update_desc->str);
+ }
+
+ /* if there is no already set update version use the newest */
+ if (gs_app_get_update_version (app) == NULL) {
+ AsRelease *rel = as_app_get_release_default (item);
+ if (rel != NULL)
+ gs_app_set_update_version (app, as_release_get_version (rel));
+ }
+
+ /* success */
+ return TRUE;
+}
+
+/**
+ * _gs_utils_locale_has_translations:
+ * @locale: A locale, e.g. "en_GB"
+ *
+ * Looks up if the locale is likely to have translations.
+ *
+ * Returns: %TRUE if the locale should have translations
+ **/
+static gboolean
+_gs_utils_locale_has_translations (const gchar *locale)
+{
+ if (g_strcmp0 (locale, "C") == 0)
+ return FALSE;
+ if (g_strcmp0 (locale, "en") == 0)
+ return FALSE;
+ if (g_strcmp0 (locale, "en_US") == 0)
+ return FALSE;
+ return TRUE;
+}
+
+static AsBundleKind
+gs_appstream_get_bundle_kind (AsApp *item)
+{
+ GPtrArray *bundles;
+ GPtrArray *pkgnames;
+
+ /* prefer bundle */
+ bundles = as_app_get_bundles (item);
+ if (bundles->len > 0) {
+ AsBundle *bundle = g_ptr_array_index (bundles, 0);
+ if (as_bundle_get_kind (bundle) != AS_BUNDLE_KIND_UNKNOWN)
+ return as_bundle_get_kind (bundle);
+ }
+
+ /* fallback to packages */
+ pkgnames = as_app_get_pkgnames (item);
+ if (pkgnames->len > 0)
+ return AS_BUNDLE_KIND_PACKAGE;
+
+ /* nothing */
+ return AS_BUNDLE_KIND_UNKNOWN;
+}
+
+static gboolean
+gs_appstream_origin_valid (const gchar *origin)
+{
+ if (origin == NULL)
+ return FALSE;
+ if (g_strcmp0 (origin, "") == 0)
+ return FALSE;
+ return TRUE;
+}
+
+gboolean
+gs_appstream_refine_app (GsPlugin *plugin,
+ GsApp *app,
+ AsApp *item,
+ GError **error)
+{
+ AsRequire *req;
+ g_autoptr(GError) error_local = NULL;
+ GHashTable *urls;
+ GPtrArray *array;
+ GPtrArray *pkgnames;
+ GPtrArray *kudos;
+ const gchar *current_desktop;
+ const gchar *tmp;
+ guint i;
+ g_autoptr(AsProfileTask) ptask = NULL;
+
+ /* search categories for the search term */
+ ptask = as_profile_start (gs_plugin_get_profile (plugin),
+ "appstream::refine-app{%s}",
+ gs_app_get_unique_id (app));
+ g_assert (ptask != NULL);
+
+ /* set the kind to be more precise */
+ if (gs_app_get_kind (app) == AS_APP_KIND_UNKNOWN ||
+ gs_app_get_kind (app) == AS_APP_KIND_GENERIC) {
+ gs_app_set_kind (app, as_app_get_kind (item));
+ }
+
+ /* is installed already */
+ if (gs_app_get_state (app) == AS_APP_STATE_UNKNOWN &&
+ as_app_get_state (item) != AS_APP_STATE_UNKNOWN) {
+ gs_app_set_state (app, as_app_get_state (item));
+ }
+
+ /* is compatible */
+ req = as_app_get_require_by_value (item,
+ AS_REQUIRE_KIND_ID,
+ "org.gnome.Software.desktop");
+ if (req != NULL) {
+ if (!as_require_version_compare (req, PACKAGE_VERSION, &error_local)) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_NOT_SUPPORTED,
+ "not for this gnome-software: %s",
+ error_local->message);
+ return FALSE;
+ }
+ }
+
+ /* types we can never launch */
+ switch (gs_app_get_kind (app)) {
+ case AS_APP_KIND_ADDON:
+ case AS_APP_KIND_CODEC:
+ case AS_APP_KIND_FIRMWARE:
+ case AS_APP_KIND_FONT:
+ case AS_APP_KIND_GENERIC:
+ case AS_APP_KIND_INPUT_METHOD:
+ case AS_APP_KIND_LOCALIZATION:
+ case AS_APP_KIND_OS_UPDATE:
+ case AS_APP_KIND_OS_UPGRADE:
+ case AS_APP_KIND_RUNTIME:
+ case AS_APP_KIND_SOURCE:
+ gs_app_add_quirk (app, AS_APP_QUIRK_NOT_LAUNCHABLE);
+ break;
+ default:
+ break;
+ }
+
+ /* set management plugin automatically */
+ gs_refine_item_management_plugin (plugin, app, item);
+
+ /* set id */
+ 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 */
+ if (gs_app_get_metadata_item (app, "appstream::source-file") == NULL) {
+#if AS_CHECK_VERSION(0,6,9)
+ AsFormat *format = as_app_get_format_by_kind (item, AS_FORMAT_KIND_DESKTOP);
+ if (format != NULL) {
+ gs_app_set_metadata (app, "appstream::source-file",
+ as_format_get_filename (format));
+ }
+#else
+ gs_app_set_metadata (app, "appstream::source-file",
+ as_app_get_source_file (item));
+#endif
+ }
+
+ /* scope */
+ if (gs_app_get_scope (app) == AS_APP_SCOPE_UNKNOWN &&
+ as_app_get_scope (item) != AS_APP_SCOPE_UNKNOWN)
+ gs_app_set_scope (app, as_app_get_scope (item));
+
+ /* set branch */
+ if (as_app_get_branch (item) != NULL &&
+ gs_app_get_branch (app) == NULL)
+ gs_app_set_branch (app, as_app_get_branch (item));
+
+ /* set content rating */
+ array = as_app_get_content_ratings (item);
+ for (i = 0; i < array->len; i++) {
+ AsContentRating *cr = g_ptr_array_index (array, i);
+ if (g_strcmp0 (as_content_rating_get_kind (cr), "oars-1.0") == 0) {
+ gs_app_set_content_rating (app, cr);
+ break;
+ }
+ }
+
+ /* bundle-kind */
+ if (gs_app_get_bundle_kind (app) == AS_BUNDLE_KIND_UNKNOWN)
+ gs_app_set_bundle_kind (app, gs_appstream_get_bundle_kind (item));
+
+ /* set name */
+ tmp = as_app_get_name (item, NULL);
+ if (tmp != NULL)
+ gs_app_set_name (app, GS_APP_QUALITY_HIGHEST, tmp);
+
+ /* set summary */
+ tmp = as_app_get_comment (item, NULL);
+ if (tmp != NULL) {
+ gs_app_set_summary (app, GS_APP_QUALITY_HIGHEST, tmp);
+ }
+
+ /* add urls */
+ urls = as_app_get_urls (item);
+ if (g_hash_table_size (urls) > 0 &&
+ gs_app_get_url (app, AS_URL_KIND_HOMEPAGE) == NULL) {
+ GList *l;
+ g_autoptr(GList) keys = NULL;
+ keys = g_hash_table_get_keys (urls);
+ for (l = keys; l != NULL; l = l->next) {
+ gs_app_set_url (app,
+ as_url_kind_from_string (l->data),
+ g_hash_table_lookup (urls, l->data));
+ }
+ }
+
+ /* set license */
+ if (as_app_get_project_license (item) != NULL && gs_app_get_license (app) == NULL)
+ gs_app_set_license (app,
+ GS_APP_QUALITY_HIGHEST,
+ as_app_get_project_license (item));
+
+ /* set keywords */
+ if (as_app_get_keywords (item, NULL) != NULL &&
+ gs_app_get_keywords (app) == NULL) {
+ gs_app_set_keywords (app, as_app_get_keywords (item, NULL));
+ gs_app_add_kudo (app, GS_APP_KUDO_HAS_KEYWORDS);
+ }
+
+ /* set origin */
+ if (as_app_get_origin (item) != NULL &&
+ gs_app_get_origin (app) == NULL ) {
+ tmp = as_app_get_unique_id (item);
+ if (tmp != NULL) {
+ if (g_str_has_prefix (tmp, "user/flatpak/") ||
+ g_str_has_prefix (tmp, "system/flatpak/"))
+ gs_app_set_origin (app, as_app_get_origin (item));
+ }
+ }
+
+ /* set description */
+ tmp = as_app_get_description (item, NULL);
+ if (tmp != NULL) {
+ g_autofree gchar *from_xml = NULL;
+ from_xml = as_markup_convert_simple (tmp, error);
+ if (from_xml == NULL) {
+ gs_utils_error_convert_appstream (error);
+ g_prefix_error (error, "trying to parse '%s': ", tmp);
+ return FALSE;
+ }
+ gs_app_set_description (app, GS_APP_QUALITY_HIGHEST, from_xml);
+ }
+
+ /* set icon */
+ if (as_app_get_icon_default (item) != NULL &&
+ gs_app_get_icons(app)->len == 0)
+ gs_refine_item_icon (plugin, app, item);
+
+ /* set categories */
+ array = as_app_get_categories (item);
+ if (array != NULL && gs_app_get_categories (app)->len == 0) {
+ for (i = 0; i < array->len; i++) {
+ tmp = g_ptr_array_index (array, i);
+ gs_app_add_category (app, tmp);
+ }
+ }
+
+ /* set project group */
+ if (as_app_get_project_group (item) != NULL &&
+ gs_app_get_project_group (app) == NULL)
+ gs_app_set_project_group (app, as_app_get_project_group (item));
+
+ /*
+ * Set the core applications for the current desktop that cannot be
+ * removed -- but note: XDG_CURRENT_DESKTOP="GNOME" is different to
+ * XDG_CURRENT_DESKTOP="Ubuntu:GNOME" here.
+ *
+ * To define what is compulsory for the hybrid desktop either:
+ *
+ * - Add an appstream merge file downstream with the tag
+ * <compulsory_for_desktop>Ubuntu:GNOME</compulsory_for_desktop>
+ *
+ * - Get upstream projects to add the <compulsory_for_desktop> tag
+ */
+ array = as_app_get_compulsory_for_desktops (item);
+ current_desktop = g_getenv ("XDG_CURRENT_DESKTOP");
+ for (i = 0; i < array->len; i++) {
+ tmp = g_ptr_array_index (array, i);
+ if (g_strcmp0 (current_desktop, tmp) == 0) {
+ gs_app_add_quirk (app, AS_APP_QUIRK_COMPULSORY);
+ break;
+ }
+ }
+
+ /* set id kind */
+ if (gs_app_get_kind (app) == AS_APP_KIND_UNKNOWN)
+ gs_app_set_kind (app, as_app_get_kind (item));
+
+ /* copy all the metadata */
+ gs_appstream_copy_metadata (app, item);
+
+ /* set package names */
+ pkgnames = as_app_get_pkgnames (item);
+ if (pkgnames->len > 0 && gs_app_get_sources(app)->len == 0)
+ gs_app_set_sources (app, pkgnames);
+
+ /* set addons */
+ if (!gs_appstream_refine_add_addons (plugin, app, item, error))
+ return FALSE;
+
+ /* set screenshots */
+ gs_appstream_refine_add_screenshots (app, item);
+
+ /* set reviews */
+ gs_appstream_refine_add_reviews (app, item);
+
+ /* set provides */
+ gs_appstream_refine_add_provides (app, item);
+
+ /* are the screenshots perfect */
+ if (gs_appstream_are_screenshots_perfect (item))
+ gs_app_add_kudo (app, GS_APP_KUDO_PERFECT_SCREENSHOTS);
+
+ /* was this application released recently */
+ if (gs_appstream_is_recent_release (item))
+ gs_app_add_kudo (app, GS_APP_KUDO_RECENT_RELEASE);
+
+ /* add kudos */
+ tmp = gs_plugin_get_locale (plugin);
+ if (!_gs_utils_locale_has_translations (tmp) ||
+ as_app_get_language (item, tmp) > 50)
+ gs_app_add_kudo (app, GS_APP_KUDO_MY_LANGUAGE);
+
+ /* add a kudo to featured and popular apps */
+ if (as_app_has_kudo (item, "GnomeSoftware::popular"))
+ gs_app_add_kudo (app, GS_APP_KUDO_FEATURED_RECOMMENDED);
+ if (as_app_has_category (item, "featured"))
+ gs_app_add_kudo (app, GS_APP_KUDO_FEATURED_RECOMMENDED);
+
+ /* add new-style kudos */
+ kudos = as_app_get_kudos (item);
+ for (i = 0; i < kudos->len; i++) {
+ tmp = g_ptr_array_index (kudos, i);
+ switch (as_kudo_kind_from_string (tmp)) {
+ case AS_KUDO_KIND_SEARCH_PROVIDER:
+ gs_app_add_kudo (app, GS_APP_KUDO_SEARCH_PROVIDER);
+ break;
+ case AS_KUDO_KIND_USER_DOCS:
+ gs_app_add_kudo (app, GS_APP_KUDO_INSTALLS_USER_DOCS);
+ break;
+ case AS_KUDO_KIND_APP_MENU:
+ gs_app_add_kudo (app, GS_APP_KUDO_USES_APP_MENU);
+ break;
+ case AS_KUDO_KIND_MODERN_TOOLKIT:
+ gs_app_add_kudo (app, GS_APP_KUDO_MODERN_TOOLKIT);
+ break;
+ case AS_KUDO_KIND_NOTIFICATIONS:
+ gs_app_add_kudo (app, GS_APP_KUDO_USES_NOTIFICATIONS);
+ break;
+ case AS_KUDO_KIND_HIGH_CONTRAST:
+ gs_app_add_kudo (app, GS_APP_KUDO_HIGH_CONTRAST);
+ break;
+ case AS_KUDO_KIND_HI_DPI_ICON:
+ gs_app_add_kudo (app, GS_APP_KUDO_HI_DPI_ICON);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* we saved the origin hostname in the metadata */
+ tmp = as_app_get_metadata_item (item, "GnomeSoftware::OriginHostnameUrl");
+ if (tmp != NULL && gs_app_get_origin_hostname (app) == NULL)
+ gs_app_set_origin_hostname (app, tmp);
+
+ /* we have an origin in the XML */
+ if (gs_app_get_origin (app) == NULL &&
+ gs_appstream_origin_valid (as_app_get_origin (item)))
+ gs_app_set_origin (app, as_app_get_origin (item));
+
+ /* is there any update information */
+ if (!gs_appstream_refine_app_updates (plugin, app, item, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+gs_appstream_store_search_item (GsPlugin *plugin,
+ AsApp *item,
+ gchar **values,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ AsApp *item_tmp;
+ GPtrArray *addons;
+ guint i;
+ guint match_value;
+ g_autoptr(GsApp) app = NULL;
+
+ /* match against the app or any of the addons */
+ match_value = as_app_search_matches_all (item, values);
+ addons = as_app_get_addons (item);
+ for (i = 0; i < addons->len; i++) {
+ item_tmp = g_ptr_array_index (addons, i);
+ match_value |= as_app_search_matches_all (item_tmp, values);
+ }
+
+ /* no match */
+ if (match_value == 0)
+ return TRUE;
+
+ /* create app */
+ app = gs_appstream_create_app (plugin, item, error);
+ if (app == NULL)
+ return FALSE;
+ gs_app_set_match_value (app, match_value);
+ gs_app_list_add (list, app);
+ return TRUE;
+}
+
+gboolean
+gs_appstream_store_search (GsPlugin *plugin,
+ AsStore *store,
+ gchar **values,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ AsApp *item;
+ GPtrArray *array;
+ gboolean ret = TRUE;
+ guint i;
+ g_autoptr(AsProfileTask) ptask = NULL;
+
+ /* search categories for the search term */
+ ptask = as_profile_start_literal (gs_plugin_get_profile (plugin),
+ "appstream::search");
+ g_assert (ptask != NULL);
+ array = as_store_get_apps (store);
+ for (i = 0; i < array->len; i++) {
+ if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+ gs_utils_error_convert_gio (error);
+ return FALSE;
+ }
+
+ item = g_ptr_array_index (array, i);
+ ret = gs_appstream_store_search_item (plugin, item,
+ values, list,
+ cancellable, error);
+ if (!ret)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+_as_app_matches_desktop_group_set (AsApp *app, gchar **desktop_groups)
+{
+ guint i;
+ for (i = 0; desktop_groups[i] != NULL; i++) {
+ if (!as_app_has_category (app, desktop_groups[i]))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+_as_app_matches_desktop_group (AsApp *app, const gchar *desktop_group)
+{
+ g_auto(GStrv) split = g_strsplit (desktop_group, "::", -1);
+ return _as_app_matches_desktop_group_set (app, split);
+}
+
+static void
+gs_appstream_store_add_categories_for_app (GsCategory *parent, AsApp *app)
+{
+ GPtrArray *children;
+ GPtrArray *desktop_groups;
+ GsCategory *category;
+ guint i, j;
+
+ /* find all the sub-categories */
+ children = gs_category_get_children (parent);
+ for (j = 0; j < children->len; j++) {
+ gboolean matched = FALSE;
+ category = GS_CATEGORY (g_ptr_array_index (children, j));
+
+ /* do any desktop_groups match this application */
+ desktop_groups = gs_category_get_desktop_groups (category);
+ for (i = 0; i < desktop_groups->len; i++) {
+ const gchar *desktop_group = g_ptr_array_index (desktop_groups, i);
+ if (_as_app_matches_desktop_group (app, desktop_group)) {
+ matched = TRUE;
+ break;
+ }
+ }
+ if (matched) {
+ gs_category_increment_size (category);
+ gs_category_increment_size (parent);
+ }
+ }
+}
+
+gboolean
+gs_appstream_store_add_category_apps (GsPlugin *plugin,
+ AsStore *store,
+ GsCategory *category,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GPtrArray *array;
+ GPtrArray *desktop_groups;
+ guint i;
+ guint j;
+ g_autoptr(AsProfileTask) ptask = NULL;
+
+ /* just look at each app in turn */
+ ptask = as_profile_start_literal (gs_plugin_get_profile (plugin),
+ "appstream::add-category-apps");
+ g_assert (ptask != NULL);
+ array = as_store_get_apps (store);
+ desktop_groups = gs_category_get_desktop_groups (category);
+ if (desktop_groups->len == 0) {
+ g_warning ("no desktop_groups for %s", gs_category_get_id (category));
+ return TRUE;
+ }
+ for (j = 0; j < desktop_groups->len; j++) {
+ const gchar *desktop_group = g_ptr_array_index (desktop_groups, j);
+ g_auto(GStrv) split = g_strsplit (desktop_group, "::", -1);
+
+ /* match the app */
+ for (i = 0; i < array->len; i++) {
+ AsApp *item;
+ g_autoptr(GsApp) app = NULL;
+
+ /* no ID is invalid */
+ item = g_ptr_array_index (array, i);
+ if (as_app_get_id (item) == NULL)
+ continue;
+
+ /* match all the desktop groups */
+ if (!_as_app_matches_desktop_group_set (item, split))
+ continue;
+
+ /* add all the data we can */
+ app = gs_appstream_create_app (plugin, item, error);
+ if (app == NULL)
+ return FALSE;
+ gs_app_list_add (list, app);
+ }
+ }
+ return TRUE;
+}
+
+gboolean
+gs_appstream_store_add_categories (GsPlugin *plugin,
+ AsStore *store,
+ GPtrArray *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ AsApp *app;
+ GPtrArray *array;
+ guint i;
+ guint j;
+ g_autoptr(AsProfileTask) ptask = NULL;
+
+ /* find out how many packages are in each category */
+ ptask = as_profile_start_literal (gs_plugin_get_profile (plugin),
+ "appstream::add-categories");
+ g_assert (ptask != NULL);
+ array = as_store_get_apps (store);
+ for (i = 0; i < array->len; i++) {
+ app = g_ptr_array_index (array, i);
+ if (as_app_get_id (app) == NULL)
+ continue;
+ if (as_app_get_priority (app) < 0)
+ continue;
+ for (j = 0; j < list->len; j++) {
+ GsCategory *parent = GS_CATEGORY (g_ptr_array_index (list, j));
+ gs_appstream_store_add_categories_for_app (parent, app);
+ }
+ }
+ return TRUE;
+}
+
+gboolean
+gs_appstream_add_popular (GsPlugin *plugin,
+ AsStore *store,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ AsApp *item;
+ GPtrArray *array;
+ guint i;
+ g_autoptr(AsProfileTask) ptask = NULL;
+
+ /* find out how many packages are in each category */
+ ptask = as_profile_start_literal (gs_plugin_get_profile (plugin),
+ "appstream::add-popular");
+ g_assert (ptask != NULL);
+ array = as_store_get_apps (store);
+ for (i = 0; i < array->len; i++) {
+ g_autoptr(GsApp) app = NULL;
+ item = g_ptr_array_index (array, i);
+ if (as_app_get_id (item) == NULL)
+ continue;
+ if (!as_app_has_kudo (item, "GnomeSoftware::popular"))
+ continue;
+ app = gs_app_new (as_app_get_id (item));
+ gs_app_add_quirk (app, AS_APP_QUIRK_MATCH_ANY_PREFIX);
+ gs_app_list_add (list, app);
+ }
+ return TRUE;
+}
+
+gboolean
+gs_appstream_add_featured (GsPlugin *plugin,
+ AsStore *store,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ AsApp *item;
+ GPtrArray *array;
+ guint i;
+ g_autoptr(AsProfileTask) ptask = NULL;
+
+ /* find out how many packages are in each category */
+ ptask = as_profile_start_literal (gs_plugin_get_profile (plugin),
+ "appstream::add-featured");
+ g_assert (ptask != NULL);
+ array = as_store_get_apps (store);
+ for (i = 0; i < array->len; i++) {
+ g_autoptr(GsApp) app = NULL;
+ item = g_ptr_array_index (array, i);
+ if (as_app_get_id (item) == NULL)
+ continue;
+ if (as_app_get_metadata_item (item, "GnomeSoftware::FeatureTile-css") == NULL)
+ continue;
+ app = gs_app_new (as_app_get_id (item));
+ gs_app_add_quirk (app, AS_APP_QUIRK_MATCH_ANY_PREFIX);
+ gs_app_list_add (list, app);
+ }
+ return TRUE;
+}
+
+void
+gs_appstream_add_extra_info (GsPlugin *plugin, AsApp *app)
+{
+ const gchar *tmp;
+
+ /* add more search terms */
+ switch (as_app_get_kind (app)) {
+ case AS_APP_KIND_WEB_APP:
+ case AS_APP_KIND_INPUT_METHOD:
+ tmp = as_app_kind_to_string (as_app_get_kind (app));
+ g_debug ("adding keyword '%s' to %s",
+ tmp, as_app_get_unique_id (app));
+ as_app_add_keyword (app, NULL, tmp);
+ break;
+ default:
+ break;
+ }
+
+ /* fix up these */
+ if (as_app_get_kind (app) == AS_APP_KIND_LOCALIZATION &&
+ g_str_has_prefix (as_app_get_id (app),
+ "org.fedoraproject.LangPack-")) {
+ g_autoptr(AsIcon) icon = NULL;
+
+ /* add icon */
+ icon = as_icon_new ();
+ as_icon_set_kind (icon, AS_ICON_KIND_STOCK);
+ as_icon_set_name (icon, "accessories-dictionary-symbolic");
+ as_app_add_icon (app, icon);
+
+ /* add categories */
+ as_app_add_category (app, "Addons");
+ as_app_add_category (app, "Localization");
+ }
+
+ /* fix up drivers with our nonstandard groups */
+ if (as_app_get_kind (app) == AS_APP_KIND_DRIVER) {
+ as_app_add_category (app, "Addons");
+ as_app_add_category (app, "Drivers");
+ }
+}
diff --git a/plugins/core/gs-appstream.h b/plugins/core/gs-appstream.h
new file mode 100644
index 0000000..c4c6d98
--- /dev/null
+++ b/plugins/core/gs-appstream.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2015-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.
+ */
+
+#ifndef __APPSTREAM_COMMON_H
+#define __APPSTREAM_COMMON_H
+
+#include <gnome-software.h>
+
+G_BEGIN_DECLS
+
+GsApp *gs_appstream_create_app (GsPlugin *plugin,
+ AsApp *item,
+ GError **error);
+gboolean gs_appstream_refine_app (GsPlugin *plugin,
+ GsApp *app,
+ AsApp *item,
+ GError **error);
+GsApp *gs_appstream_create_runtime (GsPlugin *plugin,
+ GsApp *parent,
+ const gchar *runtime);
+gboolean gs_appstream_store_search (GsPlugin *plugin,
+ AsStore *store,
+ gchar **values,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error);
+gboolean gs_appstream_store_add_categories (GsPlugin *plugin,
+ AsStore *store,
+ GPtrArray *list,
+ GCancellable *cancellable,
+ GError **error);
+gboolean gs_appstream_store_add_category_apps (GsPlugin *plugin,
+ AsStore *store,
+ GsCategory *category,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error);
+gboolean gs_appstream_add_popular (GsPlugin *plugin,
+ AsStore *store,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error);
+gboolean gs_appstream_add_featured (GsPlugin *plugin,
+ AsStore *store,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error);
+void gs_appstream_add_extra_info (GsPlugin *plugin,
+ AsApp *app);
+
+G_END_DECLS
+
+#endif /* __APPSTREAM_COMMON_H */
diff --git a/plugins/gs-desktop-common.c b/plugins/core/gs-desktop-common.c
similarity index 100%
rename from plugins/gs-desktop-common.c
rename to plugins/core/gs-desktop-common.c
diff --git a/plugins/gs-desktop-common.h b/plugins/core/gs-desktop-common.h
similarity index 100%
rename from plugins/gs-desktop-common.h
rename to plugins/core/gs-desktop-common.h
diff --git a/plugins/gs-plugin-appstream.c b/plugins/core/gs-plugin-appstream.c
similarity index 100%
rename from plugins/gs-plugin-appstream.c
rename to plugins/core/gs-plugin-appstream.c
diff --git a/plugins/gs-plugin-desktop-categories.c b/plugins/core/gs-plugin-desktop-categories.c
similarity index 100%
rename from plugins/gs-plugin-desktop-categories.c
rename to plugins/core/gs-plugin-desktop-categories.c
diff --git a/plugins/gs-plugin-desktop-menu-path.c b/plugins/core/gs-plugin-desktop-menu-path.c
similarity index 100%
rename from plugins/gs-plugin-desktop-menu-path.c
rename to plugins/core/gs-plugin-desktop-menu-path.c
diff --git a/plugins/gs-plugin-generic-updates.c b/plugins/core/gs-plugin-generic-updates.c
similarity index 100%
rename from plugins/gs-plugin-generic-updates.c
rename to plugins/core/gs-plugin-generic-updates.c
diff --git a/plugins/gs-plugin-hardcoded-blacklist.c b/plugins/core/gs-plugin-hardcoded-blacklist.c
similarity index 100%
rename from plugins/gs-plugin-hardcoded-blacklist.c
rename to plugins/core/gs-plugin-hardcoded-blacklist.c
diff --git a/plugins/gs-plugin-hardcoded-featured.c b/plugins/core/gs-plugin-hardcoded-featured.c
similarity index 100%
rename from plugins/gs-plugin-hardcoded-featured.c
rename to plugins/core/gs-plugin-hardcoded-featured.c
diff --git a/plugins/gs-plugin-hardcoded-popular.c b/plugins/core/gs-plugin-hardcoded-popular.c
similarity index 100%
rename from plugins/gs-plugin-hardcoded-popular.c
rename to plugins/core/gs-plugin-hardcoded-popular.c
diff --git a/plugins/gs-plugin-icons.c b/plugins/core/gs-plugin-icons.c
similarity index 100%
rename from plugins/gs-plugin-icons.c
rename to plugins/core/gs-plugin-icons.c
diff --git a/plugins/gs-plugin-key-colors.c b/plugins/core/gs-plugin-key-colors.c
similarity index 100%
rename from plugins/gs-plugin-key-colors.c
rename to plugins/core/gs-plugin-key-colors.c
diff --git a/plugins/gs-plugin-provenance-license.c b/plugins/core/gs-plugin-provenance-license.c
similarity index 100%
rename from plugins/gs-plugin-provenance-license.c
rename to plugins/core/gs-plugin-provenance-license.c
diff --git a/plugins/gs-plugin-provenance.c b/plugins/core/gs-plugin-provenance.c
similarity index 100%
rename from plugins/gs-plugin-provenance.c
rename to plugins/core/gs-plugin-provenance.c
diff --git a/plugins/dummy/Makefile.am b/plugins/dummy/Makefile.am
new file mode 100644
index 0000000..ead9bb3
--- /dev/null
+++ b/plugins/dummy/Makefile.am
@@ -0,0 +1,23 @@
+AM_CPPFLAGS = \
+ -DDATADIR=\"$(datadir)\" \
+ -DTESTDATADIR=\""$(srcdir)"\" \
+ -DLOCALPLUGINDIR=\""$(builddir)/.libs"\" \
+ -DLOCALPLUGINDIR_CORE=\""$(top_builddir)/plugins/core/.libs"\"
+
+plugindir = $(GS_PLUGIN_DIR)
+plugin_LTLIBRARIES = libgs_plugin_dummy.la
+
+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
+libgs_plugin_dummy_la_CFLAGS = $(GS_PLUGIN_CFLAGS)
+
+if ENABLE_TESTS
+check_PROGRAMS = gs-self-test
+gs_self_test_SOURCES = gs-self-test.c
+gs_self_test_LDADD = $(GS_PRIVATE_LIBS)
+gs_self_test_CFLAGS = $(GS_PRIVATE_CFLAGS)
+TESTS = gs-self-test
+endif
+
+-include $(top_srcdir)/git.mk
diff --git a/plugins/gs-plugin-dummy.c b/plugins/dummy/gs-plugin-dummy.c
similarity index 100%
rename from plugins/gs-plugin-dummy.c
rename to plugins/dummy/gs-plugin-dummy.c
diff --git a/plugins/dummy/gs-self-test.c b/plugins/dummy/gs-self-test.c
new file mode 100644
index 0000000..0b05e44
--- /dev/null
+++ b/plugins/dummy/gs-self-test.c
@@ -0,0 +1,715 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013-2017 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 "gnome-software-private.h"
+
+#include "gs-test.h"
+
+static guint _status_changed_cnt = 0;
+
+static void
+gs_plugin_loader_status_changed_cb (GsPluginLoader *plugin_loader,
+ GsApp *app,
+ GsPluginStatus status,
+ gpointer user_data)
+{
+ _status_changed_cnt++;
+}
+
+static void
+gs_plugin_loader_install_func (GsPluginLoader *plugin_loader)
+{
+ gboolean ret;
+ g_autoptr(GsApp) app = NULL;
+ g_autoptr(GError) error = NULL;
+
+ /* install */
+ app = gs_app_new ("chiron.desktop");
+ gs_app_set_management_plugin (app, "dummy");
+ gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
+ ret = gs_plugin_loader_app_action (plugin_loader, app,
+ GS_PLUGIN_ACTION_INSTALL,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ 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);
+
+ /* remove */
+ ret = gs_plugin_loader_app_action (plugin_loader, app,
+ GS_PLUGIN_ACTION_REMOVE,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ 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_AVAILABLE);
+}
+
+static void
+gs_plugin_loader_error_func (GsPluginLoader *plugin_loader)
+{
+ GsPluginEvent *event;
+ const GError *app_error;
+ gboolean ret;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GPtrArray) events = NULL;
+ g_autoptr(GsApp) app = NULL;
+
+ /* drop all caches */
+ gs_plugin_loader_setup_again (plugin_loader);
+
+ /* update, which should cause an error to be emitted */
+ app = gs_app_new ("chiron.desktop");
+ gs_app_set_management_plugin (app, "dummy");
+ gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
+ ret = gs_plugin_loader_app_action (plugin_loader, app,
+ GS_PLUGIN_ACTION_UPDATE,
+ GS_PLUGIN_FAILURE_FLAGS_USE_EVENTS |
+ GS_PLUGIN_FAILURE_FLAGS_NO_CONSOLE,
+ NULL,
+ &error);
+ gs_test_flush_main_context ();
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ /* get event by app-id */
+ event = gs_plugin_loader_get_event_by_id (plugin_loader,
+ "*/*/*/source/dummy/*");
+ g_assert (event != NULL);
+ g_assert (gs_plugin_event_get_app (event) == app);
+
+ /* get last active event */
+ event = gs_plugin_loader_get_event_default (plugin_loader);
+ g_assert (event != NULL);
+ g_assert (gs_plugin_event_get_app (event) == app);
+
+ /* check all the events */
+ events = gs_plugin_loader_get_events (plugin_loader);
+ g_assert_cmpint (events->len, ==, 1);
+ event = g_ptr_array_index (events, 0);
+ g_assert (gs_plugin_event_get_app (event) == app);
+ app_error = gs_plugin_event_get_error (event);
+ g_assert (app_error != NULL);
+ g_assert_error (app_error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_DOWNLOAD_FAILED);
+}
+
+static void
+gs_plugin_loader_refine_func (GsPluginLoader *plugin_loader)
+{
+ gboolean ret;
+ g_autoptr(GsApp) app = NULL;
+ g_autoptr(GError) error = NULL;
+
+ /* get the extra bits */
+ app = gs_app_new ("chiron.desktop");
+ gs_app_set_management_plugin (app, "dummy");
+ ret = gs_plugin_loader_app_refine (plugin_loader, app,
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_DESCRIPTION |
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_LICENSE |
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_URL,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ NULL,
+ &error);
+ gs_test_flush_main_context ();
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ g_assert_cmpstr (gs_app_get_license (app), ==, "GPL-2.0+");
+ g_assert_cmpstr (gs_app_get_description (app), !=, NULL);
+ g_assert_cmpstr (gs_app_get_url (app, AS_URL_KIND_HOMEPAGE), ==, "http://www.test.org/");
+}
+
+static void
+gs_plugin_loader_key_colors_func (GsPluginLoader *plugin_loader)
+{
+ GPtrArray *array;
+ gboolean ret;
+ guint i;
+ g_autoptr(GsApp) app = NULL;
+ g_autoptr(GError) error = NULL;
+
+ /* get the extra bits */
+ app = gs_app_new ("zeus.desktop");
+ ret = gs_plugin_loader_app_refine (plugin_loader, app,
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_KEY_COLORS,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ NULL,
+ &error);
+ gs_test_flush_main_context ();
+ g_assert_no_error (error);
+ g_assert (ret);
+ array = gs_app_get_key_colors (app);
+ g_assert_cmpint (array->len, >=, 3);
+
+ /* check values are in range */
+ for (i = 0; i < array->len; i++) {
+ GdkRGBA *kc = g_ptr_array_index (array, i);
+ g_assert_cmpfloat (kc->red, >=, 0.f);
+ g_assert_cmpfloat (kc->red, <=, 1.f);
+ g_assert_cmpfloat (kc->green, >=, 0.f);
+ g_assert_cmpfloat (kc->green, <=, 1.f);
+ g_assert_cmpfloat (kc->blue, >=, 0.f);
+ g_assert_cmpfloat (kc->blue, <=, 1.f);
+ g_assert_cmpfloat (kc->alpha, >=, 0.f);
+ g_assert_cmpfloat (kc->alpha, <=, 1.f);
+ }
+}
+
+static void
+gs_plugin_loader_updates_func (GsPluginLoader *plugin_loader)
+{
+ GsApp *app;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GsAppList) list = NULL;
+
+ /* get the updates list */
+ list = gs_plugin_loader_get_updates (plugin_loader,
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON |
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_UPDATE_DETAILS,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ NULL,
+ &error);
+ gs_test_flush_main_context ();
+ g_assert_no_error (error);
+ g_assert (list != NULL);
+
+ /* make sure there are two entries */
+ g_assert_cmpint (gs_app_list_length (list), ==, 3);
+ app = gs_app_list_index (list, 0);
+ g_assert_cmpstr (gs_app_get_id (app), ==, "chiron.desktop");
+ g_assert_cmpint (gs_app_get_kind (app), ==, AS_APP_KIND_DESKTOP);
+ g_assert_cmpint (gs_app_get_state (app), ==, AS_APP_STATE_UPDATABLE_LIVE);
+ g_assert_cmpstr (gs_app_get_update_details (app), ==, "Do not crash when using libvirt.");
+ g_assert_cmpint (gs_app_get_update_urgency (app), ==, AS_URGENCY_KIND_HIGH);
+
+ /* get the virtual non-apps OS update */
+ app = gs_app_list_index (list, 1);
+ g_assert_cmpstr (gs_app_get_id (app), ==, "org.gnome.Software.OsUpdate");
+ g_assert_cmpstr (gs_app_get_name (app), ==, "OS Updates");
+ g_assert_cmpstr (gs_app_get_summary (app), ==, "Includes performance, stability and security
improvements.");
+ g_assert_cmpint (gs_app_get_kind (app), ==, AS_APP_KIND_OS_UPDATE);
+ g_assert_cmpint (gs_app_get_state (app), ==, AS_APP_STATE_UPDATABLE);
+ g_assert_cmpint (gs_app_get_related(app)->len, ==, 2);
+
+ /* get the virtual non-apps OS update */
+ app = gs_app_list_index (list, 2);
+ g_assert_cmpstr (gs_app_get_id (app), ==, "proxy.desktop");
+ g_assert (gs_app_has_quirk (app, AS_APP_QUIRK_IS_PROXY));
+ g_assert_cmpint (gs_app_get_state (app), ==, AS_APP_STATE_UPDATABLE_LIVE);
+ g_assert_cmpint (gs_app_get_related(app)->len, ==, 2);
+}
+
+static void
+gs_plugin_loader_distro_upgrades_func (GsPluginLoader *plugin_loader)
+{
+ GsApp *app;
+ gboolean ret;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GsAppList) list = NULL;
+
+ /* get the updates list */
+ list = gs_plugin_loader_get_distro_upgrades (plugin_loader,
+ GS_PLUGIN_REFINE_FLAGS_DEFAULT,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ NULL,
+ &error);
+ gs_test_flush_main_context ();
+ g_assert_no_error (error);
+ g_assert (list != NULL);
+
+ /* make sure there is one entry */
+ g_assert_cmpint (gs_app_list_length (list), ==, 1);
+ app = gs_app_list_index (list, 0);
+ g_assert_cmpstr (gs_app_get_id (app), ==, "org.fedoraproject.release-rawhide.upgrade");
+ g_assert_cmpint (gs_app_get_kind (app), ==, AS_APP_KIND_OS_UPGRADE);
+ g_assert_cmpint (gs_app_get_state (app), ==, AS_APP_STATE_AVAILABLE);
+
+ /* this should be set with a higher priority by AppStream */
+ g_assert_cmpstr (gs_app_get_summary (app), ==, "Release specific tagline");
+
+ /* download the update */
+ ret = gs_plugin_loader_app_action (plugin_loader,
+ app,
+ GS_PLUGIN_ACTION_UPGRADE_DOWNLOAD,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ 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_UPDATABLE);
+
+ /* trigger the update */
+ ret = gs_plugin_loader_app_action (plugin_loader,
+ app,
+ GS_PLUGIN_ACTION_UPGRADE_TRIGGER,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ 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_UPDATABLE);
+}
+
+static void
+gs_plugin_loader_installed_func (GsPluginLoader *plugin_loader)
+{
+ GsApp *app;
+ GsApp *addon;
+ GPtrArray *addons;
+ guint64 kudos;
+ g_autofree gchar *menu_path = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GsAppList) list = NULL;
+
+ /* get installed packages */
+ list = gs_plugin_loader_get_installed (plugin_loader,
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_ORIGIN |
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_ADDONS |
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_LICENSE |
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_MENU_PATH |
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON |
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_PROVENANCE,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ NULL,
+ &error);
+ gs_test_flush_main_context ();
+ g_assert_no_error (error);
+ g_assert (list != NULL);
+
+ /* make sure there is one entry */
+ g_assert_cmpint (gs_app_list_length (list), ==, 1);
+ app = gs_app_list_index (list, 0);
+ g_assert_cmpstr (gs_app_get_id (app), ==, "zeus.desktop");
+ g_assert_cmpint (gs_app_get_kind (app), ==, AS_APP_KIND_DESKTOP);
+ g_assert_cmpint (gs_app_get_state (app), ==, AS_APP_STATE_INSTALLED);
+ g_assert_cmpstr (gs_app_get_name (app), ==, "Zeus");
+ g_assert_cmpstr (gs_app_get_source_default (app), ==, "zeus");
+ g_assert (gs_app_get_pixbuf (app) != NULL);
+
+ /* check various bitfields */
+ g_assert (gs_app_has_quirk (app, AS_APP_QUIRK_PROVENANCE));
+ g_assert_cmpstr (gs_app_get_license (app), ==, "GPL-2.0+");
+ g_assert (gs_app_get_license_is_free (app));
+
+ /* check kudos */
+ kudos = gs_app_get_kudos (app);
+ g_assert (kudos & GS_APP_KUDO_MY_LANGUAGE);
+
+ /* check categories */
+ g_assert (gs_app_has_category (app, "Player"));
+ g_assert (gs_app_has_category (app, "AudioVideo"));
+ g_assert (!gs_app_has_category (app, "ImageProcessing"));
+ g_assert (gs_app_get_menu_path (app) != NULL);
+ menu_path = g_strjoinv ("->", gs_app_get_menu_path (app));
+ g_assert_cmpstr (menu_path, ==, "Audio & Video->Music Players");
+
+ /* check addon */
+ addons = gs_app_get_addons (app);
+ g_assert_cmpint (addons->len, ==, 1);
+ addon = g_ptr_array_index (addons, 0);
+ g_assert_cmpstr (gs_app_get_id (addon), ==, "zeus-spell.addon");
+ g_assert_cmpint (gs_app_get_kind (addon), ==, AS_APP_KIND_ADDON);
+ g_assert_cmpint (gs_app_get_state (addon), ==, AS_APP_STATE_AVAILABLE);
+ g_assert_cmpstr (gs_app_get_name (addon), ==, "Spell Check");
+ g_assert_cmpstr (gs_app_get_source_default (addon), ==, "zeus-spell");
+ g_assert_cmpstr (gs_app_get_license (addon), ==,
+ "LicenseRef-free=https://www.debian.org/");
+ g_assert (gs_app_get_pixbuf (addon) == NULL);
+}
+
+static void
+gs_plugin_loader_search_func (GsPluginLoader *plugin_loader)
+{
+ GsApp *app;
+ g_autofree gchar *menu_path = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GsAppList) list = NULL;
+
+ /* get search result based on addon keyword */
+ list = gs_plugin_loader_search (plugin_loader,
+ "spell",
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ NULL,
+ &error);
+ gs_test_flush_main_context ();
+ g_assert_no_error (error);
+ g_assert (list != NULL);
+
+ /* make sure there is one entry, the parent app */
+ g_assert_cmpint (gs_app_list_length (list), ==, 1);
+ app = gs_app_list_index (list, 0);
+ g_assert_cmpstr (gs_app_get_id (app), ==, "zeus.desktop");
+ g_assert_cmpint (gs_app_get_kind (app), ==, AS_APP_KIND_DESKTOP);
+}
+
+static void
+gs_plugin_loader_url_to_app_func (GsPluginLoader *plugin_loader)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GsApp) app = NULL;
+
+ app = gs_plugin_loader_url_to_app (plugin_loader,
+ "dummy://chiron.desktop",
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ NULL,
+ &error);
+ gs_test_flush_main_context ();
+ g_assert_no_error (error);
+ g_assert (app != NULL);
+ g_assert_cmpstr (gs_app_get_id (app), ==, "chiron.desktop");
+ g_assert_cmpint (gs_app_get_kind (app), ==, AS_APP_KIND_DESKTOP);
+}
+
+static void
+gs_plugin_loader_modalias_func (GsPluginLoader *plugin_loader)
+{
+ GsApp *app;
+ g_autofree gchar *menu_path = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GsAppList) list = NULL;
+
+ /* get search result based on addon keyword */
+ list = gs_plugin_loader_search (plugin_loader,
+ "colorhug2",
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ NULL,
+ &error);
+ gs_test_flush_main_context ();
+ g_assert_no_error (error);
+ g_assert (list != NULL);
+
+ /* make sure there is one entry, the parent app */
+ g_assert_cmpint (gs_app_list_length (list), ==, 1);
+ app = gs_app_list_index (list, 0);
+ g_assert_cmpstr (gs_app_get_id (app), ==, "com.hughski.ColorHug2.driver");
+ g_assert_cmpint (gs_app_get_kind (app), ==, AS_APP_KIND_DRIVER);
+ g_assert (gs_app_has_category (app, "Addons"));
+ g_assert (gs_app_has_category (app, "Drivers"));
+}
+
+static void
+gs_plugin_loader_webapps_func (GsPluginLoader *plugin_loader)
+{
+ gboolean ret;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GsApp) app = NULL;
+
+ /* no epiphany, abort */
+ if (!gs_plugin_loader_get_enabled (plugin_loader, "epiphany"))
+ return;
+
+ /* a webapp with a local icon */
+ app = gs_app_new ("arachne.desktop");
+ gs_app_set_kind (app, AS_APP_KIND_WEB_APP);
+ ret = gs_plugin_loader_app_refine (plugin_loader, app,
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ 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_AVAILABLE);
+ g_assert (gs_app_get_pixbuf (app) != NULL);
+}
+
+static void
+gs_plugin_loader_plugin_cache_func (GsPluginLoader *plugin_loader)
+{
+ GsApp *app1;
+ GsApp *app2;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GsAppList) list1 = NULL;
+ g_autoptr(GsAppList) list2 = NULL;
+
+ /* ensure we get the same results back from calling the methods twice */
+ list1 = gs_plugin_loader_get_distro_upgrades (plugin_loader,
+ GS_PLUGIN_REFINE_FLAGS_DEFAULT,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ NULL,
+ &error);
+ gs_test_flush_main_context ();
+ g_assert_no_error (error);
+ g_assert (list1 != NULL);
+ g_assert_cmpint (gs_app_list_length (list1), ==, 1);
+ app1 = gs_app_list_index (list1, 0);
+
+ list2 = gs_plugin_loader_get_distro_upgrades (plugin_loader,
+ GS_PLUGIN_REFINE_FLAGS_DEFAULT,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ NULL,
+ &error);
+ gs_test_flush_main_context ();
+ g_assert_no_error (error);
+ g_assert (list2 != NULL);
+ g_assert_cmpint (gs_app_list_length (list2), ==, 1);
+ app2 = gs_app_list_index (list2, 0);
+
+ /* make sure there is one GObject */
+ g_assert_cmpstr (gs_app_get_id (app1), ==, gs_app_get_id (app2));
+ g_assert (app1 == app2);
+}
+
+static void
+gs_plugin_loader_authentication_func (GsPluginLoader *plugin_loader)
+{
+ GsAuth *auth;
+ gboolean ret;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GsApp) app = NULL;
+ g_autoptr(AsReview) review = NULL;
+ g_autoptr(AsReview) review2 = NULL;
+
+ /* check initial state */
+ auth = gs_plugin_loader_get_auth_by_id (plugin_loader, "dummy");
+ g_assert (GS_IS_AUTH (auth));
+ g_assert_cmpint (gs_auth_get_flags (auth), ==, 0);
+
+ /* do an action that returns a URL */
+ ret = gs_plugin_loader_auth_action (plugin_loader, auth,
+ GS_PLUGIN_ACTION_AUTH_REGISTER,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ NULL, &error);
+ gs_test_flush_main_context ();
+ g_assert_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_AUTH_INVALID);
+ g_assert (!ret);
+ g_clear_error (&error);
+ g_assert (!gs_auth_has_flag (auth, GS_AUTH_FLAG_VALID));
+
+ /* do an action that requires a login */
+ app = gs_app_new (NULL);
+ review = as_review_new ();
+ ret = gs_plugin_loader_review_action (plugin_loader, app, review,
+ GS_PLUGIN_ACTION_REVIEW_REMOVE,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ NULL, &error);
+ gs_test_flush_main_context ();
+ g_assert_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_AUTH_REQUIRED);
+ g_assert (!ret);
+ g_clear_error (&error);
+
+ /* pretend to auth with no credentials */
+ ret = gs_plugin_loader_auth_action (plugin_loader, auth,
+ GS_PLUGIN_ACTION_AUTH_LOGIN,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ NULL, &error);
+ gs_test_flush_main_context ();
+ g_assert_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_AUTH_INVALID);
+ g_assert (!ret);
+ g_clear_error (&error);
+ g_assert (!gs_auth_has_flag (auth, GS_AUTH_FLAG_VALID));
+
+ /* auth again with correct credentials */
+ gs_auth_set_username (auth, "dummy");
+ gs_auth_set_password (auth, "dummy");
+ ret = gs_plugin_loader_auth_action (plugin_loader, auth,
+ GS_PLUGIN_ACTION_AUTH_LOGIN,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ NULL, &error);
+ gs_test_flush_main_context ();
+ g_assert_no_error (error);
+ g_assert (ret);
+ g_assert (gs_auth_has_flag (auth, GS_AUTH_FLAG_VALID));
+
+ /* do the action that requires a login */
+ review2 = as_review_new ();
+ ret = gs_plugin_loader_review_action (plugin_loader, app, review2,
+ GS_PLUGIN_ACTION_REVIEW_REMOVE,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ NULL, &error);
+ gs_test_flush_main_context ();
+ g_assert_no_error (error);
+ g_assert (ret);
+}
+
+static void
+gs_plugin_loader_wildcard_func (GsPluginLoader *plugin_loader)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GsAppList) list = NULL;
+
+ list = gs_plugin_loader_get_popular (plugin_loader,
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON,
+ GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
+ NULL,
+ &error);
+ gs_test_flush_main_context ();
+ g_assert_no_error (error);
+ g_assert (list != NULL);
+ g_assert_cmpint (gs_app_list_length (list), ==, 1);
+}
+
+int
+main (int argc, char **argv)
+{
+ gboolean ret;
+ g_autofree gchar *xml = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GsPluginLoader) plugin_loader = NULL;
+ const gchar *whitelist[] = {
+ "appstream",
+ "dummy",
+ "generic-updates",
+ "hardcoded-blacklist",
+ "desktop-categories",
+ "desktop-menu-path",
+ "icons",
+ "key-colors",
+ "provenance",
+ "provenance-license",
+ NULL
+ };
+
+ g_test_init (&argc, &argv, NULL);
+ g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+
+ /* set all the things required as a dummy test harness */
+ g_setenv ("GS_SELF_TEST_LOCALE", "en_GB", TRUE);
+ g_setenv ("GS_SELF_TEST_DUMMY_ENABLE", "1", TRUE);
+ g_setenv ("GS_SELF_TEST_PROVENANCE_SOURCES", "london*,boston", TRUE);
+ g_setenv ("GS_SELF_TEST_PROVENANCE_LICENSE_SOURCES", "london*,boston", TRUE);
+ g_setenv ("GS_SELF_TEST_PROVENANCE_LICENSE_URL", "https://www.debian.org/", TRUE);
+
+ xml = g_strdup ("<?xml version=\"1.0\"?>\n"
+ "<components version=\"0.9\">\n"
+ " <component type=\"desktop\">\n"
+ " <id>chiron.desktop</id>\n"
+ " <pkgname>chiron</pkgname>\n"
+ " </component>\n"
+ " <component type=\"desktop\">\n"
+ " <id>zeus.desktop</id>\n"
+ " <name>Zeus</name>\n"
+ " <summary>A teaching application</summary>\n"
+ " <pkgname>zeus</pkgname>\n"
+ " <icon type=\"stock\">drive-harddisk</icon>\n"
+ " <categories>\n"
+ " <category>AudioVideo</category>\n"
+ " <category>Player</category>\n"
+ " </categories>\n"
+ " <languages>\n"
+ " <lang percentage=\"100\">en_GB</lang>\n"
+ " </languages>\n"
+ " </component>\n"
+ " <component type=\"desktop\">\n"
+ " <id>mate-spell.desktop</id>\n"
+ " <name>Spell</name>\n"
+ " <summary>A spelling application for MATE</summary>\n"
+ " <pkgname>mate-spell</pkgname>\n"
+ " <icon type=\"stock\">drive-harddisk</icon>\n"
+ " <project_group>MATE</project_group>\n"
+ " </component>\n"
+ " <component type=\"addon\">\n"
+ " <id>zeus-spell.addon</id>\n"
+ " <extends>zeus.desktop</extends>\n"
+ " <name>Spell Check</name>\n"
+ " <summary>Check the spelling when teaching</summary>\n"
+ " <pkgname>zeus-spell</pkgname>\n"
+ " </component>\n"
+ " <component type=\"desktop\">\n"
+ " <id>Uninstall Zeus.desktop</id>\n"
+ " <name>Uninstall Zeus</name>\n"
+ " <summary>Uninstall the teaching application</summary>\n"
+ " <icon type=\"stock\">drive-harddisk</icon>\n"
+ " </component>\n"
+ " <component type=\"os-upgrade\">\n"
+ " <id>org.fedoraproject.release-rawhide.upgrade</id>\n"
+ " <summary>Release specific tagline</summary>\n"
+ " </component>\n"
+ "</components>\n");
+ g_setenv ("GS_SELF_TEST_APPSTREAM_XML", xml, TRUE);
+
+ /* only critical and error are fatal */
+ g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
+
+ /* we can only load this once per process */
+ plugin_loader = gs_plugin_loader_new ();
+ g_signal_connect (plugin_loader, "status-changed",
+ G_CALLBACK (gs_plugin_loader_status_changed_cb), NULL);
+ gs_plugin_loader_add_location (plugin_loader, LOCALPLUGINDIR);
+ gs_plugin_loader_add_location (plugin_loader, LOCALPLUGINDIR_CORE);
+ ret = gs_plugin_loader_setup (plugin_loader,
+ (gchar**) whitelist,
+ NULL,
+ GS_PLUGIN_FAILURE_FLAGS_NONE,
+ NULL,
+ &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ g_assert (!gs_plugin_loader_get_enabled (plugin_loader, "notgoingtoexist"));
+ g_assert (gs_plugin_loader_get_enabled (plugin_loader, "appstream"));
+ g_assert (gs_plugin_loader_get_enabled (plugin_loader, "dummy"));
+
+ /* plugin tests go here */
+ g_test_add_data_func ("/gnome-software/plugin-loader{wildcard}",
+ plugin_loader,
+ (GTestDataFunc) gs_plugin_loader_wildcard_func);
+ g_test_add_data_func ("/gnome-software/plugin-loader{authentication}",
+ plugin_loader,
+ (GTestDataFunc) gs_plugin_loader_authentication_func);
+ g_test_add_data_func ("/gnome-software/plugin-loader{plugin-cache}",
+ plugin_loader,
+ (GTestDataFunc) gs_plugin_loader_plugin_cache_func);
+ g_test_add_data_func ("/gnome-software/plugin-loader{key-colors}",
+ plugin_loader,
+ (GTestDataFunc) gs_plugin_loader_key_colors_func);
+ g_test_add_data_func ("/gnome-software/plugin-loader{search}",
+ plugin_loader,
+ (GTestDataFunc) gs_plugin_loader_search_func);
+ g_test_add_data_func ("/gnome-software/plugin-loader{url-to-app}",
+ plugin_loader,
+ (GTestDataFunc) gs_plugin_loader_url_to_app_func);
+ g_test_add_data_func ("/gnome-software/plugin-loader{install}",
+ plugin_loader,
+ (GTestDataFunc) gs_plugin_loader_install_func);
+ g_test_add_data_func ("/gnome-software/plugin-loader{error}",
+ plugin_loader,
+ (GTestDataFunc) gs_plugin_loader_error_func);
+ g_test_add_data_func ("/gnome-software/plugin-loader{installed}",
+ plugin_loader,
+ (GTestDataFunc) gs_plugin_loader_installed_func);
+ g_test_add_data_func ("/gnome-software/plugin-loader{refine}",
+ plugin_loader,
+ (GTestDataFunc) gs_plugin_loader_refine_func);
+ g_test_add_data_func ("/gnome-software/plugin-loader{updates}",
+ plugin_loader,
+ (GTestDataFunc) gs_plugin_loader_updates_func);
+ g_test_add_data_func ("/gnome-software/plugin-loader{distro-upgrades}",
+ plugin_loader,
+ (GTestDataFunc) gs_plugin_loader_distro_upgrades_func);
+
+ return g_test_run ();
+}
+
+/* vim: set noexpandtab: */
diff --git a/plugins/gs-appstream.c b/plugins/gs-appstream.c
deleted file mode 100644
index 673f626..0000000
--- a/plugins/gs-appstream.c
+++ /dev/null
@@ -1,1147 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2015-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 <gnome-software.h>
-
-#include "gs-appstream.h"
-
-#define GS_APPSTREAM_MAX_SCREENSHOTS 5
-
-GsApp *
-gs_appstream_create_app (GsPlugin *plugin, AsApp *item, GError **error)
-{
- const gchar *unique_id = as_app_get_unique_id (item);
- GsApp *app = gs_plugin_cache_lookup (plugin, unique_id);
- if (app == NULL) {
- app = gs_app_new (as_app_get_id (item));
- gs_app_set_metadata (app, "GnomeSoftware::Creator",
- gs_plugin_get_name (plugin));
- if (!gs_appstream_refine_app (plugin, app, item, error)) {
- g_object_unref (app);
- return NULL;
- }
- gs_plugin_cache_add (plugin, unique_id, app);
- }
- return app;
-}
-
-static AsIcon *
-gs_appstream_get_icon_by_kind (AsApp *app, AsIconKind icon_kind)
-{
- GPtrArray *icons;
- guint i;
-
- icons = as_app_get_icons (app);
- for (i = 0; i < icons->len; i++) {
- AsIcon *icon = g_ptr_array_index (icons, i);
- if (as_icon_get_kind (icon) == icon_kind)
- return icon;
- }
- return NULL;
-}
-
-static AsIcon *
-gs_appstream_get_icon_by_kind_and_size (AsApp *app, AsIconKind icon_kind, guint sz)
-{
- GPtrArray *icons;
- guint i;
-
- icons = as_app_get_icons (app);
- for (i = 0; i < icons->len; i++) {
- AsIcon *icon = g_ptr_array_index (icons, i);
- if (as_icon_get_kind (icon) == icon_kind &&
- as_icon_get_width (icon) == sz &&
- as_icon_get_height (icon) == sz)
- return icon;
- }
- return NULL;
-}
-
-static void
-gs_refine_item_icon (GsPlugin *plugin, GsApp *app, AsApp *item)
-{
- AsIcon *icon;
-
- /* try a stock icon first */
- icon = gs_appstream_get_icon_by_kind (item, AS_ICON_KIND_STOCK);
- if (icon != NULL)
- gs_app_add_icon (app, icon);
-
- /* if HiDPI get a 128px cached icon */
- if (gs_plugin_get_scale (plugin) == 2) {
- icon = gs_appstream_get_icon_by_kind_and_size (item,
- AS_ICON_KIND_CACHED,
- 128);
- if (icon != NULL)
- gs_app_add_icon (app, icon);
- }
-
- /* non-HiDPI cached icon */
- icon = gs_appstream_get_icon_by_kind_and_size (item,
- AS_ICON_KIND_CACHED,
- 64);
- if (icon != NULL)
- gs_app_add_icon (app, icon);
-
- /* prefer local */
- icon = gs_appstream_get_icon_by_kind (item, AS_ICON_KIND_LOCAL);
- if (icon != NULL) {
- /* does not exist, so try to find using the icon theme */
- if (as_icon_get_kind (icon) == AS_ICON_KIND_LOCAL &&
- as_icon_get_filename (icon) == NULL) {
- g_debug ("converting missing LOCAL icon %s to STOCK",
- as_icon_get_name (icon));
- as_icon_set_kind (icon, AS_ICON_KIND_STOCK);
- }
- gs_app_add_icon (app, icon);
- }
-
- /* remote as a last resort */
- icon = gs_appstream_get_icon_by_kind (item, AS_ICON_KIND_REMOTE);
- if (icon != NULL)
- gs_app_add_icon (app, icon);
-}
-
-static gboolean
-gs_appstream_refine_add_addons (GsPlugin *plugin,
- GsApp *app,
- AsApp *item,
- GError **error)
-{
- GPtrArray *addons;
- guint i;
- g_autoptr(AsProfileTask) ptask = NULL;
-
- /* we only care about addons to desktop apps */
- if (gs_app_get_kind (app) != AS_APP_KIND_DESKTOP)
- return TRUE;
-
- /* search categories for the search term */
- ptask = as_profile_start (gs_plugin_get_profile (plugin),
- "appstream::refine-addons{%s}",
- gs_app_get_unique_id (app));
- g_assert (ptask != NULL);
-
- addons = as_app_get_addons (item);
- if (addons == NULL)
- return TRUE;
-
- for (i = 0; i < addons->len; i++) {
- AsApp *as_addon = g_ptr_array_index (addons, i);
- g_autoptr(GsApp) addon = NULL;
-
- addon = gs_appstream_create_app (plugin, as_addon, error);
- if (addon == NULL)
- return FALSE;
-
- /* add all the data we can */
- if (!gs_appstream_refine_app (plugin, addon, as_addon, error))
- return FALSE;
- gs_app_add_addon (app, addon);
- }
- return TRUE;
-}
-
-static void
-gs_appstream_refine_add_screenshots (GsApp *app, AsApp *item)
-{
- AsScreenshot *ss;
- GPtrArray *images_as;
- GPtrArray *screenshots_as;
- guint i;
-
- /* do we have any to add */
- screenshots_as = as_app_get_screenshots (item);
- if (screenshots_as->len == 0)
- return;
-
- /* does the app already have some */
- gs_app_add_kudo (app, GS_APP_KUDO_HAS_SCREENSHOTS);
- if (gs_app_get_screenshots(app)->len > 0)
- return;
-
- /* add any we know */
- for (i = 0; i < screenshots_as->len &&
- i < GS_APPSTREAM_MAX_SCREENSHOTS; i++) {
- ss = g_ptr_array_index (screenshots_as, i);
- images_as = as_screenshot_get_images (ss);
- if (images_as->len == 0)
- continue;
- if (as_screenshot_get_kind (ss) == AS_SCREENSHOT_KIND_UNKNOWN)
- continue;
- gs_app_add_screenshot (app, ss);
- }
-}
-
-static void
-gs_appstream_refine_add_reviews (GsApp *app, AsApp *item)
-{
- AsReview *review;
- GPtrArray *reviews;
- guint i;
-
- /* do we have any to add */
- if (gs_app_get_reviews(app)->len > 0)
- return;
- reviews = as_app_get_reviews (item);
- for (i = 0; i < reviews->len; i++) {
- review = g_ptr_array_index (reviews, i);
- gs_app_add_review (app, review);
- }
-}
-
-static void
-gs_appstream_refine_add_provides (GsApp *app, AsApp *item)
-{
- AsProvide *provide;
- GPtrArray *provides;
- guint i;
-
- /* do we have any to add */
- if (gs_app_get_provides(app)->len > 0)
- return;
- provides = as_app_get_provides (item);
- for (i = 0; i < provides->len; i++) {
- provide = g_ptr_array_index (provides, i);
- gs_app_add_provide (app, provide);
- }
-}
-
-static gboolean
-gs_appstream_is_recent_release (AsApp *app)
-{
- AsRelease *release;
- GPtrArray *releases;
- guint64 secs;
-
- /* get newest release */
- releases = as_app_get_releases (app);
- if (releases->len == 0)
- return FALSE;
- release = g_ptr_array_index (releases, 0);
-
- /* is last build less than one year ago? */
- secs = ((guint64) g_get_real_time () / G_USEC_PER_SEC) -
- as_release_get_timestamp (release);
- return secs / (60 * 60 * 24) < 365;
-}
-
-static gboolean
-gs_appstream_are_screenshots_perfect (AsApp *app)
-{
- AsImage *image;
- AsScreenshot *screenshot;
- GPtrArray *screenshots;
- guint height;
- guint i;
- guint width;
-
- screenshots = as_app_get_screenshots (app);
- if (screenshots->len == 0)
- return FALSE;
- for (i = 0; i < screenshots->len; i++) {
-
- /* get the source image as the thumbs will be resized & padded */
- screenshot = g_ptr_array_index (screenshots, i);
- image = as_screenshot_get_source (screenshot);
- if (image == NULL)
- return FALSE;
-
- width = as_image_get_width (image);
- height = as_image_get_height (image);
-
- /* too small */
- if (width < AS_IMAGE_LARGE_WIDTH || height < AS_IMAGE_LARGE_HEIGHT)
- return FALSE;
-
- /* too large */
- if (width > AS_IMAGE_LARGE_WIDTH * 2 || height > AS_IMAGE_LARGE_HEIGHT * 2)
- return FALSE;
-
- /* not 16:9 */
- if ((width / 16) * 9 != height)
- return FALSE;
- }
- return TRUE;
-}
-
-static void
-gs_appstream_copy_metadata (GsApp *app, AsApp *item)
-{
- GHashTable *hash;
- GList *l;
- g_autoptr(GList) keys = NULL;
-
- hash = as_app_get_metadata (item);
- keys = g_hash_table_get_keys (hash);
- for (l = keys; l != NULL; l = l->next) {
- const gchar *key = l->data;
- const gchar *value = g_hash_table_lookup (hash, key);
- if (gs_app_get_metadata_item (app, key) != NULL)
- continue;
- gs_app_set_metadata (app, key, value);
- }
-}
-
-GsApp *
-gs_appstream_create_runtime (GsPlugin *plugin,
- GsApp *parent,
- const gchar *runtime)
-{
- g_autofree gchar *source = NULL;
- g_auto(GStrv) split = NULL;
- g_autoptr(GsApp) app_cache = NULL;
- g_autoptr(GsApp) app = NULL;
-
- /* get the name/arch/branch */
- split = g_strsplit (runtime, "/", -1);
- if (g_strv_length (split) != 3)
- return NULL;
-
- /* create the complete GsApp from the single string */
- app = gs_app_new (split[0]);
- source = g_strdup_printf ("runtime/%s", runtime);
- gs_app_add_source (app, source);
- gs_app_set_bundle_kind (app, AS_BUNDLE_KIND_FLATPAK);
- gs_app_set_kind (app, AS_APP_KIND_RUNTIME);
- gs_app_set_branch (app, split[2]);
- gs_app_set_scope (app, gs_app_get_scope (parent));
-
- /* search in the cache */
- app_cache = gs_plugin_cache_lookup (plugin, gs_app_get_unique_id (app));
- if (app_cache != NULL) {
- /* since the cached runtime can have been created somewhere else
- * (we're using a global cache), we need to make sure that a
- * source is set */
- if (gs_app_get_source_default (app_cache) == NULL)
- gs_app_add_source (app_cache, source);
- return g_steal_pointer (&app_cache);
- }
-
- /* save in the cache */
- gs_plugin_cache_add (plugin, NULL, app);
- return g_steal_pointer (&app);
-}
-
-static void
-gs_refine_item_management_plugin (GsPlugin *plugin, GsApp *app, AsApp *item)
-{
- GPtrArray *bundles;
- const gchar *management_plugin = NULL;
- const gchar *runtime = NULL;
- guint i;
-
- /* allow override */
- management_plugin = as_app_get_metadata_item (item, "GnomeSoftware::Plugin");
- if (management_plugin != NULL)
- gs_app_set_management_plugin (app, management_plugin);
-
- /* find the default bundle kind */
- bundles = as_app_get_bundles (item);
- for (i = 0; i < bundles->len; i++) {
- AsBundle *bundle = g_ptr_array_index (bundles, i);
- AsBundleKind kind = as_bundle_get_kind (bundle);
-
- gs_app_add_source (app, as_bundle_get_id (bundle));
-
- /* automatically add runtime */
- if (kind == AS_BUNDLE_KIND_FLATPAK) {
- runtime = as_bundle_get_runtime (bundle);
- if (runtime != NULL) {
- g_autoptr(GsApp) app2 = NULL;
- app2 = gs_appstream_create_runtime (plugin, app, runtime);
- if (app2 != NULL) {
- if (app == app2) {
- g_warning ("%s runtime cannot have runtime!",
- gs_app_get_unique_id (app));
- break;
- }
- g_debug ("runtime for %s is %s",
- gs_app_get_unique_id (app),
- runtime);
- gs_app_set_update_runtime (app, app2);
- }
- }
- break;
- }
- }
-}
-
-static gboolean
-gs_appstream_refine_app_updates (GsPlugin *plugin,
- GsApp *app,
- AsApp *item,
- GError **error)
-{
- AsUrgencyKind urgency_best = AS_URGENCY_KIND_UNKNOWN;
- GPtrArray *releases;
- g_autoptr(GPtrArray) updates_list = NULL;
-
- /* only for UPDATABLE apps */
- if (!gs_app_is_updatable (app))
- return TRUE;
-
- /* make a list of valid updates */
- updates_list = g_ptr_array_new ();
- releases = as_app_get_releases (item);
- for (guint i = 0; i < releases->len; i++) {
- AsRelease *rel = g_ptr_array_index (releases, i);
-
- /* already installed */
- g_debug ("installable update %s [%u]",
- as_release_get_version (rel),
- as_release_get_state (rel));
- if (as_release_get_state (rel) == AS_RELEASE_STATE_INSTALLED)
- continue;
-
- /* use the 'worst' urgency, e.g. critical over enhancement */
- if (as_release_get_urgency (rel) > urgency_best)
- urgency_best = as_release_get_urgency (rel);
-
- /* add updates with a description */
- if (as_release_get_description (rel, NULL) == NULL)
- continue;
- g_ptr_array_add (updates_list, rel);
- }
-
- /* only set if known */
- if (urgency_best != AS_URGENCY_KIND_UNKNOWN)
- gs_app_set_update_urgency (app, urgency_best);
-
- /* no prefix on each release */
- if (updates_list->len == 1) {
- g_autofree gchar *desc = NULL;
- AsRelease *rel = g_ptr_array_index (updates_list, 0);
- desc = as_markup_convert (as_release_get_description (rel, NULL),
- AS_MARKUP_CONVERT_FORMAT_SIMPLE,
- error);
- if (desc == NULL) {
- gs_utils_error_convert_appstream (error);
- return FALSE;
- }
- gs_app_set_update_details (app, desc);
-
- /* get the descriptions with a version prefix */
- } else if (updates_list->len > 1) {
- g_autoptr(GString) update_desc = g_string_new ("");
- for (guint i = 0; i < updates_list->len; i++) {
- g_autofree gchar *desc = NULL;
- AsRelease *rel = g_ptr_array_index (updates_list, i);
- desc = as_markup_convert (as_release_get_description (rel, NULL),
- AS_MARKUP_CONVERT_FORMAT_SIMPLE,
- error);
- if (desc == NULL) {
- gs_utils_error_convert_appstream (error);
- return FALSE;
- }
- g_string_append_printf (update_desc,
- "Version %s:\n%s\n\n",
- as_release_get_version (rel),
- desc);
- }
-
- /* remove trailing newlines */
- if (update_desc->len > 2)
- g_string_truncate (update_desc, update_desc->len - 2);
- gs_app_set_update_details (app, update_desc->str);
- }
-
- /* if there is no already set update version use the newest */
- if (gs_app_get_update_version (app) == NULL) {
- AsRelease *rel = as_app_get_release_default (item);
- if (rel != NULL)
- gs_app_set_update_version (app, as_release_get_version (rel));
- }
-
- /* success */
- return TRUE;
-}
-
-/**
- * _gs_utils_locale_has_translations:
- * @locale: A locale, e.g. "en_GB"
- *
- * Looks up if the locale is likely to have translations.
- *
- * Returns: %TRUE if the locale should have translations
- **/
-static gboolean
-_gs_utils_locale_has_translations (const gchar *locale)
-{
- if (g_strcmp0 (locale, "C") == 0)
- return FALSE;
- if (g_strcmp0 (locale, "en") == 0)
- return FALSE;
- if (g_strcmp0 (locale, "en_US") == 0)
- return FALSE;
- return TRUE;
-}
-
-static AsBundleKind
-gs_appstream_get_bundle_kind (AsApp *item)
-{
- GPtrArray *bundles;
- GPtrArray *pkgnames;
-
- /* prefer bundle */
- bundles = as_app_get_bundles (item);
- if (bundles->len > 0) {
- AsBundle *bundle = g_ptr_array_index (bundles, 0);
- if (as_bundle_get_kind (bundle) != AS_BUNDLE_KIND_UNKNOWN)
- return as_bundle_get_kind (bundle);
- }
-
- /* fallback to packages */
- pkgnames = as_app_get_pkgnames (item);
- if (pkgnames->len > 0)
- return AS_BUNDLE_KIND_PACKAGE;
-
- /* nothing */
- return AS_BUNDLE_KIND_UNKNOWN;
-}
-
-static gboolean
-gs_appstream_origin_valid (const gchar *origin)
-{
- if (origin == NULL)
- return FALSE;
- if (g_strcmp0 (origin, "") == 0)
- return FALSE;
- return TRUE;
-}
-
-gboolean
-gs_appstream_refine_app (GsPlugin *plugin,
- GsApp *app,
- AsApp *item,
- GError **error)
-{
- AsRequire *req;
- g_autoptr(GError) error_local = NULL;
- GHashTable *urls;
- GPtrArray *array;
- GPtrArray *pkgnames;
- GPtrArray *kudos;
- const gchar *current_desktop;
- const gchar *tmp;
- guint i;
- g_autoptr(AsProfileTask) ptask = NULL;
-
- /* search categories for the search term */
- ptask = as_profile_start (gs_plugin_get_profile (plugin),
- "appstream::refine-app{%s}",
- gs_app_get_unique_id (app));
- g_assert (ptask != NULL);
-
- /* set the kind to be more precise */
- if (gs_app_get_kind (app) == AS_APP_KIND_UNKNOWN ||
- gs_app_get_kind (app) == AS_APP_KIND_GENERIC) {
- gs_app_set_kind (app, as_app_get_kind (item));
- }
-
- /* is installed already */
- if (gs_app_get_state (app) == AS_APP_STATE_UNKNOWN &&
- as_app_get_state (item) != AS_APP_STATE_UNKNOWN) {
- gs_app_set_state (app, as_app_get_state (item));
- }
-
- /* is compatible */
- req = as_app_get_require_by_value (item,
- AS_REQUIRE_KIND_ID,
- "org.gnome.Software.desktop");
- if (req != NULL) {
- if (!as_require_version_compare (req, PACKAGE_VERSION, &error_local)) {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_NOT_SUPPORTED,
- "not for this gnome-software: %s",
- error_local->message);
- return FALSE;
- }
- }
-
- /* types we can never launch */
- switch (gs_app_get_kind (app)) {
- case AS_APP_KIND_ADDON:
- case AS_APP_KIND_CODEC:
- case AS_APP_KIND_FIRMWARE:
- case AS_APP_KIND_FONT:
- case AS_APP_KIND_GENERIC:
- case AS_APP_KIND_INPUT_METHOD:
- case AS_APP_KIND_LOCALIZATION:
- case AS_APP_KIND_OS_UPDATE:
- case AS_APP_KIND_OS_UPGRADE:
- case AS_APP_KIND_RUNTIME:
- case AS_APP_KIND_SOURCE:
- gs_app_add_quirk (app, AS_APP_QUIRK_NOT_LAUNCHABLE);
- break;
- default:
- break;
- }
-
- /* set management plugin automatically */
- gs_refine_item_management_plugin (plugin, app, item);
-
- /* set id */
- 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 */
- if (gs_app_get_metadata_item (app, "appstream::source-file") == NULL) {
-#if AS_CHECK_VERSION(0,6,9)
- AsFormat *format = as_app_get_format_by_kind (item, AS_FORMAT_KIND_DESKTOP);
- if (format != NULL) {
- gs_app_set_metadata (app, "appstream::source-file",
- as_format_get_filename (format));
- }
-#else
- gs_app_set_metadata (app, "appstream::source-file",
- as_app_get_source_file (item));
-#endif
- }
-
- /* scope */
- if (gs_app_get_scope (app) == AS_APP_SCOPE_UNKNOWN &&
- as_app_get_scope (item) != AS_APP_SCOPE_UNKNOWN)
- gs_app_set_scope (app, as_app_get_scope (item));
-
- /* set branch */
- if (as_app_get_branch (item) != NULL &&
- gs_app_get_branch (app) == NULL)
- gs_app_set_branch (app, as_app_get_branch (item));
-
- /* set content rating */
- array = as_app_get_content_ratings (item);
- for (i = 0; i < array->len; i++) {
- AsContentRating *cr = g_ptr_array_index (array, i);
- if (g_strcmp0 (as_content_rating_get_kind (cr), "oars-1.0") == 0) {
- gs_app_set_content_rating (app, cr);
- break;
- }
- }
-
- /* bundle-kind */
- if (gs_app_get_bundle_kind (app) == AS_BUNDLE_KIND_UNKNOWN)
- gs_app_set_bundle_kind (app, gs_appstream_get_bundle_kind (item));
-
- /* set name */
- tmp = as_app_get_name (item, NULL);
- if (tmp != NULL)
- gs_app_set_name (app, GS_APP_QUALITY_HIGHEST, tmp);
-
- /* set summary */
- tmp = as_app_get_comment (item, NULL);
- if (tmp != NULL) {
- gs_app_set_summary (app, GS_APP_QUALITY_HIGHEST, tmp);
- }
-
- /* add urls */
- urls = as_app_get_urls (item);
- if (g_hash_table_size (urls) > 0 &&
- gs_app_get_url (app, AS_URL_KIND_HOMEPAGE) == NULL) {
- GList *l;
- g_autoptr(GList) keys = NULL;
- keys = g_hash_table_get_keys (urls);
- for (l = keys; l != NULL; l = l->next) {
- gs_app_set_url (app,
- as_url_kind_from_string (l->data),
- g_hash_table_lookup (urls, l->data));
- }
- }
-
- /* set license */
- if (as_app_get_project_license (item) != NULL && gs_app_get_license (app) == NULL)
- gs_app_set_license (app,
- GS_APP_QUALITY_HIGHEST,
- as_app_get_project_license (item));
-
- /* set keywords */
- if (as_app_get_keywords (item, NULL) != NULL &&
- gs_app_get_keywords (app) == NULL) {
- gs_app_set_keywords (app, as_app_get_keywords (item, NULL));
- gs_app_add_kudo (app, GS_APP_KUDO_HAS_KEYWORDS);
- }
-
- /* set origin */
- if (as_app_get_origin (item) != NULL &&
- gs_app_get_origin (app) == NULL ) {
- tmp = as_app_get_unique_id (item);
- if (tmp != NULL) {
- if (g_str_has_prefix (tmp, "user/flatpak/") ||
- g_str_has_prefix (tmp, "system/flatpak/"))
- gs_app_set_origin (app, as_app_get_origin (item));
- }
- }
-
- /* set description */
- tmp = as_app_get_description (item, NULL);
- if (tmp != NULL) {
- g_autofree gchar *from_xml = NULL;
- from_xml = as_markup_convert_simple (tmp, error);
- if (from_xml == NULL) {
- gs_utils_error_convert_appstream (error);
- g_prefix_error (error, "trying to parse '%s': ", tmp);
- return FALSE;
- }
- gs_app_set_description (app, GS_APP_QUALITY_HIGHEST, from_xml);
- }
-
- /* set icon */
- if (as_app_get_icon_default (item) != NULL &&
- gs_app_get_icons(app)->len == 0)
- gs_refine_item_icon (plugin, app, item);
-
- /* set categories */
- array = as_app_get_categories (item);
- if (array != NULL && gs_app_get_categories (app)->len == 0) {
- for (i = 0; i < array->len; i++) {
- tmp = g_ptr_array_index (array, i);
- gs_app_add_category (app, tmp);
- }
- }
-
- /* set project group */
- if (as_app_get_project_group (item) != NULL &&
- gs_app_get_project_group (app) == NULL)
- gs_app_set_project_group (app, as_app_get_project_group (item));
-
- /*
- * Set the core applications for the current desktop that cannot be
- * removed -- but note: XDG_CURRENT_DESKTOP="GNOME" is different to
- * XDG_CURRENT_DESKTOP="Ubuntu:GNOME" here.
- *
- * To define what is compulsory for the hybrid desktop either:
- *
- * - Add an appstream merge file downstream with the tag
- * <compulsory_for_desktop>Ubuntu:GNOME</compulsory_for_desktop>
- *
- * - Get upstream projects to add the <compulsory_for_desktop> tag
- */
- array = as_app_get_compulsory_for_desktops (item);
- current_desktop = g_getenv ("XDG_CURRENT_DESKTOP");
- for (i = 0; i < array->len; i++) {
- tmp = g_ptr_array_index (array, i);
- if (g_strcmp0 (current_desktop, tmp) == 0) {
- gs_app_add_quirk (app, AS_APP_QUIRK_COMPULSORY);
- break;
- }
- }
-
- /* set id kind */
- if (gs_app_get_kind (app) == AS_APP_KIND_UNKNOWN)
- gs_app_set_kind (app, as_app_get_kind (item));
-
- /* copy all the metadata */
- gs_appstream_copy_metadata (app, item);
-
- /* set package names */
- pkgnames = as_app_get_pkgnames (item);
- if (pkgnames->len > 0 && gs_app_get_sources(app)->len == 0)
- gs_app_set_sources (app, pkgnames);
-
- /* set addons */
- if (!gs_appstream_refine_add_addons (plugin, app, item, error))
- return FALSE;
-
- /* set screenshots */
- gs_appstream_refine_add_screenshots (app, item);
-
- /* set reviews */
- gs_appstream_refine_add_reviews (app, item);
-
- /* set provides */
- gs_appstream_refine_add_provides (app, item);
-
- /* are the screenshots perfect */
- if (gs_appstream_are_screenshots_perfect (item))
- gs_app_add_kudo (app, GS_APP_KUDO_PERFECT_SCREENSHOTS);
-
- /* was this application released recently */
- if (gs_appstream_is_recent_release (item))
- gs_app_add_kudo (app, GS_APP_KUDO_RECENT_RELEASE);
-
- /* add kudos */
- tmp = gs_plugin_get_locale (plugin);
- if (!_gs_utils_locale_has_translations (tmp) ||
- as_app_get_language (item, tmp) > 50)
- gs_app_add_kudo (app, GS_APP_KUDO_MY_LANGUAGE);
-
- /* add a kudo to featured and popular apps */
- if (as_app_has_kudo (item, "GnomeSoftware::popular"))
- gs_app_add_kudo (app, GS_APP_KUDO_FEATURED_RECOMMENDED);
- if (as_app_has_category (item, "featured"))
- gs_app_add_kudo (app, GS_APP_KUDO_FEATURED_RECOMMENDED);
-
- /* add new-style kudos */
- kudos = as_app_get_kudos (item);
- for (i = 0; i < kudos->len; i++) {
- tmp = g_ptr_array_index (kudos, i);
- switch (as_kudo_kind_from_string (tmp)) {
- case AS_KUDO_KIND_SEARCH_PROVIDER:
- gs_app_add_kudo (app, GS_APP_KUDO_SEARCH_PROVIDER);
- break;
- case AS_KUDO_KIND_USER_DOCS:
- gs_app_add_kudo (app, GS_APP_KUDO_INSTALLS_USER_DOCS);
- break;
- case AS_KUDO_KIND_APP_MENU:
- gs_app_add_kudo (app, GS_APP_KUDO_USES_APP_MENU);
- break;
- case AS_KUDO_KIND_MODERN_TOOLKIT:
- gs_app_add_kudo (app, GS_APP_KUDO_MODERN_TOOLKIT);
- break;
- case AS_KUDO_KIND_NOTIFICATIONS:
- gs_app_add_kudo (app, GS_APP_KUDO_USES_NOTIFICATIONS);
- break;
- case AS_KUDO_KIND_HIGH_CONTRAST:
- gs_app_add_kudo (app, GS_APP_KUDO_HIGH_CONTRAST);
- break;
- case AS_KUDO_KIND_HI_DPI_ICON:
- gs_app_add_kudo (app, GS_APP_KUDO_HI_DPI_ICON);
- break;
- default:
- break;
- }
- }
-
- /* we saved the origin hostname in the metadata */
- tmp = as_app_get_metadata_item (item, "GnomeSoftware::OriginHostnameUrl");
- if (tmp != NULL && gs_app_get_origin_hostname (app) == NULL)
- gs_app_set_origin_hostname (app, tmp);
-
- /* we have an origin in the XML */
- if (gs_app_get_origin (app) == NULL &&
- gs_appstream_origin_valid (as_app_get_origin (item)))
- gs_app_set_origin (app, as_app_get_origin (item));
-
- /* is there any update information */
- if (!gs_appstream_refine_app_updates (plugin, app, item, error))
- return FALSE;
-
- return TRUE;
-}
-
-static gboolean
-gs_appstream_store_search_item (GsPlugin *plugin,
- AsApp *item,
- gchar **values,
- GsAppList *list,
- GCancellable *cancellable,
- GError **error)
-{
- AsApp *item_tmp;
- GPtrArray *addons;
- guint i;
- guint match_value;
- g_autoptr(GsApp) app = NULL;
-
- /* match against the app or any of the addons */
- match_value = as_app_search_matches_all (item, values);
- addons = as_app_get_addons (item);
- for (i = 0; i < addons->len; i++) {
- item_tmp = g_ptr_array_index (addons, i);
- match_value |= as_app_search_matches_all (item_tmp, values);
- }
-
- /* no match */
- if (match_value == 0)
- return TRUE;
-
- /* create app */
- app = gs_appstream_create_app (plugin, item, error);
- if (app == NULL)
- return FALSE;
- gs_app_set_match_value (app, match_value);
- gs_app_list_add (list, app);
- return TRUE;
-}
-
-gboolean
-gs_appstream_store_search (GsPlugin *plugin,
- AsStore *store,
- gchar **values,
- GsAppList *list,
- GCancellable *cancellable,
- GError **error)
-{
- AsApp *item;
- GPtrArray *array;
- gboolean ret = TRUE;
- guint i;
- g_autoptr(AsProfileTask) ptask = NULL;
-
- /* search categories for the search term */
- ptask = as_profile_start_literal (gs_plugin_get_profile (plugin),
- "appstream::search");
- g_assert (ptask != NULL);
- array = as_store_get_apps (store);
- for (i = 0; i < array->len; i++) {
- if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
- gs_utils_error_convert_gio (error);
- return FALSE;
- }
-
- item = g_ptr_array_index (array, i);
- ret = gs_appstream_store_search_item (plugin, item,
- values, list,
- cancellable, error);
- if (!ret)
- return FALSE;
- }
- return TRUE;
-}
-
-static gboolean
-_as_app_matches_desktop_group_set (AsApp *app, gchar **desktop_groups)
-{
- guint i;
- for (i = 0; desktop_groups[i] != NULL; i++) {
- if (!as_app_has_category (app, desktop_groups[i]))
- return FALSE;
- }
- return TRUE;
-}
-
-static gboolean
-_as_app_matches_desktop_group (AsApp *app, const gchar *desktop_group)
-{
- g_auto(GStrv) split = g_strsplit (desktop_group, "::", -1);
- return _as_app_matches_desktop_group_set (app, split);
-}
-
-static void
-gs_appstream_store_add_categories_for_app (GsCategory *parent, AsApp *app)
-{
- GPtrArray *children;
- GPtrArray *desktop_groups;
- GsCategory *category;
- guint i, j;
-
- /* find all the sub-categories */
- children = gs_category_get_children (parent);
- for (j = 0; j < children->len; j++) {
- gboolean matched = FALSE;
- category = GS_CATEGORY (g_ptr_array_index (children, j));
-
- /* do any desktop_groups match this application */
- desktop_groups = gs_category_get_desktop_groups (category);
- for (i = 0; i < desktop_groups->len; i++) {
- const gchar *desktop_group = g_ptr_array_index (desktop_groups, i);
- if (_as_app_matches_desktop_group (app, desktop_group)) {
- matched = TRUE;
- break;
- }
- }
- if (matched) {
- gs_category_increment_size (category);
- gs_category_increment_size (parent);
- }
- }
-}
-
-gboolean
-gs_appstream_store_add_category_apps (GsPlugin *plugin,
- AsStore *store,
- GsCategory *category,
- GsAppList *list,
- GCancellable *cancellable,
- GError **error)
-{
- GPtrArray *array;
- GPtrArray *desktop_groups;
- guint i;
- guint j;
- g_autoptr(AsProfileTask) ptask = NULL;
-
- /* just look at each app in turn */
- ptask = as_profile_start_literal (gs_plugin_get_profile (plugin),
- "appstream::add-category-apps");
- g_assert (ptask != NULL);
- array = as_store_get_apps (store);
- desktop_groups = gs_category_get_desktop_groups (category);
- if (desktop_groups->len == 0) {
- g_warning ("no desktop_groups for %s", gs_category_get_id (category));
- return TRUE;
- }
- for (j = 0; j < desktop_groups->len; j++) {
- const gchar *desktop_group = g_ptr_array_index (desktop_groups, j);
- g_auto(GStrv) split = g_strsplit (desktop_group, "::", -1);
-
- /* match the app */
- for (i = 0; i < array->len; i++) {
- AsApp *item;
- g_autoptr(GsApp) app = NULL;
-
- /* no ID is invalid */
- item = g_ptr_array_index (array, i);
- if (as_app_get_id (item) == NULL)
- continue;
-
- /* match all the desktop groups */
- if (!_as_app_matches_desktop_group_set (item, split))
- continue;
-
- /* add all the data we can */
- app = gs_appstream_create_app (plugin, item, error);
- if (app == NULL)
- return FALSE;
- gs_app_list_add (list, app);
- }
- }
- return TRUE;
-}
-
-gboolean
-gs_appstream_store_add_categories (GsPlugin *plugin,
- AsStore *store,
- GPtrArray *list,
- GCancellable *cancellable,
- GError **error)
-{
- AsApp *app;
- GPtrArray *array;
- guint i;
- guint j;
- g_autoptr(AsProfileTask) ptask = NULL;
-
- /* find out how many packages are in each category */
- ptask = as_profile_start_literal (gs_plugin_get_profile (plugin),
- "appstream::add-categories");
- g_assert (ptask != NULL);
- array = as_store_get_apps (store);
- for (i = 0; i < array->len; i++) {
- app = g_ptr_array_index (array, i);
- if (as_app_get_id (app) == NULL)
- continue;
- if (as_app_get_priority (app) < 0)
- continue;
- for (j = 0; j < list->len; j++) {
- GsCategory *parent = GS_CATEGORY (g_ptr_array_index (list, j));
- gs_appstream_store_add_categories_for_app (parent, app);
- }
- }
- return TRUE;
-}
-
-gboolean
-gs_appstream_add_popular (GsPlugin *plugin,
- AsStore *store,
- GsAppList *list,
- GCancellable *cancellable,
- GError **error)
-{
- AsApp *item;
- GPtrArray *array;
- guint i;
- g_autoptr(AsProfileTask) ptask = NULL;
-
- /* find out how many packages are in each category */
- ptask = as_profile_start_literal (gs_plugin_get_profile (plugin),
- "appstream::add-popular");
- g_assert (ptask != NULL);
- array = as_store_get_apps (store);
- for (i = 0; i < array->len; i++) {
- g_autoptr(GsApp) app = NULL;
- item = g_ptr_array_index (array, i);
- if (as_app_get_id (item) == NULL)
- continue;
- if (!as_app_has_kudo (item, "GnomeSoftware::popular"))
- continue;
- app = gs_app_new (as_app_get_id (item));
- gs_app_add_quirk (app, AS_APP_QUIRK_MATCH_ANY_PREFIX);
- gs_app_list_add (list, app);
- }
- return TRUE;
-}
-
-gboolean
-gs_appstream_add_featured (GsPlugin *plugin,
- AsStore *store,
- GsAppList *list,
- GCancellable *cancellable,
- GError **error)
-{
- AsApp *item;
- GPtrArray *array;
- guint i;
- g_autoptr(AsProfileTask) ptask = NULL;
-
- /* find out how many packages are in each category */
- ptask = as_profile_start_literal (gs_plugin_get_profile (plugin),
- "appstream::add-featured");
- g_assert (ptask != NULL);
- array = as_store_get_apps (store);
- for (i = 0; i < array->len; i++) {
- g_autoptr(GsApp) app = NULL;
- item = g_ptr_array_index (array, i);
- if (as_app_get_id (item) == NULL)
- continue;
- if (as_app_get_metadata_item (item, "GnomeSoftware::FeatureTile-css") == NULL)
- continue;
- app = gs_app_new (as_app_get_id (item));
- gs_app_add_quirk (app, AS_APP_QUIRK_MATCH_ANY_PREFIX);
- gs_app_list_add (list, app);
- }
- return TRUE;
-}
-
-void
-gs_appstream_add_extra_info (GsPlugin *plugin, AsApp *app)
-{
- const gchar *tmp;
-
- /* add more search terms */
- switch (as_app_get_kind (app)) {
- case AS_APP_KIND_WEB_APP:
- case AS_APP_KIND_INPUT_METHOD:
- tmp = as_app_kind_to_string (as_app_get_kind (app));
- g_debug ("adding keyword '%s' to %s",
- tmp, as_app_get_unique_id (app));
- as_app_add_keyword (app, NULL, tmp);
- break;
- default:
- break;
- }
-
- /* fix up these */
- if (as_app_get_kind (app) == AS_APP_KIND_LOCALIZATION &&
- g_str_has_prefix (as_app_get_id (app),
- "org.fedoraproject.LangPack-")) {
- g_autoptr(AsIcon) icon = NULL;
-
- /* add icon */
- icon = as_icon_new ();
- as_icon_set_kind (icon, AS_ICON_KIND_STOCK);
- as_icon_set_name (icon, "accessories-dictionary-symbolic");
- as_app_add_icon (app, icon);
-
- /* add categories */
- as_app_add_category (app, "Addons");
- as_app_add_category (app, "Localization");
- }
-
- /* fix up drivers with our nonstandard groups */
- if (as_app_get_kind (app) == AS_APP_KIND_DRIVER) {
- as_app_add_category (app, "Addons");
- as_app_add_category (app, "Drivers");
- }
-}
diff --git a/plugins/gs-appstream.c b/plugins/gs-appstream.c
new file mode 120000
index 0000000..720e181
--- /dev/null
+++ b/plugins/gs-appstream.c
@@ -0,0 +1 @@
+core/gs-appstream.c
\ No newline at end of file
diff --git a/plugins/gs-appstream.h b/plugins/gs-appstream.h
deleted file mode 100644
index c4c6d98..0000000
--- a/plugins/gs-appstream.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2015-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.
- */
-
-#ifndef __APPSTREAM_COMMON_H
-#define __APPSTREAM_COMMON_H
-
-#include <gnome-software.h>
-
-G_BEGIN_DECLS
-
-GsApp *gs_appstream_create_app (GsPlugin *plugin,
- AsApp *item,
- GError **error);
-gboolean gs_appstream_refine_app (GsPlugin *plugin,
- GsApp *app,
- AsApp *item,
- GError **error);
-GsApp *gs_appstream_create_runtime (GsPlugin *plugin,
- GsApp *parent,
- const gchar *runtime);
-gboolean gs_appstream_store_search (GsPlugin *plugin,
- AsStore *store,
- gchar **values,
- GsAppList *list,
- GCancellable *cancellable,
- GError **error);
-gboolean gs_appstream_store_add_categories (GsPlugin *plugin,
- AsStore *store,
- GPtrArray *list,
- GCancellable *cancellable,
- GError **error);
-gboolean gs_appstream_store_add_category_apps (GsPlugin *plugin,
- AsStore *store,
- GsCategory *category,
- GsAppList *list,
- GCancellable *cancellable,
- GError **error);
-gboolean gs_appstream_add_popular (GsPlugin *plugin,
- AsStore *store,
- GsAppList *list,
- GCancellable *cancellable,
- GError **error);
-gboolean gs_appstream_add_featured (GsPlugin *plugin,
- AsStore *store,
- GsAppList *list,
- GCancellable *cancellable,
- GError **error);
-void gs_appstream_add_extra_info (GsPlugin *plugin,
- AsApp *app);
-
-G_END_DECLS
-
-#endif /* __APPSTREAM_COMMON_H */
diff --git a/plugins/gs-appstream.h b/plugins/gs-appstream.h
new file mode 120000
index 0000000..f0785a6
--- /dev/null
+++ b/plugins/gs-appstream.h
@@ -0,0 +1 @@
+core/gs-appstream.h
\ No newline at end of file
diff --git a/plugins/gs-self-test.c b/plugins/gs-self-test.c
index e4ade25..9263bb0 100644
--- a/plugins/gs-self-test.c
+++ b/plugins/gs-self-test.c
@@ -25,371 +25,6 @@
#include "gs-test.h"
-static guint _status_changed_cnt = 0;
-
-static void
-gs_plugin_loader_status_changed_cb (GsPluginLoader *plugin_loader,
- GsApp *app,
- GsPluginStatus status,
- gpointer user_data)
-{
- _status_changed_cnt++;
-}
-
-static void
-gs_plugin_loader_install_func (GsPluginLoader *plugin_loader)
-{
- gboolean ret;
- g_autoptr(GsApp) app = NULL;
- g_autoptr(GError) error = NULL;
-
- /* install */
- app = gs_app_new ("chiron.desktop");
- gs_app_set_management_plugin (app, "dummy");
- gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
- ret = gs_plugin_loader_app_action (plugin_loader, app,
- GS_PLUGIN_ACTION_INSTALL,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- 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);
-
- /* remove */
- ret = gs_plugin_loader_app_action (plugin_loader, app,
- GS_PLUGIN_ACTION_REMOVE,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- 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_AVAILABLE);
-}
-
-static void
-gs_plugin_loader_error_func (GsPluginLoader *plugin_loader)
-{
- GsPluginEvent *event;
- const GError *app_error;
- gboolean ret;
- g_autoptr(GError) error = NULL;
- g_autoptr(GPtrArray) events = NULL;
- g_autoptr(GsApp) app = NULL;
-
- /* drop all caches */
- gs_plugin_loader_setup_again (plugin_loader);
-
- /* update, which should cause an error to be emitted */
- app = gs_app_new ("chiron.desktop");
- gs_app_set_management_plugin (app, "dummy");
- gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
- ret = gs_plugin_loader_app_action (plugin_loader, app,
- GS_PLUGIN_ACTION_UPDATE,
- GS_PLUGIN_FAILURE_FLAGS_USE_EVENTS |
- GS_PLUGIN_FAILURE_FLAGS_NO_CONSOLE,
- NULL,
- &error);
- gs_test_flush_main_context ();
- g_assert_no_error (error);
- g_assert (ret);
-
- /* get event by app-id */
- event = gs_plugin_loader_get_event_by_id (plugin_loader,
- "*/*/*/source/dummy/*");
- g_assert (event != NULL);
- g_assert (gs_plugin_event_get_app (event) == app);
-
- /* get last active event */
- event = gs_plugin_loader_get_event_default (plugin_loader);
- g_assert (event != NULL);
- g_assert (gs_plugin_event_get_app (event) == app);
-
- /* check all the events */
- events = gs_plugin_loader_get_events (plugin_loader);
- g_assert_cmpint (events->len, ==, 1);
- event = g_ptr_array_index (events, 0);
- g_assert (gs_plugin_event_get_app (event) == app);
- app_error = gs_plugin_event_get_error (event);
- g_assert (app_error != NULL);
- g_assert_error (app_error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_DOWNLOAD_FAILED);
-}
-
-static void
-gs_plugin_loader_refine_func (GsPluginLoader *plugin_loader)
-{
- gboolean ret;
- g_autoptr(GsApp) app = NULL;
- g_autoptr(GError) error = NULL;
-
- /* get the extra bits */
- app = gs_app_new ("chiron.desktop");
- gs_app_set_management_plugin (app, "dummy");
- ret = gs_plugin_loader_app_refine (plugin_loader, app,
- GS_PLUGIN_REFINE_FLAGS_REQUIRE_DESCRIPTION |
- GS_PLUGIN_REFINE_FLAGS_REQUIRE_LICENSE |
- GS_PLUGIN_REFINE_FLAGS_REQUIRE_URL,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- NULL,
- &error);
- gs_test_flush_main_context ();
- g_assert_no_error (error);
- g_assert (ret);
-
- g_assert_cmpstr (gs_app_get_license (app), ==, "GPL-2.0+");
- g_assert_cmpstr (gs_app_get_description (app), !=, NULL);
- g_assert_cmpstr (gs_app_get_url (app, AS_URL_KIND_HOMEPAGE), ==, "http://www.test.org/");
-}
-
-static void
-gs_plugin_loader_key_colors_func (GsPluginLoader *plugin_loader)
-{
- GPtrArray *array;
- gboolean ret;
- guint i;
- g_autoptr(GsApp) app = NULL;
- g_autoptr(GError) error = NULL;
-
- /* get the extra bits */
- app = gs_app_new ("zeus.desktop");
- ret = gs_plugin_loader_app_refine (plugin_loader, app,
- GS_PLUGIN_REFINE_FLAGS_REQUIRE_KEY_COLORS,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- NULL,
- &error);
- gs_test_flush_main_context ();
- g_assert_no_error (error);
- g_assert (ret);
- array = gs_app_get_key_colors (app);
- g_assert_cmpint (array->len, >=, 3);
-
- /* check values are in range */
- for (i = 0; i < array->len; i++) {
- GdkRGBA *kc = g_ptr_array_index (array, i);
- g_assert_cmpfloat (kc->red, >=, 0.f);
- g_assert_cmpfloat (kc->red, <=, 1.f);
- g_assert_cmpfloat (kc->green, >=, 0.f);
- g_assert_cmpfloat (kc->green, <=, 1.f);
- g_assert_cmpfloat (kc->blue, >=, 0.f);
- g_assert_cmpfloat (kc->blue, <=, 1.f);
- g_assert_cmpfloat (kc->alpha, >=, 0.f);
- g_assert_cmpfloat (kc->alpha, <=, 1.f);
- }
-}
-
-static void
-gs_plugin_loader_updates_func (GsPluginLoader *plugin_loader)
-{
- GsApp *app;
- g_autoptr(GError) error = NULL;
- g_autoptr(GsAppList) list = NULL;
-
- /* get the updates list */
- list = gs_plugin_loader_get_updates (plugin_loader,
- GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON |
- GS_PLUGIN_REFINE_FLAGS_REQUIRE_UPDATE_DETAILS,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- NULL,
- &error);
- gs_test_flush_main_context ();
- g_assert_no_error (error);
- g_assert (list != NULL);
-
- /* make sure there are two entries */
- g_assert_cmpint (gs_app_list_length (list), ==, 3);
- app = gs_app_list_index (list, 0);
- g_assert_cmpstr (gs_app_get_id (app), ==, "chiron.desktop");
- g_assert_cmpint (gs_app_get_kind (app), ==, AS_APP_KIND_DESKTOP);
- g_assert_cmpint (gs_app_get_state (app), ==, AS_APP_STATE_UPDATABLE_LIVE);
- g_assert_cmpstr (gs_app_get_update_details (app), ==, "Do not crash when using libvirt.");
- g_assert_cmpint (gs_app_get_update_urgency (app), ==, AS_URGENCY_KIND_HIGH);
-
- /* get the virtual non-apps OS update */
- app = gs_app_list_index (list, 1);
- g_assert_cmpstr (gs_app_get_id (app), ==, "org.gnome.Software.OsUpdate");
- g_assert_cmpstr (gs_app_get_name (app), ==, "OS Updates");
- g_assert_cmpstr (gs_app_get_summary (app), ==, "Includes performance, stability and security
improvements.");
- g_assert_cmpint (gs_app_get_kind (app), ==, AS_APP_KIND_OS_UPDATE);
- g_assert_cmpint (gs_app_get_state (app), ==, AS_APP_STATE_UPDATABLE);
- g_assert_cmpint (gs_app_get_related(app)->len, ==, 2);
-
- /* get the virtual non-apps OS update */
- app = gs_app_list_index (list, 2);
- g_assert_cmpstr (gs_app_get_id (app), ==, "proxy.desktop");
- g_assert (gs_app_has_quirk (app, AS_APP_QUIRK_IS_PROXY));
- g_assert_cmpint (gs_app_get_state (app), ==, AS_APP_STATE_UPDATABLE_LIVE);
- g_assert_cmpint (gs_app_get_related(app)->len, ==, 2);
-}
-
-static void
-gs_plugin_loader_distro_upgrades_func (GsPluginLoader *plugin_loader)
-{
- GsApp *app;
- gboolean ret;
- g_autoptr(GError) error = NULL;
- g_autoptr(GsAppList) list = NULL;
-
- /* get the updates list */
- list = gs_plugin_loader_get_distro_upgrades (plugin_loader,
- GS_PLUGIN_REFINE_FLAGS_DEFAULT,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- NULL,
- &error);
- gs_test_flush_main_context ();
- g_assert_no_error (error);
- g_assert (list != NULL);
-
- /* make sure there is one entry */
- g_assert_cmpint (gs_app_list_length (list), ==, 1);
- app = gs_app_list_index (list, 0);
- g_assert_cmpstr (gs_app_get_id (app), ==, "org.fedoraproject.release-rawhide.upgrade");
- g_assert_cmpint (gs_app_get_kind (app), ==, AS_APP_KIND_OS_UPGRADE);
- g_assert_cmpint (gs_app_get_state (app), ==, AS_APP_STATE_AVAILABLE);
-
- /* this should be set with a higher priority by AppStream */
- g_assert_cmpstr (gs_app_get_summary (app), ==, "Release specific tagline");
-
- /* download the update */
- ret = gs_plugin_loader_app_action (plugin_loader,
- app,
- GS_PLUGIN_ACTION_UPGRADE_DOWNLOAD,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- 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_UPDATABLE);
-
- /* trigger the update */
- ret = gs_plugin_loader_app_action (plugin_loader,
- app,
- GS_PLUGIN_ACTION_UPGRADE_TRIGGER,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- 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_UPDATABLE);
-}
-
-static void
-gs_plugin_loader_installed_func (GsPluginLoader *plugin_loader)
-{
- GsApp *app;
- GsApp *addon;
- GPtrArray *addons;
- guint64 kudos;
- g_autofree gchar *menu_path = NULL;
- g_autoptr(GError) error = NULL;
- g_autoptr(GsAppList) list = NULL;
-
- /* get installed packages */
- list = gs_plugin_loader_get_installed (plugin_loader,
- GS_PLUGIN_REFINE_FLAGS_REQUIRE_ORIGIN |
- GS_PLUGIN_REFINE_FLAGS_REQUIRE_ADDONS |
- GS_PLUGIN_REFINE_FLAGS_REQUIRE_LICENSE |
- GS_PLUGIN_REFINE_FLAGS_REQUIRE_MENU_PATH |
- GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON |
- GS_PLUGIN_REFINE_FLAGS_REQUIRE_PROVENANCE,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- NULL,
- &error);
- gs_test_flush_main_context ();
- g_assert_no_error (error);
- g_assert (list != NULL);
-
- /* make sure there is one entry */
- g_assert_cmpint (gs_app_list_length (list), ==, 1);
- app = gs_app_list_index (list, 0);
- g_assert_cmpstr (gs_app_get_id (app), ==, "zeus.desktop");
- g_assert_cmpint (gs_app_get_kind (app), ==, AS_APP_KIND_DESKTOP);
- g_assert_cmpint (gs_app_get_state (app), ==, AS_APP_STATE_INSTALLED);
- g_assert_cmpstr (gs_app_get_name (app), ==, "Zeus");
- g_assert_cmpstr (gs_app_get_source_default (app), ==, "zeus");
- g_assert (gs_app_get_pixbuf (app) != NULL);
-
- /* check various bitfields */
- g_assert (gs_app_has_quirk (app, AS_APP_QUIRK_PROVENANCE));
- g_assert_cmpstr (gs_app_get_license (app), ==, "GPL-2.0+");
- g_assert (gs_app_get_license_is_free (app));
-
- /* check kudos */
- kudos = gs_app_get_kudos (app);
- g_assert (kudos & GS_APP_KUDO_MY_LANGUAGE);
-
- /* check categories */
- g_assert (gs_app_has_category (app, "Player"));
- g_assert (gs_app_has_category (app, "AudioVideo"));
- g_assert (!gs_app_has_category (app, "ImageProcessing"));
- g_assert (gs_app_get_menu_path (app) != NULL);
- menu_path = g_strjoinv ("->", gs_app_get_menu_path (app));
- g_assert_cmpstr (menu_path, ==, "Audio & Video->Music Players");
-
- /* check addon */
- addons = gs_app_get_addons (app);
- g_assert_cmpint (addons->len, ==, 1);
- addon = g_ptr_array_index (addons, 0);
- g_assert_cmpstr (gs_app_get_id (addon), ==, "zeus-spell.addon");
- g_assert_cmpint (gs_app_get_kind (addon), ==, AS_APP_KIND_ADDON);
- g_assert_cmpint (gs_app_get_state (addon), ==, AS_APP_STATE_AVAILABLE);
- g_assert_cmpstr (gs_app_get_name (addon), ==, "Spell Check");
- g_assert_cmpstr (gs_app_get_source_default (addon), ==, "zeus-spell");
- g_assert_cmpstr (gs_app_get_license (addon), ==,
- "LicenseRef-free=https://www.debian.org/");
- g_assert (gs_app_get_pixbuf (addon) == NULL);
-}
-
-static void
-gs_plugin_loader_search_func (GsPluginLoader *plugin_loader)
-{
- GsApp *app;
- g_autofree gchar *menu_path = NULL;
- g_autoptr(GError) error = NULL;
- g_autoptr(GsAppList) list = NULL;
-
- /* get search result based on addon keyword */
- list = gs_plugin_loader_search (plugin_loader,
- "spell",
- GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- NULL,
- &error);
- gs_test_flush_main_context ();
- g_assert_no_error (error);
- g_assert (list != NULL);
-
- /* make sure there is one entry, the parent app */
- g_assert_cmpint (gs_app_list_length (list), ==, 1);
- app = gs_app_list_index (list, 0);
- g_assert_cmpstr (gs_app_get_id (app), ==, "zeus.desktop");
- g_assert_cmpint (gs_app_get_kind (app), ==, AS_APP_KIND_DESKTOP);
-}
-
-static void
-gs_plugin_loader_url_to_app_func (GsPluginLoader *plugin_loader)
-{
- g_autoptr(GError) error = NULL;
- g_autoptr(GsApp) app = NULL;
-
- app = gs_plugin_loader_url_to_app (plugin_loader,
- "dummy://chiron.desktop",
- GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- NULL,
- &error);
- gs_test_flush_main_context ();
- g_assert_no_error (error);
- g_assert (app != NULL);
- g_assert_cmpstr (gs_app_get_id (app), ==, "chiron.desktop");
- g_assert_cmpint (gs_app_get_kind (app), ==, AS_APP_KIND_DESKTOP);
-}
-
static void
gs_plugin_loader_modalias_func (GsPluginLoader *plugin_loader)
{
@@ -1446,7 +1081,7 @@ gs_plugin_loader_flatpak_app_update_func (GsPluginLoader *plugin_loader)
g_assert (list_updates != NULL);
/* make sure there are two entries */
- g_assert_cmpint (gs_app_list_length (list_updates), >, 3);
+ g_assert_cmpint (gs_app_list_length (list_updates), ==, 1);
for (guint i = 0; i < gs_app_list_length (list_updates); i++) {
app_tmp = gs_app_list_index (list_updates, i);
g_debug ("got update %s", gs_app_get_unique_id (app_tmp));
@@ -1537,132 +1172,6 @@ gs_plugin_loader_flatpak_app_update_func (GsPluginLoader *plugin_loader)
g_assert_cmpint (gs_app_get_state (app_source), ==, AS_APP_STATE_AVAILABLE);
}
-static void
-gs_plugin_loader_plugin_cache_func (GsPluginLoader *plugin_loader)
-{
- GsApp *app1;
- GsApp *app2;
- g_autoptr(GError) error = NULL;
- g_autoptr(GsAppList) list1 = NULL;
- g_autoptr(GsAppList) list2 = NULL;
-
- /* ensure we get the same results back from calling the methods twice */
- list1 = gs_plugin_loader_get_distro_upgrades (plugin_loader,
- GS_PLUGIN_REFINE_FLAGS_DEFAULT,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- NULL,
- &error);
- gs_test_flush_main_context ();
- g_assert_no_error (error);
- g_assert (list1 != NULL);
- g_assert_cmpint (gs_app_list_length (list1), ==, 1);
- app1 = gs_app_list_index (list1, 0);
-
- list2 = gs_plugin_loader_get_distro_upgrades (plugin_loader,
- GS_PLUGIN_REFINE_FLAGS_DEFAULT,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- NULL,
- &error);
- gs_test_flush_main_context ();
- g_assert_no_error (error);
- g_assert (list2 != NULL);
- g_assert_cmpint (gs_app_list_length (list2), ==, 1);
- app2 = gs_app_list_index (list2, 0);
-
- /* make sure there is one GObject */
- g_assert_cmpstr (gs_app_get_id (app1), ==, gs_app_get_id (app2));
- g_assert (app1 == app2);
-}
-
-static void
-gs_plugin_loader_authentication_func (GsPluginLoader *plugin_loader)
-{
- GsAuth *auth;
- gboolean ret;
- g_autoptr(GError) error = NULL;
- g_autoptr(GsApp) app = NULL;
- g_autoptr(AsReview) review = NULL;
- g_autoptr(AsReview) review2 = NULL;
-
- /* check initial state */
- auth = gs_plugin_loader_get_auth_by_id (plugin_loader, "dummy");
- g_assert (GS_IS_AUTH (auth));
- g_assert_cmpint (gs_auth_get_flags (auth), ==, 0);
-
- /* do an action that returns a URL */
- ret = gs_plugin_loader_auth_action (plugin_loader, auth,
- GS_PLUGIN_ACTION_AUTH_REGISTER,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- NULL, &error);
- gs_test_flush_main_context ();
- g_assert_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_AUTH_INVALID);
- g_assert (!ret);
- g_clear_error (&error);
- g_assert (!gs_auth_has_flag (auth, GS_AUTH_FLAG_VALID));
-
- /* do an action that requires a login */
- app = gs_app_new (NULL);
- review = as_review_new ();
- ret = gs_plugin_loader_review_action (plugin_loader, app, review,
- GS_PLUGIN_ACTION_REVIEW_REMOVE,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- NULL, &error);
- gs_test_flush_main_context ();
- g_assert_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_AUTH_REQUIRED);
- g_assert (!ret);
- g_clear_error (&error);
-
- /* pretend to auth with no credentials */
- ret = gs_plugin_loader_auth_action (plugin_loader, auth,
- GS_PLUGIN_ACTION_AUTH_LOGIN,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- NULL, &error);
- gs_test_flush_main_context ();
- g_assert_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_AUTH_INVALID);
- g_assert (!ret);
- g_clear_error (&error);
- g_assert (!gs_auth_has_flag (auth, GS_AUTH_FLAG_VALID));
-
- /* auth again with correct credentials */
- gs_auth_set_username (auth, "dummy");
- gs_auth_set_password (auth, "dummy");
- ret = gs_plugin_loader_auth_action (plugin_loader, auth,
- GS_PLUGIN_ACTION_AUTH_LOGIN,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- NULL, &error);
- gs_test_flush_main_context ();
- g_assert_no_error (error);
- g_assert (ret);
- g_assert (gs_auth_has_flag (auth, GS_AUTH_FLAG_VALID));
-
- /* do the action that requires a login */
- review2 = as_review_new ();
- ret = gs_plugin_loader_review_action (plugin_loader, app, review2,
- GS_PLUGIN_ACTION_REVIEW_REMOVE,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- NULL, &error);
- gs_test_flush_main_context ();
- g_assert_no_error (error);
- g_assert (ret);
-}
-
-static void
-gs_plugin_loader_wildcard_func (GsPluginLoader *plugin_loader)
-{
- g_autoptr(GError) error = NULL;
- g_autoptr(GsAppList) list = NULL;
-
- list = gs_plugin_loader_get_popular (plugin_loader,
- GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON,
- GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
- NULL,
- &error);
- gs_test_flush_main_context ();
- g_assert_no_error (error);
- g_assert (list != NULL);
- g_assert_cmpint (gs_app_list_length (list), ==, 1);
-}
-
int
main (int argc, char **argv)
{
@@ -1780,9 +1289,8 @@ main (int argc, char **argv)
/* we can only load this once per process */
plugin_loader = gs_plugin_loader_new ();
- g_signal_connect (plugin_loader, "status-changed",
- G_CALLBACK (gs_plugin_loader_status_changed_cb), NULL);
gs_plugin_loader_add_location (plugin_loader, LOCALPLUGINDIR);
+ gs_plugin_loader_add_location (plugin_loader, LOCALPLUGINDIR_CORE);
ret = gs_plugin_loader_setup (plugin_loader,
(gchar**) whitelist,
NULL,
@@ -1794,18 +1302,8 @@ main (int argc, char **argv)
g_assert (!gs_plugin_loader_get_enabled (plugin_loader, "notgoingtoexist"));
g_assert (!gs_plugin_loader_get_enabled (plugin_loader, "packagekit"));
g_assert (gs_plugin_loader_get_enabled (plugin_loader, "appstream"));
- g_assert (gs_plugin_loader_get_enabled (plugin_loader, "dummy"));
/* plugin tests go here */
- g_test_add_data_func ("/gnome-software/plugin-loader{wildcard}",
- plugin_loader,
- (GTestDataFunc) gs_plugin_loader_wildcard_func);
- g_test_add_data_func ("/gnome-software/plugin-loader{authentication}",
- plugin_loader,
- (GTestDataFunc) gs_plugin_loader_authentication_func);
- g_test_add_data_func ("/gnome-software/plugin-loader{plugin-cache}",
- plugin_loader,
- (GTestDataFunc) gs_plugin_loader_plugin_cache_func);
g_test_add_data_func ("/gnome-software/plugin-loader{flatpak-app-with-runtime}",
plugin_loader,
(GTestDataFunc) gs_plugin_loader_flatpak_app_with_runtime_func);
@@ -1821,39 +1319,12 @@ main (int argc, char **argv)
g_test_add_data_func ("/gnome-software/plugin-loader{flatpak-app-update-runtime}",
plugin_loader,
(GTestDataFunc) gs_plugin_loader_flatpak_app_update_func);
- g_test_add_data_func ("/gnome-software/plugin-loader{key-colors}",
- plugin_loader,
- (GTestDataFunc) gs_plugin_loader_key_colors_func);
g_test_add_data_func ("/gnome-software/plugin-loader{webapps}",
plugin_loader,
(GTestDataFunc) gs_plugin_loader_webapps_func);
g_test_add_data_func ("/gnome-software/plugin-loader{modalias}",
plugin_loader,
(GTestDataFunc) gs_plugin_loader_modalias_func);
- g_test_add_data_func ("/gnome-software/plugin-loader{search}",
- plugin_loader,
- (GTestDataFunc) gs_plugin_loader_search_func);
- g_test_add_data_func ("/gnome-software/plugin-loader{url-to-app}",
- plugin_loader,
- (GTestDataFunc) gs_plugin_loader_url_to_app_func);
- g_test_add_data_func ("/gnome-software/plugin-loader{install}",
- plugin_loader,
- (GTestDataFunc) gs_plugin_loader_install_func);
- g_test_add_data_func ("/gnome-software/plugin-loader{error}",
- plugin_loader,
- (GTestDataFunc) gs_plugin_loader_error_func);
- g_test_add_data_func ("/gnome-software/plugin-loader{installed}",
- plugin_loader,
- (GTestDataFunc) gs_plugin_loader_installed_func);
- g_test_add_data_func ("/gnome-software/plugin-loader{refine}",
- plugin_loader,
- (GTestDataFunc) gs_plugin_loader_refine_func);
- g_test_add_data_func ("/gnome-software/plugin-loader{updates}",
- plugin_loader,
- (GTestDataFunc) gs_plugin_loader_updates_func);
- g_test_add_data_func ("/gnome-software/plugin-loader{distro-upgrades}",
- plugin_loader,
- (GTestDataFunc) gs_plugin_loader_distro_upgrades_func);
/* done last as it would otherwise try to do downloading in other
* gs_plugin_file_to_app()-using tests */
diff --git a/po/POTFILES.in b/po/POTFILES.in
index f4ef7f7..b80d361 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -65,10 +65,10 @@ src/gs-updates-page.ui
src/gs-upgrade-banner.c
src/gs-upgrade-banner.ui
src/org.gnome.Software.desktop.in
-plugins/gs-desktop-common.c
+plugins/core/gs-desktop-common.c
plugins/external-appstream/gs-install-appstream.c
plugins/gs-plugin-fedora-distro-upgrades.c
-plugins/gs-plugin-generic-updates.c
+plugins/core/gs-plugin-generic-updates.c
plugins/org.gnome.Software.Plugin.Epiphany.metainfo.xml.in
plugins/org.gnome.Software.Plugin.Flatpak.metainfo.xml.in
plugins/fwupd/org.gnome.Software.Plugin.Fwupd.metainfo.xml.in
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]