Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework of qmk compile #13357

Closed
wants to merge 14 commits into from
9 changes: 8 additions & 1 deletion lib/python/qmk/c_parse.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"""Functions for working with config.h files.
"""
from pathlib import Path
import re
from functools import lru_cache
from pathlib import Path

from milc import cli

Expand All @@ -12,18 +13,21 @@
multi_comment_regex = re.compile(r'/\*(.|\n)*?\*/', re.MULTILINE)


@lru_cache(maxsize=0)
def strip_line_comment(string):
"""Removes comments from a single line string.
"""
return single_comment_regex.sub('', string)


@lru_cache(maxsize=0)
def strip_multiline_comment(string):
"""Removes comments from a single line string.
"""
return multi_comment_regex.sub('', string)


@lru_cache(maxsize=0)
def c_source_files(dir_names):
"""Returns a list of all *.c, *.h, and *.cpp files for a given list of directories

Expand All @@ -38,6 +42,7 @@ def c_source_files(dir_names):
return files


@lru_cache(maxsize=0)
def find_layouts(file):
"""Returns list of parsed LAYOUT preprocessor macros found in the supplied include file.
"""
Expand Down Expand Up @@ -144,6 +149,7 @@ def _default_key(label=None):
return new_key


@lru_cache(maxsize=0)
def _parse_layout_macro(layout_macro):
"""Split the LAYOUT macro into its constituent parts
"""
Expand All @@ -154,6 +160,7 @@ def _parse_layout_macro(layout_macro):
return macro_name, layout, matrix


@lru_cache(maxsize=0)
def _parse_matrix_locations(matrix, file, macro_name):
"""Parse raw matrix data into a dictionary keyed by the LAYOUT identifier.
"""
Expand Down
6 changes: 4 additions & 2 deletions lib/python/qmk/cli/clean.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"""
from subprocess import DEVNULL

from qmk.commands import create_make_target
from qmk.commands import _find_make
from milc import cli


Expand All @@ -11,4 +11,6 @@
def clean(cli):
"""Runs `make clean` (or `make distclean` if --all is passed)
"""
cli.run(create_make_target('distclean' if cli.args.all else 'clean'), capture_output=False, stdin=DEVNULL)
make_cmd = [_find_make(), 'distclean' if cli.args.all else 'clean']

cli.run(make_cmd, capture_output=False, stdin=DEVNULL)
71 changes: 28 additions & 43 deletions lib/python/qmk/cli/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,24 @@

You can compile a keymap already in the repo or using a QMK Configurator export.
"""
from subprocess import DEVNULL

from argcomplete.completers import FilesCompleter
from milc import cli

import qmk.path
from qmk.decorators import automagic_keyboard, automagic_keymap
from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json
from qmk.keyboard import keyboard_completer, keyboard_folder
from qmk.commands import do_compile
from qmk.keyboard import keyboard_completer, is_keyboard_target
from qmk.keymap import keymap_completer
from qmk.metadata import true_values, false_values


@cli.argument('filename', nargs='?', arg_only=True, type=qmk.path.FileType('r'), completer=FilesCompleter('.json'), help='The configurator export to compile')
@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='The keyboard to build a firmware for. Ignored when a configurator export is supplied.')
@cli.argument('-t', '--target', help="The make target to run. By default it compiles the keyboard only.")
@cli.argument('-kb', '--keyboard', type=is_keyboard_target, 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('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.")
@cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs; 0 means unlimited.")
@cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs to run.")
@cli.argument('-f', '--filter', arg_only=True, action='append', default=[], help="Filter your list against info.json.")
@cli.argument('-e', '--env', arg_only=True, action='append', default=[], help="Set a variable to be passed to make. May be passed multiple times.")
@cli.argument('-c', '--clean', arg_only=True, action='store_true', help="Remove object files before compiling.")
@cli.subcommand('Compile a QMK Firmware.')
Expand All @@ -31,47 +32,31 @@ def compile(cli):

If a keyboard and keymap are provided this command will build a firmware based on that.
"""
if cli.args.clean and not cli.args.filename and not cli.args.dry_run:
command = create_make_command(cli.config.compile.keyboard, cli.config.compile.keymap, 'clean')
cli.run(command, capture_output=False, stdin=DEVNULL)
# If -f has been specified without a keyboard target, assume -kb all
keyboard = cli.config.compile.keyboard or ''

# Build the environment vars
envs = {}
for env in cli.args.env:
if '=' in env:
key, value = env.split('=', 1)
envs[key] = value
else:
cli.log.warning('Invalid environment variable: %s', env)
if cli.args.filter and not cli.args.keyboard:
cli.log.debug('--filter supplied without --keyboard, assuming --keyboard all.')
keyboard = 'all'

# Determine the compile command
command = None
if cli.args.filename and cli.args.filter:
cli.log.warning('Ignoring --filter because a keymap.json was provided.')

if cli.args.filename:
# If a configurator JSON was provided generate a keymap and compile it
user_keymap = parse_configurator_json(cli.args.filename)
command = compile_configurator_json(user_keymap, parallel=cli.config.compile.parallel, **envs)
filters = {}

else:
if cli.config.compile.keyboard and cli.config.compile.keymap:
# Generate the make command for a specific keyboard/keymap.
command = create_make_command(cli.config.compile.keyboard, cli.config.compile.keymap, parallel=cli.config.compile.parallel, **envs)
for filter in cli.args.filter:
if '=' in filter:
key, value = filter.split('=', 1)

