1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
#!/usr/bin/python
import argparse
import os.path
import sqlite3
import sys
import yaml
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=5)
return "%s with %d combinations" % (show_archset(edges.keys()),
len(combinations))
def show_files(filenames):
if len(filenames) == 1:
return next(iter(filenames))
prefix = os.path.commonprefix(filenames)
if prefix not in ('', '/'):
return "%d files starting with %s" % (len(filenames), prefix)
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()
hints = []
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):
if filename.startswith("./"):
filename = filename[1:]
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)
desc = "%s conflicts on %s on %s" % \
(package, show_files(conflicts.keys()),
show_combinations(all_combinations))
hints.append(dict(
binary=package,
description=desc,
link="https://wiki.debian.org/MultiArch/Hints#file-conflict",
severity="high"))
cur.execute("SELECT name FROM maforeign_candidate ORDER BY name;")
for name, in fetchiter(cur):
hints.append(dict(
binary=name,
description="%s could be marked Multi-Arch: foreign" % name,
link="https://wiki.debian.org/MultiArch/Hints#ma-foreign",
severity="rdeps"))
cur.execute("SELECT name FROM archall_candidate ORDER BY name;")
archall_suggests = set()
for name, in fetchiter(cur):
archall_suggests.add(name)
desc = "%s could be converted to Architecture: all and marked Multi-Arch: foreign" % \
name
hints.append(dict(
binary=name,
description=desc,
link="https://wiki.debian.org/MultiArch/Hints#arch-all",
severity="low"))
cur.execute("SELECT name FROM masame_candidate ORDER BY name;")
for name, in fetchiter(cur):
if name in archall_suggests:
continue
hints.append(dict(
binary=name,
description="%s could be marked Multi-Arch: same" % name,
link="https://wiki.debian.org/MultiArch/Hints#ma-same",
severity="normal"))
cur.execute("SELECT depender, dependee FROM colonany_candidate ORDER BY depender;")
for depender, dependee in fetchiter(cur):
desc = "%s could have its dependency on %s annotated with :any" % \
(depender, dependee)
hints.append(dict(
binary=depender,
description=desc,
link="https://wiki.debian.org/MultiArch/Hints#dep-any",
severity="normal"))
for hint in hints:
if "source" not in hint:
cur.execute("SELECT distinct(source) FROM package WHERE name = ?;",
(hint["binary"],))
row = cur.fetchone()
if row and row[0] and not cur.fetchone():
hint["source"] = row[0]
if hint.get("severity") == "rdeps":
cur.execute("SELECT count(*) FROM depends WHERE dependee = ?;",
(hint["binary"],))
rdeps = cur.fetchone()[0]
if rdeps >= 50:
hint["severity"] = "high"
elif rdeps:
hint["severity"] = "normal"
else:
hint["severity"] = "low"
yaml.safe_dump(dict(format="multiarch-hints-1.0", hints=hints),
default_flow_style=False,
width=1000,
stream=sys.stdout)
if __name__ == "__main__":
main()
|