make-index-json.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #!/usr/bin/env python3
  2. """
  3. Parse the native package index files into a json file for use by downstream
  4. tools. See:
  5. https://github.com/openwrt/openwrt/commit/218ce40cd738f3373438aab82467807a8707fb9c
  6. The "version 1" index.json contained ABI-versioned package names, making the
  7. unusable by the ASU server. The version 2 format contains package names that
  8. have been stripped of their ABI version.
  9. """
  10. import email.parser
  11. import json
  12. def parse_args():
  13. from argparse import ArgumentParser
  14. source_format = "apk", "opkg"
  15. parser = ArgumentParser()
  16. # fmt: off
  17. parser.add_argument("-a", "--architecture", required=True,
  18. help="Required device architecture: like 'x86_64' or 'aarch64_generic'")
  19. parser.add_argument("-f", "--source-format", required=True, choices=source_format,
  20. help="Required source format of input: 'apk' or 'opkg'")
  21. parser.add_argument(dest="source",
  22. help="File name for input, '-' for stdin")
  23. # fmt: on
  24. args = parser.parse_args()
  25. return args
  26. def parse_apk(text: str) -> dict:
  27. packages: dict = {}
  28. data = json.loads(text)
  29. for package in data.get("packages", []):
  30. package_name: str = package["name"]
  31. for tag in package.get("tags", []):
  32. if tag.startswith("openwrt:abiversion="):
  33. package_abi: str = tag.split("=")[-1]
  34. package_name = package_name.removesuffix(package_abi)
  35. break
  36. packages[package_name] = package["version"]
  37. return packages
  38. def parse_opkg(text: str) -> dict:
  39. packages: dict = {}
  40. parser: email.parser.Parser = email.parser.Parser()
  41. chunks: list[str] = text.strip().split("\n\n")
  42. for chunk in chunks:
  43. package: dict = parser.parsestr(chunk, headersonly=True)
  44. package_name: str = package["Package"]
  45. if package_abi := package.get("ABIVersion"):
  46. package_name = package_name.removesuffix(package_abi)
  47. packages[package_name] = package["Version"]
  48. return packages
  49. if __name__ == "__main__":
  50. import sys
  51. args = parse_args()
  52. input = sys.stdin if args.source == "-" else open(args.source, "r")
  53. with input:
  54. text: str = input.read()
  55. packages = parse_apk(text) if args.source_format == "apk" else parse_opkg(text)
  56. index = {
  57. "version": 2,
  58. "architecture": args.architecture,
  59. "packages": packages,
  60. }
  61. print(json.dumps(index, indent=2))