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 15:21:59 +0000
commite6854025cebe9740b7e5424c12dfbfb4d179e590 (patch)
treeabb500abc6442118b2aaa00b8fd41800494ee5ea
parent2519ebef3fdfe57fd5e17b604dbe277e8b443637 (diff)
downloadappstream-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.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 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;