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/.github/workflows/check.yml b/.github/workflows/check.yml index 188bd938..24ce81c3 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,14 +40,14 @@ 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) - 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} 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 \ diff --git a/meson.build b/meson.build index 049a1758..69117fe8 100644 --- a/meson.build +++ b/meson.build @@ -37,13 +37,20 @@ 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') -# 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-flatpak-utils.c b/src/builder-flatpak-utils.c index 927bdade..2829e7eb 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); @@ -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); @@ -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; 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..6be55ca4 100644 --- a/src/builder-manifest.c +++ b/src/builder-manifest.c @@ -30,6 +30,11 @@ #include #include +#define I_KNOW_THE_APPSTREAM_COMPOSE_API_IS_SUBJECT_TO_CHANGE + +#include +#include + #include "builder-manifest.h" #include "builder-utils.h" #include "builder-flatpak-utils.h" @@ -2422,30 +2427,71 @@ 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); + 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 +3117,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 e869692e..653fecc3 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; @@ -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, ]