summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2014-03-20 15:41:04 +0000
committerRichard Hughes <richard@hughsie.com>2014-03-20 17:54:52 +0000
commit50fc0be57d11b757c78b1b2445f4a9d7137a243d (patch)
tree6175aea257681c9c7a605493515e39655517a556
parent2f4dc7bdbc3b407889f239d87b2b1ae018e3a2d8 (diff)
downloadappstream-glib-50fc0be57d11b757c78b1b2445f4a9d7137a243d.tar.gz
Add an 'api-version' property to AsStore to generate old-style metadata
This allows us to keep up with the latest API and still write metadata compatible with old applications not using libappstream-glib or libappstream.
-rw-r--r--libappstream-glib/as-app-private.h3
-rw-r--r--libappstream-glib/as-app.c92
-rw-r--r--libappstream-glib/as-image-private.h3
-rw-r--r--libappstream-glib/as-image.c3
-rw-r--r--libappstream-glib/as-node.c9
-rw-r--r--libappstream-glib/as-node.h2
-rw-r--r--libappstream-glib/as-release-private.h3
-rw-r--r--libappstream-glib/as-release.c7
-rw-r--r--libappstream-glib/as-screenshot-private.h3
-rw-r--r--libappstream-glib/as-screenshot.c12
-rw-r--r--libappstream-glib/as-self-test.c110
-rw-r--r--libappstream-glib/as-store.c61
-rw-r--r--libappstream-glib/as-store.h3
-rw-r--r--libappstream-glib/as-tag.c8
14 files changed, 263 insertions, 56 deletions
diff --git a/libappstream-glib/as-app-private.h b/libappstream-glib/as-app-private.h
index 6d508b1..48f8de3 100644
--- a/libappstream-glib/as-app-private.h
+++ b/libappstream-glib/as-app-private.h
@@ -33,7 +33,8 @@
G_BEGIN_DECLS
GNode *as_app_node_insert (AsApp *app,
- GNode *parent);
+ GNode *parent,
+ gdouble api_version);
gboolean as_app_node_parse (AsApp *app,
GNode *node,
GError **error);
diff --git a/libappstream-glib/as-app.c b/libappstream-glib/as-app.c
index 660d182..209736d 100644
--- a/libappstream-glib/as-app.c
+++ b/libappstream-glib/as-app.c
@@ -1159,6 +1159,7 @@ as_app_node_insert_languages (AsApp *app, GNode *parent)
* as_app_node_insert: (skip)
* @app: a #AsApp instance.
* @parent: the parent #GNode to use..
+ * @api_version: the AppStream API version
*
* Inserts the application into the DOM tree.
*
@@ -1167,7 +1168,7 @@ as_app_node_insert_languages (AsApp *app, GNode *parent)
* Since: 0.1.0
**/
GNode *
-as_app_node_insert (AsApp *app, GNode *parent)
+as_app_node_insert (AsApp *app, GNode *parent, gdouble api_version)
{
AsAppPrivate *priv = GET_PRIVATE (app);
AsRelease *rel;
@@ -1177,12 +1178,23 @@ as_app_node_insert (AsApp *app, GNode *parent)
const gchar *tmp;
guint i;
- node_app = as_node_insert (parent, "application", NULL, 0, NULL);
+ /* <component> or <application> */
+ if (api_version >= 0.6) {
+ node_app = as_node_insert (parent, "component", NULL, 0,
+ "type", as_id_kind_to_string (priv->id_kind),
+ NULL);
+ } else {
+ node_app = as_node_insert (parent, "application", NULL, 0, NULL);
+ }
/* <id> */
- as_node_insert (node_app, "id", priv->id_full, 0,
- "type", as_id_kind_to_string (priv->id_kind),
- NULL);
+ node_tmp = as_node_insert (node_app, "id", priv->id_full, 0, NULL);
+ if (api_version < 0.6) {
+ as_node_add_attribute (node_tmp,
+ "type",
+ as_id_kind_to_string (priv->id_kind),
+ -1);
+ }
/* <priority> */
if (priv->priority != 0) {
@@ -1204,8 +1216,13 @@ as_app_node_insert (AsApp *app, GNode *parent)
as_node_insert_localized (node_app, "summary", priv->comments, 0);
/* <description> */
- as_node_insert_localized (node_app, "description", priv->descriptions,
- AS_NODE_INSERT_FLAG_PRE_ESCAPED);
+ if (api_version < 0.6) {
+ as_node_insert_localized (node_app, "description", priv->descriptions,
+ AS_NODE_INSERT_FLAG_NO_MARKUP);
+ } else {
+ as_node_insert_localized (node_app, "description", priv->descriptions,
+ AS_NODE_INSERT_FLAG_PRE_ESCAPED);
+ }
/* <icon> */
if (priv->icon != NULL) {
@@ -1215,16 +1232,26 @@ as_app_node_insert (AsApp *app, GNode *parent)
}
/* <categories> */
- if (priv->categories->len > 0) {
- node_tmp = as_node_insert (node_app, "categories", NULL, 0, NULL);
- for (i = 0; i < priv->categories->len; i++) {
- tmp = g_ptr_array_index (priv->categories, i);
- as_node_insert (node_tmp, "category", tmp, 0, NULL);
+ if (api_version >= 0.5) {
+ if (priv->categories->len > 0) {
+ node_tmp = as_node_insert (node_app, "categories", NULL, 0, NULL);
+ for (i = 0; i < priv->categories->len; i++) {
+ tmp = g_ptr_array_index (priv->categories, i);
+ as_node_insert (node_tmp, "category", tmp, 0, NULL);
+ }
+ }
+ } else {
+ if (priv->categories->len > 0) {
+ node_tmp = as_node_insert (node_app, "appcategories", NULL, 0, NULL);
+ for (i = 0; i < priv->categories->len; i++) {
+ tmp = g_ptr_array_index (priv->categories, i);
+ as_node_insert (node_tmp, "appcategory", tmp, 0, NULL);
+ }
}
}
/* <architectures> */
- if (priv->categories->len > 0) {
+ if (priv->architectures->len > 0 && api_version >= 0.6) {
node_tmp = as_node_insert (node_app, "architectures", NULL, 0, NULL);
for (i = 0; i < priv->architectures->len; i++) {
tmp = g_ptr_array_index (priv->architectures, i);
@@ -1250,23 +1277,28 @@ as_app_node_insert (AsApp *app, GNode *parent)
}
}
- /* <project_license> */
+ /* <project_license> or <licence> */
if (priv->project_license != NULL) {
- as_node_insert (node_app, "project_license",
- priv->project_license, 0, NULL);
+ if (api_version >= 0.4) {
+ as_node_insert (node_app, "project_license",
+ priv->project_license, 0, NULL);
+ } else {
+ as_node_insert (node_app, "licence",
+ priv->project_license, 0, NULL);
+ }
}
/* <url> */
as_node_insert_hash (node_app, "url", "type", priv->urls, 0);
/* <project_group> */
- if (priv->project_group != NULL) {
+ if (priv->project_group != NULL && api_version >= 0.4) {
as_node_insert (node_app, "project_group",
priv->project_group, 0, NULL);
}
/* <compulsory_for_desktop> */
- if (priv->compulsory_for_desktops != NULL) {
+ if (priv->compulsory_for_desktops != NULL && api_version >= 0.4) {
for (i = 0; i < priv->compulsory_for_desktops->len; i++) {
tmp = g_ptr_array_index (priv->compulsory_for_desktops, i);
as_node_insert (node_app, "compulsory_for_desktop",
@@ -1275,25 +1307,25 @@ as_app_node_insert (AsApp *app, GNode *parent)
}
/* <screenshots> */
- if (priv->screenshots->len > 0) {
+ if (priv->screenshots->len > 0 && api_version >= 0.4) {
node_tmp = as_node_insert (node_app, "screenshots", NULL, 0, NULL);
for (i = 0; i < priv->screenshots->len; i++) {
ss = g_ptr_array_index (priv->screenshots, i);
- as_screenshot_node_insert (ss, node_tmp);
+ as_screenshot_node_insert (ss, node_tmp, api_version);
}
}
/* <releases> */
- if (priv->releases->len > 0) {
+ if (priv->releases->len > 0 && api_version >= 0.6) {
node_tmp = as_node_insert (node_app, "releases", NULL, 0, NULL);
for (i = 0; i < priv->releases->len && i < 3; i++) {
rel = g_ptr_array_index (priv->releases, i);
- as_release_node_insert (rel, node_tmp);
+ as_release_node_insert (rel, node_tmp, api_version);
}
}
/* <languages> */
- if (g_hash_table_size (priv->languages) > 0)
+ if (g_hash_table_size (priv->languages) > 0 && api_version >= 0.4)
as_app_node_insert_languages (app, node_app);
/* <metadata> */
@@ -1327,7 +1359,8 @@ as_app_node_parse_child (AsApp *app, GNode *n, GError **error)
/* <id> */
case AS_TAG_ID:
tmp = as_node_get_attribute (n, "type");
- as_app_set_id_kind (app, as_id_kind_from_string (tmp));
+ if (tmp != NULL)
+ as_app_set_id_kind (app, as_id_kind_from_string (tmp));
as_app_set_id_full (app, as_node_get_data (n), -1);
break;
@@ -1391,7 +1424,8 @@ as_app_node_parse_child (AsApp *app, GNode *n, GError **error)
case AS_TAG_CATEGORIES:
g_ptr_array_set_size (priv->categories, 0);
for (c = n->children; c != NULL; c = c->next) {
- if (g_strcmp0 (as_node_get_name (c), "category") != 0)
+ if (g_strcmp0 (as_node_get_name (c), "category") != 0 &&
+ g_strcmp0 (as_node_get_name (c), "appcategory") != 0)
continue;
g_ptr_array_add (priv->categories, as_node_take_data (c));
}
@@ -1540,8 +1574,16 @@ as_app_node_parse (AsApp *app, GNode *node, GError **error)
{
AsAppPrivate *priv = GET_PRIVATE (app);
GNode *n;
+ const gchar *tmp;
gboolean ret = TRUE;
+ /* new style */
+ if (g_strcmp0 (as_node_get_name (node), "component") == 0) {
+ tmp = as_node_get_attribute (node, "type");
+ if (tmp != NULL)
+ as_app_set_id_kind (app, as_id_kind_from_string (tmp));
+ }
+
/* parse each node */
g_ptr_array_set_size (priv->compulsory_for_desktops, 0);
g_ptr_array_set_size (priv->pkgnames, 0);
diff --git a/libappstream-glib/as-image-private.h b/libappstream-glib/as-image-private.h
index d3098f8..2381f1e 100644
--- a/libappstream-glib/as-image-private.h
+++ b/libappstream-glib/as-image-private.h
@@ -31,7 +31,8 @@
G_BEGIN_DECLS
GNode *as_image_node_insert (AsImage *image,
- GNode *parent);
+ GNode *parent,
+ gdouble api_version);
gboolean as_image_node_parse (AsImage *image,
GNode *node,
GError **error);
diff --git a/libappstream-glib/as-image.c b/libappstream-glib/as-image.c
index 9079269..e18eee7 100644
--- a/libappstream-glib/as-image.c
+++ b/libappstream-glib/as-image.c
@@ -262,6 +262,7 @@ as_image_set_kind (AsImage *image, AsImageKind kind)
* as_image_node_insert: (skip)
* @image: a #AsImage instance.
* @parent: the parent #GNode to use..
+ * @api_version: the AppStream API version
*
* Inserts the image into the DOM tree.
*
@@ -270,7 +271,7 @@ as_image_set_kind (AsImage *image, AsImageKind kind)
* Since: 0.1.0
**/
GNode *
-as_image_node_insert (AsImage *image, GNode *parent)
+as_image_node_insert (AsImage *image, GNode *parent, gdouble api_version)
{
AsImagePrivate *priv = GET_PRIVATE (image);
GNode *n;
diff --git a/libappstream-glib/as-node.c b/libappstream-glib/as-node.c
index 9f8e3f8..1b818c3 100644
--- a/libappstream-glib/as-node.c
+++ b/libappstream-glib/as-node.c
@@ -955,8 +955,13 @@ as_node_insert_localized (GNode *parent,
value = g_hash_table_lookup (localized, key);
data = g_slice_new (AsNodeData);
data->name = g_strdup (name);
- data->cdata = g_strdup (value);
- data->cdata_escaped = insert_flags & AS_NODE_INSERT_FLAG_PRE_ESCAPED;
+ if (insert_flags & AS_NODE_INSERT_FLAG_NO_MARKUP) {
+ data->cdata = as_markup_convert_simple (value, -1, NULL);
+ data->cdata_escaped = FALSE;
+ } else {
+ data->cdata = g_strdup (value);
+ data->cdata_escaped = insert_flags & AS_NODE_INSERT_FLAG_PRE_ESCAPED;
+ }
data->attributes = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
diff --git a/libappstream-glib/as-node.h b/libappstream-glib/as-node.h
index 71b7cf6..44562bb 100644
--- a/libappstream-glib/as-node.h
+++ b/libappstream-glib/as-node.h
@@ -67,6 +67,7 @@ typedef enum {
* @AS_NODE_INSERT_FLAG_NONE: No extra flags to use
* @AS_NODE_INSERT_FLAG_PRE_ESCAPED: The data is already XML escaped
* @AS_NODE_INSERT_FLAG_SWAPPED: The name and key should be swapped
+ * @AS_NODE_INSERT_FLAG_NO_MARKUP: Preformat the 'description' markup
*
* The flags to use when inserting a node.
**/
@@ -74,6 +75,7 @@ typedef enum {
AS_NODE_INSERT_FLAG_NONE = 0, /* Since: 0.1.0 */
AS_NODE_INSERT_FLAG_PRE_ESCAPED = 1, /* Since: 0.1.0 */
AS_NODE_INSERT_FLAG_SWAPPED = 2, /* Since: 0.1.0 */
+ AS_NODE_INSERT_FLAG_NO_MARKUP = 4, /* Since: 0.1.1 */
/*< private >*/
AS_NODE_INSERT_FLAG_LAST
} AsNodeInsertFlags;
diff --git a/libappstream-glib/as-release-private.h b/libappstream-glib/as-release-private.h
index 3b0717e..73654c6 100644
--- a/libappstream-glib/as-release-private.h
+++ b/libappstream-glib/as-release-private.h
@@ -31,7 +31,8 @@
G_BEGIN_DECLS
GNode *as_release_node_insert (AsRelease *release,
- GNode *parent);
+ GNode *parent,
+ gdouble api_version);
gboolean as_release_node_parse (AsRelease *release,
GNode *node,
GError **error);
diff --git a/libappstream-glib/as-release.c b/libappstream-glib/as-release.c
index a19d327..635b192 100644
--- a/libappstream-glib/as-release.c
+++ b/libappstream-glib/as-release.c
@@ -214,15 +214,16 @@ as_release_set_description (AsRelease *release,
* as_release_node_insert: (skip)
* @release: a #AsRelease instance.
* @parent: the parent #GNode to use..
+ * @api_version: the AppStream API version
*
* Inserts the release into the DOM tree.
*
* Returns: (transfer full): A populated #GNode
*
- * Since: 0.1.0
+ * Since: 0.1.1
**/
GNode *
-as_release_node_insert (AsRelease *release, GNode *parent)
+as_release_node_insert (AsRelease *release, GNode *parent, gdouble api_version)
{
AsReleasePrivate *priv = GET_PRIVATE (release);
GNode *n;
@@ -235,7 +236,7 @@ as_release_node_insert (AsRelease *release, GNode *parent)
"timestamp", timestamp_str,
"version", priv->version,
NULL);
- if (priv->descriptions != NULL) {
+ if (priv->descriptions != NULL && api_version >= 0.6) {
as_node_insert_localized (n, "description", priv->descriptions,
AS_NODE_INSERT_FLAG_PRE_ESCAPED);
}
diff --git a/libappstream-glib/as-screenshot-private.h b/libappstream-glib/as-screenshot-private.h
index 2e25c80..92ccaa9 100644
--- a/libappstream-glib/as-screenshot-private.h
+++ b/libappstream-glib/as-screenshot-private.h
@@ -33,7 +33,8 @@
G_BEGIN_DECLS
GNode *as_screenshot_node_insert (AsScreenshot *screenshot,
- GNode *parent);
+ GNode *parent,
+ gdouble api_version);
gboolean as_screenshot_node_parse (AsScreenshot *screenshot,
GNode *node,
GError **error);
diff --git a/libappstream-glib/as-screenshot.c b/libappstream-glib/as-screenshot.c
index 9ee31f5..05b04a1 100644
--- a/libappstream-glib/as-screenshot.c
+++ b/libappstream-glib/as-screenshot.c
@@ -242,15 +242,18 @@ as_screenshot_set_caption (AsScreenshot *screenshot,
* as_screenshot_node_insert: (skip)
* @screenshot: a #AsScreenshot instance.
* @parent: the parent #GNode to use..
+ * @api_version: the AppStream API version
*
* Inserts the screenshot into the DOM tree.
*
* Returns: (transfer full): A populated #GNode
*
- * Since: 0.1.0
+ * Since: 0.1.1
**/
GNode *
-as_screenshot_node_insert (AsScreenshot *screenshot, GNode *parent)
+as_screenshot_node_insert (AsScreenshot *screenshot,
+ GNode *parent,
+ gdouble api_version)
{
AsImage *image;
AsScreenshotPrivate *priv = GET_PRIVATE (screenshot);
@@ -261,10 +264,11 @@ as_screenshot_node_insert (AsScreenshot *screenshot, GNode *parent)
AS_NODE_INSERT_FLAG_NONE,
"type", as_screenshot_kind_to_string (priv->kind),
NULL);
- as_node_insert_localized (n, "caption", priv->captions, 0);
+ if (api_version >= 0.5)
+ as_node_insert_localized (n, "caption", priv->captions, 0);
for (i = 0; i < priv->images->len; i++) {
image = g_ptr_array_index (priv->images, i);
- as_image_node_insert (image, n);
+ as_image_node_insert (image, n, api_version);
}
return n;
}
diff --git a/libappstream-glib/as-self-test.c b/libappstream-glib/as-self-test.c
index fbe8a1b..aff098e 100644
--- a/libappstream-glib/as-self-test.c
+++ b/libappstream-glib/as-self-test.c
@@ -104,7 +104,7 @@ ch_test_release_func (void)
/* back to node */
root = as_node_new ();
- n = as_release_node_insert (release, root);
+ n = as_release_node_insert (release, root, 0.4);
xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
g_assert_cmpstr (xml->str, ==, src);
g_string_free (xml, TRUE);
@@ -149,7 +149,7 @@ ch_test_release_desc_func (void)
/* back to node */
root = as_node_new ();
- n = as_release_node_insert (release, root);
+ n = as_release_node_insert (release, root, 0.6);
xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
g_assert_cmpstr (xml->str, ==, src);
g_string_free (xml, TRUE);
@@ -192,7 +192,7 @@ ch_test_image_func (void)
/* back to node */
root = as_node_new ();
- n = as_image_node_insert (image, root);
+ n = as_image_node_insert (image, root, 0.4);
xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
g_assert_cmpstr (xml->str, ==, src);
g_string_free (xml, TRUE);
@@ -239,7 +239,7 @@ ch_test_screenshot_func (void)
/* back to node */
root = as_node_new ();
- n = as_screenshot_node_insert (screenshot, root);
+ n = as_screenshot_node_insert (screenshot, root, 0.6);
xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
g_assert_cmpstr (xml->str, ==, src);
g_string_free (xml, TRUE);
@@ -258,8 +258,8 @@ ch_test_app_func (void)
GString *xml;
gboolean ret;
const gchar *src =
- "<application>"
- "<id type=\"desktop\">org.gnome.Software.desktop</id>"
+ "<component type=\"desktop\">"
+ "<id>org.gnome.Software.desktop</id>"
"<priority>-4</priority>"
"<pkgname>gnome-software</pkgname>"
"<name>Software</name>"
@@ -296,7 +296,7 @@ ch_test_app_func (void)
"<metadata>"
"<value key=\"X-Kudo-GTK3\"/>"
"</metadata>"
- "</application>";
+ "</component>";
app = as_app_new ();
@@ -304,7 +304,7 @@ ch_test_app_func (void)
root = as_node_from_xml (src, -1, 0, &error);
g_assert_no_error (error);
g_assert (root != NULL);
- n = as_node_find (root, "application");
+ n = as_node_find (root, "component");
g_assert (n != NULL);
ret = as_app_node_parse (app, n, &error);
g_assert_no_error (error);
@@ -327,7 +327,7 @@ ch_test_app_func (void)
/* back to node */
root = as_node_new ();
- n = as_app_node_insert (app, root);
+ n = as_app_node_insert (app, root, 0.6);
xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
g_assert_cmpstr (xml->str, ==, src);
g_string_free (xml, TRUE);
@@ -370,7 +370,7 @@ ch_test_app_no_markup_func (void)
/* back to node */
root = as_node_new ();
- n = as_app_node_insert (app, root);
+ n = as_app_node_insert (app, root, 0.4);
xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
g_assert_cmpstr (xml->str, ==, src);
g_string_free (xml, TRUE);
@@ -651,6 +651,8 @@ ch_test_store_func (void)
/* create a store and add a single app */
store = as_store_new ();
+ g_assert_cmpfloat (as_store_get_api_version (store), <, 1.f);
+ g_assert_cmpfloat (as_store_get_api_version (store), >, 0.f);
app = as_app_new ();
as_app_set_id_full (app, "gnome-software.desktop", -1);
as_app_set_id_kind (app, AS_ID_KIND_DESKTOP);
@@ -667,6 +669,7 @@ ch_test_store_func (void)
as_store_remove_app (store, app);
/* check string output */
+ as_store_set_api_version (store, 0.4);
xml = as_store_to_xml (store, 0);
g_assert_cmpstr (xml->str, ==,
"<applications version=\"0.4\">"
@@ -679,6 +682,92 @@ ch_test_store_func (void)
}
static void
+ch_test_store_versions_func (void)
+{
+ AsStore *store;
+ GError *error = NULL;
+ gboolean ret;
+ GString *str;
+
+ /* load a file to the store */
+ store = as_store_new ();
+ ret = as_store_from_xml (store,
+ "<applications version=\"0.4\">"
+ "<application>"
+ "<id type=\"desktop\">test.desktop</id>"
+ "<description><p>Hello world</p></description>"
+ "<architectures><arch>i386</arch></architectures>"
+ "<releases>"
+ "<release version=\"0.1.2\" timestamp=\"123\">"
+ "<description><p>Hello</p></description>"
+ "</release>"
+ "</releases>"
+ "</application>"
+ "</applications>", -1, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ g_assert_cmpfloat (as_store_get_api_version (store), <, 0.4 + 0.01);
+ g_assert_cmpfloat (as_store_get_api_version (store), >, 0.4 - 0.01);
+
+ /* test with latest features */
+ as_store_set_api_version (store, 0.6);
+ g_assert_cmpfloat (as_store_get_api_version (store), <, 0.6 + 0.01);
+ g_assert_cmpfloat (as_store_get_api_version (store), >, 0.6 - 0.01);
+ str = as_store_to_xml (store, 0);
+ g_assert_cmpstr (str->str, ==,
+ "<components version=\"0.6\">"
+ "<component type=\"desktop\">"
+ "<id>test.desktop</id>"
+ "<description><p>Hello world</p></description>"
+ "<architectures><arch>i386</arch></architectures>"
+ "<releases>"
+ "<release version=\"0.1.2\" timestamp=\"123\">"
+ "<description><p>Hello</p></description>"
+ "</release>"
+ "</releases>"
+ "</component>"
+ "</components>");
+ g_string_free (str, TRUE);
+
+ /* test with legacy options */
+ as_store_set_api_version (store, 0.3);
+ str = as_store_to_xml (store, 0);
+ g_assert_cmpstr (str->str, ==,
+ "<applications version=\"0.3\">"
+ "<application>"
+ "<id type=\"desktop\">test.desktop</id>"
+ "<description>Hello world</description>"
+ "</application>"
+ "</applications>");
+ g_string_free (str, TRUE);
+
+ g_object_unref (store);
+
+ /* load a version 0.6 file to the store */
+ store = as_store_new ();
+ ret = as_store_from_xml (store,
+ "<components version=\"0.6\">"
+ "<component type=\"desktop\">"
+ "<id>test.desktop</id>"
+ "</component>"
+ "</components>", -1, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ /* test latest spec version */
+ str = as_store_to_xml (store, 0);
+ g_assert_cmpstr (str->str, ==,
+ "<components version=\"0.6\">"
+ "<component type=\"desktop\">"
+ "<id>test.desktop</id>"
+ "</component>"
+ "</components>");
+ g_string_free (str, TRUE);
+
+ g_object_unref (store);
+}
+
+static void
ch_test_store_origin_func (void)
{
AsApp *app;
@@ -810,6 +899,7 @@ main (int argc, char **argv)
g_test_add_func ("/AppStream/node{localized-wrap}", ch_test_node_localized_wrap_func);
g_test_add_func ("/AppStream/utils", ch_test_utils_func);
g_test_add_func ("/AppStream/store", ch_test_store_func);
+ g_test_add_func ("/AppStream/store{versions}", ch_test_store_versions_func);
g_test_add_func ("/AppStream/store{origin}", ch_test_store_origin_func);
g_test_add_func ("/AppStream/store{speed}", ch_test_store_speed_func);
diff --git a/libappstream-glib/as-store.c b/libappstream-glib/as-store.c
index a0aba05..03820b0 100644
--- a/libappstream-glib/as-store.c
+++ b/libappstream-glib/as-store.c
@@ -39,11 +39,15 @@
#include "as-app-private.h"
#include "as-node-private.h"
#include "as-store.h"
+#include "as-utils-private.h"
+
+#define AS_API_VERSION_NEWEST 0.6
typedef struct _AsStorePrivate AsStorePrivate;
struct _AsStorePrivate
{
gchar *origin;
+ gdouble api_version;
GPtrArray *array; /* of AsApp */
GHashTable *hash_id; /* of AsApp{id} */
GHashTable *hash_pkgname; /* of AsApp{pkgname} */
@@ -77,6 +81,7 @@ static void
as_store_init (AsStore *store)
{
AsStorePrivate *priv = GET_PRIVATE (store);
+ priv->api_version = AS_API_VERSION_NEWEST;
priv->array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
priv->hash_id = g_hash_table_new_full (g_str_hash,
g_str_equal,
@@ -433,17 +438,30 @@ as_store_to_xml (AsStore *store, AsNodeToXmlFlags flags)
GNode *node_root;
GString *xml;
guint i;
+ gchar version[6];
/* get XML text */
node_root = as_node_new ();
- node_apps = as_node_insert (node_root, "applications", NULL, 0,
- "version", "0.4",
- NULL);
+ if (priv->api_version >= 0.6) {
+ node_apps = as_node_insert (node_root, "components", NULL, 0, NULL);
+ } else {
+ node_apps = as_node_insert (node_root, "applications", NULL, 0, NULL);
+ }
+
+ /* set origin attribute */
if (priv->origin != NULL)
- as_node_add_attribute (node_root, "origin", priv->origin, -1);
+ as_node_add_attribute (node_apps, "origin", priv->origin, -1);
+
+ /* set version attribute */
+ if (priv->api_version > 0.1f) {
+ g_ascii_formatd (version, sizeof (version),
+ "%.1f", priv->api_version);
+ as_node_add_attribute (node_apps, "version", version, -1);
+ }
+
for (i = 0; i < priv->array->len; i++) {
app = g_ptr_array_index (priv->array, i);
- as_app_node_insert (app, node_apps);
+ as_app_node_insert (app, node_apps, priv->api_version);
}
xml = as_node_to_xml (node_root, flags);
as_node_unref (node_root);
@@ -545,6 +563,39 @@ as_store_set_origin (AsStore *store, const gchar *origin)
}
/**
+ * as_store_get_api_version:
+ * @store: a #AsStore instance.
+ *
+ * Gets the AppStream API version.
+ *
+ * Returns: the #AsNodeInsertFlags, or 0 if unset
+ *
+ * Since: 0.1.1
+ **/
+gdouble
+as_store_get_api_version (AsStore *store)
+{
+ AsStorePrivate *priv = GET_PRIVATE (store);
+ return priv->api_version;
+}
+
+/**
+ * as_store_set_api_version:
+ * @store: a #AsStore instance.
+ * @api_version: the API version
+ *
+ * Sets the AppStream API version.
+ *
+ * Since: 0.1.1
+ **/
+void
+as_store_set_api_version (AsStore *store, gdouble api_version)
+{
+ AsStorePrivate *priv = GET_PRIVATE (store);
+ priv->api_version = api_version;
+}
+
+/**
* as_store_new:
*
* Creates a new #AsStore.
diff --git a/libappstream-glib/as-store.h b/libappstream-glib/as-store.h
index 57926a1..54e1c52 100644
--- a/libappstream-glib/as-store.h
+++ b/libappstream-glib/as-store.h
@@ -99,6 +99,9 @@ gboolean as_store_to_file (AsStore *store,
const gchar *as_store_get_origin (AsStore *store);
void as_store_set_origin (AsStore *store,
const gchar *origin);
+gdouble as_store_get_api_version (AsStore *store);
+void as_store_set_api_version (AsStore *store,
+ gdouble api_version);
G_END_DECLS
diff --git a/libappstream-glib/as-tag.c b/libappstream-glib/as-tag.c
index cf5d22c..96b0a86 100644
--- a/libappstream-glib/as-tag.c
+++ b/libappstream-glib/as-tag.c
@@ -70,6 +70,10 @@ as_tag_from_string (const gchar *tag)
return AS_TAG_CATEGORY;
if (g_strcmp0 (tag, "licence") == 0)
return AS_TAG_PROJECT_LICENSE;
+ if (g_strcmp0 (tag, "applications") == 0)
+ return AS_TAG_APPLICATIONS;
+ if (g_strcmp0 (tag, "application") == 0)
+ return AS_TAG_APPLICATION;
return AS_TAG_UNKNOWN;
}
@@ -89,8 +93,8 @@ as_tag_to_string (AsTag tag)
{
const gchar *str[] = {
"unknown",
- "applications",
- "application",
+ "components",
+ "component",
"id",
"pkgname",
"name",