blob: 127629463b426055a9768adbd6f1616f8e15ff7f [file] [log] [blame]
lowRISC Contributors802543a2019-08-31 12:12:56 +01001#!/usr/bin/env python3
2# Copyright lowRISC contributors.
3# Licensed under the Apache License, Version 2.0, see LICENSE for details.
4# SPDX-License-Identifier: Apache-2.0
5
6import argparse
7import json
8import os
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -07009from pathlib import Path
10import re
lowRISC Contributors802543a2019-08-31 12:12:56 +010011import subprocess
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -070012import shutil
lowRISC Contributors802543a2019-08-31 12:12:56 +010013import sys
14import tempfile
Miguel Osorio8e282802019-09-24 10:37:27 -070015import time
lowRISC Contributors802543a2019-08-31 12:12:56 +010016from urllib.request import urlopen, urlretrieve
17
lowRISC Contributors802543a2019-08-31 12:12:56 +010018ASSET_PREFIX = "lowrisc-toolchain-gcc-rv32imc-"
Miguel Osorioc7050002019-09-20 00:16:04 -070019ASSET_SUFFIX = ".tar.xz"
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -070020BUILDINFO_FILENAME = "buildinfo"
21RELEASES_URL_BASE = 'https://api.github.com/repos/lowRISC/lowrisc-toolchains/releases'
lowRISC Contributors802543a2019-08-31 12:12:56 +010022TARGET_DIR = '/tools/riscv'
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -070023TOOLCHAIN_VERSION = 'latest'
Miguel Osorio1fe4e952019-10-10 09:35:44 -070024VERSION_RE=r"(lowRISC toolchain version|Version):\s*\n(?P<version>\d+(-\d+)?)"
lowRISC Contributors802543a2019-08-31 12:12:56 +010025
26
Miguel Osorio8e282802019-09-24 10:37:27 -070027def prompt_yes_no(msg):
28 while True:
29 print(msg, end=" ")
30 response = input().lower()
31 if response in ('yes', 'y'):
32 return True
33 elif response in ('no', 'n'):
34 return False
35 else:
36 print('Invalid response. Valid options are "yes" or "no"')
37
38
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -070039def get_release_info(toolchain_version):
lowRISC Contributors802543a2019-08-31 12:12:56 +010040 if toolchain_version == 'latest':
41 releases_url = '%s/%s' % (RELEASES_URL_BASE, toolchain_version)
42 else:
43 releases_url = '%s/tags/%s' % (RELEASES_URL_BASE, toolchain_version)
44 with urlopen(releases_url) as f:
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -070045 return json.loads(f.read().decode('utf-8'))
46
47
48def get_download_url(release_info):
49 return [
50 a["browser_download_url"] for a in release_info["assets"]
51 if (a["name"].startswith(ASSET_PREFIX) and
52 a["name"].endswith(ASSET_SUFFIX))
53 ][0]
54
55
56def get_release_tag(release_info):
57 return release_info["tag_name"]
58
59
60def get_release_tag_from_file(buildinfo_file):
61 """Extracts version tag from buildinfo file.
62
63 Args:
64 buildinfo_file: Path to buildinfo_file.
65 Returns:
66 Release tag string if available, otherwise None.
67 """
68 with open(buildinfo_file, 'r') as f:
Miguel Osorio1fe4e952019-10-10 09:35:44 -070069 match = re.match(VERSION_RE, f.read(), re.M)
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -070070 if not match:
71 return None
72 return match.group("version")
lowRISC Contributors802543a2019-08-31 12:12:56 +010073
74
75def download(url):
76 print("Downloading toolchain from %s" % (url, ))
77 tmpfile = tempfile.mktemp()
78 urlretrieve(url, tmpfile)
79 return tmpfile
80
81
Miguel Osorio8e282802019-09-24 10:37:27 -070082def install(archive_file, target_dir):
lowRISC Contributors802543a2019-08-31 12:12:56 +010083 os.makedirs(target_dir)
84
85 cmd = [
86 'tar', '-x', '-f', archive_file, '--strip-components=1', '-C',
87 target_dir
88 ]
89 subprocess.run(cmd, check=True)
90
91
92def main():
93 parser = argparse.ArgumentParser()
94 parser.add_argument(
95 '--target-dir',
96 '-t',
97 required=False,
98 default=TARGET_DIR,
99 help="Target directory (must not exist) (default: %(default)s)")
100 parser.add_argument(
101 '--release-version',
102 '-r',
103 required=False,
104 default=TOOLCHAIN_VERSION,
105 help="Toolchain version (default: %(default)s)")
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -0700106 parser.add_argument(
107 '--update',
108 '-u',
109 required=False,
110 default=False,
111 action='store_true',
112 help="Set to update to target version if needed (default: %(default)s)")
Miguel Osorio8e282802019-09-24 10:37:27 -0700113 parser.add_argument(
114 '--force',
115 '-f',
116 required=False,
117 default=False,
118 action='store_true',
119 help="Set to skip directory erase prompt when --update is set "
120 "(default: %(default)s)")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100121 args = parser.parse_args()
122
Miguel Osorio1351b982019-09-24 18:05:37 -0700123 target_dir = args.target_dir
lowRISC Contributors802543a2019-08-31 12:12:56 +0100124 toolchain_version = args.release_version
125
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -0700126 if not args.update and os.path.exists(args.target_dir):
127 sys.exit('Target directory %s already exists. Delete it first '
128 'it you want to re-download the toolchain.' % (target_dir, ))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100129
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -0700130 release_info = get_release_info(toolchain_version)
131
132 if args.update and os.path.exists(args.target_dir):
Miguel Osorio1351b982019-09-24 18:05:37 -0700133 buildinfo_file = str(Path(target_dir) / BUILDINFO_FILENAME)
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -0700134 if not os.path.exists(buildinfo_file):
135 sys.exit('Unable to find buildinfo file at %s. Delete target '
136 'directory and try again.' % buildinfo_file)
137 current_release_tag = get_release_tag_from_file(buildinfo_file)
Miguel Osorio1fe4e952019-10-10 09:35:44 -0700138 if not current_release_tag and not args.force:
139 # If args.force is set then we can skip this error condition. The
140 # version check test condition will also fail, and the install
141 # will continue.
Miguel Osorio8e282802019-09-24 10:37:27 -0700142 sys.exit('Unable to extract current toolchain version from %s. '
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -0700143 'Delete target directory and try again.' % buildinfo_file)
144 if get_release_tag(release_info) == current_release_tag:
145 print('Toolchain version %s already installed at %s. Skipping '
146 'install.' % (current_release_tag, target_dir))
147 return
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -0700148
149 download_url = get_download_url(release_info)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100150 try:
151 archive_file = download(download_url)
Miguel Osorio8e282802019-09-24 10:37:27 -0700152 if args.update and os.path.exists(args.target_dir):
153 # Warn the user before deleting the target directory.
154 warning_msg = 'WARNING: Removing directory: %s.' % target_dir
155 if not args.force:
156 if not prompt_yes_no(warning_msg + ' Continue [yes/no]:'):
157 sys.exit('Aborting update.')
158 else:
159 print(warning_msg)
160 shutil.rmtree(target_dir)
161 install(archive_file, target_dir)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100162 finally:
163 os.remove(archive_file)
164
165 print('Toolchain downloaded and installed to %s' % (target_dir, ))
166
167
168if __name__ == "__main__":
169 main()