17db96d56Sopenharmony_ci#!/usr/bin/env python3
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ciimport argparse
47db96d56Sopenharmony_ciimport os
57db96d56Sopenharmony_ciimport pathlib
67db96d56Sopenharmony_ciimport sys
77db96d56Sopenharmony_ciimport time
87db96d56Sopenharmony_ciimport zipfile
97db96d56Sopenharmony_cifrom urllib.request import urlretrieve
107db96d56Sopenharmony_ci
117db96d56Sopenharmony_ci
127db96d56Sopenharmony_cidef fetch_zip(commit_hash, zip_dir, *, org='python', binary=False, verbose):
137db96d56Sopenharmony_ci    repo = f'cpython-{"bin" if binary else "source"}-deps'
147db96d56Sopenharmony_ci    url = f'https://github.com/{org}/{repo}/archive/{commit_hash}.zip'
157db96d56Sopenharmony_ci    reporthook = None
167db96d56Sopenharmony_ci    if verbose:
177db96d56Sopenharmony_ci        reporthook = print
187db96d56Sopenharmony_ci    zip_dir.mkdir(parents=True, exist_ok=True)
197db96d56Sopenharmony_ci    filename, headers = urlretrieve(
207db96d56Sopenharmony_ci        url,
217db96d56Sopenharmony_ci        zip_dir / f'{commit_hash}.zip',
227db96d56Sopenharmony_ci        reporthook=reporthook,
237db96d56Sopenharmony_ci    )
247db96d56Sopenharmony_ci    return filename
257db96d56Sopenharmony_ci
267db96d56Sopenharmony_ci
277db96d56Sopenharmony_cidef extract_zip(externals_dir, zip_path):
287db96d56Sopenharmony_ci    with zipfile.ZipFile(os.fspath(zip_path)) as zf:
297db96d56Sopenharmony_ci        zf.extractall(os.fspath(externals_dir))
307db96d56Sopenharmony_ci        return externals_dir / zf.namelist()[0].split('/')[0]
317db96d56Sopenharmony_ci
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_cidef parse_args():
347db96d56Sopenharmony_ci    p = argparse.ArgumentParser()
357db96d56Sopenharmony_ci    p.add_argument('-v', '--verbose', action='store_true')
367db96d56Sopenharmony_ci    p.add_argument('-b', '--binary', action='store_true',
377db96d56Sopenharmony_ci                   help='Is the dependency in the binary repo?')
387db96d56Sopenharmony_ci    p.add_argument('-O', '--organization',
397db96d56Sopenharmony_ci                   help='Organization owning the deps repos', default='python')
407db96d56Sopenharmony_ci    p.add_argument('-e', '--externals-dir', type=pathlib.Path,
417db96d56Sopenharmony_ci                   help='Directory in which to store dependencies',
427db96d56Sopenharmony_ci                   default=pathlib.Path(__file__).parent.parent / 'externals')
437db96d56Sopenharmony_ci    p.add_argument('tag',
447db96d56Sopenharmony_ci                   help='tag of the dependency')
457db96d56Sopenharmony_ci    return p.parse_args()
467db96d56Sopenharmony_ci
477db96d56Sopenharmony_ci
487db96d56Sopenharmony_cidef main():
497db96d56Sopenharmony_ci    args = parse_args()
507db96d56Sopenharmony_ci    zip_path = fetch_zip(
517db96d56Sopenharmony_ci        args.tag,
527db96d56Sopenharmony_ci        args.externals_dir / 'zips',
537db96d56Sopenharmony_ci        org=args.organization,
547db96d56Sopenharmony_ci        binary=args.binary,
557db96d56Sopenharmony_ci        verbose=args.verbose,
567db96d56Sopenharmony_ci    )
577db96d56Sopenharmony_ci    final_name = args.externals_dir / args.tag
587db96d56Sopenharmony_ci    extracted = extract_zip(args.externals_dir, zip_path)
597db96d56Sopenharmony_ci    for wait in [1, 2, 3, 5, 8, 0]:
607db96d56Sopenharmony_ci        try:
617db96d56Sopenharmony_ci            extracted.replace(final_name)
627db96d56Sopenharmony_ci            break
637db96d56Sopenharmony_ci        except PermissionError as ex:
647db96d56Sopenharmony_ci            retry = f" Retrying in {wait}s..." if wait else ""
657db96d56Sopenharmony_ci            print(f"Encountered permission error '{ex}'.{retry}", file=sys.stderr)
667db96d56Sopenharmony_ci            time.sleep(wait)
677db96d56Sopenharmony_ci    else:
687db96d56Sopenharmony_ci        print(
697db96d56Sopenharmony_ci            f"ERROR: Failed to extract {final_name}.",
707db96d56Sopenharmony_ci            "You may need to restart your build",
717db96d56Sopenharmony_ci            file=sys.stderr,
727db96d56Sopenharmony_ci        )
737db96d56Sopenharmony_ci        sys.exit(1)
747db96d56Sopenharmony_ci
757db96d56Sopenharmony_ci
767db96d56Sopenharmony_ciif __name__ == '__main__':
777db96d56Sopenharmony_ci    main()
78