diff --git a/.github/dependencies.apt.txt b/.github/dependencies.apt.txt index 4359473f..0fc5bd7f 100644 --- a/.github/dependencies.apt.txt +++ b/.github/dependencies.apt.txt @@ -1,4 +1,3 @@ -appstream-compose dbus debugedit desktop-file-utils @@ -9,6 +8,8 @@ fuse3 gettext git git-lfs +libappstream-compose-dev +libappstream-dev libarchive-tools libcurl4-openssl-dev libelf-dev diff --git a/meson.build b/meson.build index 049a1758..e2042430 100644 --- a/meson.build +++ b/meson.build @@ -40,10 +40,6 @@ endforeach # The debugedit program is a hard dependency debugedit = find_program('debugedit', version: '>= 5.0') -# Require appstream with compose plugin installed -appstreamcli = find_program('appstreamcli', version: '>= 0.15.0') -appstreamcli_compose = run_command(appstreamcli, ['compose', '--help'], check: true) - fusermount = get_option('system_fusermount') if fusermount == '' fusermount_program = find_program(['fusermount3', 'fusermount'], required: true) diff --git a/src/asc-font.h b/src/asc-font.h new file mode 100644 index 00000000..158168b4 --- /dev/null +++ b/src/asc-font.h @@ -0,0 +1,20 @@ +/* + * asc-font.h (stub) + * + * This header is intentionally provided as a no-op. + * + * In AppStream < 1.0.6, the public header + * appstream-compose.h -> asc-canvas.h + * includes the private header "asc-font.h". + * + * That private header is not installed by default, and nothing in + * the public API actually depends on its declarations. + * + * To allow building against older AppStream releases, we provide + * this empty stub so the include resolves cleanly. + * + * Safe to remove once the minimum required AppStream is >= 1.0.6. + */ +#ifndef __ASC_FONT_H +#define __ASC_FONT_H +#endif diff --git a/src/builder-main.c b/src/builder-main.c index 3f2704a0..be5dada9 100644 --- a/src/builder-main.c +++ b/src/builder-main.c @@ -630,12 +630,6 @@ main (int argc, return 1; } - if (policy == BUILDER_AS_URL_POLICY_FULL && !appstream_has_version (0, 16, 3)) - { - g_printerr ("AppStream version >= 0.16.3 required for 'full' compose URL policy\n"); - return 1; - } - builder_context_set_as_url_policy (build_context, policy); } diff --git a/src/builder-manifest.c b/src/builder-manifest.c index 24988326..b6a8bbe7 100644 --- a/src/builder-manifest.c +++ b/src/builder-manifest.c @@ -30,6 +30,25 @@ #include #include +/* Remove for newer appstream */ +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wstrict-prototypes" +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-prototypes" +#endif + +#define I_KNOW_THE_APPSTREAM_COMPOSE_API_IS_SUBJECT_TO_CHANGE +#include +#include + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + #include "builder-manifest.h" #include "builder-utils.h" #include "builder-flatpak-utils.h" @@ -2422,30 +2441,74 @@ cmpstringp (const void *p1, const void *p2) } static gboolean -appstreamcli_compose (GError **error, - BuilderAsUrlPolicy as_url_policy, - ...) +builder_appstreamcli_compose (const gchar *origin, + const gchar *app_id, + const gchar *result_root, + const gchar *data_dir, + const gchar *icon_dir, + const gchar *hint_dir, + const gchar *media_dir, + const gchar *media_baseurl, + BuilderAsUrlPolicy as_url_policy, + GError **error) { - g_autoptr(GPtrArray) args = NULL; - const gchar *arg; - va_list ap; + g_autoptr(AscCompose) compose = NULL; + g_autoptr(AscDirectoryUnit) dirunit = NULL; + g_autofree gchar *desktop_component = NULL; - args = g_ptr_array_new_with_free_func (g_free); - g_ptr_array_add (args, g_strdup ("appstreamcli")); - g_ptr_array_add (args, g_strdup ("compose")); + g_return_val_if_fail (origin != NULL, FALSE); + g_return_val_if_fail (app_id != NULL, FALSE); + g_return_val_if_fail (result_root != NULL, FALSE); + g_return_val_if_fail (data_dir != NULL, FALSE); + g_return_val_if_fail (icon_dir != NULL, FALSE); + g_return_val_if_fail (hint_dir != NULL, FALSE); + + compose = asc_compose_new (); + + asc_compose_set_format (compose, AS_FORMAT_KIND_XML); + asc_compose_set_origin (compose, origin); + asc_compose_set_prefix (compose, "/"); + + asc_compose_add_allowed_cid (compose, app_id); + desktop_component = g_strdup_printf ("%s.desktop", app_id); + asc_compose_add_allowed_cid (compose, desktop_component); + dirunit = asc_directory_unit_new (result_root); + asc_compose_add_unit (compose, ASC_UNIT (dirunit)); + + asc_compose_set_data_result_dir (compose, data_dir); + asc_compose_set_icons_result_dir (compose, icon_dir); + asc_compose_set_media_baseurl (compose, media_baseurl); + asc_compose_set_media_result_dir (compose, media_dir); + asc_compose_set_hints_result_dir (compose, hint_dir); + +#if AS_CHECK_VERSION(0, 16, 3) + if (as_url_policy == BUILDER_AS_URL_POLICY_FULL) + asc_compose_add_flags (compose, ASC_COMPOSE_FLAG_NO_PARTIAL_URLS); +#else if (as_url_policy == BUILDER_AS_URL_POLICY_FULL) - g_ptr_array_add (args, g_strdup ("--no-partial-urls")); + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "AppStream >= 0.16.3 required for 'full' compose URL policy " + "(Found: %s)", as_version_string ()); + return FALSE; + } +#endif - va_start (ap, as_url_policy); - while ((arg = va_arg (ap, const gchar *))) - g_ptr_array_add (args, g_strdup (arg)); - g_ptr_array_add (args, NULL); - va_end (ap); + asc_compose_remove_flags (compose, ASC_COMPOSE_FLAG_ALLOW_SCREENCASTS); + asc_compose_add_flags (compose, ASC_COMPOSE_FLAG_PROPAGATE_CUSTOM); - if (!flatpak_spawnv (NULL, NULL, 0, error, (const char * const *)args->pdata, NULL)) + g_autoptr(GPtrArray) results = asc_compose_run (compose, NULL, error); + if (results == NULL) { - g_prefix_error (error, "ERROR: appstreamcli compose failed: "); + g_prefix_error (error, "AppStream compose failed: "); + return FALSE; + } + + if (asc_compose_has_errors (compose)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "AppStream compose completed with errors"); return FALSE; } @@ -3071,59 +3134,54 @@ builder_manifest_cleanup (BuilderManifest *self, if (self->appstream_compose && appdata_file != NULL) { - g_autofree char *origin = g_strdup_printf ("--origin=%s", - builder_manifest_get_id (self)); - g_autofree char *components_arg = g_strdup_printf ("--components=%s,%s.desktop", - self->id, self->id); const char *app_root_path = flatpak_file_get_path_cached (app_root); - g_autofree char *result_root_arg = g_strdup_printf ("--result-root=%s", app_root_path); - g_autoptr(GFile) xml_dir = flatpak_build_file (app_root, "share/app-info/xmls", NULL); + + g_autoptr(GFile) data_out = flatpak_build_file (app_root, "share/app-info/xmls", NULL); g_autoptr(GFile) icon_out = flatpak_build_file (app_root, "share/app-info/icons/flatpak", NULL); - g_autoptr(GFile) media_dir = flatpak_build_file (app_root, "share/app-info/media", NULL); - g_autofree char *data_dir = g_strdup_printf ("--data-dir=%s", - flatpak_file_get_path_cached (xml_dir)); - g_autofree char *icon_dir = g_strdup_printf ("--icons-dir=%s", - flatpak_file_get_path_cached (icon_out)); + g_autoptr(GFile) media_out = flatpak_build_file (app_root, "share/app-info/media", NULL); + g_autoptr(GFile) hint_out = flatpak_build_file (app_root, "appstream", NULL); + + const char *data_dir = flatpak_file_get_path_cached (data_out); + const char *icon_dir = flatpak_file_get_path_cached (icon_out); + const char *media_dir = flatpak_file_get_path_cached (media_out); + const char *hint_dir = flatpak_file_get_path_cached (hint_out); const char *opt_mirror_screenshots_url = builder_context_get_opt_mirror_screenshots_url (context); + gboolean opt_export_only = builder_context_get_opt_export_only (context); + BuilderAsUrlPolicy as_url_policy = builder_context_get_as_url_policy (context); if (opt_mirror_screenshots_url && !opt_export_only) { g_autofree char *url = g_build_filename (opt_mirror_screenshots_url, NULL); - g_autofree char *arg_base_url = g_strdup_printf ("--media-baseurl=%s", url); - g_autofree char *arg_media_dir = g_strdup_printf ("--media-dir=%s", - flatpak_file_get_path_cached (media_dir)); g_print ("Running appstreamcli compose\n"); - g_print ("Saving screenshots in %s\n", flatpak_file_get_path_cached (media_dir)); - if (!appstreamcli_compose (error, - as_url_policy, - "--prefix=/", - origin, - arg_base_url, - arg_media_dir, - result_root_arg, - data_dir, - icon_dir, - components_arg, - app_root_path, - NULL)) - return FALSE; + g_print ("Saving screenshots in %s\n", media_dir); + if (!builder_appstreamcli_compose (builder_manifest_get_id (self), + self->id, + app_root_path, + data_dir, + icon_dir, + hint_dir, + media_dir, + url, + as_url_policy, + error)) + return FALSE; } else { g_print ("Running appstreamcli compose\n"); - if (!appstreamcli_compose (error, - as_url_policy, - "--prefix=/", - origin, - result_root_arg, - data_dir, - icon_dir, - components_arg, - app_root_path, - NULL)) + if (!builder_appstreamcli_compose (builder_manifest_get_id (self), + self->id, + app_root_path, + data_dir, + icon_dir, + hint_dir, + NULL, + NULL, + as_url_policy, + error)) return FALSE; } } diff --git a/src/builder-utils.c b/src/builder-utils.c index 05be6616..a7af7d74 100644 --- a/src/builder-utils.c +++ b/src/builder-utils.c @@ -1887,55 +1887,3 @@ flatpak_version_check (int major, return FALSE; } - -gboolean -appstream_has_version (int major, - int minor, - int micro) -{ - static int as_major = 0; - static int as_minor = 0; - static int as_micro = 0; - - if (as_major == 0 && - as_minor == 0 && - as_micro == 0) - { - const char * argv[] = { "appstreamcli", "--version", NULL }; - g_autoptr(GSubprocessLauncher) launcher = NULL; - g_autoptr(GSubprocess) subp = NULL; - g_autofree char *out = NULL; - g_auto(GStrv) lines = NULL; - - launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE); - g_subprocess_launcher_setenv (launcher, "LANGUAGE", "C", TRUE); - subp = g_subprocess_launcher_spawnv (launcher, argv, NULL); - g_subprocess_communicate_utf8 (subp, NULL, NULL, &out, NULL, NULL); - - lines = g_strsplit (out, "\n", -1); - - for (size_t i = 0; lines[i] != NULL; i++) - { - /* Only prefer library version over cli version in case of mismatch */ - if (g_str_has_prefix (lines[i], "AppStream library version:")) - { - if (sscanf (lines[i], "AppStream library version: %d.%d.%d", &as_major, &as_minor, &as_micro) == 3) - break; - } - else if (g_str_has_prefix (lines[i], "AppStream version:")) - { - if (sscanf (lines[i], "AppStream version: %d.%d.%d", &as_major, &as_minor, &as_micro) == 3) - break; - } - } - - if (as_major == 0 && as_minor == 0 && as_micro == 0) - g_warning ("Failed to find appstream version"); - else - g_debug ("Found AppStream version %d.%d.%d", as_major, as_minor, as_micro); - } - - return (as_major > major) || - (as_major == major && as_minor > minor) || - (as_major == major && as_minor == minor && as_micro >= micro); -} diff --git a/src/meson.build b/src/meson.build index a737b41d..e152f264 100644 --- a/src/meson.build +++ b/src/meson.build @@ -58,12 +58,15 @@ flatpak_builder_deps = [ dependency('libglnx', default_options: ['tests=false']), dependency('libxml-2.0', version: '>= 2.4'), dependency('ostree-1', version: '>= 2017.14'), + dependency('appstream', version: '>=0.15.0'), + dependency('appstream-compose', version: '>=0.15.0'), yaml_dep, ] flatpak_builder = executable( 'flatpak-builder', flatpak_builder_sources, + include_directories: include_directories('.'), dependencies: flatpak_builder_deps, install: true, )