diff options
Diffstat (limited to 'lib/python')
-rw-r--r-- | lib/python/qmk/cli/list/__init__.py | 1 | ||||
-rw-r--r-- | lib/python/qmk/cli/list/keymaps.py | 22 | ||||
-rw-r--r-- | lib/python/qmk/keymap.py | 38 | ||||
-rw-r--r-- | lib/python/qmk/makefile.py | 83 | ||||
-rw-r--r-- | lib/python/qmk/tests/test_cli_commands.py | 12 |
5 files changed, 156 insertions, 0 deletions
diff --git a/lib/python/qmk/cli/list/__init__.py b/lib/python/qmk/cli/list/__init__.py index c36ba69548..d83cd20b5b 100644 --- a/lib/python/qmk/cli/list/__init__.py +++ b/lib/python/qmk/cli/list/__init__.py @@ -1 +1,2 @@ from . import keyboards +from . import keymaps diff --git a/lib/python/qmk/cli/list/keymaps.py b/lib/python/qmk/cli/list/keymaps.py new file mode 100644 index 0000000000..d199d29bc3 --- /dev/null +++ b/lib/python/qmk/cli/list/keymaps.py @@ -0,0 +1,22 @@ +"""List the keymaps for a specific keyboard +""" +from milc import cli +import qmk.keymap +from qmk.errors import NoSuchKeyboardError + + +@cli.argument("-kb", "--keyboard", help="Specify keyboard name. Example: 1upkeyboards/1up60hse") +@cli.subcommand("List the keymaps for a specific keyboard") +def list_keymaps(cli): + """List the keymaps for a specific keyboard + """ + try: + for name in qmk.keymap.list_keymaps(cli.config.list_keymaps.keyboard): + # We echo instead of cli.log.info to allow easier piping of this output + cli.echo('%s', name) + except NoSuchKeyboardError as e: + cli.echo("{fg_red}%s: %s", cli.config.list_keymaps.keyboard, e.message) + except (FileNotFoundError, PermissionError) as e: + cli.echo("{fg_red}%s: %s", cli.config.list_keymaps.keyboard, e) + except TypeError: + cli.echo("{fg_red}Something went wrong. Did you specify a keyboard?") diff --git a/lib/python/qmk/keymap.py b/lib/python/qmk/keymap.py index f4a2893f38..15a91a276b 100644 --- a/lib/python/qmk/keymap.py +++ b/lib/python/qmk/keymap.py @@ -1,8 +1,10 @@ """Functions that help you work with QMK keymaps. """ import os +from pathlib import Path import qmk.path +import qmk.makefile # The `keymap.c` template to use when a keyboard doesn't have its own DEFAULT_KEYMAP_C = """#include QMK_KEYBOARD_H @@ -94,3 +96,39 @@ def write(keyboard, keymap, layout, layers): keymap_fd.write(keymap_c) return keymap_file + + +def list_keymaps(keyboard_name): + """ List the available keymaps for a keyboard. + + Args: + keyboard_name: the keyboards full name with vendor and revision if necessary, example: clueboard/66/rev3 + + Returns: + a set with the names of the available keymaps + """ + # parse all the rules.mk files for the keyboard + rules_mk = qmk.makefile.get_rules_mk(keyboard_name) + names = set() + + if rules_mk: + # qmk_firmware/keyboards + keyboards_dir = Path.cwd() / "keyboards" + # path to the keyboard's directory + kb_path = keyboards_dir / keyboard_name + # walk up the directory tree until keyboards_dir + # and collect all directories' name with keymap.c file in it + while kb_path != keyboards_dir: + keymaps_dir = kb_path / "keymaps" + if keymaps_dir.exists(): + names = names.union([keymap for keymap in os.listdir(str(keymaps_dir)) if (keymaps_dir / keymap / "keymap.c").is_file()]) + kb_path = kb_path.parent + + # if community layouts are supported, get them + if "LAYOUTS" in rules_mk: + for layout in rules_mk["LAYOUTS"].split(): + cl_path = Path.cwd() / "layouts" / "community" / layout + if cl_path.exists(): + names = names.union([keymap for keymap in os.listdir(str(cl_path)) if (cl_path / keymap / "keymap.c").is_file()]) + + return sorted(names) diff --git a/lib/python/qmk/makefile.py b/lib/python/qmk/makefile.py new file mode 100644 index 0000000000..8645056d2d --- /dev/null +++ b/lib/python/qmk/makefile.py @@ -0,0 +1,83 @@ +""" Functions for working with Makefiles +""" +from pathlib import Path + +from qmk.errors import NoSuchKeyboardError + + +def parse_rules_mk_file(file, rules_mk=None): + """Turn a rules.mk file into a dictionary. + + Args: + file: path to the rules.mk file + rules_mk: already parsed rules.mk the new file should be merged with + + Returns: + a dictionary with the file's content + """ + if not rules_mk: + rules_mk = {} + + file = Path(file) + if file.exists(): + rules_mk_lines = file.read_text().split("\n") + + for line in rules_mk_lines: + # Filter out comments + if line.strip().startswith("#"): + continue + + # Strip in-line comments + if '#' in line: + line = line[:line.index('#')].strip() + + if '=' in line: + # Append + if '+=' in line: + key, value = line.split('+=', 1) + if key.strip() not in rules_mk: + rules_mk[key.strip()] = value.strip() + else: + rules_mk[key.strip()] += ' ' + value.strip() + # Set if absent + elif "?=" in line: + key, value = line.split('?=', 1) + if key.strip() not in rules_mk: + rules_mk[key.strip()] = value.strip() + else: + if ":=" in line: + line.replace(":", "") + key, value = line.split('=', 1) + rules_mk[key.strip()] = value.strip() + + return rules_mk + + +def get_rules_mk(keyboard): + """ Get a rules.mk for a keyboard + + Args: + keyboard: name of the keyboard + + Raises: + NoSuchKeyboardError: when the keyboard does not exists + + Returns: + a dictionary with the content of the rules.mk file + """ + # Start with qmk_firmware/keyboards + kb_path = Path.cwd() / "keyboards" + # walk down the directory tree + # and collect all rules.mk files + kb_dir = kb_path / keyboard + if kb_dir.exists(): + rules_mk = dict() + for directory in Path(keyboard).parts: + kb_path = kb_path / directory + rules_mk_path = kb_path / "rules.mk" + if rules_mk_path.exists(): + rules_mk = parse_rules_mk_file(rules_mk_path, rules_mk) + else: + raise NoSuchKeyboardError("The requested keyboard and/or revision does not exist.") + + return rules_mk diff --git a/lib/python/qmk/tests/test_cli_commands.py b/lib/python/qmk/tests/test_cli_commands.py index f1a92d9a31..bb77952faf 100644 --- a/lib/python/qmk/tests/test_cli_commands.py +++ b/lib/python/qmk/tests/test_cli_commands.py @@ -54,3 +54,15 @@ def test_list_keyboards(): # check to see if a known keyboard is returned # this will fail if handwired/onekey/pytest is removed assert 'handwired/onekey/pytest' in result.stdout + + +def test_list_keymaps(): + result = check_subcommand("list-keymaps", "-kb", "handwired/onekey/pytest") + assert result.returncode == 0 + assert "default" and "test" in result.stdout + + +def test_list_keymaps_no_keyboard_found(): + result = check_subcommand("list-keymaps", "-kb", "asdfghjkl") + assert result.returncode == 0 + assert "does not exist" in result.stdout |