#!/usr/bin/env python3 # Adélie Linux architecture package tester # Ensure all packages are all on arches # # Copyright © 2018-2020 Adélie Linux team. All rights reserved. # NCSA license. # import argparse import os import sys from pathlib import Path from apkkit.base.index import Index from output import FORMATTERS, Yes, No, YES_MISSING, PARTIAL_MISSING from version import is_older def analyze(opts): newest = dict() arch_newest = {arch: dict() for arch in opts.arches} for arch in opts.arches: print(f"Loading {arch}...", file=sys.stderr) url = f"{opts.url}/{opts.repo}/{arch}/APKINDEX.tar.gz" for pkg in Index(url=url).packages: if pkg.name != pkg.origin: continue new = pkg.version for mydict in (newest, arch_newest[arch]): curr = mydict.get(pkg.name, None) if curr is None: mydict[pkg.name] = new elif is_older(curr, new): mydict[pkg.name] = new return newest, arch_newest def order_arch(opts, ign): newest, arch_newest = analyze(opts) yield ["arch", "package", "version for arch", "newest version"] for arch in opts.arches: old = list() for pkg in newest.keys(): ver = newest[pkg] archver = arch_newest[arch].get(pkg, None) if archver is None and pkg not in ign: yield [arch, pkg, PARTIAL_MISSING, ver] elif archver is not None and is_older(archver, ver): if opts.only_missing: continue yield [arch, pkg, archver, ver] def order_pkg(opts, ign): newest, arch_newest = analyze(opts) yield ["package", *opts.arches] for pkg in sorted(newest.keys()): for i in opts.arches: archver = arch_newest[i].get(pkg, None) if archver is None: break if opts.only_missing: continue if archver is not None and is_older(archver, newest[pkg]): break else: continue row = [pkg] for i in opts.arches: archver = arch_newest[i].get(pkg, None) if archver is None and pkg in ign: row.append(YES_MISSING) elif archver is None: row.append(PARTIAL_MISSING) elif is_older(archver, newest[pkg]): row.append(No(archver)) else: row.append(Yes(archver)) yield row ORDERS = { "pkg": order_pkg, "arch": order_arch, } if __name__ == "__main__": opts = argparse.ArgumentParser( description="""Scan the REPO/ARCH repositories under URL and look for outdated or missing packages when comparing across architectures. This script only examines main packages, not subpackages. At least two architectures must be given in order to make a comparison.""" ) opts.add_argument( "-f", "--format", choices=FORMATTERS.keys(), default="pretty" if os.isatty(sys.stdout.fileno()) else "tab", help="display format", ) opts.add_argument( "-m", "--only-missing", action="store_true", help="show only missing packages", ) opts.add_argument( "-o", "--order", choices=ORDERS.keys(), default="pkg", help="display order", ) opts.add_argument( "url", metavar="URL", help="base URL (no repository or arch)", ) opts.add_argument( "repo", metavar="REPO", help="repository", ) opts.add_argument( "arches", metavar="ARCHES", help="architectures (comma separated, at least 2)", ) opts = opts.parse_args() opts.arches = opts.arches.split(",") if len(opts.arches) < 2: print("At least two arches are required", file=sys.stderr) sys.exit(1) if Path(opts.repo + "-specific").is_file(): with open(opts.repo + '-specific', 'r') as ignore_file: ign = set(pkg[:-1] for pkg in ignore_file.readlines()) else: ign = set() # FIXME: support multiple repos FORMATTERS[opts.format]( opts, ORDERS[opts.order](opts, ign), )