diff options
author | Richard Hughes <richard@hughsie.com> | 2016-12-21 13:58:23 +0000 |
---|---|---|
committer | Richard Hughes <richard@hughsie.com> | 2016-12-21 15:21:59 +0000 |
commit | e6854025cebe9740b7e5424c12dfbfb4d179e590 (patch) | |
tree | abb500abc6442118b2aaa00b8fd41800494ee5ea | |
parent | 2519ebef3fdfe57fd5e17b604dbe277e8b443637 (diff) | |
download | appstream-glib-wip/hughsie/AsRequire.tar.gz |
Add AsRequire as a way to store runtime requirementswip/hughsie/AsRequire
This can be used by fwupd to prevent incompatible firmware being installed on
devices, and GNOME Software for limiting artificial fake components to
supported plugin versions.
-rw-r--r-- | libappstream-glib/Makefile.am | 5 | ||||
-rw-r--r-- | libappstream-glib/appstream-glib.h | 1 | ||||
-rw-r--r-- | libappstream-glib/as-app.c | 100 | ||||
-rw-r--r-- | libappstream-glib/as-app.h | 7 | ||||
-rw-r--r-- | libappstream-glib/as-require-private.h | 48 | ||||
-rw-r--r-- | libappstream-glib/as-require.c | 471 | ||||
-rw-r--r-- | libappstream-glib/as-require.h | 121 | ||||
-rw-r--r-- | libappstream-glib/as-self-test.c | 77 | ||||
-rw-r--r-- | libappstream-glib/as-tag.c | 1 | ||||
-rw-r--r-- | libappstream-glib/as-tag.gperf | 1 | ||||
-rw-r--r-- | libappstream-glib/as-tag.h | 2 |
11 files changed, 834 insertions, 0 deletions
diff --git a/libappstream-glib/Makefile.am b/libappstream-glib/Makefile.am index 26161e7..98a12bb 100644 --- a/libappstream-glib/Makefile.am +++ b/libappstream-glib/Makefile.am @@ -83,6 +83,7 @@ libappstream_glib_include_HEADERS = \ as-profile.h \ as-provide.h \ as-release.h \ + as-require.h \ as-review.h \ as-screenshot.h \ as-store.h \ @@ -128,6 +129,8 @@ libappstream_glib_la_SOURCES = \ as-ref-string.h \ as-release.c \ as-release-private.h \ + as-require.c \ + as-require-private.h \ as-review.c \ as-review-private.h \ as-resources.c \ @@ -226,6 +229,8 @@ introspection_sources = \ as-provide.h \ as-release.c \ as-release.h \ + as-require.c \ + as-require.h \ as-review.c \ as-review.h \ as-screenshot.c \ diff --git a/libappstream-glib/appstream-glib.h b/libappstream-glib/appstream-glib.h index 785affb..3082b6e 100644 --- a/libappstream-glib/appstream-glib.h +++ b/libappstream-glib/appstream-glib.h @@ -39,6 +39,7 @@ #include <as-profile.h> #include <as-provide.h> #include <as-release.h> +#include <as-require.h> #include <as-review.h> #include <as-screenshot.h> #include <as-store.h> diff --git a/libappstream-glib/as-app.c b/libappstream-glib/as-app.c index 77ec9a1..1d6fbe5 100644 --- a/libappstream-glib/as-app.c +++ b/libappstream-glib/as-app.c @@ -46,6 +46,7 @@ #include "as-provide-private.h" #include "as-release-private.h" #include "as-ref-string.h" +#include "as-require-private.h" #include "as-review-private.h" #include "as-screenshot-private.h" #include "as-stemmer.h" @@ -87,6 +88,7 @@ typedef struct GPtrArray *bundles; /* of AsBundle */ GPtrArray *translations; /* of AsTranslation */ GPtrArray *suggests; /* of AsSuggest */ + GPtrArray *requires; /* of AsRequire */ GPtrArray *vetos; /* of AsRefString */ AsAppSourceKind source_kind; AsAppScope scope; @@ -513,6 +515,7 @@ as_app_finalize (GObject *object) g_ptr_array_unref (priv->bundles); g_ptr_array_unref (priv->translations); g_ptr_array_unref (priv->suggests); + g_ptr_array_unref (priv->requires); g_ptr_array_unref (priv->vetos); G_OBJECT_CLASS (as_app_parent_class)->finalize (object); @@ -543,6 +546,7 @@ as_app_init (AsApp *app) priv->bundles = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); priv->translations = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); priv->suggests = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + priv->requires = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); priv->vetos = g_ptr_array_new_with_free_func ((GDestroyNotify) as_ref_string_unref); priv->comments = g_hash_table_new_full (g_str_hash, g_str_equal, @@ -1237,6 +1241,50 @@ as_app_get_suggests (AsApp *app) } /** + * as_app_get_requires: + * @app: a #AsApp instance. + * + * Gets any requires the application has defined. A rquirement could be that + * a firmware version has to be below a defined version or that another + * application is required to be installed. + * + * Returns: (element-type AsRequire) (transfer none): an array + * + * Since: 0.6.7 + **/ +GPtrArray * +as_app_get_requires (AsApp *app) +{ + AsAppPrivate *priv = GET_PRIVATE (app); + return priv->requires; +} + +/** + * as_app_get_require_by_value: + * @app: a #AsApp instance. + * @kind: a #AsRequireKind, e.g. %AS_REQUIRE_KIND_FIRMWARE + * @value: a string, or NULL, e.g. `bootloader` + * + * Gets a specific requirement for the application. + * + * Returns: (transfer none): A #AsRequire, or %NULL for not found + * + * Since: 0.6.7 + **/ +AsRequire * +as_app_get_require_by_value (AsApp *app, AsRequireKind kind, const gchar *value) +{ + AsAppPrivate *priv = GET_PRIVATE (app); + for (guint i = 0; i < priv->requires->len; i++) { + AsRequire *req = g_ptr_array_index (priv->requires, i); + if (as_require_get_kind (req) == kind && + g_strcmp0 (as_require_get_value (req), value) == 0) + return req; + } + return NULL; +} + +/** * as_app_get_names: * @app: a #AsApp instance. * @@ -3181,6 +3229,22 @@ as_app_add_suggest (AsApp *app, AsSuggest *suggest) } /** + * as_app_add_require: + * @app: a #AsApp instance. + * @require: a #AsRequire instance. + * + * Adds a require to an application. + * + * Since: 0.6.7 + **/ +void +as_app_add_require (AsApp *app, AsRequire *require) +{ + AsAppPrivate *priv = GET_PRIVATE (app); + g_ptr_array_add (priv->requires, g_object_ref (require)); +} + +/** * as_app_add_pkgname: * @app: a #AsApp instance. * @pkgname: the package name. @@ -3562,6 +3626,17 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags) } } + /* requires */ + if (flags & AS_APP_SUBSUME_FLAG_SUGGESTS) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->requires->len > 0) + g_ptr_array_set_size (papp->requires, 0); + for (i = 0; i < priv->requires->len; i++) { + AsRequire *require = g_ptr_array_index (priv->requires, i); + as_app_add_require (app, require); + } + } + /* releases */ if (flags & AS_APP_SUBSUME_FLAG_RELEASES) { if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && @@ -4030,6 +4105,15 @@ as_app_node_insert (AsApp *app, GNode *parent, AsNodeContext *ctx) as_suggest_node_insert (suggest, node_app, ctx); } + /* <requires> */ + if (priv->requires->len > 0) { + node_tmp = as_node_insert (node_app, "requires", NULL, 0, NULL); + for (i = 0; i < priv->requires->len; i++) { + AsRequire *require = g_ptr_array_index (priv->requires, i); + as_require_node_insert (require, node_tmp, ctx); + } + } + /* <name> */ as_node_insert_localized (node_app, "name", priv->names, @@ -4311,6 +4395,21 @@ as_app_node_parse_child (AsApp *app, GNode *n, AsAppParseFlags flags, break; } + /* <requires> */ + case AS_TAG_REQUIRES: + if (!(flags & AS_APP_PARSE_FLAG_APPEND_DATA)) + g_ptr_array_set_size (priv->requires, 0); + for (c = n->children; c != NULL; c = c->next) { + g_autoptr(AsRequire) ic = NULL; + ic = as_require_new (); + if (!as_require_node_parse (ic, c, ctx, error)) + return FALSE; + as_app_add_require (app, ic); + } + if (n->children == NULL) + priv->problems |= AS_APP_PROBLEM_EXPECTED_CHILDREN; + break; + /* <name> */ case AS_TAG_NAME: xml_lang = as_node_fix_locale (as_node_get_attribute (n, "xml:lang")); @@ -4777,6 +4876,7 @@ as_app_node_parse_full (AsApp *app, GNode *node, AsAppParseFlags flags, g_ptr_array_set_size (priv->bundles, 0); g_ptr_array_set_size (priv->translations, 0); g_ptr_array_set_size (priv->suggests, 0); + g_ptr_array_set_size (priv->requires, 0); g_ptr_array_set_size (priv->content_ratings, 0); g_hash_table_remove_all (priv->keywords); } diff --git a/libappstream-glib/as-app.h b/libappstream-glib/as-app.h index 5110f49..ca62e36 100644 --- a/libappstream-glib/as-app.h +++ b/libappstream-glib/as-app.h @@ -34,6 +34,7 @@ #include "as-provide.h" #include "as-release.h" #include "as-screenshot.h" +#include "as-require.h" #include "as-review.h" #include "as-suggest.h" #include "as-content-rating.h" @@ -497,6 +498,7 @@ GPtrArray *as_app_get_icons (AsApp *app); GPtrArray *as_app_get_bundles (AsApp *app); GPtrArray *as_app_get_translations (AsApp *app); GPtrArray *as_app_get_suggests (AsApp *app); +GPtrArray *as_app_get_requires (AsApp *app); GHashTable *as_app_get_names (AsApp *app); GHashTable *as_app_get_comments (AsApp *app); GHashTable *as_app_get_developer_names (AsApp *app); @@ -628,6 +630,8 @@ void as_app_add_translation (AsApp *app, AsTranslation *translation); void as_app_add_suggest (AsApp *app, AsSuggest *suggest); +void as_app_add_require (AsApp *app, + AsRequire *require); void as_app_add_language (AsApp *app, gint percentage, const gchar *locale); @@ -685,6 +689,9 @@ AsBundle *as_app_get_bundle_default (AsApp *app); AsRelease *as_app_get_release (AsApp *app, const gchar *version); AsRelease *as_app_get_release_default (AsApp *app); +AsRequire *as_app_get_require_by_value (AsApp *app, + AsRequireKind kind, + const gchar *value); gboolean as_app_convert_icons (AsApp *app, AsIconKind kind, GError **error); diff --git a/libappstream-glib/as-require-private.h b/libappstream-glib/as-require-private.h new file mode 100644 index 0000000..98ff8b4 --- /dev/null +++ b/libappstream-glib/as-require-private.h @@ -0,0 +1,48 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2016 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU Lesser General Public License Version 2.1 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if !defined (__APPSTREAM_GLIB_PRIVATE_H) && !defined (AS_COMPILATION) +#error "Only <appstream-glib.h> can be included directly." +#endif + +#ifndef __AS_REQUIRE_PRIVATE_H +#define __AS_REQUIRE_PRIVATE_H + +#include "as-require.h" +#include "as-node-private.h" + +G_BEGIN_DECLS + +GNode *as_require_node_insert (AsRequire *require, + GNode *parent, + AsNodeContext *ctx); +gboolean as_require_node_parse (AsRequire *require, + GNode *node, + AsNodeContext *ctx, + GError **error); +gboolean as_require_node_parse_dep11 (AsRequire *require, + GNode *node, + AsNodeContext *ctx, + GError **error); + +G_END_DECLS + +#endif /* __AS_REQUIRE_PRIVATE_H */ diff --git a/libappstream-glib/as-require.c b/libappstream-glib/as-require.c new file mode 100644 index 0000000..64bca14 --- /dev/null +++ b/libappstream-glib/as-require.c @@ -0,0 +1,471 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2016 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU Lesser General Public License Version 2.1 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * SECTION:as-require + * @short_description: Object representing a single requirement. + * @include: appstream-glib.h + * @stability: Unstable + * + * Requirements are things the component needs to be valid. + * + * See also: #AsApp + */ + +#include "config.h" + +#include "as-require-private.h" +#include "as-node-private.h" +#include "as-ref-string.h" +#include "as-utils-private.h" + +typedef struct +{ + AsRequireKind kind; + AsRequireCompare compare; + AsRefString *version; /* utf8 */ + AsRefString *value; /* utf8 */ +} AsRequirePrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (AsRequire, as_require, G_TYPE_OBJECT) + +#define GET_PRIVATE(o) (as_require_get_instance_private (o)) + +static void +as_require_finalize (GObject *object) +{ + AsRequire *require = AS_REQUIRE (object); + AsRequirePrivate *priv = GET_PRIVATE (require); + + if (priv->version != NULL) + as_ref_string_unref (priv->version); + if (priv->value != NULL) + as_ref_string_unref (priv->value); + + G_OBJECT_CLASS (as_require_parent_class)->finalize (object); +} + +static void +as_require_init (AsRequire *require) +{ +// AsRequirePrivate *priv = GET_PRIVATE (require); +} + +static void +as_require_class_init (AsRequireClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = as_require_finalize; +} + +/** + * as_require_kind_from_string: + * @kind: the string. + * + * Converts the text representation to an enumerated value. + * + * Returns: (transfer full): a #AsRequireKind, or %AS_REQUIRE_KIND_UNKNOWN for unknown. + * + * Since: 0.6.7 + **/ +AsRequireKind +as_require_kind_from_string (const gchar *kind) +{ + if (g_strcmp0 (kind, "id") == 0) + return AS_REQUIRE_KIND_ID; + if (g_strcmp0 (kind, "firmware") == 0) + return AS_REQUIRE_KIND_FIRMWARE; + return AS_REQUIRE_KIND_UNKNOWN; +} + +/** + * as_require_kind_to_string: + * @kind: the #AsRequireKind. + * + * Converts the enumerated value to an text representation. + * + * Returns: string version of @kind + * + * Since: 0.6.7 + **/ +const gchar * +as_require_kind_to_string (AsRequireKind kind) +{ + if (kind == AS_REQUIRE_KIND_ID) + return "id"; + if (kind == AS_REQUIRE_KIND_FIRMWARE) + return "firmware"; + return NULL; +} + +/** + * as_require_compare_from_string: + * @compare: the string. + * + * Converts the text representation to an enumerated value. + * + * Returns: (transfer full): a #AsRequireCompare, or + * %AS_REQUIRE_COMPARE_UNKNOWN for unknown. + * + * Since: 0.6.7 + **/ +AsRequireCompare +as_require_compare_from_string (const gchar *compare) +{ + if (g_strcmp0 (compare, "eq") == 0) + return AS_REQUIRE_COMPARE_EQ; + if (g_strcmp0 (compare, "ne") == 0) + return AS_REQUIRE_COMPARE_NE; + if (g_strcmp0 (compare, "gt") == 0) + return AS_REQUIRE_COMPARE_GT; + if (g_strcmp0 (compare, "lt") == 0) + return AS_REQUIRE_COMPARE_LT; + if (g_strcmp0 (compare, "ge") == 0) + return AS_REQUIRE_COMPARE_GE; + if (g_strcmp0 (compare, "le") == 0) + return AS_REQUIRE_COMPARE_LE; + return AS_REQUIRE_COMPARE_UNKNOWN; +} + +/** + * as_require_compare_to_string: + * @compare: the #AsRequireCompare. + * + * Converts the enumerated value to an text representation. + * + * Returns: string version of @compare + * + * Since: 0.6.7 + **/ +const gchar * +as_require_compare_to_string (AsRequireCompare compare) +{ + if (compare == AS_REQUIRE_COMPARE_EQ) + return "eq"; + if (compare == AS_REQUIRE_COMPARE_NE) + return "ne"; + if (compare == AS_REQUIRE_COMPARE_GT) + return "gt"; + if (compare == AS_REQUIRE_COMPARE_LT) + return "lt"; + if (compare == AS_REQUIRE_COMPARE_GE) + return "ge"; + if (compare == AS_REQUIRE_COMPARE_LE) + return "le"; + return NULL; +} + +/** + * as_require_get_version: + * @require: a #AsRequire instance. + * + * Gets the require version if set. + * + * Returns: the version, e.g. "0.1.2" + * + * Since: 0.6.7 + **/ +const gchar * +as_require_get_version (AsRequire *require) +{ + AsRequirePrivate *priv = GET_PRIVATE (require); + return priv->version; +} + +/** + * as_require_get_value: + * @require: a #AsRequire instance. + * + * Gets the require value if set. + * + * Returns: the value, e.g. "bootloader" + * + * Since: 0.6.7 + **/ +const gchar * +as_require_get_value (AsRequire *require) +{ + AsRequirePrivate *priv = GET_PRIVATE (require); + return priv->value; +} + +/** + * as_require_get_kind: + * @require: a #AsRequire instance. + * + * Gets the require kind. + * + * Returns: the #AsRequireKind + * + * Since: 0.6.7 + **/ +AsRequireKind +as_require_get_kind (AsRequire *require) +{ + AsRequirePrivate *priv = GET_PRIVATE (require); + return priv->kind; +} + +/** + * as_require_set_kind: + * @require: a #AsRequire instance. + * @kind: the #AsRequireKind, e.g. %AS_REQUIRE_KIND_ID. + * + * Sets the require kind. + * + * Since: 0.6.7 + **/ +void +as_require_set_kind (AsRequire *require, AsRequireKind kind) +{ + AsRequirePrivate *priv = GET_PRIVATE (require); + priv->kind = kind; +} + +/** + * as_require_get_compare: + * @require: a #AsRequire instance. + * + * Gets the require version comparison type. + * + * Returns: the #AsRequireKind + * + * Since: 0.6.7 + **/ +AsRequireCompare +as_require_get_compare (AsRequire *require) +{ + AsRequirePrivate *priv = GET_PRIVATE (require); + return priv->compare; +} + +/** + * as_require_set_compare: + * @require: a #AsRequire instance. + * @compare: the #AsRequireKind, e.g. %AS_REQUIRE_KIND_ID. + * + * Sets the require version comparison type. + * + * Since: 0.6.7 + **/ +void +as_require_set_compare (AsRequire *require, AsRequireCompare compare) +{ + AsRequirePrivate *priv = GET_PRIVATE (require); + priv->compare = compare; +} + +/** + * as_require_set_version: + * @require: a #AsRequire instance. + * @version: an version number, e.g. `0.1.2` + * + * Sets the require version. + * + * Since: 0.6.7 + **/ +void +as_require_set_version (AsRequire *require, const gchar *version) +{ + AsRequirePrivate *priv = GET_PRIVATE (require); + if (priv->version != NULL) + as_ref_string_unref (priv->version); + priv->version = as_ref_string_new (version); +} + +/** + * as_require_set_value: + * @require: a #AsRequire instance. + * @value: an require version, e.g. `firmware` + * + * Sets the require value. + * + * Since: 0.6.7 + **/ +void +as_require_set_value (AsRequire *require, const gchar *value) +{ + AsRequirePrivate *priv = GET_PRIVATE (require); + if (priv->value != NULL) + as_ref_string_unref (priv->value); + priv->value = as_ref_string_new (value); +} + + +/** + * as_require_version_compare: + * @require: a #AsRequire instance. + * @version: a version number, e.g. `0.1.3` + * @error: A #GError or %NULL + * + * Compares the version number of the requirement with a predicate. + * + * Returns: %TRUE if the predicate was true + * + * Since: 0.6.7 + **/ +gboolean +as_require_version_compare (AsRequire *require, + const gchar *version, + GError **error) +{ + AsRequirePrivate *priv = GET_PRIVATE (require); + gint tmp = as_utils_vercmp (version, priv->version); + gboolean ret = FALSE; + + switch (priv->compare) { + case AS_REQUIRE_COMPARE_EQ: + ret = tmp == 0; + break; + case AS_REQUIRE_COMPARE_NE: + ret = tmp != 0; + break; + case AS_REQUIRE_COMPARE_LT: + ret = tmp < 0; + break; + case AS_REQUIRE_COMPARE_GT: + ret = tmp > 0; + break; + case AS_REQUIRE_COMPARE_LE: + ret = tmp <= 0; + break; + case AS_REQUIRE_COMPARE_GE: + ret = tmp >= 0; + break; + default: + break; + } + + /* set error */ + if (!ret && error != NULL) { + g_set_error (error, + AS_UTILS_ERROR, + AS_UTILS_ERROR_FAILED, + "failed predicate [%s %s %s]", + priv->version, + as_require_compare_to_string (priv->compare), + version); + } + return ret; +} + +/** + * as_require_node_insert: (skip) + * @require: a #AsRequire instance. + * @parent: the parent #GNode to use.. + * @ctx: the #AsNodeContext + * + * Inserts the require into the DOM tree. + * + * Returns: (transfer none): A populated #GNode + * + * Since: 0.6.7 + **/ +GNode * +as_require_node_insert (AsRequire *require, GNode *parent, AsNodeContext *ctx) +{ + AsRequirePrivate *priv = GET_PRIVATE (require); + GNode *n; + + /* don't know what to do here */ + if (priv->kind == AS_REQUIRE_KIND_UNKNOWN) + return NULL; + + n = as_node_insert (parent, as_require_kind_to_string (priv->kind), NULL, + AS_NODE_INSERT_FLAG_NONE, + NULL); + if (priv->compare != AS_REQUIRE_COMPARE_UNKNOWN) { + as_node_add_attribute (n, "compare", + as_require_compare_to_string (priv->compare)); + } + if (priv->version != NULL) + as_node_add_attribute (n, "version", priv->version); + if (priv->value != NULL) + as_node_set_data (n, priv->value, AS_NODE_INSERT_FLAG_NONE); + return n; +} + +/** + * as_require_node_parse: + * @require: a #AsRequire instance. + * @node: a #GNode. + * @ctx: a #AsNodeContext. + * @error: A #GError or %NULL. + * + * Populates the object from a DOM node. + * + * Returns: %TRUE for success + * + * Since: 0.6.7 + **/ +gboolean +as_require_node_parse (AsRequire *require, GNode *node, + AsNodeContext *ctx, GError **error) +{ + AsRequirePrivate *priv = GET_PRIVATE (require); + const gchar *tmp; + tmp = as_node_get_name (node); + if (tmp != NULL) + as_require_set_kind (require, as_require_kind_from_string (tmp)); + tmp = as_node_get_attribute (node, "compare"); + if (tmp != NULL) + as_require_set_compare (require, as_require_compare_from_string (tmp)); + as_ref_string_assign (&priv->version, as_node_get_attribute (node, "version")); + as_ref_string_assign (&priv->value, as_node_get_data (node)); + return TRUE; +} + +/** + * as_require_node_parse_dep11: + * @require: a #AsRequire instance. + * @node: a #GNode. + * @ctx: a #AsNodeContext. + * @error: A #GError or %NULL. + * + * Populates the object from a DEP-11 node. + * + * Returns: %TRUE for success + * + * Since: 0.6.7 + **/ +gboolean +as_require_node_parse_dep11 (AsRequire *im, GNode *node, + AsNodeContext *ctx, GError **error) +{ + return TRUE; +} + +/** + * as_require_new: + * + * Creates a new #AsRequire. + * + * Returns: (transfer full): a #AsRequire + * + * Since: 0.6.7 + **/ +AsRequire * +as_require_new (void) +{ + AsRequire *require; + require = g_object_new (AS_TYPE_REQUIRE, NULL); + return AS_REQUIRE (require); +} diff --git a/libappstream-glib/as-require.h b/libappstream-glib/as-require.h new file mode 100644 index 0000000..92a48b5 --- /dev/null +++ b/libappstream-glib/as-require.h @@ -0,0 +1,121 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2016 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU Lesser General Public License Version 2.1 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if !defined (__APPSTREAM_GLIB_H) && !defined (AS_COMPILATION) +#error "Only <appstream-glib.h> can be included directly." +#endif + +#ifndef __AS_REQUIRE_H +#define __AS_REQUIRE_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define AS_TYPE_REQUIRE (as_require_get_type ()) +G_DECLARE_DERIVABLE_TYPE (AsRequire, as_require, AS, REQUIRE, GObject) + +struct _AsRequireClass +{ + GObjectClass parent_class; + /*< private >*/ + void (*_as_reserved1) (void); + void (*_as_reserved2) (void); + void (*_as_reserved3) (void); + void (*_as_reserved4) (void); + void (*_as_reserved5) (void); + void (*_as_reserved6) (void); + void (*_as_reserved7) (void); + void (*_as_reserved8) (void); +}; + +/** + * AsRequireKind: + * @AS_REQUIRE_KIND_UNKNOWN: Type invalid or not known + * @AS_REQUIRE_KIND_ID: Component ID + * @AS_REQUIRE_KIND_FIRMWARE: Device firmware version + * + * The require type. + **/ +typedef enum { + AS_REQUIRE_KIND_UNKNOWN, + AS_REQUIRE_KIND_ID, + AS_REQUIRE_KIND_FIRMWARE, + /*< private >*/ + AS_REQUIRE_KIND_LAST +} AsRequireKind; + +/** + * AsRequireCompare: + * @AS_REQUIRE_COMPARE_UNKNOWN: Comparison predicate invalid or not known + * @AS_REQUIRE_COMPARE_EQ: Equal to + * @AS_REQUIRE_COMPARE_NE: Not equal to + * @AS_REQUIRE_COMPARE_LT: Less than + * @AS_REQUIRE_COMPARE_GT: Greater than + * @AS_REQUIRE_COMPARE_LE: Less than or equal to + * @AS_REQUIRE_COMPARE_GE: Greater than or equal to + * + * The relational comparison type. + **/ +typedef enum { + AS_REQUIRE_COMPARE_UNKNOWN, + AS_REQUIRE_COMPARE_EQ, + AS_REQUIRE_COMPARE_NE, + AS_REQUIRE_COMPARE_LT, + AS_REQUIRE_COMPARE_GT, + AS_REQUIRE_COMPARE_LE, + AS_REQUIRE_COMPARE_GE, + /*< private >*/ + AS_REQUIRE_COMPARE_LAST +} AsRequireCompare; + +AsRequire *as_require_new (void); + +/* helpers */ +AsRequireKind as_require_kind_from_string (const gchar *kind); +const gchar *as_require_kind_to_string (AsRequireKind kind); +AsRequireCompare as_require_compare_from_string (const gchar *compare); +const gchar *as_require_compare_to_string (AsRequireCompare compare); + +/* getters */ +AsRequireKind as_require_get_kind (AsRequire *require); +AsRequireCompare as_require_get_compare (AsRequire *require); +const gchar *as_require_get_version (AsRequire *require); +const gchar *as_require_get_value (AsRequire *require); + +/* setters */ +void as_require_set_kind (AsRequire *require, + AsRequireKind kind); +void as_require_set_compare (AsRequire *require, + AsRequireCompare compare); +void as_require_set_version (AsRequire *require, + const gchar *version); +void as_require_set_value (AsRequire *require, + const gchar *value); + +/* object methods */ +gboolean as_require_version_compare (AsRequire *require, + const gchar *version, + GError **error); + +G_END_DECLS + +#endif /* __AS_REQUIRE_H */ diff --git a/libappstream-glib/as-self-test.c b/libappstream-glib/as-self-test.c index ae002b4..6072f24 100644 --- a/libappstream-glib/as-self-test.c +++ b/libappstream-glib/as-self-test.c @@ -35,6 +35,7 @@ #include "as-enums.h" #include "as-icon-private.h" #include "as-image-private.h" +#include "as-require-private.h" #include "as-review-private.h" #include "as-markup.h" #include "as-monitor.h" @@ -1240,6 +1241,81 @@ as_test_review_func (void) } static void +as_test_require_func (void) +{ + GError *error = NULL; + AsNode *n; + AsNode *root; + const gchar *src = + "<component type=\"desktop\">\n" + "<requires>\n" + "<id>gimp.desktop</id>\n" + "<firmware compare=\"ge\" version=\"0.1.2\">bootloader</firmware>\n" + "<firmware compare=\"eq\" version=\"1.0.0\">runtime</firmware>\n" + "</requires>\n" + "</component>\n"; + gboolean ret; + GPtrArray *requires; + g_autoptr(AsApp) app = NULL; + g_autoptr(AsNodeContext) ctx = NULL; + g_autoptr(AsRequire) require = NULL; + g_autoptr(GString) xml = NULL; + + /* to object */ + root = as_node_from_xml (src, 0, &error); + g_assert_no_error (error); + g_assert (root != NULL); + n = as_node_find (root, "component"); + g_assert (n != NULL); + ctx = as_node_context_new (); + app = as_app_new (); + ret = as_app_node_parse (app, n, ctx, &error); + g_assert_no_error (error); + g_assert (ret); + as_node_unref (root); + + /* verify */ + requires = as_app_get_requires (app); + g_assert_cmpint (requires->len, ==, 3); + require = g_ptr_array_index (requires, 0); + g_assert_cmpint (as_require_get_kind (require), ==, AS_REQUIRE_KIND_ID); + g_assert_cmpint (as_require_get_compare (require), ==, AS_REQUIRE_COMPARE_UNKNOWN); + g_assert_cmpstr (as_require_get_version (require), ==, NULL); + g_assert_cmpstr (as_require_get_value (require), ==, "gimp.desktop"); + require = as_app_get_require_by_value (app, AS_REQUIRE_KIND_FIRMWARE, "bootloader"); + g_assert_cmpint (as_require_get_kind (require), ==, AS_REQUIRE_KIND_FIRMWARE); + g_assert_cmpint (as_require_get_compare (require), ==, AS_REQUIRE_COMPARE_GE); + g_assert_cmpstr (as_require_get_version (require), ==, "0.1.2"); + g_assert_cmpstr (as_require_get_value (require), ==, "bootloader"); + + /* back to node */ + root = as_node_new (); + as_node_context_set_version (ctx, 0.4); + n = as_app_node_insert (app, root, ctx); + xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE); + ret = as_test_compare_lines (xml->str, src, &error); + g_assert_no_error (error); + g_assert (ret); + as_node_unref (root); + + /* test we can go back and forth */ + for (guint i = 0; i < AS_REQUIRE_COMPARE_LAST; i++) { + const gchar *tmp = as_require_compare_to_string (i); + g_assert_cmpint (as_require_compare_from_string (tmp), ==, i); + } + + /* check predicates */ + require = as_require_new (); + as_require_set_version (require, "0.1.2"); + as_require_set_compare (require, AS_REQUIRE_COMPARE_EQ); + g_assert (as_require_version_compare (require, "0.1.2", NULL)); + as_require_set_compare (require, AS_REQUIRE_COMPARE_LT); + g_assert (as_require_version_compare (require, "0.1.1", NULL)); + as_require_set_compare (require, AS_REQUIRE_COMPARE_LE); + g_assert (as_require_version_compare (require, "0.1.2", NULL)); +} + +static void as_test_suggest_func (void) { GError *error = NULL; @@ -5099,6 +5175,7 @@ main (int argc, char **argv) g_test_add_func ("/AppStream/utils{string-replace}", as_test_utils_string_replace_func); g_test_add_func ("/AppStream/tag", as_test_tag_func); g_test_add_func ("/AppStream/provide", as_test_provide_func); + g_test_add_func ("/AppStream/require", as_test_require_func); g_test_add_func ("/AppStream/checksum", as_test_checksum_func); g_test_add_func ("/AppStream/content_rating", as_test_content_rating_func); g_test_add_func ("/AppStream/release", as_test_release_func); diff --git a/libappstream-glib/as-tag.c b/libappstream-glib/as-tag.c index 7d83d83..021425c 100644 --- a/libappstream-glib/as-tag.c +++ b/libappstream-glib/as-tag.c @@ -200,6 +200,7 @@ as_tag_to_string (AsTag tag) "reviewer_name", "reviewer_id", "suggests", + "requires", NULL }; if (tag > AS_TAG_LAST) tag = AS_TAG_LAST; diff --git a/libappstream-glib/as-tag.gperf b/libappstream-glib/as-tag.gperf index 9004b5e..1b5eb79 100644 --- a/libappstream-glib/as-tag.gperf +++ b/libappstream-glib/as-tag.gperf @@ -64,3 +64,4 @@ review, AS_TAG_REVIEW reviewer_name, AS_TAG_REVIEWER_NAME reviewer_id, AS_TAG_REVIEWER_ID suggests, AS_TAG_SUGGESTS +requires, AS_TAG_REQUIRES diff --git a/libappstream-glib/as-tag.h b/libappstream-glib/as-tag.h index a8f4d17..66a4ad1 100644 --- a/libappstream-glib/as-tag.h +++ b/libappstream-glib/as-tag.h @@ -89,6 +89,7 @@ G_BEGIN_DECLS * @AS_TAG_REVIEWER_NAME: `reviewer_name` * @AS_TAG_REVIEWER_ID: `reviewer_id` * @AS_TAG_SUGGESTS: `suggests` + * @AS_TAG_REQUIRES: `requires` * * The tag type. **/ @@ -150,6 +151,7 @@ typedef enum { AS_TAG_REVIEWER_NAME, /* Since: 0.6.1 */ AS_TAG_REVIEWER_ID, /* Since: 0.6.1 */ AS_TAG_SUGGESTS, /* Since: 0.6.1 */ + AS_TAG_REQUIRES, /* Since: 0.6.7 */ /*< private >*/ AS_TAG_LAST } AsTag; |