From a7000253364b14662d136adc145834416e2bbfd8 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Fri, 10 Nov 2023 14:39:48 +0000 Subject: [PATCH 1/3] Refactor generating Flatpak manifest Move the main body of this script into a main() function, in advance of factoring more sections out of it. https://phabricator.endlessm.com/T35013 --- hooks/image/70-flatpak-manifest | 201 ++++++++++++++++---------------- 1 file changed, 103 insertions(+), 98 deletions(-) diff --git a/hooks/image/70-flatpak-manifest b/hooks/image/70-flatpak-manifest index dfadb54a..d1e2995e 100755 --- a/hooks/image/70-flatpak-manifest +++ b/hooks/image/70-flatpak-manifest @@ -34,106 +34,111 @@ def write_manifest(data): json.dump(data, manifest) -# Build the json data structure -data = { - 'flatpak': { - 'remotes': {}, - 'runtimes': {}, - 'apps': {}, +def main(): + # Build the json data structure + data = { + 'flatpak': { + 'remotes': {}, + 'runtimes': {}, + 'apps': {}, + } } -} -if os.environ.get('EIB_FLATPAK_ENABLE', 'false') != 'true': - # Write out an empty manifest so it always exists + if os.environ.get('EIB_FLATPAK_ENABLE', 'false') != 'true': + # Write out an empty manifest so it always exists + write_manifest(data) + return + + # Open the flatpak installation in the OS /var/lib/flatpak. + system_path = os.path.join(os.environ['OSTREE_VAR'], 'lib/flatpak') + print('Opening flatpak installation in', system_path) + system_file = Gio.File.new_for_path(system_path) + system = Flatpak.Installation.new_for_path(system_file, user=False) + + repo_file = system_file.get_child('repo') + print('Opening ostree repo in', repo_file.get_path()) + repo = OSTree.Repo.new(repo_file) + repo.open() + + remotes = system.list_remotes() + for remote in remotes: + name = remote.get_name() + url = remote.get_url() + collection_id = remote.get_collection_id() + + # Skip disabled remotes + if remote.get_disabled(): + continue + + # Skip local remotes (e.g., external apps) + if url.startswith('file://'): + continue + + data['flatpak']['remotes'][name] = { + 'url': url, + 'collection-id': collection_id, + } + + runtimes = system.list_installed_refs_by_kind(Flatpak.RefKind.RUNTIME) + for runtime in runtimes: + name = runtime.get_name() + arch = runtime.get_arch() + branch = runtime.get_branch() + key = '{}/{}/{}'.format(name, arch, branch) + remote = runtime.get_origin() + commit = runtime.get_commit() + size = runtime.get_installed_size() + ref = runtime.format_ref() + date = commit_date_string(repo, commit) + version = runtime.get_appdata_version() + + data['flatpak']['runtimes'][key] = { + 'name': name, + 'arch': arch, + 'branch': branch, + 'remote': remote, + 'commit': commit, + 'size': size, + 'ref': ref, + 'date': date, + 'version': version, + } + + apps = system.list_installed_refs_by_kind(Flatpak.RefKind.APP) + for app in apps: + name = app.get_name() + arch = app.get_arch() + branch = app.get_branch() + key = '{}/{}/{}'.format(name, arch, branch) + remote = app.get_origin() + commit = app.get_commit() + size = app.get_installed_size() + ref = app.format_ref() + date = commit_date_string(repo, commit) + version = app.get_appdata_version() + metadata = GLib.KeyFile() + metadata.load_from_bytes(app.load_metadata(), GLib.KeyFileFlags.NONE) + try: + runtime = metadata.get_string('Application', 'runtime') + except GLib.GError: + runtime = None + + data['flatpak']['apps'][key] = { + 'name': name, + 'arch': arch, + 'branch': branch, + 'remote': remote, + 'commit': commit, + 'size': size, + 'ref': ref, + 'date': date, + 'version': version, + 'runtime': runtime, + } + + # Now write out the json to a fragment write_manifest(data) - exit(0) - -# Open the flatpak installation in the OS /var/lib/flatpak. -system_path = os.path.join(os.environ['OSTREE_VAR'], 'lib/flatpak') -print('Opening flatpak installation in', system_path) -system_file = Gio.File.new_for_path(system_path) -system = Flatpak.Installation.new_for_path(system_file, user=False) - -repo_file = system_file.get_child('repo') -print('Opening ostree repo in', repo_file.get_path()) -repo = OSTree.Repo.new(repo_file) -repo.open() - -remotes = system.list_remotes() -for remote in remotes: - name = remote.get_name() - url = remote.get_url() - collection_id = remote.get_collection_id() - - # Skip disabled remotes - if remote.get_disabled(): - continue - - # Skip local remotes (e.g., external apps) - if url.startswith('file://'): - continue - - data['flatpak']['remotes'][name] = { - 'url': url, - 'collection-id': collection_id, - } - -runtimes = system.list_installed_refs_by_kind(Flatpak.RefKind.RUNTIME) -for runtime in runtimes: - name = runtime.get_name() - arch = runtime.get_arch() - branch = runtime.get_branch() - key = '{}/{}/{}'.format(name, arch, branch) - remote = runtime.get_origin() - commit = runtime.get_commit() - size = runtime.get_installed_size() - ref = runtime.format_ref() - date = commit_date_string(repo, commit) - version = runtime.get_appdata_version() - - data['flatpak']['runtimes'][key] = { - 'name': name, - 'arch': arch, - 'branch': branch, - 'remote': remote, - 'commit': commit, - 'size': size, - 'ref': ref, - 'date': date, - 'version': version, - } -apps = system.list_installed_refs_by_kind(Flatpak.RefKind.APP) -for app in apps: - name = app.get_name() - arch = app.get_arch() - branch = app.get_branch() - key = '{}/{}/{}'.format(name, arch, branch) - remote = app.get_origin() - commit = app.get_commit() - size = app.get_installed_size() - ref = app.format_ref() - date = commit_date_string(repo, commit) - version = app.get_appdata_version() - metadata = GLib.KeyFile() - metadata.load_from_bytes(app.load_metadata(), GLib.KeyFileFlags.NONE) - try: - runtime = metadata.get_string('Application', 'runtime') - except GLib.GError: - runtime = None - - data['flatpak']['apps'][key] = { - 'name': name, - 'arch': arch, - 'branch': branch, - 'remote': remote, - 'commit': commit, - 'size': size, - 'ref': ref, - 'date': date, - 'version': version, - 'runtime': runtime, - } -# Now write out the json to a fragment -write_manifest(data) +if __name__ == '__main__': + main() From 025ef88fc06c7691a593f055967b425d78b6dca8 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Fri, 10 Nov 2023 14:39:52 +0000 Subject: [PATCH 2/3] Refactor building per-app/-runtime manifest snippets There is a common subset of keys being exported for installed apps and runtimes alike. Factor this out into a function, so we can export even more data. https://phabricator.endlessm.com/T35013 --- hooks/image/70-flatpak-manifest | 78 ++++++++++++++------------------- 1 file changed, 34 insertions(+), 44 deletions(-) diff --git a/hooks/image/70-flatpak-manifest b/hooks/image/70-flatpak-manifest index d1e2995e..c8d68eee 100755 --- a/hooks/image/70-flatpak-manifest +++ b/hooks/image/70-flatpak-manifest @@ -34,6 +34,34 @@ def write_manifest(data): json.dump(data, manifest) +def get_data_for_ref( + repo: OSTree.Repo, + installed_ref: Flatpak.InstalledRef, +) -> dict: + name = installed_ref.get_name() + arch = installed_ref.get_arch() + branch = installed_ref.get_branch() + key = '{}/{}/{}'.format(name, arch, branch) + remote = installed_ref.get_origin() + commit = installed_ref.get_commit() + size = installed_ref.get_installed_size() + ref = installed_ref.format_ref() + date = commit_date_string(repo, commit) + version = installed_ref.get_appdata_version() + + return key, { + 'name': name, + 'arch': arch, + 'branch': branch, + 'remote': remote, + 'commit': commit, + 'size': size, + 'ref': ref, + 'date': date, + 'version': version, + } + + def main(): # Build the json data structure data = { @@ -81,60 +109,22 @@ def main(): runtimes = system.list_installed_refs_by_kind(Flatpak.RefKind.RUNTIME) for runtime in runtimes: - name = runtime.get_name() - arch = runtime.get_arch() - branch = runtime.get_branch() - key = '{}/{}/{}'.format(name, arch, branch) - remote = runtime.get_origin() - commit = runtime.get_commit() - size = runtime.get_installed_size() - ref = runtime.format_ref() - date = commit_date_string(repo, commit) - version = runtime.get_appdata_version() - - data['flatpak']['runtimes'][key] = { - 'name': name, - 'arch': arch, - 'branch': branch, - 'remote': remote, - 'commit': commit, - 'size': size, - 'ref': ref, - 'date': date, - 'version': version, - } + key, runtime_data = get_data_for_ref(repo, runtime) + data['flatpak']['runtimes'][key] = runtime_data apps = system.list_installed_refs_by_kind(Flatpak.RefKind.APP) for app in apps: - name = app.get_name() - arch = app.get_arch() - branch = app.get_branch() - key = '{}/{}/{}'.format(name, arch, branch) - remote = app.get_origin() - commit = app.get_commit() - size = app.get_installed_size() - ref = app.format_ref() - date = commit_date_string(repo, commit) - version = app.get_appdata_version() + key, app_data = get_data_for_ref(repo, app) + metadata = GLib.KeyFile() metadata.load_from_bytes(app.load_metadata(), GLib.KeyFileFlags.NONE) try: runtime = metadata.get_string('Application', 'runtime') except GLib.GError: runtime = None + app_data['runtime'] = runtime - data['flatpak']['apps'][key] = { - 'name': name, - 'arch': arch, - 'branch': branch, - 'remote': remote, - 'commit': commit, - 'size': size, - 'ref': ref, - 'date': date, - 'version': version, - 'runtime': runtime, - } + data['flatpak']['apps'][key] = app_data # Now write out the json to a fragment write_manifest(data) From 7ea457cbc6899c350edc9d669d59dae90ce350d2 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Fri, 10 Nov 2023 14:55:26 +0000 Subject: [PATCH 3/3] Add human-readable name & summary to Flatpak manifest https://phabricator.endlessm.com/T35013 --- hooks/image/70-flatpak-manifest | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/hooks/image/70-flatpak-manifest b/hooks/image/70-flatpak-manifest index c8d68eee..9286e69a 100755 --- a/hooks/image/70-flatpak-manifest +++ b/hooks/image/70-flatpak-manifest @@ -49,7 +49,7 @@ def get_data_for_ref( date = commit_date_string(repo, commit) version = installed_ref.get_appdata_version() - return key, { + data = { 'name': name, 'arch': arch, 'branch': branch, @@ -61,6 +61,20 @@ def get_data_for_ref( 'version': version, } + # TODO: It would be nice to consider EIB_FLATPAK_LOCALES and extract the + # name and summary in those locales too. Unfortunately while there is + # internal API to do this easily, it is not exposed by libflatpak. + appdata_name = installed_ref.get_appdata_name() + appdata_summary = installed_ref.get_appdata_summary() + if appdata_name or appdata_summary: + data['appdata'] = {'C': {}} + if appdata_name: + data['appdata']['C']['name'] = appdata_name + if appdata_summary: + data['appdata']['C']['summary'] = appdata_summary + + return key, data + def main(): # Build the json data structure