Add support for LVFS component tags

These allow us to tag components as being part of a set, e.g. a BKC.
This commit is contained in:
Richard Hughes 2021-11-25 09:46:08 +00:00
parent 677c80eb64
commit 4fe8a36729
7 changed files with 149 additions and 0 deletions

View File

@ -34,6 +34,14 @@ G_BEGIN_DECLS
* The D-Bus type signature string is 'as' i.e. an array of strings. * The D-Bus type signature string is 'as' i.e. an array of strings.
**/ **/
#define FWUPD_RESULT_KEY_CHECKSUM "Checksum" #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: * FWUPD_RESULT_KEY_CREATED:
* *

View File

@ -31,6 +31,7 @@ fwupd_release_finalize(GObject *object);
typedef struct { typedef struct {
GPtrArray *checksums; GPtrArray *checksums;
GPtrArray *tags;
GPtrArray *categories; GPtrArray *categories;
GPtrArray *issues; GPtrArray *issues;
GHashTable *metadata; GHashTable *metadata;
@ -488,6 +489,72 @@ fwupd_release_has_checksum(FwupdRelease *self, const gchar *checksum)
return FALSE; 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: * fwupd_release_get_metadata:
* @self: a #FwupdRelease * @self: a #FwupdRelease
@ -1651,6 +1718,13 @@ fwupd_release_to_variant(FwupdRelease *self)
FWUPD_RESULT_KEY_URI, FWUPD_RESULT_KEY_URI,
g_variant_new_string(g_ptr_array_index(priv->locations, 0))); 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) { if (priv->homepage != NULL) {
g_variant_builder_add(&builder, g_variant_builder_add(&builder,
"{sv}", "{sv}",
@ -1797,6 +1871,12 @@ fwupd_release_from_key_value(FwupdRelease *self, const gchar *key, GVariant *val
fwupd_release_add_location(self, strv[i]); fwupd_release_add_location(self, strv[i]);
return; 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) { if (g_strcmp0(key, FWUPD_RESULT_KEY_URI) == 0) {
fwupd_release_add_location(self, g_variant_get_string(value, NULL)); fwupd_release_add_location(self, g_variant_get_string(value, NULL));
return; return;
@ -1974,6 +2054,15 @@ fwupd_release_to_json(FwupdRelease *self, JsonBuilder *builder)
} }
json_builder_end_array(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); fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_LICENSE, priv->license);
if (priv->size > 0) if (priv->size > 0)
fwupd_common_json_add_int(builder, FWUPD_RESULT_KEY_SIZE, priv->size); 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); g_autofree gchar *checksum_display = fwupd_checksum_format_for_display(checksum);
fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_CHECKSUM, checksum_display); 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_str(str, FWUPD_RESULT_KEY_LICENSE, priv->license);
fwupd_pad_kv_siz(str, FWUPD_RESULT_KEY_SIZE, priv->size); fwupd_pad_kv_siz(str, FWUPD_RESULT_KEY_SIZE, priv->size);
fwupd_pad_kv_unx(str, FWUPD_RESULT_KEY_CREATED, priv->created); 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->categories = g_ptr_array_new_with_free_func(g_free);
priv->issues = 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->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->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); 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->categories);
g_ptr_array_unref(priv->issues); g_ptr_array_unref(priv->issues);
g_ptr_array_unref(priv->checksums); g_ptr_array_unref(priv->checksums);
g_ptr_array_unref(priv->tags);
g_hash_table_unref(priv->metadata); g_hash_table_unref(priv->metadata);
G_OBJECT_CLASS(fwupd_release_parent_class)->finalize(object); G_OBJECT_CLASS(fwupd_release_parent_class)->finalize(object);

View File

@ -62,6 +62,12 @@ void
fwupd_release_add_checksum(FwupdRelease *self, const gchar *checksum); fwupd_release_add_checksum(FwupdRelease *self, const gchar *checksum);
gboolean gboolean
fwupd_release_has_checksum(FwupdRelease *self, const gchar *checksum); 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 * GHashTable *
fwupd_release_get_metadata(FwupdRelease *self); fwupd_release_get_metadata(FwupdRelease *self);

