From 4fe8a36729b2410820a8c86b05e15ea37c7f4207 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 25 Nov 2021 09:46:08 +0000 Subject: [PATCH] Add support for LVFS component tags These allow us to tag components as being part of a set, e.g. a BKC. --- libfwupd/fwupd-enums-private.h | 8 +++ libfwupd/fwupd-release.c | 95 ++++++++++++++++++++++++++++++++++ libfwupd/fwupd-release.h | 6 +++ libfwupd/fwupd-self-test.c | 8 +++ libfwupd/fwupd.map | 8 +++ src/fu-engine.c | 10 ++++ src/fu-util-common.c | 14 +++++ 7 files changed, 149 insertions(+) diff --git a/libfwupd/fwupd-enums-private.h b/libfwupd/fwupd-enums-private.h index 6cd858a81..ee11af1d2 100644 --- a/libfwupd/fwupd-enums-private.h +++ b/libfwupd/fwupd-enums-private.h @@ -34,6 +34,14 @@ G_BEGIN_DECLS * The D-Bus type signature string is 'as' i.e. an array of strings. **/ #define FWUPD_RESULT_KEY_CHECKSUM "Checksum" +/** + * FWUPD_RESULT_KEY_TAGS: + * + * Result key to represent release tags + * + * The D-Bus type signature string is 'as' i.e. an array of strings. + **/ +#define FWUPD_RESULT_KEY_TAGS "Tags" /** * FWUPD_RESULT_KEY_CREATED: * diff --git a/libfwupd/fwupd-release.c b/libfwupd/fwupd-release.c index 40c1d4876..28fe255ec 100644 --- a/libfwupd/fwupd-release.c +++ b/libfwupd/fwupd-release.c @@ -31,6 +31,7 @@ fwupd_release_finalize(GObject *object); typedef struct { GPtrArray *checksums; + GPtrArray *tags; GPtrArray *categories; GPtrArray *issues; GHashTable *metadata; @@ -488,6 +489,72 @@ fwupd_release_has_checksum(FwupdRelease *self, const gchar *checksum) return FALSE; } +/** + * fwupd_release_get_tags: + * @self: a #FwupdRelease + * + * Gets the release tags. + * + * Returns: (element-type utf8) (transfer none): the tags, which may be empty + * + * Since: 1.7.3 + **/ +GPtrArray * +fwupd_release_get_tags(FwupdRelease *self) +{ + FwupdReleasePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL); + return priv->tags; +} + +/** + * fwupd_release_add_tag: + * @self: a #FwupdRelease + * @tag: the update tag, e.g. `vendor-factory-2021q1` + * + * Adds a specific release tag. + * + * Since: 1.7.3 + **/ +void +fwupd_release_add_tag(FwupdRelease *self, const gchar *tag) +{ + FwupdReleasePrivate *priv = GET_PRIVATE(self); + g_return_if_fail(FWUPD_IS_RELEASE(self)); + g_return_if_fail(tag != NULL); + for (guint i = 0; i < priv->tags->len; i++) { + const gchar *tag_tmp = g_ptr_array_index(priv->tags, i); + if (g_strcmp0(tag_tmp, tag) == 0) + return; + } + g_ptr_array_add(priv->tags, g_strdup(tag)); +} + +/** + * fwupd_release_has_tag: + * @self: a #FwupdRelease + * @tag: the update tag, e.g. `vendor-factory-2021q1` + * + * Finds out if the release has a specific tag. + * + * Returns: %TRUE if the release matches + * + * Since: 1.7.3 + **/ +gboolean +fwupd_release_has_tag(FwupdRelease *self, const gchar *tag) +{ + FwupdReleasePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(FWUPD_IS_RELEASE(self), FALSE); + g_return_val_if_fail(tag != NULL, FALSE); + for (guint i = 0; i < priv->tags->len; i++) { + const gchar *tag_tmp = g_ptr_array_index(priv->tags, i); + if (g_strcmp0(tag_tmp, tag) == 0) + return TRUE; + } + return FALSE; +} + /** * fwupd_release_get_metadata: * @self: a #FwupdRelease @@ -1651,6 +1718,13 @@ fwupd_release_to_variant(FwupdRelease *self) FWUPD_RESULT_KEY_URI, g_variant_new_string(g_ptr_array_index(priv->locations, 0))); } + if (priv->tags->len > 0) { + g_variant_builder_add( + &builder, + "{sv}", + FWUPD_RESULT_KEY_TAGS, + g_variant_new_strv((const gchar *const *)priv->tags->pdata, priv->tags->len)); + } if (priv->homepage != NULL) { g_variant_builder_add(&builder, "{sv}", @@ -1797,6 +1871,12 @@ fwupd_release_from_key_value(FwupdRelease *self, const gchar *key, GVariant *val fwupd_release_add_location(self, strv[i]); return; } + if (g_strcmp0(key, FWUPD_RESULT_KEY_TAGS) == 0) { + g_autofree const gchar **strv = g_variant_get_strv(value, NULL); + for (guint i = 0; strv[i] != NULL; i++) + fwupd_release_add_tag(self, strv[i]); + return; + } if (g_strcmp0(key, FWUPD_RESULT_KEY_URI) == 0) { fwupd_release_add_location(self, g_variant_get_string(value, NULL)); return; @@ -1974,6 +2054,15 @@ fwupd_release_to_json(FwupdRelease *self, JsonBuilder *builder) } json_builder_end_array(builder); } + if (priv->tags->len > 0) { + json_builder_set_member_name(builder, FWUPD_RESULT_KEY_TAGS); + json_builder_begin_array(builder); + for (guint i = 0; i < priv->tags->len; i++) { + const gchar *tag = g_ptr_array_index(priv->tags, i); + json_builder_add_string_value(builder, tag); + } + json_builder_end_array(builder); + } fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_LICENSE, priv->license); if (priv->size > 0) fwupd_common_json_add_int(builder, FWUPD_RESULT_KEY_SIZE, priv->size); @@ -2073,6 +2162,10 @@ fwupd_release_to_string(FwupdRelease *self) g_autofree gchar *checksum_display = fwupd_checksum_format_for_display(checksum); fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_CHECKSUM, checksum_display); } + for (guint i = 0; i < priv->tags->len; i++) { + const gchar *tag = g_ptr_array_index(priv->tags, i); + fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_TAGS, tag); + } fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_LICENSE, priv->license); fwupd_pad_kv_siz(str, FWUPD_RESULT_KEY_SIZE, priv->size); fwupd_pad_kv_unx(str, FWUPD_RESULT_KEY_CREATED, priv->created); @@ -2122,6 +2215,7 @@ fwupd_release_init(FwupdRelease *self) priv->categories = g_ptr_array_new_with_free_func(g_free); priv->issues = g_ptr_array_new_with_free_func(g_free); priv->checksums = g_ptr_array_new_with_free_func(g_free); + priv->tags = g_ptr_array_new_with_free_func(g_free); priv->locations = g_ptr_array_new_with_free_func(g_free); priv->metadata = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); } @@ -2156,6 +2250,7 @@ fwupd_release_finalize(GObject *object) g_ptr_array_unref(priv->categories); g_ptr_array_unref(priv->issues); g_ptr_array_unref(priv->checksums); + g_ptr_array_unref(priv->tags); g_hash_table_unref(priv->metadata); G_OBJECT_CLASS(fwupd_release_parent_class)->finalize(object); diff --git a/libfwupd/fwupd-release.h b/libfwupd/fwupd-release.h index 2893e1049..df60e8739 100644 --- a/libfwupd/fwupd-release.h +++ b/libfwupd/fwupd-release.h @@ -62,6 +62,12 @@ void fwupd_release_add_checksum(FwupdRelease *self, const gchar *checksum); gboolean fwupd_release_has_checksum(FwupdRelease *self, const gchar *checksum); +GPtrArray * +fwupd_release_get_tags(FwupdRelease *self); +void +fwupd_release_add_tag(FwupdRelease *self, const gchar *tag); +gboolean +fwupd_release_has_tag(FwupdRelease *self, const gchar *tag); GHashTable * fwupd_release_get_metadata(FwupdRelease *self); diff --git a/libfwupd/fwupd-self-test.c b/libfwupd/fwupd-self-test.c index 281fb8e21..5ffd843da 100644 --- a/libfwupd/fwupd-self-test.c +++ b/libfwupd/fwupd-self-test.c @@ -424,6 +424,8 @@ fwupd_device_func(void) fwupd_release_set_size(rel, 1024); fwupd_release_add_location(rel, "http://foo.com"); fwupd_release_add_location(rel, "ftp://foo.com"); + fwupd_release_add_tag(rel, "vendor-2021q1"); + fwupd_release_add_tag(rel, "vendor-2021q2"); fwupd_release_set_version(rel, "1.2.3"); fwupd_device_add_release(dev, rel); str = fwupd_device_to_string(dev); @@ -456,6 +458,8 @@ fwupd_device_func(void) " Version: 1.2.3\n" " Filename: firmware.bin\n" " Checksum: SHA1(deadbeef)\n" + " Tags: vendor-2021q1\n" + " Tags: vendor-2021q2\n" " Size: 1.0 kB\n" " Uri: http://foo.com\n" " Uri: ftp://foo.com\n" @@ -505,6 +509,10 @@ fwupd_device_func(void) " \"Checksum\" : [\n" " \"deadbeef\"\n" " ],\n" + " \"Tags\" : [\n" + " \"vendor-2021q1\",\n" + " \"vendor-2021q2\"\n" + " ],\n" " \"Size\" : 1024,\n" " \"Locations\" : [\n" " \"http://foo.com\",\n" diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index eac9c717a..b291e9683 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -733,3 +733,11 @@ LIBFWUPD_1.7.2 { fwupd_release_set_id; local: *; } LIBFWUPD_1.7.1; + +LIBFWUPD_1.7.3 { + global: + fwupd_release_add_tag; + fwupd_release_get_tags; + fwupd_release_has_tag; + local: *; +} LIBFWUPD_1.7.2; diff --git a/src/fu-engine.c b/src/fu-engine.c index a2b7b6428..45a9bbf7f 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -4239,6 +4239,7 @@ fu_engine_get_result_from_component(FuEngine *self, g_autoptr(FwupdRelease) rel = NULL; g_autoptr(GError) error_local = NULL; g_autoptr(GPtrArray) provides = NULL; + g_autoptr(GPtrArray) tags = NULL; g_autoptr(XbNode) description = NULL; g_autoptr(XbNode) release = NULL; #if LIBXMLB_CHECK_VERSION(0, 2, 0) @@ -4286,6 +4287,15 @@ fu_engine_get_result_from_component(FuEngine *self, return NULL; } + /* add tags */ + tags = xb_node_query(component, "tags/tag[@namespace=$'lvfs']", 0, NULL); + if (tags != NULL) { + for (guint i = 0; i < tags->len; i++) { + XbNode *tag = g_ptr_array_index(tags, i); + fwupd_release_add_tag(rel, xb_node_get_text(tag)); + } + } + /* check we can install it */ task = fu_install_task_new(NULL, component); if (!fu_engine_check_requirements(self, diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 796cb6a18..4d85fa9c7 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1643,6 +1643,7 @@ gchar * fu_util_release_to_string(FwupdRelease *rel, guint idt) { GPtrArray *issues = fwupd_release_get_issues(rel); + GPtrArray *tags = fwupd_release_get_tags(rel); GString *str = g_string_new(NULL); guint64 flags = fwupd_release_get_flags(rel); g_autoptr(GString) flags_str = g_string_new(NULL); @@ -1785,6 +1786,19 @@ fu_util_release_to_string(FwupdRelease *rel, guint idt) fu_common_string_append_kv(str, idt + 1, "", issue); } } + for (guint i = 0; i < tags->len; i++) { + const gchar *tag = g_ptr_array_index(tags, i); + if (i == 0) { + fu_common_string_append_kv( + str, + idt + 1, + /* TRANSLATORS: release tag set for release, e.g. lenovo-2021q3 */ + ngettext("Tag", "Tags", tags->len), + tag); + } else { + fu_common_string_append_kv(str, idt + 1, "", tag); + } + } return g_string_free(str, FALSE); }