summaryrefslogtreecommitdiff
path: root/depver_test.py
diff options
context:
space:
mode:
Diffstat (limited to 'depver_test.py')
-rw-r--r--depver_test.py142
1 files changed, 142 insertions, 0 deletions
diff --git a/depver_test.py b/depver_test.py
new file mode 100644
index 0000000..3dcf596
--- /dev/null
+++ b/depver_test.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python3
+# Adélie Linux architecture package tester
+# Ensure all packages depend on latest versions of each other
+#
+# Copyright © 2019-2020 Adélie Linux team. All rights reserved.
+# NCSA license.
+#
+import argparse
+import collections
+import functools
+import os
+import sys
+
+from apkkit.base.index import Index
+
+from version import is_older, is_same, verkey, ver_is, APK_OPS
+from output import FORMATTERS, No, Partial
+
+def atomize(spec):
+ if not any(i in spec for i in APK_OPS):
+ return spec, None
+
+ for op in APK_OPS:
+ try:
+ name, ver = spec.split(op, maxsplit=1)
+ except ValueError:
+ continue
+
+ return name, functools.partial(ver_is, op=op, b=ver)
+
+ # Not reached
+ assert False
+
+def analyze(url, repos, arch):
+ pkgs = collections.defaultdict(dict)
+ newest = {}
+ providers = collections.defaultdict(list)
+
+ print("Loading " + arch + "...", file=sys.stderr)
+
+ index = []
+ for repo in repos:
+ index.extend(Index(url=url + f"/{repo}/{arch}/APKINDEX.tar.gz").packages)
+
+ for pkg in index:
+ new = pkg.version
+ pkgs[pkg.name][new] = pkg
+
+ curr = newest.get(pkg.name, None)
+ if curr is None:
+ newest[pkg.name] = new
+ elif is_older(curr, new):
+ newest[pkg.name] = new
+
+ providers[pkg.name].append((pkg.name, new))
+ for i in pkg.provides:
+ i = i.split("=", maxsplit=1)
+ if len(i) == 2:
+ i, pver = i
+ else:
+ i, pver = i[0], new
+
+ curr = newest.get(i, None)
+ if curr is None:
+ newest[i] = pver
+ elif is_older(curr, pver):
+ newest[i] = pver
+
+ providers[i].append((pkg.name, pver))
+
+ yield ["arch", "package", "version", "issue"]
+
+ for name in sorted(pkgs.keys()):
+ # DON'T use newest[] here. It is possible that a package
+ # provides= another package's name with a newer version
+ ver = sorted(pkgs[name].keys(), key=verkey)[-1]
+ pkg = pkgs[name][ver]
+
+ for dep in pkg.depends:
+ if dep.startswith("!"):
+ continue
+
+ spec = dep
+ dep, constraint = atomize(dep)
+
+ if dep in pkg.provides:
+ continue
+ if dep not in providers:
+ yield [arch, name, ver, No(f"Missing {spec}")]
+ continue
+
+ if constraint:
+ for provider, pver in providers[dep]:
+ if constraint(pver):
+ break
+ else:
+ yield [arch, name, ver, No(f"Missing {spec}")]
+
+ for _, pver in providers[dep]:
+ if is_same(pver, newest[dep]):
+ break
+ else:
+ yield [arch, name, ver, Partial(f"Old {spec}")]
+
+if __name__ == "__main__":
+ opts = argparse.ArgumentParser(
+ description="""Scan the REPO/ARCH repositories under URL and
+ look for outdated or missing dependencies as required by the
+ most recent version of each package. This script examines both
+ main packages and subpackages.
+
+ Be sure to include any repositories on which the repository of
+ interest depends, otherwise a lot of dependencies will be
+ incorrectly marked as missing.""",
+ )
+ opts.add_argument(
+ "-f", "--format", choices=FORMATTERS.keys(),
+ default="pretty" if os.isatty(sys.stdout.fileno()) else "tab",
+ help="display format",
+ )
+ opts.add_argument(
+ "url", metavar="URL",
+ help="base URL (no repository or arch)",
+ )
+ opts.add_argument(
+ "repos", metavar="REPOS",
+ help="repositories (comma separated)",
+ )
+ opts.add_argument(
+ "arches", metavar="ARCHES",
+ help="architectures (comma separated)",
+ )
+ opts = opts.parse_args()
+ opts.repos = opts.repos.split(",")
+ opts.arches = opts.arches.split(",")
+
+ for arch in opts.arches:
+ # FIXME: with html, wrapping will repeat for > 1 arch
+ FORMATTERS[opts.format](
+ opts,
+ analyze(opts.url, opts.repos, arch),
+ )