From 9f3e786c298161553e2d2612ef9375086184eab3 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 28 Sep 2017 16:29:50 +0200 Subject: [PATCH] Add appdata-license field This lets you modify the project_license field in the appdata file. This is useful because appdata files from upstream generally only contain license information for the app itself, whereas the bundled app may contain other code with additional licenses. Closes: #41 Approved by: alexlarsson --- configure.ac | 2 +- doc/flatpak-manifest.xml | 9 +++++ src/builder-manifest.c | 84 ++++++++++++++++++++++++++++++++++++++++ src/builder-utils.h | 14 +++++++ 4 files changed, 108 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5e406cd5..897362e0 100644 --- a/configure.ac +++ b/configure.ac @@ -93,7 +93,7 @@ AC_CHECK_FUNCS(fdwalk) AC_CHECK_HEADER([sys/xattr.h], [], [AC_MSG_ERROR([You must have sys/xattr.h from glibc])]) AC_CHECK_HEADER([sys/capability.h], have_caps=yes, [AC_MSG_ERROR([sys/capability.h header not found])]) -PKG_CHECK_MODULES(BASE, [glib-2.0 >= $GLIB_REQS gio-2.0 gio-unix-2.0 libsoup-2.4 ostree-1 >= $OSTREE_REQS json-glib-1.0]) +PKG_CHECK_MODULES(BASE, [glib-2.0 >= $GLIB_REQS gio-2.0 gio-unix-2.0 libsoup-2.4 ostree-1 >= $OSTREE_REQS json-glib-1.0 libxml-2.0 >= 2.4]) dnl ************************ dnl *** check for libelf *** diff --git a/doc/flatpak-manifest.xml b/doc/flatpak-manifest.xml index 8056dd7d..052a18a8 100644 --- a/doc/flatpak-manifest.xml +++ b/doc/flatpak-manifest.xml @@ -207,6 +207,15 @@ (string) Any icon with this name will be renamed to a name based on id during the cleanup phase. Note that this is the icon name, not the full filenames, so it should not include a filename extension. + + (string) + Replace the appdata + project_license field with this string. This is + useful as the upstream license is typically only + about the application itself, whereas the bundled + app can contain other licenses + too. + (boolean) If rename-icon is set, keep a copy of the old icon file. diff --git a/src/builder-manifest.c b/src/builder-manifest.c index d48ff625..1659b7bf 100644 --- a/src/builder-manifest.c +++ b/src/builder-manifest.c @@ -34,6 +34,8 @@ #include "builder-post-process.h" #include "builder-extension.h" +#include + #include "libglnx/libglnx.h" #define LOCALES_SEPARATE_DIR "share/runtime/locale" @@ -83,6 +85,7 @@ struct BuilderManifest char **tags; char *rename_desktop_file; char *rename_appdata_file; + char *appdata_license; char *rename_icon; gboolean copy_icon; char *desktop_file_name_prefix; @@ -147,6 +150,7 @@ enum { PROP_TAGS, PROP_RENAME_DESKTOP_FILE, PROP_RENAME_APPDATA_FILE, + PROP_APPDATA_LICENSE, PROP_RENAME_ICON, PROP_COPY_ICON, PROP_DESKTOP_FILE_NAME_PREFIX, @@ -189,6 +193,7 @@ builder_manifest_finalize (GObject *object) g_strfreev (self->tags); g_free (self->rename_desktop_file); g_free (self->rename_appdata_file); + g_free (self->appdata_license); g_free (self->rename_icon); g_free (self->desktop_file_name_prefix); g_free (self->desktop_file_name_suffix); @@ -399,6 +404,10 @@ builder_manifest_get_property (GObject *object, g_value_set_string (value, self->rename_appdata_file); break; + case PROP_APPDATA_LICENSE: + g_value_set_string (value, self->appdata_license); + break; + case PROP_RENAME_ICON: g_value_set_string (value, self->rename_icon); break; @@ -621,6 +630,11 @@ builder_manifest_set_property (GObject *object, self->rename_appdata_file = g_value_dup_string (value); break; + case PROP_APPDATA_LICENSE: + g_free (self->appdata_license); + self->appdata_license = g_value_dup_string (value); + break; + case PROP_RENAME_ICON: g_free (self->rename_icon); self->rename_icon = g_value_dup_string (value); @@ -905,6 +919,13 @@ builder_manifest_class_init (BuilderManifestClass *klass) "", NULL, G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_APPDATA_LICENSE, + g_param_spec_string ("appdata-license", + "", + "", + NULL, + G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_RENAME_ICON, g_param_spec_string ("rename-icon", @@ -1543,6 +1564,7 @@ builder_manifest_checksum_for_cleanup (BuilderManifest *self, builder_cache_checksum_strv (cache, self->cleanup_commands); builder_cache_checksum_str (cache, self->rename_desktop_file); builder_cache_checksum_str (cache, self->rename_appdata_file); + builder_cache_checksum_compat_str (cache, self->appdata_license); builder_cache_checksum_str (cache, self->rename_icon); builder_cache_checksum_boolean (cache, self->copy_icon); builder_cache_checksum_str (cache, self->desktop_file_name_prefix); @@ -2028,6 +2050,62 @@ strcatv (char **strv1, return retval; } +static gboolean +rewrite_appdata (GFile *file, + const char *license, + GError **error) +{ + g_autofree gchar *data = NULL; + gsize data_len; + g_autoptr(xmlDoc) doc = NULL; + xml_autofree xmlChar *xmlbuff = NULL; + int buffersize; + xmlNode *root_element, *component_node; + + if (!g_file_load_contents (file, NULL, &data, &data_len, NULL, error)) + return FALSE; + + doc = xmlReadMemory (data, data_len, NULL, NULL, 0); + if (doc == NULL) + return flatpak_fail (error, _("Error parsing appstream")); + + root_element = xmlDocGetRootElement (doc); + + for (component_node = root_element; component_node; component_node = component_node->next) + { + xmlNode *sub_node = NULL; + xmlNode *license_node = NULL; + + if (component_node->type != XML_ELEMENT_NODE || + strcmp ((char *)component_node->name, "component") != 0) + continue; + + for (sub_node = component_node->children; sub_node; sub_node = sub_node->next) + { + if (sub_node->type != XML_ELEMENT_NODE || + strcmp ((char *)sub_node->name, "project_license") != 0) + continue; + + license_node = sub_node; + break; + } + + if (license_node) + xmlNodeSetContent(license_node, (xmlChar *)license); + else + xmlNewChild(component_node, NULL, (xmlChar *)"project_license", (xmlChar *)license); + } + + xmlDocDumpFormatMemory (doc, &xmlbuff, &buffersize, 1); + + if (!g_file_set_contents (flatpak_file_get_path_cached (file), + (gchar *)xmlbuff, buffersize, + error)) + return FALSE; + + return TRUE; +} + gboolean builder_manifest_cleanup (BuilderManifest *self, BuilderCache *cache, @@ -2120,6 +2198,12 @@ builder_manifest_cleanup (BuilderManifest *self, return FALSE; } + if (self->appdata_license != NULL && self->appdata_license[0] != 0) + { + if (!rewrite_appdata (appdata_file, self->appdata_license, error)) + return FALSE; + } + if (self->rename_desktop_file != NULL) { g_autoptr(GFile) applications_dir = g_file_resolve_relative_path (app_root, "share/applications"); diff --git a/src/builder-utils.h b/src/builder-utils.h index 48120f3a..c3960f4d 100644 --- a/src/builder-utils.h +++ b/src/builder-utils.h @@ -25,6 +25,8 @@ #include #include +#include + G_BEGIN_DECLS typedef struct BuilderUtils BuilderUtils; @@ -75,6 +77,18 @@ GParamSpec * builder_serializable_find_property_with_error (JsonSerializable *se void builder_set_term_title (const gchar *format, ...) G_GNUC_PRINTF (1, 2); +static inline void +xml_autoptr_cleanup_generic_free (void *p) +{ + void **pp = (void**)p; + if (*pp) + xmlFree (*pp); +} + +#define xml_autofree _GLIB_CLEANUP(xml_autoptr_cleanup_generic_free) + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (xmlDoc, xmlFreeDoc) + G_END_DECLS #endif /* __BUILDER_UTILS_H__ */