summaryrefslogtreecommitdiffstats
path: root/scripts/make-index-json.py
blob: 7751cde810236a81f5416d29374d893614e216ec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#!/usr/bin/env python3
"""
Parse the native package index files into a json file for use by downstream
tools.  See:

    https://github.com/openwrt/openwrt/commit/218ce40cd738f3373438aab82467807a8707fb9c

The "version 1" index.json contained ABI-versioned package names, making the
unusable by the ASU server.  The version 2 format contains package names that
have been stripped of their ABI version.
"""

import email.parser
import json


def removesuffix(src, suffix):
    # For compatibility with Python < 3.9.
    suffix_length = len(suffix)
    return src[:-suffix_length] if suffix_length and src.endswith(suffix) else src


def parse_args():
    from argparse import ArgumentParser

    source_format = "apk", "opkg"

    parser = ArgumentParser()
    # fmt: off
    parser.add_argument("-a", "--architecture", required=True,
                        help="Required device architecture: like 'x86_64' or 'aarch64_generic'")
    parser.add_argument("-f", "--source-format", required=True, choices=source_format,
                        help="Required source format of input: 'apk' or 'opkg'")
    parser.add_argument("-m", "--manifest", action="store_true", default=False,
                        help="Print output in manifest format, as package:version pairs")
    parser.add_argument(dest="source",
                        help="File name for input, '-' for stdin")
    # fmt: on
    args = parser.parse_args()
    return args


def parse_apk(text: str) -> dict:
    packages: dict = {}

    data = json.loads(text)
    if isinstance(data, dict) and "packages" in data:
        # Extract 'apk adbdump' dict field to 'apk query' package list
        data = data["packages"]

    for package in data:
        package_name: str = package["name"]

        for tag in package.get("tags", []):
            if tag.startswith("openwrt:abiversion="):
                package_abi: str = tag.split("=")[-1]
                package_name = removesuffix(package_name, package_abi)
                break

        packages[package_name] = package["version"]

    return packages


def parse_opkg(text: str) -> dict:
    packages: dict = {}

    parser: email.parser.Parser = email.parser.Parser()
    chunks: list[str] = text.strip().split("\n\n")
    for chunk in chunks:
        package: dict = parser.parsestr(chunk, headersonly=True)
        package_name: str = package["Package"]
        package_abi = package.get("ABIVersion")
        if package_abi:
            package_name = removesuffix(package_name, package_abi)

        packages[package_name] = package["Version"]

    return packages


if __name__ == "__main__":
    import sys

    args = parse_args()

    input = sys.stdin if args.source == "-" else open(args.source, "r")
    with input:
        text: str = input.read()

    packages = parse_apk(text) if args.source_format == "apk" else parse_opkg(text)
    if args.manifest:
        for name, version in packages.items():
            print(name, version)
    else:
        index = {
            "version": 2,
            "architecture": args.architecture,
            "packages": packages,
        }
        print(json.dumps(index, indent=2))