-
Notifications
You must be signed in to change notification settings - Fork 34
/
wgets
executable file
·68 lines (60 loc) · 2.47 KB
/
wgets
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
#!/usr/bin/env python
import urllib.parse as up, binascii as ba
import os, sys, types, subprocess, hashlib
def print_usage(extras=None, exit_with=1):
p = lambda *a: print(*a, file=sys.stderr)
cmd = os.path.basename(sys.argv[0])
example_args = 'http://os.archlinuxarm.org/os/'\
'ArchLinuxARM-sun4i-latest.tar.gz', 'cea5d785df19151806aa5ac3a917e41c'
p(f'Usage: {cmd} [ wget_opts ] url checksum')
p('Example: {} -c {} {}'.format(cmd, *example_args))
if extras is not None:
if isinstance(extras, types.StringTypes): extras = [extras]
for line in extras: p(line)
if exit_with is not None: sys.exit(exit_with)
class InputError(Exception):
def print_usage(self):
if not self.args: print_usage()
msg = self.args[0].format(*self.args[1:])
print_usage(f'ERROR: {msg}')
def process_cli(args=None):
if args is None: args = sys.argv[1:]
args = args or ['-h']
for arg in args:
if arg.startswith('-h') or arg == '--help': raise InputError
args, checksum = args[:-1], args[-1]
if not args: raise InputError('both url and checksum must be specified')
args, url = args[:-1], args[-1]
file_path = up.urlparse(url).path
file_path = up.unquote_plus(file_path.rsplit('/', 1)[-1])
if not file_path: raise InputError('failed to detect output filename from url')
args = ['wget'] + args + ['-O', file_path, url]
return file_path, checksum, args
def validate_digest( checksum,
_hash_funcs = [ ('md5', 16), ('sha1', 20),
('sha256', 32), ('sha512', 64), ('sha224', 28), ('sha384', 48) ] ):
digest = ba.a2b_hex(checksum)
for hash_name, hash_len in _hash_funcs:
if len(digest) == hash_len: break
else:
raise InputError( 'Error: failed to pick hash'
f' for value (len: {len(checksum)}): {checksum}' )
return digest, hash_name, getattr(hashlib, hash_name)
class DigestError(Exception): pass
def check_hash(file_path, hash_func, digest, bs=4*2**20):
chk = hash_func()
with open(file_path, 'rb') as src:
for chunk in iter(lambda: src.read(bs), b''): chk.update(chunk)
if digest != (chk := chk.digest()):
raise DigestError(f'{ba.b2a_hex(digest)} (expected) != {ba.b2a_hex(chk)} (real)')
def main(args=None):
try:
file_path, checksum, wget_args = process_cli(args)
digest, hash_name, hash_func = validate_digest(checksum)
except InputError as err: err.print_usage()
print(f'Using hash: {hash_name}')
print(f'Using output filename: {file_path}')
subprocess.run(wget_args, check=True)
check_hash(file_path, hash_func, digest)
print('Checksum matched')
if __name__ == '__main__': sys.exit(main())