1# Copyright 2023 The Chromium Authors 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import argparse 6import hashlib 7import json 8import os 9import pathlib 10import re 11import sys 12from typing import Dict, List 13import urllib.request 14 15import scripthash 16 17 18def _fetch_json(url): 19 return json.load(urllib.request.urlopen(url)) 20 21 22def _find_valid_urls(release, artifact_regex): 23 urls = [x['browser_download_url'] for x in release['assets']] 24 if artifact_regex: 25 urls = [x for x in urls if re.search(artifact_regex, x)] 26 return urls 27 28 29def _latest(api_url, install_scripts=None, artifact_regex=None): 30 # Make the version change every time this file changes. 31 file_hash = scripthash.compute(extra_paths=install_scripts) 32 33 releases: List[Dict] = _fetch_json(f'{api_url}/releases') 34 for release in releases: 35 tag_name = release['tag_name'] 36 urls = _find_valid_urls(release, artifact_regex) 37 if len(urls) == 1: 38 print('{}.{}'.format(tag_name, file_hash)) 39 return 40 print(f'Bad urls={urls} for tag_name={tag_name}, skipping.', 41 file=sys.stderr) 42 43 44def _get_url(api_url, 45 artifact_filename=None, 46 artifact_extension=None, 47 artifact_regex=None): 48 # Split off our md5 hash. 49 version = os.environ['_3PP_VERSION'].rsplit('.', 1)[0] 50 json_dict = _fetch_json(f'{api_url}/releases/tags/{version}') 51 urls = _find_valid_urls(json_dict, artifact_regex) 52 53 if len(urls) != 1: 54 raise Exception('len(urls) != 1, urls: \n' + '\n'.join(urls)) 55 56 partial_manifest = { 57 'url': urls, 58 'ext': artifact_extension or '', 59 } 60 if artifact_filename: 61 partial_manifest['name'] = [artifact_filename] 62 63 print(json.dumps(partial_manifest)) 64 65 66def main(*, 67 project, 68 artifact_filename=None, 69 artifact_extension=None, 70 artifact_regex=None, 71 install_scripts=None): 72 """The fetch.py script for a 3pp module. 73 74 Args: 75 project: GitHub username for the repo. e.g. "google/protobuf". 76 artifact_filename: The name for the downloaded file. Required when not 77 setting "unpack_archive: true" in 3pp.pb. 78 artifact_extension: File extension of file being downloaded. Required when 79 setting "unpack_archive: true" in 3pp.pb. 80 artifact_regex: A regex to use to identify the desired artifact from the 81 list of artifacts on the release. 82 install_scripts: List of script to add to the md5 of the version. The main 83 module and this module are always included. 84 """ 85 parser = argparse.ArgumentParser() 86 parser.add_argument('action', choices=('latest', 'get_url')) 87 args = parser.parse_args() 88 89 api_url = f'https://api.github.com/repos/{project}' 90 if args.action == 'latest': 91 _latest(api_url, 92 install_scripts=install_scripts, 93 artifact_regex=artifact_regex) 94 else: 95 _get_url(api_url, 96 artifact_filename=artifact_filename, 97 artifact_extension=artifact_extension, 98 artifact_regex=artifact_regex) 99