summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2016-08-04 21:18:57 +0100
committerRichard Hughes <richard@hughsie.com>2016-08-04 21:27:49 +0100
commit0bf85282254910808c60a1a68152b9715d055d0e (patch)
tree2e19aafad495bbb7fdce97b075fb6b6f2383d6fa
parent86ebfd1d4b94f626a2d5aeb3843b5c551e06447d (diff)
downloadappstream-glib-0bf85282254910808c60a1a68152b9715d055d0e.tar.gz
Support merge components
This allows us to match soon-to-be-specified merge components to every component in the store.
-rw-r--r--client/as-util.c62
-rw-r--r--libappstream-glib/as-self-test.c49
-rw-r--r--libappstream-glib/as-store.c61
-rw-r--r--libappstream-glib/as-store.h8
4 files changed, 176 insertions, 4 deletions
diff --git a/client/as-util.c b/client/as-util.c
index 84648b3..77482f2 100644
--- a/client/as-util.c
+++ b/client/as-util.c
@@ -1200,7 +1200,9 @@ as_util_search (AsUtilPrivate *priv, gchar **values, GError **error)
/* load system database */
store = as_store_new ();
- as_store_set_add_flags (store, AS_STORE_ADD_FLAG_USE_UNIQUE_ID);
+ as_store_set_add_flags (store,
+ AS_STORE_ADD_FLAG_USE_UNIQUE_ID |
+ AS_STORE_ADD_FLAG_USE_MERGE_HEURISTIC);
if (!as_store_load (store,
AS_STORE_LOAD_FLAG_IGNORE_INVALID |
AS_STORE_LOAD_FLAG_APP_INFO_SYSTEM |
@@ -1254,6 +1256,9 @@ as_util_search_pkgname (AsUtilPrivate *priv, gchar **values, GError **error)
/* load system database */
store = as_store_new ();
+ as_store_set_add_flags (store,
+ AS_STORE_ADD_FLAG_USE_UNIQUE_ID |
+ AS_STORE_ADD_FLAG_USE_MERGE_HEURISTIC);
if (!as_store_load (store,
AS_STORE_LOAD_FLAG_IGNORE_INVALID |
AS_STORE_LOAD_FLAG_APP_INFO_SYSTEM |
@@ -1273,6 +1278,55 @@ as_util_search_pkgname (AsUtilPrivate *priv, gchar **values, GError **error)
return TRUE;
}
+static gboolean
+as_util_search_category (AsUtilPrivate *priv, gchar **values, GError **error)
+{
+ GPtrArray *apps;
+ guint i, j;
+ g_autoptr(AsStore) store = NULL;
+
+ /* check args */
+ if (g_strv_length (values) < 1) {
+ g_set_error_literal (error,
+ AS_ERROR,
+ AS_ERROR_INVALID_ARGUMENTS,
+ "Not enough arguments, "
+ "expected search terms");
+ return FALSE;
+ }
+
+ /* load system database */
+ store = as_store_new ();
+ as_store_set_add_flags (store,
+ AS_STORE_ADD_FLAG_USE_UNIQUE_ID |
+ AS_STORE_ADD_FLAG_USE_MERGE_HEURISTIC);
+ if (!as_store_load (store,
+ AS_STORE_LOAD_FLAG_IGNORE_INVALID |
+ AS_STORE_LOAD_FLAG_APP_INFO_SYSTEM |
+ AS_STORE_LOAD_FLAG_APP_INFO_USER |
+ AS_STORE_LOAD_FLAG_APPDATA |
+ AS_STORE_LOAD_FLAG_DESKTOP,
+ NULL, error))
+ return FALSE;
+
+ /* find by source */
+ apps = as_store_get_apps (store);
+ for (j = 0; j < apps->len; j++) {
+ gboolean found = FALSE;
+ AsApp *app = g_ptr_array_index (apps, j);
+ for (i = 0; values[i] != NULL; i++) {
+ if (as_app_has_category (app, values[i])) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (!found)
+ continue;
+ g_print ("%s\n", as_app_get_unique_id (app));
+ }
+ return TRUE;
+}
+
static gint
as_util_search_token_sort_cb (gconstpointer a, gconstpointer b, gpointer user_data)
{
@@ -3876,6 +3930,12 @@ main (int argc, char *argv[])
_("Search for AppStream applications by package name"),
as_util_search_pkgname);
as_util_add (priv->cmd_array,
+ "search-category",
+ NULL,
+ /* TRANSLATORS: command description */
+ _("Search for AppStream applications by category name"),
+ as_util_search_category);
+ as_util_add (priv->cmd_array,
"show-search-tokens",
NULL,
/* TRANSLATORS: command description */
diff --git a/libappstream-glib/as-self-test.c b/libappstream-glib/as-self-test.c
index 7aefaac..1ca784a 100644
--- a/libappstream-glib/as-self-test.c
+++ b/libappstream-glib/as-self-test.c
@@ -5045,6 +5045,54 @@ as_test_utils_unique_id_func (void)
g_print ("%.0f ns: ", duration_ns / (loops * 4));
}
+static void
+as_test_store_merge_func (void)
+{
+ g_autoptr (AsApp) app1 = NULL;
+ g_autoptr (AsApp) app2 = NULL;
+ g_autoptr (AsApp) app_merge = NULL;
+ g_autoptr (AsStore) store = NULL;
+
+ store = as_store_new ();
+ as_store_set_add_flags (store,
+ AS_STORE_ADD_FLAG_USE_UNIQUE_ID |
+ AS_STORE_ADD_FLAG_USE_MERGE_HEURISTIC);
+
+ /* add app */
+ app1 = as_app_new ();
+ as_app_set_id (app1, "org.gnome.Software.desktop");
+ as_app_set_branch (app1, "master");
+ as_app_set_source_kind (app1, AS_APP_SOURCE_KIND_APPDATA);
+ as_app_add_pkgname (app1, "gnome-software");
+ g_assert_cmpstr (as_app_get_unique_id (app1), ==,
+ "*/package/*/*/org.gnome.Software.desktop/*/master/*");
+ as_store_add_app (store, app1);
+
+ /* add merge component */
+ app_merge = as_app_new ();
+ as_app_set_kind (app_merge, AS_APP_KIND_DESKTOP);
+ as_app_set_id (app_merge, "org.gnome.Software.desktop");
+ as_app_set_source_kind (app_merge, AS_APP_SOURCE_KIND_APPSTREAM);
+ as_app_add_category (app_merge, "special");
+ g_assert_cmpstr (as_app_get_unique_id (app_merge), ==,
+ "*/*/*/desktop/org.gnome.Software.desktop/*/*/*");
+ as_store_add_app (store, app_merge);
+
+ /* add app */
+ app2 = as_app_new ();
+ as_app_set_id (app2, "org.gnome.Software.desktop");
+ as_app_set_branch (app2, "stable");
+ as_app_set_source_kind (app2, AS_APP_SOURCE_KIND_APPSTREAM);
+ as_app_add_pkgname (app2, "gnome-software");
+ g_assert_cmpstr (as_app_get_unique_id (app2), ==,
+ "*/package/*/*/org.gnome.Software.desktop/*/stable/*");
+ as_store_add_app (store, app2);
+
+ /* verify that both apps have the category */
+ g_assert (as_app_has_category (app1, "special"));
+ g_assert (as_app_has_category (app2, "special"));
+}
+
int
main (int argc, char **argv)
{
@@ -5117,6 +5165,7 @@ main (int argc, char **argv)
g_test_add_func ("/AppStream/yaml", as_test_yaml_func);
g_test_add_func ("/AppStream/store", as_test_store_func);
g_test_add_func ("/AppStream/store{unique}", as_test_store_unique_func);
+ g_test_add_func ("/AppStream/store{merge}", as_test_store_merge_func);
g_test_add_func ("/AppStream/store{empty}", as_test_store_empty_func);
if (g_test_slow ()) {
g_test_add_func ("/AppStream/store{auto-reload-dir}", as_test_store_auto_reload_dir_func);
diff --git a/libappstream-glib/as-store.c b/libappstream-glib/as-store.c
index 1023cb5..bc11d8b 100644
--- a/libappstream-glib/as-store.c
+++ b/libappstream-glib/as-store.c
@@ -65,6 +65,7 @@ typedef struct
gdouble api_version;
GPtrArray *array; /* of AsApp */
GHashTable *hash_id; /* of GPtrArray of AsApp{id} */
+ GHashTable *hash_merge_id; /* of GPtrArray of AsApp{id} */
GHashTable *hash_unique_id; /* of AsApp{unique_id} */
GHashTable *hash_pkgname; /* of AsApp{pkgname} */
AsMonitor *monitor;
@@ -125,6 +126,7 @@ as_store_finalize (GObject *object)
g_object_unref (priv->monitor);
g_object_unref (priv->profile);
g_hash_table_unref (priv->hash_id);
+ g_hash_table_unref (priv->hash_merge_id);
g_hash_table_unref (priv->hash_unique_id);
g_hash_table_unref (priv->hash_pkgname);
g_hash_table_unref (priv->metadata_indexes);
@@ -296,6 +298,7 @@ as_store_remove_all (AsStore *store)
g_return_if_fail (AS_IS_STORE (store));
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);
g_hash_table_remove_all (priv->hash_unique_id);
g_hash_table_remove_all (priv->hash_pkgname);
}
@@ -879,6 +882,20 @@ as_store_remove_app_by_id (AsStore *store, const gchar *id)
as_store_perhaps_emit_changed (store, "remove-app-by-id");
}
+static gboolean
+_as_app_is_perhaps_merge_component (AsApp *app)
+{
+ if (as_app_get_kind (app) != AS_APP_KIND_DESKTOP)
+ return FALSE;
+ if (as_app_get_source_kind (app) != AS_APP_SOURCE_KIND_APPSTREAM)
+ return FALSE;
+ if (as_app_get_bundle_kind (app) != AS_BUNDLE_KIND_UNKNOWN)
+ return FALSE;
+ if (as_app_get_name (app, NULL) != NULL)
+ return FALSE;
+ return TRUE;
+}
+
/**
* as_store_add_app:
* @store: a #AsStore instance.
@@ -909,6 +926,46 @@ as_store_add_app (AsStore *store, AsApp *app)
return;
}
+ /* this is a special merge component */
+ if ((priv->add_flags & AS_STORE_ADD_FLAG_USE_MERGE_HEURISTIC) > 0 &&
+ _as_app_is_perhaps_merge_component (app)) {
+ 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);
+ g_hash_table_insert (priv->hash_merge_id,
+ (gpointer) as_app_get_id (app),
+ apps);
+ }
+ g_debug ("added merge component: %s",
+ as_app_get_unique_id (app));
+ g_ptr_array_add (apps, g_object_ref (app));
+
+ /* apply to existing components */
+ 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)
+ continue;
+ g_debug ("using merge component %s on %s",
+ id, as_app_get_unique_id (app_tmp));
+ as_app_subsume_full (app_tmp, app,
+ AS_APP_SUBSUME_FLAG_NO_OVERWRITE);
+ }
+ return;
+ }
+
+ /* is there any merge components to add to this app */
+ apps = g_hash_table_lookup (priv->hash_merge_id, id);
+ if (apps != NULL) {
+ for (i = 0; i < apps->len; i++) {
+ AsApp *app_tmp = g_ptr_array_index (apps, i);
+ g_debug ("using merge component %s on %s",
+ as_app_get_unique_id (app_tmp),
+ as_app_get_unique_id (app));
+ as_app_subsume_full (app, app_tmp,
+ AS_APP_SUBSUME_FLAG_NO_OVERWRITE);
+ }
+ }
+
/* find the item */
if (priv->add_flags & AS_STORE_ADD_FLAG_USE_UNIQUE_ID) {
item = as_store_get_app_by_app (store, app);
@@ -3044,6 +3101,10 @@ as_store_init (AsStore *store)
g_str_equal,
NULL,
(GDestroyNotify) g_ptr_array_unref);
+ priv->hash_merge_id = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ NULL,
+ (GDestroyNotify) g_ptr_array_unref);
priv->hash_unique_id = g_hash_table_new_full (g_str_hash,
g_str_equal,
NULL,
diff --git a/libappstream-glib/as-store.h b/libappstream-glib/as-store.h
index 5d8d855..5daba5b 100644
--- a/libappstream-glib/as-store.h
+++ b/libappstream-glib/as-store.h
@@ -90,13 +90,15 @@ typedef enum {
* @AS_STORE_ADD_FLAG_NONE: No extra flags to use
* @AS_STORE_ADD_FLAG_PREFER_LOCAL: Local files will be used by default
* @AS_STORE_ADD_FLAG_USE_UNIQUE_ID: Allow multiple apps with the same AppStream ID
+ * @AS_STORE_ADD_FLAG_USE_MERGE_HEURISTIC: Use a heuristic when adding merge components
*
* The flags to use when adding applications to the store.
**/
typedef enum {
- AS_STORE_ADD_FLAG_NONE = 0, /* Since: 0.2.2 */
- AS_STORE_ADD_FLAG_PREFER_LOCAL = 1, /* Since: 0.2.2 */
- AS_STORE_ADD_FLAG_USE_UNIQUE_ID = 2, /* Since: 0.6.1 */
+ AS_STORE_ADD_FLAG_NONE = 0, /* Since: 0.2.2 */
+ AS_STORE_ADD_FLAG_PREFER_LOCAL = 1 << 0, /* Since: 0.2.2 */
+ AS_STORE_ADD_FLAG_USE_UNIQUE_ID = 1 << 1, /* Since: 0.6.1 */
+ AS_STORE_ADD_FLAG_USE_MERGE_HEURISTIC = 1 << 2, /* Since: 0.6.1 */
/*< private >*/
AS_STORE_ADD_FLAG_LAST
} AsStoreAddFlags;