~ruther/qmk_firmware

e77188458f136da3e25ce066e80b21d38f6e8cdc — Cody Bender 5 years ago 774cbbf
Add QMK Compile Context Sensitivity (#6884)

* Add context sensitive compile, without config check

* Initial full working state. Plan to refactor

* Refactor loop for simplicity, add comments

* Update docs/cli.md with qmk compile examples

* Simplify path for keyboard derivation

* Update path to use path.join instead of concat

* Refactor keyboard path, the skully way

* Add in keymap folder support

* Add /layouts compile support

* Update docs/cli.md with empty compile in layouts

* Add comments to compile.py

* Update docs for clarity, and fix compile error typo

* Fix config option compile

* Fix layout compile and failure mode

* Add rules.mk check

* Fix variable names for global config

* Add in_layout priority

* Remove default fallback in favor of throw, update docs

* Add keymap folder context

* Fix formatting

* Add os import

* Convert to create_make_command

* Fix Travis lint errors

* Remove blank line with whitespace

* Add blank lines for readability

* Remove unnecessary config logic

* Update Docs to add flash

Co-Authored-By: skullydazed <skullydazed@users.noreply.github.com>

* Shift config precedence to MILC

Co-authored-by: skullydazed <skullydazed@users.noreply.github.com>
2 files changed, 120 insertions(+), 4 deletions(-)

M docs/cli.md
M lib/python/qmk/cli/compile.py
M docs/cli.md => docs/cli.md +48 -1
@@ 81,7 81,7 @@ qmk cformat [file1] [file2] [...] [fileN]

## `qmk compile`

This command allows you to compile firmware from any directory. You can compile JSON exports from <https://config.qmk.fm> or compile keymaps in the repo.
This command allows you to compile firmware from any directory. You can compile JSON exports from <https://config.qmk.fm>, compile keymaps in the repo, or compile the keyboard in the current working directory.

**Usage for Configurator Exports**:



@@ 95,6 95,53 @@ qmk compile <configuratorExport.json>
qmk compile -kb <keyboard_name> -km <keymap_name>
```

**Usage in Keyboard Directory**:  

Must be in keyboard directory with a default keymap, or in keymap directory for keyboard, or supply one with `--keymap <keymap_name>`
```
qmk compile
```

**Example**:
```
$ qmk config compile.keymap=default
$ cd ~/qmk_firmware/keyboards/planck/rev6
$ qmk compile
Ψ Compiling keymap with make planck/rev6:default
...
```
or with optional keymap argument

```
$ cd ~/qmk_firmware/keyboards/clueboard/66/rev4 
$ qmk compile -km 66_iso
Ψ Compiling keymap with make clueboard/66/rev4:66_iso
...
```
or in keymap directory

```
$ cd ~/qmk_firmware/keyboards/gh60/satan/keymaps/colemak
$ qmk compile
Ψ Compiling keymap with make make gh60/satan:colemak
...
```

**Usage in Layout Directory**:  

Must be under `qmk_firmware/layouts/`, and in a keymap folder.
```
qmk compile -kb <keyboard_name>
```

**Example**:
```
$ cd ~/qmk_firmware/layouts/community/60_ansi/mechmerlin-ansi
$ qmk compile -kb dz60
Ψ Compiling keymap with make dz60:mechmerlin-ansi
...
```

## `qmk flash`

This command is similar to `qmk compile`, but can also target a bootloader. The bootloader is optional, and is set to `:flash` by default.

M lib/python/qmk/cli/compile.py => lib/python/qmk/cli/compile.py +72 -3
@@ 3,6 3,7 @@
You can compile a keymap already in the repo or using a QMK Configurator export.
"""
import subprocess
import os
from argparse import FileType

from milc import cli


@@ 28,6 29,46 @@ def compile(cli):
    If --keyboard and --keymap are provided this command will build a firmware based on that.

    """
    # Set CWD as directory command was issued from
    cwd = os.environ['ORIG_CWD']
    qmk_path = os.getcwd()
    current_folder = os.path.basename(cwd)
    # Initialize boolean to check for being in a keyboard directory and initialize keyboard string
    in_keyboard = False
    in_layout = False
    keyboard = ""
    keymap = ""
    user_keymap = ""
    user_keyboard = ""

    # Set path for '/keyboards/' directory
    keyboards_path = os.path.join(qmk_path, "keyboards")
    layouts_path = os.path.join(qmk_path, "layouts")

    # If below 'keyboards' and not in 'keyboards' or 'keymaps', get current keyboard name
    if cwd.startswith(keyboards_path):
        if current_folder != "keyboards" and current_folder != "keymaps":
            if os.path.basename(os.path.abspath(os.path.join(cwd, ".."))) == "keymaps":
                # If in a keymap folder, set relative path, get everything before /keymaps, and the keymap name
                relative_path = cwd[len(keyboards_path):][1:]
                keyboard = str(relative_path).split("/keymaps", 1)[0]
                keymap = str(relative_path.rsplit("/", 1)[-1])
            else:
                keyboard = str(cwd[len(keyboards_path):])[1:]

            in_keyboard = True

    # If in layouts dir
    if cwd.startswith(layouts_path):
        if current_folder != "layouts":
            in_layout = True

    # If user keyboard/keymap or compile keyboard/keymap are supplied, assign those
    if cli.config.compile.keyboard:
        user_keyboard = cli.config.compile.keyboard
    if cli.config.compile.keymap and not in_layout:
        user_keymap = cli.config.compile.keymap

    if cli.args.filename:
        # Parse the configurator json
        user_keymap = parse_configurator_json(cli.args.filename)


@@ 41,12 82,40 @@ def compile(cli):

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

    elif cli.config.compile.keyboard and cli.config.compile.keymap:
    elif user_keyboard and user_keymap:
        # Generate the make command for a specific keyboard/keymap.
        command = create_make_command(cli.config.compile.keyboard, cli.config.compile.keymap)
        command = create_make_command(user_keyboard, user_keymap)

    elif in_keyboard:
        keyboard = user_keyboard if user_keyboard else keyboard
        keymap = user_keymap if user_keymap else keymap

        if not os.path.exists(os.path.join(keyboards_path, keyboard, "rules.mk")):
            cli.log.error('This directory does not contain a rules.mk file. Change directory or supply --keyboard with optional --keymap')
            return False

        # Get path for keyboard directory
        keymap_path = qmk.path.keymap(keyboard)

        # Check for global keymap config first
        if keymap:
            command = create_make_command(keyboard, keymap)

        else:
            # If no default keymap exists and none provided
            cli.log.error('This directory does not contain a keymap. Set one with `qmk config` or supply `--keymap` ')
            return False

    elif in_layout:
        if user_keyboard:
            keymap = current_folder
            command = create_make_command(user_keyboard, keymap)
        else:
            cli.log.error('You must supply a keyboard to compile a layout keymap. Set one with `qmk config` or supply `--keyboard` ')
            return False

    else:
        cli.log.error('You must supply a configurator export or both `--keyboard` and `--keymap`.')
        cli.log.error('You must supply a configurator export, both `--keyboard` and `--keymap`, or be in a directory for a keyboard or keymap.')
        return False

    cli.log.info('Compiling keymap with {fg_cyan}%s\n\n', ' '.join(command))