summaryrefslogtreecommitdiff
path: root/lib/python/qmk/cli
diff options
context:
space:
mode:
authorIlya Zhuravlev <whatever@xyz.is>2024-09-07 19:49:19 -0600
committerIlya Zhuravlev <whatever@xyz.is>2024-09-07 19:49:19 -0600
commita780dd1cb1736b67b2139bf15cb93c932108e8fd (patch)
tree6e9bccf1700bfd804643aba6aed8ce219f03b40d /lib/python/qmk/cli
parentbb7961c3c27666c154393bca22aef31f8e60f5b9 (diff)
parentf0435451446621a0e768c8a9123789b239a325b4 (diff)
Merge remote-tracking branch 'qmk/master' into merge-2024-09-07
Diffstat (limited to 'lib/python/qmk/cli')
-rw-r--r--lib/python/qmk/cli/__init__.py29
-rw-r--r--lib/python/qmk/cli/doctor/check.py5
-rwxr-xr-xlib/python/qmk/cli/doctor/main.py2
-rwxr-xr-xlib/python/qmk/cli/format/json.py9
-rwxr-xr-xlib/python/qmk/cli/generate/config_h.py4
-rwxr-xr-xlib/python/qmk/cli/generate/keyboard_c.py38
-rw-r--r--lib/python/qmk/cli/generate/keymap_h.py51
-rw-r--r--lib/python/qmk/cli/lint.py10
-rwxr-xr-xlib/python/qmk/cli/mass_compile.py24
-rw-r--r--lib/python/qmk/cli/new/keyboard.py34
-rw-r--r--lib/python/qmk/cli/userspace/add.py10
-rw-r--r--lib/python/qmk/cli/userspace/compile.py10
-rw-r--r--lib/python/qmk/cli/userspace/list.py23
-rwxr-xr-xlib/python/qmk/cli/userspace/path.py2
-rw-r--r--lib/python/qmk/cli/userspace/remove.py10
15 files changed, 193 insertions, 68 deletions
diff --git a/lib/python/qmk/cli/__init__.py b/lib/python/qmk/cli/__init__.py
index b504aa5f8c..0baf19a629 100644
--- a/lib/python/qmk/cli/__init__.py
+++ b/lib/python/qmk/cli/__init__.py
@@ -58,6 +58,7 @@ subcommands = [
'qmk.cli.generate.keyboard_h',
'qmk.cli.generate.keycodes',
'qmk.cli.generate.keycodes_tests',
+ 'qmk.cli.generate.keymap_h',
'qmk.cli.generate.make_dependencies',
'qmk.cli.generate.rgb_breathe_table',
'qmk.cli.generate.rules_mk',
@@ -189,20 +190,22 @@ def _eprint(errmsg):
# Supported version information
#
# Based on the OSes we support these are the minimum python version available by default.
-# Last update: 2021 Jan 02
+# Last update: 2024 Jun 24
#
-# Arch: 3.9
-# Debian: 3.7
-# Fedora 31: 3.7
-# Fedora 32: 3.8
-# Fedora 33: 3.9
-# FreeBSD: 3.7
-# Gentoo: 3.7
-# macOS: 3.9 (from homebrew)
-# msys2: 3.8
-# Slackware: 3.7
-# solus: 3.7
-# void: 3.9
+# Arch: 3.12
+# Debian 11: 3.9
+# Debian 12: 3.11
+# Fedora 39: 3.12
+# Fedora 40: 3.12
+# FreeBSD: 3.11
+# Gentoo: 3.12
+# macOS: 3.12 (from homebrew)
+# msys2: 3.11
+# Slackware: 3.9
+# solus: 3.10
+# Ubuntu 22.04: 3.10
+# Ubuntu 24.04: 3.12
+# void: 3.12
if sys.version_info[0] != 3 or sys.version_info[1] < 7:
_eprint('Error: Your Python is too old! Please upgrade to Python 3.7 or later.')
diff --git a/lib/python/qmk/cli/doctor/check.py b/lib/python/qmk/cli/doctor/check.py
index cd69cdd11c..d563811aba 100644
--- a/lib/python/qmk/cli/doctor/check.py
+++ b/lib/python/qmk/cli/doctor/check.py
@@ -53,11 +53,6 @@ def _check_avr_gcc_version():
version_number = ESSENTIAL_BINARIES['avr-gcc']['output'].strip()
cli.log.info('Found avr-gcc version %s', version_number)
- parsed_version = _parse_gcc_version(version_number)
- if parsed_version['major'] > 8:
- cli.log.warning('{fg_yellow}We do not recommend avr-gcc newer than 8. Downgrading to 8.x is recommended.')
- return CheckStatus.WARNING
-
return CheckStatus.OK
diff --git a/lib/python/qmk/cli/doctor/main.py b/lib/python/qmk/cli/doctor/main.py
index dd8b58b2c7..5215d3a7ee 100755
--- a/lib/python/qmk/cli/doctor/main.py
+++ b/lib/python/qmk/cli/doctor/main.py
@@ -187,5 +187,5 @@ def doctor(cli):
return 1
else:
cli.log.info('{fg_red}Major problems detected, please fix these problems before proceeding.')
- cli.log.info('{fg_blue}Check out the FAQ (https://docs.qmk.fm/#/faq_build) or join the QMK Discord (https://discord.gg/Uq7gcHh) for help.')
+ cli.log.info('{fg_blue}Check out the FAQ (https://docs.qmk.fm/#/faq_build) or join the QMK Discord (https://discord.gg/qmk) for help.')
return 2
diff --git a/lib/python/qmk/cli/format/json.py b/lib/python/qmk/cli/format/json.py
index 87a3837d10..3670294434 100755
--- a/lib/python/qmk/cli/format/json.py
+++ b/lib/python/qmk/cli/format/json.py
@@ -18,13 +18,20 @@ def _detect_json_format(file, json_data):
"""
json_encoder = None
try:
- validate(json_data, 'qmk.user_repo.v1')
+ validate(json_data, 'qmk.user_repo.v1_1')
json_encoder = UserspaceJSONEncoder
except ValidationError:
pass
if json_encoder is None:
try:
+ validate(json_data, 'qmk.user_repo.v1')
+ json_encoder = UserspaceJSONEncoder
+ except ValidationError:
+ pass
+
+ if json_encoder is None:
+ try:
validate(json_data, 'qmk.keyboard.v1')
json_encoder = InfoJSONEncoder
except ValidationError as e:
diff --git a/lib/python/qmk/cli/generate/config_h.py b/lib/python/qmk/cli/generate/config_h.py
index fc681300a3..d613f7b92c 100755
--- a/lib/python/qmk/cli/generate/config_h.py
+++ b/lib/python/qmk/cli/generate/config_h.py
@@ -135,8 +135,8 @@ def generate_encoder_config(encoder_json, config_h_lines, postfix=''):
b_pads.append(encoder["pin_b"])
resolutions.append(encoder.get("resolution", None))
- config_h_lines.append(generate_define(f'ENCODERS_PAD_A{postfix}', f'{{ {", ".join(a_pads)} }}'))
- config_h_lines.append(generate_define(f'ENCODERS_PAD_B{postfix}', f'{{ {", ".join(b_pads)} }}'))
+ config_h_lines.append(generate_define(f'ENCODER_A_PINS{postfix}', f'{{ {", ".join(a_pads)} }}'))
+ config_h_lines.append(generate_define(f'ENCODER_B_PINS{postfix}', f'{{ {", ".join(b_pads)} }}'))
if None in resolutions:
cli.log.debug(f"Unable to generate ENCODER_RESOLUTION{postfix} configuration")
diff --git a/lib/python/qmk/cli/generate/keyboard_c.py b/lib/python/qmk/cli/generate/keyboard_c.py
index 5a6c967486..228b320942 100755
--- a/lib/python/qmk/cli/generate/keyboard_c.py
+++ b/lib/python/qmk/cli/generate/keyboard_c.py
@@ -6,7 +6,7 @@ from qmk.info import info_json
from qmk.commands import dump_lines
from qmk.keyboard import keyboard_completer, keyboard_folder
from qmk.path import normpath
-from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE
+from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, JOYSTICK_AXES
def _gen_led_configs(info_data):
@@ -91,6 +91,41 @@ def _gen_matrix_mask(info_data):
return lines
+def _gen_joystick_axes(info_data):
+ """Convert info.json content to joystick_axes
+ """
+ if 'axes' not in info_data.get('joystick', {}):
+ return []
+
+ axes = info_data['joystick']['axes']
+ axes_keys = list(axes.keys())
+
+ lines = []
+ lines.append('#ifdef JOYSTICK_ENABLE')
+ lines.append('joystick_config_t joystick_axes[JOYSTICK_AXIS_COUNT] = {')
+
+ # loop over all available axes - injecting virtual axis for those not specified
+ for index, cur in enumerate(JOYSTICK_AXES):
+ # bail out if we have generated all requested axis
+ if len(axes_keys) == 0:
+ break
+
+ axis = 'virtual'
+ if cur in axes:
+ axis = axes[cur]
+ axes_keys.remove(cur)
+
+ if axis == 'virtual':
+ lines.append(f" [{index}] = JOYSTICK_AXIS_VIRTUAL,")
+ else:
+ lines.append(f" [{index}] = JOYSTICK_AXIS_IN({axis['input_pin']}, {axis['low']}, {axis['rest']}, {axis['high']}),")
+
+ lines.append('};')
+ lines.append('#endif')
+
+ return lines
+
+
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
@cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, completer=keyboard_completer, required=True, help='Keyboard to generate keyboard.c for.')
@@ -105,6 +140,7 @@ def generate_keyboard_c(cli):
keyboard_h_lines.extend(_gen_led_configs(kb_info_json))
keyboard_h_lines.extend(_gen_matrix_mask(kb_info_json))
+ keyboard_h_lines.extend(_gen_joystick_axes(kb_info_json))
# Show the results
dump_lines(cli.args.output, keyboard_h_lines, cli.args.quiet)
diff --git a/lib/python/qmk/cli/generate/keymap_h.py b/lib/python/qmk/cli/generate/keymap_h.py
new file mode 100644
index 0000000000..a3aaa405c0
--- /dev/null
+++ b/lib/python/qmk/cli/generate/keymap_h.py
@@ -0,0 +1,51 @@
+from argcomplete.completers import FilesCompleter
+
+from milc import cli
+
+import qmk.path
+from qmk.commands import dump_lines
+from qmk.commands import parse_configurator_json
+from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE
+
+
+def _generate_keycodes_function(keymap_json):
+ """Generates keymap level keycodes.
+ """
+ lines = []
+ lines.append('enum keymap_keycodes {')
+
+ for index, item in enumerate(keymap_json.get('keycodes', [])):
+ key = item["key"]
+ if index == 0:
+ lines.append(f' {key} = QK_USER_0,')
+ else:
+ lines.append(f' {key},')
+
+ lines.append('};')
+
+ for item in keymap_json.get('keycodes', []):
+ key = item["key"]
+ for alias in item.get("aliases", []):
+ lines.append(f'#define {alias} {key}')
+
+ return lines
+
+
+@cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to')
+@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
+@cli.argument('filename', type=qmk.path.FileType('r'), arg_only=True, completer=FilesCompleter('.json'), help='Configurator JSON file')
+@cli.subcommand('Creates a keymap.h from a QMK Configurator export.')
+def generate_keymap_h(cli):
+ """Creates a keymap.h from a QMK Configurator export
+ """
+ if cli.args.output and cli.args.output.name == '-':
+ cli.args.output = None
+
+ keymap_h_lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once', '// clang-format off']
+
+ keymap_json = parse_configurator_json(cli.args.filename)
+
+ if 'keycodes' in keymap_json and keymap_json['keycodes'] is not None:
+ keymap_h_lines += _generate_keycodes_function(keymap_json)
+
+ dump_lines(cli.args.output, keymap_h_lines, cli.args.quiet)
diff --git a/lib/python/qmk/cli/lint.py b/lib/python/qmk/cli/lint.py
index ba0c3f274c..efb29704ae 100644
--- a/lib/python/qmk/cli/lint.py
+++ b/lib/python/qmk/cli/lint.py
@@ -14,15 +14,16 @@ from qmk.c_parse import c_source_files
CHIBIOS_CONF_CHECKS = ['chconf.h', 'halconf.h', 'mcuconf.h', 'board.h']
INVALID_KB_FEATURES = set(['encoder_map', 'dip_switch_map', 'combo', 'tap_dance', 'via'])
+INVALID_KM_NAMES = ['via', 'vial']
def _list_defaultish_keymaps(kb):
"""Return default like keymaps for a given keyboard
"""
- defaultish = ['ansi', 'iso', 'via']
+ defaultish = ['ansi', 'iso']
# This is only here to flag it as "testable", so it doesn't fly under the radar during PR
- defaultish.append('vial')
+ defaultish.extend(INVALID_KM_NAMES)
keymaps = set()
for x in list_keymaps(kb):
@@ -136,6 +137,11 @@ def keymap_check(kb, km):
cli.log.error("%s: Can't find %s keymap.", kb, km)
return ok
+ if km in INVALID_KM_NAMES:
+ ok = False
+ cli.log.error("%s: The keymap %s should not exist!", kb, km)
+ return ok
+
# Additional checks
invalid_files = git_get_ignored_files(keymap_path.parent.as_posix())
for file in invalid_files:
diff --git a/lib/python/qmk/cli/mass_compile.py b/lib/python/qmk/cli/mass_compile.py
index d13afc6143..cf9be0fd1e 100755
--- a/lib/python/qmk/cli/mass_compile.py
+++ b/lib/python/qmk/cli/mass_compile.py
@@ -7,6 +7,7 @@ from typing import List
from pathlib import Path
from subprocess import DEVNULL
from milc import cli
+import shlex
from qmk.constants import QMK_FIRMWARE
from qmk.commands import find_make, get_make_parallel_args, build_environment
@@ -26,7 +27,8 @@ def mass_compile_targets(targets: List[BuildTarget], clean: bool, dry_run: bool,
if dry_run:
cli.log.info('Compilation targets:')
for target in sorted(targets, key=lambda t: (t.keyboard, t.keymap)):
- cli.log.info(f"{{fg_cyan}}qmk compile -kb {target.keyboard} -km {target.keymap}{{fg_reset}}")
+ extra_args = ' '.join([f"-e {shlex.quote(f'{k}={v}')}" for k, v in target.extra_args.items()])
+ cli.log.info(f"{{fg_cyan}}qmk compile -kb {target.keyboard} -km {target.keymap} {extra_args}{{fg_reset}}")
else:
if clean:
cli.run([make_cmd, 'clean'], capture_output=False, stdin=DEVNULL)
@@ -36,18 +38,26 @@ def mass_compile_targets(targets: List[BuildTarget], clean: bool, dry_run: bool,
for target in sorted(targets, key=lambda t: (t.keyboard, t.keymap)):
keyboard_name = target.keyboard
keymap_name = target.keymap
+ keyboard_safe = keyboard_name.replace('/', '_')
+ target_filename = target.target_name(**env)
target.configure(parallel=1) # We ignore parallelism on a per-build basis as we defer to the parent make invocation
target.prepare_build(**env) # If we've got json targets, allow them to write out any extra info to .build before we kick off `make`
command = target.compile_command(**env)
command[0] = '+@$(MAKE)' # Override the make so that we can use jobserver to handle parallelism
- keyboard_safe = keyboard_name.replace('/', '_')
+ extra_args = '_'.join([f"{k}_{v}" for k, v in target.extra_args.items()])
build_log = f"{QMK_FIRMWARE}/.build/build.log.{os.getpid()}.{keyboard_safe}.{keymap_name}"
failed_log = f"{QMK_FIRMWARE}/.build/failed.log.{os.getpid()}.{keyboard_safe}.{keymap_name}"
+ target_suffix = ''
+ if len(extra_args) > 0:
+ build_log += f".{extra_args}"
+ failed_log += f".{extra_args}"
+ target_suffix = f"_{extra_args}"
# yapf: disable
f.write(
f"""\
-all: {keyboard_safe}_{keymap_name}_binary
-{keyboard_safe}_{keymap_name}_binary:
+.PHONY: {target_filename}{target_suffix}_binary
+all: {target_filename}{target_suffix}_binary
+{target_filename}{target_suffix}_binary:
@rm -f "{build_log}" || true
@echo "Compiling QMK Firmware for target: '{keyboard_name}:{keymap_name}'..." >>"{build_log}"
{' '.join(command)} \\
@@ -65,9 +75,9 @@ all: {keyboard_safe}_{keymap_name}_binary
# yapf: disable
f.write(
f"""\
- @rm -rf "{QMK_FIRMWARE}/.build/{keyboard_safe}_{keymap_name}.elf" 2>/dev/null || true
- @rm -rf "{QMK_FIRMWARE}/.build/{keyboard_safe}_{keymap_name}.map" 2>/dev/null || true
- @rm -rf "{QMK_FIRMWARE}/.build/obj_{keyboard_safe}_{keymap_name}" || true
+ @rm -rf "{QMK_FIRMWARE}/.build/{target_filename}.elf" 2>/dev/null || true
+ @rm -rf "{QMK_FIRMWARE}/.build/{target_filename}.map" 2>/dev/null || true
+ @rm -rf "{QMK_FIRMWARE}/.build/obj_{target_filename}" || true
"""# noqa
)
# yapf: enable
diff --git a/lib/python/qmk/cli/new/keyboard.py b/lib/python/qmk/cli/new/keyboard.py
index 56bd05e1e3..b84b130f8e 100644
--- a/lib/python/qmk/cli/new/keyboard.py
+++ b/lib/python/qmk/cli/new/keyboard.py
@@ -14,7 +14,7 @@ from qmk.git import git_get_username
from qmk.json_schema import load_jsonschema
from qmk.path import keyboard
from qmk.json_encoders import InfoJSONEncoder
-from qmk.json_schema import deep_update, json_load
+from qmk.json_schema import deep_update
from qmk.constants import MCU2BOOTLOADER, QMK_FIRMWARE
COMMUNITY = Path('layouts/default/')
@@ -78,7 +78,7 @@ def replace_string(src, token, value):
src.write_text(src.read_text().replace(token, value))
-def augment_community_info(src, dest):
+def augment_community_info(config, src, dest):
"""Splice in any additional data into info.json
"""
info = json.loads(src.read_text())
@@ -86,6 +86,7 @@ def augment_community_info(src, dest):
# merge community with template
deep_update(info, template)
+ deep_update(info, config)
# avoid assumptions on macro name by using the first available
first_layout = next(iter(info["layouts"].values()))["layout"]
@@ -105,7 +106,7 @@ def augment_community_info(src, dest):
for item in first_layout:
item["matrix"] = [int(item["y"]), int(item["x"])]
- # finally write out the updated info.json
+ # finally write out the updated json
dest.write_text(json.dumps(info, cls=InfoJSONEncoder, sort_keys=True))
@@ -212,15 +213,12 @@ def new_keyboard(cli):
default_layout = cli.args.layout if cli.args.layout else prompt_layout()
mcu = cli.args.type if cli.args.type else prompt_mcu()
- # Preprocess any development_board presets
+ config = {}
if mcu in dev_boards:
- defaults_map = json_load(Path('data/mappings/defaults.hjson'))
- board = defaults_map['development_board'][mcu]
-
- mcu = board['processor']
- bootloader = board['bootloader']
+ config['development_board'] = mcu
else:
- bootloader = select_default_bootloader(mcu)
+ config['processor'] = mcu
+ config['bootloader'] = select_default_bootloader(mcu)
detach_layout = False
if default_layout == 'none of the above':
@@ -231,17 +229,9 @@ def new_keyboard(cli):
'YEAR': str(date.today().year),
'KEYBOARD': kb_name,
'USER_NAME': user_name,
- 'REAL_NAME': real_name,
- 'LAYOUT': default_layout,
- 'MCU': mcu,
- 'BOOTLOADER': bootloader
+ 'REAL_NAME': real_name
}
- if cli.config.general.verbose:
- cli.log.info("Creating keyboard with:")
- for key, value in tokens.items():
- cli.echo(f" {key.ljust(10)}: {value}")
-
# begin with making the deepest folder in the tree
keymaps_path = keyboard(kb_name) / 'keymaps/'
keymaps_path.mkdir(parents=True)
@@ -256,7 +246,7 @@ def new_keyboard(cli):
# merge in infos
community_info = Path(COMMUNITY / f'{default_layout}/info.json')
- augment_community_info(community_info, keyboard(kb_name) / 'keyboard.json')
+ augment_community_info(config, community_info, keyboard(kb_name) / 'keyboard.json')
# detach community layout and rename to just "LAYOUT"
if detach_layout:
@@ -265,5 +255,5 @@ def new_keyboard(cli):
cli.log.info(f'{{fg_green}}Created a new keyboard called {{fg_cyan}}{kb_name}{{fg_green}}.{{fg_reset}}')
cli.log.info(f"Build Command: {{fg_yellow}}qmk compile -kb {kb_name} -km default{{fg_reset}}.")
- cli.log.info(f'Project Location: {{fg_cyan}}{QMK_FIRMWARE}/{keyboard(kb_name)}{{fg_reset}},')
- cli.log.info("{{fg_yellow}}Now update the config files to match the hardware!{{fg_reset}}")
+ cli.log.info(f'Project Location: {{fg_cyan}}{QMK_FIRMWARE}/{keyboard(kb_name)}{{fg_reset}}.')
+ cli.log.info("{fg_yellow}Now update the config files to match the hardware!{fg_reset}")
diff --git a/lib/python/qmk/cli/userspace/add.py b/lib/python/qmk/cli/userspace/add.py
index 8993d54dba..0d6f32cd11 100644
--- a/lib/python/qmk/cli/userspace/add.py
+++ b/lib/python/qmk/cli/userspace/add.py
@@ -1,8 +1,9 @@
-# Copyright 2023 Nick Brassel (@tzarc)
+# Copyright 2023-2024 Nick Brassel (@tzarc)
# SPDX-License-Identifier: GPL-2.0-or-later
from pathlib import Path
from milc import cli
+from qmk.commands import parse_env_vars
from qmk.constants import QMK_USERSPACE, HAS_QMK_USERSPACE
from qmk.keyboard import keyboard_completer, keyboard_folder_or_all
from qmk.keymap import keymap_completer, is_keymap_target
@@ -12,12 +13,15 @@ from qmk.userspace import UserspaceDefs
@cli.argument('builds', nargs='*', arg_only=True, help="List of builds in form <keyboard>:<keymap>, or path to a keymap JSON file.")
@cli.argument('-kb', '--keyboard', type=keyboard_folder_or_all, completer=keyboard_completer, help='The keyboard to build a firmware for. Ignored when a configurator export is supplied.')
@cli.argument('-km', '--keymap', completer=keymap_completer, help='The keymap to build a firmware for. Ignored when a configurator export is supplied.')
+@cli.argument('-e', '--env', arg_only=True, action='append', default=[], help="Extra variables to set during build. May be passed multiple times.")
@cli.subcommand('Adds a build target to userspace `qmk.json`.')
def userspace_add(cli):
if not HAS_QMK_USERSPACE:
cli.log.error('Could not determine QMK userspace location. Please run `qmk doctor` or `qmk userspace-doctor` to diagnose.')
return False
+ build_env = None if len(cli.args.env) == 0 else parse_env_vars(cli.args.env)
+
userspace = UserspaceDefs(QMK_USERSPACE / 'qmk.json')
if len(cli.args.builds) > 0:
@@ -44,8 +48,8 @@ def userspace_add(cli):
cli.config.new_keymap.keyboard = cli.args.keyboard
cli.config.new_keymap.keymap = cli.args.keymap
if new_keymap(cli) is not False:
- userspace.add_target(keyboard=cli.args.keyboard, keymap=cli.args.keymap)
+ userspace.add_target(keyboard=cli.args.keyboard, keymap=cli.args.keymap, build_env=build_env)
else:
- userspace.add_target(keyboard=cli.args.keyboard, keymap=cli.args.keymap)
+ userspace.add_target(keyboard=cli.args.keyboard, keymap=cli.args.keymap, build_env=build_env)
return userspace.save()
diff --git a/lib/python/qmk/cli/userspace/compile.py b/lib/python/qmk/cli/userspace/compile.py
index e8cdf6cd97..f164ca2ef1 100644
--- a/lib/python/qmk/cli/userspace/compile.py
+++ b/lib/python/qmk/cli/userspace/compile.py
@@ -1,4 +1,4 @@
-# Copyright 2023 Nick Brassel (@tzarc)
+# Copyright 2023-2024 Nick Brassel (@tzarc)
# SPDX-License-Identifier: GPL-2.0-or-later
from pathlib import Path
from milc import cli
@@ -12,6 +12,10 @@ from qmk.cli.mass_compile import mass_compile_targets
from qmk.util import maybe_exit_config
+def _extra_arg_setter(target, extra_args):
+ target.extra_args = extra_args
+
+
@cli.argument('-t', '--no-temp', arg_only=True, action='store_true', help="Remove temporary files during build.")
@cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs; 0 means unlimited.")
@cli.argument('-c', '--clean', arg_only=True, action='store_true', help="Remove object files before compiling.")
@@ -33,8 +37,8 @@ def userspace_compile(cli):
if isinstance(e, Path):
build_targets.append(JsonKeymapBuildTarget(e))
elif isinstance(e, dict):
- keyboard_keymap_targets.append((e['keyboard'], e['keymap']))
-
+ f = e['env'] if 'env' in e else None
+ keyboard_keymap_targets.append((e['keyboard'], e['keymap'], f))
if len(keyboard_keymap_targets) > 0:
build_targets.extend(search_keymap_targets(keyboard_keymap_targets))
diff --git a/lib/python/qmk/cli/userspace/list.py b/lib/python/qmk/cli/userspace/list.py
index 8689c80a76..9f83a14a2a 100644
--- a/lib/python/qmk/cli/userspace/list.py
+++ b/lib/python/qmk/cli/userspace/list.py
@@ -1,4 +1,4 @@
-# Copyright 2023 Nick Brassel (@tzarc)
+# Copyright 2023-2024 Nick Brassel (@tzarc)
# SPDX-License-Identifier: GPL-2.0-or-later
from pathlib import Path
from dotty_dict import Dotty
@@ -13,6 +13,10 @@ from qmk.search import search_keymap_targets
from qmk.util import maybe_exit_config
+def _extra_arg_setter(target, extra_args):
+ target.extra_args = extra_args
+
+
@cli.argument('-e', '--expand', arg_only=True, action='store_true', help="Expands any use of `all` for either keyboard or keymap.")
@cli.subcommand('Lists the build targets specified in userspace `qmk.json`.')
def userspace_list(cli):
@@ -26,11 +30,15 @@ def userspace_list(cli):
if cli.args.expand:
build_targets = []
+ keyboard_keymap_targets = []
for e in userspace.build_targets:
if isinstance(e, Path):
build_targets.append(e)
elif isinstance(e, dict) or isinstance(e, Dotty):
- build_targets.extend(search_keymap_targets([(e['keyboard'], e['keymap'])]))
+ f = e['env'] if 'env' in e else None
+ keyboard_keymap_targets.append((e['keyboard'], e['keymap'], f))
+ if len(keyboard_keymap_targets) > 0:
+ build_targets.extend(search_keymap_targets(keyboard_keymap_targets))
else:
build_targets = userspace.build_targets
@@ -43,12 +51,19 @@ def userspace_list(cli):
# keyboard/keymap dict from userspace
keyboard = e['keyboard']
keymap = e['keymap']
+ extra_args = e.get('env')
elif isinstance(e, BuildTarget):
# BuildTarget from search_keymap_targets()
keyboard = e.keyboard
keymap = e.keymap
+ extra_args = e.extra_args
+
+ extra_args_str = ''
+ if extra_args is not None and len(extra_args) > 0:
+ extra_args_str = ', '.join([f'{{fg_cyan}}{k}={v}{{fg_reset}}' for k, v in extra_args.items()])
+ extra_args_str = f' ({{fg_cyan}}{extra_args_str}{{fg_reset}})'
if is_all_keyboards(keyboard) or is_keymap_target(keyboard_folder(keyboard), keymap):
- cli.log.info(f'Keyboard: {{fg_cyan}}{keyboard}{{fg_reset}}, keymap: {{fg_cyan}}{keymap}{{fg_reset}}')
+ cli.log.info(f'Keyboard: {{fg_cyan}}{keyboard}{{fg_reset}}, keymap: {{fg_cyan}}{keymap}{{fg_reset}}{extra_args_str}')
else:
- cli.log.warn(f'Keyboard: {{fg_cyan}}{keyboard}{{fg_reset}}, keymap: {{fg_cyan}}{keymap}{{fg_reset}} -- not found!')
+ cli.log.warn(f'Keyboard: {{fg_cyan}}{keyboard}{{fg_reset}}, keymap: {{fg_cyan}}{keymap}{{fg_reset}}{extra_args_str} -- not found!')
diff --git a/lib/python/qmk/cli/userspace/path.py b/lib/python/qmk/cli/userspace/path.py
index df4648e8c7..d0c1b544fb 100755
--- a/lib/python/qmk/cli/userspace/path.py
+++ b/lib/python/qmk/cli/userspace/path.py
@@ -4,5 +4,5 @@ from qmk.constants import QMK_USERSPACE
@cli.subcommand('Detected path to QMK Userspace.', hidden=True)
def userspace_path(cli):
- print(QMK_USERSPACE)
+ print(QMK_USERSPACE or '')
return
diff --git a/lib/python/qmk/cli/userspace/remove.py b/lib/python/qmk/cli/userspace/remove.py
index c7d180bfd1..b2da08a98e 100644
--- a/lib/python/qmk/cli/userspace/remove.py
+++ b/lib/python/qmk/cli/userspace/remove.py
@@ -1,8 +1,9 @@
-# Copyright 2023 Nick Brassel (@tzarc)
+# Copyright 2023-2024 Nick Brassel (@tzarc)
# SPDX-License-Identifier: GPL-2.0-or-later
from pathlib import Path
from milc import cli
+from qmk.commands import parse_env_vars
from qmk.constants import QMK_USERSPACE, HAS_QMK_USERSPACE
from qmk.keyboard import keyboard_completer, keyboard_folder_or_all
from qmk.keymap import keymap_completer
@@ -12,12 +13,15 @@ from qmk.userspace import UserspaceDefs
@cli.argument('builds', nargs='*', arg_only=True, help="List of builds in form <keyboard>:<keymap>, or path to a keymap JSON file.")
@cli.argument('-kb', '--keyboard', type=keyboard_folder_or_all, completer=keyboard_completer, help='The keyboard to build a firmware for. Ignored when a configurator export is supplied.')
@cli.argument('-km', '--keymap', completer=keymap_completer, help='The keymap to build a firmware for. Ignored when a configurator export is supplied.')
+@cli.argument('-e', '--env', arg_only=True, action='append', default=[], help="Extra variables to set during build. May be passed multiple times.")
@cli.subcommand('Removes a build target from userspace `qmk.json`.')
def userspace_remove(cli):
if not HAS_QMK_USERSPACE:
cli.log.error('Could not determine QMK userspace location. Please run `qmk doctor` or `qmk userspace-doctor` to diagnose.')
return False
+ build_env = None if len(cli.args.env) == 0 else parse_env_vars(cli.args.env)
+
userspace = UserspaceDefs(QMK_USERSPACE / 'qmk.json')
if len(cli.args.builds) > 0:
@@ -29,9 +33,9 @@ def userspace_remove(cli):
for e in make_like_targets:
s = e.split(':')
- userspace.remove_target(keyboard=s[0], keymap=s[1])
+ userspace.remove_target(keyboard=s[0], keymap=s[1], build_env=build_env)
else:
- userspace.remove_target(keyboard=cli.args.keyboard, keymap=cli.args.keymap)
+ userspace.remove_target(keyboard=cli.args.keyboard, keymap=cli.args.keymap, build_env=build_env)
return userspace.save()