-
Notifications
You must be signed in to change notification settings - Fork 36
/
pyusbtool.py
executable file
·142 lines (119 loc) · 3.98 KB
/
pyusbtool.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
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
#!/usr/bin/env python3
#
# Cross platform python script to download all the CSA tools to a specified
# directory
#
import argparse
import contextlib
import csv
import hashlib
import pathlib
import urllib.request
import sys
USER_AGENT = "python-frc-csa-tool/1.0"
CHUNK_SIZE = 2**20
def download(url: str, dst_fname: pathlib.Path):
"""
Downloads a file to a specified directory
"""
def _reporthook(count, blocksize, totalsize):
percent = int(count * blocksize * 100 / totalsize)
if percent < 0 or percent > 100:
sys.stdout.write("\r--%")
else:
sys.stdout.write("\r%02d%%" % percent)
sys.stdout.flush()
print("Downloading", url)
request = urllib.request.Request(url, headers={"User-Agent": USER_AGENT})
with contextlib.closing(urllib.request.urlopen(request)) as fp:
headers = fp.info()
with open(dst_fname, "wb") as tfp:
# copied from urlretrieve source code, Python license
bs = 1024 * 8
size = -1
blocknum = 0
read = 0
if "content-length" in headers:
size = int(headers["Content-Length"])
while True:
block = fp.read(bs)
if not block:
break
read += len(block)
tfp.write(block)
blocknum += 1
_reporthook(blocknum, bs, size)
sys.stdout.write("\n")
sys.stdout.flush()
def md5_file(fname: pathlib.Path) -> str:
with open(fname, "rb") as fp:
h = hashlib.md5()
chunk = fp.read(CHUNK_SIZE)
while chunk:
h.update(chunk)
chunk = fp.read(CHUNK_SIZE)
return h.hexdigest()
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("csv", type=pathlib.Path, help="Specifies the csv to read from")
parser.add_argument("dst", type=pathlib.Path, help="Specifies the destination directory")
parser.add_argument("--update", help="Update CSV file as specified year")
parser.add_argument(
"-d",
"--download",
action="store_true",
default=False,
help="Download files to disk (default is to check only)",
)
parser.add_argument(
"--no-verify",
action="store_true",
default=False,
help="Don't verify md5sum of existing files",
)
args = parser.parse_args()
present = 0
missing = 0
invalid = 0
with open(args.csv) as fp:
# #FriendlyName,FileName,URL,MD5,isZipped
for name, fname, url, md5, zipped in csv.reader(fp):
if name.startswith("#"):
continue
md5 = md5.lower()
valid_checksum = md5 != "0" * len(md5)
fname = args.dst / fname
is_invalid = False
if fname.exists():
if not valid_checksum:
print(name, "exists and has no checksum")
present += 1
continue
elif args.no_verify:
print(name, "exists")
present += 1
continue
elif md5_file(fname) == md5:
print(name, "exists and has valid checksum")
present += 1
continue
is_invalid = True
if args.download:
download(url, fname)
if valid_checksum and md5_file(fname) != md5:
print(name, "does not match checksum")
invalid += 1
else:
present += 1
else:
if is_invalid:
print(name, "does not match checksum")
invalid += 1
else:
print(name, "is missing")
missing += 1
print()
print("Finished!")
print("-", present, "OK")
print("-", missing, "missing")
print("-", invalid, "invalid")