From 4d4c546709e270c9cfb7da1b5a11453aa39e7e85 Mon Sep 17 00:00:00 2001 From: "David M. Klein" <4+leander19961@noreply.localhost> Date: Wed, 26 Aug 2026 11:44:59 +0200 Subject: [PATCH] =?UTF-8?q?docker/sync=5Fhelpers.py=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker/sync_helpers.py | 105 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 docker/sync_helpers.py diff --git a/docker/sync_helpers.py b/docker/sync_helpers.py new file mode 100644 index 0000000..338e44e --- /dev/null +++ b/docker/sync_helpers.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +""" +sync_helpers.py - small helper used by sync.sh + +Two jobs, on purpose kept out of bash because reliable YAML parsing and XML +escaping in pure bash/sed is a losing game: + + parse-yaml + Reads the "sources:" list from the YAML file and prints it as JSON + on stdout, so sync.sh can loop over it safely (no word-splitting + issues, handles quoting etc.). + + gen-appstream + entries_json is a JSON array of {"name":..., "summary":...} objects + (only the *explicitly requested* top-level packages, never pulled-in + dependencies). Prints a minimal AppStream "generic component" catalog + on stdout, which sync.sh gzips and injects into the repo metadata via + modifyrepo_c. + + NOTE: "generic" components (no icon/screenshots/.desktop file) make a + package installable from GNOME Software / Discover and show up in + search, but will NOT appear on the curated "Explore" front page - + that's a GNOME Software behaviour for non-desktop-app components, not + something fixable at the repo-metadata level. +""" +import sys +import json +import argparse +from xml.sax.saxutils import escape + + +def cmd_parse_yaml(path: str) -> None: + try: + import yaml + except ImportError: + sys.stderr.write( + "ERROR: python3-pyyaml (PyYAML) is not installed.\n" + "Install it with: dnf install -y python3-pyyaml\n" + ) + sys.exit(1) + + with open(path, "r", encoding="utf-8") as fh: + data = yaml.safe_load(fh) or {} + + sources = data.get("sources") or [] + if not isinstance(sources, list): + sys.stderr.write("ERROR: 'sources' in YAML is not a list\n") + sys.exit(1) + + for i, src in enumerate(sources): + for field in ("name", "baseurl", "packages"): + if field not in src: + sys.stderr.write( + f"ERROR: source #{i} is missing required field '{field}'\n" + ) + sys.exit(1) + if not isinstance(src["packages"], list) or not src["packages"]: + sys.stderr.write( + f"ERROR: source '{src.get('name')}' has an empty/invalid packages list\n" + ) + sys.exit(1) + + json.dump(sources, sys.stdout) + + +def cmd_gen_appstream(origin: str, entries_json: str) -> None: + entries = json.loads(entries_json) + print('') + print(f'') + for e in entries: + name = e.get("name", "") + summary = e.get("summary") or f"{name} (mirrored package)" + cid = f"{name}.generic" + print(' ') + print(f" {escape(cid)}") + print(f" {escape(name)}") + print(f" {escape(name)}") + print(f" {escape(summary)}") + print(" CC0-1.0") + print(" unknown") + print(" ") + print("") + + +def main() -> None: + ap = argparse.ArgumentParser() + sub = ap.add_subparsers(dest="cmd", required=True) + + p1 = sub.add_parser("parse-yaml") + p1.add_argument("path") + + p2 = sub.add_parser("gen-appstream") + p2.add_argument("origin") + p2.add_argument("entries_json") + + args = ap.parse_args() + + if args.cmd == "parse-yaml": + cmd_parse_yaml(args.path) + elif args.cmd == "gen-appstream": + cmd_gen_appstream(args.origin, args.entries_json) + + +if __name__ == "__main__": + main()