[gnome-software/wip/hughsie/libxmlb: 23/23] Use libxmlb to parse AppStream XML
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software/wip/hughsie/libxmlb: 23/23] Use libxmlb to parse AppStream XML
- Date: Mon, 8 Oct 2018 09:15:41 +0000 (UTC)
commit 76c20477e1537a1c817d32ee85905de6a5434f19
Author: Richard Hughes <richard hughsie com>
Date: Mon Sep 24 13:35:31 2018 +0100
Use libxmlb to parse AppStream XML
lib/gs-utils.c | 6 +
meson.build | 3 +-
plugins/core/gs-appstream.c | 1427 +++++++++++---------
plugins/core/gs-appstream.h | 36 +-
plugins/core/gs-plugin-appstream.c | 789 +++++------
plugins/core/gs-self-test.c | 6 +-
plugins/core/meson.build | 6 +-
plugins/dummy/gs-self-test.c | 9 +-
plugins/external-appstream/gs-install-appstream.c | 44 +-
plugins/external-appstream/meson.build | 7 +-
plugins/flatpak/gs-flatpak.c | 391 +++---
plugins/flatpak/gs-plugin-flatpak.c | 6 +
plugins/flatpak/gs-self-test.c | 21 +
plugins/flatpak/meson.build | 6 +-
plugins/modalias/gs-self-test.c | 7 +
plugins/odrs/meson.build | 1 +
.../shell-extensions/gs-plugin-shell-extensions.c | 164 ++-
plugins/shell-extensions/gs-self-test.c | 17 +-
plugins/shell-extensions/meson.build | 6 +-
19 files changed, 1638 insertions(+), 1314 deletions(-)
---
diff --git a/lib/gs-utils.c b/lib/gs-utils.c
index 23d24995..7805483b 100644
--- a/lib/gs-utils.c
+++ b/lib/gs-utils.c
@@ -165,11 +165,17 @@ gs_utils_get_cache_filename (const gchar *kind,
GsUtilsCacheFlags flags,
GError **error)
{
+ const gchar *tmp;
g_autofree gchar *basename = NULL;
g_autofree gchar *cachedir = NULL;
g_autoptr(GFile) cachedir_file = NULL;
g_autoptr(GPtrArray) candidates = g_ptr_array_new_with_free_func (g_free);
+ /* in the self tests */
+ tmp = g_getenv ("GS_SELF_TEST_CORE_DATADIR");
+ if (tmp != NULL)
+ return g_build_filename (tmp, kind, resource, NULL);
+
/* get basename */
if (flags & GS_UTILS_CACHE_FLAG_USE_HASH) {
g_autofree gchar *basename_tmp = g_path_get_basename (resource);
diff --git a/meson.build b/meson.build
index 0c4460fd..41329b38 100644
--- a/meson.build
+++ b/meson.build
@@ -96,8 +96,9 @@ add_project_arguments('-D_GNU_SOURCE', language : 'c')
conf.set('HAVE_LINUX_UNISTD_H', cc.has_header('linux/unistd.h'))
-appstream_glib = dependency('appstream-glib', version : '>= 0.7.11')
+appstream_glib = dependency('appstream-glib', version : '>= 0.7.14')
gdk_pixbuf = dependency('gdk-pixbuf-2.0', version : '>= 2.32.0')
+libxmlb = dependency('xmlb', version : '>= 0.1.1')
gio_unix = dependency('gio-unix-2.0')
gmodule = dependency('gmodule-2.0')
gtk = dependency('gtk+-3.0', version : '>= 3.22.4')
diff --git a/plugins/core/gs-appstream.c b/plugins/core/gs-appstream.c
index 06f8288a..d924ca3e 100644
--- a/plugins/core/gs-appstream.c
+++ b/plugins/core/gs-appstream.c
@@ -28,80 +28,80 @@
#define GS_APPSTREAM_MAX_SCREENSHOTS 5
GsApp *
-gs_appstream_create_app (GsPlugin *plugin, AsApp *item, GError **error)
+gs_appstream_create_app (GsPlugin *plugin, XbSilo *silo, XbNode *component, GError **error)
{
- const gchar *unique_id = as_app_get_unique_id (item);
- GsApp *app = gs_plugin_cache_lookup (plugin, unique_id);
-
- /* if the app we found has the "match-any-prefix" quirk and our item does
- * not, then we create a new one because ours will be "complete", and
- * using the mentioned quirk will lead to a different behavior (e.g. it'll
- * be refined using refine_wildcard, it won't allow a management plugin to
- * be set, etc.) */
- if (app != NULL && gs_app_has_quirk (app, AS_APP_QUIRK_MATCH_ANY_PREFIX) &&
- !as_app_has_quirk (item, AS_APP_QUIRK_MATCH_ANY_PREFIX)) {
- g_debug ("Looking for %s, got %s but has 'match-any-prefix' quirk "
- "so we create a new one instead.",
- unique_id, gs_app_get_unique_id (app));
- g_clear_object (&app);
- }
-
+ g_autofree gchar *cache_key = g_strdup_printf ("%p", component);
+ GsApp *app = gs_plugin_cache_lookup (plugin, cache_key);
if (app == NULL) {
app = gs_app_new (NULL);
- gs_app_set_from_unique_id (app, unique_id);
- /* clear origin set from unique_id: appstream origin goes to
- * GsApp's origin-appstream field instead */
- gs_app_set_origin (app, NULL);
gs_app_set_metadata (app, "GnomeSoftware::Creator",
gs_plugin_get_name (plugin));
- if (!gs_appstream_refine_app (plugin, app, item, error)) {
+ if (!gs_appstream_refine_app (plugin, app, silo, component,
+ GS_PLUGIN_REFINE_FLAGS_DEFAULT,
+ error)) {
g_object_unref (app);
return NULL;
}
- gs_plugin_cache_add (plugin, unique_id, app);
+ gs_plugin_cache_add (plugin, cache_key, app);
}
return app;
}
static AsIcon *
-gs_appstream_get_icon_by_kind (AsApp *app, AsIconKind icon_kind)
+gs_appstream_new_icon (XbNode *n, AsIconKind icon_kind, guint sz)
{
- GPtrArray *icons = as_app_get_icons (app);
- for (guint 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;
+ AsIcon *icon = as_icon_new ();
+ as_icon_set_kind (icon, icon_kind);
+ as_icon_set_name (icon, xb_node_get_text (n));
+ if (sz == 0)
+ sz = xb_node_get_attr_as_uint (n, "width");
+ as_icon_set_width (icon, sz);
+ as_icon_set_height (icon, sz);
+ as_icon_set_prefix (icon, "/usr/share/app-info/icons/fedora");
+ return icon;
}
static AsIcon *
-gs_appstream_get_icon_by_kind_and_size (AsApp *app, AsIconKind icon_kind, guint sz)
+gs_appstream_get_icon_by_kind (XbNode *component, AsIconKind icon_kind)
{
- GPtrArray *icons = as_app_get_icons (app);
- for (guint 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;
+ g_autofree gchar *xpath = NULL;
+ g_autoptr(XbNode) icon = NULL;
+
+ xpath = g_strdup_printf ("icon[@type='%s']",
+ as_icon_kind_to_string (icon_kind));
+ icon = xb_node_query_first (component, xpath, NULL);
+ if (icon == NULL)
+ return NULL;
+ return gs_appstream_new_icon (icon, icon_kind, 0);
+}
+
+static AsIcon *
+gs_appstream_get_icon_by_kind_and_size (XbNode *component, AsIconKind icon_kind, guint sz)
+{
+ g_autofree gchar *xpath = NULL;
+ g_autoptr(XbNode) icon = NULL;
+
+ xpath = g_strdup_printf ("icon[@type='%s'][@height='%u'][@width='%u']",
+ as_icon_kind_to_string (icon_kind), sz, sz);
+ icon = xb_node_query_first (component, xpath, NULL);
+ if (icon == NULL)
+ return NULL;
+ return gs_appstream_new_icon (icon, icon_kind, sz);
}
static void
-gs_refine_item_icon (GsPlugin *plugin, GsApp *app, AsApp *item)
+gs_refine_item_icon (GsPlugin *plugin, GsApp *app, XbNode *component)
{
AsIcon *icon;
/* try a stock icon first */
- icon = gs_appstream_get_icon_by_kind (item, AS_ICON_KIND_STOCK);
+ icon = gs_appstream_get_icon_by_kind (component, 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,
+ icon = gs_appstream_get_icon_by_kind_and_size (component,
AS_ICON_KIND_CACHED,
128);
if (icon != NULL)
@@ -109,14 +109,14 @@ gs_refine_item_icon (GsPlugin *plugin, GsApp *app, AsApp *item)
}
/* non-HiDPI cached icon */
- icon = gs_appstream_get_icon_by_kind_and_size (item,
+ icon = gs_appstream_get_icon_by_kind_and_size (component,
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);
+ icon = gs_appstream_get_icon_by_kind (component, 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 &&
@@ -129,7 +129,7 @@ gs_refine_item_icon (GsPlugin *plugin, GsApp *app, AsApp *item)
}
/* remote as a last resort */
- icon = gs_appstream_get_icon_by_kind (item, AS_ICON_KIND_REMOTE);
+ icon = gs_appstream_get_icon_by_kind (component, AS_ICON_KIND_REMOTE);
if (icon != NULL)
gs_app_add_icon (app, icon);
}
@@ -137,114 +137,137 @@ gs_refine_item_icon (GsPlugin *plugin, GsApp *app, AsApp *item)
static gboolean
gs_appstream_refine_add_addons (GsPlugin *plugin,
GsApp *app,
- AsApp *item,
+ XbSilo *silo,
GError **error)
{
- GPtrArray *addons;
-
- /* we only care about addons to desktop apps */
- if (gs_app_get_kind (app) != AS_APP_KIND_DESKTOP)
- return TRUE;
-
- addons = as_app_get_addons (item);
- if (addons == NULL)
- return TRUE;
-
+ g_autofree gchar *xpath = NULL;
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) addons = NULL;
+
+ /* get all components */
+ xpath = g_strdup_printf ("components/component/extends[text()='%s']/..",
+ gs_app_get_id (app));
+ addons = xb_silo_query (silo, xpath, 0, &error_local);
+ if (addons == NULL) {
+ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ return TRUE;
+ g_propagate_error (error, g_steal_pointer (&error_local));
+ return FALSE;
+ }
for (guint 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))
+ XbNode *addon = g_ptr_array_index (addons, i);
+ g_autoptr(GsApp) app2 = NULL;
+ app2 = gs_appstream_create_app (plugin, silo, addon, error);
+ if (app2 == NULL)
return FALSE;
- gs_app_add_addon (app, addon);
+ gs_app_add_addon (app, app2);
}
return TRUE;
}
-static void
-gs_appstream_refine_add_screenshots (GsApp *app, AsApp *item)
+static gboolean
+gs_appstream_refine_add_images (GsApp *app, AsScreenshot *ss, XbNode *screenshot, GError **error)
{
- GPtrArray *screenshots_as;
-
- /* 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 (guint i = 0; i < screenshots_as->len &&
- i < GS_APPSTREAM_MAX_SCREENSHOTS; i++) {
- AsScreenshot *ss = g_ptr_array_index (screenshots_as, i);
- GPtrArray *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);
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) images = NULL;
+
+ /* get all components */
+ images = xb_node_query (screenshot, "image", 0, &error_local);
+ if (images == NULL) {
+ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ return TRUE;
+ g_propagate_error (error, g_steal_pointer (&error_local));
+ return FALSE;
}
+ for (guint i = 0; i < images->len; i++) {
+ XbNode *image = g_ptr_array_index (images, i);
+ g_autoptr(AsImage) im = as_image_new ();
+ as_image_set_height (im, xb_node_get_attr_as_uint (image, "height"));
+ as_image_set_width (im, xb_node_get_attr_as_uint (image, "width"));
+ as_image_set_kind (im, as_image_kind_from_string (xb_node_get_attr (image, "type")));
+ as_image_set_url (im, xb_node_get_text (image));
+ as_screenshot_add_image (ss, g_steal_pointer (&im));
+ }
+
+ /* success */
+ return TRUE;
}
-static void
-gs_appstream_refine_add_reviews (GsApp *app, AsApp *item)
+static gboolean
+gs_appstream_refine_add_screenshots (GsApp *app, XbNode *component, GError **error)
{
- GPtrArray *reviews;
-
- /* do we have any to add */
- if (gs_app_get_reviews(app)->len > 0)
- return;
- reviews = as_app_get_reviews (item);
- for (guint i = 0; i < reviews->len; i++) {
- AsReview *review = g_ptr_array_index (reviews, i);
- gs_app_add_review (app, review);
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) screenshots = NULL;
+
+ /* get all components */
+ screenshots = xb_node_query (component, "screenshots/screenshot", 0, &error_local);
+ if (screenshots == NULL) {
+ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ return TRUE;
+ g_propagate_error (error, g_steal_pointer (&error_local));
+ return FALSE;
+ }
+ for (guint i = 0; i < screenshots->len; i++) {
+ XbNode *screenshot = g_ptr_array_index (screenshots, i);
+ g_autoptr(AsScreenshot) ss = as_screenshot_new ();
+ if (!gs_appstream_refine_add_images (app, ss, screenshot, error))
+ return FALSE;
+ gs_app_add_screenshot (app, g_steal_pointer (&ss));
}
+
+ /* FIXME: move into no refine flags section? */
+ if (screenshots ->len > 0)
+ gs_app_add_kudo (app, GS_APP_KUDO_HAS_SCREENSHOTS);
+
+ /* success */
+ return TRUE;
}
-static void
-gs_appstream_refine_add_provides (GsApp *app, AsApp *item)
+static gboolean
+gs_appstream_refine_add_provides (GsApp *app, XbNode *component, GError **error)
{
- GPtrArray *provides;
-
- /* do we have any to add */
- if (gs_app_get_provides(app)->len > 0)
- return;
- provides = as_app_get_provides (item);
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) provides = NULL;
+
+ /* get all components */
+ provides = xb_node_query (component, "provides/*", 0, &error_local);
+ if (provides == NULL) {
+ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ return TRUE;
+ g_propagate_error (error, g_steal_pointer (&error_local));
+ return FALSE;
+ }
for (guint i = 0; i < provides->len; i++) {
- AsProvide *provide = g_ptr_array_index (provides, i);
- gs_app_add_provide (app, provide);
+ XbNode *provide = g_ptr_array_index (provides, i);
+ g_autoptr(AsProvide) pr = as_provide_new ();
+ as_provide_set_kind (pr, as_provide_kind_from_string (xb_node_get_element (provide)));
+ as_provide_set_value (pr, xb_node_get_text (provide));
+ gs_app_add_provide (app, g_steal_pointer (&pr));
}
+
+ /* success */
+ return TRUE;
}
static gboolean
-gs_appstream_is_recent_release (AsApp *app)
+gs_appstream_is_recent_release (XbNode *component)
{
- AsRelease *release;
- GPtrArray *releases;
+ guint64 ts;
guint64 secs;
/* get newest release */
- releases = as_app_get_releases (app);
- if (releases->len == 0)
+ ts = xb_node_query_attr_as_uint (component, "releases/release", "timestamp", NULL);
+ if (ts == G_MAXUINT64)
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);
+ secs = ((guint64) g_get_real_time () / G_USEC_PER_SEC) - ts;
return secs / (60 * 60 * 24) < 365;
}
+#if 0
static gboolean
-gs_appstream_are_screenshots_perfect (AsApp *app)
+gs_appstream_are_screenshots_perfect (XbNode *component)
{
AsImage *image;
AsScreenshot *screenshot;
@@ -280,11 +303,13 @@ gs_appstream_are_screenshots_perfect (AsApp *app)
}
return TRUE;
}
+#endif
+#if 0
static void
-gs_appstream_copy_metadata (GsApp *app, AsApp *item)
+gs_appstream_copy_metadata (GsApp *app, XbNode *component)
{
- GHashTable *hash = as_app_get_metadata (item);
+ GHashTable *hash = as_app_get_metadata (component);
g_autoptr(GList) keys = g_hash_table_get_keys (hash);
for (GList *l = keys; l != NULL; l = l->next) {
const gchar *key = l->data;
@@ -294,32 +319,15 @@ gs_appstream_copy_metadata (GsApp *app, AsApp *item)
gs_app_set_metadata (app, key, value);
}
}
-
-static void
-gs_refine_item_management_plugin (GsPlugin *plugin, GsApp *app, AsApp *item)
-{
- GPtrArray *bundles;
- const gchar *management_plugin = NULL;
-
- /* 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 (guint i = 0; i < bundles->len; i++) {
- AsBundle *bundle = g_ptr_array_index (bundles, i);
- gs_app_add_source (app, as_bundle_get_id (bundle));
- }
-}
+#endif
static gboolean
gs_appstream_refine_app_updates (GsPlugin *plugin,
GsApp *app,
- AsApp *item,
+ XbNode *component,
GError **error)
{
+#if 0
AsUrgencyKind urgency_best = AS_URGENCY_KIND_UNKNOWN;
GPtrArray *releases;
g_autoptr(GPtrArray) updates_list = NULL;
@@ -330,7 +338,7 @@ gs_appstream_refine_app_updates (GsPlugin *plugin,
/* make a list of valid updates */
updates_list = g_ptr_array_new ();
- releases = as_app_get_releases (item);
+ releases = as_app_get_releases (component);
for (guint i = 0; i < releases->len; i++) {
AsRelease *rel = g_ptr_array_index (releases, i);
@@ -395,11 +403,11 @@ gs_appstream_refine_app_updates (GsPlugin *plugin,
/* 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);
+ AsRelease *rel = as_app_get_release_default (component);
if (rel != NULL)
gs_app_set_update_version (app, as_release_get_version (rel));
}
-
+#endif
/* success */
return TRUE;
}
@@ -424,29 +432,6 @@ _gs_utils_locale_has_translations (const gchar *locale)
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)
{
@@ -458,46 +443,144 @@ gs_appstream_origin_valid (const gchar *origin)
}
static gboolean
-gs_appstream_is_valid_project_group (AsApp *item)
+gs_appstream_is_valid_project_group (const gchar *project_group)
{
- const gchar *project_group = as_app_get_project_group (item);
if (project_group == NULL)
return FALSE;
return as_utils_is_environment_id (project_group);
}
+static gchar *
+gs_appstream_format_description (XbNode *root, GError **error)
+{
+ g_autoptr(GString) str = g_string_new (NULL);
+ g_autoptr(XbNode) n = g_object_ref (root);
+
+ while (n != NULL) {
+ g_autoptr(XbNode) n2 = NULL;
+
+ /* support <p>, <ul>, <ol> and <li>, ignore all else */
+ if (g_strcmp0 (xb_node_get_element (n), "p") == 0) {
+ g_string_append_printf (str, "%s\n\n", xb_node_get_text (n));
+ } else if (g_strcmp0 (xb_node_get_element (n), "ul") == 0) {
+ g_autoptr(GPtrArray) children = xb_node_get_children (n);
+ for (guint i = 0; i < children->len; i++) {
+ XbNode *nc = g_ptr_array_index (children, i);
+ if (g_strcmp0 (xb_node_get_element (nc), "li") == 0) {
+ g_string_append_printf (str, " • %s\n",
+ xb_node_get_text (nc));
+ }
+ }
+ g_string_append (str, "\n");
+ } else if (g_strcmp0 (xb_node_get_element (n), "ol") == 0) {
+ g_autoptr(GPtrArray) children = xb_node_get_children (n);
+ for (guint i = 0; i < children->len; i++) {
+ XbNode *nc = g_ptr_array_index (children, i);
+ if (g_strcmp0 (xb_node_get_element (nc), "li") == 0) {
+ g_string_append_printf (str, " %u. %s\n",
+ i + 1,
+ xb_node_get_text (nc));
+ }
+ }
+ g_string_append (str, "\n");
+ }
+
+ n2 = xb_node_get_next (n);
+ g_set_object (&n, n2);
+ }
+
+ /* remove extra newline */
+ if (str->len > 0)
+ g_string_truncate (str, str->len - 1);
+
+ /* success */
+ return g_string_free (g_steal_pointer (&str), FALSE);
+}
+
+static gboolean
+gs_appstream_refine_app_content_rating (GsPlugin *plugin,
+ GsApp *app,
+ XbNode *content_rating,
+ GError **error)
+{
+ g_autoptr(AsContentRating) cr = as_content_rating_new ();
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) content_attributes = NULL;
+
+ /* get kind */
+ as_content_rating_set_kind (cr, xb_node_get_attr (content_rating, "type"));
+
+ /* get attributes */
+ content_attributes = xb_node_query (content_rating, "content_attribute", 0, &error_local);
+ if (content_attributes == NULL) {
+ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ return TRUE;
+ g_propagate_error (error, g_steal_pointer (&error_local));
+ return FALSE;
+ }
+ for (guint i = 0; i < content_attributes->len; i++) {
+ XbNode *content_attribute = g_ptr_array_index (content_attributes, i);
+ as_content_rating_add_attribute (cr,
+ xb_node_get_attr (content_attribute, "id"),
+ as_content_rating_value_from_string (xb_node_get_text
(content_attribute)));
+ }
+
+ /* we only really expect OARS 1.0 and 1.1 */
+ if (g_str_has_prefix (as_content_rating_get_kind (cr), "oars-1."))
+ gs_app_set_content_rating (app, cr);
+ return TRUE;
+}
+
+static gboolean
+gs_appstream_refine_app_content_ratings (GsPlugin *plugin,
+ GsApp *app,
+ XbNode *component,
+ GError **error)
+{
+ g_autoptr(GPtrArray) content_ratings = NULL;
+ g_autoptr(GError) error_local = NULL;
+
+ /* find any content ratings */
+ content_ratings = xb_node_query (component, "content_rating", 0, &error_local);
+ if (content_ratings == NULL) {
+ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ return TRUE;
+ g_propagate_error (error, g_steal_pointer (&error_local));
+ return FALSE;
+ }
+ for (guint i = 0; i < content_ratings->len; i++) {
+ XbNode *content_rating = g_ptr_array_index (content_ratings, i);
+ if (!gs_appstream_refine_app_content_rating (plugin, app, content_rating, error))
+ return FALSE;
+ }
+ return TRUE;
+}
+
gboolean
gs_appstream_refine_app (GsPlugin *plugin,
GsApp *app,
- AsApp *item,
+ XbSilo *silo,
+ XbNode *component,
+ GsPluginRefineFlags refine_flags,
GError **error)
{
- AsRequire *req;
- g_autoptr(GError) error_local = NULL;
- GHashTable *urls;
- GPtrArray *launchables;
- GPtrArray *array;
- GPtrArray *pkgnames;
- GPtrArray *kudos;
const gchar *tmp;
-
- /* 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));
- }
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) bundles = NULL;
+ g_autoptr(GPtrArray) launchables = NULL;
+ g_autoptr(GPtrArray) pkgnames = NULL;
+ g_autoptr(XbNode) req = NULL;
/* is compatible */
- req = as_app_get_require_by_value (item,
- AS_REQUIRE_KIND_ID,
- "org.gnome.Software.desktop");
+ req = xb_node_query_first (component,
+ "requires/id[@type='id']"
+ "[text()='org.gnome.Software.desktop']", NULL);
if (req != NULL) {
- if (!as_require_version_compare (req, PACKAGE_VERSION, &error_local)) {
+ if (as_utils_vercmp (xb_node_get_attr (req, "version"), PACKAGE_VERSION) > 0) {
g_set_error (error,
GS_PLUGIN_ERROR,
GS_PLUGIN_ERROR_NOT_SUPPORTED,
- "not for this gnome-software: %s",
- error_local->message);
+ "not for this gnome-software");
return FALSE;
}
}
@@ -531,330 +614,382 @@ gs_appstream_refine_app (GsPlugin *plugin,
gs_app_remove_quirk (app, AS_APP_QUIRK_NOT_LAUNCHABLE);
}
- /* 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) {
- 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));
- }
- }
-
- /* 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));
+ tmp = xb_node_query_text (component, "id", NULL);
+ if (tmp != NULL && gs_app_get_id (app) == NULL)
+ gs_app_set_id (app, tmp);
/* set content rating */
- array = as_app_get_content_ratings (item);
- for (guint i = 0; i < array->len; i++) {
- AsContentRating *cr = g_ptr_array_index (array, i);
- if (g_str_has_prefix (as_content_rating_get_kind (cr), "oars-1.")) {
- gs_app_set_content_rating (app, cr);
- break;
- }
+ if (refine_flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SCREENSHOTS) { //FIXME: need REQUIRE_CONTENT_RATING
+ if (!gs_appstream_refine_app_content_ratings (plugin, app, component, error))
+ return FALSE;
}
- /* 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);
+ tmp = xb_node_query_text (component, "name", 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) {
+ tmp = xb_node_query_text (component, "summary", 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) {
- g_autoptr(GList) keys = NULL;
- keys = g_hash_table_get_keys (urls);
- for (GList *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));
+ if (refine_flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_URL) {
+ g_autoptr(GPtrArray) urls = NULL;
+ urls = xb_node_query (component, "url", 0, NULL);
+ if (urls != NULL) {
+ for (guint i = 0; i < urls->len; i++) {
+ XbNode *url = g_ptr_array_index (urls, i);
+ const gchar *type = xb_node_get_attr (url, "type");
+ if (type == NULL)
+ continue;
+ gs_app_set_url (app,
+ as_url_kind_from_string (tmp),
+ xb_node_get_text (url));
+ }
}
}
/* add launchables */
- launchables = as_app_get_launchables (item);
- for (guint i = 0; i < launchables->len; i++) {
- AsLaunchable *launchable = g_ptr_array_index (launchables, i);
- switch (as_launchable_get_kind (launchable)) {
- case AS_LAUNCHABLE_KIND_DESKTOP_ID:
- gs_app_set_launchable (app,
- AS_LAUNCHABLE_KIND_DESKTOP_ID,
- as_launchable_get_value (launchable));
- break;
- case AS_LAUNCHABLE_KIND_SERVICE:
- gs_app_set_launchable (app,
- AS_LAUNCHABLE_KIND_SERVICE,
- as_launchable_get_value (launchable));
- break;
- case AS_LAUNCHABLE_KIND_COCKPIT_MANIFEST:
- gs_app_set_launchable (app,
- AS_LAUNCHABLE_KIND_COCKPIT_MANIFEST,
- as_launchable_get_value (launchable));
- break;
- case AS_LAUNCHABLE_KIND_URL:
- gs_app_set_launchable (app,
- AS_LAUNCHABLE_KIND_URL,
- as_launchable_get_value (launchable));
- break;
- default:
- break;
+ launchables = xb_node_query (component, "launchable", 0, NULL);
+ if (launchables != NULL) {
+ for (guint i = 0; i < launchables->len; i++) {
+ XbNode *launchable = g_ptr_array_index (launchables, i);
+ const gchar *kind = xb_node_get_attr (launchable, "type");
+ if (g_strcmp0 (kind, "desktop-id") == 0) {
+ gs_app_set_launchable (app,
+ AS_LAUNCHABLE_KIND_DESKTOP_ID,
+ xb_node_get_text (launchable));
+ break;
+ } else if (g_strcmp0 (kind, "url") == 0) {
+ gs_app_set_launchable (app,
+ AS_LAUNCHABLE_KIND_URL,
+ xb_node_get_text (launchable));
+ }
}
}
/* 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_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));
- }
+ if ((refine_flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_LICENSE) > 0 &&
+ gs_app_get_license (app) == NULL) {
+ tmp = xb_node_query_text (component, "project_license", NULL);
+ if (tmp != NULL)
+ gs_app_set_license (app, GS_APP_QUALITY_HIGHEST, tmp);
}
/* 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);
+ if (refine_flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_DESCRIPTION) {
+ g_autofree gchar *description = NULL;
+ g_autoptr(XbNode) n = xb_node_query_first (component, "description", NULL);
+ if (n != NULL)
+ description = gs_appstream_format_description (n, NULL);
+ if (description != NULL)
+ gs_app_set_description (app, GS_APP_QUALITY_HIGHEST, description);
}
/* set icon */
- if (as_app_get_icon_default (item) != NULL &&
+ if ((refine_flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON) > 0 &&
gs_app_get_icons(app)->len == 0)
- gs_refine_item_icon (plugin, app, item);
+ gs_refine_item_icon (plugin, app, component);
/* set categories */
- array = as_app_get_categories (item);
- if (array != NULL && gs_app_get_categories (app)->len == 0) {
- for (guint i = 0; i < array->len; i++) {
- tmp = g_ptr_array_index (array, i);
- gs_app_add_category (app, tmp);
+ if (refine_flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_CATEGORIES) {
+ g_autoptr(GPtrArray) categories = NULL;
+ categories = xb_node_query (component, "categories/category", 0, NULL);
+ if (categories != NULL) {
+ for (guint i = 0; i < categories->len; i++) {
+ XbNode *category = g_ptr_array_index (categories, i);
+ gs_app_add_category (app, xb_node_get_text (category));
+ }
}
}
/* set project group */
- if (gs_app_get_project_group (app) == NULL &&
- gs_appstream_is_valid_project_group (item))
- gs_app_set_project_group (app, as_app_get_project_group (item));
+ if ((refine_flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_PROJECT_GROUP) > 0 &&
+ gs_app_get_project_group (app) == NULL) {
+ tmp = xb_node_query_text (component, "project_group", NULL);
+ if (tmp != NULL && gs_appstream_is_valid_project_group (tmp))
+ gs_app_set_project_group (app, tmp);
+ }
/* set developer name */
- if (gs_app_get_developer_name (app) == NULL &&
- as_app_get_developer_name (item, NULL) != NULL)
- gs_app_set_developer_name (app, as_app_get_developer_name (item, NULL));
+ if ((refine_flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_DEVELOPER_NAME) > 0 &&
+ gs_app_get_developer_name (app) == NULL) {
+ tmp = xb_node_query_text (component, "developer_name", NULL);
+ if (tmp != NULL)
+ gs_app_set_developer_name (app, tmp);
+ }
/* set id kind */
- if (gs_app_get_kind (app) == AS_APP_KIND_UNKNOWN)
- gs_app_set_kind (app, as_app_get_kind (item));
+ if (gs_app_get_kind (app) == AS_APP_KIND_UNKNOWN ||
+ gs_app_get_kind (app) == AS_APP_KIND_GENERIC) {
+ tmp = xb_node_get_attr (component, "type");
+ gs_app_set_kind (app, as_app_kind_from_string (tmp));
+ }
/* copy all the metadata */
- gs_appstream_copy_metadata (app, item);
+// gs_appstream_copy_metadata (app, component);
+
+ /* add package names */
+ pkgnames = xb_node_query (component, "pkgname", 0, NULL);
+ if (pkgnames != NULL && gs_app_get_sources(app)->len == 0) {
+ for (guint i = 0; i < pkgnames->len; i++) {
+ XbNode *pkgname = g_ptr_array_index (pkgnames, i);
+ gs_app_add_source (app, xb_node_get_text (pkgname));
+ }
+ gs_app_set_bundle_kind (app, AS_BUNDLE_KIND_PACKAGE);
+ }
- /* 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);
+ /* add bundles */
+ bundles = xb_node_query (component, "bundle", 0, NULL);
+ if (bundles != NULL && gs_app_get_sources(app)->len == 0) {
+ for (guint i = 0; i < bundles->len; i++) {
+ XbNode *bundle = g_ptr_array_index (bundles, i);
+ const gchar *kind = xb_node_get_attr (bundle, "type");
+ gs_app_add_source (app, xb_node_get_text (bundle));
+ gs_app_set_bundle_kind (app, as_bundle_kind_from_string (kind));
+ }
+ }
/* set addons */
- if (!gs_appstream_refine_add_addons (plugin, app, item, error))
- return FALSE;
+ if (refine_flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_ADDONS) {
+ if (!gs_appstream_refine_add_addons (plugin, app, silo, error))
+ return FALSE;
+ }
/* set screenshots */
- gs_appstream_refine_add_screenshots (app, item);
-
- /* set reviews */
- gs_appstream_refine_add_reviews (app, item);
+ if ((refine_flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SCREENSHOTS) > 0 &&
+ gs_app_get_screenshots(app)->len == 0) {
+ if (!gs_appstream_refine_add_screenshots (app, component, error))
+ return FALSE;
+ }
/* set provides */
- gs_appstream_refine_add_provides (app, item);
+ if (!gs_appstream_refine_add_provides (app, component, error))
+ return FALSE;
- /* are the screenshots perfect */
- if (gs_appstream_are_screenshots_perfect (item))
- gs_app_add_kudo (app, GS_APP_KUDO_PERFECT_SCREENSHOTS);
+ /* add kudos */
+ if (refine_flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_KUDOS) {
+ g_autoptr(GPtrArray) kudos = NULL;
+ tmp = gs_plugin_get_locale (plugin);
+ if (!_gs_utils_locale_has_translations (tmp)) {
+ gs_app_add_kudo (app, GS_APP_KUDO_MY_LANGUAGE);
+ } else {
+ g_autofree gchar *xpath = NULL;
+ xpath = g_strdup_printf ("languages/lang[text()='%s'][@percentage>50]", tmp);
+ if (xb_node_query_text (component, xpath, NULL) != NULL)
+ gs_app_add_kudo (app, GS_APP_KUDO_MY_LANGUAGE);
+ }
- /* was this application released recently */
- if (gs_appstream_is_recent_release (item))
- gs_app_add_kudo (app, GS_APP_KUDO_RECENT_RELEASE);
+ /* any keywords */
+ if (xb_node_query_text (component, "keywords/keyword", NULL) != NULL)
+ gs_app_add_kudo (app, GS_APP_KUDO_HAS_KEYWORDS);
- /* 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 (guint 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:
+ /* HiDPI icon */
+ if (xb_node_query_text (component, "icon[@width='128']", NULL) != NULL)
gs_app_add_kudo (app, GS_APP_KUDO_HI_DPI_ICON);
- break;
- default:
- break;
+
+ /* are the screenshots perfect */
+ // if (gs_appstream_are_screenshots_perfect (component))
+ // gs_app_add_kudo (app, GS_APP_KUDO_PERFECT_SCREENSHOTS);
+
+ /* was this application released recently */
+ if (gs_appstream_is_recent_release (component))
+ gs_app_add_kudo (app, GS_APP_KUDO_RECENT_RELEASE);
+
+ /* add a kudo to featured and popular apps */
+ if (xb_node_query_text (component, "kudos/kudo[text()='GnomeSoftware::popular']", NULL) !=
NULL)
+ gs_app_add_kudo (app, GS_APP_KUDO_FEATURED_RECOMMENDED);
+ if (xb_node_query_text (component, "categories/category[text()='featured']", NULL) != NULL)
+ gs_app_add_kudo (app, GS_APP_KUDO_FEATURED_RECOMMENDED);
+
+ /* add new-style kudos */
+ kudos = xb_node_query (component, "kudos/kudo", 0, NULL);
+ for (guint i = 0; kudos != NULL && i < kudos->len; i++) {
+ XbNode *kudo = g_ptr_array_index (kudos, i);
+ switch (as_kudo_kind_from_string (xb_node_get_text (kudo))) {
+ 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_appstream (app, as_app_get_origin (item));
+ if ((refine_flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_ORIGIN) > 0 &&
+ gs_app_get_origin_appstream (app) == NULL) {
+ g_autoptr(XbNode) parent = xb_node_get_parent (component);
+ tmp = xb_node_get_attr (parent, "origin");
+ if (gs_appstream_origin_valid (tmp))
+ gs_app_set_origin_appstream (app, tmp);
+ }
/* is there any update information */
- if (!gs_appstream_refine_app_updates (plugin, app, item, error))
- return FALSE;
+ if (refine_flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_UPDATE_DETAILS) {
+ if (!gs_appstream_refine_app_updates (plugin, app, component, error))
+ return FALSE;
+ }
return TRUE;
}
-static gboolean
-gs_appstream_store_search_item (GsPlugin *plugin,
- AsApp *item,
- gchar **values,
- GsAppList *list,
- GCancellable *cancellable,
- GError **error)
+typedef struct {
+ AsAppSearchMatch match_value;
+ gchar *xpath;
+} GsAppstreamSearchHelper;
+
+static void
+gs_appstream_search_helper_free (GsAppstreamSearchHelper *helper)
{
- GPtrArray *addons;
- guint match_value;
- g_autoptr(GsApp) app = NULL;
+ g_free (helper->xpath);
+ g_free (helper);
+}
- /* 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 (guint i = 0; i < addons->len; i++) {
- AsApp *item_tmp = g_ptr_array_index (addons, i);
- match_value |= as_app_search_matches_all (item_tmp, values);
+static guint16
+gs_appstream_silo_search_component2 (XbNode *component, const gchar *search)
+{
+ GsAppstreamSearchHelper *helper;
+ guint16 match_value = 0;
+ g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func ((GDestroyNotify)
gs_appstream_search_helper_free);
+
+ /* mimetype */
+ helper = g_new0 (GsAppstreamSearchHelper, 1);
+ helper->match_value = AS_APP_SEARCH_MATCH_MIMETYPE;
+ helper->xpath = g_strdup_printf ("mimetypes/mimetype[type()~='%s']", search);
+ g_ptr_array_add (array, helper);
+
+ /* package name */
+ helper = g_new0 (GsAppstreamSearchHelper, 1);
+ helper->match_value = AS_APP_SEARCH_MATCH_PKGNAME;
+ helper->xpath = g_strdup_printf ("pkgname[text()~='%s']", search);
+ g_ptr_array_add (array, helper);
+
+ /* summary */
+ helper = g_new0 (GsAppstreamSearchHelper, 1);
+ helper->match_value = AS_APP_SEARCH_MATCH_COMMENT;
+ helper->xpath = g_strdup_printf ("summary[text()~='%s']", search);
+ g_ptr_array_add (array, helper);
+
+ /* name */
+ helper = g_new0 (GsAppstreamSearchHelper, 1);
+ helper->match_value = AS_APP_SEARCH_MATCH_NAME;
+ helper->xpath = g_strdup_printf ("name[text()~='%s']", search);
+ g_ptr_array_add (array, helper);
+
+ /* keywords */
+ helper = g_new0 (GsAppstreamSearchHelper, 1);
+ helper->match_value = AS_APP_SEARCH_MATCH_KEYWORD;
+ helper->xpath = g_strdup_printf ("keywords/keyword[text()~='%s']", search);
+ g_ptr_array_add (array, helper);
+
+ /* AppStream ID */
+ helper = g_new0 (GsAppstreamSearchHelper, 1);
+ helper->match_value = AS_APP_SEARCH_MATCH_ID;
+ helper->xpath = g_strdup_printf ("id[text()~='%s']", search);
+ g_ptr_array_add (array, helper);
+
+ /* origin */
+ helper = g_new0 (GsAppstreamSearchHelper, 1);
+ helper->match_value = AS_APP_SEARCH_MATCH_ORIGIN;
+ helper->xpath = g_strdup_printf ("../components[@origin~='%s']", search);
+ g_ptr_array_add (array, helper);
+
+ /* do searches */
+ for (guint i = 0; i < array->len; i++) {
+ g_autoptr(XbNode) n = NULL;
+ helper = g_ptr_array_index (array, i);
+ n = xb_node_query_first (component, helper->xpath, NULL);
+ if (n != NULL)
+ match_value |= helper->match_value;
}
-
- /* 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;
+ return match_value;
}
-gboolean
-gs_appstream_store_search (GsPlugin *plugin,
- AsStore *store,
- gchar **values,
- GsAppList *list,
- GCancellable *cancellable,
- GError **error)
+static guint16
+gs_appstream_silo_search_component (XbNode *component, gchar **search)
{
- GPtrArray *array;
- gboolean ret = TRUE;
-
- array = as_store_get_apps (store);
- for (guint i = 0; i < array->len; i++) {
- AsApp *item = g_ptr_array_index (array, i);
- if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
- gs_utils_error_convert_gio (error);
- return FALSE;
- }
- ret = gs_appstream_store_search_item (plugin, item,
- values, list,
- cancellable, error);
- if (!ret)
- return FALSE;
+ guint16 matches_sum = 0;
+
+ /* do *all* search keywords match */
+ for (guint i = 0; search[i] != NULL; i++) {
+ guint tmp = gs_appstream_silo_search_component2 (component, search[i]);
+ if (tmp == 0)
+ return 0;
+ matches_sum |= tmp;
}
- return TRUE;
+ return matches_sum;
}
-static gboolean
-_as_app_matches_desktop_group_set (AsApp *app, gchar **desktop_groups)
+gboolean
+gs_appstream_silo_search (GsPlugin *plugin,
+ XbSilo *silo,
+ gchar **values,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
{
- for (guint i = 0; desktop_groups[i] != NULL; i++) {
- if (!as_app_has_category (app, desktop_groups[i]))
- return FALSE;
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) components = NULL;
+ g_autoptr(GTimer) timer = g_timer_new ();
+
+ /* get all components */
+ components = xb_silo_query (silo, "components/component", 0, &error_local);
+ if (components == NULL) {
+ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ return TRUE;
+ g_propagate_error (error, g_steal_pointer (&error_local));
+ return FALSE;
}
+ for (guint i = 0; i < components->len; i++) {
+ XbNode *component = g_ptr_array_index (components, i);
+ guint16 match_value = gs_appstream_silo_search_component (component, values);
+ if (match_value != 0) {
+ g_autoptr(GsApp) app = gs_appstream_create_app (plugin, silo, component, error);
+ if (app == NULL)
+ return FALSE;
+ g_debug ("add %s", gs_app_get_id (app));
+ gs_app_set_match_value (app, match_value);
+ gs_app_list_add (list, app);
+ }
+ }
+ g_debug ("search took %fms", g_timer_elapsed (timer, NULL) * 1000);
return TRUE;
}
static gboolean
-_as_app_matches_desktop_group (AsApp *app, const gchar *desktop_group)
+gs_appstream_silo_component_matches_groups (XbNode *component, const gchar *desktop_group)
{
g_auto(GStrv) split = g_strsplit (desktop_group, "::", -1);
- return _as_app_matches_desktop_group_set (app, split);
+ g_autofree gchar *xpath = NULL;
+ xpath = g_strdup_printf ("categories/category[text()='%s']/../category[text()='%s']",
+ split[0], split[1]);
+ return xb_node_query_text (component, xpath, NULL) != NULL;
}
static void
-gs_appstream_store_add_categories_for_app (GsCategory *parent, AsApp *app)
+gs_appstream_silo_add_categories_for_app (GsCategory *parent, XbNode *component)
{
GPtrArray *children;
GPtrArray *desktop_groups;
@@ -869,7 +1004,7 @@ gs_appstream_store_add_categories_for_app (GsCategory *parent, AsApp *app)
desktop_groups = gs_category_get_desktop_groups (category);
for (guint 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)) {
+ if (gs_appstream_silo_component_matches_groups (component, desktop_group)) {
matched = TRUE;
break;
}
@@ -882,18 +1017,16 @@ gs_appstream_store_add_categories_for_app (GsCategory *parent, AsApp *app)
}
gboolean
-gs_appstream_store_add_category_apps (GsPlugin *plugin,
- AsStore *store,
- GsCategory *category,
- GsAppList *list,
- GCancellable *cancellable,
- GError **error)
+gs_appstream_silo_add_category_apps (GsPlugin *plugin,
+ XbSilo *silo,
+ GsCategory *category,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
{
- GPtrArray *array;
GPtrArray *desktop_groups;
+ g_autoptr(GError) error_local = NULL;
- /* just look at each app in turn */
- 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));
@@ -901,52 +1034,72 @@ gs_appstream_store_add_category_apps (GsPlugin *plugin,
}
for (guint j = 0; j < desktop_groups->len; j++) {
const gchar *desktop_group = g_ptr_array_index (desktop_groups, j);
+ g_autofree gchar *xpath = NULL;
g_auto(GStrv) split = g_strsplit (desktop_group, "::", -1);
+ g_autoptr(GPtrArray) components = NULL;
+
+ /* generate query */
+ if (g_strv_length (split) == 1) {
+ xpath = g_strdup_printf ("components/component/categories/"
+ "category[text()='%s']/../..",
+ split[0]);
+ } else if (g_strv_length (split) == 2) {
+ xpath = g_strdup_printf ("components/component/categories/"
+ "category[text()='%s']/../"
+ "category[text()='%s']/../..",
+ split[0], split[1]);
+ }
+ components = xb_silo_query (silo, xpath, 0, &error_local);
+ if (components == NULL) {
+ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ return TRUE;
+ g_propagate_error (error, g_steal_pointer (&error_local));
+ return FALSE;
+ }
- /* match the app */
- for (guint i = 0; i < array->len; i++) {
- AsApp *item;
+ /* create app */
+ for (guint i = 0; i < components->len; i++) {
+ XbNode *component = g_ptr_array_index (components, i);
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);
+ app = gs_appstream_create_app (plugin, silo, component, error);
if (app == NULL)
return FALSE;
gs_app_list_add (list, app);
}
+
}
return TRUE;
}
gboolean
-gs_appstream_store_add_categories (GsPlugin *plugin,
- AsStore *store,
+gs_appstream_silo_add_categories (GsPlugin *plugin,
+ XbSilo *silo,
GPtrArray *list,
GCancellable *cancellable,
GError **error)
{
- GPtrArray *array;
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) array = NULL;
/* find out how many packages are in each category */
- array = as_store_get_apps (store);
+ array = xb_silo_query (silo, "components/component", 0, &error_local);
+ if (array == NULL) {
+ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ return TRUE;
+ g_propagate_error (error, g_steal_pointer (&error_local));
+ return FALSE;
+ }
for (guint i = 0; i < array->len; i++) {
- AsApp *app = g_ptr_array_index (array, i);
- if (as_app_get_id (app) == NULL)
- continue;
- if (as_app_get_priority (app) < 0)
- continue;
+ XbNode *component = g_ptr_array_index (array, i);
+// if (xb_node_query_text (component, "id (app) == NULL)
+// continue;
+// if (xb_node_query_text (component, "priority (app) < 0)
+// continue;
for (guint 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);
+ gs_appstream_silo_add_categories_for_app (parent, component);
}
}
return TRUE;
@@ -954,60 +1107,65 @@ gs_appstream_store_add_categories (GsPlugin *plugin,
gboolean
gs_appstream_add_popular (GsPlugin *plugin,
- AsStore *store,
+ XbSilo *silo,
GsAppList *list,
GCancellable *cancellable,
GError **error)
{
- GPtrArray *array = as_store_get_apps (store);
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) array = NULL;
+
+ /* find out how many packages are in each category */
+ array = xb_silo_query (silo,
+ "components/component/kudos/"
+ "kudo[text()='GnomeSoftware::popular'/../..",
+ 0, &error_local);
+ if (array == NULL) {
+ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ return TRUE;
+ g_propagate_error (error, g_steal_pointer (&error_local));
+ return FALSE;
+ }
for (guint i = 0; i < array->len; i++) {
g_autoptr(GsApp) app = NULL;
- AsApp *item = g_ptr_array_index (array, i);
- if (as_app_get_id (item) == NULL)
- continue;
- if (!as_app_has_kudo (item, "GnomeSoftware::popular"))
+ XbNode *component = g_ptr_array_index (array, i);
+ const gchar *component_id = xb_node_query_text (component, "id", NULL);
+ if (component_id == NULL)
continue;
- app = gs_app_new (as_app_get_id (item));
+ app = gs_app_new (component_id);
gs_app_add_quirk (app, AS_APP_QUIRK_MATCH_ANY_PREFIX);
gs_app_list_add (list, app);
}
return TRUE;
}
-static gboolean
-_as_app_is_recent (AsApp *app, guint64 age)
-{
- AsRelease *rel;
- guint64 ts;
- guint64 now;
-
- rel = as_app_get_release_default (app);
- if (rel == NULL)
- return FALSE;
- ts = as_release_get_timestamp (rel);
- if (ts == 0)
- return FALSE;
- now = (guint64) g_get_real_time () / G_USEC_PER_SEC;
- return (now - ts) < age;
-}
-
gboolean
gs_appstream_add_recent (GsPlugin *plugin,
- AsStore *store,
+ XbSilo *silo,
GsAppList *list,
guint64 age,
GCancellable *cancellable,
GError **error)
{
- GPtrArray *array = as_store_get_apps (store);
+ guint64 now = (guint64) g_get_real_time () / G_USEC_PER_SEC;
+ g_autofree gchar *xpath = NULL;
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) array = NULL;
+
+ /* use predicate conditions to the max */
+ xpath = g_strdup_printf ("components/component/releases/"
+ "release[@timestamp>%" G_GUINT64_FORMAT "]/../..",
+ now - (30 * 24 * 60 * 60));
+ array = xb_silo_query (silo, xpath, 0, &error_local);
+ if (array == NULL) {
+ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ return TRUE;
+ g_propagate_error (error, g_steal_pointer (&error_local));
+ return FALSE;
+ }
for (guint i = 0; i < array->len; i++) {
- g_autoptr(GsApp) app = NULL;
- AsApp *item = g_ptr_array_index (array, i);
- if (as_app_get_id (item) == NULL)
- continue;
- if (!_as_app_is_recent (item, age))
- continue;
- app = gs_appstream_create_app (plugin, item, error);
+ XbNode *component = g_ptr_array_index (array, i);
+ g_autoptr(GsApp) app = gs_appstream_create_app (plugin, silo, component, error);
if (app == NULL)
return FALSE;
gs_app_list_add (list, app);
@@ -1015,97 +1173,47 @@ gs_appstream_add_recent (GsPlugin *plugin,
return TRUE;
}
-static void
-_g_ptr_array_add_str_uniq (GPtrArray *array, const gchar *str)
-{
- if (str == NULL)
- return;
- for (guint i = 0; i < array->len; i++) {
- const gchar *str_tmp = g_ptr_array_index (array, i);
- if (g_strcmp0 (str, str_tmp) == 0)
- return;
- }
- g_ptr_array_add (array, g_strdup (str));
-}
-
-/* add the component ID for any matching <provide><id/></provide> value */
-static void
-gs_appstream_add_alternates_new_id (GPtrArray *array, AsApp *item, const gchar *id)
-{
- GPtrArray *provides = as_app_get_provides (item);
- for (guint i = 0; i < provides->len; i++) {
- AsProvide *provide = g_ptr_array_index (provides, i);
- if (as_provide_get_kind (provide) == AS_PROVIDE_KIND_ID &&
- g_strcmp0 (as_provide_get_value (provide), id) == 0) {
- _g_ptr_array_add_str_uniq (array, as_app_get_id (item));
- break;
- }
- }
-
-}
-
-/* add all <provide><id/></provide> values for a matching component ID */
-static void
-gs_appstream_add_alternates_old_id (GPtrArray *array, AsApp *item, const gchar *id)
-{
- GPtrArray *provides;
- if (g_strcmp0 (as_app_get_id (item), id) != 0)
- return;
- provides = as_app_get_provides (item);
- for (guint i = 0; i < provides->len; i++) {
- AsProvide *provide = g_ptr_array_index (provides, i);
- if (as_provide_get_kind (provide) == AS_PROVIDE_KIND_ID)
- _g_ptr_array_add_str_uniq (array, as_provide_get_value (provide));
- }
-}
-
-/* find any matching package names */
-static void
-gs_appstream_add_alternates_source (GPtrArray *array, AsApp *item, const gchar *source)
-{
- GPtrArray *item_pkgnames = as_app_get_pkgnames (item);
- for (guint i = 0; i < item_pkgnames->len; i++) {
- const gchar *pkgname = g_ptr_array_index (item_pkgnames, i);
- if (g_strcmp0 (pkgname, source) == 0) {
- _g_ptr_array_add_str_uniq (array, as_app_get_id (item));
- break;
- }
- }
-}
-
gboolean
gs_appstream_add_alternates (GsPlugin *plugin,
- AsStore *store,
+ XbSilo *silo,
GsApp *app,
GsAppList *list,
GCancellable *cancellable,
GError **error)
{
- GPtrArray *apps = as_store_get_apps (store);
- GPtrArray *ids = g_ptr_array_new_with_free_func (g_free);
-
- /* find apps that provide the new name */
- for (guint i = 0; i < apps->len; i++) {
- AsApp *item = g_ptr_array_index (apps, i);
- GPtrArray *sources = gs_app_get_sources (app);
-
- /* new ID -> old ID */
- gs_appstream_add_alternates_old_id (ids, item, gs_app_get_id (app));
-
- /* old ID -> new ID */
- gs_appstream_add_alternates_new_id (ids, item, gs_app_get_id (app));
-
- /* find apps that use the same pkgname */
- for (guint j = 0; j < sources->len; j++) {
- const gchar *source = g_ptr_array_index (sources, j);
- gs_appstream_add_alternates_source (ids, item, source);
- }
+ GPtrArray *sources = gs_app_get_sources (app);
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) ids = NULL;
+ g_autoptr(GString) xpath = g_string_new (NULL);
+
+ /* new ID -> old ID */
+ g_string_append_printf (xpath, "components/component/id[text()='%s']/../provides/id",
+ gs_app_get_id (app));
+
+ /* old ID -> new ID */
+ g_string_append (xpath, "|");
+ g_string_append_printf (xpath, "components/component/provides/id[text()='%s']/../../id",
+ gs_app_get_id (app));
+
+ /* find apps that use the same pkgname */
+ for (guint j = 0; j < sources->len; j++) {
+ const gchar *source = g_ptr_array_index (sources, j);
+ g_string_append (xpath, "|");
+ g_string_append_printf (xpath, "components/component/pkgname[text()='%s']/../id", source);
}
- /* add all results */
+ /* do a big query, and return all the unique results */
+ ids = xb_silo_query (silo, xpath->str, 0, &error_local);
+ if (ids == NULL) {
+ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ return TRUE;
+ g_propagate_error (error, g_steal_pointer (&error_local));
+ return FALSE;
+ }
for (guint i = 0; i < ids->len; i++) {
- const gchar *id = g_ptr_array_index (ids, i);
- g_autoptr(GsApp) app2 = gs_app_new (id);
+ XbNode *n = g_ptr_array_index (ids, i);
+ g_autoptr(GsApp) app2 = NULL;
+ app2 = gs_app_new (xb_node_get_text (n));
gs_app_add_quirk (app2, AS_APP_QUIRK_MATCH_ANY_PREFIX);
gs_app_list_add (list, app2);
}
@@ -1114,20 +1222,32 @@ gs_appstream_add_alternates (GsPlugin *plugin,
gboolean
gs_appstream_add_featured (GsPlugin *plugin,
- AsStore *store,
+ XbSilo *silo,
GsAppList *list,
GCancellable *cancellable,
GError **error)
{
- GPtrArray *array = as_store_get_apps (store);
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) array = NULL;
+
+ /* find out how many packages are in each category */
+ array = xb_silo_query (silo,
+ "components/component/kudos/"
+ "kudo[text()='GnomeSoftware::FeatureTile-css'/../..",
+ 0, &error_local);
+ if (array == NULL) {
+ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ return TRUE;
+ g_propagate_error (error, g_steal_pointer (&error_local));
+ return FALSE;
+ }
for (guint i = 0; i < array->len; i++) {
g_autoptr(GsApp) app = NULL;
- AsApp *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)
+ XbNode *component = g_ptr_array_index (array, i);
+ const gchar *component_id = xb_node_query_text (component, "id", NULL);
+ if (component_id == NULL)
continue;
- app = gs_app_new (as_app_get_id (item));
+ app = gs_app_new (component_id);
gs_app_add_quirk (app, AS_APP_QUIRK_MATCH_ANY_PREFIX);
gs_app_list_add (list, app);
}
@@ -1135,78 +1255,101 @@ gs_appstream_add_featured (GsPlugin *plugin,
}
void
-gs_appstream_add_extra_info (GsPlugin *plugin, AsApp *app)
+gs_appstream_add_keyword (XbBuilderNode *component, const gchar *str)
{
- const gchar *tmp;
- g_autoptr(AsIcon) icon = NULL;
+ g_autoptr(XbBuilderNode) keyword = NULL;
+ g_autoptr(XbBuilderNode) keywords = NULL;
+
+ /* create <keywords> if it does not already exist */
+ keywords = xb_builder_node_get_child (component, "keywords", NULL);
+ if (keywords == NULL)
+ keywords = xb_builder_node_insert (component, "keywords", NULL);
+
+ /* create <keyword>str</keyword> if it does not already exist */
+ keyword = xb_builder_node_get_child (keywords, "keyword", str);
+ if (keyword == NULL) {
+ keyword = xb_builder_node_insert (keywords, "keyword", NULL);
+ xb_builder_node_set_text (keyword, str, -1);
+ }
+}
- /* 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;
+void
+gs_appstream_add_category (XbBuilderNode *component, const gchar *str)
+{
+ g_autoptr(XbBuilderNode) category = NULL;
+ g_autoptr(XbBuilderNode) categories = NULL;
+
+ /* create <categories> if it does not already exist */
+ categories = xb_builder_node_get_child (component, "categories", NULL);
+ if (categories == NULL)
+ categories = xb_builder_node_insert (component, "categories", NULL);
+
+ /* create <category>str</category> if it does not already exist */
+ category = xb_builder_node_get_child (categories, "category", str);
+ if (category == NULL) {
+ category = xb_builder_node_insert (categories, "category", NULL);
+ xb_builder_node_set_text (category, str, -1);
}
+}
+
+void
+gs_appstream_add_icon (XbBuilderNode *component, const gchar *str)
+{
+ g_autoptr(XbBuilderNode) icon = NULL;
+
+ /* create <icon>str</icon> if it does not already exist */
+ icon = xb_builder_node_get_child (component, "icon", NULL);
+ if (icon == NULL) {
+ icon = xb_builder_node_insert (component, "icon",
+ "type", "stock",
+ NULL);
+ xb_builder_node_set_text (icon, str, -1);
+ }
+}
+
+void
+gs_appstream_add_extra_info (GsPlugin *plugin, XbBuilderNode *component)
+{
+ const gchar *kind = xb_builder_node_get_attr (component, "type");
/* add the gnome-software-specific 'Addon' group and ensure they
* all have an icon set */
- switch (as_app_get_kind (app)) {
+ switch (as_app_kind_from_string (kind)) {
+ case AS_APP_KIND_WEB_APP:
+ gs_appstream_add_keyword (component, kind);
+ break;
case AS_APP_KIND_FONT:
- as_app_add_category (app, "Addon");
- as_app_add_category (app, "Font");
+ gs_appstream_add_category (component, "Addon");
+ gs_appstream_add_category (component, "Font");
break;
case AS_APP_KIND_SHELL_EXTENSION:
- as_app_add_category (app, "Addon");
- as_app_add_category (app, "ShellExtension");
- if (g_hash_table_size (as_app_get_comments (app)) == 0)
- as_app_set_comment (app, NULL, "GNOME Shell Extension");
- icon = as_icon_new ();
- as_icon_set_kind (icon, AS_ICON_KIND_STOCK);
- as_icon_set_name (icon, "application-x-addon-symbolic");
- as_app_add_icon (app, icon);
+ gs_appstream_add_category (component, "Addon");
+ gs_appstream_add_category (component, "ShellExtension");
+ gs_appstream_add_icon (component, "application-x-addon-symbolic");
break;
case AS_APP_KIND_DRIVER:
- as_app_add_category (app, "Addon");
- as_app_add_category (app, "Driver");
- icon = as_icon_new ();
- as_icon_set_kind (icon, AS_ICON_KIND_STOCK);
- as_icon_set_name (icon, "application-x-firmware-symbolic");
- as_app_add_icon (app, icon);
+ gs_appstream_add_category (component, "Addon");
+ gs_appstream_add_category (component, "Driver");
+ gs_appstream_add_icon (component, "application-x-firmware-symbolic");
break;
case AS_APP_KIND_LOCALIZATION:
- as_app_add_category (app, "Addon");
- as_app_add_category (app, "Localization");
- 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);
+ gs_appstream_add_category (component, "Addon");
+ gs_appstream_add_category (component, "Localization");
+ gs_appstream_add_icon (component, "accessories-dictionary-symbolic");
break;
case AS_APP_KIND_CODEC:
- as_app_add_category (app, "Addon");
- as_app_add_category (app, "Codec");
- icon = as_icon_new ();
- as_icon_set_kind (icon, AS_ICON_KIND_STOCK);
- as_icon_set_name (icon, "application-x-addon");
- as_app_add_icon (app, icon);
+ gs_appstream_add_category (component, "Addon");
+ gs_appstream_add_category (component, "Codec");
+ gs_appstream_add_icon (component, "application-x-addon");
break;
case AS_APP_KIND_INPUT_METHOD:
- as_app_add_category (app, "Addon");
- as_app_add_category (app, "InputSource");
- icon = as_icon_new ();
- as_icon_set_kind (icon, AS_ICON_KIND_STOCK);
- as_icon_set_name (icon, "system-run-symbolic");
- as_app_add_icon (app, icon);
+ gs_appstream_add_keyword (component, kind);
+ gs_appstream_add_category (component, "Addon");
+ gs_appstream_add_category (component, "InputSource");
+ gs_appstream_add_icon (component, "system-run-symbolic");
break;
case AS_APP_KIND_FIRMWARE:
- icon = as_icon_new ();
- as_icon_set_kind (icon, AS_ICON_KIND_STOCK);
- as_icon_set_name (icon, "system-run-symbolic");
- as_app_add_icon (app, icon);
+ gs_appstream_add_icon (component, "system-run-symbolic");
break;
default:
break;
diff --git a/plugins/core/gs-appstream.h b/plugins/core/gs-appstream.h
index 29ccc11a..81e882a0 100644
--- a/plugins/core/gs-appstream.h
+++ b/plugins/core/gs-appstream.h
@@ -23,57 +23,67 @@
#define __APPSTREAM_COMMON_H
#include <gnome-software.h>
+#include <xmlb.h>
G_BEGIN_DECLS
GsApp *gs_appstream_create_app (GsPlugin *plugin,
- AsApp *item,
+ XbSilo *silo,
+ XbNode *component,
GError **error);
gboolean gs_appstream_refine_app (GsPlugin *plugin,
GsApp *app,
- AsApp *item,
+ XbSilo *silo,
+ XbNode *component,
+ GsPluginRefineFlags flags,
GError **error);
-gboolean gs_appstream_store_search (GsPlugin *plugin,
- AsStore *store,
+gboolean gs_appstream_silo_search (GsPlugin *plugin,
+ XbSilo *silo,
gchar **values,
GsAppList *list,
GCancellable *cancellable,
GError **error);
-gboolean gs_appstream_store_add_categories (GsPlugin *plugin,
- AsStore *store,
+gboolean gs_appstream_silo_add_categories (GsPlugin *plugin,
+ XbSilo *silo,
GPtrArray *list,
GCancellable *cancellable,
GError **error);
-gboolean gs_appstream_store_add_category_apps (GsPlugin *plugin,
- AsStore *store,
+gboolean gs_appstream_silo_add_category_apps (GsPlugin *plugin,
+ XbSilo *silo,
GsCategory *category,
GsAppList *list,
GCancellable *cancellable,
GError **error);
gboolean gs_appstream_add_popular (GsPlugin *plugin,
- AsStore *store,
+ XbSilo *silo,
GsAppList *list,
GCancellable *cancellable,
GError **error);
gboolean gs_appstream_add_featured (GsPlugin *plugin,
- AsStore *store,
+ XbSilo *silo,
GsAppList *list,
GCancellable *cancellable,
GError **error);
gboolean gs_appstream_add_alternates (GsPlugin *plugin,
- AsStore *store,
+ XbSilo *silo,
GsApp *app,
GsAppList *list,
GCancellable *cancellable,
GError **error);
gboolean gs_appstream_add_recent (GsPlugin *plugin,
- AsStore *store,
+ XbSilo *silo,
GsAppList *list,
guint64 age,
GCancellable *cancellable,
GError **error);
void gs_appstream_add_extra_info (GsPlugin *plugin,
- AsApp *app);
+ XbBuilderNode *component);
+void gs_appstream_add_keyword (XbBuilderNode *component,
+ const gchar *str);
+void gs_appstream_add_category (XbBuilderNode *component,
+ const gchar *str);
+void gs_appstream_add_icon (XbBuilderNode *component,
+ const gchar *str);
G_END_DECLS
diff --git a/plugins/core/gs-plugin-appstream.c b/plugins/core/gs-plugin-appstream.c
index 88c55c55..d9bef170 100644
--- a/plugins/core/gs-plugin-appstream.c
+++ b/plugins/core/gs-plugin-appstream.c
@@ -24,6 +24,7 @@
#include <glib/gi18n.h>
#include <gnome-software.h>
+#include <xmlb.h>
#include "gs-appstream.h"
@@ -39,255 +40,277 @@
*/
struct GsPluginData {
- AsStore *store;
- GHashTable *app_hash_old;
- guint store_changed_id;
+ XbSilo *silo;
GSettings *settings;
};
-#define GS_PLUGIN_NUMBER_CHANGED_RELOAD 10
-
-static GHashTable *
-gs_plugin_appstream_create_app_hash (AsStore *store)
+void
+gs_plugin_initialize (GsPlugin *plugin)
{
- GHashTable *hash;
- GPtrArray *apps;
- guint i;
-
- hash = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, (GDestroyNotify) g_object_unref);
- apps = as_store_get_apps (store);
- for (i = 0; i < apps->len; i++) {
- AsApp *app = g_ptr_array_index (apps, i);
- gchar *key = g_strdup (as_app_get_id (app));
- g_hash_table_insert (hash, key, g_object_ref (app));
- }
- return hash;
+ GsPluginData *priv = gs_plugin_alloc_data (plugin, sizeof(GsPluginData));
+
+ /* need package name */
+ gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_RUN_AFTER, "dpkg");
+
+ /* require settings */
+ priv->settings = g_settings_new ("org.gnome.software");
}
-static void
-gs_plugin_detect_reload_apps (GsPlugin *plugin)
+void
+gs_plugin_destroy (GsPlugin *plugin)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- AsApp *item;
- GsApp *app;
- guint cnt = 0;
- g_autoptr(GHashTable) app_hash = NULL;
- g_autoptr(GList) keys = NULL;
- g_autoptr(GList) keys_old = NULL;
-
- /* find packages that have been added */
- app_hash = gs_plugin_appstream_create_app_hash (priv->store);
- keys = g_hash_table_get_keys (app_hash);
- for (GList *l = keys; l != NULL; l = l->next) {
- const gchar *key = l->data;
- item = g_hash_table_lookup (priv->app_hash_old, key);
- if (item == NULL) {
- item = g_hash_table_lookup (app_hash, key);
- app = gs_plugin_cache_lookup (plugin,
- as_app_get_unique_id (item));
- if (app != NULL)
- g_debug ("added GsApp %s", gs_app_get_id (app));
- cnt++;
- }
- }
+ g_object_unref (priv->silo);
+ g_object_unref (priv->settings);
+}
- /* find packages that have been removed */
- keys_old = g_hash_table_get_keys (priv->app_hash_old);
- for (GList *l = keys_old; l != NULL; l = l->next) {
- const gchar *key = l->data;
- item = g_hash_table_lookup (app_hash, key);
- if (item == NULL) {
- item = g_hash_table_lookup (priv->app_hash_old, key);
- app = gs_plugin_cache_lookup (plugin,
- as_app_get_unique_id (item));
- if (app != NULL)
- g_debug ("removed GsApp %s", gs_app_get_id (app));
- cnt++;
+static gboolean
+gs_plugin_appstream_upgrade_cb (XbBuilderSource *self,
+ XbBuilderNode *bn,
+ gpointer user_data,
+ GError **error)
+{
+ if (g_strcmp0 (xb_builder_node_get_element (bn), "application") == 0) {
+ g_autoptr(XbBuilderNode) id = xb_builder_node_get_child (bn, "id", NULL);
+ g_autofree gchar *kind = NULL;
+ if (id != NULL) {
+ kind = g_strdup (xb_builder_node_get_attr (id, "type"));
+ xb_builder_node_remove_attr (id, "type");
}
+ if (kind != NULL)
+ xb_builder_node_set_attr (bn, "type", kind);
+ xb_builder_node_set_element (bn, "component");
+ } else if (g_strcmp0 (xb_builder_node_get_element (bn), "metadata") == 0) {
+ xb_builder_node_set_element (bn, "custom");
}
-
- /* replace if any changes */
- if (cnt > 0) {
- if (priv->app_hash_old != NULL)
- g_hash_table_unref (priv->app_hash_old);
- priv->app_hash_old = g_hash_table_ref (app_hash);
- }
-
- /* invalidate all if a large number of apps changed */
- if (cnt > GS_PLUGIN_NUMBER_CHANGED_RELOAD) {
- g_debug ("%u is more than %i AsApps changed",
- cnt, GS_PLUGIN_NUMBER_CHANGED_RELOAD);
- gs_plugin_reload (plugin);
- }
+ return TRUE;
}
-static void
-gs_plugin_appstream_store_changed_cb (AsStore *store, GsPlugin *plugin)
+static gboolean
+gs_plugin_appstream_add_icons_cb (XbBuilderSource *self,
+ XbBuilderNode *bn,
+ gpointer user_data,
+ GError **error)
{
- g_debug ("AppStream metadata changed");
-
- /* send ::reload-apps */
- gs_plugin_detect_reload_apps (plugin);
-
- /* all the UI is reloaded as something external has happened */
- if (!gs_plugin_has_flags (plugin, GS_PLUGIN_FLAGS_RUNNING_OTHER))
- gs_plugin_reload (plugin);
+ GsPlugin *plugin = GS_PLUGIN (user_data);
+ if (g_strcmp0 (xb_builder_node_get_element (bn), "component") != 0)
+ return TRUE;
+ gs_appstream_add_extra_info (plugin, bn);
+ return TRUE;
}
-static void
-gs_plugin_appstream_store_app_added_cb (AsStore *store,
- AsApp *app,
- GsPlugin *plugin)
+static gboolean
+gs_plugin_appstream_add_origin_keyword_cb (XbBuilderSource *self,
+ XbBuilderNode *bn,
+ gpointer user_data,
+ GError **error)
{
- gs_appstream_add_extra_info (plugin, app);
+ if (g_strcmp0 (xb_builder_node_get_element (bn), "components") == 0) {
+ const gchar *origin = xb_builder_node_get_attr (bn, "origin");
+ GPtrArray *components = xb_builder_node_get_children (bn);
+ if (origin == NULL || origin[0] == '\0')
+ return TRUE;
+ g_debug ("origin %s has %u components", origin, components->len);
+ if (components->len < 200) {
+ for (guint i = 0; i < components->len; i++) {
+ XbBuilderNode *component = g_ptr_array_index (components, i);
+ gs_appstream_add_keyword (component, origin);
+ }
+ }
+ }
+ return TRUE;
}
-static void
-gs_plugin_appstream_store_app_removed_cb (AsStore *store,
- AsApp *app,
- GsPlugin *plugin)
+static gboolean
+gs_plugin_appstream_load_appdata (GsPlugin *plugin,
+ XbBuilder *builder,
+ const gchar *path,
+ GCancellable *cancellable,
+ GError **error)
{
- g_debug ("AppStream app was removed, doing delete from global cache");
- gs_plugin_cache_remove (plugin, as_app_get_unique_id (app));
-}
+ const gchar *fn;
+ g_autoptr(GDir) dir = g_dir_open (path, 0, error);
+ g_autoptr(GFile) parent = g_file_new_for_path (path);
+ if (!g_file_query_exists (parent, cancellable))
+ return TRUE;
+ if (dir == NULL)
+ return FALSE;
+ while ((fn = g_dir_read_name (dir)) != NULL) {
+ if (g_str_has_suffix (fn, ".appdata.xml") ||
+ g_str_has_suffix (fn, ".metainfo.xml")) {
+ g_autofree gchar *filename = g_build_filename (path, fn, NULL);
+ g_autoptr(GFile) file = g_file_new_for_path (filename);
+ g_autoptr(XbBuilderSource) source = NULL;
+
+ /* add source */
+ source = xb_builder_source_new_file (file,
+ XB_BUILDER_SOURCE_FLAG_WATCH_FILE,
+ cancellable,
+ error);
+ if (source == NULL)
+ return FALSE;
-void
-gs_plugin_initialize (GsPlugin *plugin)
-{
- GsPluginData *priv = gs_plugin_alloc_data (plugin, sizeof(GsPluginData));
- priv->store = as_store_new ();
- g_signal_connect (priv->store, "app-added",
- G_CALLBACK (gs_plugin_appstream_store_app_added_cb),
- plugin);
- g_signal_connect (priv->store, "app-removed",
- G_CALLBACK (gs_plugin_appstream_store_app_removed_cb),
- plugin);
- as_store_set_add_flags (priv->store,
- AS_STORE_ADD_FLAG_USE_UNIQUE_ID |
- AS_STORE_ADD_FLAG_ONLY_NATIVE_LANGS |
- AS_STORE_ADD_FLAG_USE_MERGE_HEURISTIC);
- as_store_set_watch_flags (priv->store,
- AS_STORE_WATCH_FLAG_ADDED |
- AS_STORE_WATCH_FLAG_REMOVED);
- as_store_set_search_match (priv->store,
- AS_APP_SEARCH_MATCH_MIMETYPE |
- AS_APP_SEARCH_MATCH_PKGNAME |
- AS_APP_SEARCH_MATCH_COMMENT |
- AS_APP_SEARCH_MATCH_NAME |
- AS_APP_SEARCH_MATCH_KEYWORD |
- AS_APP_SEARCH_MATCH_ID);
+ /* fix up any legacy installed files */
+ xb_builder_source_add_node_func (source, "AppStreamUpgrade",
+ gs_plugin_appstream_upgrade_cb,
+ plugin, NULL);
- /* need package name */
- gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_RUN_AFTER, "dpkg");
+ /* success */
+ xb_builder_import_source (builder, source);
+ }
+ }
- /* require settings */
- priv->settings = g_settings_new ("org.gnome.software");
+ /* success */
+ return TRUE;
}
-void
-gs_plugin_destroy (GsPlugin *plugin)
+static gboolean
+gs_plugin_appstream_load_appstream (GsPlugin *plugin,
+ XbBuilder *builder,
+ const gchar *path,
+ GCancellable *cancellable,
+ GError **error)
{
- GsPluginData *priv = gs_plugin_get_data (plugin);
- if (priv->store_changed_id != 0)
- g_signal_handler_disconnect (priv->store, priv->store_changed_id);
- if (priv->app_hash_old != NULL)
- g_hash_table_unref (priv->app_hash_old);
- g_object_unref (priv->store);
- g_object_unref (priv->settings);
-}
+ const gchar *fn;
+ g_autoptr(GDir) dir = g_dir_open (path, 0, error);
+ g_autoptr(GFile) parent = g_file_new_for_path (path);
+ if (!g_file_query_exists (parent, cancellable))
+ return TRUE;
+ if (dir == NULL)
+ return FALSE;
+ while ((fn = g_dir_read_name (dir)) != NULL) {
+ if (g_str_has_suffix (fn, ".xml") ||
+ g_str_has_suffix (fn, ".xml.gz")) {
+ g_autofree gchar *filename = g_build_filename (path, fn, NULL);
+ g_autoptr(GFile) file = g_file_new_for_path (filename);
+ g_autoptr(XbBuilderSource) source = NULL;
+
+ /* add source */
+ source = xb_builder_source_new_file (file,
+ XB_BUILDER_SOURCE_FLAG_WATCH_FILE |
+ XB_BUILDER_SOURCE_FLAG_LITERAL_TEXT,
+ cancellable,
+ error);
+ if (source == NULL)
+ return FALSE;
-/*
- * Returns: A hash table with a string key of the application origin and a
- * value of the guint percentage of the store is made up by that origin.
- */
-static GHashTable *
-gs_plugin_appstream_get_origins_hash (GPtrArray *array)
-{
- AsApp *app;
- GHashTable *origins = NULL;
- const gchar *tmp;
- gdouble perc;
- guint *cnt;
- guint i;
- g_autoptr(GList) keys = NULL;
-
- /* create a hash table with origin:cnt */
- origins = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, g_free);
- for (i = 0; i < array->len; i++) {
- app = g_ptr_array_index (array, i);
- tmp = as_app_get_origin (app);
- if (tmp == NULL)
- continue;
- cnt = g_hash_table_lookup (origins, tmp);
- if (cnt == NULL) {
- cnt = g_new0 (guint, 1);
- g_hash_table_insert (origins, g_strdup (tmp), cnt);
- }
- (*cnt)++;
- }
+ /* add missing icons as required */
+ xb_builder_source_add_node_func (source, "AddIcons",
+ gs_plugin_appstream_add_icons_cb,
+ plugin, NULL);
- /* convert the cnt to a percentage */
- keys = g_hash_table_get_keys (origins);
- for (GList *l = keys; l != NULL; l = l->next) {
- tmp = l->data;
- if (tmp == NULL || tmp[0] == '\0')
- continue;
- cnt = g_hash_table_lookup (origins, tmp);
- perc = (100.f / (gdouble) array->len) * (gdouble) (*cnt);
- g_debug ("origin %s provides %u apps (%.0f%%)", tmp, *cnt, perc);
- *cnt = (guint) perc;
+ /* add the origin as a search keyword for small repos */
+ xb_builder_source_add_node_func (source, "AddOriginKeyword",
+ gs_plugin_appstream_add_origin_keyword_cb,
+ plugin, NULL);
+
+ /* success */
+ xb_builder_import_source (builder, source);
+ }
}
- return origins;
+ /* success */
+ return TRUE;
}
-gboolean
-gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
+static gboolean
+gs_plugin_appstream_check_silo (GsPlugin *plugin,
+ GCancellable *cancellable,
+ GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- GPtrArray *items;
- gboolean ret;
- const gchar *tmp;
const gchar *test_xml;
- const gchar *test_icon_root;
- gboolean all_origin_keywords = g_getenv ("GS_SELF_TEST_ALL_ORIGIN_KEYWORDS") != NULL;
- guint *perc;
- guint i;
- g_autoptr(GHashTable) origins = NULL;
-
- /* Parse the XML */
- if (g_getenv ("GNOME_SOFTWARE_PREFER_LOCAL") != NULL) {
- as_store_set_add_flags (priv->store,
- AS_STORE_ADD_FLAG_PREFER_LOCAL);
- }
+ g_autofree gchar *blobfn = NULL;
+ g_autoptr(XbBuilder) builder = xb_builder_new ();
+ g_autoptr(XbNode) n = NULL;
+ g_autoptr(GFile) file = NULL;
+ g_autoptr(GPtrArray) parent_appdata = g_ptr_array_new_with_free_func (g_free);
+ g_autoptr(GPtrArray) parent_appstream = g_ptr_array_new_with_free_func (g_free);
+ const gchar *const *locales = g_get_language_names ();
+
+ /* everything is okay */
+ if (priv->silo != NULL && xb_silo_is_valid (priv->silo))
+ return TRUE;
+
+ /* drat! silo needs regenerating */
+ g_clear_object (&priv->silo);
+
+ /* add current locales */
+ for (guint i = 0; locales[i] != NULL; i++)
+ xb_builder_add_locale (builder, locales[i]);
/* only when in self test */
test_xml = g_getenv ("GS_SELF_TEST_APPSTREAM_XML");
if (test_xml != NULL) {
- test_icon_root = g_getenv ("GS_SELF_TEST_APPSTREAM_ICON_ROOT");
- g_debug ("using self test data of %s... with icon root %s",
- test_xml, test_icon_root);
- if (!as_store_from_xml (priv->store, test_xml, test_icon_root, error))
+ g_autoptr(XbBuilderSource) source = NULL;
+ source = xb_builder_source_new_xml (test_xml,
+ XB_BUILDER_SOURCE_FLAG_NONE,
+ error);
+ if (source == NULL)
return FALSE;
+ xb_builder_source_add_node_func (source, "AddOriginKeywords",
+ gs_plugin_appstream_add_origin_keyword_cb,
+ plugin, NULL);
+ xb_builder_source_add_node_func (source, "AddIcons",
+ gs_plugin_appstream_add_icons_cb,
+ plugin, NULL);
+ xb_builder_import_source (builder, source);
} else {
- ret = as_store_load (priv->store,
- AS_STORE_LOAD_FLAG_IGNORE_INVALID |
- AS_STORE_LOAD_FLAG_APP_INFO_SYSTEM |
- AS_STORE_LOAD_FLAG_APP_INFO_USER |
- AS_STORE_LOAD_FLAG_APPDATA |
- AS_STORE_LOAD_FLAG_DESKTOP |
- AS_STORE_LOAD_FLAG_APP_INSTALL,
- cancellable,
- error);
- if (!ret) {
- gs_utils_error_convert_appstream (error);
- return FALSE;
+ /* add search paths */
+ g_ptr_array_add (parent_appstream,
+ g_build_filename ("/usr/share", "app-info", "xmls", NULL));
+ g_ptr_array_add (parent_appdata,
+ g_build_filename ("/usr/share", "appdata", NULL));
+ g_ptr_array_add (parent_appdata,
+ g_build_filename ("/usr/share", "metainfo", NULL));
+
+ /* import all files */
+ for (guint i = 0; i < parent_appstream->len; i++) {
+ const gchar *fn = g_ptr_array_index (parent_appstream, i);
+ if (!gs_plugin_appstream_load_appstream (plugin, builder, fn,
+ cancellable, error))
+ return FALSE;
+ }
+ for (guint i = 0; i < parent_appdata->len; i++) {
+ const gchar *fn = g_ptr_array_index (parent_appdata, i);
+ if (!gs_plugin_appstream_load_appdata (plugin, builder, fn,
+ cancellable, error))
+ return FALSE;
}
}
- items = as_store_get_apps (priv->store);
- if (items->len == 0) {
+
+ /* create per-user cache */
+ blobfn = gs_utils_get_cache_filename ("appstream", "components.xmlb",
+ GS_UTILS_CACHE_FLAG_WRITEABLE,
+ error);
+ if (blobfn == NULL)
+ return FALSE;
+ file = g_file_new_for_path (blobfn);
+ g_debug ("ensuring %s", blobfn);
+ priv->silo = xb_builder_ensure (builder, file,
+ XB_BUILDER_COMPILE_FLAG_IGNORE_INVALID |
+ XB_BUILDER_COMPILE_FLAG_SINGLE_LANG,
+ NULL, error);
+ if (priv->silo == NULL)
+ return FALSE;
+
+ /* watch all directories too */
+ for (guint i = 0; i < parent_appstream->len; i++) {
+ const gchar *fn = g_ptr_array_index (parent_appstream, i);
+ g_autoptr(GFile) file_tmp = g_file_new_for_path (fn);
+ if (!xb_silo_watch_file (priv->silo, file_tmp, cancellable, error))
+ return FALSE;
+ }
+ for (guint i = 0; i < parent_appdata->len; i++) {
+ const gchar *fn = g_ptr_array_index (parent_appdata, i);
+ g_autoptr(GFile) file_tmp = g_file_new_for_path (fn);
+ if (!xb_silo_watch_file (priv->silo, file_tmp, cancellable, error))
+ return FALSE;
+ }
+
+ /* test we found something */
+ n = xb_silo_query_first (priv->silo, "components/component", NULL);
+ if (n == NULL) {
g_warning ("No AppStream data, try 'make install-sample-data' in data/");
g_set_error (error,
GS_PLUGIN_ERROR,
@@ -296,36 +319,17 @@ gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
return FALSE;
}
- /* prime the cache */
- priv->app_hash_old = gs_plugin_appstream_create_app_hash (priv->store);
-
- /* watch for changes */
- priv->store_changed_id =
- g_signal_connect (priv->store, "changed",
- G_CALLBACK (gs_plugin_appstream_store_changed_cb),
- plugin);
-
- /* add search terms for apps not in the main source */
- origins = gs_plugin_appstream_get_origins_hash (items);
- for (i = 0; i < items->len; i++) {
- AsApp *app = g_ptr_array_index (items, i);
- tmp = as_app_get_origin (app);
- if (tmp == NULL || tmp[0] == '\0')
- continue;
- perc = g_hash_table_lookup (origins, tmp);
- if (*perc < 10 || all_origin_keywords) {
- g_debug ("adding keyword '%s' to %s",
- tmp, as_app_get_id (app));
- as_app_set_search_match (app,
- as_store_get_search_match (priv->store) |
- AS_APP_SEARCH_MATCH_ORIGIN);
- }
- }
-
- /* rely on the store keeping itself updated */
+ /* success */
return TRUE;
}
+gboolean
+gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
+{
+ /* set up silo, compiling if required */
+ return gs_plugin_appstream_check_silo (plugin, cancellable, error);
+}
+
gboolean
gs_plugin_url_to_app (GsPlugin *plugin,
GsAppList *list,
@@ -334,10 +338,15 @@ gs_plugin_url_to_app (GsPlugin *plugin,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- AsApp *item;
g_autofree gchar *path = NULL;
g_autofree gchar *scheme = NULL;
+ g_autofree gchar *xpath = NULL;
g_autoptr(GsApp) app = NULL;
+ g_autoptr(XbNode) component = NULL;
+
+ /* check silo is valid */
+ if (!gs_plugin_appstream_check_silo (plugin, cancellable, error))
+ return FALSE;
/* not us */
scheme = gs_utils_get_url_scheme (url);
@@ -346,10 +355,11 @@ gs_plugin_url_to_app (GsPlugin *plugin,
/* create app */
path = gs_utils_get_url_path (url);
- item = as_store_get_app_by_id (priv->store, path);
- if (item == NULL)
+ xpath = g_strdup_printf ("components/component/id[text()='%s']", path);
+ component = xb_silo_query_first (priv->silo, xpath, NULL);
+ if (component == NULL)
return TRUE;
- app = gs_appstream_create_app (plugin, item, error);
+ app = gs_appstream_create_app (plugin, priv->silo, component, error);
if (app == NULL)
return FALSE;
gs_app_list_add (list, app);
@@ -357,9 +367,9 @@ gs_plugin_url_to_app (GsPlugin *plugin,
}
static void
-gs_plugin_appstream_set_compulsory_quirk (GsApp *app, AsApp *item)
+gs_plugin_appstream_set_compulsory_quirk (GsApp *app, XbNode *component)
{
- GPtrArray *array;
+ g_autoptr(GPtrArray) array = NULL;
const gchar *current_desktop;
/*
@@ -377,12 +387,15 @@ gs_plugin_appstream_set_compulsory_quirk (GsApp *app, AsApp *item)
* compulsory apps for such compound desktops if they want.
*
*/
- array = as_app_get_compulsory_for_desktops (item);
+ array = xb_node_query (component, "compulsory_for_desktop", 0, NULL);
+ if (array == NULL)
+ return;
current_desktop = g_getenv ("XDG_CURRENT_DESKTOP");
if (current_desktop != NULL) {
g_auto(GStrv) xdg_current_desktops = g_strsplit (current_desktop, ":", 0);
for (guint i = 0; i < array->len; i++) {
- const gchar *tmp = g_ptr_array_index (array, i);
+ XbNode *n = g_ptr_array_index (array, i);
+ const gchar *tmp = xb_node_get_text (n);
/* if the value has a :, check the whole string */
if (g_strstr_len (tmp, -1, ":")) {
if (g_strcmp0 (current_desktop, tmp) == 0) {
@@ -401,53 +414,54 @@ gs_plugin_appstream_set_compulsory_quirk (GsApp *app, AsApp *item)
static gboolean
gs_plugin_refine_from_id (GsPlugin *plugin,
GsApp *app,
+ GsPluginRefineFlags flags,
gboolean *found,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- const gchar *unique_id;
- AsApp *item;
-
- /* unfound */
- *found = FALSE;
+ const gchar *id;
+ g_autofree gchar *xpath = NULL;
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) components = NULL;
- /* find anything that matches the ID */
- unique_id = gs_app_get_unique_id (app);
- if (unique_id == NULL)
+ /* not enough info to find */
+ id = gs_app_get_id (app);
+ if (id == NULL)
return TRUE;
/* nothing found */
- g_debug ("searching appstream for %s", unique_id);
- item = as_store_get_app_by_unique_id (priv->store, unique_id,
- AS_STORE_SEARCH_FLAG_USE_WILDCARDS);
- if (item == NULL) {
- GPtrArray *apps = as_store_get_apps (priv->store);
- g_debug ("no app with ID %s found in system appstream", unique_id);
- for (guint i = 0; i < apps->len; i++) {
- item = g_ptr_array_index (apps, i);
- if (g_strcmp0 (as_app_get_id (item), gs_app_get_id (app)) != 0)
- continue;
- g_debug ("possible match: %s",
- as_app_get_unique_id (item));
- }
+ g_debug ("searching appstream for %s", id);
- /* fall back to trying to get a merge app */
- apps = as_store_get_apps_by_id_merge (priv->store, gs_app_get_id (app));
- if (apps != NULL) {
- for (guint i = 0; i < apps->len; i++) {
- item = g_ptr_array_index (apps, i);
- if (!gs_appstream_refine_app (plugin, app, item, error))
- return FALSE;
- gs_plugin_appstream_set_compulsory_quirk (app, item);
- }
- }
- return TRUE;
+ /* find all apps when matching any prefixes */
+ xpath = g_strdup_printf ("components/component/id[text()='%s']/..", id);
+ components = xb_silo_query (priv->silo, xpath, 0, &error_local);
+ if (components == NULL) {
+ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ return TRUE;
+ g_propagate_error (error, g_steal_pointer (&error_local));
+ return FALSE;
+ }
+ for (guint i = 0; i < components->len; i++) {
+ XbNode *component = g_ptr_array_index (components, i);
+ if (!gs_appstream_refine_app (plugin, app, priv->silo,
+ component, flags, error))
+ return FALSE;
+ gs_plugin_appstream_set_compulsory_quirk (app, component);
}
- /* set new properties */
- if (!gs_appstream_refine_app (plugin, app, item, error))
- return FALSE;
+ /* maybe no if */
+{
+ g_autoptr(XbNode) component_installed = NULL;
+ g_autofree gchar *xpath2 = NULL;
+// if (gs_app_get_state (app) == AS_APP_STATE_UNKNOWN) {
+ xpath2 = g_strdup_printf ("component/id[text()='%s']", id);
+ component_installed = xb_silo_query_first (priv->silo, xpath2, NULL);
+ if (component_installed != NULL)
+ gs_app_set_state (app, AS_APP_STATE_INSTALLED);
+// }
+}
+ /* success */
*found = TRUE;
return TRUE;
}
@@ -455,56 +469,43 @@ gs_plugin_refine_from_id (GsPlugin *plugin,
static gboolean
gs_plugin_refine_from_pkgname (GsPlugin *plugin,
GsApp *app,
+ GsPluginRefineFlags flags,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- AsApp *item = NULL;
- GPtrArray *sources;
-
- /* find anything that matches the ID */
- sources = gs_app_get_sources (app);
- for (guint i = 0; i < sources->len && item == NULL; i++) {
- const gchar *pkgname = g_ptr_array_index (sources, i);
- item = as_store_get_app_by_pkgname (priv->store, pkgname);
- if (item == NULL)
- g_debug ("no AppStream match for {pkgname} %s", pkgname);
- }
+ GPtrArray *sources = gs_app_get_sources (app);
+ g_autoptr(GError) error_local = NULL;
- /* nothing found */
- if (item == NULL)
+ /* not enough info to find */
+ if (sources->len == 0)
return TRUE;
- /* set new properties */
- return gs_appstream_refine_app (plugin, app, item, error);
-}
-
-gboolean
-gs_plugin_add_distro_upgrades (GsPlugin *plugin,
- GsAppList *list,
- GCancellable *cancellable,
- GError **error)
-{
- GsPluginData *priv = gs_plugin_get_data (plugin);
- AsApp *item;
- GPtrArray *array;
- guint i;
-
- /* find any upgrades */
- array = as_store_get_apps (priv->store);
- for (i = 0; i < array->len; i++) {
- g_autoptr(GsApp) app = NULL;
- item = g_ptr_array_index (array, i);
- if (as_app_get_kind (item) != AS_APP_KIND_OS_UPDATE)
- continue;
-
- /* create */
- app = gs_appstream_create_app (plugin, item, error);
- if (app == NULL)
+ /* find all apps when matching any prefixes */
+ for (guint j = 0; j < sources->len; j++) {
+ const gchar *pkgname = g_ptr_array_index (sources, j);
+ g_autofree gchar *xpath = NULL;
+ g_autoptr(GPtrArray) components = NULL;
+
+ g_debug ("searching appstream for pkg %s", pkgname);
+ xpath = g_strdup_printf ("components/component/pkgname[text()='%s']/..",
+ pkgname);
+ components = xb_silo_query (priv->silo, xpath, 0, &error_local);
+ if (components == NULL) {
+ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ continue;
+ g_propagate_error (error, g_steal_pointer (&error_local));
return FALSE;
- gs_app_set_kind (app, AS_APP_KIND_OS_UPGRADE);
- gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
- gs_app_list_add (list, app);
+ }
+ for (guint i = 0; i < components->len; i++) {
+ XbNode *component = g_ptr_array_index (components, i);
+ if (!gs_appstream_refine_app (plugin, app, priv->silo,
+ component, flags, error))
+ return FALSE;
+ gs_plugin_appstream_set_compulsory_quirk (app, component);
+ }
}
+
+ /* success */
return TRUE;
}
@@ -524,11 +525,15 @@ gs_plugin_refine_app (GsPlugin *plugin,
return TRUE;
}
- /* find by ID then package name */
- if (!gs_plugin_refine_from_id (plugin, app, &found, error))
+ /* check silo is valid */
+ if (!gs_plugin_appstream_check_silo (plugin, cancellable, error))
+ return FALSE;
+
+ /* find by ID then fall back to package name */
+ if (!gs_plugin_refine_from_id (plugin, app, flags, &found, error))
return FALSE;
if (!found) {
- if (!gs_plugin_refine_from_pkgname (plugin, app, error))
+ if (!gs_plugin_refine_from_pkgname (plugin, app, flags, error))
return FALSE;
}
@@ -546,8 +551,13 @@ gs_plugin_refine_wildcard (GsPlugin *plugin,
{
GsPluginData *priv = gs_plugin_get_data (plugin);
const gchar *id;
- guint i;
- g_autoptr(GPtrArray) items = NULL;
+ g_autofree gchar *xpath = NULL;
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) components = NULL;
+
+ /* check silo is valid */
+ if (!gs_plugin_appstream_check_silo (plugin, cancellable, error))
+ return FALSE;
/* not enough info to find */
id = gs_app_get_id (app);
@@ -555,40 +565,28 @@ gs_plugin_refine_wildcard (GsPlugin *plugin,
return TRUE;
/* find all apps when matching any prefixes */
- items = as_store_get_apps_by_id (priv->store, id);
- for (i = 0; i < items->len; i++) {
- AsApp *item = g_ptr_array_index (items, i);
+ xpath = g_strdup_printf ("components/component/id[text()='%s']/..", id);
+ components = xb_silo_query (priv->silo, xpath, 0, &error_local);
+ if (components == NULL) {
+ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ return TRUE;
+ g_propagate_error (error, g_steal_pointer (&error_local));
+ return FALSE;
+ }
+ for (guint i = 0; i < components->len; i++) {
+ XbNode *component = g_ptr_array_index (components, i);
g_autoptr(GsApp) new = NULL;
- /* is compatible */
- if (!as_utils_unique_id_match (gs_app_get_unique_id (app),
- as_app_get_unique_id (item),
- AS_UNIQUE_ID_MATCH_FLAG_SCOPE |
- AS_UNIQUE_ID_MATCH_FLAG_BUNDLE_KIND |
- /* don't match origin as AsApp appstream
- * origin can differ from package origin */
- AS_UNIQUE_ID_MATCH_FLAG_KIND |
- AS_UNIQUE_ID_MATCH_FLAG_ID |
- AS_UNIQUE_ID_MATCH_FLAG_BRANCH)) {
- g_debug ("does not match unique ID constraints: %s, %s",
- gs_app_get_unique_id (app),
- as_app_get_unique_id (item));
- continue;
- }
-
/* does the app have an installation method */
- if (as_app_get_pkgname_default (item) == NULL &&
- as_app_get_bundle_default (item) == NULL) {
- g_debug ("not using %s for wildcard as "
- "no bundle or pkgname",
- as_app_get_id (item));
+ if (xb_node_query_text (component, "pkgname", NULL) == NULL) {
+ g_debug ("not using %s for wildcard as no pkgname",
+ xb_node_query_text (component, "id", NULL));
continue;
}
/* new app */
- g_debug ("found %s for wildcard %s",
- as_app_get_id (item), id);
- new = gs_appstream_create_app (plugin, item, error);
+ g_debug ("found component for wildcard %s", id);
+ new = gs_appstream_create_app (plugin, priv->silo, component, error);
if (new == NULL)
return FALSE;
gs_app_list_add (list, new);
@@ -606,12 +604,14 @@ gs_plugin_add_category_apps (GsPlugin *plugin,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- return gs_appstream_store_add_category_apps (plugin,
- priv->store,
- category,
- list,
- cancellable,
- error);
+ if (!gs_plugin_appstream_check_silo (plugin, cancellable, error))
+ return FALSE;
+ return gs_appstream_silo_add_category_apps (plugin,
+ priv->silo,
+ category,
+ list,
+ cancellable,
+ error);
}
gboolean
@@ -622,12 +622,14 @@ gs_plugin_add_search (GsPlugin *plugin,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- return gs_appstream_store_search (plugin,
- priv->store,
- values,
- list,
- cancellable,
- error);
+ if (!gs_plugin_appstream_check_silo (plugin, cancellable, error))
+ return FALSE;
+ return gs_appstream_silo_search (plugin,
+ priv->silo,
+ values,
+ list,
+ cancellable,
+ error);
}
gboolean
@@ -637,19 +639,23 @@ gs_plugin_add_installed (GsPlugin *plugin,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- GPtrArray *array;
-
- /* search categories for the search term */
- array = as_store_get_apps (priv->store);
- for (guint i = 0; i < array->len; i++) {
- AsApp *item = g_ptr_array_index (array, i);
- if (as_app_get_state (item) == AS_APP_STATE_INSTALLED) {
- g_autoptr(GsApp) app = NULL;
- app = gs_appstream_create_app (plugin, item, error);
- if (app == NULL)
- return FALSE;
- gs_app_list_add (list, app);
- }
+ g_autoptr(GPtrArray) components = NULL;
+
+ /* check silo is valid */
+ if (!gs_plugin_appstream_check_silo (plugin, cancellable, error))
+ return FALSE;
+
+ /* get all installed appdata files (notice no 'components/' prefix...) */
+ components = xb_silo_query (priv->silo, "component", 0, NULL);
+ if (components == NULL)
+ return TRUE;
+ for (guint i = 0; i < components->len; i++) {
+ XbNode *component = g_ptr_array_index (components, i);
+ g_autoptr(GsApp) app = gs_appstream_create_app (plugin, priv->silo, component, error);
+ if (app == NULL)
+ return FALSE;
+ gs_app_set_state (app, AS_APP_STATE_INSTALLED);
+ gs_app_list_add (list, app);
}
return TRUE;
}
@@ -661,8 +667,10 @@ gs_plugin_add_categories (GsPlugin *plugin,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- return gs_appstream_store_add_categories (plugin, priv->store, list,
- cancellable, error);
+ if (!gs_plugin_appstream_check_silo (plugin, cancellable, error))
+ return FALSE;
+ return gs_appstream_silo_add_categories (plugin, priv->silo, list,
+ cancellable, error);
}
gboolean
@@ -672,8 +680,9 @@ gs_plugin_add_popular (GsPlugin *plugin,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- return gs_appstream_add_popular (plugin, priv->store, list, cancellable,
- error);
+ if (!gs_plugin_appstream_check_silo (plugin, cancellable, error))
+ return FALSE;
+ return gs_appstream_add_popular (plugin, priv->silo, list, cancellable, error);
}
gboolean
@@ -683,8 +692,9 @@ gs_plugin_add_featured (GsPlugin *plugin,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- return gs_appstream_add_featured (plugin, priv->store, list, cancellable,
- error);
+ if (!gs_plugin_appstream_check_silo (plugin, cancellable, error))
+ return FALSE;
+ return gs_appstream_add_featured (plugin, priv->silo, list, cancellable, error);
}
gboolean
@@ -695,7 +705,9 @@ gs_plugin_add_recent (GsPlugin *plugin,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- return gs_appstream_add_recent (plugin, priv->store, list, age,
+ if (!gs_plugin_appstream_check_silo (plugin, cancellable, error))
+ return FALSE;
+ return gs_appstream_add_recent (plugin, priv->silo, list, age,
cancellable, error);
}
@@ -707,7 +719,10 @@ gs_plugin_add_alternates (GsPlugin *plugin,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- return gs_appstream_add_alternates (plugin, priv->store, app, list, cancellable, error);
+ if (!gs_plugin_appstream_check_silo (plugin, cancellable, error))
+ return FALSE;
+ return gs_appstream_add_alternates (plugin, priv->silo, app, list,
+ cancellable, error);
}
gboolean
@@ -716,11 +731,5 @@ gs_plugin_refresh (GsPlugin *plugin,
GCancellable *cancellable,
GError **error)
{
- GsPluginData *priv = gs_plugin_get_data (plugin);
-
- /* ensure the token cache */
- if (cache_age == G_MAXUINT)
- as_store_load_search_cache (priv->store);
-
- return TRUE;
+ return gs_plugin_appstream_check_silo (plugin, cancellable, error);
}
diff --git a/plugins/core/gs-self-test.c b/plugins/core/gs-self-test.c
index c7724a54..3d8fdcac 100644
--- a/plugins/core/gs-self-test.c
+++ b/plugins/core/gs-self-test.c
@@ -21,6 +21,8 @@
#include "config.h"
+#include <glib/gstdio.h>
+
#include "gnome-software-private.h"
#include "gs-appstream.h"
@@ -37,6 +39,7 @@ gs_plugins_core_search_repo_name_func (GsPluginLoader *plugin_loader)
g_autoptr(GsPluginJob) plugin_job = NULL;
/* drop all caches */
+ g_unlink ("/var/tmp/self-test/appstream/components.xmlb");
gs_plugin_loader_setup_again (plugin_loader);
/* force this app to be installed */
@@ -70,6 +73,7 @@ gs_plugins_core_os_release_func (GsPluginLoader *plugin_loader)
g_autoptr(GError) error = NULL;
/* drop all caches */
+ g_unlink ("/var/tmp/self-test/appstream/components.xmlb");
gs_plugin_loader_setup_again (plugin_loader);
/* refine system application */
@@ -120,6 +124,7 @@ gs_plugins_core_generic_updates_func (GsPluginLoader *plugin_loader)
g_autoptr(GsAppList) list_wildcard = NULL;
/* drop all caches */
+ g_unlink ("/var/tmp/self-test/appstream/components.xmlb");
gs_plugin_loader_setup_again (plugin_loader);
/* create a list with generic apps */
@@ -238,7 +243,6 @@ main (int argc, char **argv)
" </component>\n"
"</components>\n";
g_setenv ("GS_SELF_TEST_APPSTREAM_XML", xml, TRUE);
- g_setenv ("GS_SELF_TEST_ALL_ORIGIN_KEYWORDS", "1", TRUE);
/* only critical and error are fatal */
g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
diff --git a/plugins/core/meson.build b/plugins/core/meson.build
index 92ec67a5..599d2bb2 100644
--- a/plugins/core/meson.build
+++ b/plugins/core/meson.build
@@ -92,7 +92,10 @@ shared_module(
install : true,
install_dir: plugin_dir,
c_args : cargs,
- dependencies : plugin_libs
+ dependencies : [
+ plugin_libs,
+ libxmlb,
+ ],
)
shared_module(
@@ -208,6 +211,7 @@ if get_option('tests')
],
dependencies : [
plugin_libs,
+ libxmlb,
],
link_with : [
libgnomesoftware
diff --git a/plugins/dummy/gs-self-test.c b/plugins/dummy/gs-self-test.c
index feb4f0f2..6b123b59 100644
--- a/plugins/dummy/gs-self-test.c
+++ b/plugins/dummy/gs-self-test.c
@@ -21,6 +21,8 @@
#include "config.h"
+#include <glib/gstdio.h>
+
#include "gnome-software-private.h"
#include "gs-test.h"
@@ -104,6 +106,7 @@ gs_plugins_dummy_error_func (GsPluginLoader *plugin_loader)
g_autoptr(GsPluginJob) plugin_job = NULL;
/* drop all caches */
+ g_unlink ("/var/tmp/self-test/appstream/components.xmlb");
gs_plugin_loader_setup_again (plugin_loader);
/* update, which should cause an error to be emitted */
@@ -425,7 +428,7 @@ gs_plugins_dummy_search_func (GsPluginLoader *plugin_loader)
/* get search result based on addon keyword */
plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_SEARCH,
- "search", "spell",
+ "search", "zeus",
"refine-flags", GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON,
NULL);
list = gs_plugin_loader_job_process (plugin_loader, plugin_job, NULL, &error);
@@ -479,6 +482,7 @@ gs_plugins_dummy_hang_func (GsPluginLoader *plugin_loader)
g_autoptr(GsPluginJob) plugin_job = NULL;
/* drop all caches */
+ g_unlink ("/var/tmp/self-test/appstream/components.xmlb");
gs_plugin_loader_setup_again (plugin_loader);
/* get search result based on addon keyword */
@@ -735,6 +739,7 @@ gs_plugins_dummy_limit_parallel_ops_func (GsPluginLoader *plugin_loader)
g_autoptr(GsDummyTestHelper) helper3 = gs_dummy_test_helper_new ();
/* drop all caches */
+ g_unlink ("/var/tmp/self-test/appstream/components.xmlb");
gs_plugin_loader_setup_again (plugin_loader);
/* get the updates list */
@@ -826,6 +831,7 @@ gs_plugins_dummy_limit_parallel_ops_func (GsPluginLoader *plugin_loader)
int
main (int argc, char **argv)
{
+ const gchar *tmp_root = "/var/tmp/self-test";
gboolean ret;
g_autofree gchar *xml = NULL;
g_autoptr(GError) error = NULL;
@@ -854,6 +860,7 @@ main (int argc, char **argv)
g_setenv ("GS_SELF_TEST_PROVENANCE_LICENSE_SOURCES", "london*,boston", TRUE);
g_setenv ("GS_SELF_TEST_PROVENANCE_LICENSE_URL", "https://www.debian.org/", TRUE);
g_setenv ("GNOME_SOFTWARE_POPULAR", "", TRUE);
+ g_setenv ("GS_SELF_TEST_CORE_DATADIR", tmp_root, TRUE);
xml = g_strdup ("<?xml version=\"1.0\"?>\n"
"<components version=\"0.9\">\n"
diff --git a/plugins/external-appstream/gs-install-appstream.c
b/plugins/external-appstream/gs-install-appstream.c
index d4a430c9..79cfe54f 100644
--- a/plugins/external-appstream/gs-install-appstream.c
+++ b/plugins/external-appstream/gs-install-appstream.c
@@ -24,10 +24,8 @@
#include <locale.h>
#include <stdlib.h>
-#include <appstream-glib.h>
-#include <gio/gio.h>
+#include <xmlb.h>
#include <glib/gi18n.h>
-#include <glib-object.h>
#include "gs-external-appstream-utils.h"
@@ -59,8 +57,11 @@ static gboolean
gs_install_appstream_check_content_type (GFile *file, GError **error)
{
const gchar *type;
- g_autoptr(AsStore) store = NULL;
+ g_autoptr(GError) error_local = NULL;
g_autoptr(GFileInfo) info = NULL;
+ g_autoptr(GPtrArray) components = NULL;
+ g_autoptr(XbBuilder) builder = xb_builder_new ();
+ g_autoptr(XbSilo) silo = NULL;
/* check is correct type */
info = g_file_query_info (file,
@@ -80,14 +81,35 @@ gs_install_appstream_check_content_type (GFile *file, GError **error)
}
/* check is an AppStream file */
- store = as_store_new ();
- if (!as_store_from_file (store, file, NULL, NULL, error))
+ if (!xb_builder_import_file (builder, file, NULL, NULL, &error_local)) {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "Failed to import XML: %s", error_local->message);
return FALSE;
- if (as_store_get_size (store) == 0) {
- g_set_error_literal (error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_DATA,
- "No applications found in the AppStream XML");
+ }
+ silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE,
+ NULL, &error_local);
+ if (silo == NULL) {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "Failed to parse XML: %s", error_local->message);
+ return FALSE;
+ }
+ components = xb_silo_query (silo, "components/component", 0, &error_local);
+ if (components == NULL) {
+ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "No applications found in the AppStream XML");
+ return FALSE;
+ }
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "Failed to query XML: %s", error_local->message);
return FALSE;
}
diff --git a/plugins/external-appstream/meson.build b/plugins/external-appstream/meson.build
index 6e2f3dfa..78c5609a 100644
--- a/plugins/external-appstream/meson.build
+++ b/plugins/external-appstream/meson.build
@@ -8,8 +8,13 @@ executable(
],
include_directories : [
include_directories('../..'),
+ include_directories('../../libxmlb/src'),
+ ],
+ dependencies : [
+ gio_unix,
+ appstream_glib
+ libxmlb,
],
- dependencies : [gio_unix, appstream_glib],
c_args : cargs,
install : true,
install_dir : get_option('libexecdir')
diff --git a/plugins/flatpak/gs-flatpak.c b/plugins/flatpak/gs-flatpak.c
index 5218e9b9..5e008c4c 100644
--- a/plugins/flatpak/gs-flatpak.c
+++ b/plugins/flatpak/gs-flatpak.c
@@ -30,6 +30,7 @@
#include <config.h>
#include <glib/gi18n.h>
+#include <xmlb.h>
#include "gs-appstream.h"
#include "gs-flatpak-app.h"
@@ -44,7 +45,7 @@ struct _GsFlatpak {
GFileMonitor *monitor;
AsAppScope scope;
GsPlugin *plugin;
- AsStore *store;
+ XbSilo *silo;
gchar *id;
guint changed_id;
};
@@ -196,11 +197,11 @@ gs_plugin_flatpak_changed_cb (GFileMonitor *monitor,
GsFlatpak *self)
{
g_autoptr(GError) error = NULL;
- g_autoptr(GError) error_md = NULL;
+// g_autoptr(GError) error_md = NULL;
/* don't refresh when it's us ourselves doing the change */
- if (gs_plugin_has_flags (self->plugin, GS_PLUGIN_FLAGS_RUNNING_SELF))
- return;
+// if (gs_plugin_has_flags (self->plugin, GS_PLUGIN_FLAGS_RUNNING_SELF))
+// return;
/* manually drop the cache */
if (!flatpak_installation_drop_caches (self->installation,
@@ -210,14 +211,15 @@ gs_plugin_flatpak_changed_cb (GFileMonitor *monitor,
}
/* if this is a new remote, get the AppStream data */
- if (!gs_flatpak_refresh_appstream (self, G_MAXUINT, NULL, &error_md)) {
- g_warning ("failed to get initial available data: %s",
- error_md->message);
- }
+// if (!gs_flatpak_refresh_appstream (self, G_MAXUINT, NULL, &error_md)) {
+// g_warning ("failed to get initial available data: %s",
+// error_md->message);
+// }
}
+#if 0
static void
-gs_flatpak_remove_prefixed_names (AsApp *app)
+gs_flatpak_remove_prefixed_names (XbNode *component)
{
GHashTable *names;
g_autoptr(GList) keys = NULL;
@@ -234,23 +236,51 @@ gs_flatpak_remove_prefixed_names (AsApp *app)
as_app_set_name (app, locale, value + 10);
}
}
+#endif
+
+static gboolean
+gs_flatpak_add_flatpak_keyword_cb (XbBuilderSource *self,
+ XbBuilderNode *bn,
+ gpointer user_data,
+ GError **error)
+{
+ if (g_strcmp0 (xb_builder_node_get_element (bn), "component") == 0) {
+ gs_appstream_add_keyword (bn, "flatpak");
+ }
+ return TRUE;
+}
+
+static gboolean
+gs_flatpak_set_origin_cb (XbBuilderSource *self,
+ XbBuilderNode *bn,
+ gpointer user_data,
+ GError **error)
+{
+ FlatpakRemote *xremote = FLATPAK_REMOTE (user_data);
+ if (g_strcmp0 (xb_builder_node_get_element (bn), "components") == 0) {
+ xb_builder_node_set_attr (bn, "origin",
+ flatpak_remote_get_name (xremote));
+ }
+ return TRUE;
+}
static gboolean
gs_flatpak_add_apps_from_xremote (GsFlatpak *self,
+ XbBuilder *builder,
FlatpakRemote *xremote,
GCancellable *cancellable,
GError **error)
{
- GPtrArray *apps;
+// GPtrArray *apps;
g_autofree gchar *appstream_dir_fn = NULL;
g_autofree gchar *appstream_fn = NULL;
g_autofree gchar *default_branch = NULL;
g_autofree gchar *only_app_id = NULL;
- g_autoptr(AsStore) store = NULL;
g_autoptr(GFile) appstream_dir = NULL;
- g_autoptr(GFile) file = NULL;
- g_autoptr(GSettings) settings = NULL;
+ g_autoptr(GFile) file_xml = NULL;
g_autoptr(GPtrArray) app_filtered = NULL;
+ g_autoptr(GSettings) settings = NULL;
+ g_autoptr(XbBuilderSource) source = NULL;
/* get the AppStream data location */
appstream_dir = flatpak_remote_get_appstream_dir (xremote, NULL);
@@ -260,40 +290,38 @@ gs_flatpak_add_apps_from_xremote (GsFlatpak *self,
return TRUE;
}
- /* load the file into a temp store */
+ /* load the file into a temp silo */
appstream_dir_fn = g_file_get_path (appstream_dir);
- appstream_fn = g_build_filename (appstream_dir_fn,
- "appstream.xml.gz", NULL);
+ appstream_fn = g_build_filename (appstream_dir_fn, "appstream.xml.gz", NULL);
if (!g_file_test (appstream_fn, G_FILE_TEST_EXISTS)) {
g_debug ("no %s appstream metadata found: %s",
flatpak_remote_get_name (xremote),
appstream_fn);
return TRUE;
}
- file = g_file_new_for_path (appstream_fn);
- store = as_store_new ();
- as_store_set_add_flags (store,
- AS_STORE_ADD_FLAG_USE_UNIQUE_ID |
- AS_STORE_ADD_FLAG_ONLY_NATIVE_LANGS);
- as_store_set_search_match (store,
- AS_APP_SEARCH_MATCH_MIMETYPE |
- AS_APP_SEARCH_MATCH_PKGNAME |
- AS_APP_SEARCH_MATCH_COMMENT |
- AS_APP_SEARCH_MATCH_NAME |
- AS_APP_SEARCH_MATCH_KEYWORD |
- AS_APP_SEARCH_MATCH_ORIGIN |
- AS_APP_SEARCH_MATCH_ID);
- if (!as_store_from_file (store, file, NULL, cancellable, error)) {
- gs_utils_error_convert_appstream (error);
+
+ /* add source */
+ file_xml = g_file_new_for_path (appstream_fn);
+ source = xb_builder_source_new_file (file_xml,
+ XB_BUILDER_SOURCE_FLAG_WATCH_FILE |
+ XB_BUILDER_SOURCE_FLAG_LITERAL_TEXT,
+ cancellable,
+ error);
+ if (source == NULL)
return FALSE;
- }
+
+ /* add the origin as a search keyword for small repos */
+ xb_builder_source_add_node_func (source, "AddKeywordFlatpak",
+ gs_flatpak_add_flatpak_keyword_cb,
+ self, NULL);
/* override the *AppStream* origin */
- apps = as_store_get_apps (store);
- for (guint i = 0; i < apps->len; i++) {
- AsApp *app = g_ptr_array_index (apps, i);
- as_app_set_origin (app, flatpak_remote_get_name (xremote));
- }
+ xb_builder_source_add_node_func (source, "SetOrigin",
+ gs_flatpak_set_origin_cb,
+ xremote, NULL);
+
+ /* success */
+ xb_builder_import_source (builder, source);
/* only add the specific app for noenumerate=true */
if (flatpak_remote_get_noenumerate (xremote)) {
@@ -308,10 +336,11 @@ gs_flatpak_add_apps_from_xremote (GsFlatpak *self,
if (g_settings_get_boolean (settings, "filter-default-branch"))
default_branch = flatpak_remote_get_default_branch (xremote);
+#if 0
/* get all the apps and fix them up */
app_filtered = g_ptr_array_new ();
for (guint i = 0; i < apps->len; i++) {
- AsApp *app = g_ptr_array_index (apps, i);
+ XbNode *component = g_ptr_array_index (apps, i);
/* filter to app */
if (only_app_id != NULL &&
@@ -334,20 +363,15 @@ gs_flatpak_add_apps_from_xremote (GsFlatpak *self,
/* add */
as_app_set_scope (app, self->scope);
as_app_set_origin (app, flatpak_remote_get_name (xremote));
- as_app_add_keyword (app, NULL, "flatpak");
g_debug ("adding %s", as_app_get_unique_id (app));
g_ptr_array_add (app_filtered, app);
}
-
- /* add them to the main store */
- as_store_add_apps (self->store, app_filtered);
-
- /* ensure the token cache for all apps */
- as_store_load_search_cache (store);
+#endif
return TRUE;
}
+#if 0
static gchar *
gs_flatpak_discard_desktop_suffix (const gchar *app_id)
{
@@ -360,7 +384,9 @@ gs_flatpak_discard_desktop_suffix (const gchar *app_id)
app_prefix_len = strlen (app_id) - strlen (desktop_suffix);
return g_strndup (app_id, app_prefix_len);
}
+#endif
+#if 0
static void
gs_flatpak_rescan_installed (GsFlatpak *self,
GCancellable *cancellable,
@@ -385,7 +411,7 @@ gs_flatpak_rescan_installed (GsFlatpak *self,
while ((fn = g_dir_read_name (dir)) != NULL) {
g_autofree gchar *fn_desktop = NULL;
g_autoptr(GError) error_local = NULL;
- g_autoptr(AsApp) app = NULL;
+ g_autoptr(XbNode) app = NULL;
g_autoptr(AsFormat) format = as_format_new ();
g_autoptr(FlatpakInstalledRef) app_ref = NULL;
g_autofree gchar *app_id = NULL;
@@ -406,7 +432,7 @@ gs_flatpak_rescan_installed (GsFlatpak *self,
/* fix up icons */
icons = as_app_get_icons (app);
for (guint i = 0; i < icons->len; i++) {
- AsIcon *ic = g_ptr_array_index (icons, i);
+ XbNode *ic = g_ptr_array_index (icons, i);
if (as_icon_get_kind (ic) == AS_ICON_KIND_UNKNOWN) {
as_icon_set_kind (ic, AS_ICON_KIND_STOCK);
as_icon_set_prefix (ic, path_exports);
@@ -437,19 +463,34 @@ gs_flatpak_rescan_installed (GsFlatpak *self,
as_app_set_branch (app, flatpak_ref_get_branch (FLATPAK_REF (app_ref)));
as_app_set_icon_path (app, path_exports);
as_app_add_keyword (app, NULL, "flatpak");
- as_store_add_app (self->store, app);
+ as_store_add_app (self->silo, app);
}
}
+#endif
static gboolean
gs_flatpak_rescan_appstream_store (GsFlatpak *self,
GCancellable *cancellable,
GError **error)
{
+ const gchar *const *locales = g_get_language_names ();
+ g_autofree gchar *blobfn = NULL;
+ g_autoptr(GFile) file = NULL;
g_autoptr(GPtrArray) xremotes = NULL;
+ g_autoptr(XbBuilder) builder = xb_builder_new ();
+
+ /* everything is okay */
+ if (self->silo != NULL && xb_silo_is_valid (self->silo)) {
+ g_debug ("silo valid, returning");
+ return TRUE;
+ }
+
+ /* drat! silo needs regenerating */
+ g_clear_object (&self->silo);
- /* remove all components */
- as_store_remove_all (self->store);
+ /* add current locales */
+ for (guint i = 0; locales[i] != NULL; i++)
+ xb_builder_add_locale (builder, locales[i]);
/* go through each remote adding metadata */
xremotes = flatpak_installation_list_remotes (self->installation,
@@ -465,13 +506,29 @@ gs_flatpak_rescan_appstream_store (GsFlatpak *self,
continue;
g_debug ("found remote %s",
flatpak_remote_get_name (xremote));
- if (!gs_flatpak_add_apps_from_xremote (self, xremote, cancellable, error))
+ if (!gs_flatpak_add_apps_from_xremote (self, builder, xremote, cancellable, error))
return FALSE;
}
/* add any installed files without AppStream info */
- gs_flatpak_rescan_installed (self, cancellable, error);
+// gs_flatpak_rescan_installed (self, cancellable, error);
+ /* create per-user cache */
+ blobfn = gs_utils_get_cache_filename ("flatpak", "components.xmlb",
+ GS_UTILS_CACHE_FLAG_WRITEABLE,
+ error);
+ if (blobfn == NULL)
+ return FALSE;
+ file = g_file_new_for_path (blobfn);
+ g_debug ("ensuring %s", blobfn);
+ self->silo = xb_builder_ensure (builder, file,
+ XB_BUILDER_COMPILE_FLAG_IGNORE_INVALID |
+ XB_BUILDER_COMPILE_FLAG_SINGLE_LANG,
+ NULL, error);
+ if (self->silo == NULL)
+ return FALSE;
+
+ /* success */
return TRUE;
}
@@ -605,7 +662,6 @@ gs_flatpak_refresh_appstream (GsFlatpak *self, guint cache_age,
GCancellable *cancellable, GError **error)
{
gboolean ret;
- gboolean something_changed = FALSE;
g_autoptr(GPtrArray) xremotes = NULL;
/* get remotes */
@@ -677,21 +733,15 @@ gs_flatpak_refresh_appstream (GsFlatpak *self, guint cache_age,
continue;
}
- /* add the new AppStream repo to the shared store */
+ /* add the new AppStream repo to the shared silo */
file = flatpak_remote_get_appstream_dir (xremote, NULL);
appstream_fn = g_file_get_path (file);
g_debug ("using AppStream metadata found at: %s", appstream_fn);
-
- /* trigger the symlink rebuild */
- something_changed = TRUE;
}
- /* ensure the AppStream store is up to date */
- if (something_changed ||
- as_store_get_size (self->store) == 0) {
- if (!gs_flatpak_rescan_appstream_store (self, cancellable, error))
- return FALSE;
- }
+ /* ensure the AppStream silo is up to date */
+ if (!gs_flatpak_rescan_appstream_store (self, cancellable, error))
+ return FALSE;
return TRUE;
}
@@ -829,6 +879,10 @@ gs_flatpak_add_sources (GsFlatpak *self, GsAppList *list,
g_autoptr(GPtrArray) xrefs = NULL;
g_autoptr(GPtrArray) xremotes = NULL;
+ /* refresh */
+ if (!gs_flatpak_rescan_appstream_store (self, cancellable, error))
+ return FALSE;
+
/* get installed apps and runtimes */
xrefs = flatpak_installation_list_installed_refs (self->installation,
cancellable,
@@ -1044,10 +1098,10 @@ gs_flatpak_app_install_source (GsFlatpak *self, GsApp *app,
}
/* refresh the AppStream data manually */
- if (!gs_flatpak_add_apps_from_xremote (self, xremote, cancellable, error)) {
- g_prefix_error (error, "cannot refresh remote AppStream: ");
- return FALSE;
- }
+// if (!gs_flatpak_add_apps_from_xremote (self, xremote, cancellable, error)) {
+// g_prefix_error (error, "cannot refresh remote AppStream: ");
+// return FALSE;
+// }
/* success */
gs_app_set_state (app, AS_APP_STATE_INSTALLED);
@@ -1136,6 +1190,10 @@ gs_flatpak_add_updates (GsFlatpak *self, GsAppList *list,
{
g_autoptr(GPtrArray) xrefs = NULL;
+ /* ensure valid */
+ if (!gs_flatpak_rescan_appstream_store (self, cancellable, error))
+ return FALSE;
+
/* get all the updatable apps and runtimes */
xrefs = flatpak_installation_list_installed_refs_for_update (self->installation,
cancellable,
@@ -1235,8 +1293,19 @@ gs_flatpak_refresh (GsFlatpak *self,
return FALSE;
}
+ /* manually do this in case we created the first appstream file */
+ xb_silo_invalidate (self->silo);
+
/* update AppStream metadata */
- return gs_flatpak_refresh_appstream (self, cache_age, cancellable, error);
+ if (!gs_flatpak_refresh_appstream (self, cache_age, cancellable, error))
+ return FALSE;
+
+ /* ensure valid */
+ if (!gs_flatpak_rescan_appstream_store (self, cancellable, error))
+ return FALSE;
+
+ /* success */
+ return TRUE;
}
static gboolean
@@ -1426,6 +1495,10 @@ gs_flatpak_refine_app_state (GsFlatpak *self,
g_autoptr(FlatpakInstalledRef) ref = NULL;
g_autoptr(GError) error_local = NULL;
+ /* ensure valid */
+ if (!gs_flatpak_rescan_appstream_store (self, cancellable, error))
+ return FALSE;
+
/* already found */
if (gs_app_get_state (app) != AS_APP_STATE_UNKNOWN)
return TRUE;
@@ -1819,56 +1892,47 @@ gs_plugin_refine_item_size (GsFlatpak *self,
}
static void
-gs_flatpak_refine_appstream_release (AsApp *item, GsApp *app)
+gs_flatpak_refine_appstream_release (XbNode *component, GsApp *app)
{
- AsRelease *rel = as_app_get_release_default (item);
- if (rel == NULL)
- return;
- if (as_release_get_version (rel) == NULL)
+ const gchar *version;
+
+ /* get first release */
+ version = xb_node_query_attr (component, "releases/release", "version", NULL);
+ if (version == NULL)
return;
switch (gs_app_get_state (app)) {
case AS_APP_STATE_INSTALLED:
case AS_APP_STATE_AVAILABLE:
case AS_APP_STATE_AVAILABLE_LOCAL:
- gs_app_set_version (app, as_release_get_version (rel));
+ gs_app_set_version (app, version);
break;
default:
g_debug ("%s is not installed, so ignoring version of %s",
- as_app_get_id (item), as_release_get_version (rel));
+ gs_app_get_unique_id (app), version);
break;
}
}
static gboolean
-gs_flatpak_refine_appstream (GsFlatpak *self, GsApp *app, GError **error)
+gs_flatpak_refine_appstream (GsFlatpak *self, GsApp *app, GsPluginRefineFlags flags, GError **error)
{
- AsApp *item;
- const gchar *unique_id = gs_app_get_unique_id (app);
+ const gchar *id = gs_app_get_id (app);
+ g_autofree gchar *xpath = NULL;
+ g_autoptr(XbNode) component = NULL;
- if (unique_id == NULL)
- return TRUE;
- item = as_store_get_app_by_unique_id (self->store,
- unique_id,
- AS_STORE_SEARCH_FLAG_USE_WILDCARDS);
- if (item == NULL) {
- g_autoptr(GPtrArray) apps = NULL;
- apps = as_store_get_apps_by_id (self->store, gs_app_get_id (app));
- if (apps->len > 0) {
- g_debug ("potential matches for %s:", unique_id);
- for (guint i = 0; i < apps->len; i++) {
- AsApp *app_tmp = g_ptr_array_index (apps, i);
- g_debug ("- %s", as_app_get_unique_id (app_tmp));
- }
- }
+ if (id == NULL)
return TRUE;
- }
- if (!gs_appstream_refine_app (self->plugin, app, item, error))
+ /* find using ID */
+ xpath = g_strdup_printf ("components/component/id[text()='%s']/..", id);
+ component = xb_silo_query_first (self->silo, xpath, NULL);
+ if (component == NULL)
+ return TRUE;
+ if (!gs_appstream_refine_app (self->plugin, app, self->silo, component, flags, error))
return FALSE;
/* use the default release as the version number */
- gs_flatpak_refine_appstream_release (item, app);
-
+ gs_flatpak_refine_appstream_release (component, app);
return TRUE;
}
@@ -1880,9 +1944,14 @@ gs_flatpak_refine_app (GsFlatpak *self,
GError **error)
{
AsAppState old_state = gs_app_get_state (app);
+//FIXME: only do for bundle type flatpak
+
+ /* ensure valid */
+ if (!gs_flatpak_rescan_appstream_store (self, cancellable, error))
+ return FALSE;
/* always do AppStream properties */
- if (!gs_flatpak_refine_appstream (self, app, error))
+ if (!gs_flatpak_refine_appstream (self, app, flags, error))
return FALSE;
/* AppStream sets the source to appname/arch/branch */
@@ -1902,7 +1971,7 @@ gs_flatpak_refine_app (GsFlatpak *self,
/* if the state was changed, perhaps set the version from the release */
if (old_state != gs_app_get_state (app)) {
- if (!gs_flatpak_refine_appstream (self, app, error))
+ if (!gs_flatpak_refine_appstream (self, app, flags, error))
return FALSE;
}
@@ -1952,6 +2021,11 @@ gs_flatpak_refine_wildcard (GsFlatpak *self, GsApp *app,
GsAppList *list, GsPluginRefineFlags flags,
GCancellable *cancellable, GError **error)
{
+#if 0
+ /* ensure valid */
+ if (!gs_flatpak_rescan_appstream_store (self, cancellable, error))
+ return FALSE;
+
const gchar *id;
guint i;
g_autoptr(GPtrArray) items = NULL;
@@ -1962,29 +2036,29 @@ gs_flatpak_refine_wildcard (GsFlatpak *self, GsApp *app,
return TRUE;
/* find all apps when matching any prefixes */
- items = as_store_get_apps_by_id (self->store, id);
+ items = as_store_get_apps_by_id (self->silo, id);
for (i = 0; i < items->len; i++) {
- AsApp *item = g_ptr_array_index (items, i);
+ XbNode *component = g_ptr_array_index (items, i);
g_autoptr(GsApp) new = NULL;
/* is compatible */
if (!as_utils_unique_id_equal (gs_app_get_unique_id (app),
- as_app_get_unique_id (item))) {
+ as_app_get_unique_id (component))) {
g_debug ("does not match unique ID constraints");
continue;
}
/* does the app have an installation method */
- if (as_app_get_bundle_default (item) == NULL) {
+ if (as_app_get_bundle_default (component) == NULL) {
g_debug ("not using %s for wildcard as no bundle",
- as_app_get_id (item));
+ xb_node_query_first (component, "id", NULL));
continue;
}
/* new app */
g_debug ("found %s for wildcard %s",
- as_app_get_unique_id (item), id);
- new = gs_appstream_create_app (self->plugin, item, NULL);
+ as_app_get_unique_id (component), id);
+ new = gs_appstream_create_app (self->plugin, component, NULL);
if (new == NULL)
return FALSE;
gs_flatpak_claim_app (self, new);
@@ -1992,6 +2066,7 @@ gs_flatpak_refine_wildcard (GsFlatpak *self, GsApp *app,
return FALSE;
gs_app_list_add (list, new);
}
+#endif
return TRUE;
}
@@ -2115,9 +2190,9 @@ gs_flatpak_file_to_app_bundle (GsFlatpak *self,
g_autoptr(GInputStream) stream_gz = NULL;
g_autoptr(GInputStream) stream_data = NULL;
g_autoptr(GBytes) appstream = NULL;
- g_autoptr(AsStore) store = NULL;
+ g_autoptr(XbSilo) silo = NULL;
g_autofree gchar *id = NULL;
- AsApp *item;
+// XbNode *component;
/* decompress data */
decompressor = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
@@ -2135,23 +2210,24 @@ gs_flatpak_file_to_app_bundle (GsFlatpak *self,
gs_flatpak_error_convert (error);
return NULL;
}
- store = as_store_new ();
- if (!as_store_from_bytes (store, appstream, cancellable, error)) {
- gs_flatpak_error_convert (error);
- return NULL;
- }
+// silo = xb_silo_new ();
+// if (!as_store_from_bytes (silo, appstream, cancellable, error)) {
+// gs_flatpak_error_convert (error);
+// return NULL;
+// }
+#if 0
/* allow peeking into this for debugging */
if (g_getenv ("GS_FLATPAK_DEBUG_APPSTREAM") != NULL) {
g_autoptr(GString) str = NULL;
- str = as_store_to_xml (store,
+ str = as_store_to_xml (silo,
AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE |
AS_NODE_TO_XML_FLAG_FORMAT_INDENT);
g_debug ("showing AppStream data: %s", str->str);
}
/* check for sanity */
- if (as_store_get_size (store) == 0) {
+ if (as_store_get_size (silo) == 0) {
g_set_error_literal (error,
GS_PLUGIN_ERROR,
GS_PLUGIN_ERROR_NOT_SUPPORTED,
@@ -2159,12 +2235,12 @@ gs_flatpak_file_to_app_bundle (GsFlatpak *self,
return NULL;
}
g_debug ("%u applications found in AppStream data",
- as_store_get_size (store));
+ as_store_get_size (silo));
/* find app */
id = g_strdup_printf ("%s.desktop", gs_flatpak_app_get_ref_name (app));
- item = as_store_get_app_by_id (store, id);
- if (item == NULL) {
+ component = as_store_get_app_by_id (silo, id);
+ if (component == NULL) {
g_set_error (error,
GS_PLUGIN_ERROR,
GS_PLUGIN_ERROR_INVALID_FORMAT,
@@ -2174,8 +2250,11 @@ gs_flatpak_file_to_app_bundle (GsFlatpak *self,
}
/* copy details from AppStream to app */
- if (!gs_appstream_refine_app (self->plugin, app, item, error))
+ if (!gs_appstream_refine_app (self->plugin, app, silo, component,
+ GS_PLUGIN_REFINE_FLAGS_DEFAULT,
+ error))
return NULL;
+#endif
} else {
g_warning ("no appstream metadata in file");
gs_app_set_name (app, GS_APP_QUALITY_LOWEST,
@@ -2323,10 +2402,10 @@ gs_flatpak_file_to_app_ref (GsFlatpak *self,
/* set the origin data */
remote_name = flatpak_remote_ref_get_remote_name (xref);
g_debug ("auto-created remote name: %s", remote_name);
- xremote = flatpak_installation_get_remote_by_name (self->installation,
- remote_name,
- cancellable,
- error);
+// xremote = flatpak_installation_get_remote_by_name (self->installation,
+// remote_name,
+// cancellable,
+// error);
if (xremote == NULL) {
gs_flatpak_error_convert (error);
return NULL;
@@ -2367,11 +2446,11 @@ gs_flatpak_file_to_app_ref (GsFlatpak *self,
}
/* parse it */
- if (!gs_flatpak_add_apps_from_xremote (self, xremote, cancellable, error))
- return NULL;
+// if (!gs_flatpak_add_apps_from_xremote (self, xremote, cancellable, error))
+// return NULL;
/* get extra AppStream data if available */
- if (!gs_flatpak_refine_appstream (self, app, error))
+ if (!gs_flatpak_refine_appstream (self, app, GS_PLUGIN_REFINE_FLAGS_DEFAULT, error))
return NULL;
/* success */
@@ -2386,7 +2465,9 @@ gs_flatpak_search (GsFlatpak *self,
GError **error)
{
g_autoptr(GsAppList) list_tmp = gs_app_list_new ();
- if (!gs_appstream_store_search (self->plugin, self->store, values, list_tmp,
+ if (!gs_flatpak_rescan_appstream_store (self, cancellable, error))
+ return FALSE;
+ if (!gs_appstream_silo_search (self->plugin, self->silo, values, list_tmp,
cancellable, error))
return FALSE;
gs_flatpak_claim_app_list (self, list_tmp);
@@ -2402,7 +2483,9 @@ gs_flatpak_add_category_apps (GsFlatpak *self,
GError **error)
{
g_autoptr(GsAppList) list_tmp = gs_app_list_new ();
- if (!gs_appstream_store_add_category_apps (self->plugin, self->store,
+ if (!gs_flatpak_rescan_appstream_store (self, cancellable, error))
+ return FALSE;
+ if (!gs_appstream_silo_add_category_apps (self->plugin, self->silo,
category, list_tmp,
cancellable, error))
return FALSE;
@@ -2417,7 +2500,9 @@ gs_flatpak_add_categories (GsFlatpak *self,
GCancellable *cancellable,
GError **error)
{
- return gs_appstream_store_add_categories (self->plugin, self->store,
+ if (!gs_flatpak_rescan_appstream_store (self, cancellable, error))
+ return FALSE;
+ return gs_appstream_silo_add_categories (self->plugin, self->silo,
list, cancellable, error);
}
@@ -2428,7 +2513,9 @@ gs_flatpak_add_popular (GsFlatpak *self,
GError **error)
{
g_autoptr(GsAppList) list_tmp = gs_app_list_new ();
- if (!gs_appstream_add_popular (self->plugin, self->store, list_tmp,
+ if (!gs_flatpak_rescan_appstream_store (self, cancellable, error))
+ return FALSE;
+ if (!gs_appstream_add_popular (self->plugin, self->silo, list_tmp,
cancellable, error))
return FALSE;
gs_flatpak_claim_app_list (self, list_tmp);
@@ -2443,7 +2530,9 @@ gs_flatpak_add_featured (GsFlatpak *self,
GError **error)
{
g_autoptr(GsAppList) list_tmp = gs_app_list_new ();
- if (!gs_appstream_add_featured (self->plugin, self->store, list_tmp,
+ if (!gs_flatpak_rescan_appstream_store (self, cancellable, error))
+ return FALSE;
+ if (!gs_appstream_add_featured (self->plugin, self->silo, list_tmp,
cancellable, error))
return FALSE;
gs_flatpak_claim_app_list (self, list_tmp);
@@ -2459,7 +2548,9 @@ gs_flatpak_add_alternates (GsFlatpak *self,
GError **error)
{
g_autoptr(GsAppList) list_tmp = gs_app_list_new ();
- if (!gs_appstream_add_alternates (self->plugin, self->store, app, list_tmp,
+ if (!gs_flatpak_rescan_appstream_store (self, cancellable, error))
+ return FALSE;
+ if (!gs_appstream_add_alternates (self->plugin, self->silo, app, list_tmp,
cancellable, error))
return FALSE;
gs_flatpak_claim_app_list (self, list_tmp);
@@ -2475,7 +2566,9 @@ gs_flatpak_add_recent (GsFlatpak *self,
GError **error)
{
g_autoptr(GsAppList) list_tmp = gs_app_list_new ();
- if (!gs_appstream_add_recent (self->plugin, self->store, list_tmp, age,
+ if (!gs_flatpak_rescan_appstream_store (self, cancellable, error))
+ return FALSE;
+ if (!gs_appstream_add_recent (self->plugin, self->silo, list_tmp, age,
cancellable, error))
return FALSE;
gs_flatpak_claim_app_list (self, list_tmp);
@@ -2483,19 +2576,6 @@ gs_flatpak_add_recent (GsFlatpak *self,
return TRUE;
}
-static void
-gs_flatpak_store_app_added_cb (AsStore *store, AsApp *app, GsFlatpak *self)
-{
- gs_appstream_add_extra_info (self->plugin, app);
-}
-
-static void
-gs_flatpak_store_app_removed_cb (AsStore *store, AsApp *app, GsFlatpak *self)
-{
- g_debug ("AppStream app was removed, doing delete from global cache");
- gs_plugin_cache_remove (self->plugin, as_app_get_unique_id (app));
-}
-
const gchar *
gs_flatpak_get_id (GsFlatpak *self)
{
@@ -2537,11 +2617,12 @@ gs_flatpak_finalize (GObject *object)
g_signal_handler_disconnect (self->monitor, self->changed_id);
self->changed_id = 0;
}
+ if (self->silo != NULL)
+ g_object_unref (self->silo);
g_free (self->id);
g_object_unref (self->installation);
g_object_unref (self->plugin);
- g_object_unref (self->store);
g_hash_table_unref (self->broken_remotes);
G_OBJECT_CLASS (gs_flatpak_parent_class)->finalize (object);
@@ -2559,22 +2640,6 @@ gs_flatpak_init (GsFlatpak *self)
{
self->broken_remotes = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
- self->store = as_store_new ();
- g_signal_connect (self->store, "app-added",
- G_CALLBACK (gs_flatpak_store_app_added_cb),
- self);
- g_signal_connect (self->store, "app-removed",
- G_CALLBACK (gs_flatpak_store_app_removed_cb),
- self);
- as_store_set_add_flags (self->store, AS_STORE_ADD_FLAG_USE_UNIQUE_ID);
- as_store_set_watch_flags (self->store, AS_STORE_WATCH_FLAG_REMOVED);
- as_store_set_search_match (self->store,
- AS_APP_SEARCH_MATCH_MIMETYPE |
- AS_APP_SEARCH_MATCH_PKGNAME |
- AS_APP_SEARCH_MATCH_COMMENT |
- AS_APP_SEARCH_MATCH_NAME |
- AS_APP_SEARCH_MATCH_KEYWORD |
- AS_APP_SEARCH_MATCH_ID);
}
GsFlatpak *
diff --git a/plugins/flatpak/gs-plugin-flatpak.c b/plugins/flatpak/gs-plugin-flatpak.c
index eec3d6f0..2bd94791 100644
--- a/plugins/flatpak/gs-plugin-flatpak.c
+++ b/plugins/flatpak/gs-plugin-flatpak.c
@@ -292,6 +292,12 @@ gs_plugin_flatpak_refine_app (GsPlugin *plugin,
GsPluginData *priv = gs_plugin_get_data (plugin);
GsFlatpak *flatpak = NULL;
+ /* not us */
+ if (gs_app_get_bundle_kind (app) != AS_BUNDLE_KIND_FLATPAK) {
+ g_debug ("%s not a package, ignoring", gs_app_get_unique_id (app));
+ return TRUE;
+ }
+
/* we have to look for the app in all GsFlatpak stores */
if (gs_app_get_scope (app) == AS_APP_SCOPE_UNKNOWN) {
for (guint i = 0; i < priv->flatpaks->len; i++) {
diff --git a/plugins/flatpak/gs-self-test.c b/plugins/flatpak/gs-self-test.c
index 6d672d82..5a06a2e8 100644
--- a/plugins/flatpak/gs-self-test.c
+++ b/plugins/flatpak/gs-self-test.c
@@ -22,6 +22,8 @@
#include "config.h"
+#include <glib/gstdio.h>
+
#include "gnome-software-private.h"
#include "gs-flatpak-app.h"
@@ -230,6 +232,8 @@ gs_plugins_flatpak_app_with_runtime_func (GsPluginLoader *plugin_loader)
g_autoptr(GsPluginJob) plugin_job = NULL;
/* drop all caches */
+ g_unlink ("/var/tmp/self-test/flatpak/components.xmlb");
+ g_unlink ("/var/tmp/self-test/appstream/components.xmlb");
gs_plugin_loader_setup_again (plugin_loader);
/* no flatpak, abort */
@@ -323,6 +327,8 @@ gs_plugins_flatpak_app_with_runtime_func (GsPluginLoader *plugin_loader)
"refine-flags", GS_PLUGIN_REFINE_FLAGS_REQUIRE_ORIGIN_HOSTNAME |
GS_PLUGIN_REFINE_FLAGS_REQUIRE_PERMISSIONS |
GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION |
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_KUDOS |
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_RUNTIME |
GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON,
NULL);
list = gs_plugin_loader_job_process (plugin_loader, plugin_job, NULL, &error);
@@ -496,6 +502,8 @@ gs_plugins_flatpak_app_missing_runtime_func (GsPluginLoader *plugin_loader)
g_autoptr(GsPluginJob) plugin_job = NULL;
/* drop all caches */
+ g_unlink ("/var/tmp/self-test/flatpak/components.xmlb");
+ g_unlink ("/var/tmp/self-test/appstream/components.xmlb");
gs_plugin_loader_setup_again (plugin_loader);
/* no flatpak, abort */
@@ -642,6 +650,8 @@ gs_plugins_flatpak_runtime_repo_func (GsPluginLoader *plugin_loader)
g_autoptr(GsPluginJob) plugin_job = NULL;
/* drop all caches */
+ g_unlink ("/var/tmp/self-test/flatpak/components.xmlb");
+ g_unlink ("/var/tmp/self-test/appstream/components.xmlb");
gs_plugin_loader_setup_again (plugin_loader);
/* write a flatpakrepo file */
@@ -777,6 +787,8 @@ gs_plugins_flatpak_runtime_repo_redundant_func (GsPluginLoader *plugin_loader)
g_autoptr(GsPluginJob) plugin_job = NULL;
/* drop all caches */
+ g_unlink ("/var/tmp/self-test/flatpak/components.xmlb");
+ g_unlink ("/var/tmp/self-test/appstream/components.xmlb");
gs_plugin_loader_setup_again (plugin_loader);
/* write a flatpakrepo file */
@@ -930,6 +942,8 @@ gs_plugins_flatpak_broken_remote_func (GsPluginLoader *plugin_loader)
g_autoptr(GsPluginJob) plugin_job = NULL;
/* drop all caches */
+ g_unlink ("/var/tmp/self-test/flatpak/components.xmlb");
+ g_unlink ("/var/tmp/self-test/appstream/components.xmlb");
gs_plugin_loader_setup_again (plugin_loader);
/* no flatpak, abort */
@@ -1018,6 +1032,8 @@ gs_plugins_flatpak_ref_func (GsPluginLoader *plugin_loader)
g_autoptr(GString) str = g_string_new (NULL);
/* drop all caches */
+ g_unlink ("/var/tmp/self-test/flatpak/components.xmlb");
+ g_unlink ("/var/tmp/self-test/appstream/components.xmlb");
gs_plugin_loader_setup_again (plugin_loader);
/* no flatpak, abort */
@@ -1237,6 +1253,8 @@ gs_plugins_flatpak_app_update_func (GsPluginLoader *plugin_loader)
g_autoptr(GMainLoop) loop = g_main_loop_new (NULL, FALSE);
/* drop all caches */
+ g_unlink ("/var/tmp/self-test/flatpak/components.xmlb");
+ g_unlink ("/var/tmp/self-test/appstream/components.xmlb");
gs_plugin_loader_setup_again (plugin_loader);
/* no flatpak, abort */
@@ -1484,6 +1502,8 @@ gs_plugins_flatpak_runtime_extension_func (GsPluginLoader *plugin_loader)
g_autoptr(GMainLoop) loop = g_main_loop_new (NULL, FALSE);
/* drop all caches */
+ g_unlink ("/var/tmp/self-test/flatpak/components.xmlb");
+ g_unlink ("/var/tmp/self-test/appstream/components.xmlb");
gs_plugin_loader_setup_again (plugin_loader);
/* no flatpak, abort */
@@ -1704,6 +1724,7 @@ main (int argc, char **argv)
g_test_init (&argc, &argv, NULL);
g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
g_setenv ("GS_SELF_TEST_FLATPAK_DATADIR", tmp_root, TRUE);
+ g_setenv ("GS_SELF_TEST_CORE_DATADIR", tmp_root, TRUE); //FIXME
g_setenv ("GS_SELF_TEST_PLUGIN_ERROR_FAIL_HARD", "1", TRUE);
/* allow dist'ing with no gnome-software installed */
diff --git a/plugins/flatpak/meson.build b/plugins/flatpak/meson.build
index 25b853db..ac82bfc0 100644
--- a/plugins/flatpak/meson.build
+++ b/plugins/flatpak/meson.build
@@ -19,7 +19,11 @@ shared_module(
install : true,
install_dir: plugin_dir,
c_args : cargs,
- dependencies : [ plugin_libs, flatpak ]
+ dependencies : [
+ plugin_libs,
+ flatpak,
+ libxmlb,
+ ],
)
metainfo = 'org.gnome.Software.Plugin.Flatpak.metainfo.xml'
diff --git a/plugins/modalias/gs-self-test.c b/plugins/modalias/gs-self-test.c
index dbe628a7..1aa11a30 100644
--- a/plugins/modalias/gs-self-test.c
+++ b/plugins/modalias/gs-self-test.c
@@ -21,6 +21,8 @@
#include "config.h"
+#include <glib/gstdio.h>
+
#include "gnome-software-private.h"
#include "gs-test.h"
@@ -34,6 +36,9 @@ gs_plugins_modalias_func (GsPluginLoader *plugin_loader)
g_autoptr(GsAppList) list = NULL;
g_autoptr(GsPluginJob) plugin_job = NULL;
+ /* drop all caches */
+// g_unlink ("/var/tmp/self-test/appstream/components.xmlb");
+
/* get search result based on addon keyword */
plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_SEARCH,
"search", "colorhug2",
@@ -56,6 +61,7 @@ gs_plugins_modalias_func (GsPluginLoader *plugin_loader)
int
main (int argc, char **argv)
{
+ const gchar *tmp_root = "/var/tmp/self-test";
gboolean ret;
g_autofree gchar *xml = NULL;
g_autoptr(GError) error = NULL;
@@ -83,6 +89,7 @@ main (int argc, char **argv)
" </component>\n"
"</components>\n");
g_setenv ("GS_SELF_TEST_APPSTREAM_XML", xml, TRUE);
+ g_setenv ("GS_SELF_TEST_CORE_DATADIR", tmp_root, TRUE);
/* only critical and error are fatal */
g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
diff --git a/plugins/odrs/meson.build b/plugins/odrs/meson.build
index 28de57a4..026ffc92 100644
--- a/plugins/odrs/meson.build
+++ b/plugins/odrs/meson.build
@@ -6,6 +6,7 @@ shared_module(
include_directories : [
include_directories('../..'),
include_directories('../../lib'),
+ include_directories('../../libxmlb/src'),
],
install : true,
install_dir: plugin_dir,
diff --git a/plugins/shell-extensions/gs-plugin-shell-extensions.c
b/plugins/shell-extensions/gs-plugin-shell-extensions.c
index 28259adb..13f03c83 100644
--- a/plugins/shell-extensions/gs-plugin-shell-extensions.c
+++ b/plugins/shell-extensions/gs-plugin-shell-extensions.c
@@ -26,6 +26,7 @@
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <json-glib/json-glib.h>
+#include <xmlb.h>
#include <gnome-software.h>
@@ -437,7 +438,8 @@ gs_plugin_refine_app (GsPlugin *plugin,
static gboolean
gs_plugin_shell_extensions_parse_version (GsPlugin *plugin,
- AsApp *app,
+ const gchar *component_id,
+ XbBuilderNode *app,
JsonObject *ver_map,
GError **error)
{
@@ -445,7 +447,7 @@ gs_plugin_shell_extensions_parse_version (GsPlugin *plugin,
JsonObject *json_ver = NULL;
gint64 version;
g_autofree gchar *shell_version = NULL;
- g_autoptr(AsRelease) release = NULL;
+ g_autoptr(XbBuilderNode) release = NULL;
/* look for version, major.minor.micro */
if (json_object_has_member (ver_map, priv->shell_version)) {
@@ -468,7 +470,7 @@ gs_plugin_shell_extensions_parse_version (GsPlugin *plugin,
/* FIXME: mark as incompatible? */
if (json_ver == NULL) {
g_debug ("no version_map for %s: %s",
- as_app_get_id (app),
+ component_id,
priv->shell_version);
return TRUE;
}
@@ -485,108 +487,106 @@ gs_plugin_shell_extensions_parse_version (GsPlugin *plugin,
shell_version = g_strdup_printf ("%" G_GINT64_FORMAT, version);
/* add a dummy release */
- release = as_release_new ();
- as_release_set_version (release, shell_version);
- as_app_add_release (app, release);
+ xb_builder_node_insert_text (app, "release", NULL,
+ "version", shell_version,
+ NULL);
return TRUE;
}
-static AsApp *
+
+
+static XbBuilderNode *
gs_plugin_shell_extensions_parse_app (GsPlugin *plugin,
JsonObject *json_app,
GError **error)
{
- g_autoptr(AsApp) app = NULL;
JsonObject *json_ver_map;
const gchar *tmp;
+ g_autofree gchar *component_id = NULL;
+ g_autoptr(XbBuilderNode) app = NULL;
+ g_autoptr(XbBuilderNode) metadata = NULL;
- app = as_app_new ();
- as_app_set_kind (app, AS_APP_KIND_SHELL_EXTENSION);
- as_app_set_project_license (app, "GPL-2.0+");
+ app = xb_builder_node_new ("component");
+ xb_builder_node_set_attr (app, "kind", "shell-extension");
+ xb_builder_node_insert_text (app, "project_license", "GPL-2.0+", NULL);
+ metadata = xb_builder_node_insert (app, "metadata", NULL);
tmp = json_object_get_string_member (json_app, "description");
if (tmp != NULL) {
- g_autofree gchar *desc = NULL;
- desc = as_markup_import (tmp, AS_MARKUP_CONVERT_FORMAT_SIMPLE, error);
- if (desc == NULL) {
- gs_utils_error_convert_appstream (error);
- return NULL;
- }
- as_app_set_description (app, NULL, desc);
+ g_auto(GStrv) paras = g_strsplit (tmp, "\n", -1);
+ g_autoptr(XbBuilderNode) desc = xb_builder_node_insert (app, "description", NULL);
+ for (guint i = 0; paras[i] != NULL; i++)
+ xb_builder_node_insert_text (desc, "p", paras[i], NULL);
}
tmp = json_object_get_string_member (json_app, "screenshot");
if (tmp != NULL) {
- g_autoptr(AsScreenshot) ss = NULL;
- g_autoptr(AsImage) im = NULL;
+ g_autoptr(XbBuilderNode) screenshots = NULL;
+ g_autoptr(XbBuilderNode) screenshot = NULL;
g_autofree gchar *uri = NULL;
+ screenshots = xb_builder_node_insert (app, "screenshots", NULL);
+ screenshot = xb_builder_node_insert (screenshots, "screenshot",
+ "kind", "default",
+ NULL);
uri = g_build_path ("/", SHELL_EXTENSIONS_API_URI, tmp, NULL);
- im = as_image_new ();
- as_image_set_kind (im, AS_IMAGE_KIND_SOURCE);
- as_image_set_url (im, uri);
- ss = as_screenshot_new ();
- as_screenshot_set_kind (ss, AS_SCREENSHOT_KIND_DEFAULT);
- as_screenshot_add_image (ss, im);
- as_app_add_screenshot (app, ss);
+ xb_builder_node_insert_text (screenshot, "image", uri,
+ "kind", "source",
+ NULL);
}
tmp = json_object_get_string_member (json_app, "name");
if (tmp != NULL)
- as_app_set_name (app, NULL, tmp);
+ xb_builder_node_insert_text (app, "name", tmp, NULL);
tmp = json_object_get_string_member (json_app, "uuid");
if (tmp != NULL) {
- g_autofree gchar *id = NULL;
- id = as_utils_appstream_id_build (tmp);
- as_app_set_id (app, id);
- as_app_add_metadata (app, "shell-extensions::uuid", tmp);
+ component_id = as_utils_appstream_id_build (tmp);
+ xb_builder_node_insert_text (app, "id", component_id, NULL);
+ xb_builder_node_insert_text (metadata, "value", tmp,
+ "key", "shell-extensions::uuid",
+ NULL);
}
tmp = json_object_get_string_member (json_app, "link");
if (tmp != NULL) {
g_autofree gchar *uri = NULL;
uri = g_build_filename (SHELL_EXTENSIONS_API_URI, tmp, NULL);
- as_app_add_url (app, AS_URL_KIND_HOMEPAGE, uri);
+ xb_builder_node_insert_text (app, "url", uri,
+ "type", "homepage",
+ NULL);
}
tmp = json_object_get_string_member (json_app, "icon");
if (tmp != NULL) {
- g_autoptr(AsIcon) ic = NULL;
/* just use a stock icon as the remote icons are
* sometimes missing, poor quality and low resolution */
- ic = as_icon_new ();
- as_icon_set_kind (ic, AS_ICON_KIND_STOCK);
- as_icon_set_name (ic, "application-x-addon-symbolic");
- as_app_add_icon (app, ic);
+ xb_builder_node_insert_text (app, "icon",
+ "application-x-addon-symbolic",
+ "type", "stock",
+ NULL);
}
/* try to get version */
json_ver_map = json_object_get_object_member (json_app, "shell_version_map");
if (json_ver_map != NULL) {
if (!gs_plugin_shell_extensions_parse_version (plugin,
+ component_id,
app,
json_ver_map,
error))
return NULL;
}
- /* we have no data :/ */
- as_app_add_metadata (app, "GnomeSoftware::Plugin",
- gs_plugin_get_name (plugin));
- as_app_add_metadata (app, "GnomeSoftware::OriginHostnameUrl",
- SHELL_EXTENSIONS_API_URI);
-
return g_steal_pointer (&app);
}
-static GPtrArray *
+static XbBuilderNode *
gs_plugin_shell_extensions_parse_apps (GsPlugin *plugin,
const gchar *data,
gssize data_len,
GError **error)
{
- GPtrArray *apps;
JsonArray *json_extensions_array;
JsonNode *json_extensions;
JsonNode *json_root;
JsonObject *json_item;
- guint i;
g_autoptr(JsonParser) json_parser = NULL;
+ g_autoptr(XbBuilderNode) apps = NULL;
/* nothing */
if (data == NULL) {
@@ -628,7 +628,7 @@ gs_plugin_shell_extensions_parse_apps (GsPlugin *plugin,
}
/* load extensions */
- apps = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+ apps = xb_builder_node_new ("components");
json_extensions = json_object_get_member (json_item, "extensions");
if (json_extensions == NULL) {
g_set_error_literal (error,
@@ -647,36 +647,36 @@ gs_plugin_shell_extensions_parse_apps (GsPlugin *plugin,
}
/* parse each app */
- for (i = 0; i < json_array_get_length (json_extensions_array); i++) {
- AsApp *app;
+ for (guint i = 0; i < json_array_get_length (json_extensions_array); i++) {
+ XbBuilderNode *component;
JsonNode *json_extension;
JsonObject *json_extension_obj;
json_extension = json_array_get_element (json_extensions_array, i);
json_extension_obj = json_node_get_object (json_extension);
- app = gs_plugin_shell_extensions_parse_app (plugin,
+ component = gs_plugin_shell_extensions_parse_app (plugin,
json_extension_obj,
error);
- if (app == NULL)
+ if (component == NULL)
return NULL;
- g_ptr_array_add (apps, app);
+ xb_builder_node_add_child (apps, component);
}
- return apps;
+ return g_steal_pointer (&apps);
}
-static GPtrArray *
+static XbBuilderNode *
gs_plugin_shell_extensions_get_apps (GsPlugin *plugin,
guint cache_age,
GCancellable *cancellable,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- GPtrArray *apps;
g_autofree gchar *cachefn = NULL;
g_autofree gchar *uri = NULL;
- g_autoptr(GFile) cachefn_file = NULL;
g_autoptr(GBytes) data = NULL;
+ g_autoptr(GFile) cachefn_file = NULL;
g_autoptr(GsApp) app_dl = gs_app_new (gs_plugin_get_name (plugin));
+ g_autoptr(XbBuilderNode) apps = NULL;
/* look in the cache */
cachefn = gs_utils_get_cache_filename ("shell-extensions",
@@ -730,7 +730,7 @@ gs_plugin_shell_extensions_get_apps (GsPlugin *plugin,
error))
return NULL;
- return apps;
+ return g_steal_pointer (&apps);
}
static gboolean
@@ -740,25 +740,26 @@ gs_plugin_shell_extensions_refresh (GsPlugin *plugin,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- AsApp *app;
gboolean repo_enabled;
const gchar *fn_test;
- guint i;
g_autofree gchar *fn = NULL;
- g_autoptr(GPtrArray) apps = NULL;
- g_autoptr(AsStore) store = NULL;
+ g_autoptr(GError) error_local = NULL;
g_autoptr(GFile) file = NULL;
+ g_autoptr(XbBuilder) builder = xb_builder_new ();
+ g_autoptr(XbBuilderNode) apps = NULL;
+ g_autoptr(XbSilo) silo = NULL;
/* check age */
fn_test = g_getenv ("GS_SELF_TEST_SHELL_EXTENSIONS_XML_FN");
if (fn_test != NULL) {
fn = g_strdup (fn_test);
} else {
- fn = g_build_filename (g_get_user_data_dir (),
- "app-info",
- "xmls",
- "extensions-web.xml",
- NULL);
+ fn = gs_utils_get_cache_filename ("shell-extensions",
+ "extensions-web.xmlb",
+ GS_UTILS_CACHE_FLAG_WRITEABLE,
+ error);
+ if (fn == NULL)
+ return FALSE;
}
/* remove old appstream data if the repo is disabled */
@@ -785,25 +786,22 @@ gs_plugin_shell_extensions_refresh (GsPlugin *plugin,
if (apps == NULL)
return FALSE;
- /* add to local store */
- store = as_store_new ();
- as_store_set_origin (store, "extensions-web");
- for (i = 0; i < apps->len; i++) {
- app = g_ptr_array_index (apps, i);
- g_debug ("adding to local store %s", as_app_get_id (app));
- as_store_add_app (store, app);
- }
+ /* add to builder */
+ xb_builder_import_node (builder, apps);
/* save to disk */
- if (!gs_mkdir_parent (fn, error))
+ silo = xb_builder_ensure (builder, file,
+ XB_BUILDER_COMPILE_FLAG_NONE,
+ cancellable, &error_local);
+ if (silo == NULL) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "failed to compile %s",
+ error_local->message);
return FALSE;
- g_debug ("saving to %s", fn);
- return as_store_to_file (store, file,
- AS_NODE_TO_XML_FLAG_ADD_HEADER |
- AS_NODE_TO_XML_FLAG_FORMAT_INDENT |
- AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE,
- cancellable,
- error);
+ }
+ return TRUE;
}
gboolean
diff --git a/plugins/shell-extensions/gs-self-test.c b/plugins/shell-extensions/gs-self-test.c
index b0fb993d..29db7106 100644
--- a/plugins/shell-extensions/gs-self-test.c
+++ b/plugins/shell-extensions/gs-self-test.c
@@ -22,6 +22,7 @@
#include "config.h"
#include <glib/gstdio.h>
+#include <xmlb.h>
#include "gnome-software-private.h"
@@ -77,12 +78,13 @@ gs_plugins_shell_extensions_installed_func (GsPluginLoader *plugin_loader)
static void
gs_plugins_shell_extensions_remote_func (GsPluginLoader *plugin_loader)
{
- const gchar *xml_fn = "/var/tmp/self-test/extensions-web.xml";
+ const gchar *xml_fn = "/var/tmp/self-test/extensions-web.xmlb";
gboolean ret;
g_autoptr(GError) error = NULL;
g_autoptr(GFile) file = NULL;
+ g_autoptr(GPtrArray) components = NULL;
g_autoptr(GsPluginJob) plugin_job = NULL;
- g_autoptr(AsStore) store = NULL;
+ g_autoptr(XbSilo) silo = NULL;
/* no shell-extensions, abort */
if (!gs_plugin_loader_get_enabled (plugin_loader, "shell-extensions")) {
@@ -103,12 +105,17 @@ gs_plugins_shell_extensions_remote_func (GsPluginLoader *plugin_loader)
g_assert (ret);
/* ensure file was populated */
- store = as_store_new ();
+ silo = xb_silo_new ();
file = g_file_new_for_path (xml_fn);
- ret = as_store_from_file (store, file, NULL, NULL, &error);
+ ret = xb_silo_load_from_file (silo, file,
+ XB_SILO_LOAD_FLAG_NONE,
+ NULL, &error);
g_assert_no_error (error);
g_assert (ret);
- g_assert_cmpint (as_store_get_size (store), >, 20);
+ components = xb_silo_query (silo, "components/component", 0, &error);
+ g_assert_no_error (error);
+ g_assert_nonnull (components);
+ g_assert_cmpint (components->len, >, 20);
}
int
diff --git a/plugins/shell-extensions/meson.build b/plugins/shell-extensions/meson.build
index 655562bc..dec9d97d 100644
--- a/plugins/shell-extensions/meson.build
+++ b/plugins/shell-extensions/meson.build
@@ -11,7 +11,10 @@ sources : 'gs-plugin-shell-extensions.c',
install : true,
install_dir: plugin_dir,
c_args : cargs,
- dependencies : plugin_libs
+ dependencies : [
+ plugin_libs,
+ libxmlb,
+ ],
)
if get_option('tests')
@@ -27,6 +30,7 @@ if get_option('tests')
],
dependencies : [
plugin_libs,
+ libxmlb,
],
link_with : [
libgnomesoftware
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]