diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml
index da15643d..f212cc71 100644
--- a/.github/workflows/check.yml
+++ b/.github/workflows/check.yml
@@ -74,14 +74,14 @@ jobs:
run: make -j $(getconf _NPROCESSORS_ONLN)
check-meson:
- name: Ubuntu 22.04 meson build
- runs-on: ubuntu-22.04
+ name: Ubuntu meson build
+ runs-on: ${{ matrix.os }}
strategy:
matrix:
+ os: ['ubuntu-22.04', 'ubuntu-24.04']
compiler: ['gcc', 'clang']
env:
- UBUNTU_VERSION: '22.04'
CC: ${{ matrix.compiler }}
BASE_CFLAGS: -Wp,-D_FORTIFY_SOURCE=2
BUILDDIR: builddir
diff --git a/doc/flatpak-builder.xml b/doc/flatpak-builder.xml
index 847bb57e..6cc19e2b 100644
--- a/doc/flatpak-builder.xml
+++ b/doc/flatpak-builder.xml
@@ -589,6 +589,21 @@
+
+
+
+
+ Set the AppStream compose URL policy. Accepted values
+ are partial and full.
+ full requires AppStream version >= 0.16.3.
+ Defaults to partial if unspecified.
+ This policy only takes effect when used in conjunction
+ with ;
+ otherwise the Appstream catalogue will preserve
+ the source media URLs.
+
+
+
diff --git a/src/builder-context.c b/src/builder-context.c
index 508ab91f..4458a229 100644
--- a/src/builder-context.c
+++ b/src/builder-context.c
@@ -88,6 +88,8 @@ struct BuilderContext
char *opt_mirror_screenshots_url;
BuilderSdkConfig *sdk_config;
+
+ BuilderAsUrlPolicy as_url_policy;
};
typedef struct
@@ -1241,6 +1243,19 @@ builder_context_create_state_dir (BuilderContext *self,
return TRUE;
}
+void
+builder_context_set_as_url_policy (BuilderContext *self,
+ BuilderAsUrlPolicy policy)
+{
+ self->as_url_policy = policy;
+}
+
+BuilderAsUrlPolicy
+builder_context_get_as_url_policy (BuilderContext *self)
+{
+ return self->as_url_policy;
+}
+
BuilderContext *
builder_context_new (GFile *run_dir,
GFile *app_dir,
diff --git a/src/builder-context.h b/src/builder-context.h
index 69671398..f6c12329 100644
--- a/src/builder-context.h
+++ b/src/builder-context.h
@@ -29,6 +29,11 @@
G_BEGIN_DECLS
+typedef enum {
+ BUILDER_AS_URL_POLICY_PARTIAL = 0,
+ BUILDER_AS_URL_POLICY_FULL,
+} BuilderAsUrlPolicy;
+
/* Same as SOUP_HTTP_URI_FLAGS, means all possible flags for http uris */
#if GLIB_CHECK_VERSION (2, 68, 0)
@@ -185,6 +190,10 @@ BuilderSdkConfig * builder_context_get_sdk_config (BuilderContext *self);
gboolean builder_context_create_state_dir (BuilderContext *self,
GError **error);
+void builder_context_set_as_url_policy (BuilderContext *self,
+ BuilderAsUrlPolicy policy);
+BuilderAsUrlPolicy builder_context_get_as_url_policy (BuilderContext *self);
+
G_DEFINE_AUTOPTR_CLEANUP_FUNC (BuilderContext, g_object_unref)
G_END_DECLS
diff --git a/src/builder-main.c b/src/builder-main.c
index aa6d0e4d..dfb61d66 100644
--- a/src/builder-main.c
+++ b/src/builder-main.c
@@ -89,6 +89,7 @@ static gboolean opt_log_session_bus;
static gboolean opt_log_system_bus;
static gboolean opt_yes;
static gint64 opt_source_date_epoch = -1;
+static gchar *opt_as_url_policy = NULL;
static GOptionEntry entries[] = {
{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &opt_verbose, "Print debug information during command processing", NULL },
@@ -144,6 +145,7 @@ static GOptionEntry entries[] = {
{ "assumeyes", 'y', 0, G_OPTION_ARG_NONE, &opt_yes, N_("Automatically answer yes for all questions"), NULL },
{ "no-shallow-clone", 0, 0, G_OPTION_ARG_NONE, &opt_no_shallow_clone, "Don't use shallow clones when mirroring git repos", NULL },
{ "override-source-date-epoch", 0, 0, G_OPTION_ARG_INT64, &opt_source_date_epoch, "Use this timestamp to perform the build, instead of the last modification time of the manifest.", NULL },
+ { "compose-url-policy", 0, 0, G_OPTION_ARG_STRING, &opt_as_url_policy, "Set the AppStream compose URL policy to either 'partial' (default) or 'full'", "POLICY" },
{ NULL }
};
@@ -608,6 +610,29 @@ main (int argc,
builder_context_set_opt_export_only (build_context, opt_export_only);
builder_context_set_opt_mirror_screenshots_url (build_context, opt_mirror_screenshots_url);
+ if (opt_mirror_screenshots_url)
+ {
+ BuilderAsUrlPolicy policy = BUILDER_AS_URL_POLICY_PARTIAL;
+
+ if (g_strcmp0 (opt_as_url_policy, "full") == 0)
+ policy = BUILDER_AS_URL_POLICY_FULL;
+ else if (g_strcmp0 (opt_as_url_policy, "partial") == 0)
+ policy = BUILDER_AS_URL_POLICY_PARTIAL;
+ else if (opt_as_url_policy != NULL)
+ {
+ g_printerr ("Invalid value for --compose-url-policy: %s\n", opt_as_url_policy);
+ 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);
+ }
+
git_init_email ();
if (!builder_context_create_state_dir (build_context, &error))
diff --git a/src/builder-manifest.c b/src/builder-manifest.c
index 50596368..0fc94ebe 100644
--- a/src/builder-manifest.c
+++ b/src/builder-manifest.c
@@ -2422,7 +2422,8 @@ cmpstringp (const void *p1, const void *p2)
}
static gboolean
-appstreamcli_compose (GError **error,
+appstreamcli_compose (GError **error,
+ BuilderAsUrlPolicy as_url_policy,
...)
{
g_autoptr(GPtrArray) args = NULL;
@@ -2433,7 +2434,10 @@ appstreamcli_compose (GError **error,
g_ptr_array_add (args, g_strdup ("appstreamcli"));
g_ptr_array_add (args, g_strdup ("compose"));
- va_start (ap, error);
+ if (as_url_policy == BUILDER_AS_URL_POLICY_FULL)
+ g_ptr_array_add (args, g_strdup ("--no-partial-urls"));
+
+ 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);
@@ -3066,6 +3070,7 @@ builder_manifest_cleanup (BuilderManifest *self,
flatpak_file_get_path_cached (icon_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)
{
@@ -3077,6 +3082,7 @@ builder_manifest_cleanup (BuilderManifest *self,
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,
@@ -3093,6 +3099,7 @@ builder_manifest_cleanup (BuilderManifest *self,
{
g_print ("Running appstreamcli compose\n");
if (!appstreamcli_compose (error,
+ as_url_policy,
"--prefix=/",
origin,
result_root_arg,
diff --git a/src/builder-utils.c b/src/builder-utils.c
index 060fdeed..7a8b0083 100644
--- a/src/builder-utils.c
+++ b/src/builder-utils.c
@@ -1837,3 +1837,52 @@ 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(GSubprocess) subp = NULL;
+ g_autofree char *out = NULL;
+ g_auto(GStrv) lines = NULL;
+
+ subp = g_subprocess_newv (argv, G_SUBPROCESS_FLAGS_STDOUT_PIPE, 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/builder-utils.h b/src/builder-utils.h
index 05dfd839..ddbc5a00 100644
--- a/src/builder-utils.h
+++ b/src/builder-utils.h
@@ -216,6 +216,10 @@ gboolean flatpak_version_check (int major,
int minor,
int micro);
+gboolean appstream_has_version (int major,
+ int minor,
+ int micro);
+
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakXml, flatpak_xml_free);
G_END_DECLS
diff --git a/tests/Makefile.am.inc b/tests/Makefile.am.inc
index ff10308d..a16c74f3 100644
--- a/tests/Makefile.am.inc
+++ b/tests/Makefile.am.inc
@@ -61,6 +61,8 @@ dist_installed_test_data = \
tests/org.flatpak_builder.gui.desktop \
tests/org.flatpak_builder.gui.json \
tests/org.flatpak_builder.gui.metainfo.xml \
+ tests/org.flatpak.appstream_media.json \
+ tests/org.test.Hello-256.png \
$(NULL)
installed_test_keyringdir = $(installed_testdir)/test-keyring
diff --git a/tests/libtest.sh b/tests/libtest.sh
index 3536e922..75c1f215 100644
--- a/tests/libtest.sh
+++ b/tests/libtest.sh
@@ -309,6 +309,47 @@ skip_without_python2 () {
fi
}
+appstream_has_version () {
+ req_major=$1
+ req_minor=$2
+ req_micro=$3
+
+ maj=0; min=0; mic=0
+
+ out=$(appstreamcli --version 2>/dev/null) || return 1
+
+ while IFS= read -r line; do
+ case "$line" in
+ "AppStream library version:"* )
+ ver=$(echo "$line" | awk '{print $4}')
+ ;;
+ "AppStream version:"* )
+ ver=$(echo "$line" | awk '{print $3}')
+ ;;
+ * ) continue ;;
+ esac
+
+ maj=$(echo "$ver" | cut -d. -f1)
+ min=$(echo "$ver" | cut -d. -f2)
+ mic=$(echo "$ver" | cut -d. -f3)
+ break
+ done <&2 || true
if test -n "${TEST_SKIP_CLEANUP:-}"; then
diff --git a/tests/meson.build b/tests/meson.build
index 46c84fa9..373ed557 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -108,6 +108,8 @@ if get_option('installed_tests')
'org.flatpak_builder.gui.desktop',
'org.flatpak_builder.gui.json',
'org.flatpak_builder.gui.metainfo.xml',
+ 'org.flatpak.appstream_media.json',
+ 'org.test.Hello-256.png',
install_dir: installed_testdir,
install_mode: 'rw-r--r--',
diff --git a/tests/org.flatpak.appstream_media.json b/tests/org.flatpak.appstream_media.json
new file mode 100644
index 00000000..c9adf661
--- /dev/null
+++ b/tests/org.flatpak.appstream_media.json
@@ -0,0 +1,44 @@
+{
+ "id": "org.flatpak.appstream_media",
+ "runtime": "org.test.Platform",
+ "sdk": "org.test.Sdk",
+ "rename-desktop-file": "org.flatpak_builder.gui.desktop",
+ "rename-appdata-file": "org.flatpak_builder.gui.metainfo.xml",
+ "rename-icon": "org.test.Hello-256",
+ "command": "hello",
+ "modules": [
+ {
+ "name": "appstream_media",
+ "buildsystem": "simple",
+ "build-commands": [
+ "mkdir -p ${FLATPAK_DEST}/bin ${FLATPAK_DEST}/share/metainfo ${FLATPAK_DEST}/share/applications",
+ "mkdir -p ${FLATPAK_DEST}/share/icons/hicolor/256x256/apps",
+ "cp -vf hello.sh ${FLATPAK_DEST}/bin/hello",
+ "cp -vf org.flatpak_builder.gui.metainfo.xml ${FLATPAK_DEST}/share/metainfo",
+ "cp -vf org.flatpak_builder.gui.desktop ${FLATPAK_DEST}/share/applications",
+ "cp -vf org.test.Hello-256.png ${FLATPAK_DEST}/share/icons/hicolor/256x256/apps"
+ ],
+ "sources": [
+ {
+ "type": "script",
+ "dest-filename": "hello.sh",
+ "commands": [
+ "echo \"Hello world, from a sandbox\""
+ ]
+ },
+ {
+ "type": "file",
+ "path": "org.flatpak_builder.gui.desktop"
+ },
+ {
+ "type": "file",
+ "path": "org.flatpak_builder.gui.metainfo.xml"
+ },
+ {
+ "type": "file",
+ "path": "org.test.Hello-256.png"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/org.test.Hello-256.png b/tests/org.test.Hello-256.png
new file mode 100644
index 00000000..68473c5a
Binary files /dev/null and b/tests/org.test.Hello-256.png differ
diff --git a/tests/test-builder.sh b/tests/test-builder.sh
index 8b22ac8a..0b29ef1f 100755
--- a/tests/test-builder.sh
+++ b/tests/test-builder.sh
@@ -23,7 +23,7 @@ set -euo pipefail
skip_without_fuse
-echo "1..8"
+echo "1..10"
setup_repo
install_repo
@@ -53,6 +53,8 @@ cp $(dirname $0)/org.flatpak_builder.gui.desktop .
cp $(dirname $0)/org.flatpak_builder.gui.json .
cp $(dirname $0)/org.flatpak_builder.gui.metainfo.xml .
cp $(dirname $0)/org.test.Hello.png .
+cp $(dirname $0)/org.test.Hello-256.png .
+cp $(dirname $0)/org.flatpak.appstream_media.json .
mkdir include1
cp $(dirname $0)/module1.json include1/
cp $(dirname $0)/module1.yaml include1/
@@ -144,3 +146,30 @@ ostree checkout --repo=$REPO/repo_sc -U screenshots/$(flatpak --default-arch) ou
find outdir_sc -path "*/icons/64x64/org.test.Hello.png" -type f | grep -q .
echo "ok screenshot ref commit"
+
+# test compose partial url policy
+${FLATPAK_BUILDER} --force-clean builddir_sc \
+ --mirror-screenshots-url=https://example.org/media \
+ --state-dir .fp-compose-url-policy-partial \
+ --compose-url-policy=partial \
+ org.flatpak.appstream_media.json >&2
+# we test for the icon tag instead of screenshot
+# the former works offline the latter does not
+gzip -cdq builddir_sc/files/share/app-info/xmls/org.flatpak.appstream_media.xml.gz|grep -Eq '>org/flatpak/appstream_media/[^/]+/icons/128x128/org.flatpak.appstream_media.png'
+
+echo "ok compose partial url policy"
+
+# test compose full url policy
+if appstream_has_version 0 16 3; then
+ ${FLATPAK_BUILDER} --force-clean builddir_sc \
+ --mirror-screenshots-url=https://example.org/media \
+ --state-dir .fp-compose-url-policy-full \
+ --compose-url-policy=full \
+ org.flatpak.appstream_media.json >&2
+
+ gzip -cdq builddir_sc/files/share/app-info/xmls/org.flatpak.appstream_media.xml.gz|grep -Eq '>https://example.org/media/org/flatpak/appstream_media/[^/]+/icons/128x128/org.flatpak.appstream_media.png'
+
+ echo "ok compose full url policy"
+else
+ echo "ok # Skip AppStream < 0.16.3"
+fi