1#!/usr/bin/env python3 2 3import argparse 4import os 5import pathlib 6import sys 7import time 8import zipfile 9from urllib.request import urlretrieve 10 11 12def fetch_zip(commit_hash, zip_dir, *, org='python', binary=False, verbose): 13 repo = f'cpython-{"bin" if binary else "source"}-deps' 14 url = f'https://github.com/{org}/{repo}/archive/{commit_hash}.zip' 15 reporthook = None 16 if verbose: 17 reporthook = print 18 zip_dir.mkdir(parents=True, exist_ok=True) 19 filename, headers = urlretrieve( 20 url, 21 zip_dir / f'{commit_hash}.zip', 22 reporthook=reporthook, 23 ) 24 return filename 25 26 27def extract_zip(externals_dir, zip_path): 28 with zipfile.ZipFile(os.fspath(zip_path)) as zf: 29 zf.extractall(os.fspath(externals_dir)) 30 return externals_dir / zf.namelist()[0].split('/')[0] 31 32 33def parse_args(): 34 p = argparse.ArgumentParser() 35 p.add_argument('-v', '--verbose', action='store_true') 36 p.add_argument('-b', '--binary', action='store_true', 37 help='Is the dependency in the binary repo?') 38 p.add_argument('-O', '--organization', 39 help='Organization owning the deps repos', default='python') 40 p.add_argument('-e', '--externals-dir', type=pathlib.Path, 41 help='Directory in which to store dependencies', 42 default=pathlib.Path(__file__).parent.parent / 'externals') 43 p.add_argument('tag', 44 help='tag of the dependency') 45 return p.parse_args() 46 47 48def main(): 49 args = parse_args() 50 zip_path = fetch_zip( 51 args.tag, 52 args.externals_dir / 'zips', 53 org=args.organization, 54 binary=args.binary, 55 verbose=args.verbose, 56 ) 57 final_name = args.externals_dir / args.tag 58 extracted = extract_zip(args.externals_dir, zip_path) 59 for wait in [1, 2, 3, 5, 8, 0]: 60 try: 61 extracted.replace(final_name) 62 break 63 except PermissionError as ex: 64 retry = f" Retrying in {wait}s..." if wait else "" 65 print(f"Encountered permission error '{ex}'.{retry}", file=sys.stderr) 66 time.sleep(wait) 67 else: 68 print( 69 f"ERROR: Failed to extract {final_name}.", 70 "You may need to restart your build", 71 file=sys.stderr, 72 ) 73 sys.exit(1) 74 75 76if __name__ == '__main__': 77 main() 78