Download relevant toolchain.
This commit is contained in:
parent
3ffe8d917a
commit
33f5e67408
1
.gitignore
vendored
1
.gitignore
vendored
@ -25,6 +25,7 @@
|
||||
*.la
|
||||
*.stackdump
|
||||
*.sym
|
||||
qmk_toolchains*
|
||||
|
||||
# QMK-specific
|
||||
api_data/v1
|
||||
|
@ -82,6 +82,7 @@ subcommands = [
|
||||
'qmk.cli.painter',
|
||||
'qmk.cli.pytest',
|
||||
'qmk.cli.test.c',
|
||||
'qmk.cli.toolchain.commands',
|
||||
'qmk.cli.userspace.add',
|
||||
'qmk.cli.userspace.compile',
|
||||
'qmk.cli.userspace.doctor',
|
||||
@ -258,3 +259,11 @@ for subcommand in subcommands:
|
||||
_eprint(f'Warning: Could not import {subcommand}: {e.__class__.__name__}, {e}')
|
||||
else:
|
||||
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
|
||||
|
0
lib/python/qmk/cli/toolchain/__init__.py
Normal file
0
lib/python/qmk/cli/toolchain/__init__.py
Normal file
70
lib/python/qmk/cli/toolchain/commands.py
Normal file
70
lib/python/qmk/cli/toolchain/commands.py
Normal 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)}')
|
@ -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.
|
||||
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
|
||||
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
|
||||
|
@ -3,6 +3,7 @@
|
||||
import contextlib
|
||||
import multiprocessing
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
def parallelize():
|
||||
"""Returns a function that can be used in place of a map() call.
|
||||
|
@ -6,8 +6,11 @@ dotty-dict
|
||||
hid
|
||||
hjson
|
||||
jsonschema>=4
|
||||
milc>=1.4.2
|
||||
milc>=1.8.0
|
||||
pygments
|
||||
pyserial
|
||||
pyusb
|
||||
pillow
|
||||
requests
|
||||
requests-cache
|
||||
tqdm
|
||||
|
Loading…
x
Reference in New Issue
Block a user