blob: 73d82e3a648bcdefb8d01f89289644c31e83efa8 [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
Philipp Wagner1c514412019-11-27 14:48:47 +00008import logging as log
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -07009import re
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -070010import shutil
Philipp Wagner1c514412019-11-27 14:48:47 +000011import subprocess
lowRISC Contributors802543a2019-08-31 12:12:56 +010012import sys
13import tempfile
Philipp Wagner1c514412019-11-27 14:48:47 +000014from pathlib import Path
lowRISC Contributors802543a2019-08-31 12:12:56 +010015from urllib.request import urlopen, urlretrieve
16
Philipp Wagner1c514412019-11-27 14:48:47 +000017log.basicConfig(level=log.INFO, format="%(levelname)s: %(message)s")
18
lowRISC Contributors802543a2019-08-31 12:12:56 +010019ASSET_PREFIX = "lowrisc-toolchain-gcc-rv32imc-"
Miguel Osorioc7050002019-09-20 00:16:04 -070020ASSET_SUFFIX = ".tar.xz"
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -070021RELEASES_URL_BASE = 'https://api.github.com/repos/lowRISC/lowrisc-toolchains/releases'
Philipp Wagner1c514412019-11-27 14:48:47 +000022
lowRISC Contributors802543a2019-08-31 12:12:56 +010023TARGET_DIR = '/tools/riscv'
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -070024TOOLCHAIN_VERSION = 'latest'
lowRISC Contributors802543a2019-08-31 12:12:56 +010025
26
Philipp Wagner1c514412019-11-27 14:48:47 +000027def get_available_toolchain_info(version):
28 if version == 'latest':
29 releases_url = '%s/%s' % (RELEASES_URL_BASE, version)
lowRISC Contributors802543a2019-08-31 12:12:56 +010030 else:
Philipp Wagner1c514412019-11-27 14:48:47 +000031 releases_url = '%s/tags/%s' % (RELEASES_URL_BASE, version)
32
lowRISC Contributors802543a2019-08-31 12:12:56 +010033 with urlopen(releases_url) as f:
Philipp Wagner1c514412019-11-27 14:48:47 +000034 release_info = json.loads(f.read().decode('utf-8'))
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -070035
Philipp Wagner1c514412019-11-27 14:48:47 +000036 download_url = [
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -070037 a["browser_download_url"] for a in release_info["assets"]
38 if (a["name"].startswith(ASSET_PREFIX) and
39 a["name"].endswith(ASSET_SUFFIX))
40 ][0]
41
Philipp Wagner1c514412019-11-27 14:48:47 +000042 return {'download_url': download_url, 'version': release_info['tag_name']}
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -070043
44
Philipp Wagner1c514412019-11-27 14:48:47 +000045def get_installed_toolchain_info(install_path):
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -070046
Philipp Wagner1c514412019-11-27 14:48:47 +000047 # Try new-style buildinfo.json first
48 try:
49 buildinfo = {}
50 with open(str(install_path / 'buildinfo.json'), 'r') as f:
51 buildinfo = json.loads(f.read())
52 return buildinfo
53 except Exception as e:
54 # buildinfo.json might not exist in older builds
55 log.info("Unable to parse buildinfo.json: %s", str(e))
56 pass
57
58 # If that wasn't successful, try old-style plaintext buildinfo
59 version_re = r"(lowRISC toolchain version|Version):\s*\n?(?P<version>[^\n\s]+)"
60 buildinfo_txt_path = install_path / 'buildinfo'
61 try:
62 with open(str(buildinfo_txt_path), 'r') as f:
63 match = re.match(version_re, f.read(), re.M)
64 if not match:
65 log.warning("Unable extract version from %s",
66 str(buildinfo_txt_path))
67 return None
68 return {'version': match.group("version")}
69 except Exception as e:
70 log.error("Unable to read %s: %s", str(buildinfo_txt_path), str(e))
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -070071 return None
lowRISC Contributors802543a2019-08-31 12:12:56 +010072
73
74def download(url):
Philipp Wagner1c514412019-11-27 14:48:47 +000075 log.info("Downloading toolchain from %s", url)
76 tmpfile = tempfile.mkstemp()[1]
lowRISC Contributors802543a2019-08-31 12:12:56 +010077 urlretrieve(url, tmpfile)
Philipp Wagner1c514412019-11-27 14:48:47 +000078 return Path(tmpfile)
lowRISC Contributors802543a2019-08-31 12:12:56 +010079
80
Miguel Osorio8e282802019-09-24 10:37:27 -070081def install(archive_file, target_dir):
Philipp Wagner1c514412019-11-27 14:48:47 +000082 target_dir.mkdir(parents=True, exist_ok=True)
lowRISC Contributors802543a2019-08-31 12:12:56 +010083
84 cmd = [
Philipp Wagner1c514412019-11-27 14:48:47 +000085 'tar', '-x', '-f', str(archive_file), '--strip-components=1', '-C',
86 str(target_dir)
lowRISC Contributors802543a2019-08-31 12:12:56 +010087 ]
88 subprocess.run(cmd, check=True)
89
90
91def main():
92 parser = argparse.ArgumentParser()
Philipp Wagner1c514412019-11-27 14:48:47 +000093 parser.add_argument('--target-dir',
94 '-t',
95 required=False,
96 default=TARGET_DIR,
97 help="Target directory (default: %(default)s)")
98 parser.add_argument('--release-version',
99 '-r',
100 required=False,
101 default=TOOLCHAIN_VERSION,
102 help="Toolchain version (default: %(default)s)")
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -0700103 parser.add_argument(
104 '--update',
105 '-u',
106 required=False,
107 default=False,
108 action='store_true',
Philipp Wagner1c514412019-11-27 14:48:47 +0000109 help="Update to target version if needed (default: %(default)s)")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100110 args = parser.parse_args()
111
Philipp Wagner1c514412019-11-27 14:48:47 +0000112 target_dir = Path(args.target_dir)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100113
Philipp Wagner1c514412019-11-27 14:48:47 +0000114 available_toolchain = get_available_toolchain_info(args.release_version)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100115
Philipp Wagner1c514412019-11-27 14:48:47 +0000116 if args.update and target_dir.is_dir():
117 installed_toolchain = get_installed_toolchain_info(target_dir)
118 if installed_toolchain is None:
119 sys.exit('Unable to extract current toolchain version. '
120 'Delete target directory and try again.')
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -0700121
Philipp Wagner1c514412019-11-27 14:48:47 +0000122 if available_toolchain['version'] == installed_toolchain['version']:
123 log.info(
124 'Toolchain version %s already installed at %s. Skipping '
125 'install.', installed_toolchain['version'], str(target_dir))
126 sys.exit(0)
Miguel Osorio1e5fc8e2019-09-23 17:33:54 -0700127
Philipp Wagner1c514412019-11-27 14:48:47 +0000128 log.info(
129 "Found installed toolchain version %s, updating to version %s.",
130 installed_toolchain['version'], available_toolchain['version'])
131 else:
132 if target_dir.exists():
133 sys.exit(
134 'Target directory %s already exists. Delete it first, or use --update.'
135 % str(target_dir))
136
137 archive_file = None
lowRISC Contributors802543a2019-08-31 12:12:56 +0100138 try:
Philipp Wagner1c514412019-11-27 14:48:47 +0000139 archive_file = download(available_toolchain['download_url'])
140
141 if args.update and target_dir.exists():
142 # We only reach this point if |target_dir| contained a toolchain
143 # before, so removing it is reasonably safe.
Miguel Osorio8e282802019-09-24 10:37:27 -0700144 shutil.rmtree(target_dir)
Philipp Wagner1c514412019-11-27 14:48:47 +0000145
Miguel Osorio8e282802019-09-24 10:37:27 -0700146 install(archive_file, target_dir)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100147 finally:
Philipp Wagner1c514412019-11-27 14:48:47 +0000148 if archive_file:
149 archive_file.unlink()
lowRISC Contributors802543a2019-08-31 12:12:56 +0100150
Philipp Wagner1c514412019-11-27 14:48:47 +0000151 log.info('Toolchain version %s downloaded and installed to %s.',
152 available_toolchain['version'], str(target_dir))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100153
154
155if __name__ == "__main__":
156 main()