diff options
author | Helmut Grohne <helmut@subdivi.de> | 2016-06-10 07:26:12 +0200 |
---|---|---|
committer | Helmut Grohne <helmut@subdivi.de> | 2016-06-10 07:26:12 +0200 |
commit | e123f857a74e2ec8742ceebddebd7d296dcaca3c (patch) | |
tree | e597edbdbfac8eb88cb1ccaf5d5c9d80ada4bb0a /multiarchanalyze.py | |
parent | 1853954f5a600a51cea30cdab689d7774045fcb1 (diff) | |
download | debian-dedup-e123f857a74e2ec8742ceebddebd7d296dcaca3c.tar.gz |
add a separate tool for generating hints on Multi-Arch headers
It builds on the core functionality of dedup, but uses a different
database schema. Unlike dedup, it aborts downloading Arch:all packages
early and consumes any other architecture in its entirety instead.
Diffstat (limited to 'multiarchanalyze.py')
-rwxr-xr-x | multiarchanalyze.py | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/multiarchanalyze.py b/multiarchanalyze.py new file mode 100755 index 0000000..5cd5de7 --- /dev/null +++ b/multiarchanalyze.py @@ -0,0 +1,114 @@ +#!/usr/bin/python + +import argparse +import sqlite3 + +from dedup.utils import fetchiter + +def bipartitions(edges): + """ + @type edges: {T: set(T)} + @rtype: [(set(T), set(T))] + """ + todo = set(edges.keys()) + result = [] + colors = {} + while todo: + node = todo.pop() + colors[node] = False + partition = (set((node,)), set()) + todo2 = set((node,)) + while todo2: + partnode = todo2.pop() + for nextnode in edges[partnode]: + try: + if colors[nextnode] == colors[partnode]: + raise ValueError("not bipartite") + except KeyError: + colors[nextnode] = not colors[partnode] + partition[colors[nextnode]].add(nextnode) + todo2.add(nextnode) + todo.remove(nextnode) + result.append(partition) + return result + +def show_archset(archs, limit=3): + """ + @type archs: set(str) + @rtype: str + """ + archs = set(archs) + if len(archs) > limit: + return "%d archs" % len(archs) + return ", ".join(sorted(archs)) + +def show_combinations(combinations): + edges = {} + for left, right in combinations: + edges.setdefault(left, set()).add(right) + edges.setdefault(right, set()).add(left) # safety + if len(edges) == 2: + return "%s <-> %s" % (min(left, right), max(left, right)) + try: + partitions = bipartitions(edges) + except ValueError: + pass + else: + if len(partitions) == 1: + return " <-> ".join(show_archset(archs, 4) + for archs in sorted(partitions[0], key=len)) + else: + return "%d bipartitions of %s" % (len(partitions), + show_archset(edges.keys())) + if all(len(outedges) == len(edges) - 1 for outedges in edges.values()): + return "any two of " + show_archset(edges.keys(), limit=4) + return "%s with %d combinations" % (show_archset(edges.keys()), + len(combinations)) + +def show_files(filenames): + if len(filenames) == 1: + return next(iter(filenames)) + return "%d files" % len(filenames) + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("-d", "--database", action="store", + default="test.sqlite3", + help="path to the sqlite3 database file") + args = parser.parse_args() + db = sqlite3.connect(args.database) + cur = db.cursor() + cur.execute("SELECT name1, architecture1, architecture2, filename FROM masame_conflict;") + same_conflicts = {} + for package, arch1, arch2, filename in fetchiter(cur): + conflicts = same_conflicts.setdefault(package, {}) + conflicts.setdefault(filename, set()).add((arch1, arch2)) + for package, conflicts in sorted(same_conflicts.items()): + all_combinations = set() + for combinations in conflicts.values(): + all_combinations.update(combinations) + print("%s conflicts on %s on %s" % + (package, show_files(conflicts.keys()), + show_combinations(all_combinations))) + + cur.execute("SELECT name FROM maforeign_candidate ORDER BY name;") + for name, in fetchiter(cur): + print("%s could be Multi-Arch: foreign" % name) + + cur.execute("SELECT name FROM archall_candidate ORDER BY name;") + archall_suggests = set() + for name, in fetchiter(cur): + archall_suggests.add(name) + print("%s could be converted to Architecture: all + Multi-Arch: foreign" % name) + + cur.execute("SELECT name FROM masame_candidate ORDER BY name;") + for name, in fetchiter(cur): + if name not in archall_suggests: + print("%s could be Multi-Arch: same" % name) + cur.execute("SELECT depender, dependee FROM colonany_candidate ORDER BY depender;") + for depender, dependee in fetchiter(cur): + print("%s could have its %s dependency annotated with :any" % + (depender, dependee)) + +if __name__ == "__main__": + main() |