diff options
-rw-r--r-- | .github/labeler.yml | 1 | ||||
-rw-r--r-- | .github/workflows/cli.yml | 1 | ||||
-rw-r--r-- | Makefile | 6 | ||||
-rwxr-xr-x | bin/qmk | 58 | ||||
-rw-r--r-- | build_keyboard.mk | 19 | ||||
-rw-r--r-- | docs/cli_commands.md | 48 | ||||
-rw-r--r-- | docs/contributing.md | 2 | ||||
-rw-r--r-- | docs/de/cli.md | 19 | ||||
-rw-r--r-- | docs/fr-fr/cli.md | 19 | ||||
-rw-r--r-- | docs/hardware_keyboard_guidelines.md | 28 | ||||
-rw-r--r-- | keyboards/dztech/dz65rgb/keymaps/jumper149/readme.md | 4 | ||||
-rw-r--r-- | lib/python/qmk/cli/__init__.py | 1 | ||||
-rw-r--r-- | lib/python/qmk/cli/console.py | 303 | ||||
-rw-r--r-- | lib/python/qmk/cli/doctor/check.py | 1 | ||||
-rwxr-xr-x | lib/python/qmk/cli/format/python.py | 6 | ||||
-rw-r--r-- | lib/python/qmk/cli/lint.py | 145 | ||||
-rw-r--r-- | lib/python/qmk/cli/pytest.py | 2 | ||||
-rw-r--r-- | lib/python/qmk/commands.py | 2 | ||||
-rw-r--r-- | lib/python/qmk/tests/test_cli_commands.py | 2 | ||||
-rw-r--r-- | shell.nix | 2 |
20 files changed, 159 insertions, 510 deletions
diff --git a/.github/labeler.yml b/.github/labeler.yml index 53921f7f95..41b2475f67 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -22,7 +22,6 @@ keymap: via: - keyboards/**/keymaps/via/* cli: - - bin/qmk - requirements.txt - lib/python/**/* python: diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index 7a8dc8540f..3bf9741ac7 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -8,7 +8,6 @@ on: pull_request: paths: - 'lib/python/**' - - 'bin/qmk' - 'requirements.txt' - '.github/workflows/cli.yml' @@ -30,11 +30,7 @@ endif endif # Determine which qmk cli to use -ifeq (,$(shell which qmk)) - QMK_BIN = bin/qmk -else - QMK_BIN = qmk -endif +QMK_BIN := qmk # avoid 'Entering|Leaving directory' messages MAKEFLAGS += --no-print-directory diff --git a/bin/qmk b/bin/qmk deleted file mode 100755 index 617f992826..0000000000 --- a/bin/qmk +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python3 -"""CLI wrapper for running QMK commands. -""" -import os -import sys -from pathlib import Path - -# Add the QMK python libs to our path -script_dir = Path(os.path.realpath(__file__)).parent -qmk_dir = script_dir.parent -python_lib_dir = Path(qmk_dir / 'lib' / 'python').resolve() -sys.path.append(str(python_lib_dir)) - -# Setup the CLI -import milc # noqa - -milc.EMOJI_LOGLEVELS['INFO'] = '{fg_blue}Ψ{style_reset_all}' - - -@milc.cli.entrypoint('QMK Helper Script') -def qmk_main(cli): - """The function that gets run when no subcommand is provided. - """ - cli.print_help() - - -def main(): - """Setup our environment and then call the CLI entrypoint. - """ - # Change to the root of our checkout - os.environ['ORIG_CWD'] = os.getcwd() - os.environ['DEPRECATED_BIN_QMK'] = '1' - os.chdir(qmk_dir) - - print('Warning: The bin/qmk script is being deprecated. Please install the QMK CLI: python3 -m pip install qmk', file=sys.stderr) - - # Import the subcommands - import milc.subcommand.config # noqa - import qmk.cli # noqa - - # Execute - return_code = milc.cli() - - if return_code is False: - exit(1) - - elif return_code is not True and isinstance(return_code, int): - if return_code < 0 or return_code > 255: - milc.cli.log.error('Invalid return_code: %d', return_code) - exit(255) - - exit(return_code) - - exit(0) - - -if __name__ == '__main__': - main() diff --git a/build_keyboard.mk b/build_keyboard.mk index 37fa6852f8..420643c3e7 100644 --- a/build_keyboard.mk +++ b/build_keyboard.mk @@ -115,6 +115,7 @@ include $(INFO_RULES_MK) # Check for keymap.json first, so we can regenerate keymap.c include build_json.mk +# Pull in keymap level rules.mk ifeq ("$(wildcard $(KEYMAP_PATH))", "") # Look through the possible keymap folders until we find a matching keymap.c ifneq ("$(wildcard $(MAIN_KEYMAP_PATH_5)/keymap.c)","") @@ -345,6 +346,7 @@ ifeq ("$(USER_NAME)","") endif USER_PATH := users/$(USER_NAME) +# Pull in user level rules.mk -include $(USER_PATH)/rules.mk ifneq ("$(wildcard $(USER_PATH)/config.h)","") CONFIG_H += $(USER_PATH)/config.h @@ -356,6 +358,23 @@ endif # Disable features that a keyboard doesn't support -include disable_features.mk +# Pull in post_rules.mk files from all our subfolders +ifneq ("$(wildcard $(KEYBOARD_PATH_1)/post_rules.mk)","") + include $(KEYBOARD_PATH_1)/post_rules.mk +endif +ifneq ("$(wildcard $(KEYBOARD_PATH_2)/post_rules.mk)","") + include $(KEYBOARD_PATH_2)/post_rules.mk +endif +ifneq ("$(wildcard $(KEYBOARD_PATH_3)/post_rules.mk)","") + include $(KEYBOARD_PATH_3)/post_rules.mk +endif +ifneq ("$(wildcard $(KEYBOARD_PATH_4)/post_rules.mk)","") + include $(KEYBOARD_PATH_4)/post_rules.mk +endif +ifneq ("$(wildcard $(KEYBOARD_PATH_5)/post_rules.mk)","") + include $(KEYBOARD_PATH_5)/post_rules.mk +endif + ifneq ("$(wildcard $(KEYMAP_PATH)/config.h)","") CONFIG_H += $(KEYMAP_PATH)/config.h endif diff --git a/docs/cli_commands.md b/docs/cli_commands.md index 8fa7ad41dc..06568afb46 100644 --- a/docs/cli_commands.md +++ b/docs/cli_commands.md @@ -118,54 +118,6 @@ This command lets you configure the behavior of QMK. For the full `qmk config` d qmk config [-ro] [config_token1] [config_token2] [...] [config_tokenN] ``` -## `qmk console` - -This command lets you connect to keyboard consoles to get debugging messages. It only works if your keyboard firmware has been compiled with `CONSOLE_ENABLE=yes`. - -**Usage**: - -``` -qmk console [-d <pid>:<vid>[:<index>]] [-l] [-n] [-t] [-w <seconds>] -``` - -**Examples**: - -Connect to all available keyboards and show their console messages: - -``` -qmk console -``` - -List all devices: - -``` -qmk console -l -``` - -Show only messages from clueboard/66/rev3 keyboards: - -``` -qmk console -d C1ED:2370 -``` - -Show only messages from the second clueboard/66/rev3: - -``` -qmk console -d C1ED:2370:2 -``` - -Show timestamps and VID:PID instead of names: - -``` -qmk console -n -t -``` - -Disable bootloader messages: - -``` -qmk console --no-bootloaders -``` - ## `qmk doctor` This command examines your environment and alerts you to potential build or flash problems. It can fix many of them if you want it to. diff --git a/docs/contributing.md b/docs/contributing.md index 1d68d22d9f..eb033d167f 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -105,7 +105,7 @@ enum my_keycodes { Before opening a pull request, you can preview your changes if you have set up the development environment by running this command from the `qmk_firmware/` folder: - ./bin/qmk docs + qmk docs or if you only have Python 3 installed: diff --git a/docs/de/cli.md b/docs/de/cli.md index 7dc02d505b..259aeecf75 100644 --- a/docs/de/cli.md +++ b/docs/de/cli.md @@ -51,25 +51,6 @@ Wir suchen nach Freiwilligen, die ein `qmk`-Package für weitere Betriebssysteme * Installiere mit einem [virtualenv](https://virtualenv.pypa.io/en/latest/). * Weise den User an, die Umgebungs-Variable `QMK_HOME` zu setzen, um die Firmware-Quelle anders einzustellen als `~/qmk_firmware`. -# Lokale CLI - -Wenn Du die globale CLI nicht verwenden möchtest, beinhaltet `qmk_firmware` auch eine lokale CLI. Du kannst sie hier finden: `qmk_firmware/bin/qmk`. Du kannst den `qmk`-Befehl aus irgendeinem Datei-Verzeichnis ausführen und es wird immer auf dieser Kopie von `qmk_firmware` arbeiten. - -**Beispiel**: - -``` -$ ~/qmk_firmware/bin/qmk hello -Ψ Hello, World! -``` - -## Einschränkungen der lokalen CLI - -Hier ein Vergleich mit der globalen CLI: - -* Die lokale CLI unterstützt kein `qmk setup` oder `qmk clone`. -* Die lokale CLI arbeitet immer innerhalb der selben `qmk_firmware`-Verzeichnisstruktur, auch wenn Du mehrere Repositories geklont hast. -* Die lokale CLI läuft nicht in einer virtualenv. Daher ist es möglich, dass Abhängigkeiten (dependencies) miteinander in Konflikt kommen/stehen. - # CLI-Befehle ## `qmk compile` diff --git a/docs/fr-fr/cli.md b/docs/fr-fr/cli.md index bfa060f2ad..917a9315bc 100644 --- a/docs/fr-fr/cli.md +++ b/docs/fr-fr/cli.md @@ -48,25 +48,6 @@ Nous recherchons des gens pour créer et maintenir un paquet `qmk` pour plus de * Installez en utilisant un virtualenv * Expliquez à l'utilisateur de définir la variable d'environnement `QMK_Home` pour "check out" les sources du firmware à un autre endroit que `~/qmk_firmware`. -# CLI locale - -Si vous ne voulez pas utiliser la CLI globale, il y a une CLI locale empaquetée avec `qmk_firmware`. Vous pouvez le trouver dans `qmk_firmware/bin/qmk`. Vous pouvez lancer la commande `qmk` depuis n'importe quel répertoire et elle fonctionnera toujours sur cette copie de `qmk_firmware`. - -**Exemple**: - -``` -$ ~/qmk_firmware/bin/qmk hello -Ψ Hello, World! -``` - -## Limitations de la CLI locale - -Il y a quelques limitations à la CLI locale comparé à la globale: - -* La CLI locale ne supporte pas `qmk setup` ou `qmk clone` -* La CLI locale n'opère pas sur le même arbre `qmk_firmware`, même si vous avez plusieurs dépôts clonés. -* La CLI locale ne s'exécute pas dans un virtualenv, donc il y a des risques que des dépendances seront en conflit - # Les commandes CLI ## `qmk compile` diff --git a/docs/hardware_keyboard_guidelines.md b/docs/hardware_keyboard_guidelines.md index 7630b44e0c..17be7ee6aa 100644 --- a/docs/hardware_keyboard_guidelines.md +++ b/docs/hardware_keyboard_guidelines.md @@ -144,10 +144,38 @@ The `rules.mk` file can also be placed in a sub-folder, and its reading order is * `keyboards/top_folder/sub_1/sub_2/sub_3/sub_4/rules.mk` * `keyboards/top_folder/keymaps/a_keymap/rules.mk` * `users/a_user_folder/rules.mk` + * `keyboards/top_folder/sub_1/sub_2/sub_3/sub_4/post_rules.mk` + * `keyboards/top_folder/sub_1/sub_2/sub_3/post_rules.mk` + * `keyboards/top_folder/sub_1/sub_2/post_rules.mk` + * `keyboards/top_folder/sub_1/post_rules.mk` +* `keyboards/top_folder/post_rules.mk` * `common_features.mk` Many of the settings written in the `rules.mk` file are interpreted by `common_features.mk`, which sets the necessary source files and compiler options. +The `post_rules.mk` file can interpret `features` of a keyboard-level before `common_features.mk`. For example, when your designed keyboard has the option to implement backlighting or underglow using rgblight.c, writing the following in the `post_rules.mk` makes it easier for the user to configure the `rules.mk`. + +* `keyboards/top_folder/keymaps/a_keymap/rules.mk` + ```makefile + # Please set the following according to the selection of the hardware implementation option. + RGBLED_OPTION_TYPE = backlight ## none, backlight or underglow + ``` +* `keyboards/top_folder/post_rules.mk` + ```makefile + ifeq ($(filter $(strip $(RGBLED_OPTION_TYPE))x, nonex backlightx underglowx x),) + $(error unknown RGBLED_OPTION_TYPE value "$(RGBLED_OPTION_TYPE)") + endif + + ifeq ($(strip $(RGBLED_OPTION_TYPE)),backlight) + RGBLIGHT_ENABLE = yes + OPT_DEFS += -DRGBLED_NUM=30 + endif + ifeq ($(strip $(RGBLED_OPTION_TYPE)),underglow) + RGBLIGHT_ENABLE = yes + OPT_DEFS += -DRGBLED_NUM=6 + endif + ``` + ?> See `build_keyboard.mk` and `common_features.mk` for more details. ### `<keyboard_name.c>` diff --git a/keyboards/dztech/dz65rgb/keymaps/jumper149/readme.md b/keyboards/dztech/dz65rgb/keymaps/jumper149/readme.md index d872587317..9de86be2d1 100644 --- a/keyboards/dztech/dz65rgb/keymaps/jumper149/readme.md +++ b/keyboards/dztech/dz65rgb/keymaps/jumper149/readme.md @@ -3,13 +3,13 @@ Run commands in the root directory of this repository. ``` -./bin/qmk compile && sudo dfu-programmer atmega32u4 erase && sudo dfu-programmer atmega32u4 flash ./dztech_dz65rgb_v2_jumper149.hex && sudo dfu-programmer atmega32u4 reset +qmk compile && sudo dfu-programmer atmega32u4 erase && sudo dfu-programmer atmega32u4 flash ./dztech_dz65rgb_v2_jumper149.hex && sudo dfu-programmer atmega32u4 reset ``` ## build ``` -./bin/qmk compile +qmk compile ``` ## flash diff --git a/lib/python/qmk/cli/__init__.py b/lib/python/qmk/cli/__init__.py index f45e33240c..292dcbe812 100644 --- a/lib/python/qmk/cli/__init__.py +++ b/lib/python/qmk/cli/__init__.py @@ -35,7 +35,6 @@ subcommands = [ 'qmk.cli.chibios.confmigrate', 'qmk.cli.clean', 'qmk.cli.compile', - 'qmk.cli.console', 'qmk.cli.docs', 'qmk.cli.doctor', 'qmk.cli.fileformat', diff --git a/lib/python/qmk/cli/console.py b/lib/python/qmk/cli/console.py deleted file mode 100644 index 3c508160e3..0000000000 --- a/lib/python/qmk/cli/console.py +++ /dev/null @@ -1,303 +0,0 @@ -"""Acquire debugging information from usb hid devices - -cli implementation of https://www.pjrc.com/teensy/hid_listen.html -""" -from pathlib import Path -from threading import Thread -from time import sleep, strftime - -import hid -import usb.core - -from milc import cli - -LOG_COLOR = { - 'next': 0, - 'colors': [ - '{fg_blue}', - '{fg_cyan}', - '{fg_green}', - '{fg_magenta}', - '{fg_red}', - '{fg_yellow}', - ], -} - -KNOWN_BOOTLOADERS = { - # VID , PID - ('03EB', '2FEF'): 'atmel-dfu: ATmega16U2', - ('03EB', '2FF0'): 'atmel-dfu: ATmega32U2', - ('03EB', '2FF3'): 'atmel-dfu: ATmega16U4', - ('03EB', '2FF4'): 'atmel-dfu: ATmega32U4', - ('03EB', '2FF9'): 'atmel-dfu: AT90USB64', - ('03EB', '2FFA'): 'atmel-dfu: AT90USB162', - ('03EB', '2FFB'): 'atmel-dfu: AT90USB128', - ('03EB', '6124'): 'Microchip SAM-BA', - ('0483', 'DF11'): 'stm32-dfu: STM32 BOOTLOADER', - ('16C0', '05DC'): 'USBasp: USBaspLoader', - ('16C0', '05DF'): 'bootloadHID: HIDBoot', - ('16C0', '0478'): 'halfkay: Teensy Halfkay', - ('1B4F', '9203'): 'caterina: Pro Micro 3.3V', - ('1B4F', '9205'): 'caterina: Pro Micro 5V', - ('1B4F', '9207'): 'caterina: LilyPadUSB', - ('1C11', 'B007'): 'kiibohd: Kiibohd DFU Bootloader', - ('1EAF', '0003'): 'stm32duino: Maple 003', - ('1FFB', '0101'): 'caterina: Polou A-Star 32U4 Bootloader', - ('2341', '0036'): 'caterina: Arduino Leonardo', - ('2341', '0037'): 'caterina: Arduino Micro', - ('239A', '000C'): 'caterina: Adafruit Feather 32U4', - ('239A', '000D'): 'caterina: Adafruit ItsyBitsy 32U4 3v', - ('239A', '000E'): 'caterina: Adafruit ItsyBitsy 32U4 5v', - ('2A03', '0036'): 'caterina: Arduino Leonardo', - ('2A03', '0037'): 'caterina: Arduino Micro', - ('314B', '0106'): 'apm32-dfu: APM32 DFU ISP Mode', - ('03EB', '2067'): 'qmk-hid: HID Bootloader', - ('03EB', '2045'): 'lufa-ms: LUFA Mass Storage Bootloader' -} - - -class MonitorDevice(object): - def __init__(self, hid_device, numeric): - self.hid_device = hid_device - self.numeric = numeric - self.device = hid.Device(path=hid_device['path']) - self.current_line = '' - - cli.log.info('Console Connected: %(color)s%(manufacturer_string)s %(product_string)s{style_reset_all} (%(color)s%(vendor_id)04X:%(product_id)04X:%(index)d{style_reset_all})', hid_device) - - def read(self, size, encoding='ascii', timeout=1): - """Read size bytes from the device. - """ - return self.device.read(size, timeout).decode(encoding) - - def read_line(self): - """Read from the device's console until we get a \n. - """ - while '\n' not in self.current_line: - self.current_line += self.read(32).replace('\x00', '') - - lines = self.current_line.split('\n', 1) - self.current_line = lines[1] - - return lines[0] - - def run_forever(self): - while True: - try: - message = {**self.hid_device, 'text': self.read_line()} - identifier = (int2hex(message['vendor_id']), int2hex(message['product_id'])) if self.numeric else (message['manufacturer_string'], message['product_string']) - message['identifier'] = ':'.join(identifier) - message['ts'] = '{style_dim}{fg_green}%s{style_reset_all} ' % (strftime(cli.config.general.datetime_fmt),) if cli.args.timestamp else '' - - cli.echo('%(ts)s%(color)s%(identifier)s:%(index)d{style_reset_all}: %(text)s' % message) - - except hid.HIDException: - break - - -class FindDevices(object): - def __init__(self, vid, pid, index, numeric): - self.vid = vid - self.pid = pid - self.index = index - self.numeric = numeric - - def run_forever(self): - """Process messages from our queue in a loop. - """ - live_devices = {} - live_bootloaders = {} - - while True: - try: - for device in list(live_devices): - if not live_devices[device]['thread'].is_alive(): - cli.log.info('Console Disconnected: %(color)s%(manufacturer_string)s %(product_string)s{style_reset_all} (%(color)s%(vendor_id)04X:%(product_id)04X:%(index)d{style_reset_all})', live_devices[device]) - del live_devices[device] - - for device in self.find_devices(): - if device['path'] not in live_devices: - device['color'] = LOG_COLOR['colors'][LOG_COLOR['next']] - LOG_COLOR['next'] = (LOG_COLOR['next'] + 1) % len(LOG_COLOR['colors']) - live_devices[device['path']] = device - - try: - monitor = MonitorDevice(device, self.numeric) - device['thread'] = Thread(target=monitor.run_forever, daemon=True) - - device['thread'].start() - except Exception as e: - device['e'] = e - device['e_name'] = e.__class__.__name__ - cli.log.error("Could not connect to %(color)s%(manufacturer_string)s %(product_string)s{style_reset_all} (%(color)s:%(vendor_id)04X:%(product_id)04X:%(index)d): %(e_name)s: %(e)s", device) - if cli.config.general.verbose: - cli.log.exception(e) - del live_devices[device['path']] - - if cli.args.bootloaders: - for device in self.find_bootloaders(): - if device.address in live_bootloaders: - live_bootloaders[device.address]._qmk_found = True - else: - name = KNOWN_BOOTLOADERS[(int2hex(device.idVendor), int2hex(device.idProduct))] - cli.log.info('Bootloader Connected: {style_bright}{fg_magenta}%s', name) - device._qmk_found = True - live_bootloaders[device.address] = device - - for device in list(live_bootloaders): - if live_bootloaders[device]._qmk_found: - live_bootloaders[device]._qmk_found = False - else: - name = KNOWN_BOOTLOADERS[(int2hex(live_bootloaders[device].idVendor), int2hex(live_bootloaders[device].idProduct))] - cli.log.info('Bootloader Disconnected: {style_bright}{fg_magenta}%s', name) - del live_bootloaders[device] - - sleep(.1) - - except KeyboardInterrupt: - break - - def is_bootloader(self, hid_device): - """Returns true if the device in question matches a known bootloader vid/pid. - """ - return (int2hex(hid_device.idVendor), int2hex(hid_device.idProduct)) in KNOWN_BOOTLOADERS - - def is_console_hid(self, hid_device): - """Returns true when the usage page indicates it's a teensy-style console. - """ - return hid_device['usage_page'] == 0xFF31 and hid_device['usage'] == 0x0074 - - def is_filtered_device(self, hid_device): - """Returns True if the device should be included in the list of available consoles. - """ - return int2hex(hid_device['vendor_id']) == self.vid and int2hex(hid_device['product_id']) == self.pid - - def find_devices_by_report(self, hid_devices): - """Returns a list of available teensy-style consoles by doing a brute-force search. - - Some versions of linux don't report usage and usage_page. In that case we fallback to reading the report (possibly inaccurately) ourselves. - """ - devices = [] - - for device in hid_devices: - path = device['path'].decode('utf-8') - - if path.startswith('/dev/hidraw'): - number = path[11:] - report = Path(f'/sys/class/hidraw/hidraw{number}/device/report_descriptor') - - if report.exists(): - rp = report.read_bytes() - - if rp[1] == 0x31 and rp[3] == 0x09: - devices.append(device) - - return devices - - def find_bootloaders(self): - """Returns a list of available bootloader devices. - """ - return list(filter(self.is_bootloader, usb.core.find(find_all=True))) - - def find_devices(self): - """Returns a list of available teensy-style consoles. - """ - hid_devices = hid.enumerate() - devices = list(filter(self.is_console_hid, hid_devices)) - - if not devices: - devices = self.find_devices_by_report(hid_devices) - - if self.vid and self.pid: - devices = list(filter(self.is_filtered_device, devices)) - - # Add index numbers - device_index = {} - for device in devices: - id = ':'.join((int2hex(device['vendor_id']), int2hex(device['product_id']))) - - if id not in device_index: - device_index[id] = 0 - - device_index[id] += 1 - device['index'] = device_index[id] - - return devices - - -def int2hex(number): - """Returns a string representation of the number as hex. - """ - return "%04X" % number - - -def list_devices(device_finder): - """Show the user a nicely formatted list of devices. - """ - devices = device_finder.find_devices() - - if devices: - cli.log.info('Available devices:') - for dev in devices: - color = LOG_COLOR['colors'][LOG_COLOR['next']] - LOG_COLOR['next'] = (LOG_COLOR['next'] + 1) % len(LOG_COLOR['colors']) - cli.log.info("\t%s%s:%s:%d{style_reset_all}\t%s %s", color, int2hex(dev['vendor_id']), int2hex(dev['product_id']), dev['index'], dev['manufacturer_string'], dev['product_string']) - - if cli.args.bootloaders: - bootloaders = device_finder.find_bootloaders() - - if bootloaders: - cli.log.info('Available Bootloaders:') - - for dev in bootloaders: - cli.log.info("\t%s:%s\t%s", int2hex(dev.idVendor), int2hex(dev.idProduct), KNOWN_BOOTLOADERS[(int2hex(dev.idVendor), int2hex(dev.idProduct))]) - - -@cli.argument('--bootloaders', arg_only=True, default=True, action='store_boolean', help='displaying bootloaders.') -@cli.argument('-d', '--device', help='Device to select - uses format <pid>:<vid>[:<index>].') -@cli.argument('-l', '--list', arg_only=True, action='store_true', help='List available hid_listen devices.') -@cli.argument('-n', '--numeric', arg_only=True, action='store_true', help='Show VID/PID instead of names.') -@cli.argument('-t', '--timestamp', arg_only=True, action='store_true', help='Print the timestamp for received messages as well.') -@cli.argument('-w', '--wait', type=int, default=1, help="How many seconds to wait between checks (Default: 1)") -@cli.subcommand('Acquire debugging information from usb hid devices.', hidden=False if cli.config.user.developer else True) -def console(cli): - """Acquire debugging information from usb hid devices - """ - vid = None - pid = None - index = 1 - - if cli.config.console.device: - device = cli.config.console.device.split(':') - - if len(device) == 2: - vid, pid = device - - elif len(device) == 3: - vid, pid, index = device - - if not index.isdigit(): - cli.log.error('Device index must be a number! Got "%s" instead.', index) - exit(1) - - index = int(index) - - if index < 1: - cli.log.error('Device index must be greater than 0! Got %s', index) - exit(1) - - else: - cli.log.error('Invalid format for device, expected "<pid>:<vid>[:<index>]" but got "%s".', cli.config.console.device) - cli.print_help() - exit(1) - - vid = vid.upper() - pid = pid.upper() - - device_finder = FindDevices(vid, pid, index, cli.args.numeric) - - if cli.args.list: - return list_devices(device_finder) - - print('Looking for devices...', flush=True) - device_finder.run_forever() diff --git a/lib/python/qmk/cli/doctor/check.py b/lib/python/qmk/cli/doctor/check.py index 0807f41518..2d691b64b0 100644 --- a/lib/python/qmk/cli/doctor/check.py +++ b/lib/python/qmk/cli/doctor/check.py @@ -26,7 +26,6 @@ ESSENTIAL_BINARIES = { 'arm-none-eabi-gcc': { 'version_arg': '-dumpversion' }, - 'bin/qmk': {}, } diff --git a/lib/python/qmk/cli/format/python.py b/lib/python/qmk/cli/format/python.py index 00612f97ec..b32a726401 100755 --- a/lib/python/qmk/cli/format/python.py +++ b/lib/python/qmk/cli/format/python.py @@ -11,15 +11,15 @@ def format_python(cli): """Format python code according to QMK's style. """ edit = '--diff' if cli.args.dry_run else '--in-place' - yapf_cmd = ['yapf', '-vv', '--recursive', edit, 'bin/qmk', 'lib/python'] + yapf_cmd = ['yapf', '-vv', '--recursive', edit, 'lib/python'] try: cli.run(yapf_cmd, check=True, capture_output=False, stdin=DEVNULL) - cli.log.info('Python code in `bin/qmk` and `lib/python` is correctly formatted.') + cli.log.info('Python code in `lib/python` is correctly formatted.') return True except CalledProcessError: if cli.args.dry_run: - cli.log.error('Python code in `bin/qmk` and `lib/python` incorrectly formatted!') + cli.log.error('Python code in `lib/python` is incorrectly formatted!') else: cli.log.error('Error formatting python code!') diff --git a/lib/python/qmk/cli/lint.py b/lib/python/qmk/cli/lint.py index 02b31fbc41..96593ed69b 100644 --- a/lib/python/qmk/cli/lint.py +++ b/lib/python/qmk/cli/lint.py @@ -1,72 +1,129 @@ """Command to look over a keyboard/keymap and check for common mistakes. """ +from pathlib import Path + from milc import cli from qmk.decorators import automagic_keyboard, automagic_keymap from qmk.info import info_json -from qmk.keyboard import find_readme, keyboard_completer +from qmk.keyboard import keyboard_completer, list_keyboards from qmk.keymap import locate_keymap from qmk.path import is_keyboard, keyboard -@cli.argument('--strict', action='store_true', help='Treat warnings as errors.') -@cli.argument('-kb', '--keyboard', completer=keyboard_completer, help='The keyboard to check.') -@cli.argument('-km', '--keymap', help='The keymap to check.') +def keymap_check(kb, km): + """Perform the keymap level checks. + """ + ok = True + keymap_path = locate_keymap(kb, km) + + if not keymap_path: + ok = False + cli.log.error("%s: Can't find %s keymap.", kb, km) + + return ok + + +def rules_mk_assignment_only(keyboard_path): + """Check the keyboard-level rules.mk to ensure it only has assignments. + """ + current_path = Path() + errors = [] + + for path_part in keyboard_path.parts: + current_path = current_path / path_part + rules_mk = current_path / 'rules.mk' + + if rules_mk.exists(): + continuation = None + + for i, line in enumerate(rules_mk.open()): + line = line.strip() + + if '#' in line: + line = line[:line.index('#')] + + if continuation: + line = continuation + line + continuation = None + + if line: + if line[-1] == '\\': + continuation = line[:-1] + continue + + if line and '=' not in line: + errors.append(f'Non-assignment code on line +{i} {rules_mk}: {line}') + + return errors + + +@cli.argument('--strict', action='store_true', help='Treat warnings as errors') +@cli.argument('-kb', '--keyboard', completer=keyboard_completer, help='Comma separated list of keyboards to check') +@cli.argument('-km', '--keymap', help='The keymap to check') +@cli.argument('--all-kb', action='store_true', arg_only=True, help='Check all keyboards') @cli.subcommand('Check keyboard and keymap for common mistakes.') @automagic_keyboard @automagic_keymap def lint(cli): """Check keyboard and keymap for common mistakes. """ - if not cli.config.lint.keyboard: - cli.log.error('Missing required argument: --keyboard') - cli.print_help() - return False + failed = [] - if not is_keyboard(cli.config.lint.keyboard): - cli.log.error('No such keyboard: %s', cli.config.lint.keyboard) - return False + # Determine our keyboard list + if cli.args.all_kb: + if cli.args.keyboard: + cli.log.warning('Both --all-kb and --keyboard passed, --all-kb takes presidence.') - # Gather data about the keyboard. - ok = True - keyboard_path = keyboard(cli.config.lint.keyboard) - keyboard_info = info_json(cli.config.lint.keyboard) - readme_path = find_readme(cli.config.lint.keyboard) - missing_readme_path = keyboard_path / 'readme.md' + keyboard_list = list_keyboards() + elif not cli.config.lint.keyboard: + cli.log.error('Missing required arguments: --keyboard or --all-kb') + cli.print_help() + return False + else: + keyboard_list = cli.config.lint.keyboard.split(',') - # Check for errors in the info.json - if keyboard_info['parse_errors']: - ok = False - cli.log.error('Errors found when generating info.json.') + # Lint each keyboard + for kb in keyboard_list: + if not is_keyboard(kb): + cli.log.error('No such keyboard: %s', kb) + continue - if cli.config.lint.strict and keyboard_info['parse_warnings']: - ok = False - cli.log.error('Warnings found when generating info.json (Strict mode enabled.)') + # Gather data about the keyboard. + ok = True + keyboard_path = keyboard(kb) + keyboard_info = info_json(kb) - # Check for a readme.md and warn if it doesn't exist - if not readme_path: - ok = False - cli.log.error('Missing %s', missing_readme_path) + # Check for errors in the info.json + if keyboard_info['parse_errors']: + ok = False + cli.log.error('%s: Errors found when generating info.json.', kb) - # Keymap specific checks - if cli.config.lint.keymap: - keymap_path = locate_keymap(cli.config.lint.keyboard, cli.config.lint.keymap) + if cli.config.lint.strict and keyboard_info['parse_warnings']: + ok = False + cli.log.error('%s: Warnings found when generating info.json (Strict mode enabled.)', kb) - if not keymap_path: + # Check the rules.mk file(s) + rules_mk_assignment_errors = rules_mk_assignment_only(keyboard_path) + if rules_mk_assignment_errors: ok = False - |