-
Notifications
You must be signed in to change notification settings - Fork 5
/
dedup_wheels.py
78 lines (58 loc) · 2.13 KB
/
dedup_wheels.py
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
"""
Split wheels by set of architectures and delete redundant ones.
"""
import argparse
import os
import pathlib
import re
import sys
from collections import defaultdict
from typing import Iterable
def list_wheels(wheel_dir: pathlib.Path):
return (wheel.name for wheel in wheel_dir.glob("*.whl"))
def dedup_wheels(wheel_names: Iterable[str]):
split_wheelname = re.compile(r"(?P<project>\w+-[0-9a-z.]+)-(?P<python>[^-]+-[^-]+)-(?P<archs>(?:[^.]+[.])+)whl").match
keep: set = set()
seen: dict[tuple[str,str],list[set[str]]] = defaultdict(list)
best: dict[tuple[str,str],list[str]] = defaultdict(list)
for wheel in sorted(wheel_names, key=len, reverse=True):
parts = split_wheelname(wheel)
if not parts:
keep.add(wheel)
continue
archs = set(parts['archs'].rstrip('.').split('.'))
key = (parts['project'], parts['python'])
for archs_seen in seen[key]:
if not (archs - archs_seen):
break
else:
seen[key].append(archs)
best[key].append(wheel)
keep.update(wheel for wheel_list in best.values() for wheel in wheel_list)
return sorted(keep)
def print_wheels(wheel_names: Iterable[str]):
for wheel in sorted(wheel_names):
print(f" {wheel}")
def main(wheel_dir: str, delete=True):
wheel_path = pathlib.Path(wheel_dir)
all_wheels = list(list_wheels(wheel_path))
wheels = dedup_wheels(all_wheels)
redundant = set(all_wheels).difference(wheels)
if delete:
for wheel in sorted(redundant):
print(f"deleting {wheel}")
os.unlink(wheel_path / wheel)
elif redundant:
print("Redundant wheels found:")
print_wheels(redundant)
def parse_args(args):
parser = argparse.ArgumentParser()
parser.add_argument("directory")
parser.add_argument("-d", "--delete", action="store_true")
return parser.parse_args(args)
if __name__ == "__main__":
if len(sys.argv) > 1:
args = parse_args(sys.argv[1:])
main(args.directory, delete=args.delete)
else:
print(f"Usage: {sys.argv[0]} WHEEL_DIR", file=sys.stderr)