xref: /aosp_15_r20/external/angle/build/3pp_common/fetch_github_release.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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