]>
Commit | Line | Data |
---|---|---|
d8ce2152 XL |
1 | #!/usr/bin/pypy3 |
2 | # pypy3 runs faster than python3 | |
3 | # | |
43ed93d8 SL |
4 | # the excuses file can be found here: |
5 | # https://release.debian.org/britney/excuses.yaml | |
1db6a00b | 6 | |
00c29ce1 XL |
7 | import re |
8 | import subprocess | |
1db6a00b XL |
9 | import sys |
10 | import yaml | |
11 | ||
60c13697 | 12 | if len(sys.argv) != 4: |
b4000f35 SL |
13 | print( |
14 | """Generates dot files to show the migration deps | |
60c13697 | 15 | Usage: %s excuses.dot excuses_arch.dot regressions.list |
7f8aa2ce SL |
16 | |
17 | Expects excuses.yaml in the current dir | |
b4000f35 SL |
18 | """ |
19 | % sys.argv[0] | |
20 | ) | |
7f8aa2ce SL |
21 | sys.exit(0) |
22 | ||
1db6a00b XL |
23 | print("parsing excuses.yaml...", file=sys.stderr) |
24 | with open("excuses.yaml") as fp: | |
78e0158a | 25 | y = yaml.load(fp, Loader=yaml.FullLoader) |
1db6a00b XL |
26 | |
27 | excuses = {} | |
28 | for e in y["sources"]: | |
b4000f35 | 29 | excuses[e["source"]] = e |
1db6a00b | 30 | |
00c29ce1 | 31 | print("generating dot files...", file=sys.stderr) |
1db6a00b XL |
32 | rust_excuses = open(sys.argv[1], "w") |
33 | rust_excuses_arch = open(sys.argv[2], "w") | |
60c13697 | 34 | rust_regressions = open(sys.argv[3], "w") |
1db6a00b XL |
35 | |
36 | already_seen = set() | |
37 | ||
00c29ce1 | 38 | def edge_dep(name, dep): |
b4000f35 SL |
39 | return " ".join(['"%s"' % name, "->", '"%s"' % dep]) |
40 | ||
00c29ce1 | 41 | def edge_dep_label(name, dep, label): |
b4000f35 SL |
42 | return " ".join(['"%s"' % name, "->", '"%s"' % dep, '[label="%s"]' % label]) |
43 | ||
1db6a00b | 44 | def print_all(*args, **kwargs): |
b4000f35 SL |
45 | print(*args, **kwargs, file=rust_excuses) |
46 | print(*args, **kwargs, file=rust_excuses_arch) | |
47 | ||
00c29ce1 XL |
48 | is_in_debian_cache = {} |
49 | def is_in_debian(src): | |
b4000f35 SL |
50 | global is_in_debian_cache |
51 | if src not in is_in_debian_cache: | |
52 | n = subprocess.check_output( | |
53 | "apt-cache showsrc %s 2>/dev/null | grep ^Package: | wc -l" % src, | |
54 | shell=True, | |
55 | ) | |
56 | is_in_debian_cache[src] = int(n.strip()) | |
57 | x = is_in_debian_cache[src] | |
58 | return x | |
59 | ||
00c29ce1 | 60 | |
d8ce2152 XL |
61 | BG_NOT_IN_DEBIAN = "#cc0000" |
62 | BG_OLD_IN_DEBIAN = "#ffcc66" | |
63 | BG_TOO_NEW = "#66ff99" | |
a2ba87f9 | 64 | BG_MISC_WAIT = "#ffcc99" |
d8ce2152 | 65 | BG_MISC_FAIL = "#ff6666" |
508cd1b3 | 66 | BG_SOURCEONLY = "#9999ff" |
a2ba87f9 | 67 | VERDICT_FAIL = ("REJECTED_CANNOT_DETERMINE_IF_PERMANENT", "REJECTED_NEEDS_APPROVAL", "REJECTED_PERMANENTLY") |
d8ce2152 | 68 | |
1db6a00b | 69 | def traverse(name, arch="", d=0): |
b4000f35 SL |
70 | if name in already_seen: |
71 | return | |
72 | already_seen.add(name) | |
73 | dependencies = excuses.get(name, {}).get("dependencies", {}) | |
74 | ||
75 | edges = set() | |
76 | for arch, deps in dependencies.get("unsatisfiable-dependencies", {}).items(): | |
77 | for dep in deps: | |
78 | vers = "" | |
79 | if dep.startswith("librust-"): | |
80 | try: | |
81 | results = re.match(r"librust-(\S+?)(-[.0-9]+)?(\+\S*)?-dev", dep) | |
82 | dep = "rust-" + results.group(1) | |
83 | if results.group(2): | |
84 | vers = results.group(2) | |
85 | except Exception: | |
86 | print(dep, file=sys.stderr) | |
87 | raise | |
88 | edges.add(edge_dep_label(name, dep, vers)) | |
89 | print( | |
90 | edge_dep_label(name, dep, "%s/%s" % (vers, arch) if vers else arch), | |
91 | file=rust_excuses_arch, | |
92 | ) | |
93 | if dep not in already_seen: | |
94 | if is_in_debian(dep): | |
d8ce2152 | 95 | print_all('"%s" [fillcolor="%s",style=filled]' % (dep, BG_OLD_IN_DEBIAN)) |
b4000f35 | 96 | else: |
d8ce2152 | 97 | print_all('"%s" [fillcolor="%s",style=filled]' % (dep, BG_NOT_IN_DEBIAN)) |
b4000f35 SL |
98 | for edge in edges: |
99 | print(edge, file=rust_excuses) | |
100 | ||
101 | for dep in dependencies.get("migrate-after", []) + dependencies.get( | |
102 | "blocked-by", [] | |
103 | ): | |
104 | if "/" in dep: | |
105 | dep, arch = dep.split("/") | |
106 | print(edge_dep_label(name, dep, arch), file=rust_excuses_arch) | |
107 | else: | |
108 | print_all(edge_dep(name, dep)) | |
109 | traverse(dep, arch, d + 1) | |
110 | ||
d8ce2152 | 111 | policy = excuses.get(name, {}).get("policy_info", {}) |
a2ba87f9 | 112 | failed = {k: v["verdict"] for (k, v) in policy.items() if v.get("verdict", "") != "PASS"} |
d8ce2152 XL |
113 | attrs = {"shape": "box"} |
114 | if "age" in failed: | |
a2ba87f9 | 115 | del failed["age"] |
d8ce2152 | 116 | attrs.update({ "fillcolor": BG_TOO_NEW, "style": "filled" }) |
60c13697 XL |
117 | if "autopkgtest" in failed: |
118 | for k, v in policy["autopkgtest"].items(): | |
119 | if k == "verdict": continue | |
120 | for uu in v.values(): | |
121 | if "REGRESSION" in uu: | |
122 | for u in uu: | |
123 | if u and u.startswith("https://ci.debian.net/data/autopkgtest/testing"): | |
124 | print(u, file=rust_regressions) | |
d8ce2152 | 125 | if failed: |
a2ba87f9 XL |
126 | if list(failed.keys()) == ["builtonbuildd"]: |
127 | bg = BG_SOURCEONLY | |
128 | attrs.update({ "label": "\\N\\nneeds source-only upload" }) | |
129 | elif any(v in VERDICT_FAIL for v in failed.values()): | |
130 | bg = BG_MISC_FAIL | |
131 | attrs.update({ "label": "\\N\\nfailed: %s" % ",".join(failed.keys()) }) | |
132 | else: | |
133 | bg = BG_MISC_WAIT | |
134 | attrs.update({ "label": "\\N\\nwaiting: %s" % ",".join(failed.keys()) }) | |
508cd1b3 | 135 | attrs.update({ "fillcolor": bg, "style": "filled" }) |
d8ce2152 | 136 | print_all('"%s" [%s]' % (name, ",".join("%s=\"%s\"" % p for p in attrs.items()))) |
b4000f35 SL |
137 | |
138 | ||
139 | # import code | |
140 | # code.interact(local=locals()) | |
141 | ||
d166a967 | 142 | |
1db6a00b XL |
143 | print_all("digraph {") |
144 | for s in excuses.keys(): | |
b4000f35 SL |
145 | if s.startswith("rust-"): |
146 | traverse(s) | |
1db6a00b | 147 | print_all("}") |