Compare commits

..

No commits in common. 'c9' and 'c8' have entirely different histories.
c9 ... c8

2
.gitignore vendored

@ -1 +1 @@
SOURCES/appstream-glib-0.7.18.tar.xz
SOURCES/appstream-glib-0.7.14.tar.xz

@ -1 +1 @@
f01aa02454db76f5907b1d4e65d1f07944df28a9 SOURCES/appstream-glib-0.7.18.tar.xz
de3efb3940cf32dd178340da46c7cb1b3b304562 SOURCES/appstream-glib-0.7.14.tar.xz

@ -1,243 +0,0 @@
diff -Nru appstream-glib-0.7.18/libappstream-glib/as-node.c appstream-glib-0.7.18/libappstream-glib/as-node.c
--- appstream-glib-0.7.18/libappstream-glib/as-node.c 2020-09-07 11:20:43.894573000 +0100
+++ appstream-glib-0.7.18/libappstream-glib/as-node.c 2023-06-07 20:58:11.000000000 +0100
@@ -555,6 +555,8 @@
AsNode *current;
AsNodeFromXmlFlags flags;
const gchar * const *locales;
+ guint8 is_em_text:1;
+ guint8 is_code_text:1;
} AsNodeToXmlHelper;
/**
@@ -604,6 +606,16 @@
AsNode *current;
guint i;
+ /* do not create a child node for em and code tags */
+ if (g_strcmp0 (element_name, "em") == 0) {
+ helper->is_em_text = 1;
+ return;
+ }
+ if (g_strcmp0 (element_name, "code") == 0) {
+ helper->is_code_text = 1;
+ return;
+ }
+
/* check if we should ignore the locale */
data = g_slice_new0 (AsNodeData);
@@ -662,6 +674,53 @@
GError **error)
{
AsNodeToXmlHelper *helper = (AsNodeToXmlHelper *) user_data;
+ AsNodeData *data = helper->current->data;
+
+ /* do not create a child node for em and code tags */
+ if (g_strcmp0 (element_name, "em") == 0) {
+ helper->is_em_text = 0;
+ return;
+ }
+ if (g_strcmp0 (element_name, "code") == 0) {
+ helper->is_code_text = 0;
+ return;
+ }
+
+ if (data->cdata != NULL) {
+ /* split up into lines and add each with spaces stripped */
+ if ((helper->flags & AS_NODE_FROM_XML_FLAG_LITERAL_TEXT) == 0) {
+ AsRefString *cdata = data->cdata;
+ data->cdata = as_node_reflow_text (cdata, strlen (cdata));
+ as_ref_string_unref (cdata);
+ }
+
+ /* intern commonly duplicated tag values and save a bit of memory */
+ if (data->is_tag_valid) {
+ AsNode *root = g_node_get_root (helper->current);
+ switch (data->tag) {
+ case AS_TAG_CATEGORY:
+ case AS_TAG_COMPULSORY_FOR_DESKTOP:
+ case AS_TAG_CONTENT_ATTRIBUTE:
+ case AS_TAG_DEVELOPER_NAME:
+ case AS_TAG_EXTENDS:
+ case AS_TAG_ICON:
+ case AS_TAG_ID:
+ case AS_TAG_KUDO:
+ case AS_TAG_LANG:
+ case AS_TAG_METADATA_LICENSE:
+ case AS_TAG_MIMETYPE:
+ case AS_TAG_PROJECT_GROUP:
+ case AS_TAG_PROJECT_LICENSE:
+ case AS_TAG_SOURCE_PKGNAME:
+ case AS_TAG_URL:
+ as_node_cdata_to_intern (root, data);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
helper->current = helper->current->parent;
}
@@ -693,8 +752,9 @@
if (i >= text_len)
return;
- /* split up into lines and add each with spaces stripped */
- if (data->cdata != NULL) {
+ if (data->cdata != NULL &&
+ g_strcmp0 (as_tag_data_get_name (data), "p") != 0 &&
+ g_strcmp0 (as_tag_data_get_name (data), "li") != 0) {
g_set_error (error,
AS_NODE_ERROR,
AS_NODE_ERROR_INVALID_MARKUP,
@@ -703,37 +763,33 @@
data->cdata, text);
return;
}
- if ((helper->flags & AS_NODE_FROM_XML_FLAG_LITERAL_TEXT) > 0) {
- data->cdata = as_ref_string_new_with_length (text, text_len + 1);
- } else {
- data->cdata = as_node_reflow_text (text, (gssize) text_len);
- }
- /* intern commonly duplicated tag values and save a bit of memory */
- if (data->is_tag_valid && data->cdata != NULL) {
- AsNode *root = g_node_get_root (helper->current);
- switch (data->tag) {
- case AS_TAG_CATEGORY:
- case AS_TAG_COMPULSORY_FOR_DESKTOP:
- case AS_TAG_CONTENT_ATTRIBUTE:
- case AS_TAG_DEVELOPER_NAME:
- case AS_TAG_EXTENDS:
- case AS_TAG_ICON:
- case AS_TAG_ID:
- case AS_TAG_KUDO:
- case AS_TAG_LANG:
- case AS_TAG_METADATA_LICENSE:
- case AS_TAG_MIMETYPE:
- case AS_TAG_PROJECT_GROUP:
- case AS_TAG_PROJECT_LICENSE:
- case AS_TAG_SOURCE_PKGNAME:
- case AS_TAG_URL:
- as_node_cdata_to_intern (root, data);
- break;
- default:
- break;
+ /* support em and code tags */
+ if (helper->is_em_text || helper->is_code_text || data->cdata != NULL) {
+ g_autoptr(GString) str = g_string_new (NULL);
+
+ if (data->cdata != NULL) {
+ g_string_append (str, data->cdata);
+ as_ref_string_unref (data->cdata);
}
+
+ if (helper->is_em_text)
+ g_string_append (str, "<em>");
+ if (helper->is_code_text)
+ g_string_append (str, "<code>");
+
+ g_string_append_len (str, text, text_len);
+
+ if (helper->is_code_text)
+ g_string_append (str, "</code>");
+ if (helper->is_em_text)
+ g_string_append (str, "</em>");
+
+ data->cdata = as_ref_string_new_with_length (str->str, str->len);
+ return;
}
+
+ data->cdata = as_ref_string_new_with_length (text, text_len);
}
static void
@@ -790,7 +846,7 @@
AsNodeFromXmlFlags flags,
GError **error)
{
- AsNodeToXmlHelper helper;
+ AsNodeToXmlHelper helper = {0};
AsNode *root = NULL;
gboolean ret;
g_autoptr(GError) error_local = NULL;
@@ -927,7 +983,7 @@
GCancellable *cancellable,
GError **error)
{
- AsNodeToXmlHelper helper;
+ AsNodeToXmlHelper helper = {0};
GError *error_local = NULL;
AsNode *root = NULL;
const gchar *content_type = NULL;
diff -Nru appstream-glib-0.7.18/libappstream-glib/as-self-test.c appstream-glib-0.7.18/libappstream-glib/as-self-test.c
--- appstream-glib-0.7.18/libappstream-glib/as-self-test.c 2020-09-07 11:20:43.896573000 +0100
+++ appstream-glib-0.7.18/libappstream-glib/as-self-test.c 2023-06-07 20:58:11.000000000 +0100
@@ -2861,6 +2861,20 @@
"<!-- this documents bar -->"
"<bar key=\"value\">baz</bar>"
"</foo>";
+ const gchar *valid_em_code = "<description>"
+ "<p>"
+ "It now also supports <em>em</em> and <code>code</code> tags."
+ "</p>"
+ "</description>";
+ const gchar *valid_em_code_2 = "<description>"
+ "<p><em>Emphasis</em> at the start of the paragraph</p>"
+ "</description>";
+ const gchar *valid_em_code_empty = "<description>"
+ "<p><em></em></p>"
+ "</description>";
+ const gchar *valid_em_code_empty_2 = "<description>"
+ "<p>empty <em></em> emphasis</p>"
+ "</description>";
GError *error = NULL;
AsNode *n2;
AsNode *root;
@@ -2924,6 +2938,43 @@
g_string_free (xml, TRUE);
as_node_unref (root);
+ /* support em and code tags */
+ root = as_node_from_xml (valid_em_code, 0, &error);
+ g_assert_no_error (error);
+ g_assert (root != NULL);
+
+ n2 = as_node_find (root, "description/p");
+ g_assert (n2 != NULL);
+ g_assert_cmpstr (as_node_get_data (n2), ==, "It now also supports <em>em</em> and <code>code</code> tags.");
+ as_node_unref (root);
+
+ root = as_node_from_xml (valid_em_code_2, 0, &error);
+ g_assert_no_error (error);
+ g_assert (root != NULL);
+
+ n2 = as_node_find (root, "description/p");
+ g_assert (n2 != NULL);
+ g_assert_cmpstr (as_node_get_data (n2), ==, "<em>Emphasis</em> at the start of the paragraph");
+ as_node_unref (root);
+
+ root = as_node_from_xml (valid_em_code_empty, 0, &error);
+ g_assert_no_error (error);
+ g_assert (root != NULL);
+
+ n2 = as_node_find (root, "description/p");
+ g_assert (n2 != NULL);
+ g_assert_cmpstr (as_node_get_data (n2), ==, NULL);
+ as_node_unref (root);
+
+ root = as_node_from_xml (valid_em_code_empty_2, 0, &error);
+ g_assert_no_error (error);
+ g_assert (root != NULL);
+
+ n2 = as_node_find (root, "description/p");
+ g_assert (n2 != NULL);
+ g_assert_cmpstr (as_node_get_data (n2), ==, "empty emphasis");
+ as_node_unref (root);
+
/* keep comments */
root = as_node_from_xml (valid,
AS_NODE_FROM_XML_FLAG_KEEP_COMMENTS,

@ -0,0 +1,880 @@
From e5f73b24c4950ec8e51f6970ad658d604baf6d24 Mon Sep 17 00:00:00 2001
From: Kalev Lember <klember@redhat.com>
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 <richard@hughsie.com>
+ * Copyright (C) 2015-2018 Kalev Lember <klember@redhat.com>
*
* 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 <klember@redhat.com>
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 <klember@redhat.com>
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

@ -0,0 +1,144 @@
From d651281e77120ce4c7431364e4787f08189666b6 Mon Sep 17 00:00:00 2001
From: Richard Hughes <richard@hughsie.com>
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 <klember@redhat.com>
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

@ -1,18 +1,18 @@
%global glib2_version 2.45.8
%global libsoup_version 2.51.92
%global json_glib_version 1.1.2
%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.18
Release: 5%{?dist}
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: 0001-Improve-handling-of-em-and-code-tags.patch
# Backported from upstream
Patch0: as_utils_vercmp_full.patch
Patch1: as-store-locking.patch
BuildRequires: glib2-devel >= %{glib2_version}
BuildRequires: docbook-utils
@ -28,13 +28,13 @@ BuildRequires: libuuid-devel
BuildRequires: libstemmer-devel
BuildRequires: json-glib-devel >= %{json_glib_version}
BuildRequires: meson
BuildRequires: rpm-devel
BuildRequires: git-core
# for the builder component
BuildRequires: fontconfig-devel
BuildRequires: freetype-devel
BuildRequires: pango-devel
BuildRequires: rpm-devel
BuildRequires: sqlite-devel
# for the manpages
BuildRequires: libxslt
@ -50,9 +50,6 @@ Requires: libsoup%{?_isa} >= %{libsoup_version}
Obsoletes: appdata-tools < 0.1.9
Provides: appdata-tools
# Removed in F30
Obsoletes: libappstream-glib-builder-devel < 0.7.15
# this is not a library version
%define as_plugin_version 5
@ -78,8 +75,15 @@ Recommends: pngquant
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 -Sgit -n appstream-glib-%{version}
%autosetup -p1 -n appstream-glib-%{version}
%build
%meson \
@ -131,79 +135,18 @@ from a directory of packages.
%{_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
%changelog
* Fri Apr 26 2024 Richard Hughes <richard@hughsie.com> 0.7.18-5
- Backport a patch from upstream to fix handling unknown tags in AppStream metadata
- Resolves: #RHEL-34564
* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 0.7.18-4
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
Related: rhbz#1991688
* Fri Apr 16 2021 Mohan Boddu <mboddu@redhat.com> - 0.7.18-3
- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 0.7.18-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
* Mon Sep 07 2020 Richard Hughes <richard@hughsie.com> 0.7.18-1
- New upstream release
- Add content rating system APIs from gnome-software
- Add "validate-version" command
- Allow timestamp in the future in validate-relax
- Don't ignore localized strings that are the same as original
- Fix crash with invalid children of <ul/>
- Properly initialize mutexes
- Test launchable tags in validation
* Tue Jul 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 0.7.17-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Thu Feb 20 2020 Richard Hughes <richard@hughsie.com> 0.7.17-1
- New upstream release
- Add "icon-theme" as recognised component type
- Fix CI by moving 'future' back a bit
- Make default content rating values match OARS semantics
- Properly initialize unique_id_mutex
* Wed Jan 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 0.7.16-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
* Thu Nov 14 2019 Kalev Lember <klember@redhat.com> - 0.7.16-2
- Backport a patch to fix parsing Qt translations in subdirectories
* Mon Sep 30 2019 Richard Hughes <richard@hughsie.com> 0.7.16-1
- Update to 0.7.15
- Add UPL short name to SPDX conversion
- Allow parsing desktop files using as_app_parse_data()
- Do not preserve restrictive permissions when installing AppStream files
- Modernize the validation requirements
- Remove relative path from icon names
- Support loading YAML from as_store_from_bytes()
- Update list of allowed metadata licences
- Update the SPDX license list to v3.5
* Thu Jul 25 2019 Fedora Release Engineering <releng@fedoraproject.org> - 0.7.15-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
* Mon Jun 10 22:13:19 CET 2019 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 0.7.15-3
- Rebuild for RPM 4.15
* Mon Jun 10 15:42:02 CET 2019 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 0.7.15-2
- Rebuild for RPM 4.15
* Thu Feb 28 2019 Kalev Lember <klember@redhat.com> - 0.7.15-1
- Update to 0.7.15
- Remove and obsolete the -builder-devel subpackage
* Fri Feb 01 2019 Fedora Release Engineering <releng@fedoraproject.org> - 0.7.14-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
* Fri Dec 28 2018 Kalev Lember <klember@redhat.com> 0.7.14-4
- Backport an upstream patch to fix common gnome-software crash
%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 <klember@redhat.com> 0.7.14-3
- Backport AsStore locking patches from upstream

Loading…
Cancel
Save