make-index-json.py 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  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 removesuffix(src, suffix):
  13. # For compatibility with Python < 3.9.
  14. suffix_length = len(suffix)
  15. return src[:-suffix_length] if suffix_length and src.endswith(suffix) else src
  16. def parse_args():
  17. from argparse import ArgumentParser
  18. source_format = "apk", "opkg"
  19. parser = ArgumentParser()
  20. # fmt: off
  21. parser.add_argument("-a", "--architecture", required=True,
  22. help="Required device architecture: like 'x86_64' or 'aarch64_generic'")
  23. parser.add_argument("-f", "--source-format", required=True, choices=source_format,
  24. help="Required source format of input: 'apk' or 'opkg'")
  25. parser.add_argument(dest="source",
  26. help="File name for input, '-' for stdin")
  27. # fmt: on
  28. args = parser.parse_args()
  29. return args
  30. def parse_apk(text: str) -> dict:
  31. packages: dict = {}
  32. data = json.loads(text)
  33. for package in data.get("packages", []):
  34. package_name: str = package["name"]
  35. for tag in package.get("tags", []):
  36. if tag.startswith("openwrt:abiversion="):
  37. package_abi: str = tag.split("=")[-1]
  38. package_name = removesuffix(package_name, package_abi)
  39. break
  40. packages[package_name] = package["version"]
  41. return packages
  42. def parse_opkg(text: str) -> dict:
  43. packages: dict = {}
  44. parser: email.parser.Parser = email.parser.Parser()
  45. chunks: list[str] = text.strip().split("\n\n")
  46. for chunk in chunks:
  47. package: dict = parser.parsestr(chunk, headersonly=True)
  48. package_name: str = package["Package"]
  49. package_abi = package.get("ABIVersion")
  50. if package_abi:
  51. package_name = removesuffix(package_name, package_abi)
  52. packages[package_name] = package["Version"]
  53. return packages
  54. if __name__ == "__main__":
  55. import sys
  56. args = parse_args()
  57. input = sys.stdin if args.source == "-" else open(args.source, "r")
  58. with input:
  59. text: str = input.read()
  60. packages = parse_apk(text) if args.source_format == "apk" else parse_opkg(text)
  61. index = {
  62. "version": 2,
  63. "architecture": args.architecture,
  64. "packages": packages,
  65. }
  66. print(json.dumps(index, indent=2))