diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..97e17e2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/appstream-glib-0.7.14.tar.xz diff --git a/.libappstream-glib.metadata b/.libappstream-glib.metadata new file mode 100644 index 0000000..73d7c70 --- /dev/null +++ b/.libappstream-glib.metadata @@ -0,0 +1 @@ +de3efb3940cf32dd178340da46c7cb1b3b304562 SOURCES/appstream-glib-0.7.14.tar.xz diff --git a/SOURCES/as-store-locking.patch b/SOURCES/as-store-locking.patch new file mode 100644 index 0000000..e40836c --- /dev/null +++ b/SOURCES/as-store-locking.patch @@ -0,0 +1,880 @@ +From e5f73b24c4950ec8e51f6970ad658d604baf6d24 Mon Sep 17 00:00:00 2001 +From: Kalev Lember +Date: Fri, 14 Dec 2018 11:40:46 +0100 +Subject: [PATCH 1/3] store: Add thread safe dup() functions for multithreaded + clients + +gnome-software spawns a new worker thread for each of its plugin +operations and occasionally this leads to issues where one thread is +reading from AsStore, and another one is changing it. There's also file +monitor callbacks in AsStore that run in a yet another thread and can +update internal data structures as well. + +This leads to a situation where functions returning pointers to internal +data structures can't guarantee the data structure lifetime because +another thread might be changing it in the background. + +To fix this, this commit adds new as_store_dup_apps() and +as_store_dup_apps_by_id_merge() functions that return a deep copy of the +internal structure, and updates existing "transfer container" +as_store_get_apps_by_id() to return a deep copy, instead just returning +a reffed container. +--- + libappstream-glib/as-self-test.c | 4 +- + libappstream-glib/as-store.c | 65 +++++++++++++++++++++++++++++++- + libappstream-glib/as-store.h | 3 ++ + 3 files changed, 69 insertions(+), 3 deletions(-) + +diff --git a/libappstream-glib/as-self-test.c b/libappstream-glib/as-self-test.c +index d90af48..7fd7d75 100644 +--- a/libappstream-glib/as-self-test.c ++++ b/libappstream-glib/as-self-test.c +@@ -3477,12 +3477,12 @@ as_test_store_flatpak_func (void) + AsApp *app; + AsFormat *format; + GError *error = NULL; +- GPtrArray *apps; + gboolean ret; + g_autofree gchar *filename = NULL; + g_autofree gchar *filename_root = NULL; + g_autoptr(AsStore) store = NULL; + g_autoptr(GFile) file = NULL; ++ g_autoptr(GPtrArray) apps = NULL; + + /* make throws us under a bus, yet again */ + g_setenv ("AS_SELF_TEST_PREFIX_DELIM", "_", TRUE); +@@ -3503,7 +3503,7 @@ as_test_store_flatpak_func (void) + /* test extraction of symlink data */ + g_assert_cmpstr (as_store_get_origin (store), ==, "flatpak"); + g_assert_cmpint (as_store_get_size (store), ==, 1); +- apps = as_store_get_apps (store); ++ apps = as_store_dup_apps (store); + g_assert_cmpint (apps->len, ==, 1); + app = g_ptr_array_index (apps, 0); + g_assert_cmpstr (as_app_get_id (app), ==, "flatpak:test.desktop"); +diff --git a/libappstream-glib/as-store.c b/libappstream-glib/as-store.c +index d2075eb..59a7f1c 100644 +--- a/libappstream-glib/as-store.c ++++ b/libappstream-glib/as-store.c +@@ -1,6 +1,7 @@ + /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2013-2016 Richard Hughes ++ * Copyright (C) 2015-2018 Kalev Lember + * + * Licensed under the GNU Lesser General Public License Version 2.1 + * +@@ -264,6 +265,22 @@ as_store_changed_uninhibit_cb (void *v) + + #define _cleanup_uninhibit_ __attribute__ ((cleanup(as_store_changed_uninhibit_cb))) + ++static GPtrArray * ++_dup_app_array (GPtrArray *array) ++{ ++ GPtrArray *array_dup; ++ ++ g_return_val_if_fail (array != NULL, NULL); ++ ++ array_dup = g_ptr_array_new_full (array->len, (GDestroyNotify) g_object_unref); ++ for (guint i = 0; i < array->len; i++) { ++ AsApp *app = g_ptr_array_index (array, i); ++ g_ptr_array_add (array_dup, g_object_ref (app)); ++ } ++ ++ return array_dup; ++} ++ + /** + * as_store_add_filter: + * @store: a #AsStore instance. +@@ -344,6 +361,27 @@ as_store_get_apps (AsStore *store) + return priv->array; + } + ++/** ++ * as_store_dup_apps: ++ * @store: a #AsStore instance. ++ * ++ * Gets an array of all the valid applications in the store. ++ * ++ * Returns: (element-type AsApp) (transfer container): an array ++ * ++ * Since: 0.7.15 ++ **/ ++GPtrArray * ++as_store_dup_apps (AsStore *store) ++{ ++ ++ AsStorePrivate *priv = GET_PRIVATE (store); ++ ++ g_return_val_if_fail (AS_IS_STORE (store), NULL); ++ ++ return _dup_app_array (priv->array); ++} ++ + /** + * as_store_remove_all: + * @store: a #AsStore instance. +@@ -471,7 +509,7 @@ as_store_get_apps_by_id (AsStore *store, const gchar *id) + g_return_val_if_fail (AS_IS_STORE (store), NULL); + apps = g_hash_table_lookup (priv->hash_id, id); + if (apps != NULL) +- return g_ptr_array_ref (apps); ++ return _dup_app_array (apps); + return g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + } + +@@ -494,6 +532,31 @@ as_store_get_apps_by_id_merge (AsStore *store, const gchar *id) + return g_hash_table_lookup (priv->hash_merge_id, id); + } + ++/** ++ * as_store_dup_apps_by_id_merge: ++ * @store: a #AsStore instance. ++ * @id: the application full ID. ++ * ++ * Gets an array of all the merge applications that match a specific ID. ++ * ++ * Returns: (element-type AsApp) (transfer container): an array ++ * ++ * Since: 0.7.15 ++ **/ ++GPtrArray * ++as_store_dup_apps_by_id_merge (AsStore *store, const gchar *id) ++{ ++ AsStorePrivate *priv = GET_PRIVATE (store); ++ GPtrArray *apps; ++ ++ g_return_val_if_fail (AS_IS_STORE (store), NULL); ++ ++ apps = g_hash_table_lookup (priv->hash_merge_id, id); ++ if (apps != NULL) ++ return _dup_app_array (apps); ++ return g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); ++} ++ + /** + * as_store_add_metadata_index: + * @store: a #AsStore instance. +diff --git a/libappstream-glib/as-store.h b/libappstream-glib/as-store.h +index 3d8c749..b15aca4 100644 +--- a/libappstream-glib/as-store.h ++++ b/libappstream-glib/as-store.h +@@ -209,10 +209,13 @@ void as_store_set_search_match (AsStore *store, + guint16 as_store_get_search_match (AsStore *store); + void as_store_remove_all (AsStore *store); + GPtrArray *as_store_get_apps (AsStore *store); ++GPtrArray *as_store_dup_apps (AsStore *store); + GPtrArray *as_store_get_apps_by_id (AsStore *store, + const gchar *id); + GPtrArray *as_store_get_apps_by_id_merge (AsStore *store, + const gchar *id); ++GPtrArray *as_store_dup_apps_by_id_merge (AsStore *store, ++ const gchar *id); + GPtrArray *as_store_get_apps_by_metadata (AsStore *store, + const gchar *key, + const gchar *value); +-- +2.19.1 + + +From 0f79c943948abb62a54d0e54b1135ff89ebf5ab4 Mon Sep 17 00:00:00 2001 +From: Kalev Lember +Date: Fri, 14 Dec 2018 11:52:19 +0100 +Subject: [PATCH 2/3] store: Return deep copy in as_store_get_apps_by_metadata + +This is strictly not necessary for making gnome-software's AsStore use +thread safe as gnome-software doesn't actually use this function, but +let's fix it anyway while I'm at it. + +This also updates tests that test the performance of the function as the +deep copying makes it noticably slower (but that's fine because nothing +actually uses it and it's still reasonably fast). +--- + libappstream-glib/as-self-test.c | 2 +- + libappstream-glib/as-store.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libappstream-glib/as-self-test.c b/libappstream-glib/as-self-test.c +index 7fd7d75..981b790 100644 +--- a/libappstream-glib/as-self-test.c ++++ b/libappstream-glib/as-self-test.c +@@ -4730,7 +4730,7 @@ static void + as_test_store_metadata_index_func (void) + { + GPtrArray *apps; +- const guint repeats = 10000; ++ const guint repeats = 500; + guint i; + g_autoptr(AsStore) store = NULL; + g_autoptr(GTimer) timer = NULL; +diff --git a/libappstream-glib/as-store.c b/libappstream-glib/as-store.c +index 59a7f1c..018bdb5 100644 +--- a/libappstream-glib/as-store.c ++++ b/libappstream-glib/as-store.c +@@ -473,7 +473,7 @@ as_store_get_apps_by_metadata (AsStore *store, + } + apps = g_hash_table_lookup (index, value); + if (apps != NULL) +- return g_ptr_array_ref (apps); ++ return _dup_app_array (apps); + return g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + } + +-- +2.19.1 + + +From 24913fb9ac74f671fdba7547049bcaa0899704ee Mon Sep 17 00:00:00 2001 +From: Kalev Lember +Date: Fri, 14 Dec 2018 12:03:37 +0100 +Subject: [PATCH 3/3] store: Add internal locking + +This adds fine-grained locking around priv->array and various +priv-stored hash table use. There are more thread safe issues in +AsStore, but this should take care of those that cause frequent +gnome-software crashes in F29. + +This may regress the perfomance a bit because it changes a few places to +keep a deep copy to simplify locking, but I haven't observed any visible +performance regressions in gnome-software. Also, gnome-software is in +the process of switching to libxmlb anyway so it shouldn't matter a +whole lot in the long run. + +This patch takes care to make sure that locking is fine grained enough +so that we can be sure it doesn't lead into deadlocks, and also makes +sure that we never invoke any callbacks (signals) while locked to +prevent deadlocks when a client app calls back into AsStore code. +--- + libappstream-glib/as-store.c | 191 ++++++++++++++++++++++++++++------- + 1 file changed, 155 insertions(+), 36 deletions(-) + +diff --git a/libappstream-glib/as-store.c b/libappstream-glib/as-store.c +index 018bdb5..0308585 100644 +--- a/libappstream-glib/as-store.c ++++ b/libappstream-glib/as-store.c +@@ -68,6 +68,7 @@ typedef struct + GHashTable *hash_merge_id; /* of GPtrArray of AsApp{id} */ + GHashTable *hash_unique_id; /* of AsApp{unique_id} */ + GHashTable *hash_pkgname; /* of AsApp{pkgname} */ ++ GMutex mutex; + AsMonitor *monitor; + GHashTable *metadata_indexes; /* GHashTable{key} */ + GHashTable *appinfo_dirs; /* GHashTable{path:AsStorePathData} */ +@@ -140,6 +141,7 @@ as_store_finalize (GObject *object) + g_hash_table_unref (priv->metadata_indexes); + g_hash_table_unref (priv->appinfo_dirs); + g_hash_table_unref (priv->search_blacklist); ++ g_mutex_clear (&priv->mutex); + + G_OBJECT_CLASS (as_store_parent_class)->finalize (object); + } +@@ -339,7 +341,11 @@ guint + as_store_get_size (AsStore *store) + { + AsStorePrivate *priv = GET_PRIVATE (store); ++ g_autoptr(GMutexLocker) locker = NULL; ++ + g_return_val_if_fail (AS_IS_STORE (store), 0); ++ ++ locker = g_mutex_locker_new (&priv->mutex); + return priv->array->len; + } + +@@ -357,7 +363,11 @@ GPtrArray * + as_store_get_apps (AsStore *store) + { + AsStorePrivate *priv = GET_PRIVATE (store); ++ g_autoptr(GMutexLocker) locker = NULL; ++ + g_return_val_if_fail (AS_IS_STORE (store), NULL); ++ ++ locker = g_mutex_locker_new (&priv->mutex); + return priv->array; + } + +@@ -376,9 +386,11 @@ as_store_dup_apps (AsStore *store) + { + + AsStorePrivate *priv = GET_PRIVATE (store); ++ g_autoptr(GMutexLocker) locker = NULL; + + g_return_val_if_fail (AS_IS_STORE (store), NULL); + ++ locker = g_mutex_locker_new (&priv->mutex); + return _dup_app_array (priv->array); + } + +@@ -394,7 +406,11 @@ void + as_store_remove_all (AsStore *store) + { + AsStorePrivate *priv = GET_PRIVATE (store); ++ g_autoptr(GMutexLocker) locker = NULL; ++ + g_return_if_fail (AS_IS_STORE (store)); ++ ++ locker = g_mutex_locker_new (&priv->mutex); + g_ptr_array_set_size (priv->array, 0); + g_hash_table_remove_all (priv->hash_id); + g_hash_table_remove_all (priv->hash_merge_id); +@@ -461,9 +477,12 @@ as_store_get_apps_by_metadata (AsStore *store, + GHashTable *index; + GPtrArray *apps; + guint i; ++ g_autoptr(GMutexLocker) locker = NULL; + + g_return_val_if_fail (AS_IS_STORE (store), NULL); + ++ locker = g_mutex_locker_new (&priv->mutex); ++ + /* do we have this indexed? */ + index = g_hash_table_lookup (priv->metadata_indexes, key); + if (index != NULL) { +@@ -506,7 +525,12 @@ as_store_get_apps_by_id (AsStore *store, const gchar *id) + { + AsStorePrivate *priv = GET_PRIVATE (store); + GPtrArray *apps; ++ g_autoptr(GMutexLocker) locker = NULL; ++ + g_return_val_if_fail (AS_IS_STORE (store), NULL); ++ ++ locker = g_mutex_locker_new (&priv->mutex); ++ + apps = g_hash_table_lookup (priv->hash_id, id); + if (apps != NULL) + return _dup_app_array (apps); +@@ -528,7 +552,11 @@ GPtrArray * + as_store_get_apps_by_id_merge (AsStore *store, const gchar *id) + { + AsStorePrivate *priv = GET_PRIVATE (store); ++ g_autoptr(GMutexLocker) locker = NULL; ++ + g_return_val_if_fail (AS_IS_STORE (store), NULL); ++ ++ locker = g_mutex_locker_new (&priv->mutex); + return g_hash_table_lookup (priv->hash_merge_id, id); + } + +@@ -548,9 +576,12 @@ as_store_dup_apps_by_id_merge (AsStore *store, const gchar *id) + { + AsStorePrivate *priv = GET_PRIVATE (store); + GPtrArray *apps; ++ g_autoptr(GMutexLocker) locker = NULL; + + g_return_val_if_fail (AS_IS_STORE (store), NULL); + ++ locker = g_mutex_locker_new (&priv->mutex); ++ + apps = g_hash_table_lookup (priv->hash_merge_id, id); + if (apps != NULL) + return _dup_app_array (apps); +@@ -572,6 +603,12 @@ as_store_dup_apps_by_id_merge (AsStore *store, const gchar *id) + void + as_store_add_metadata_index (AsStore *store, const gchar *key) + { ++ AsStorePrivate *priv = GET_PRIVATE (store); ++ g_autoptr(GMutexLocker) locker = NULL; ++ ++ g_return_if_fail (AS_IS_STORE (store)); ++ ++ locker = g_mutex_locker_new (&priv->mutex); + as_store_regen_metadata_index_key (store, key); + } + +@@ -594,7 +631,11 @@ as_store_get_app_by_id (AsStore *store, const gchar *id) + { + AsStorePrivate *priv = GET_PRIVATE (store); + GPtrArray *apps; ++ g_autoptr(GMutexLocker) locker = NULL; ++ + g_return_val_if_fail (AS_IS_STORE (store), NULL); ++ ++ locker = g_mutex_locker_new (&priv->mutex); + apps = g_hash_table_lookup (priv->hash_id, id); + if (apps == NULL) + return NULL; +@@ -641,6 +682,7 @@ as_store_get_app_by_app (AsStore *store, AsApp *app) + { + AsStorePrivate *priv = GET_PRIVATE (store); + guint i; ++ g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&priv->mutex); + + for (i = 0; i < priv->array->len; i++) { + AsApp *app_tmp = g_ptr_array_index (priv->array, i); +@@ -675,8 +717,10 @@ as_store_get_app_by_unique_id (AsStore *store, + g_return_val_if_fail (unique_id != NULL, NULL); + + /* no globs */ +- if ((search_flags & AS_STORE_SEARCH_FLAG_USE_WILDCARDS) == 0) ++ if ((search_flags & AS_STORE_SEARCH_FLAG_USE_WILDCARDS) == 0) { ++ g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&priv->mutex); + return g_hash_table_lookup (priv->hash_unique_id, unique_id); ++ } + + /* create virtual app using scope/system/origin/kind/id/branch */ + app_tmp = _as_app_new_from_unique_id (unique_id); +@@ -706,11 +750,14 @@ as_store_get_app_by_provide (AsStore *store, AsProvideKind kind, const gchar *va + guint i; + guint j; + GPtrArray *provides; ++ g_autoptr(GMutexLocker) locker = NULL; + + g_return_val_if_fail (AS_IS_STORE (store), NULL); + g_return_val_if_fail (kind != AS_PROVIDE_KIND_UNKNOWN, NULL); + g_return_val_if_fail (value != NULL, NULL); + ++ locker = g_mutex_locker_new (&priv->mutex); ++ + /* find an application that provides something */ + for (i = 0; i < priv->array->len; i++) { + app = g_ptr_array_index (priv->array, i); +@@ -744,11 +791,14 @@ AsApp * + as_store_get_app_by_launchable (AsStore *store, AsLaunchableKind kind, const gchar *value) + { + AsStorePrivate *priv = GET_PRIVATE (store); ++ g_autoptr(GMutexLocker) locker = NULL; + + g_return_val_if_fail (AS_IS_STORE (store), NULL); + g_return_val_if_fail (kind != AS_LAUNCHABLE_KIND_UNKNOWN, NULL); + g_return_val_if_fail (value != NULL, NULL); + ++ locker = g_mutex_locker_new (&priv->mutex); ++ + for (guint i = 0; i < priv->array->len; i++) { + AsApp *app = g_ptr_array_index (priv->array, i); + GPtrArray *launchables = as_app_get_launchables (app); +@@ -782,11 +832,14 @@ as_store_get_apps_by_provide (AsStore *store, AsProvideKind kind, const gchar *v + { + AsStorePrivate *priv = GET_PRIVATE (store); + GPtrArray *apps = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); ++ g_autoptr(GMutexLocker) locker = NULL; + + g_return_val_if_fail (AS_IS_STORE (store), NULL); + g_return_val_if_fail (kind != AS_PROVIDE_KIND_UNKNOWN, NULL); + g_return_val_if_fail (value != NULL, NULL); + ++ locker = g_mutex_locker_new (&priv->mutex); ++ + /* find an application that provides something */ + for (guint i = 0; i < priv->array->len; i++) { + AsApp *app = g_ptr_array_index (priv->array, i); +@@ -820,10 +873,13 @@ as_store_get_app_by_id_ignore_prefix (AsStore *store, const gchar *id) + AsApp *app; + AsStorePrivate *priv = GET_PRIVATE (store); + guint i; ++ g_autoptr(GMutexLocker) locker = NULL; + + g_return_val_if_fail (AS_IS_STORE (store), NULL); + g_return_val_if_fail (id != NULL, NULL); + ++ locker = g_mutex_locker_new (&priv->mutex); ++ + /* find an application that provides something */ + for (i = 0; i < priv->array->len; i++) { + app = g_ptr_array_index (priv->array, i); +@@ -1017,9 +1073,12 @@ as_store_get_app_by_pkgname (AsStore *store, const gchar *pkgname) + AsApp *app; + AsStorePrivate *priv = GET_PRIVATE (store); + guint i; ++ g_autoptr(GMutexLocker) locker = NULL; + + g_return_val_if_fail (AS_IS_STORE (store), NULL); + ++ locker = g_mutex_locker_new (&priv->mutex); ++ + /* in most cases, we can use the cache */ + app = g_hash_table_lookup (priv->hash_pkgname, pkgname); + if (app != NULL) +@@ -1059,6 +1118,7 @@ as_store_get_app_by_pkgnames (AsStore *store, gchar **pkgnames) + g_return_val_if_fail (pkgnames != NULL, NULL); + + for (i = 0; pkgnames[i] != NULL; i++) { ++ g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&priv->mutex); + app = g_hash_table_lookup (priv->hash_pkgname, pkgnames[i]); + if (app != NULL) + return app; +@@ -1087,6 +1147,7 @@ as_store_remove_app (AsStore *store, AsApp *app) + g_signal_emit (store, signals[SIGNAL_APP_REMOVED], 0, app); + + /* only remove this specific unique app */ ++ g_mutex_lock (&priv->mutex); + apps = g_hash_table_lookup (priv->hash_id, as_app_get_id (app)); + if (apps != NULL) { + g_ptr_array_remove (apps, app); +@@ -1100,6 +1161,7 @@ as_store_remove_app (AsStore *store, AsApp *app) + g_hash_table_remove (priv->hash_unique_id, as_app_get_unique_id (app)); + g_ptr_array_remove (priv->array, app); + g_hash_table_remove_all (priv->metadata_indexes); ++ g_mutex_unlock (&priv->mutex); + + /* removed */ + as_store_perhaps_emit_changed (store, "remove-app"); +@@ -1117,27 +1179,37 @@ as_store_remove_app (AsStore *store, AsApp *app) + void + as_store_remove_app_by_id (AsStore *store, const gchar *id) + { +- AsApp *app; + AsStorePrivate *priv = GET_PRIVATE (store); +- guint i; ++ g_autoptr(GPtrArray) apps = NULL; + + g_return_if_fail (AS_IS_STORE (store)); + +- if (!g_hash_table_remove (priv->hash_id, id)) ++ g_mutex_lock (&priv->mutex); ++ if (!g_hash_table_remove (priv->hash_id, id)) { ++ g_mutex_unlock (&priv->mutex); + return; +- for (i = 0; i < priv->array->len; i++) { +- app = g_ptr_array_index (priv->array, i); ++ } ++ g_mutex_unlock (&priv->mutex); ++ ++ apps = as_store_dup_apps (store); ++ for (guint i = 0; i < apps->len; i++) { ++ AsApp *app = g_ptr_array_index (apps, i); ++ + if (g_strcmp0 (id, as_app_get_id (app)) != 0) + continue; + + /* emit before removal */ + g_signal_emit (store, signals[SIGNAL_APP_REMOVED], 0, app); + ++ g_mutex_lock (&priv->mutex); + g_ptr_array_remove (priv->array, app); + g_hash_table_remove (priv->hash_unique_id, + as_app_get_unique_id (app)); ++ g_mutex_unlock (&priv->mutex); + } ++ g_mutex_lock (&priv->mutex); + g_hash_table_remove_all (priv->metadata_indexes); ++ g_mutex_unlock (&priv->mutex); + + /* removed */ + as_store_perhaps_emit_changed (store, "remove-app-by-id"); +@@ -1242,7 +1314,9 @@ as_store_add_app (AsStore *store, AsApp *app) + if (as_app_has_quirk (app, AS_APP_QUIRK_MATCH_ANY_PREFIX)) { + guint64 flags = AS_APP_SUBSUME_FLAG_MERGE; + AsAppMergeKind merge_kind = as_app_get_merge_kind (app); ++ g_autoptr(GPtrArray) apps_changed = NULL; + ++ g_mutex_lock (&priv->mutex); + apps = g_hash_table_lookup (priv->hash_merge_id, id); + if (apps == NULL) { + apps = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); +@@ -1254,11 +1328,16 @@ as_store_add_app (AsStore *store, AsApp *app) + as_app_merge_kind_to_string (merge_kind), + as_app_get_unique_id (app)); + g_ptr_array_add (apps, g_object_ref (app)); ++ g_mutex_unlock (&priv->mutex); + + /* apply to existing components */ + flags |= AS_APP_SUBSUME_FLAG_NO_OVERWRITE; + if (merge_kind == AS_APP_MERGE_KIND_REPLACE) + flags |= AS_APP_SUBSUME_FLAG_REPLACE; ++ ++ apps_changed = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); ++ ++ g_mutex_lock (&priv->mutex); + for (i = 0; i < priv->array->len; i++) { + AsApp *app_tmp = g_ptr_array_index (priv->array, i); + if (g_strcmp0 (as_app_get_id (app_tmp), id) != 0) +@@ -1267,7 +1346,11 @@ as_store_add_app (AsStore *store, AsApp *app) + as_app_merge_kind_to_string (merge_kind), + id, as_app_get_unique_id (app_tmp)); + as_app_subsume_full (app_tmp, app, flags); +- ++ g_ptr_array_add (apps_changed, g_object_ref (app_tmp)); ++ } ++ g_mutex_unlock (&priv->mutex); ++ for (i = 0; i < apps_changed->len; i++) { ++ AsApp *app_tmp = g_ptr_array_index (apps_changed, i); + /* emit after changes have been made */ + g_signal_emit (store, signals[SIGNAL_APP_CHANGED], + 0, app_tmp); +@@ -1276,6 +1359,7 @@ as_store_add_app (AsStore *store, AsApp *app) + } + + /* is there any merge components to add to this app */ ++ g_mutex_lock (&priv->mutex); + apps = g_hash_table_lookup (priv->hash_merge_id, id); + if (apps != NULL) { + for (i = 0; i < apps->len; i++) { +@@ -1292,14 +1376,17 @@ as_store_add_app (AsStore *store, AsApp *app) + as_app_subsume_full (app, app_tmp, flags); + } + } ++ g_mutex_unlock (&priv->mutex); + + /* find the item */ + if (priv->add_flags & AS_STORE_ADD_FLAG_USE_UNIQUE_ID) { + item = as_store_get_app_by_app (store, app); + } else { ++ g_mutex_lock (&priv->mutex); + apps = g_hash_table_lookup (priv->hash_id, id); + if (apps != NULL && apps->len > 0) + item = g_ptr_array_index (apps, 0); ++ g_mutex_unlock (&priv->mutex); + } + if (item != NULL) { + AsFormat *app_format = as_app_get_format_default (app); +@@ -1427,6 +1514,7 @@ as_store_add_app (AsStore *store, AsApp *app) + } + + /* create hash of id:[apps] if required */ ++ g_mutex_lock (&priv->mutex); + apps = g_hash_table_lookup (priv->hash_id, id); + if (apps == NULL) { + apps = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); +@@ -1448,6 +1536,7 @@ as_store_add_app (AsStore *store, AsApp *app) + g_strdup (pkgname), + g_object_ref (app)); + } ++ g_mutex_unlock (&priv->mutex); + + /* add helper objects */ + as_app_set_stemmer (app, priv->stemmer); +@@ -1495,15 +1584,16 @@ as_store_match_addons (AsStore *store) + AsStorePrivate *priv = GET_PRIVATE (store); + guint i; + g_autoptr(AsProfileTask) ptask = NULL; ++ g_autoptr(GPtrArray) apps = NULL; + + /* profile */ + ptask = as_profile_start_literal (priv->profile, "AsStore:match-addons"); + g_assert (ptask != NULL); +- for (i = 0; i < priv->array->len; i++) { +- AsApp *app = g_ptr_array_index (priv->array, i); +- if (as_app_get_kind (app) != AS_APP_KIND_ADDON) +- continue; +- as_store_match_addons_app (store, app); ++ apps = as_store_dup_apps (store); ++ for (i = 0; i < apps->len; i++) { ++ AsApp *app = g_ptr_array_index (apps, i); ++ if (as_app_get_kind (app) == AS_APP_KIND_ADDON) ++ as_store_match_addons_app (store, app); + } + } + +@@ -1858,15 +1948,15 @@ static void + as_store_remove_by_source_file (AsStore *store, const gchar *filename) + { + AsApp *app; +- GPtrArray *apps; + guint i; + const gchar *tmp; + _cleanup_uninhibit_ guint32 *tok = NULL; ++ g_autoptr(GPtrArray) apps = NULL; + g_autoptr(GPtrArray) ids = NULL; + + /* find any applications in the store with this source file */ + ids = g_ptr_array_new_with_free_func (g_free); +- apps = as_store_get_apps (store); ++ apps = as_store_dup_apps (store); + for (i = 0; i < apps->len; i++) { + AsFormat *format; + app = g_ptr_array_index (apps, i); +@@ -1909,16 +1999,21 @@ as_store_watch_source_added (AsStore *store, const gchar *filename) + if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) + return; + +- /* we helpfully saved this */ + dirname = g_path_get_dirname (filename); + g_debug ("parsing new file %s from %s", filename, dirname); ++ ++ /* we helpfully saved this */ ++ g_mutex_lock (&priv->mutex); + path_data = g_hash_table_lookup (priv->appinfo_dirs, filename); + if (path_data == NULL) + path_data = g_hash_table_lookup (priv->appinfo_dirs, dirname); + if (path_data == NULL) { + g_warning ("no path data for %s", dirname); ++ g_mutex_unlock (&priv->mutex); + return; + } ++ g_mutex_unlock (&priv->mutex); ++ + file = g_file_new_for_path (filename); + /* Do not watch the file for changes: we're already watching its + * parent directory */ +@@ -2010,7 +2105,9 @@ as_store_add_path_data (AsStore *store, + } + + /* check not already exists */ ++ g_mutex_lock (&priv->mutex); + path_data = g_hash_table_lookup (priv->appinfo_dirs, path); ++ g_mutex_unlock (&priv->mutex); + if (path_data != NULL) { + if (path_data->scope != scope || + g_strcmp0 (path_data->arch, arch) != 0) { +@@ -2033,7 +2130,9 @@ as_store_add_path_data (AsStore *store, + path_data = g_slice_new0 (AsStorePathData); + path_data->scope = scope; + path_data->arch = g_strdup (arch); ++ g_mutex_lock (&priv->mutex); + g_hash_table_insert (priv->appinfo_dirs, g_strdup (path), path_data); ++ g_mutex_unlock (&priv->mutex); + } + + static gboolean +@@ -2287,6 +2386,7 @@ as_store_check_apps_for_veto (AsStore *store) + guint i; + AsApp *app; + AsStorePrivate *priv = GET_PRIVATE (store); ++ g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&priv->mutex); + + /* add any vetos */ + for (i = 0; i < priv->array->len; i++) { +@@ -2306,27 +2406,28 @@ as_store_check_apps_for_veto (AsStore *store) + void + as_store_remove_apps_with_veto (AsStore *store) + { +- guint i; +- AsApp *app; +- AsStorePrivate *priv = GET_PRIVATE (store); + _cleanup_uninhibit_ guint32 *tok = NULL; ++ g_autoptr(GPtrArray) apps = NULL; ++ g_autoptr(GPtrArray) apps_remove = NULL; + + g_return_if_fail (AS_IS_STORE (store)); + + /* don't shortcut the list as we have to use as_store_remove_app() + * rather than just removing from the GPtrArray */ + tok = as_store_changed_inhibit (store); +- do { +- for (i = 0; i < priv->array->len; i++) { +- app = g_ptr_array_index (priv->array, i); +- if (as_app_get_vetos (app)->len > 0) { +- g_debug ("removing %s as vetoed", +- as_app_get_id (app)); +- as_store_remove_app (store, app); +- break; +- } +- } +- } while (i < priv->array->len); ++ apps = as_store_dup_apps (store); ++ apps_remove = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); ++ for (guint i = 0; i < apps->len; i++) { ++ AsApp *app = g_ptr_array_index (apps, i); ++ if (as_app_get_vetos (app)->len > 0) ++ g_ptr_array_add (apps_remove, g_object_ref (app)); ++ } ++ for (guint i = 0; i < apps_remove->len; i++) { ++ AsApp *app = g_ptr_array_index (apps_remove, i); ++ g_debug ("removing %s as vetoed", ++ as_app_get_id (app)); ++ as_store_remove_app (store, app); ++ } + as_store_changed_uninhibit (&tok); + as_store_perhaps_emit_changed (store, "remove-apps-with-veto"); + } +@@ -2379,22 +2480,28 @@ as_store_to_xml (AsStore *store, guint32 flags) + as_node_add_attribute (node_apps, "version", version); + } + +- /* sort by ID */ +- g_ptr_array_sort (priv->array, as_store_apps_sort_cb); +- + /* output is trusted, so include update_contact */ + if (g_getenv ("APPSTREAM_GLIB_OUTPUT_TRUSTED") != NULL) + output_trusted = TRUE; + +- /* add applications */ + ctx = as_node_context_new (); + as_node_context_set_version (ctx, priv->api_version); + as_node_context_set_output (ctx, AS_FORMAT_KIND_APPSTREAM); + as_node_context_set_output_trusted (ctx, output_trusted); ++ ++ g_mutex_lock (&priv->mutex); ++ ++ /* sort by ID */ ++ g_ptr_array_sort (priv->array, as_store_apps_sort_cb); ++ ++ /* add applications */ + for (i = 0; i < priv->array->len; i++) { + app = g_ptr_array_index (priv->array, i); + as_app_node_insert (app, node_apps, ctx); + } ++ ++ g_mutex_unlock (&priv->mutex); ++ + xml = as_node_to_xml (node_root, flags); + as_node_unref (node_root); + return xml; +@@ -2418,9 +2525,12 @@ as_store_convert_icons (AsStore *store, AsIconKind kind, GError **error) + AsStorePrivate *priv = GET_PRIVATE (store); + AsApp *app; + guint i; ++ g_autoptr(GMutexLocker) locker = NULL; + + g_return_val_if_fail (AS_IS_STORE (store), FALSE); + ++ locker = g_mutex_locker_new (&priv->mutex); ++ + /* convert application icons */ + for (i = 0; i < priv->array->len; i++) { + app = g_ptr_array_index (priv->array, i); +@@ -2818,8 +2928,12 @@ as_store_load_app_info (AsStore *store, + _cleanup_uninhibit_ guint32 *tok = NULL; + + /* Don't add the same dir twice, we're monitoring it for changes anyway */ +- if (g_hash_table_contains (priv->appinfo_dirs, path)) ++ g_mutex_lock (&priv->mutex); ++ if (g_hash_table_contains (priv->appinfo_dirs, path)) { ++ g_mutex_unlock (&priv->mutex); + return TRUE; ++ } ++ g_mutex_unlock (&priv->mutex); + + /* emit once when finished */ + tok = as_store_changed_inhibit (store); +@@ -3329,10 +3443,12 @@ as_store_load_search_cache (AsStore *store) + pool = g_thread_pool_new (as_store_load_search_cache_cb, + store, 4, TRUE, NULL); + g_assert (pool != NULL); ++ g_mutex_lock (&priv->mutex); + for (i = 0; i < priv->array->len; i++) { + AsApp *app = g_ptr_array_index (priv->array, i); + g_thread_pool_push (pool, app, NULL); + } ++ g_mutex_unlock (&priv->mutex); + g_thread_pool_free (pool, FALSE, TRUE); + } + +@@ -3510,6 +3626,7 @@ as_store_validate (AsStore *store, guint32 flags, GError **error) + GPtrArray *probs; + guint i; + g_autoptr(GHashTable) hash_names = NULL; ++ g_autoptr(GPtrArray) apps = NULL; + + g_return_val_if_fail (AS_IS_STORE (store), NULL); + +@@ -3546,14 +3663,15 @@ as_store_validate (AsStore *store, guint32 flags, GError **error) + g_free, (GDestroyNotify) g_object_unref); + + /* check each application */ +- for (i = 0; i < priv->array->len; i++) { ++ apps = as_store_dup_apps (store); ++ for (i = 0; i < apps->len; i++) { + AsApp *app_tmp; + AsProblem *prob; + guint j; + g_autofree gchar *app_key = NULL; + g_autoptr(GPtrArray) probs_app = NULL; + +- app = g_ptr_array_index (priv->array, i); ++ app = g_ptr_array_index (apps, i); + if (priv->api_version < 0.3) { + if (as_app_get_source_pkgname (app) != NULL) { + as_store_validate_add (probs, +@@ -3804,6 +3922,7 @@ static void + as_store_init (AsStore *store) + { + AsStorePrivate *priv = GET_PRIVATE (store); ++ g_mutex_init (&priv->mutex); + priv->profile = as_profile_new (); + priv->stemmer = as_stemmer_new (); + priv->api_version = AS_API_VERSION_NEWEST; +-- +2.19.1 + diff --git a/SOURCES/as_utils_vercmp_full.patch b/SOURCES/as_utils_vercmp_full.patch new file mode 100644 index 0000000..9d30732 --- /dev/null +++ b/SOURCES/as_utils_vercmp_full.patch @@ -0,0 +1,144 @@ +From d651281e77120ce4c7431364e4787f08189666b6 Mon Sep 17 00:00:00 2001 +From: Richard Hughes +Date: Wed, 24 Oct 2018 10:15:00 +0100 +Subject: [PATCH 1/2] Add as_utils_vercmp_full() for gnome-software + +Sometimes we don't want to do the firmware-style heuristics. +--- + libappstream-glib/as-utils.c | 42 ++++++++++++++++++++++++++++-------- + libappstream-glib/as-utils.h | 14 ++++++++++++ + 2 files changed, 47 insertions(+), 9 deletions(-) + +diff --git a/libappstream-glib/as-utils.c b/libappstream-glib/as-utils.c +index 29f1637..62d411a 100644 +--- a/libappstream-glib/as-utils.c ++++ b/libappstream-glib/as-utils.c +@@ -1388,22 +1388,23 @@ as_utils_vercmp_chunk (const gchar *str1, const gchar *str2) + } + + /** +- * as_utils_vercmp: ++ * as_utils_vercmp_full: + * @version_a: the release version, e.g. 1.2.3 + * @version_b: the release version, e.g. 1.2.3.1 ++ * @flags: some #AsVersionCompareFlag + * + * Compares version numbers for sorting. + * + * Returns: -1 if a < b, +1 if a > b, 0 if they are equal, and %G_MAXINT on error + * +- * Since: 0.3.5 ++ * Since: 0.7.14 + */ + gint +-as_utils_vercmp (const gchar *version_a, const gchar *version_b) ++as_utils_vercmp_full (const gchar *version_a, ++ const gchar *version_b, ++ AsVersionCompareFlag flags) + { + guint longest_split; +- g_autofree gchar *str_a = NULL; +- g_autofree gchar *str_b = NULL; + g_auto(GStrv) split_a = NULL; + g_auto(GStrv) split_b = NULL; + +@@ -1416,10 +1417,15 @@ as_utils_vercmp (const gchar *version_a, const gchar *version_b) + return 0; + + /* split into sections, and try to parse */ +- str_a = as_utils_version_parse (version_a); +- str_b = as_utils_version_parse (version_b); +- split_a = g_strsplit (str_a, ".", -1); +- split_b = g_strsplit (str_b, ".", -1); ++ if (flags & AS_VERSION_COMPARE_FLAG_USE_HEURISTICS) { ++ g_autofree gchar *str_a = as_utils_version_parse (version_a); ++ g_autofree gchar *str_b = as_utils_version_parse (version_b); ++ split_a = g_strsplit (str_a, ".", -1); ++ split_b = g_strsplit (str_b, ".", -1); ++ } else { ++ split_a = g_strsplit (version_a, ".", -1); ++ split_b = g_strsplit (version_b, ".", -1); ++ } + longest_split = MAX (g_strv_length (split_a), g_strv_length (split_b)); + for (guint i = 0; i < longest_split; i++) { + gchar *endptr_a = NULL; +@@ -1456,6 +1462,24 @@ as_utils_vercmp (const gchar *version_a, const gchar *version_b) + return 0; + } + ++/** ++ * as_utils_vercmp: ++ * @version_a: the release version, e.g. 1.2.3 ++ * @version_b: the release version, e.g. 1.2.3.1 ++ * ++ * Compares version numbers for sorting. ++ * ++ * Returns: -1 if a < b, +1 if a > b, 0 if they are equal, and %G_MAXINT on error ++ * ++ * Since: 0.3.5 ++ */ ++gint ++as_utils_vercmp (const gchar *version_a, const gchar *version_b) ++{ ++ return as_utils_vercmp_full (version_a, version_b, ++ AS_VERSION_COMPARE_FLAG_USE_HEURISTICS); ++} ++ + /** + * as_ptr_array_find_string: + * @array: gchar* array +diff --git a/libappstream-glib/as-utils.h b/libappstream-glib/as-utils.h +index ecb7cdd..8401df8 100644 +--- a/libappstream-glib/as-utils.h ++++ b/libappstream-glib/as-utils.h +@@ -95,6 +95,20 @@ typedef enum { + AS_VERSION_PARSE_FLAG_LAST + } AsVersionParseFlag; + ++/** ++ * AsVersionCompareFlag: ++ * @AS_VERSION_COMPARE_FLAG_NONE: No flags set ++ * @AS_VERSION_COMPARE_FLAG_USE_HEURISTICS: Use a heuristic to parse version numbers ++ * ++ * The flags used when comparing version numbers. ++ **/ ++typedef enum { ++ AS_VERSION_COMPARE_FLAG_NONE = 0, ++ AS_VERSION_COMPARE_FLAG_USE_HEURISTICS = 1 << 0, ++ /*< private >*/ ++ AS_VERSION_COMPARE_FLAG_LAST ++} AsVersionCompareFlag; ++ + /** + * AsUniqueIdMatchFlags: + * @AS_UNIQUE_ID_MATCH_FLAG_NONE: No flags set +-- +2.19.1 + + +From d8f67b1a9be9707c04ed4f1f71eb5365c09c275d Mon Sep 17 00:00:00 2001 +From: Kalev Lember +Date: Wed, 24 Oct 2018 11:45:56 +0200 +Subject: [PATCH 2/2] trivial: Add missing prototype for as_utils_vercmp_full + +--- + libappstream-glib/as-utils.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/libappstream-glib/as-utils.h b/libappstream-glib/as-utils.h +index 8401df8..2fa5199 100644 +--- a/libappstream-glib/as-utils.h ++++ b/libappstream-glib/as-utils.h +@@ -160,6 +160,9 @@ gboolean as_utils_install_filename (AsUtilsLocation location, + GError **error); + gboolean as_utils_search_token_valid (const gchar *token); + gchar **as_utils_search_tokenize (const gchar *search); ++gint as_utils_vercmp_full (const gchar *version_a, ++ const gchar *version_b, ++ AsVersionCompareFlag flags); + gint as_utils_vercmp (const gchar *version_a, + const gchar *version_b); + gboolean as_utils_guid_is_valid (const gchar *guid); +-- +2.19.1 + diff --git a/SPECS/libappstream-glib.spec b/SPECS/libappstream-glib.spec new file mode 100644 index 0000000..2901008 --- /dev/null +++ b/SPECS/libappstream-glib.spec @@ -0,0 +1,797 @@ +%global glib2_version 2.45.8 +%global libsoup_version 2.51.92 +%global json_glib_version 1.1.1 +%global gdk_pixbuf_version 2.31.5 + +Summary: Library for AppStream metadata +Name: libappstream-glib +Version: 0.7.14 +Release: 3%{?dist} +License: LGPLv2+ +URL: http://people.freedesktop.org/~hughsient/appstream-glib/ +Source0: http://people.freedesktop.org/~hughsient/appstream-glib/releases/appstream-glib-%{version}.tar.xz +# Backported from upstream +Patch0: as_utils_vercmp_full.patch +Patch1: as-store-locking.patch + +BuildRequires: glib2-devel >= %{glib2_version} +BuildRequires: docbook-utils +BuildRequires: gtk-doc +BuildRequires: gobject-introspection-devel +BuildRequires: gperf +BuildRequires: libarchive-devel +BuildRequires: libsoup-devel >= %{libsoup_version} +BuildRequires: gdk-pixbuf2-devel >= %{gdk_pixbuf_version} +BuildRequires: gtk3-devel +BuildRequires: gettext +BuildRequires: libuuid-devel +BuildRequires: libstemmer-devel +BuildRequires: json-glib-devel >= %{json_glib_version} +BuildRequires: meson + +# for the builder component +BuildRequires: fontconfig-devel +BuildRequires: freetype-devel +BuildRequires: pango-devel +BuildRequires: rpm-devel +BuildRequires: sqlite-devel + +# for the manpages +BuildRequires: libxslt +BuildRequires: docbook-style-xsl + +# Make sure we pull in the minimum required versions +Requires: gdk-pixbuf2%{?_isa} >= %{gdk_pixbuf_version} +Requires: glib2%{?_isa} >= %{glib2_version} +Requires: json-glib%{?_isa} >= %{json_glib_version} +Requires: libsoup%{?_isa} >= %{libsoup_version} + +# no longer required +Obsoletes: appdata-tools < 0.1.9 +Provides: appdata-tools + +# this is not a library version +%define as_plugin_version 5 + +%description +This library provides GObjects and helper methods to make it easy to read and +write AppStream metadata. It also provides a simple DOM implementation that +makes it easy to edit nodes and convert to and from the standardized XML +representation. + +%package devel +Summary: GLib Libraries and headers for appstream-glib +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description devel +GLib headers and libraries for appstream-glib. + +%package builder +Summary: Library and command line tools for building AppStream metadata +Requires: %{name}%{?_isa} = %{version}-%{release} +Recommends: pngquant + +%description builder +This library and command line tool is used for building AppStream metadata +from a directory of packages. + +%package builder-devel +Summary: GLib Libraries and headers for appstream-builder +Requires: %{name}-builder%{?_isa} = %{version}-%{release} + +%description builder-devel +GLib headers and libraries for appstream-builder. + +%prep +%autosetup -p1 -n appstream-glib-%{version} + +%build +%meson \ + -Dgtk-doc=true \ + -Dstemmer=true \ + -Ddep11=false +%meson_build + +%install +%meson_install + +%find_lang appstream-glib + +%ldconfig_scriptlets +%ldconfig_scriptlets builder + +%files -f appstream-glib.lang +%license COPYING +%doc README.md AUTHORS NEWS +%{_libdir}/libappstream-glib.so.8* +%{_libdir}/girepository-1.0/*.typelib +%{_bindir}/appstream-util +%{_bindir}/appstream-compose +%dir %{_datadir}/bash-completion/completions/ +%{_datadir}/bash-completion/completions/appstream-util +%{_mandir}/man1/appstream-util.1.gz +%{_mandir}/man1/appstream-compose.1.gz + +%files devel +%{_libdir}/libappstream-glib.so +%{_libdir}/pkgconfig/appstream-glib.pc +%dir %{_includedir}/libappstream-glib +%{_includedir}/libappstream-glib/*.h +%{_datadir}/gtk-doc/html/appstream-glib +%{_datadir}/gir-1.0/AppStreamGlib-1.0.gir +%{_datadir}/aclocal/*.m4 +%{_datadir}/installed-tests/appstream-glib/*.test +%{_datadir}/gettext/its/appdata.its +%{_datadir}/gettext/its/appdata.loc + +%files builder +%license COPYING +%{_bindir}/appstream-builder +%{_datadir}/bash-completion/completions/appstream-builder +%{_libdir}/asb-plugins-%{as_plugin_version}/libasb_plugin_appdata.so +%{_libdir}/asb-plugins-%{as_plugin_version}/libasb_plugin_desktop.so +%{_libdir}/asb-plugins-%{as_plugin_version}/libasb_plugin_font.so +%{_libdir}/asb-plugins-%{as_plugin_version}/libasb_plugin_gettext.so +%{_libdir}/asb-plugins-%{as_plugin_version}/libasb_plugin_hardcoded.so +%{_libdir}/asb-plugins-%{as_plugin_version}/libasb_plugin_icon.so +%{_libdir}/asb-plugins-%{as_plugin_version}/libasb_plugin_shell_extension.so +%{_libdir}/libappstream-builder.so.8* +%{_mandir}/man1/appstream-builder.1.gz + +%files builder-devel +%license COPYING +%{_libdir}/libappstream-builder.so +%{_libdir}/pkgconfig/appstream-builder.pc +%dir %{_includedir}/libappstream-builder +%{_includedir}/libappstream-builder/*.h +%{_datadir}/gir-1.0/AppStreamBuilder-1.0.gir + +%changelog +* Tue Dec 18 2018 Kalev Lember 0.7.14-3 +- Backport AsStore locking patches from upstream + +* Wed Oct 24 2018 Kalev Lember 0.7.14-2 +- Add new as_utils_vercmp_full() API for gnome-software + +* Tue Oct 16 2018 Richard Hughes 0.7.14-1 +- New upstream release +- Add new API for gnome-software +- Set the AppStream ID from the X-Flatpak desktop key + +* Fri Sep 28 2018 Richard Hughes 0.7.13-1 +- New upstream release +- Do not restrict the maximum number of releases allowed +- Throw an error when a launchable desktop-id is invalid + +* Mon Aug 13 2018 Richard Hughes 0.7.12-1 +- New upstream release +- Support localised text in agreement sections + +* Thu Aug 09 2018 Richard Hughes 0.7.11-1 +- New upstream release +- Add AS_APP_QUIRK_DEVELOPER_VERIFIED +- Escape quotes in attributes +- Provide async variants of store load functions + +* Fri Jul 13 2018 Fedora Release Engineering - 0.7.10-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Wed Jul 11 2018 Richard Hughes 0.7.10-1 +- New upstream release +- Do not parse firmware files anymore +- Do not require a release transaction when validating in relaxed mode +- Extract release descriptions and agreement sections for translation + +* Mon Jun 04 2018 Richard Hughes 0.7.9-1 +- New upstream release +- Convert local icons found in metainfo files +- Follow the Debian tilde usage when ordering versions +- Use the launchable to find the desktop filename + +* Fri Apr 20 2018 Richard Hughes 0.7.8-1 +- New upstream release +- Add as_version_string() for fwupd +- Add support for component agreements +- Correctly compare version numbers like '1.2.3' and '1.2.3a' +- Don't include the path component in the name when parsing the package filename +- If the launchable is specified don't guess it when composing +- Never add more than one component to the AppStream store when composing + +* Tue Apr 17 2018 Kalev Lember 0.7.7-3 +- Veto apps that have empty OnlyShowIn= (#1568492) + +* Thu Mar 15 2018 Kalev Lember 0.7.7-2 +- Backport a patch to add as_utils_unique_id_match() + +* Tue Mar 13 2018 Richard Hughes 0.7.7-1 +- New upstream release +- Add custom metadata key for shell extension uuid +- Always resize AppStream icons to fit the destination size +- Correctly validate files using OR in the metadata_license +- Do not fail to validate if the timestamps are out of order +- Don't abort the build if pngquant fails +- Update the SPDX license list to v3.0 + +* Fri Feb 09 2018 Richard Hughes 0.7.6-1 +- New upstream release +- Add support for release types + +* Wed Feb 07 2018 Fedora Release Engineering - 0.7.5-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Fri Feb 02 2018 Igor Gnatenko - 0.7.5-4 +- Switch to %%ldconfig_scriptlets + +* Tue Jan 30 2018 Richard Hughes 0.7.5-3 +- Backport a fix from master to fix XML generation. + +* Wed Jan 24 2018 Richard Hughes 0.7.5-2 +- Backport two crash fixes from master. + +* Mon Jan 22 2018 Richard Hughes 0.7.5-1 +- New upstream release +- Add more GObject Introspection annotations for Python +- Do not try to extract duplicate files in the icon theme packages +- Don't expect an enum when really passing a bitfield +- Fix a crash when calling as_release_add_location() directly +- Fix appstream-compose when using new-style desktop IDs +- Fix compile with GCab v1.0 +- Fix the arithmetic when fitting an image in 16:9 +- Generate icons and samples for emoji fonts +- Never change the default screenshot when processing AppData +- Support OARS v1.1 additions +- Use pngquant to make the application icons take up less space + +* Thu Nov 09 2017 Kalev Lember 0.7.4-1 +- Update to 0.7.4 + +* Mon Oct 23 2017 Richard Hughes 0.7.3-1 +- New upstream release +- Add new API required by fwupd +- Do not assign "flatpak" as an app's origin when no origin was found +- Fix the inode mode to be sane on extracted files +- Prefer /usr/share/metainfo as default path for metainfo files +- Write XML for newer AppStream specification versions + +* Mon Aug 21 2017 Richard Hughes 0.7.2-1 +- New upstream release +- Allow remote icon types for desktop AppData files +- Do not check the suffix of tags +- Prefer /usr/share/metainfo as default path for metainfo files + +* Fri Aug 11 2017 Igor Gnatenko - 0.7.1-4 +- Rebuilt after RPM update (№ 3) + +* Thu Aug 10 2017 Igor Gnatenko - 0.7.1-3 +- Rebuilt for RPM soname bump + +* Thu Aug 10 2017 Igor Gnatenko - 0.7.1-2 +- Rebuilt for RPM soname bump + +* Thu Aug 03 2017 Richard Hughes 0.7.1-1 +- New upstream release +- Add kinds for application provides +- Fail to validate if AppData screenshots are duplicated +- Install appdata-xml.m4 +- Skip loading desktop data from Snap directory +- Update the SPDX license list to 2.6 +- Validate the format according to the spec + +* Thu Aug 03 2017 Fedora Release Engineering - 0.7.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 0.7.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Thu Jun 22 2017 Richard Hughes 0.7.0-1 +- New upstream release +- Add the limits in the validation output messages +- Do not enforce that the project is a valid environment_id +- Don't cast gsize to guint32 when getting file length +- Remove the cache-id functionality +- Show a warning if adding keywords after the cache creation +- Switch to the meson build system + +* Mon May 08 2017 Richard Hughes 0.6.13-1 +- New upstream release +- Add a 'check-component' command to appstream-util +- Add new API for gnome-software and fwupd +- Add support for icon scaling and +- Allow using the app origin as a search keyword +- Casefold all stemmed entries +- Support non-numeric version numbers correctly + +* Wed Apr 12 2017 Richard Hughes 0.6.12-1 +- New upstream release +- Validate kudos in AppData and AppStream files +- Copy hash table keys to avoid a common crash on Ubuntu +- Fix the predicate comparison when using globs in metainfo files + +* Mon Mar 20 2017 Richard Hughes 0.6.11-1 +- New upstream release +- Add initial support for Mozilla .xpi translations +- Fix a problem with appstream-compose with older AppData files +- Make content_rating required for any component with a 'Game' category +- Parse small version numbers correctly +- Show a warning if a desktop file is not found when required + +* Mon Mar 06 2017 Richard Hughes 0.6.10-1 +- New upstream release +- Fix small unintentional ABI break +- Ignore

