From 13bf7af0fb33ce49415c06d02964d95bbedeedd0 Mon Sep 17 00:00:00 2001 From: bbhtt Date: Mon, 27 Apr 2026 10:24:55 +0530 Subject: [PATCH 1/6] builder-manifest: Port to libappstream-compose API --- .github/dependencies.apt.txt | 2 +- meson.build | 4 - src/builder-main.c | 6 -- src/builder-manifest.c | 142 +++++++++++++++++++++-------------- src/builder-utils.c | 52 ------------- src/meson.build | 2 + 6 files changed, 90 insertions(+), 118 deletions(-) diff --git a/.github/dependencies.apt.txt b/.github/dependencies.apt.txt index 4359473f..ea376c44 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,7 @@ fuse3 gettext git git-lfs +libappstream-compose-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/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..7466782b 100644 --- a/src/builder-manifest.c +++ b/src/builder-manifest.c @@ -30,6 +30,9 @@ #include #include +#include +#include + #include "builder-manifest.h" #include "builder-utils.h" #include "builder-flatpak-utils.h" @@ -2422,30 +2425,68 @@ 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 *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); + + 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); + +#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); + g_autoptr(GPtrArray) results = asc_compose_run (compose, NULL, error); + if (results == NULL) + { + g_prefix_error (error, "AppStream compose failed: "); + return FALSE; + } - if (!flatpak_spawnv (NULL, NULL, 0, error, (const char * const *)args->pdata, NULL)) + if (asc_compose_has_errors (compose)) { - g_prefix_error (error, "ERROR: appstreamcli compose failed: "); + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "AppStream compose completed with errors"); return FALSE; } @@ -3071,59 +3112,50 @@ 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); + + 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 *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, + 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, + 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..82ead752 100644 --- a/src/meson.build +++ b/src/meson.build @@ -58,6 +58,8 @@ 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, ] From e641508ec4f5ff50f685f43de66bf84cbf13f756 Mon Sep 17 00:00:00 2001 From: bbhtt Date: Mon, 27 Apr 2026 10:16:28 +0530 Subject: [PATCH 2/6] builder-manifest: Disable processing screencasts in appstream Screencasts are generally unwanted in catalogue to as they are more expensive to download, store in ref and serve. Also no appstore currently supports showing them. This can later be changed if needed. --- src/builder-manifest.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/builder-manifest.c b/src/builder-manifest.c index 7466782b..608a09ce 100644 --- a/src/builder-manifest.c +++ b/src/builder-manifest.c @@ -2476,6 +2476,8 @@ builder_appstreamcli_compose (const gchar *origin, } #endif + asc_compose_remove_flags (compose, ASC_COMPOSE_FLAG_ALLOW_SCREENCASTS); + g_autoptr(GPtrArray) results = asc_compose_run (compose, NULL, error); if (results == NULL) { From b87c13d3e2702a79a175aa43522515022c8590ea Mon Sep 17 00:00:00 2001 From: bbhtt Date: Mon, 27 Apr 2026 10:17:25 +0530 Subject: [PATCH 3/6] builder-manifest: Allow all custom appstream tags in catalogue This allows all `` tags from metainfo files to reach catalogue data. Custom tags are used by Flathub to store verification and build information and often downstream vendors who use Flathub's catalogue for their own app store want custom tags to identify or highlight their own apps. For example cosmic using Flathub catalogue data to highlight cosmic apps on cosmic store app etc. Allowing individual custom tags one by one is annoying and this is what libappstream-glib did before the port in 1.3.4. So this brings back the old as-glib behaviour that was lost in >=1.3.4 --- src/builder-manifest.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/builder-manifest.c b/src/builder-manifest.c index 608a09ce..aea8fd83 100644 --- a/src/builder-manifest.c +++ b/src/builder-manifest.c @@ -2477,6 +2477,7 @@ builder_appstreamcli_compose (const gchar *origin, #endif asc_compose_remove_flags (compose, ASC_COMPOSE_FLAG_ALLOW_SCREENCASTS); + asc_compose_add_flags (compose, ASC_COMPOSE_FLAG_PROPAGATE_CUSTOM); g_autoptr(GPtrArray) results = asc_compose_run (compose, NULL, error); if (results == NULL) From c7f8f6b3a7e60f1360ad5b770d0a84cbdfc63dfc Mon Sep 17 00:00:00 2001 From: bbhtt Date: Mon, 27 Apr 2026 10:20:42 +0530 Subject: [PATCH 4/6] builder-manifest: Set hint dir for appstream compose On request from maintainer. This sets a place to post output of compose errors --- src/builder-manifest.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/builder-manifest.c b/src/builder-manifest.c index aea8fd83..52f29aa3 100644 --- a/src/builder-manifest.c +++ b/src/builder-manifest.c @@ -2430,6 +2430,7 @@ builder_appstreamcli_compose (const gchar *origin, 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, @@ -2444,6 +2445,7 @@ builder_appstreamcli_compose (const gchar *origin, 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 (); @@ -2462,6 +2464,7 @@ builder_appstreamcli_compose (const gchar *origin, 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) @@ -3120,10 +3123,12 @@ builder_manifest_cleanup (BuilderManifest *self, 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_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); @@ -3141,6 +3146,7 @@ builder_manifest_cleanup (BuilderManifest *self, app_root_path, data_dir, icon_dir, + hint_dir, media_dir, url, as_url_policy, @@ -3155,6 +3161,7 @@ builder_manifest_cleanup (BuilderManifest *self, app_root_path, data_dir, icon_dir, + hint_dir, NULL, NULL, as_url_policy, From aaf3399efff8dd29dfbaa4f20698b5e92721470c Mon Sep 17 00:00:00 2001 From: bbhtt Date: Mon, 27 Apr 2026 10:25:47 +0530 Subject: [PATCH 5/6] [drop] Add a stub header for asc-font --- src/asc-font.h | 20 ++++++++++++++++++++ src/meson.build | 1 + 2 files changed, 21 insertions(+) create mode 100644 src/asc-font.h 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/meson.build b/src/meson.build index 82ead752..e152f264 100644 --- a/src/meson.build +++ b/src/meson.build @@ -66,6 +66,7 @@ flatpak_builder_deps = [ flatpak_builder = executable( 'flatpak-builder', flatpak_builder_sources, + include_directories: include_directories('.'), dependencies: flatpak_builder_deps, install: true, ) From 862f9c9e8adb028c1d53b3f8b16ca8cf4ba6327d Mon Sep 17 00:00:00 2001 From: bbhtt Date: Mon, 27 Apr 2026 10:33:27 +0530 Subject: [PATCH 6/6] [drop] Define stuff --- .github/dependencies.apt.txt | 1 + src/builder-manifest.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/.github/dependencies.apt.txt b/.github/dependencies.apt.txt index ea376c44..0fc5bd7f 100644 --- a/.github/dependencies.apt.txt +++ b/.github/dependencies.apt.txt @@ -9,6 +9,7 @@ gettext git git-lfs libappstream-compose-dev +libappstream-dev libarchive-tools libcurl4-openssl-dev libelf-dev diff --git a/src/builder-manifest.c b/src/builder-manifest.c index 52f29aa3..b6a8bbe7 100644 --- a/src/builder-manifest.c +++ b/src/builder-manifest.c @@ -30,9 +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"