summaryrefslogtreecommitdiff
path: root/multiarchanalyze.py
diff options
context:
space:
mode:
authorHelmut Grohne <helmut@subdivi.de>2016-06-10 07:26:12 +0200
committerHelmut Grohne <helmut@subdivi.de>2016-06-10 07:26:12 +0200
commite123f857a74e2ec8742ceebddebd7d296dcaca3c (patch)
treee597edbdbfac8eb88cb1ccaf5d5c9d80ada4bb0a /multiarchanalyze.py
parent1853954f5a600a51cea30cdab689d7774045fcb1 (diff)
downloaddebian-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-xmultiarchanalyze.py114
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()