diff options
author | Richard Hughes <richard@hughsie.com> | 2016-09-02 16:41:20 +0100 |
---|---|---|
committer | Richard Hughes <richard@hughsie.com> | 2016-09-02 16:45:45 +0100 |
commit | 754f21a013d66bd0956a41c6c288a41ff7c8a68a (patch) | |
tree | a18e706cff676134cd7e2591ccf523a2f2d555d7 | |
parent | 9b3ab01fe1393f26af80a99fa9df0020df410a1c (diff) | |
download | appstream-glib-754f21a013d66bd0956a41c6c288a41ff7c8a68a.tar.gz |
Support components with merge=replace rules
This allows components to replace parts of the app without just appending.
-rw-r--r-- | libappstream-glib/as-app.c | 90 | ||||
-rw-r--r-- | libappstream-glib/as-app.h | 7 | ||||
-rw-r--r-- | libappstream-glib/as-self-test.c | 52 | ||||
-rw-r--r-- | libappstream-glib/as-store.c | 28 |
4 files changed, 146 insertions, 31 deletions
diff --git a/libappstream-glib/as-app.c b/libappstream-glib/as-app.c index 524db25..67896bf 100644 --- a/libappstream-glib/as-app.c +++ b/libappstream-glib/as-app.c @@ -3383,7 +3383,7 @@ as_app_add_addon (AsApp *app, AsApp *addon) static void -as_app_subsume_dict (GHashTable *dest, GHashTable *src, gboolean overwrite) +as_app_subsume_dict (GHashTable *dest, GHashTable *src, AsAppSubsumeFlags flags) { GList *l; const gchar *tmp; @@ -3392,9 +3392,11 @@ as_app_subsume_dict (GHashTable *dest, GHashTable *src, gboolean overwrite) g_autoptr(GList) keys = NULL; keys = g_hash_table_get_keys (src); + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && keys != NULL) + g_hash_table_remove_all (dest); for (l = keys; l != NULL; l = l->next) { key = l->data; - if (!overwrite) { + if (flags & AS_APP_SUBSUME_FLAG_NO_OVERWRITE) { tmp = g_hash_table_lookup (dest, key); if (tmp != NULL) continue; @@ -3469,14 +3471,11 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) AsAppPrivate *papp = GET_PRIVATE (app); const gchar *tmp; const gchar *key; - gboolean overwrite; guint i; /* stop us shooting ourselves in the foot */ papp->trust_flags |= AS_APP_TRUST_FLAG_CHECK_DUPLICATES; - overwrite = (flags & AS_APP_SUBSUME_FLAG_NO_OVERWRITE) == 0; - /* id-kind */ if (flags & AS_APP_SUBSUME_FLAG_KIND) { if (papp->kind == AS_APP_KIND_UNKNOWN) @@ -3499,6 +3498,9 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) /* pkgnames */ if (flags & AS_APP_SUBSUME_FLAG_BUNDLES) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->pkgnames->len > 0) + g_ptr_array_set_size (papp->pkgnames, 0); for (i = 0; i < priv->pkgnames->len; i++) { tmp = g_ptr_array_index (priv->pkgnames, i); as_app_add_pkgname (app, tmp); @@ -3507,6 +3509,9 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) /* bundles */ if (flags & AS_APP_SUBSUME_FLAG_BUNDLES) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->bundles->len > 0) + g_ptr_array_set_size (papp->bundles, 0); for (i = 0; i < priv->bundles->len; i++) { AsBundle *bundle = g_ptr_array_index (priv->bundles, i); as_app_add_bundle (app, bundle); @@ -3515,6 +3520,9 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) /* translations */ if (flags & AS_APP_SUBSUME_FLAG_TRANSLATIONS) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->translations->len > 0) + g_ptr_array_set_size (papp->translations, 0); for (i = 0; i < priv->translations->len; i++) { AsTranslation *tr = g_ptr_array_index (priv->translations, i); as_app_add_translation (app, tr); @@ -3522,13 +3530,21 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) } /* suggests */ - for (i = 0; i < priv->suggests->len; i++) { - AsSuggest *suggest = g_ptr_array_index (priv->suggests, i); - as_app_add_suggest (app, suggest); + if (flags & AS_APP_SUBSUME_FLAG_SUGGESTS) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->suggests->len > 0) + g_ptr_array_set_size (papp->suggests, 0); + for (i = 0; i < priv->suggests->len; i++) { + AsSuggest *suggest = g_ptr_array_index (priv->suggests, i); + as_app_add_suggest (app, suggest); + } } /* releases */ if (flags & AS_APP_SUBSUME_FLAG_RELEASES) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->releases->len > 0) + g_ptr_array_set_size (papp->releases, 0); for (i = 0; i < priv->releases->len; i++) { AsRelease *rel= g_ptr_array_index (priv->releases, i); as_app_add_release (app, rel); @@ -3537,6 +3553,9 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) /* kudos */ if (flags & AS_APP_SUBSUME_FLAG_KUDOS) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->kudos->len > 0) + g_ptr_array_set_size (papp->kudos, 0); for (i = 0; i < priv->kudos->len; i++) { tmp = g_ptr_array_index (priv->kudos, i); as_app_add_kudo (app, tmp); @@ -3545,6 +3564,9 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) /* categories */ if (flags & AS_APP_SUBSUME_FLAG_CATEGORIES) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->categories->len > 0) + g_ptr_array_set_size (papp->categories, 0); for (i = 0; i < priv->categories->len; i++) { tmp = g_ptr_array_index (priv->categories, i); as_app_add_category (app, tmp); @@ -3553,6 +3575,9 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) /* permissions */ if (flags & AS_APP_SUBSUME_FLAG_PERMISSIONS) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->permissions->len > 0) + g_ptr_array_set_size (papp->permissions, 0); for (i = 0; i < priv->permissions->len; i++) { tmp = g_ptr_array_index (priv->permissions, i); as_app_add_permission (app, tmp); @@ -3561,6 +3586,9 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) /* extends */ if (flags & AS_APP_SUBSUME_FLAG_EXTENDS) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->extends->len > 0) + g_ptr_array_set_size (papp->extends, 0); for (i = 0; i < priv->extends->len; i++) { tmp = g_ptr_array_index (priv->extends, i); as_app_add_extends (app, tmp); @@ -3569,6 +3597,9 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) /* compulsory_for_desktops */ if (flags & AS_APP_SUBSUME_FLAG_COMPULSORY) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->compulsory_for_desktops->len > 0) + g_ptr_array_set_size (papp->compulsory_for_desktops, 0); for (i = 0; i < priv->compulsory_for_desktops->len; i++) { tmp = g_ptr_array_index (priv->compulsory_for_desktops, i); as_app_add_compulsory_for_desktop (app, tmp); @@ -3577,6 +3608,9 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) /* screenshots */ if (flags & AS_APP_SUBSUME_FLAG_SCREENSHOTS) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->screenshots->len > 0) + g_ptr_array_set_size (papp->screenshots, 0); for (i = 0; i < priv->screenshots->len; i++) { AsScreenshot *ss = g_ptr_array_index (priv->screenshots, i); as_app_add_screenshot (app, ss); @@ -3585,6 +3619,9 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) /* reviews */ if (flags & AS_APP_SUBSUME_FLAG_REVIEWS) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->reviews->len > 0) + g_ptr_array_set_size (papp->reviews, 0); for (i = 0; i < priv->reviews->len; i++) { AsReview *review = g_ptr_array_index (priv->reviews, i); as_app_add_review (app, review); @@ -3593,6 +3630,9 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) /* content_ratings */ if (flags & AS_APP_SUBSUME_FLAG_CONTENT_RATINGS) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->content_ratings->len > 0) + g_ptr_array_set_size (papp->content_ratings, 0); for (i = 0; i < priv->content_ratings->len; i++) { AsContentRating *content_rating; content_rating = g_ptr_array_index (priv->content_ratings, i); @@ -3602,6 +3642,9 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) /* provides */ if (flags & AS_APP_SUBSUME_FLAG_PROVIDES) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->provides->len > 0) + g_ptr_array_set_size (papp->provides, 0); for (i = 0; i < priv->provides->len; i++) { AsProvide *pr = g_ptr_array_index (priv->provides, i); as_app_add_provide (app, pr); @@ -3610,6 +3653,9 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) /* icons */ if (flags & AS_APP_SUBSUME_FLAG_ICONS) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->icons->len > 0) + g_ptr_array_set_size (papp->icons, 0); for (i = 0; i < priv->icons->len; i++) { AsIcon *ic = g_ptr_array_index (priv->icons, i); as_app_subsume_icon (app, ic); @@ -3618,6 +3664,9 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) /* mimetypes */ if (flags & AS_APP_SUBSUME_FLAG_MIMETYPES) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->mimetypes->len > 0) + g_ptr_array_set_size (papp->mimetypes, 0); for (i = 0; i < priv->mimetypes->len; i++) { tmp = g_ptr_array_index (priv->mimetypes, i); as_app_add_mimetype (app, tmp); @@ -3626,6 +3675,9 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) /* vetos */ if (flags & AS_APP_SUBSUME_FLAG_VETOS) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->vetos->len > 0) + g_ptr_array_set_size (papp->vetos, 0); for (i = 0; i < priv->vetos->len; i++) { tmp = g_ptr_array_index (priv->vetos, i); as_app_add_veto (app, "%s", tmp); @@ -3636,6 +3688,8 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) if (flags & AS_APP_SUBSUME_FLAG_LANGUAGES) { GList *l; g_autoptr(GList) keys = g_hash_table_get_keys (priv->languages); + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && keys != NULL) + g_hash_table_remove_all (papp->languages); for (l = keys; l != NULL; l = l->next) { gint percentage; key = l->data; @@ -3651,19 +3705,19 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) /* dictionaries */ if (flags & AS_APP_SUBSUME_FLAG_NAME) - as_app_subsume_dict (papp->names, priv->names, overwrite); + as_app_subsume_dict (papp->names, priv->names, flags); if (flags & AS_APP_SUBSUME_FLAG_COMMENT) - as_app_subsume_dict (papp->comments, priv->comments, overwrite); + as_app_subsume_dict (papp->comments, priv->comments, flags); if (flags & AS_APP_SUBSUME_FLAG_DEVELOPER_NAME) - as_app_subsume_dict (papp->developer_names, priv->developer_names, overwrite); + as_app_subsume_dict (papp->developer_names, priv->developer_names, flags); if (flags & AS_APP_SUBSUME_FLAG_DESCRIPTION) - as_app_subsume_dict (papp->descriptions, priv->descriptions, overwrite); + as_app_subsume_dict (papp->descriptions, priv->descriptions, flags); if (flags & AS_APP_SUBSUME_FLAG_METADATA) - as_app_subsume_dict (papp->metadata, priv->metadata, overwrite); + as_app_subsume_dict (papp->metadata, priv->metadata, flags); if (flags & AS_APP_SUBSUME_FLAG_URL) - as_app_subsume_dict (papp->urls, priv->urls, overwrite); + as_app_subsume_dict (papp->urls, priv->urls, flags); if (flags & AS_APP_SUBSUME_FLAG_KEYWORDS) - as_app_subsume_keywords (app, donor, overwrite); + as_app_subsume_keywords (app, donor, flags); /* source */ if (flags & AS_APP_SUBSUME_FLAG_SOURCE_FILE) { @@ -3721,12 +3775,6 @@ as_app_subsume_full (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) { g_assert (app != donor); - /* legacy value */ - if (flags & AS_APP_SUBSUME_FLAG_PARTIAL) { - g_warning ("using AS_APP_SUBSUME_FLAG_PARTIAL fallback"); - flags |= AS_APP_SUBSUME_FLAG_MERGE; - } - /* two way sync implies no overwriting */ if ((flags & AS_APP_SUBSUME_FLAG_BOTH_WAYS) > 0) flags |= AS_APP_SUBSUME_FLAG_NO_OVERWRITE; diff --git a/libappstream-glib/as-app.h b/libappstream-glib/as-app.h index bb21512..982d360 100644 --- a/libappstream-glib/as-app.h +++ b/libappstream-glib/as-app.h @@ -129,7 +129,7 @@ typedef enum { AS_APP_SUBSUME_FLAG_NONE = 0, AS_APP_SUBSUME_FLAG_NO_OVERWRITE = 1ull << 0, /* Since: 0.1.4 */ AS_APP_SUBSUME_FLAG_BOTH_WAYS = 1ull << 1, /* Since: 0.1.4 */ - AS_APP_SUBSUME_FLAG_PARTIAL = 1ull << 2, /* Since: 0.2.2 */ + AS_APP_SUBSUME_FLAG_REPLACE = 1ull << 2, /* Since: 0.6.3 */ AS_APP_SUBSUME_FLAG_KIND = 1ull << 3, /* Since: 0.6.1 */ AS_APP_SUBSUME_FLAG_STATE = 1ull << 4, /* Since: 0.6.1 */ AS_APP_SUBSUME_FLAG_BUNDLES = 1ull << 5, /* Since: 0.6.1 */ @@ -162,6 +162,7 @@ typedef enum { AS_APP_SUBSUME_FLAG_PROJECT_LICENSE = 1ull << 32, /* Since: 0.6.1 */ AS_APP_SUBSUME_FLAG_PROJECT_GROUP = 1ull << 33, /* Since: 0.6.1 */ AS_APP_SUBSUME_FLAG_SOURCE_KIND = 1ull << 34, /* Since: 0.6.1 */ + AS_APP_SUBSUME_FLAG_SUGGESTS = 1ull << 35, /* Since: 0.6.3 */ /*< private >*/ AS_APP_SUBSUME_FLAG_LAST, } AsAppSubsumeFlags; @@ -186,9 +187,13 @@ typedef enum { AS_APP_SUBSUME_FLAG_RELEASES | \ AS_APP_SUBSUME_FLAG_REVIEWS | \ AS_APP_SUBSUME_FLAG_SCREENSHOTS | \ + AS_APP_SUBSUME_FLAG_SUGGESTS | \ AS_APP_SUBSUME_FLAG_TRANSLATIONS | \ AS_APP_SUBSUME_FLAG_URL) +/* deprecated name */ +#define AS_APP_SUBSUME_FLAG_PARTIAL AS_APP_SUBSUME_FLAG_MERGE + /* all properties */ #define AS_APP_SUBSUME_FLAG_DEDUPE (AS_APP_SUBSUME_FLAG_BRANCH | \ AS_APP_SUBSUME_FLAG_BUNDLES | \ diff --git a/libappstream-glib/as-self-test.c b/libappstream-glib/as-self-test.c index c80ed1d..84a8470 100644 --- a/libappstream-glib/as-self-test.c +++ b/libappstream-glib/as-self-test.c @@ -4866,6 +4866,57 @@ as_test_store_merge_func (void) g_assert_cmpstr (as_app_get_source_file (app2), ==, NULL); } +static void +as_test_store_merge_replace_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); + + /* 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"); + as_app_add_category (app1, "Family"); + 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_set_origin (app_merge, "utopia"); + as_app_set_scope (app_merge, AS_APP_SCOPE_USER); + as_app_set_merge_kind (app_merge, AS_APP_MERGE_KIND_REPLACE); + as_app_add_category (app_merge, "Horror"); + as_store_add_app (store, app_merge); + g_assert_cmpstr (as_app_get_unique_id (app_merge), ==, + "*/*/*/desktop/org.gnome.Software.desktop/*"); + + /* 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"); + as_app_add_category (app2, "Family"); + as_store_add_app (store, app2); + + /* verify that both apps have the category */ + g_assert (as_app_has_category (app1, "Horror")); + g_assert (as_app_has_category (app2, "Horror")); + + /* verify we replaced rather than appended */ + g_assert (!as_app_has_category (app1, "Family")); + g_assert (!as_app_has_category (app2, "Family")); +} + /* shows the unique-id globbing functions at work */ static void as_test_utils_unique_id_hash_func (void) @@ -5008,6 +5059,7 @@ main (int argc, char **argv) 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{merge-replace}", as_test_store_merge_replace_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 4348ee9..7ac5d2f 100644 --- a/libappstream-glib/as-store.c +++ b/libappstream-glib/as-store.c @@ -935,6 +935,9 @@ as_store_add_app (AsStore *store, AsApp *app) /* this is a special merge component */ if (as_app_has_quirk (app, AS_APP_QUIRK_MATCH_ANY_PREFIX)) { + AsAppSubsumeFlags flags = AS_APP_SUBSUME_FLAG_MERGE; + AsAppMergeKind merge_kind = as_app_get_merge_kind (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); @@ -942,20 +945,23 @@ as_store_add_app (AsStore *store, AsApp *app) (gpointer) as_app_get_id (app), apps); } - g_debug ("added merge component: %s", + g_debug ("added %s merge component: %s", + as_app_merge_kind_to_string (merge_kind), as_app_get_unique_id (app)); g_ptr_array_add (apps, g_object_ref (app)); /* 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; 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", + g_debug ("using %s merge component %s on %s", + as_app_merge_kind_to_string (merge_kind), id, as_app_get_unique_id (app_tmp)); - as_app_subsume_full (app_tmp, app, - AS_APP_SUBSUME_FLAG_NO_OVERWRITE | - AS_APP_SUBSUME_FLAG_MERGE); + as_app_subsume_full (app_tmp, app, flags); } return; } @@ -965,12 +971,16 @@ as_store_add_app (AsStore *store, AsApp *app) 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", + AsAppMergeKind merge_kind = as_app_get_merge_kind (app_tmp); + AsAppSubsumeFlags flags = AS_APP_SUBSUME_FLAG_MERGE; + g_debug ("using %s merge component %s on %s", + as_app_merge_kind_to_string (merge_kind), 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 | - AS_APP_SUBSUME_FLAG_MERGE); + flags |= AS_APP_SUBSUME_FLAG_NO_OVERWRITE; + if (merge_kind == AS_APP_MERGE_KIND_REPLACE) + flags |= AS_APP_SUBSUME_FLAG_REPLACE; + as_app_subsume_full (app, app_tmp, flags); } } |