Skip to content

Commit

Permalink
Export appstream catalogue for preinstalled Flatpak apps
Browse files Browse the repository at this point in the history
Although we have added the name and summary for each app to the JSON
manifest, there is no substitute for having all the data. XML compresses
very well!

It is better to capture this at build time rather than fetching it on
the fly later because apps can change or disappear, but we would like to
be able to describe exactly what is in any given image.

librsvg2-compose is required for apps which only ship an SVG file, because
appstream-compose really, really wants to export 64px and 128px bitmaps
for each app.

https://phabricator.endlessm.com/T35013
  • Loading branch information
wjt committed Nov 10, 2023
1 parent 3e90d23 commit f6da493
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ indent_style = space
indent_size = 2

# Python
[{*.py,eos-image-builder,run-build,helpers/{assemble-manifest,fetch-remote-collection-id,generate-ovf-files,kill-chroot-procs,kolibri-pick-content-from-channel,mutable-path,packages-manifest},hooks/{content/{50-flatpak,50-kolibri-content},image/{50-flatpak.chroot,52-ek-content-cache,62-kolibri-options,70-flatpak-manifest,70-ostree-manifest}}}]
[{*.py,eos-image-builder,run-build,helpers/{assemble-manifest,fetch-remote-collection-id,generate-ovf-files,kill-chroot-procs,kolibri-pick-content-from-channel,mutable-path,packages-manifest},hooks/{content/{50-flatpak,50-kolibri-content},image/{50-flatpak.chroot,52-ek-content-cache,62-kolibri-options,70-flatpak-appstream-catalog,70-flatpak-manifest,70-ostree-manifest}}}]
indent_size = 4
max_line_length = 88
1 change: 1 addition & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ filename =
./hooks/content/50-kolibri-content,
./hooks/image/50-flatpak.chroot,
./hooks/image/62-kolibri-options,
./hooks/image/70-flatpak-appstream-catalog,
./hooks/image/70-flatpak-manifest,
./hooks/image/70-ostree-manifest,
./run-build
3 changes: 3 additions & 0 deletions config/defaults.ini
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ base = bullseye

# Packages to install in the buildroot
packages_add =
appstream-util
attr
awscli
ca-certificates
Expand All @@ -88,6 +89,7 @@ packages_add =
json-glib-tools
jq
libfsapfs-utils
librsvg2-common
mount
openssh-client
ostree
Expand Down Expand Up @@ -145,6 +147,7 @@ hooks_add =
62-kolibri-automatic-provision
62-kolibri-options
63-icon-grid
70-flatpak-appstream-catalog
70-flatpak-manifest
70-ostree-manifest
80-ldconfig-aux-cache.chroot
Expand Down
88 changes: 88 additions & 0 deletions hooks/image/70-flatpak-appstream-catalog
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/env python3

# Construct AppStream XML for preinstalled apps

import glob
import logging
import os
import subprocess

logging.basicConfig(
level=logging.INFO,
format='+ %(asctime)s %(levelname)s %(name)s: %(message)s',
datefmt='%H:%M:%S'
)
logger = logging.getLogger(os.path.basename(__file__))


def main():
root = os.path.join(os.environ['OSTREE_VAR'], 'lib/flatpak/exports')

# Find the metainfo files to include in the AppStream.
ids = []
for metainfo in glob.glob(os.path.join(root, 'share/metainfo/*.xml')):
# Everything here should end in .metainfo.xml or .appdata.xml, but
# let's be sure.
if not (metainfo.endswith('.metainfo.xml') or
metainfo.endswith('.appdata.xml')):
raise Exception(f'Unexpected metainfo file {metainfo}')

# It's kind of bad to reject these files here because they're obviously
# valid enough for Flathub to have published them. Reasons that appstream-util
# 0.7.18-1+deb11u1 considers appdata to be invalid include:
#
# - Using a <url type=''> attribute from a more recent version of the spec
# (dozens of apps, including GIMP)
#
# - A <li> element contains a nested <em> element (Pods; OK this is not a
# preinstalled app, but still)
#
# - <release> elements are not in order (FileRoller)
#
# None of these are reasons to exclude the app from the catalogue but there is
# no way to tell the tool to ignore them: if we pass these files to
# appstream-compose it will fail.
#
# TODO: Switch to appstreamcli validate-relax once we are on Bookworm and can
# use appstreamcli compose.
cmd = ('appstream-util', 'validate-relax', '--nonet', metainfo)
proc = subprocess.run(cmd)
if proc.returncode != 0:
logger.warning('Skipping %s considered invalid by appstream-util', metainfo)
continue

# Convert the filename to an "app-id" as expected by
# appstream-compose. This isn't necessarily the app ID but the stem
# of the metainfo XML file without .metainfo.xml or .appdata.xml.
# Most of the time these are the same.
metainfo_id = os.path.basename(metainfo)
if metainfo_id.endswith('.metainfo.xml'):
metainfo_id = metainfo_id.rpartition('.metainfo.xml')[0]
else:
metainfo_id = metainfo_id.rpartition('.appdata.xml')[0]
logger.info('Including metainfo ID %s', metainfo_id)
ids.append(metainfo_id)

# Exit if there aren't any desktop metainfo files.
if len(ids) == 0:
logger.info('No metainfo files')
return

# Compose the AppStream XML.
# TODO: Switch to appstreamcli compose once we are on Bookworm
cmd = [
'appstream-compose',
f'--origin={os.environ["EIB_OUTVERSION"]}',
f'--prefix={root}',
f'--output-dir={os.environ["EIB_OUTDIR"]}',
# We don't want to export the icons but we can't tell
# appstream-compose not to do so...
f'--icons-dir={os.environ["EIB_TMPDIR"]}/appstream-compose-icons',
]
cmd += ids
logger.info('Composing AppStream XML: %s', ' '.join(cmd))
subprocess.run(cmd, check=True)


if __name__ == '__main__':
main()

0 comments on commit f6da493

Please sign in to comment.