summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Rees <maxcrees@me.com>2020-04-13 22:49:36 -0500
committerMax Rees <maxcrees@me.com>2020-04-13 22:49:36 -0500
commit51097aa5ba7eee5ee71f2ec88ddfefc955f38237 (patch)
tree9dfe8f0f8a38c4e7955d3a5f182324778ac9a6fa
parent51e825910f64e24c7427f7ea4d9414da93673a6d (diff)
downloadarch-tester-51097aa5ba7eee5ee71f2ec88ddfefc955f38237.tar.gz
arch-tester-51097aa5ba7eee5ee71f2ec88ddfefc955f38237.tar.bz2
arch-tester-51097aa5ba7eee5ee71f2ec88ddfefc955f38237.tar.xz
arch-tester-51097aa5ba7eee5ee71f2ec88ddfefc955f38237.zip
depver_test: support multiple arches correctly
-rw-r--r--depver_test.py194
-rw-r--r--output.py8
2 files changed, 132 insertions, 70 deletions
diff --git a/depver_test.py b/depver_test.py
index 5e25c39..014e296 100644
--- a/depver_test.py
+++ b/depver_test.py
@@ -14,7 +14,7 @@ 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
+from output import FORMATTERS, Yes, No, Partial, PARTIAL_MISSING
def atomize(spec):
if not any(i in spec for i in APK_OPS):
@@ -31,79 +31,134 @@ def atomize(spec):
# Not reached
assert False
-def analyze(opts, arch):
- pkgs = collections.defaultdict(dict)
- newest = {}
- providers = collections.defaultdict(list)
-
- print("Loading " + arch + "...", file=sys.stderr)
-
- index = []
- for repo in opts.repos:
- url = f"{opts.url}/{repo}/{arch}/APKINDEX.tar.gz"
- index.extend(Index(url=url).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
+def analyze(opts):
+ pkgs = {i: collections.defaultdict(dict) for i in opts.arches}
+ newest = {i: dict() for i in opts.arches}
+ providers = {i: collections.defaultdict(list) for i in opts.arches}
+
+ for arch in opts.arches:
+ print("Loading " + arch + "...", file=sys.stderr)
+
+ index = []
+ for repo in opts.repos:
+ url = f"{opts.url}/{repo}/{arch}/APKINDEX.tar.gz"
+ index.extend(Index(url=url).packages)
- curr = newest.get(i, None)
+ for pkg in index:
+ new = pkg.version
+ pkgs[arch][pkg.name][new] = pkg
+
+ curr = newest[arch].get(pkg.name, None)
if curr is None:
- newest[i] = pver
- elif is_older(curr, pver):
- newest[i] = pver
+ newest[arch][pkg.name] = new
+ elif is_older(curr, new):
+ newest[arch][pkg.name] = new
+
+ providers[arch][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[arch].get(i, None)
+ if curr is None:
+ newest[arch][i] = pver
+ elif is_older(curr, pver):
+ newest[arch][i] = pver
+
+ providers[arch][i].append((pkg.name, pver))
+
+ return pkgs, newest, providers
+
+def trace_deps(providers, newest, pkg):
+ 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 No(f"missing {spec}")
+ continue
+
+ if constraint:
+ for provider, pver in providers[dep]:
+ if constraint(pver):
+ break
+ else:
+ yield No(f"missing {spec}")
- providers[i].append((pkg.name, pver))
+ for _, pver in providers[dep]:
+ if is_same(pver, newest[dep]):
+ break
+ else:
+ yield No(f"old {spec}")
+
+def order_arch(opts):
+ pkgs, newest, providers = analyze(opts)
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("!"):
+ for arch in opts.arches:
+ for name in sorted(pkgs[arch].keys()):
+ # DON'T use newest[] here. It is possible that a package
+ # provides= another package's name with a newer version
+ ver = sorted(pkgs[arch][name].keys(), key=verkey)[-1]
+ pkg = pkgs[arch][name][ver]
+
+ for problem in trace_deps(providers[arch], newest[arch], pkg):
+ yield [arch, name, ver, problem]
+
+def order_pkg(opts):
+ pkgs, newest, providers = analyze(opts)
+
+ all_pkgs = set()
+ for arch in pkgs:
+ all_pkgs.update(pkgs[arch].keys())
+
+ yield ["package", "problem", *opts.arches]
+ for name in sorted(all_pkgs):
+ all_problems = set()
+ problems = {}
+
+ for arch in opts.arches:
+ vers = pkgs[arch].get(name, {})
+ if not vers:
+ problems[arch] = [PARTIAL_MISSING]
+ # Don't add PARTIAL_MISSING to all_problems: we don't
+ # care if "name" is missing, use pkgver_test.py for that
continue
+ ver = sorted(vers.keys(), key=verkey)[-1]
+ pkg = vers[ver]
- spec = dep
- dep, constraint = atomize(dep)
+ problems[arch] = list(
+ trace_deps(providers[arch], newest[arch], pkg)
+ )
+ all_problems.update(problems[arch])
- if dep in pkg.provides:
- continue
- if dep not in providers:
- yield [arch, name, ver, No(f"Missing {spec}")]
- continue
+ if not all_problems:
+ continue
- if constraint:
- for provider, pver in providers[dep]:
- if constraint(pver):
- break
+ for problem in sorted(all_problems):
+ row = [name, problem.content]
+ for arch in opts.arches:
+ if problem in problems[arch]:
+ row.append(type(problem)("yes"))
+ elif PARTIAL_MISSING in problems[arch]:
+ row.append(Yes("n/a"))
else:
- yield [arch, name, ver, No(f"Missing {spec}")]
+ row.append(Yes("no"))
- if opts.only_missing:
- continue
+ yield row
- for _, pver in providers[dep]:
- if is_same(pver, newest[dep]):
- break
- else:
- yield [arch, name, ver, Partial(f"Old {spec}")]
+ORDERS = {
+ "arch": order_arch,
+ "pkg": order_pkg,
+}
if __name__ == "__main__":
opts = argparse.ArgumentParser(
@@ -122,8 +177,9 @@ if __name__ == "__main__":
help="display format",
)
opts.add_argument(
- "-m", "--only-missing", action="store_true",
- help="show only missing dependencies",
+ "-o", "--order", choices=ORDERS.keys(),
+ default="pkg",
+ help="display order",
)
opts.add_argument(
"url", metavar="URL",
@@ -141,9 +197,7 @@ if __name__ == "__main__":
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, arch),
- )
+ FORMATTERS[opts.format](
+ opts,
+ ORDERS[opts.order](opts),
+ )
diff --git a/output.py b/output.py
index 870d618..c8bb542 100644
--- a/output.py
+++ b/output.py
@@ -3,11 +3,19 @@
# Copyright © 2019-2020 Adélie Linux team. All rights reserved.
# NCSA license.
#
+import functools
import subprocess
+@functools.total_ordering
class _Cell:
def __init__(self, content):
self.content = content
+ def __eq__(self, other):
+ return self.content == other.content
+ def __lt__(self, other):
+ return self.content < other.content
+ def __hash__(self):
+ return hash(self.content)
_ANSI_CLEAR = "\033[0;00m"