Download relevant toolchain.

This commit is contained in:
Nick Brassel 2024-07-01 21:49:21 +10:00
parent 3ffe8d917a
commit 33f5e67408
No known key found for this signature in database
7 changed files with 109 additions and 1 deletions

1
.gitignore vendored
View File

@ -25,6 +25,7 @@
*.la *.la
*.stackdump *.stackdump
*.sym *.sym
qmk_toolchains*
# QMK-specific # QMK-specific
api_data/v1 api_data/v1

View File

@ -82,6 +82,7 @@ subcommands = [
'qmk.cli.painter', 'qmk.cli.painter',
'qmk.cli.pytest', 'qmk.cli.pytest',
'qmk.cli.test.c', 'qmk.cli.test.c',
'qmk.cli.toolchain.commands',
'qmk.cli.userspace.add', 'qmk.cli.userspace.add',
'qmk.cli.userspace.compile', 'qmk.cli.userspace.compile',
'qmk.cli.userspace.doctor', 'qmk.cli.userspace.doctor',
@ -258,3 +259,11 @@ for subcommand in subcommands:
_eprint(f'Warning: Could not import {subcommand}: {e.__class__.__name__}, {e}') _eprint(f'Warning: Could not import {subcommand}: {e.__class__.__name__}, {e}')
else: else:
raise raise
# Add the QMK toolchains to $PATH
try:
from qmk.constants import QMK_TOOLCHAINS_PATH # noqa
if QMK_TOOLCHAINS_PATH.exists():
os.environ['PATH'] = f'{QMK_TOOLCHAINS_PATH}/bin{os.pathsep}{os.environ["PATH"]}'
except Exception:
pass

View File

View File

@ -0,0 +1,70 @@
"""This script sets up the QMK-provided toolchains.
"""
import platform
import shutil
import subprocess
import os
from milc import cli
from pathlib import Path
from qmk.constants import QMK_TOOLCHAINS_PATH, QMK_TOOLCHAINS_TAG
from qmk.util import download_with_progress, cached_get
def _os_prefix():
os = platform.system().lower()
if "linux" in os:
return "linux"
elif "darwin" in os or "mac" in os or "macos" in os or "osx" in os or "macosx" in os:
return "macos"
elif "windows" in os or "cygwin" in os or "msys" in os or "win32" in os or "win64" in os or "nt" in os:
return "windows"
return "unknown"
def _arch_suffix():
arch = platform.machine().lower()
if "amd64" in arch or "x86_64" in arch or "x64" in arch or "x86-64" in arch:
return "X64"
elif "arm64" in arch or "aarch64" in arch:
return "ARM64"
return "unknown"
def _os_arch():
return f'{_os_prefix()}{_arch_suffix()}'
def _gcc_version_str(gcc_exe):
lines = cli.run([gcc_exe, '-v'], check=True, capture_output=True, combined_output=True, stdin=subprocess.DEVNULL).stdout.strip().splitlines()
return list(filter(lambda x: x.startswith('gcc version'), lines))[0].strip()
@cli.argument('-t', '--tag', default=QMK_TOOLCHAINS_TAG, help=f'The tag of the QMK-provided toolchains to download. Defaults to `{QMK_TOOLCHAINS_TAG}`.')
@cli.subcommand('Set up the QMK-provided toolchains.', hidden=False if cli.config.user.developer else True)
def toolchain_setup(cli):
"""Set up the QMK-provided toolchains.
"""
# Remove the toolchains directory if it exists already
if QMK_TOOLCHAINS_PATH.exists():
cli.log.info(f'Removing existing toolchains at `{QMK_TOOLCHAINS_PATH}`...')
shutil.rmtree(QMK_TOOLCHAINS_PATH)
url = f'https://api.github.com/repos/qmk/qmk_toolchains/releases/tags/{cli.args.tag}'
payload = cached_get(url)
if payload.status_code != 200:
cli.log.error(f'Failed to fetch toolchain metadata from `{url}`.')
return
downloadables = filter(lambda x: _os_arch() in x['name'], payload.json()['assets'])
for downloadable in downloadables:
if not Path(downloadable["name"]).exists():
download_with_progress(downloadable['browser_download_url'], downloadable["name"])
cli.log.info(f'Extracting `{downloadable["name"]}` to `{QMK_TOOLCHAINS_PATH}`...')
QMK_TOOLCHAINS_PATH.mkdir(parents=True, exist_ok=True)
cli.run(['tar', 'xf', downloadable["name"], '-C', QMK_TOOLCHAINS_PATH, '--strip-components=1'], capture_output=False, check=True, stdin=subprocess.DEVNULL)
os.environ['PATH'] = f'{QMK_TOOLCHAINS_PATH}/bin{os.pathsep}{os.environ["PATH"]}'
for gcc_exe in ['avr-gcc', 'arm-none-eabi-gcc', 'riscv32-unknown-elf-gcc']:
cli.log.info(f'{gcc_exe:24s}: {_gcc_version_str(gcc_exe)}')

View File

@ -21,6 +21,12 @@ QMK_FIRMWARE_UPSTREAM = 'qmk/qmk_firmware'
# This is the number of directories under `qmk_firmware/keyboards` that will be traversed. This is currently a limitation of our make system. # This is the number of directories under `qmk_firmware/keyboards` that will be traversed. This is currently a limitation of our make system.
MAX_KEYBOARD_SUBFOLDERS = 5 MAX_KEYBOARD_SUBFOLDERS = 5
# Intended qmk/qmk_toolchains release to deploy
QMK_TOOLCHAINS_TAG = 'v14.1.0-4'
# QMK Toolchains path
QMK_TOOLCHAINS_PATH = Path('~/.local/qmk/toolchains').expanduser()
# Supported processor types # Supported processor types
CHIBIOS_PROCESSORS = 'cortex-m0', 'cortex-m0plus', 'cortex-m3', 'cortex-m4', 'MKL26Z64', 'MK20DX128', 'MK20DX256', 'MK64FX512', 'MK66FX1M0', 'RP2040', 'STM32F042', 'STM32F072', 'STM32F103', 'STM32F303', 'STM32F401', 'STM32F405', 'STM32F407', 'STM32F411', 'STM32F446', 'STM32G431', 'STM32G474', 'STM32H723', 'STM32H733', 'STM32L412', 'STM32L422', 'STM32L432', 'STM32L433', 'STM32L442', 'STM32L443', 'GD32VF103', 'WB32F3G71', 'WB32FQ95' CHIBIOS_PROCESSORS = 'cortex-m0', 'cortex-m0plus', 'cortex-m3', 'cortex-m4', 'MKL26Z64', 'MK20DX128', 'MK20DX256', 'MK64FX512', 'MK66FX1M0', 'RP2040', 'STM32F042', 'STM32F072', 'STM32F103', 'STM32F303', 'STM32F401', 'STM32F405', 'STM32F407', 'STM32F411', 'STM32F446', 'STM32G431', 'STM32G474', 'STM32H723', 'STM32H733', 'STM32L412', 'STM32L422', 'STM32L432', 'STM32L433', 'STM32L442', 'STM32L443', 'GD32VF103', 'WB32F3G71', 'WB32FQ95'
LUFA_PROCESSORS = 'at90usb162', 'atmega16u2', 'atmega32u2', 'atmega16u4', 'atmega32u4', 'at90usb646', 'at90usb647', 'at90usb1286', 'at90usb1287', None LUFA_PROCESSORS = 'at90usb162', 'atmega16u2', 'atmega32u2', 'atmega16u4', 'atmega32u4', 'at90usb646', 'at90usb647', 'at90usb1286', 'at90usb1287', None

View File

@ -3,6 +3,7 @@
import contextlib import contextlib
import multiprocessing import multiprocessing
import sys import sys
from pathlib import Path
from milc import cli from milc import cli
@ -27,6 +28,24 @@ def maybe_exit_config(should_exit: bool = True, should_reraise: bool = False):
maybe_exit_reraise = should_reraise maybe_exit_reraise = should_reraise
def cached_get(*args, **kwargs):
import requests_cache
session = requests_cache.CachedSession(Path('~/.local/qmk/qmk_requests.sqlite').expanduser(), expire_after=300, cache_control=True)
return session.get(*args, **kwargs)
def download_with_progress(url, filename):
import requests
import tqdm
response = requests.get(url, stream=True)
total_size = int(response.headers.get('content-length', 0))
with tqdm.tqdm(desc=filename, total=total_size, unit='B', unit_scale=True) as pbar:
with open(filename, 'wb') as file:
for data in response.iter_content(1024):
file.write(data)
pbar.update(len(data))
@contextlib.contextmanager @contextlib.contextmanager
def parallelize(): def parallelize():
"""Returns a function that can be used in place of a map() call. """Returns a function that can be used in place of a map() call.

View File

@ -6,8 +6,11 @@ dotty-dict
hid hid
hjson hjson
jsonschema>=4 jsonschema>=4
milc>=1.4.2 milc>=1.8.0
pygments pygments
pyserial pyserial
pyusb pyusb
pillow pillow
requests
requests-cache
tqdm