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__ */