pkgs/rocm-packages/ubuntu2nix.py (106 lines of code) (raw):

#!/usr/bin/env python3 import argparse import json from typing import Any, Dict, Set from urllib import request BASEURL = "https://repo.radeon.com/rocm/apt/{version}" UBUNTU_VERSION = "20.04" parser = argparse.ArgumentParser(description="Parse ROCm repository") parser.add_argument("version", help="ROCm version") class Package: def __init__(self, info: Dict[str, Any]): self._info = info def __str__(self): return f"{self._info['Package']} {self._info['Version']}" def depends(self, version: str) -> Set[str]: if "Depends" in self._info: depends = self._info["Depends"].split(", ") return {depend.split(" ")[0].removesuffix(version) for depend in depends} else: return set() @property def name(self) -> str: return self._info["Package"] @property def sha256(self) -> str: return self._info["SHA256"] @property def version(self) -> str: return self._info["Version"].removesuffix(f"~{UBUNTU_VERSION}") @property def filename(self) -> str: return self._info["Filename"] def package_info(version: str): packages_url = ( f"{BASEURL.format(version=version)}/dists/focal/main/binary-amd64/Packages" ) packages = request.urlopen(packages_url).read().decode("utf-8") info = {} for line in packages.split("\n"): line = line.rstrip() if len(line) == 0: if "Package" in info: yield Package(info) info = {} continue elif line[0] == " ": # We don't care about long descriptions continue parts = line.split(": ", maxsplit=1) if len(parts) == 2: info[parts[0]] = parts[1].strip() if len(info) > 0: yield Package(info) def __main__(): args = parser.parse_args() packages = {} for pkg in package_info(args.version): # Skip debug symbol packages for now. if "dbgsym" not in pkg.name: packages[pkg.name] = pkg filtered_packages = {} # Filter dupes like hip-dev vs. hip-dev6.3.4 for name, info in packages.items(): if name.endswith(args.version): name_without_version = name[: -len(args.version)] if name_without_version not in packages: filtered_packages[name_without_version] = info else: filtered_packages[name] = info packages = filtered_packages # First pass # Find -dev and -rpath packages that should be merged. dev_to_merge = {} for name in packages.keys(): if name.endswith("-dev") and name[:-4] in packages: dev_to_merge[name] = name[:-4] elif name.endswith("-dev-rpath") and name[:-10] in packages: dev_to_merge[name] = name[:-10] elif name.endswith("-rpath") and name[:-6] in packages: dev_to_merge[name] = name[:-6] # Second pass: get ROCm dependencies and merge -dev packages. metadata = {} # sorted will put -dev after non-dev packages. for name in sorted(packages.keys()): info = packages[name] deps = { dev_to_merge.get(dep, dep) for dep in info.depends(args.version) if dep in packages } pkg_metadata = { "name": name, "sha256": info.sha256, "url": f"{BASEURL.format(version=args.version)}/{info.filename}", "version": info.version, } if name in dev_to_merge: target_pkg = dev_to_merge[name] metadata[target_pkg]["components"].append(pkg_metadata) metadata[target_pkg]["deps"].update(deps) else: metadata[name] = { "deps": deps, "components": [pkg_metadata], "version": info.version, } # Remove self-references and convert dependencies to list. for name, pkg_metadata in metadata.items(): deps = pkg_metadata["deps"] deps -= {name, f"{name}-dev"} deps -= {name, f"{name}-rpath"} pkg_metadata["deps"] = list(sorted(deps)) print(json.dumps(metadata, indent=2)) if __name__ == "__main__": __main__()