0
0
mirror of https://git.openwrt.org/openwrt/openwrt.git synced 2025-07-06 10:22:59 +00:00
Files
openwrt/scripts/make-index-json.py
Eric Fahlgren 23dc466969 imagebuilder: implement STRIP_ABI option for manifest target
When using apk as the package manager, imagebuilder make command

    make manifest STRIP_ABI=1

does not strip package names of their ABI-version suffix.  The ASU
server relies on this to validate builds, so many snapshot build
requests are failing.

Fix this by using the already existing package data parser in
make-index-json.py and augment it to write the result in manifest
format.

Fixes: https://github.com/openwrt/openwrt/issues/19274
Signed-off-by: Eric Fahlgren <ericfahlgren@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/19278
Signed-off-by: Robert Marko <robimarko@gmail.com>
2025-07-03 12:45:59 +02:00

102 lines
3.1 KiB
Python
Executable File

#!/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))