Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/dependencies.apt.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
appstream-compose
dbus
debugedit
desktop-file-utils
Expand All @@ -9,6 +8,8 @@ fuse3
gettext
git
git-lfs
libappstream-compose-dev
libappstream-compose0-dbgsym
libarchive-tools
libcurl4-openssl-dev
libelf-dev
Expand Down
4 changes: 3 additions & 1 deletion doc/flatpak-builder.xml
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,9 @@
Set the AppStream compose URL policy. Accepted values
are <literal>partial</literal> and <literal>full</literal>.
<literal>full</literal> requires AppStream version >= 0.16.3.
Defaults to <literal>partial</literal> if unspecified.
Defaults to <literal>full</literal> since
1.5.0 but <literal>partial</literal> for earlier
versions, if unspecified.
This policy only takes effect when used in conjunction
with <option>--mirror-screenshots-url=URL</option>;
otherwise the Appstream catalogue will preserve
Expand Down
4 changes: 0 additions & 4 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 2 additions & 8 deletions src/builder-main.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,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" },
{ "compose-url-policy", 0, 0, G_OPTION_ARG_STRING, &opt_as_url_policy, "Set the AppStream compose URL policy to either 'full' (default) or 'partial'", "POLICY" },
{ NULL }
};

Expand Down Expand Up @@ -620,7 +620,7 @@ main (int argc,

if (opt_mirror_screenshots_url)
{
BuilderAsUrlPolicy policy = BUILDER_AS_URL_POLICY_PARTIAL;
BuilderAsUrlPolicy policy = BUILDER_AS_URL_POLICY_FULL;

if (g_strcmp0 (opt_as_url_policy, "full") == 0)
policy = BUILDER_AS_URL_POLICY_FULL;
Expand All @@ -632,12 +632,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);
}

Expand Down
150 changes: 78 additions & 72 deletions src/builder-manifest.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
#include <sys/statfs.h>
#include <glib/gi18n.h>

/* Drop once AppStream 1.1.3 is required */
#define I_KNOW_THE_APPSTREAM_COMPOSE_API_IS_SUBJECT_TO_CHANGE
Comment thread
bbhtt marked this conversation as resolved.
#include <appstream-compose.h>

#include "builder-manifest.h"
#include "builder-utils.h"
#include "builder-flatpak-utils.h"
Expand Down Expand Up @@ -2434,30 +2438,85 @@ cmpstringp (const void *p1, const void *p2)
}

static gboolean
appstreamcli_compose (GError **error,
BuilderAsUrlPolicy as_url_policy,
...)
builder_appstreamcli_compose (const char *app_id,
GFile *app_root,
BuilderContext *context,
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 char *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_autoptr(GFile) data_out = NULL;
g_autoptr(GFile) icon_out = NULL;
const char *app_root_path = NULL;
const char *data_dir = NULL;
const char *icon_dir = NULL;

const char *opt_mirror_screenshots_url = NULL;
gboolean opt_export_only;
BuilderAsUrlPolicy as_url_policy;

g_return_val_if_fail (app_id != NULL, FALSE);
g_return_val_if_fail (G_IS_FILE (app_root), FALSE);

app_root_path = flatpak_file_get_path_cached (app_root);

data_out = flatpak_build_file (app_root, "share/app-info/xmls", NULL);
icon_out = flatpak_build_file (app_root, "share/app-info/icons/flatpak", NULL);

data_dir = flatpak_file_get_path_cached (data_out);
icon_dir = flatpak_file_get_path_cached (icon_out);

opt_mirror_screenshots_url = builder_context_get_opt_mirror_screenshots_url (context);
opt_export_only = builder_context_get_opt_export_only (context);
as_url_policy = builder_context_get_as_url_policy (context);

compose = asc_compose_new ();

asc_compose_set_format (compose, AS_FORMAT_KIND_XML);
asc_compose_set_origin (compose, app_id);
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 (app_root_path);
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);

if (opt_mirror_screenshots_url && !opt_export_only)
{
g_autoptr(GFile) media_out = flatpak_build_file (app_root, "share/app-info/media", NULL);
const char *media_dir = flatpak_file_get_path_cached (media_out);

g_print ("Saving screenshots in %s\n", media_dir);
asc_compose_set_media_baseurl (compose, opt_mirror_screenshots_url);
asc_compose_set_media_result_dir (compose, media_dir);
}

if (as_url_policy == BUILDER_AS_URL_POLICY_FULL)
g_ptr_array_add (args, g_strdup ("--no-partial-urls"));
asc_compose_add_flags (compose, ASC_COMPOSE_FLAG_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);
va_end (ap);
asc_compose_add_flags (compose, ASC_COMPOSE_FLAG_PROPAGATE_CUSTOM);
asc_compose_remove_flags (compose, ASC_COMPOSE_FLAG_ALLOW_SCREENCASTS);

if (!flatpak_spawnv (NULL, NULL, 0, error, (const char * const *)args->pdata, NULL))
g_print ("Running appstreamcli compose\n");

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,
Comment thread
bbhtt marked this conversation as resolved.
"AppStream compose completed with errors");
return FALSE;
}

Expand Down Expand Up @@ -3084,61 +3143,8 @@ 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) 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));
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;
}
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))
return FALSE;
}
if (!builder_appstreamcli_compose (self->id, app_root, context, error))
return FALSE;
}

if (!builder_context_disable_rofiles (context, error))
Expand Down
52 changes: 0 additions & 52 deletions src/builder-utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
1 change: 1 addition & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ flatpak_builder_deps = [
dependency('libglnx', default_options: ['tests=false']),
dependency('libxml-2.0', version: '>= 2.4'),
dependency('ostree-1', version: '>= 2017.14'),
dependency('appstream-compose', version: '>=1.1.2'),
yaml_dep,
]

Expand Down
41 changes: 0 additions & 41 deletions tests/libtest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -330,47 +330,6 @@ skip_without_python2 () {
fi
}

appstream_has_version () {
req_major=$1
req_minor=$2
req_micro=$3

maj=0; min=0; mic=0

out=$(LANGUAGE=C 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 <<EOF
$out
EOF

if [ "$maj" -gt "$req_major" ]; then
return 0
elif [ "$maj" -eq "$req_major" ]; then
if [ "$min" -gt "$req_minor" ]; then
return 0
elif [ "$min" -eq "$req_minor" ]; then
[ "$mic" -ge "$req_micro" ] && return 0
fi
fi

return 1
}

cleanup () {
gpg-connect-agent --homedir "${FL_GPG_HOMEDIR}" killagent /bye >&2 || true
if test -n "${TEST_SKIP_CLEANUP:-}"; then
Expand Down
5 changes: 5 additions & 0 deletions tests/lsan.supp
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,9 @@ leak:g_thread_pool_spawn_thread
leak:g_main_context_iteration
leak:sysprof_collector_get

# Fix in https://github.com/ximion/appstream/pull/752
leak:asc_compose_init
leak:asc_icon_policy_init
leak:asc_compose_process_task_cb

# flatpak-builder
22 changes: 9 additions & 13 deletions tests/test-builder.sh
Original file line number Diff line number Diff line change
Expand Up @@ -180,19 +180,15 @@ gzip -cdq builddir_sc/files/share/app-info/xmls/org.flatpak.appstream_media.xml.
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</icon>'

echo "ok compose full url policy"
else
echo "ok # Skip AppStream < 0.16.3"
fi
${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</icon>'

echo "ok compose full url policy"

# test install
${FLATPAK_BUILDER} --user --install \
Expand Down
Loading