summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2016-12-21 13:58:23 +0000
committerRichard Hughes <richard@hughsie.com>2016-12-21 16:01:41 +0000
commit01b9771203fd450741282504c730d296d7b9cce5 (patch)
treec9b8691df2828c9a09d2b6620d5382abea4ede66
parent20f63a5a007d1f6038a2473b7b7901c59584fed1 (diff)
downloadappstream-glib-01b9771203fd450741282504c730d296d7b9cce5.tar.gz
Add AsRequire as a way to store runtime requirements
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.am5
-rw-r--r--libappstream-glib/appstream-glib.h1
-rw-r--r--libappstream-glib/as-app.c100
-rw-r--r--libappstream-glib/as-app.h7
-rw-r--r--libappstream-glib/as-require-private.h48
-rw-r--r--libappstream-glib/as-require.c471
-rw-r--r--libappstream-glib/as-require.h121
-rw-r--r--libappstream-glib/as-self-test.c77
-rw-r--r--libappstream-glib/as-tag.c1
-rw-r--r--libappstream-glib/as-tag.gperf1
-rw-r--r--libappstream-glib/as-tag.h2
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 b23c15d..4429b0f 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;
@@ -5098,6 +5174,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;