1import argparse
2import concurrent.futures
3import json
4import os
5import subprocess
6import sys
7
8updates = {}
9
10def eprint(*args, **kwargs):
11 print(*args, file=sys.stderr, **kwargs)
12
13def run_update_script(package):
14 eprint(f" - {package['name']}: UPDATING ...")
15
16 subprocess.run(package['updateScript'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=True)
17
18
19def main(max_workers, keep_going, packages):
20 with open(sys.argv[1]) as f:
21 packages = json.load(f)
22
23 eprint()
24 eprint('Going to be running update for following packages:')
25 for package in packages:
26 eprint(f" - {package['name']}")
27 eprint()
28
29 confirm = input('Press Enter key to continue...')
30 if confirm == '':
31 eprint()
32 eprint('Running update for:')
33
34 with concurrent.futures.ProcessPoolExecutor(max_workers=max_workers) as executor:
35 for package in packages:
36 updates[executor.submit(run_update_script, package)] = package
37
38 for future in concurrent.futures.as_completed(updates):
39 package = updates[future]
40
41 try:
42 future.result()
43 eprint(f" - {package['name']}: DONE.")
44 except subprocess.CalledProcessError as e:
45 eprint(f" - {package['name']}: ERROR")
46 eprint()
47 eprint(f"--- SHOWING ERROR LOG FOR {package['name']} ----------------------")
48 eprint()
49 eprint(e.stdout.decode('utf-8'))
50 with open(f"{package['pname']}.log", 'wb') as f:
51 f.write(e.stdout)
52 eprint()
53 eprint(f"--- SHOWING ERROR LOG FOR {package['name']} ----------------------")
54
55 if not keep_going:
56 sys.exit(1)
57
58 eprint()
59 eprint('Packages updated!')
60 sys.exit()
61 else:
62 eprint('Aborting!')
63 sys.exit(130)
64
65parser = argparse.ArgumentParser(description='Update packages')
66parser.add_argument('--max-workers', '-j', dest='max_workers', type=int, help='Number of updates to run concurrently', nargs='?', default=4)
67parser.add_argument('--keep-going', '-k', dest='keep_going', action='store_true', help='Do not stop after first failure')
68parser.add_argument('packages', help='JSON file containing the list of package names and their update scripts')
69
70if __name__ == '__main__':
71 args = parser.parse_args()
72
73 try:
74 main(args.max_workers, args.keep_going, args.packages)
75 except (KeyboardInterrupt, SystemExit) as e:
76 for update in updates:
77 update.cancel()
78
79 sys.exit(e.code if isinstance(e, SystemExit) else 130)