in AppStream markup + +* Mon Feb 27 2017 Richard Hughes 0.6.9-1 +- New upstream release +- Do not set the AsApp state using the AsRelease state +- Fail to validate if any release is in the future or in the wrong order + +* Fri Feb 10 2017 Fedora Release Engineering - 0.6.8-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Fri Feb 03 2017 Kalev Lember 0.6.8-2 +- Backport a patch for overly strict appstream-util validate-relax + +* Thu Feb 02 2017 Kalev Lember 0.6.8-1 +- New upstream release + +* Fri Jan 27 2017 Kalev Lember 0.6.7-3 +- Backport two use-after-free fixes from upstream + +* Mon Jan 16 2017 Kalev Lember 0.6.7-2 +- Fix epiphany showing up twice in gnome-software + +* Thu Jan 12 2017 Richard Hughes 0.6.7-1 +- New upstream release +- Add AsRequire as a way to store runtime requirements +- Add support for "+" at the end of SPDX license identifiers +- Allow loading application XPM icons +- Fix a crash when using as_release_get_location_default() +- Fix dep extraction when multiple versions are available +- Only fail to validate in AppData desktop components +- Scan /usr/share/metainfo as well when building appstream-data +- Update the SPDX licence list to v2.5 + +* Thu Dec 15 2016 Richard Hughes 0.6.6-1 +- New upstream release +- Add Geary to the app id fallbacks +- Deduplicate the AsNode attribute key and value using a hash table +- Detect invalid files in the libyaml read handler +- Do not absorb core addons into the main application +- Do not add , , or for addons +- Do not save the attributes if the node or parent node is ignored +- Set a better icon for codecs + +* Mon Nov 07 2016 Richard Hughes 0.6.5-1 +- New upstream release +- Add app-removed, app-added and app-changed signals to AsStore +- Add a 'watch' command to appstream-util +- Allow only loading native languages when parsing AppStream +- Allow the client to control what search fields are indexed +- Always copy the state when replacing AppData with AppStream +- Do not sent a REMOVED signal when deleting a transient temp file +- Ensure the component scope is set when loading yaml files +- Handle files being moved into monitored AppStream directories +- Load the search token blacklist into a hash table +- Monitor missing AppStream directories +- Only transliterate when the locale requires it +- Process file changes when an attribute changes + +* Wed Oct 12 2016 Richard Hughes 0.6.4-1 +- New upstream release +- Add more API used by gnome-software master branch +- Add support for AppImage bundles +- Don't show a critical warning on invalid yaml file +- Fix a small memory leak when parsing yaml files +- Fix building metadata on repos with mixed architecture content +- Fix setting the origin for Flatpak user repos +- Fix the CSM rating age calculation +- Never inhierit Name and Comment when using appstream-compose + +* Tue Sep 06 2016 Richard Hughes 0.6.3-1 +- New upstream release +- Add a component kind of 'driver' +- Add an easy way to add a language to an existing file +- Add an easy way to add a modalias to an existing file +- Support components with merge=replace rules + +* Mon Aug 29 2016 Richard Hughes 0.6.2-1 +- New upstream release +- Add API for gnome-software +- Do not merge all LangPack entries +- Do not require an icon from LOCALIZATION kind +- Do not use the prefix check when parsing YAML +- Ignore system datadirs that are actually per-user +- Invalidate the unique-id if any of the parts are changed +- Make upgrade check for SPDX license string +- Pay attention to errors from libyaml + +* Wed Aug 17 2016 Kalev Lember 0.6.1-2 +- Fix gcc shift warnings on 32 bit platforms + +* Fri Aug 12 2016 Richard Hughes 0.6.1-1 +- New upstream release +- Add new API for latest AppStream specification level +- Add some more validation checks for keywords +- Add support for AppStream merge components +- Add support for Google .PAK files +- Allow multiple components with the same ID in the AsStore +- Convert all current component-type names +- Do not save the 'X-' prefixed keys to the AppStream metadata +- Ensure predictable output order of XML attributes +- Port away from intltool +- Remove specific support for flatpak +- Restrict addons to the same scope and bundle kind + +* Wed Aug 10 2016 Richard Hughes 0.5.18-1 +- New upstream release +- Add Sugar as a valid desktop environment +- Add the translate URL kind +- Do not split up the main AudioVideo category +- Don't redundantly monitor files +- No validation failure for lots of releases + +* Wed Jul 13 2016 Richard Hughes 0.5.17-1 +- New upstream release +- Add external (X-*) keys of an app's desktop file as metadata AsApp +- Correct disabling of timestamps for gzip +- Do not add multiple categories for apps with AudioVideo +- Do not emit a warning when flatpak user directory doesn't exist +- Fall back to the country code in as_app_get_language() +- Use libstemmer for keyword stemming + +* Fri Jul 01 2016 Kalev Lember 0.5.16-2 +- Set minimum required versions for dependencies + +* Mon Jun 13 2016 Richard Hughes 0.5.16-1 +- New upstream release +- Add elementary to list of project groups +- Allow setting the id prefix and origin using a symlink name +- Correctly detect new AppStream apps in new directories +- Do not rename a category ID in AsApp +- Load metainfo files if present +- Never allow NULL to be added to AsApp string array + +* Mon May 23 2016 Richard Hughes 0.5.15-1 +- New upstream release +- Add all applications for all architectures when loading Flatpak apps +- Add new API for gnome-software +- Ignore files with invalid suffixes when building installed stores +- Omit timestamp from gzip compressed files +- Rename the xdg-app support to the new name: Flatpak +- Sort archive contents by name for repeatable results + +* Wed Apr 20 2016 Richard Hughes 0.5.14-1 +- New upstream release +- Add new API for gnome-software 3.21 +- Add search-pkgname to appstream-cmd +- Fall back to searching in as_store_get_app_by_pkgname() +- Ignore desktop files with X-AppStream-Ignore +- Search /usr/share/metainfo for local files + +* Fri Apr 01 2016 Richard Hughes 0.5.13-1 +- New upstream release +- Enforce the requirement of AppData for 'Categories=DesktopSettings' +- Also filter YAML apps before adding to the store +- Always veto anything with X-Unity-Settings-Panel +- Do not hardcode x86_64 when searching for xdg-app metadata +- Support more DEP11 YAML markup + +* Tue Mar 29 2016 Richard Hughes 0.5.12-1 +- New upstream release +- Add a merge-appstream command to appstream-util +- Add new API required for GNOME Software +- Add support for content ratings +- Split up AudioVideo into two categories + +* Mon Mar 14 2016 Richard Hughes - 0.5.11-2 +- Rebuild to fix NVRs + +* Tue Mar 08 2016 Richard Hughes 0.5.11-1 +- New upstream release +- Add new API for gnome-software +- Fix token splitting for searching + +* Fri Feb 26 2016 Richard Hughes 0.5.10-1 +- New upstream release +- Add an application prefix to the ID for certain install scopes +- Add a 'split-appstream' command to appstream-util +- Add support for getting the SDK and runtime from the bundle +- Improve the application search tokenizing and filtering +- Load AppStream stores in a predictable order + +* Fri Feb 12 2016 Richard Hughes 0.5.9-1 +- New upstream release +- Accept FSFAP as a valid metadata license +- Fix a validation error for metainfo files with descriptions +- Pick up newly added appinfo dirs for xdg-app remotes +- Update the SPDX license list + +* Tue Feb 02 2016 Richard Hughes 0.5.8-1 +- New upstream release +- Add a modify command to appstream-util +- Add support for per-user and system-wide xdg-app installed stores +- Reject an invalid project group when parsing +- Support multi-line copyright statements +- Support the QT translation system +- Support tags in AppData files + +* Fri Jan 15 2016 Richard Hughes 0.5.6-1 +- New upstream release +- Accept various 'or later' metadata content licenses +- Check the project_group when validating +- Cull the application blacklist now we depend on AppData files +- Fix things up for xdg-app use +- Install gettext ITS rules + +* Wed Dec 16 2015 Richard Hughes 0.5.5-1 +- New upstream release +- Add as_utils_license_to_spdx() +- Add the package name as another application search token +- Fix a crash when tokenizing a NULL string +- Log when we auto-add kudos or keywords +- Support live updates + +* Wed Nov 18 2015 Richard Hughes 0.5.4-1 +- New upstream release +- Add as_utils_version_from_uint16() +- Generate GUID values according to RFC4122 + +* Thu Nov 05 2015 Richard Hughes 0.5.3-1 +- New upstream release +- Return the correct error when the desktop file has no group +- Strip Win32 and Linux paths when decompressing firmware + +* Tue Oct 27 2015 Richard Hughes 0.5.2-1 +- New upstream release +- Accept a '0x' hexidecimal prefix when parsing a version +- Add multi-guid cabinet firmware support +- Add support for AppStream metadata +- Fix crash in validator when processing '
  • ' +- Remove the long-obsolete appdata-validate tool +- Require AppData files to be present in the AppStream metadata +- Use g_set_object() to fix potential crash when adding pixbufs + +* Thu Oct 15 2015 Kalev Lember 0.5.1-2 +- Backport a patch to fix icons in gnome-software for apps without AppData +- Use license macro for COPYING + +* Tue Sep 15 2015 Richard Hughes 0.5.1-1 +- New upstream release +- Add a few applications that have changed desktop ID +- Add support for release urgency +- Do not blacklist the 'desktop' token +- Don't show mangled version numbers as negatives +- Ignore empty AppStream XML files +- Support SPDX IDs with the LicenseRef prefix + +* Sat Sep 05 2015 Kalev Lember - 0.5.0-2 +- Rebuilt for librpm soname bump + +* Wed Aug 12 2015 Richard Hughes 0.5.0-1 +- New upstream release +- Add support for the flashed firmware provide kind +- Make the DriverVer in the .inf file optional +- Show a better error message when there's not enough text + +* Wed Jul 29 2015 Zbigniew Jędrzejewski-Szmek - 0.4.1-2 +- Rebuilt for rpm 4.12.90 + +* Mon Jul 20 2015 Richard Hughes 0.4.1-1 +- New upstream release +- Add am 'incorporate' command to appstream-util +- Add a 'mirror-local-firmware' and 'compare' commands to appstream-util +- Add extra flags for use when building metadata +- Be less strict when loading incorrect AppData files +- Do not duplicate tags within a release +- Do not expect the INF ClassGuid to be the ESRT GUID +- Don't crash when parsing a with no description +- Update the SPDX licence list to v2.0 + +* Wed Jun 17 2015 Fedora Release Engineering - 0.4.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Tue May 26 2015 Richard Hughes 0.4.0-1 +- New upstream release +- Add a mirror-screenshots command to appstream-util +- Check for duplicate screenshots when adding fonts +- Detect recolorable symbolic icons +- Fix a crash for an invalid AppData file +- Remove all networking support when building metadata +- Remove overzealous blacklisting entry + +* Wed Apr 29 2015 Kalev Lember 0.3.6-2 +- Fix exo-web-browser blacklist entry (#1216218) + +* Mon Mar 30 2015 Richard Hughes 0.3.6-1 +- New upstream release +- Add a 'replace-screenshots' command to appstream-util +- Always upscale screenshots if they are too small +- Assume the INF DriverVer is UTC +- Remove the gtk3 dep from libappstream-glib +- Use the correct image URL for HiDPI screenshots + +* Wed Mar 11 2015 Richard Hughes 0.3.5-1 +- New upstream release +- Add new API required for firmware support +- Add new API required for OSTree and xdg-app support + +* Sat Jan 17 2015 Richard Hughes 0.3.4-1 +- New upstream release +- Add more applications to the blacklist +- Add show-search-tokens subcommand to appstream-util +- Add some new API for gnome-software to use +- Add the matrix-html subcommand to appstream-util +- Add the VCS information to the AppStream metadata +- Assume foo is a source image kind for AppData files +- Assume that stock icons are available in HiDPI sizes +- Blacklist the 40 most common search tokens +- Check if the search entries are valid before searching +- Check screenshots are a reasonable size +- Fall back to the dumb tokenizer for keywords with special chars +- Set an error if an XML file contains font markup +- Show the offending text when validation fails + +* Mon Nov 24 2014 Richard Hughes 0.3.3-1 +- New upstream release +- Allow filtering addons in the status html pages +- Detect missing parents in the old metadata +- Do not fail to load all the desktop files if one is bad +- Improve appdata-xml.m4 deprecation notice + +* Tue Nov 04 2014 Richard Hughes 0.3.2-1 +- New upstream release +- Add a simple 'search' command to appstream-util +- Add some more valid metadata licenses +- Do not generate metadata with an icon prefix +- Obsolete the appdata-tools package +- Show the kudo stats on the status page + +* Tue Oct 21 2014 Richard Hughes 0.3.1-1 +- New upstream release +- Add an --enable-hidpi argument to appstream-builder +- Add AS_ICON_KIND_EMBEDDED and AS_ICON_KIND_LOCAL +- Add more applications to the blacklist +- Allow application with NoDisplay=true and an AppData file +- Allow AppStream files to be upgraded using appstream-util +- Install AppStream files with correct permissions +- Monitor the XML and icons path for changes +- Relax validation requirements for font metainfo files + +* Mon Sep 01 2014 Richard Hughes 0.3.0-1 +- New upstream release +- Add a new kudo for high contrast icons +- A keyword search match is better than the project name +- Allow desktop->addon demotion with an AppData file +- Allow translated keywords +- Conform to the actual SPDX 2.0 license expression syntax +- Ignore AppData screenshots with xml:lang attributes +- Metadata licenses like 'CC0 and CC-BY-3.0' are content licenses +- Update the SPDX license list to v1.20 + +* Mon Aug 18 2014 Richard Hughes 0.2.5-1 +- New upstream release +- Add check-root to appstream-util +- Add some validation rules for metainfo files +- Allow desktop->addon demotion with an AppData file +- Allow different source roots to define addons +- Do not require sentence case when validating with relaxed settings +- Fix up legacy license IDs when tokenizing +- Metadata licenses like 'CC0 and CC-BY-3.0' are valid content licenses +- Never add duplicate tags + +* Sun Aug 17 2014 Fedora Release Engineering - 0.2.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Tue Aug 05 2014 Richard Hughes 0.2.4-1 +- New upstream release +- Add an installed tests to validate appdata +- Add support for which will be in AppStream 0.8 +- Add the provide for applications automatically +- Do not load applications with NoDisplay=true when loading local +- Do not pad the compressed AppStream metadata with NUL bytes +- Do not treat app-install metadata as installed +- Markup errors should not be fatal when assembling a store + +* Tue Jul 22 2014 Kalev Lember - 0.2.3-2 +- Rebuilt for gobject-introspection 1.41.4 + +* Thu Jul 17 2014 Richard Hughes 0.2.3-1 +- New upstream release +- Add oxygen-icon-theme when an application depends on kde-runtime +- Add some simple filtering in the status.html page +- Be more careful with untrusted XML data +- Do not allow duplicates to be added when using as_app_add_kudo_kind() +- Do not fail to build packages with invalid KDE service files +- Record if distro metadata and screenshots are being used +- Show any package duplicates when generating metadata +- Show the builder progress in a ncurses-style panel + +* Fri Jul 11 2014 Richard Hughes 0.2.2-1 +- New upstream release +- Add two new builder plugins to add kudos on KDE applications +- Assume local files are untrusted when parsing +- Do not allow NoDisplay=true applications to ever be in the metadata +- Never scale up small screenshots +- Never upscale icons, either pad or downscale with sharpening +- Sharpen resized screenshots after resizing with a cubic interpolation +- Write metadata of the failed applications + +* Tue Jun 24 2014 Richard Hughes 0.2.1-1 +- New upstream release +- Add an 'appstream-util upgrade' command to convert version < 0.6 metadata +- Add packages recursively when using appstream-builder --packages-dir +- Allow empty URL sections +- Fix the xmldir in the APPSTREAM_XML_RULES m4 helper + +* Thu Jun 19 2014 Richard Hughes 0.2.0-1 +- New upstream release +- Accept slightly truncated SPDX IDs +- Allow any SPDX license when validating in relaxed mode +- Allow as_node_get_attribute_as_int() to parse negative numbers +- Allow dumping .desktop, .appdata.xml and .metainfo.xml files in appstream-util +- Do not add addons that are packaged in the parent package +- Do not require a content license to be included into the metadata +- This is the first release that merges the createrepo_as project. +- Validate the tag values + +* Thu Jun 12 2014 Richard Hughes 0.1.7-1 +- New upstream release +- Add from the draft AppStream 0.7 specification +- Add support for the 'dbus' AsProvideKind +- Add support for validating metainfo.xml files +- Allow 'appstream-util validate' to validate multiple files +- Do not log a critical warning in as_store_to_xml() +- Fix a crash when we try to validate

    +- Support the non-standard X-Ubuntu-Software-Center-Name + +* Sat Jun 07 2014 Fedora Release Engineering - 0.1.6-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Wed May 28 2014 Richard Hughes 0.1.6-1 +- New upstream release +- Add some more API for createrepo_as and gnome-software +- Also support validating .appdata.xml.in files +- Correctly parse the localized descriptions from AppData files +- Fix validation of old-style AppData files without screenshot sizes +- Only autodetect the AsAppSourceKind when unknown +- Only require when being strict +- Only show the thumbnail when creating the HTML status page +- Retain comments in .desktop and .appdata.xml files when required + +* Mon May 12 2014 Richard Hughes 0.1.5-1 +- New upstream release +- Add some more API for createrepo_as and gnome-software +- Be less strict with the case of the XML header +- Check the licenses against the SPDX list when validating +- Support AppData version 0.6 files too + +* Fri Apr 25 2014 Richard Hughes 0.1.4-1 +- New upstream release +- Add some more API for createrepo_as and gnome-software +- Add tool appstream-util + +* Thu Apr 10 2014 Richard Hughes 0.1.3-1 +- New upstream release +- Add new API required by gnome-software +- Ignore settings panels when parsing desktop files +- Load AppStream files assuming literal text strings + +* Wed Mar 26 2014 Richard Hughes 0.1.2-1 +- New upstream release +- Add more API for gnome-software to use +- Reduce the number of small attr key allocations +- Use gperf to generate a perfect hash for the tag names +- Use the full ID for the AsStore hash + +* Fri Mar 21 2014 Richard Hughes 0.1.1-1 +- New upstream release +- Add an 'api-version' property to AsStore +- Add the new AsUrlKind's and from API 0.6 +- Support old-style markup-less tags +- Support the 'origin' attribute on the root node +- Do not crash when using getting an unset description +- Do not depend on functions introduced in Glib 2.39.1 +- Fix parsing incompletely translated AppData files + +* Tue Mar 18 2014 Richard Hughes 0.1.0-1 +- First upstream release