View File

@ -424,6 +424,8 @@ fwupd_device_func(void)
fwupd_release_set_size(rel, 1024); fwupd_release_set_size(rel, 1024);
fwupd_release_add_location(rel, "http://foo.com"); fwupd_release_add_location(rel, "http://foo.com");
fwupd_release_add_location(rel, "ftp://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_release_set_version(rel, "1.2.3");
fwupd_device_add_release(dev, rel); fwupd_device_add_release(dev, rel);
str = fwupd_device_to_string(dev); str = fwupd_device_to_string(dev);
@ -456,6 +458,8 @@ fwupd_device_func(void)
" Version: 1.2.3\n" " Version: 1.2.3\n"
" Filename: firmware.bin\n" " Filename: firmware.bin\n"
" Checksum: SHA1(deadbeef)\n" " Checksum: SHA1(deadbeef)\n"
" Tags: vendor-2021q1\n"
" Tags: vendor-2021q2\n"
" Size: 1.0 kB\n" " Size: 1.0 kB\n"
" Uri: http://foo.com\n" " Uri: http://foo.com\n"
" Uri: ftp://foo.com\n" " Uri: ftp://foo.com\n"
@ -505,6 +509,10 @@ fwupd_device_func(void)
" \"Checksum\" : [\n" " \"Checksum\" : [\n"
" \"deadbeef\"\n" " \"deadbeef\"\n"
" ],\n" " ],\n"
" \"Tags\" : [\n"
" \"vendor-2021q1\",\n"
" \"vendor-2021q2\"\n"
" ],\n"
" \"Size\" : 1024,\n" " \"Size\" : 1024,\n"
" \"Locations\" : [\n" " \"Locations\" : [\n"
" \"http://foo.com\",\n" " \"http://foo.com\",\n"

View File

@ -733,3 +733,11 @@ LIBFWUPD_1.7.2 {
fwupd_release_set_id; fwupd_release_set_id;
local: *; local: *;
} LIBFWUPD_1.7.1; } 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;

View File

@ -4239,6 +4239,7 @@ fu_engine_get_result_from_component(FuEngine *self,
g_autoptr(FwupdRelease) rel = NULL; g_autoptr(FwupdRelease) rel = NULL;
g_autoptr(GError) error_local = NULL; g_autoptr(GError) error_local = NULL;
g_autoptr(GPtrArray) provides = NULL; g_autoptr(GPtrArray) provides = NULL;
g_autoptr(GPtrArray) tags = NULL;
g_autoptr(XbNode) description = NULL; g_autoptr(XbNode) description = NULL;
g_autoptr(XbNode) release = NULL; g_autoptr(XbNode) release = NULL;
#if LIBXMLB_CHECK_VERSION(0, 2, 0) #if LIBXMLB_CHECK_VERSION(0, 2, 0)
@ -4286,6 +4287,15 @@ fu_engine_get_result_from_component(FuEngine *self,
return NULL; 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 */ /* check we can install it */
task = fu_install_task_new(NULL, component); task = fu_install_task_new(NULL, component);
if (!fu_engine_check_requirements(self, if (!fu_engine_check_requirements(self,

View File

@ -1643,6 +1643,7 @@ gchar *
fu_util_release_to_string(FwupdRelease *rel, guint idt) fu_util_release_to_string(FwupdRelease *rel, guint idt)
{ {
GPtrArray *issues = fwupd_release_get_issues(rel); GPtrArray *issues = fwupd_release_get_issues(rel);
GPtrArray *tags = fwupd_release_get_tags(rel);
GString *str = g_string_new(NULL); GString *str = g_string_new(NULL);
guint64 flags = fwupd_release_get_flags(rel); guint64 flags = fwupd_release_get_flags(rel);
g_autoptr(GString) flags_str = g_string_new(NULL); 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); 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); return g_string_free(str, FALSE);
} }