From 4c384692e896e5949cd6f65f8e324f102d4c8dfb Mon Sep 17 00:00:00 2001 From: bbhtt Date: Sat, 16 May 2026 11:06:46 +0530 Subject: [PATCH 01/10] ci: Use ubuntu 26.04 container Needed for new dependencies like appstream, GitHub is yet to make actions-images available for 26.04 --- .github/workflows/check.yml | 7 ++++--- .github/workflows/release.yml | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 188bd938..a2203ba6 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -21,6 +21,7 @@ jobs: check-meson: name: Ubuntu meson build runs-on: ${{ matrix.os }} + container: ubuntu:26.04 strategy: matrix: os: ['ubuntu-24.04'] @@ -39,9 +40,9 @@ jobs: - name: Install Dependencies run: | - sudo apt-get update - sudo apt-get install -y findutils - sudo apt-get install -y \ + apt-get update + apt-get install -y findutils + apt-get install -y \ ${{ matrix.compiler }} \ $(xargs < .github/dependencies.apt.txt) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5ee3fa6c..2f1bfaeb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,6 +13,7 @@ jobs: release: name: Build and publish release runs-on: ubuntu-24.04 + container: ubuntu:26.04 permissions: contents: write steps: @@ -24,9 +25,9 @@ jobs: - name: Install Dependencies run: | - sudo apt-get update - sudo apt-get install -y findutils - sudo apt-get install -y \ + apt-get update + apt-get install -y findutils + apt-get install -y \ gcc \ perl \ jq \ From f7c9da6ea1620a510a498c6fcfbfbf6eb955d885 Mon Sep 17 00:00:00 2001 From: bbhtt Date: Sat, 16 May 2026 11:18:51 +0530 Subject: [PATCH 02/10] builder-flatpak-utils: Fix const correctness warnings Glibc 2.43 implements C23 const-preserving string-search functions [1] This fixes the build with Glibc 2.43 and GCC 15.1 (which defaults to C23). [1]: https://sourceware.org/glibc/wiki/Release/2.43#C23_Const-Preserving_Standard_Library_Macros_May_Break_Some_Packages --- src/builder-flatpak-utils.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/builder-flatpak-utils.c b/src/builder-flatpak-utils.c index 927bdade..34a37087 100644 --- a/src/builder-flatpak-utils.c +++ b/src/builder-flatpak-utils.c @@ -185,7 +185,7 @@ flatpak_path_match_prefix (const char *pattern, /* special case * at end */ if (c == 0) { - char *tmp = strchr (string, '/'); + const char *tmp = strchr (string, '/'); if (tmp != NULL) return tmp; return string + strlen (string); @@ -1633,7 +1633,7 @@ get_xdg_user_dir_from_string (const char *filesystem, const char **suffix, const char **dir) { - char *slash; + const char *slash; const char *rest; g_autofree char *prefix = NULL; gsize len; @@ -2087,7 +2087,7 @@ option_add_generic_policy_cb (const gchar *option_name, GError **error) { FlatpakContext *context = data; - char *t; + const char *t; g_autofree char *key = NULL; const char *policy_value; @@ -2114,7 +2114,7 @@ option_remove_generic_policy_cb (const gchar *option_name, GError **error) { FlatpakContext *context = data; - char *t; + const char *t; g_autofree char *key = NULL; const char *policy_value; g_autofree char *extended_value = NULL; From b6cd2e6376a1c97644cc2d19becf1053d8be5ca0 Mon Sep 17 00:00:00 2001 From: bbhtt Date: Sat, 16 May 2026 11:25:38 +0530 Subject: [PATCH 03/10] ci: Exercise -Werror in CI Only for non-wrap path as upstream projects in wraps are unmaintained --- .github/workflows/check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index a2203ba6..24ce81c3 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -47,7 +47,7 @@ jobs: $(xargs < .github/dependencies.apt.txt) - name: Configure flatpak-builder - run: meson setup --wrap-mode nodownload ${CONFIG_OPTS} ${BUILDDIR} . + run: meson setup --wrap-mode nodownload ${CONFIG_OPTS} -Dwerror=true ${BUILDDIR} . - name: Build flatpak-builder with Meson run: meson compile -C ${BUILDDIR} From 88cfa9c1fb04ff5c916d331fc17347fcacb69ad3 Mon Sep 17 00:00:00 2001 From: bbhtt Date: Sat, 16 May 2026 12:45:38 +0530 Subject: [PATCH 04/10] build: Ignore typedef-redefinition when building with clang --- meson.build | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/meson.build b/meson.build index 049a1758..f5e5d8c3 100644 --- a/meson.build +++ b/meson.build @@ -37,6 +37,17 @@ foreach arg : project_c_args endif endforeach +if cc.get_id() == 'clang' + clang_args = [ + '-Wno-typedef-redefinition', + ] + foreach arg : clang_args + if cc.has_argument(arg) + add_project_arguments(arg, language: 'c') + endif + endforeach +endif + # The debugedit program is a hard dependency debugedit = find_program('debugedit', version: '>= 5.0') From 9335a2134fa827e7003a798cbf0bf3bf4d20dde6 Mon Sep 17 00:00:00 2001 From: bbhtt Date: Sat, 16 May 2026 12:50:46 +0530 Subject: [PATCH 05/10] builder-flatpak-utils: Use long values for curl_easy_setopt Fixes Wattribute-warning when building with clang --- src/builder-flatpak-utils.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/builder-flatpak-utils.c b/src/builder-flatpak-utils.c index 34a37087..2829e7eb 100644 --- a/src/builder-flatpak-utils.c +++ b/src/builder-flatpak-utils.c @@ -1163,11 +1163,11 @@ flatpak_create_curl_session (const char *user_agent) if (curl_session == NULL) return NULL; - curl_easy_setopt (curl_session, CURLOPT_CONNECTTIMEOUT, 60); - curl_easy_setopt (curl_session, CURLOPT_FAILONERROR, 1); - curl_easy_setopt (curl_session, CURLOPT_FOLLOWLOCATION, 1); - curl_easy_setopt (curl_session, CURLOPT_MAXREDIRS, 50); - curl_easy_setopt (curl_session, CURLOPT_NOPROGRESS, 0); + curl_easy_setopt (curl_session, CURLOPT_CONNECTTIMEOUT, 60L); + curl_easy_setopt (curl_session, CURLOPT_FAILONERROR, 1L); + curl_easy_setopt (curl_session, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt (curl_session, CURLOPT_MAXREDIRS, 50L); + curl_easy_setopt (curl_session, CURLOPT_NOPROGRESS, 0L); curl_easy_setopt (curl_session, CURLOPT_LOW_SPEED_TIME, 60L); curl_easy_setopt (curl_session, CURLOPT_LOW_SPEED_LIMIT, 10000L); curl_easy_setopt (curl_session, CURLOPT_USERAGENT, user_agent); From fd5181d89e91980a71d25bdb5e042ce65bcca6c5 Mon Sep 17 00:00:00 2001 From: bbhtt Date: Sat, 16 May 2026 12:59:34 +0530 Subject: [PATCH 06/10] builder-utils: Fix curl write callback signature --- src/builder-utils.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/builder-utils.c b/src/builder-utils.c index e869692e..811ae3aa 100644 --- a/src/builder-utils.c +++ b/src/builder-utils.c @@ -1150,11 +1150,11 @@ typedef struct { GError **error; } CURLWriteData; -static gsize -builder_curl_write_cb (gpointer *buffer, +static size_t +builder_curl_write_cb (char *buffer, gsize size, gsize nmemb, - gpointer *userdata) + void *userdata) { gsize bytes_written; CURLWriteData *write_data = (CURLWriteData *) userdata; From 1859e9e9f6887c1200dea23fcacb252840c01c73 Mon Sep 17 00:00:00 2001 From: bbhtt Date: Mon, 27 Apr 2026 10:24:55 +0530 Subject: [PATCH 07/10] 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 f5e5d8c3..69117fe8 100644 --- a/meson.build +++ b/meson.build @@ -51,10 +51,6 @@ endif # 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 811ae3aa..653fecc3 100644 --- a/src/builder-utils.c +++ b/src/builder-utils.c @@ -1921,55 +1921,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 9179074cb54a75285e6fd6eb3dcaa90db36746be Mon Sep 17 00:00:00 2001 From: bbhtt Date: Mon, 27 Apr 2026 10:16:28 +0530 Subject: [PATCH 08/10] 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 a8d028344f1662d0296b935b61a76abffa90ba83 Mon Sep 17 00:00:00 2001 From: bbhtt Date: Mon, 27 Apr 2026 10:17:25 +0530 Subject: [PATCH 09/10] 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 50d1e0f4fb41c6235fb92f42db00368a1be465a5 Mon Sep 17 00:00:00 2001 From: bbhtt Date: Sat, 16 May 2026 16:23:49 +0530 Subject: [PATCH 10/10] re-add macro --- src/builder-manifest.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/builder-manifest.c b/src/builder-manifest.c index aea8fd83..6be55ca4 100644 --- a/src/builder-manifest.c +++ b/src/builder-manifest.c @@ -30,6 +30,8 @@ #include #include +#define I_KNOW_THE_APPSTREAM_COMPOSE_API_IS_SUBJECT_TO_CHANGE + #include #include