diff options
author | Richard Hughes <richard@hughsie.com> | 2016-08-04 21:18:57 +0100 |
---|---|---|
committer | Richard Hughes <richard@hughsie.com> | 2016-08-04 21:27:49 +0100 |
commit | 0bf85282254910808c60a1a68152b9715d055d0e (patch) | |
tree | 2e19aafad495bbb7fdce97b075fb6b6f2383d6fa | |
parent | 86ebfd1d4b94f626a2d5aeb3843b5c551e06447d (diff) | |
download | appstream-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.c | 62 | ||||
-rw-r--r-- | libappstream-glib/as-self-test.c | 49 | ||||
-rw-r--r-- | libappstream-glib/as-store.c | 61 | ||||
-rw-r--r-- | libappstream-glib/as-store.h | 8 |
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; |