elif not cli.config.compile.keyboard:
cli.log.error('Could not determine keyboard!')
elif not cli.config.compile.keymap:
cli.log.error('Could not determine keymap!')
if value in true_values:
value = True
elif value in false_values:
value = False
elif value.isdigit():
value = int(value)
elif '.' in value and value.replace('.').isdigit():
value = float(value)

# Compile the firmware, if we're able to
if command:
cli.log.info('Compiling keymap with {fg_cyan}%s', ' '.join(command))
if not cli.args.dry_run:
cli.echo('\n')
# FIXME(skullydazed/anyone): Remove text=False once milc 1.0.11 has had enough time to be installed everywhere.
compile = cli.run(command, capture_output=False, text=False)
return compile.returncode
filters[key] = value

else:
cli.log.error('You must supply a configurator export, both `--keyboard` and `--keymap`, or be in a directory for a keyboard or keymap.')
cli.echo('usage: qmk compile [-h] [-b] [-kb KEYBOARD] [-km KEYMAP] [filename]')
return False
return do_compile(keyboard, cli.config.compile.keymap, cli.config.compile.parallel, cli.config.compile.target, filters)
57 changes: 5 additions & 52 deletions lib/python/qmk/cli/flash.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@
You can compile a keymap already in the repo or using a QMK Configurator export.
A bootloader must be specified.
"""
from subprocess import DEVNULL

from argcomplete.completers import FilesCompleter
from milc import cli

import qmk.path
from qmk.decorators import automagic_keyboard, automagic_keymap
from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json
from qmk.keyboard import keyboard_completer, keyboard_folder
from qmk.commands import do_compile
from qmk.keyboard import keyboard_completer, is_keyboard_target


def print_bootloader_help():
Expand All @@ -36,7 +34,7 @@ def print_bootloader_help():
@cli.argument('-b', '--bootloaders', action='store_true', help='List the available bootloaders.')
@cli.argument('-bl', '--bootloader', default='flash', help='The flash command, corresponding to qmk\'s make options of bootloaders.')
@cli.argument('-km', '--keymap', help='The keymap to build a firmware for. Use this if you dont have a configurator file. Ignored when a configurator file is supplied.')
@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='The keyboard to build a firmware for. Use this if you dont have a configurator file. Ignored when a configurator file is supplied.')
@cli.argument('-kb', '--keyboard', type=is_keyboard_target, completer=keyboard_completer, help='The keyboard to build a firmware for. Use this if you dont have a configurator file. Ignored when a configurator file is supplied.')
@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.")
@cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs; 0 means unlimited.")
@cli.argument('-e', '--env', arg_only=True, action='append', default=[], help="Set a variable to be passed to make. May be passed multiple times.")
Expand All @@ -54,55 +52,10 @@ def flash(cli):

If bootloader is omitted the make system will use the configured bootloader for that keyboard.
"""
if cli.args.clean and not cli.args.filename and not cli.args.dry_run:
command = create_make_command(cli.config.flash.keyboard, cli.config.flash.keymap, 'clean')
cli.run(command, capture_output=False, stdin=DEVNULL)

# Build the environment vars
envs = {}
for env in cli.args.env:
if '=' in env:
key, value = env.split('=', 1)
envs[key] = value
else:
cli.log.warning('Invalid environment variable: %s', env)

# Determine the compile command
command = ''

if cli.args.bootloaders:
# Provide usage and list bootloaders
cli.echo('usage: qmk flash [-h] [-b] [-n] [-kb KEYBOARD] [-km KEYMAP] [-bl BOOTLOADER] [filename]')
cli.print_usage()
print_bootloader_help()
return False

if cli.args.filename:
# Handle compiling a configurator JSON
user_keymap = parse_configurator_json(cli.args.filename)
keymap_path = qmk.path.keymap(user_keymap['keyboard'])
command = compile_configurator_json(user_keymap, cli.args.bootloader, parallel=cli.config.flash.parallel, **envs)

cli.log.info('Wrote keymap to {fg_cyan}%s/%s/keymap.c', keymap_path, user_keymap['keymap'])

else:
if cli.config.flash.keyboard and cli.config.flash.keymap:
# Generate the make command for a specific keyboard/keymap.
command = create_make_command(cli.config.flash.keyboard, cli.config.flash.keymap, cli.args.bootloader, parallel=cli.config.flash.parallel, **envs)

elif not cli.config.flash.keyboard:
cli.log.error('Could not determine keyboard!')
elif not cli.config.flash.keymap:
cli.log.error('Could not determine keymap!')

# Compile the firmware, if we're able to
if command:
cli.log.info('Compiling keymap with {fg_cyan}%s', ' '.join(command))
if not cli.args.dry_run:
cli.echo('\n')
compile = cli.run(command, capture_output=False, stdin=DEVNULL)
return compile.returncode

else:
cli.log.error('You must supply a configurator export, both `--keyboard` and `--keymap`, or be in a directory for a keyboard or keymap.')
cli.echo('usage: qmk flash [-h] [-b] [-n] [-kb KEYBOARD] [-km KEYMAP] [-bl BOOTLOADER] [filename]')
return False
return do_compile(cli.config.flash.keyboard, cli.config.flash.keymap, cli.config.flash.parallel, cli.config.flash.bootloader)
Loading