Beispiel #1
0
def generate_config_h(cli):
    """Generates the info_config.h file.
    """
    # Determine our keyboard(s)
    if not cli.config.generate_config_h.keyboard:
        cli.log.error('Missing paramater: --keyboard')
        cli.subcommands['info'].print_help()
        return False

    if not is_keyboard(cli.config.generate_config_h.keyboard):
        cli.log.error('Invalid keyboard: "%s"', cli.config.generate_config_h.keyboard)
        return False

    # Build the info.json file
    kb_info_json = info_json(cli.config.generate_config_h.keyboard)

    # Build the info_config.h file.
    config_h_lines = ['/* This file was generated by `qmk generate-config-h`. Do not edit or copy.' ' */', '', '#pragma once']

    if 'debounce' in kb_info_json:
        config_h_lines.append(debounce(kb_info_json['debounce']))

    if 'diode_direction' in kb_info_json:
        config_h_lines.append(diode_direction(kb_info_json['diode_direction']))

    if 'indicators' in kb_info_json:
        config_h_lines.append(indicators(kb_info_json['indicators']))

    if 'keyboard_name' in kb_info_json:
        config_h_lines.append(keyboard_name(kb_info_json['keyboard_name']))

    if 'layout_aliases' in kb_info_json:
        config_h_lines.append(layout_aliases(kb_info_json['layout_aliases']))

    if 'manufacturer' in kb_info_json:
        config_h_lines.append(manufacturer(kb_info_json['manufacturer']))

    if 'rgblight' in kb_info_json:
        config_h_lines.append(rgblight(kb_info_json['rgblight']))

    if 'matrix_pins' in kb_info_json:
        config_h_lines.append(matrix_pins(kb_info_json['matrix_pins']))

    if 'usb' in kb_info_json:
        config_h_lines.append(usb_properties(kb_info_json['usb']))

    # Show the results
    config_h = '\n'.join(config_h_lines)

    if cli.args.output:
        cli.args.output.parent.mkdir(parents=True, exist_ok=True)
        if cli.args.output.exists():
            cli.args.output.replace(cli.args.output.name + '.bak')
        cli.args.output.write_text(config_h)

        if not cli.args.quiet:
            cli.log.info('Wrote info_config.h to %s.', cli.args.output)

    else:
        print(config_h)
Beispiel #2
0
    def wrapper(*args, **kwargs):
        # Check to make sure their copy of MILC supports config_source
        if not hasattr(cli, 'config_source'):
            cli.log.error(
                "This subcommand requires a newer version of the QMK CLI. Please upgrade using `pip3 install --upgrade qmk` or your package manager."
            )
            exit(1)

        # Ensure that `--keyboard` was not passed and CWD is under `qmk_firmware/keyboards`
        if cli.config_source[
                cli._entrypoint.__name__]['keyboard'] != 'argument':
            relative_cwd = under_qmk_firmware()

            if relative_cwd and len(
                    relative_cwd.parts
            ) > 1 and relative_cwd.parts[0] == 'keyboards':
                # Attempt to extract the keyboard name from the current directory
                current_path = Path('/'.join(relative_cwd.parts[1:]))

                if 'keymaps' in current_path.parts:
                    # Strip current_path of anything after `keymaps`
                    keymap_index = len(
                        current_path.parts) - current_path.parts.index(
                            'keymaps') - 1
                    current_path = current_path.parents[keymap_index]

                if is_keyboard(current_path):
                    cli.config[cli._entrypoint.__name__]['keyboard'] = str(
                        current_path)
                    cli.config_source[cli._entrypoint.__name__][
                        'keyboard'] = 'keyboard_directory'

        return func(*args, **kwargs)
Beispiel #3
0
def info(cli):
    """Compile an info.json for a particular keyboard and pretty-print it.
    """
    # Determine our keyboard(s)
    if not cli.config.info.keyboard:
        cli.log.error('Missing parameter: --keyboard')
        cli.subcommands['info'].print_help()
        return False

    if not is_keyboard(cli.config.info.keyboard):
        cli.log.error('Invalid keyboard: "%s"', cli.config.info.keyboard)
        return False

    # Build the info.json file
    kb_info_json = info_json(cli.config.info.keyboard)

    # Output in the requested format
    if cli.args.format == 'json':
        print(json.dumps(kb_info_json, cls=InfoJSONEncoder))
    elif cli.args.format == 'text':
        print_text_output(kb_info_json)
    elif cli.args.format == 'friendly':
        print_friendly_output(kb_info_json)
    else:
        cli.log.error('Unknown format: %s', cli.args.format)
        return False
Beispiel #4
0
def generate_dfu_header(cli):
    """Generates the Keyboard.h file.
    """
    # Determine our keyboard(s)
    if not cli.config.generate_dfu_header.keyboard:
        cli.log.error('Missing parameter: --keyboard')
        cli.subcommands['info'].print_help()
        return False

    if not is_keyboard(cli.config.generate_dfu_header.keyboard):
        cli.log.error('Invalid keyboard: "%s"', cli.config.generate_dfu_header.keyboard)
        return False

    # Build the Keyboard.h file.
    kb_info_json = dotty(info_json(cli.config.generate_dfu_header.keyboard))

    keyboard_h_lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once']
    keyboard_h_lines.append(f'#define MANUFACTURER {kb_info_json["manufacturer"]}')
    keyboard_h_lines.append(f'#define PRODUCT {kb_info_json["keyboard_name"]} Bootloader')

    # Optional
    if 'qmk_lufa_bootloader.esc_output' in kb_info_json:
        keyboard_h_lines.append(f'#define QMK_ESC_OUTPUT {kb_info_json["qmk_lufa_bootloader.esc_output"]}')
    if 'qmk_lufa_bootloader.esc_input' in kb_info_json:
        keyboard_h_lines.append(f'#define QMK_ESC_INPUT {kb_info_json["qmk_lufa_bootloader.esc_input"]}')
    if 'qmk_lufa_bootloader.led' in kb_info_json:
        keyboard_h_lines.append(f'#define QMK_LED {kb_info_json["qmk_lufa_bootloader.led"]}')
    if 'qmk_lufa_bootloader.speaker' in kb_info_json:
        keyboard_h_lines.append(f'#define QMK_SPEAKER {kb_info_json["qmk_lufa_bootloader.speaker"]}')

    # Show the results
    dump_lines(cli.args.output, keyboard_h_lines, cli.args.quiet)
Beispiel #5
0
def lint(cli):
    """Check keyboard and keymap for common mistakes.
    """
    failed = []

    # 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 precedence.'
            )

        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(',')

    # Lint each keyboard
    for kb in keyboard_list:
        if not is_keyboard(kb):
            cli.log.error('No such keyboard: %s', kb)
            continue

        # Determine keymaps to also check
        if cli.args.all_km:
            keymaps = list_keymaps(kb)
        elif cli.config.lint.keymap:
            keymaps = {cli.config.lint.keymap}
        else:
            keymaps = _list_defaultish_keymaps(kb)
            # Ensure that at least a 'default' keymap always exists
            keymaps.add('default')

        ok = True

        # keyboard level checks
        if not keyboard_check(kb):
            ok = False

        # Keymap specific checks
        for keymap in keymaps:
            if not keymap_check(kb, keymap):
                ok = False

        # Report status
        if not ok:
            failed.append(kb)

    # Check and report the overall status
    if failed:
        cli.log.error('Lint check failed for: %s', ', '.join(failed))
        return False

    cli.log.info('Lint check passed!')
    return True
Beispiel #6
0
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

    if not is_keyboard(cli.config.lint.keyboard):
        cli.log.error('No such keyboard: %s', cli.config.lint.keyboard)
        return False

    # 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'

    # Check for errors in the info.json
    if keyboard_info['parse_errors']:
        ok = False
        cli.log.error('Errors found when generating info.json.')

    if cli.config.lint.strict and keyboard_info['parse_warnings']:
        ok = False
        cli.log.error(
            'Warnings found when generating info.json (Strict mode enabled.)')

    # 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)

    # Keymap specific checks
    if cli.config.lint.keymap:
        keymap_path = locate_keymap(cli.config.lint.keyboard,
                                    cli.config.lint.keymap)

        if not keymap_path:
            ok = False
            cli.log.error("Can't find %s keymap for %s keyboard.",
                          cli.config.lint.keymap, cli.config.lint.keyboard)
        else:
            keymap_readme = keymap_path.parent / 'readme.md'
            if not keymap_readme.exists():
                cli.log.warning('Missing %s', keymap_readme)

                if cli.config.lint.strict:
                    ok = False

    # Check and report the overall status
    if ok:
        cli.log.info('Lint check passed!')
        return True

    cli.log.error('Lint check failed!')
    return False
def generate_dfu_header(cli):
    """Generates the Keyboard.h file.
    """
    # Determine our keyboard(s)
    if not cli.config.generate_dfu_header.keyboard:
        cli.log.error('Missing parameter: --keyboard')
        cli.subcommands['info'].print_help()
        return False

    if not is_keyboard(cli.config.generate_dfu_header.keyboard):
        cli.log.error('Invalid keyboard: "%s"',
                      cli.config.generate_dfu_header.keyboard)
        return False

    # Build the Keyboard.h file.
    kb_info_json = dotty(info_json(cli.config.generate_dfu_header.keyboard))

    keyboard_h_lines = [
        '/* This file was generated by `qmk generate-dfu-header`. Do not edit or copy.',
        ' */', '', '#pragma once'
    ]
    keyboard_h_lines.append(
        f'#define MANUFACTURER {kb_info_json["manufacturer"]}')
    keyboard_h_lines.append(
        f'#define PRODUCT {kb_info_json["keyboard_name"]} Bootloader')

    # Optional
    if 'qmk_lufa_bootloader.esc_output' in kb_info_json:
        keyboard_h_lines.append(
            f'#define QMK_ESC_OUTPUT {kb_info_json["qmk_lufa_bootloader.esc_output"]}'
        )
    if 'qmk_lufa_bootloader.esc_input' in kb_info_json:
        keyboard_h_lines.append(
            f'#define QMK_ESC_INPUT {kb_info_json["qmk_lufa_bootloader.esc_input"]}'
        )
    if 'qmk_lufa_bootloader.led' in kb_info_json:
        keyboard_h_lines.append(
            f'#define QMK_LED {kb_info_json["qmk_lufa_bootloader.led"]}')
    if 'qmk_lufa_bootloader.speaker' in kb_info_json:
        keyboard_h_lines.append(
            f'#define QMK_SPEAKER {kb_info_json["qmk_lufa_bootloader.speaker"]}'
        )

    # Show the results
    keyboard_h = '\n'.join(keyboard_h_lines)

    if cli.args.output:
        cli.args.output.parent.mkdir(parents=True, exist_ok=True)
        if cli.args.output.exists():
            cli.args.output.replace(cli.args.output.parent /
                                    (cli.args.output.name + '.bak'))
        cli.args.output.write_text(keyboard_h)

        if not cli.args.quiet:
            cli.log.info('Wrote Keyboard.h to %s.', cli.args.output)

    else:
        print(keyboard_h)
Beispiel #8
0
def list_keymaps(cli):
    """List the keymaps for a specific keyboard
    """
    if not is_keyboard(cli.config.list_keymaps.keyboard):
        cli.log.error('Keyboard %s does not exist!', cli.config.list_keymaps.keyboard)
        exit(1)

    for name in qmk.keymap.list_keymaps(cli.config.list_keymaps.keyboard):
        print(name)
Beispiel #9
0
def generate_rules_mk(cli):
    """Generates a rules.mk file from info.json.
    """
    if not cli.config.generate_rules_mk.keyboard:
        cli.log.error('Missing parameter: --keyboard')
        cli.subcommands['info'].print_help()
        return False

    if not is_keyboard(cli.config.generate_rules_mk.keyboard):
        cli.log.error('Invalid keyboard: "%s"',
                      cli.config.generate_rules_mk.keyboard)
        return False

    kb_info_json = dotty(info_json(cli.config.generate_rules_mk.keyboard))
    info_rules_map = _json_load(Path('data/mappings/info_rules.json'))
    rules_mk_lines = [
        '# This file was generated by `qmk generate-rules-mk`. Do not edit or copy.',
        ''
    ]

    # Iterate through the info_rules map to generate basic rules
    for rules_key, info_dict in info_rules_map.items():
        new_entry = process_mapping_rule(kb_info_json, rules_key, info_dict)

        if new_entry:
            rules_mk_lines.append(new_entry)

    # Iterate through features to enable/disable them
    if 'features' in kb_info_json:
        for feature, enabled in kb_info_json['features'].items():
            if feature == 'bootmagic_lite' and enabled:
                rules_mk_lines.append('BOOTMAGIC_ENABLE ?= lite')
            else:
                feature = feature.upper()
                enabled = 'yes' if enabled else 'no'
                rules_mk_lines.append(f'{feature}_ENABLE ?= {enabled}')

    # Show the results
    rules_mk = '\n'.join(rules_mk_lines) + '\n'

    if cli.args.output:
        cli.args.output.parent.mkdir(parents=True, exist_ok=True)
        if cli.args.output.exists():
            cli.args.output.replace(cli.args.output.parent /
                                    (cli.args.output.name + '.bak'))
        cli.args.output.write_text(rules_mk)

        if cli.args.quiet:
            if cli.args.escape:
                print(cli.args.output.as_posix().replace(' ', '\\ '))
            else:
                print(cli.args.output)
        else:
            cli.log.info('Wrote rules.mk to %s.', cli.args.output)

    else:
        print(rules_mk)
Beispiel #10
0
def info(cli):
    """Compile an info.json for a particular keyboard and pretty-print it.
    """
    # Determine our keyboard(s)
    if not cli.config.info.keyboard:
        cli.log.error('Missing parameter: --keyboard')
        cli.subcommands['info'].print_help()
        return False

    if not is_keyboard(cli.config.info.keyboard):
        cli.log.error('Invalid keyboard: "%s"', cli.config.info.keyboard)
        return False

    if bool(cli.args.rules_mk):
        print_parsed_rules_mk(cli.config.info.keyboard)
        return False

    # default keymap stored in config file should be ignored
    if cli.config_source.info.keymap == 'config_file':
        cli.config_source.info.keymap = None

    # Build the info.json file
    if cli.config.info.keymap:
        kb_info_json = keymap_json(cli.config.info.keyboard,
                                   cli.config.info.keymap)
    else:
        kb_info_json = info_json(cli.config.info.keyboard)

    # Output in the requested format
    if cli.args.format == 'json':
        print(json.dumps(kb_info_json, cls=InfoJSONEncoder))
        return True
    elif cli.args.format == 'text':
        print_dotted_output(kb_info_json)
        title_caps = False
    elif cli.args.format == 'friendly':
        print_friendly_output(kb_info_json)
        title_caps = True
    else:
        cli.log.error('Unknown format: %s', cli.args.format)
        return False

    # Output requested extras
    if cli.config.info.layouts:
        show_layouts(kb_info_json, title_caps)

    if cli.config.info.matrix:
        show_matrix(kb_info_json, title_caps)

    if cli.config.info.keymap:
        show_keymap(kb_info_json, title_caps)
Beispiel #11
0
def find_keyboard_from_dir():
    """Returns a keyboard name based on the user's current directory.
    """
    relative_cwd = under_qmk_firmware()

    if relative_cwd and len(
            relative_cwd.parts) > 1 and relative_cwd.parts[0] == 'keyboards':
        # Attempt to extract the keyboard name from the current directory
        current_path = Path('/'.join(relative_cwd.parts[1:]))

        if 'keymaps' in current_path.parts:
            # Strip current_path of anything after `keymaps`
            keymap_index = len(
                current_path.parts) - current_path.parts.index('keymaps') - 1
            current_path = current_path.parents[keymap_index]

        if is_keyboard(current_path):
            return str(current_path)
Beispiel #12
0
def generate_info_json(cli):
    """Generate an info.json file for a keyboard
    """
    # Determine our keyboard(s)
    if not cli.config.generate_info_json.keyboard:
        cli.log.error('Missing parameter: --keyboard')
        cli.subcommands['info'].print_help()
        return False

    if not is_keyboard(cli.config.generate_info_json.keyboard):
        cli.log.error('Invalid keyboard: "%s"', cli.config.generate_info_json.keyboard)
        return False

    # Build the info.json file
    kb_info_json = info_json(cli.config.generate_info_json.keyboard)
    strip_info_json(kb_info_json)

    # Display the results
    print(json.dumps(kb_info_json, indent=2, cls=InfoJSONEncoder))
Beispiel #13
0
def generate_info_json(cli):
    """Generate an info.json file for a keyboard
    """
    # Determine our keyboard(s)
    if not cli.config.generate_info_json.keyboard:
        cli.log.error('Missing parameter: --keyboard')
        cli.subcommands['info'].print_help()
        return False

    if not is_keyboard(cli.config.generate_info_json.keyboard):
        cli.log.error('Invalid keyboard: "%s"',
                      cli.config.generate_info_json.keyboard)
        return False

    if cli.args.overwrite:
        output_path = (Path('keyboards') /
                       cli.config.generate_info_json.keyboard /
                       'info.json').resolve()

        if cli.args.output:
            cli.log.warning('Overwriting user supplied --output with %s',
                            output_path)

        cli.args.output = output_path

    # Build the info.json file
    kb_info_json = info_json(cli.config.generate_info_json.keyboard)
    strip_info_json(kb_info_json)
    info_json_text = json.dumps(kb_info_json, indent=4, cls=InfoJSONEncoder)

    if cli.args.output:
        # Write to a file
        output_path = normpath(cli.args.output)

        if output_path.exists():
            cli.log.warning('Overwriting output file %s', output_path)

        output_path.write_text(info_json_text + '\n')
        cli.log.info('Wrote info.json to %s.', output_path)

    else:
        # Display the results
        print(info_json_text)
Beispiel #14
0
def keyboard_folder(keyboard):
    """Returns the actual keyboard folder.

    This checks aliases and DEFAULT_FOLDER to resolve the actual path for a keyboard.
    """
    aliases = json_load(Path('data/mappings/keyboard_aliases.json'))

    if keyboard in aliases:
        keyboard = aliases[keyboard].get('target', keyboard)

    rules_mk_file = Path(base_path, keyboard, 'rules.mk')

    if rules_mk_file.exists():
        rules_mk = parse_rules_mk_file(rules_mk_file)
        keyboard = rules_mk.get('DEFAULT_FOLDER', keyboard)

    if not is_keyboard(keyboard):
        raise ValueError(f'Invalid keyboard: {keyboard}')

    return keyboard
Beispiel #15
0
def generate_layouts(cli):
    """Generates the layouts.h file.
    """
    # Determine our keyboard(s)
    if not cli.config.generate_layouts.keyboard:
        cli.log.error('Missing paramater: --keyboard')
        cli.subcommands['info'].print_help()
        return False

    if not is_keyboard(cli.config.generate_layouts.keyboard):
        cli.log.error('Invalid keyboard: "%s"',
                      cli.config.generate_layouts.keyboard)
        return False

    # Build the info.json file
    kb_info_json = info_json(cli.config.generate_layouts.keyboard)

    # Build the layouts.h file.
    layouts_h_lines = [
        '/* This file was generated by `qmk generate-layouts`. Do not edit or copy.'
        ' */', '', '#pragma once'
    ]

    if 'matrix_pins' in kb_info_json:
        if 'direct' in kb_info_json['matrix_pins']:
            col_num = len(kb_info_json['matrix_pins']['direct'][0])
            row_num = len(kb_info_json['matrix_pins']['direct'])
        elif 'cols' in kb_info_json['matrix_pins'] and 'rows' in kb_info_json[
                'matrix_pins']:
            col_num = len(kb_info_json['matrix_pins']['cols'])
            row_num = len(kb_info_json['matrix_pins']['rows'])
        else:
            cli.log.error('%s: Invalid matrix config.',
                          cli.config.generate_layouts.keyboard)
            return False

    for layout_name in kb_info_json['layouts']:
        if kb_info_json['layouts'][layout_name]['c_macro']:
            continue

        if 'matrix' not in kb_info_json['layouts'][layout_name]['layout'][0]:
            cli.log.debug('%s/%s: No matrix data!',
                          cli.config.generate_layouts.keyboard, layout_name)
            continue

        layout_keys = []
        layout_matrix = [['KC_NO' for i in range(col_num)]
                         for i in range(row_num)]

        for i, key in enumerate(
                kb_info_json['layouts'][layout_name]['layout']):
            row = key['matrix'][0]
            col = key['matrix'][1]
            identifier = 'k%s%s' % (ROW_LETTERS[row], COL_LETTERS[col])

            try:
                layout_matrix[row][col] = identifier
                layout_keys.append(identifier)
            except IndexError:
                key_name = key.get('label', identifier)
                cli.log.error(
                    'Matrix data out of bounds for layout %s at index %s (%s): %s, %s',
                    layout_name, i, key_name, row, col)
                return False

        layouts_h_lines.append('')
        layouts_h_lines.append('#define %s(%s) {\\' %
                               (layout_name, ', '.join(layout_keys)))

        rows = ', \\\n'.join(
            ['\t {' + ', '.join(row) + '}' for row in layout_matrix])
        rows += ' \\'
        layouts_h_lines.append(rows)
        layouts_h_lines.append('}')

    # Show the results
    layouts_h = '\n'.join(layouts_h_lines) + '\n'

    if cli.args.output:
        cli.args.output.parent.mkdir(parents=True, exist_ok=True)
        if cli.args.output.exists():
            cli.args.output.replace(cli.args.output.name + '.bak')
        cli.args.output.write_text(layouts_h)

        if not cli.args.quiet:
            cli.log.info('Wrote info_config.h to %s.', cli.args.output)

    else:
        print(layouts_h)
Beispiel #16
0
def info(cli):
    """Compile an info.json for a particular keyboard and pretty-print it.
    """
    # Determine our keyboard(s)
    if not is_keyboard(cli.config.info.keyboard):
        cli.log.error('Invalid keyboard: %s!', cli.config.info.keyboard)
        exit(1)

    # Build the info.json file
    kb_info_json = info_json(cli.config.info.keyboard)

    # Output in the requested format
    if cli.args.format == 'json':
        print(json.dumps(kb_info_json))
        exit()

    if cli.args.format == 'text':
        for key in sorted(kb_info_json):
            if key == 'layouts':
                cli.echo('{fg_blue}layouts{fg_reset}: %s',
                         ', '.join(sorted(kb_info_json['layouts'].keys())))
            else:
                cli.echo('{fg_blue}%s{fg_reset}: %s', key, kb_info_json[key])

        if cli.config.info.layouts:
            show_layouts(kb_info_json, False)

        if cli.config.info.matrix:
            show_matrix(kb_info_json, False)

        if cli.config_source.info.keymap and cli.config_source.info.keymap != 'config_file':
            show_keymap(kb_info_json, False)

    elif cli.args.format == 'friendly':
        cli.echo('{fg_blue}Keyboard Name{fg_reset}: %s',
                 kb_info_json.get('keyboard_name', 'Unknown'))
        cli.echo('{fg_blue}Manufacturer{fg_reset}: %s',
                 kb_info_json.get('manufacturer', 'Unknown'))
        if 'url' in kb_info_json:
            cli.echo('{fg_blue}Website{fg_reset}: %s', kb_info_json['url'])
        if kb_info_json.get('maintainer') == 'qmk':
            cli.echo('{fg_blue}Maintainer{fg_reset}: QMK Community')
        else:
            cli.echo('{fg_blue}Maintainer{fg_reset}: %s',
                     kb_info_json.get('maintainer', 'qmk'))
        cli.echo('{fg_blue}Keyboard Folder{fg_reset}: %s',
                 kb_info_json.get('keyboard_folder', 'Unknown'))
        cli.echo('{fg_blue}Layouts{fg_reset}: %s',
                 ', '.join(sorted(kb_info_json['layouts'].keys())))
        if 'width' in kb_info_json and 'height' in kb_info_json:
            cli.echo('{fg_blue}Size{fg_reset}: %s x %s' %
                     (kb_info_json['width'], kb_info_json['height']))
        cli.echo('{fg_blue}Processor{fg_reset}: %s',
                 kb_info_json.get('processor', 'Unknown'))
        cli.echo('{fg_blue}Bootloader{fg_reset}: %s',
                 kb_info_json.get('bootloader', 'Unknown'))

        if cli.config.info.layouts:
            show_layouts(kb_info_json, True)

        if cli.config.info.matrix:
            show_matrix(kb_info_json, True)

        if cli.config_source.info.keymap and cli.config_source.info.keymap != 'config_file':
            show_keymap(kb_info_json, True)

    else:
        cli.log.error('Unknown format: %s', cli.args.format)
Beispiel #17
0
def find_keyboard_keymap():
    """Returns `(keyboard_name, keymap_name)` based on the user's current environment.

    This determines the keyboard and keymap name using the following precedence order:

        * Command line flags (--keyboard and --keymap)
        * Current working directory
            * `keyboards/<keyboard_name>`
            * `keyboards/<keyboard_name>/keymaps/<keymap_name>`
            * `layouts/**/<keymap_name>`
            * `users/<keymap_name>`
        * Configuration
            * cli.config.<subcommand>.keyboard
            * cli.config.<subcommand>.keymap
    """
    # Check to make sure their copy of MILC supports config_source
    if not hasattr(cli, 'config_source'):
        cli.log.error(
            "Your QMK CLI is out of date. Please upgrade using pip3 or your package manager."
        )
        exit(1)

    # State variables
    relative_cwd = under_qmk_firmware()
    keyboard_name = ""
    keymap_name = ""

    # If the keyboard or keymap are passed as arguments use that in preference to anything else
    if cli.config_source[cli._entrypoint.__name__]['keyboard'] == 'argument':
        keyboard_name = cli.config[cli._entrypoint.__name__]['keyboard']
    if cli.config_source[cli._entrypoint.__name__]['keymap'] == 'argument':
        keymap_name = cli.config[cli._entrypoint.__name__]['keymap']

    if not keyboard_name or not keymap_name:
        # If we don't have a keyboard_name and keymap_name from arguments try to derive one or both
        if relative_cwd and relative_cwd.parts and relative_cwd.parts[
                0] == 'keyboards':
            # Try to determine the keyboard and/or keymap name
            current_path = Path('/'.join(relative_cwd.parts[1:]))

            if current_path.parts[-2] == 'keymaps':
                if not keymap_name:
                    keymap_name = current_path.parts[-1]
                if not keyboard_name:
                    keyboard_name = '/'.join(current_path.parts[:-2])
            elif not keyboard_name and is_keyboard(current_path):
                keyboard_name = str(current_path)

        elif relative_cwd and relative_cwd.parts and relative_cwd.parts[
                0] == 'layouts':
            # Try to determine the keymap name from the community layout
            if is_keymap_dir(relative_cwd) and not keymap_name:
                keymap_name = relative_cwd.name

        elif relative_cwd and relative_cwd.parts and relative_cwd.parts[
                0] == 'users':
            # Try to determine the keymap name based on which userspace they're in
            if not keymap_name and len(relative_cwd.parts) > 1:
                keymap_name = relative_cwd.parts[1]

    # If we still don't have a keyboard and keymap check the config
    if not keyboard_name and cli.config[cli._entrypoint.__name__]['keyboard']:
        keyboard_name = cli.config[cli._entrypoint.__name__]['keyboard']

    if not keymap_name and cli.config[cli._entrypoint.__name__]['keymap']:
        keymap_name = cli.config[cli._entrypoint.__name__]['keymap']

    return (keyboard_name, keymap_name)
Beispiel #18
0
def generate_rules_mk(cli):
    """Generates a rules.mk file from info.json.
    """
    # Determine our keyboard(s)
    if not cli.config.generate_rules_mk.keyboard:
        cli.log.error('Missing paramater: --keyboard')
        cli.subcommands['info'].print_help()
        return False

    if not is_keyboard(cli.config.generate_rules_mk.keyboard):
        cli.log.error('Invalid keyboard: "%s"',
                      cli.config.generate_rules_mk.keyboard)
        return False

    # Build the info.json file
    kb_info_json = info_json(cli.config.generate_rules_mk.keyboard)
    rules_mk_lines = [
        '# This file was generated by `qmk generate-rules-mk`. Do not edit or copy.',
        ''
    ]

    # Bring in settings
    for info_key, rule_key in info_to_rules.items():
        if info_key in kb_info_json:
            rules_mk_lines.append(f'{rule_key} ?= {kb_info_json[info_key]}')

    # Find features that should be enabled
    if 'features' in kb_info_json:
        for feature, enabled in kb_info_json['features'].items():
            if feature == 'bootmagic_lite' and enabled:
                rules_mk_lines.append('BOOTMAGIC_ENABLE ?= lite')
            else:
                feature = feature.upper()
                enabled = 'yes' if enabled else 'no'
                rules_mk_lines.append(f'{feature}_ENABLE ?= {enabled}')

    # Set the LED driver
    if 'led_matrix' in kb_info_json and 'driver' in kb_info_json['led_matrix']:
        driver = kb_info_json['led_matrix']['driver']
        rules_mk_lines.append(f'LED_MATRIX_DRIVER ?= {driver}')

    # Add community layouts
    if 'community_layouts' in kb_info_json:
        rules_mk_lines.append(
            f'LAYOUTS ?= {" ".join(kb_info_json["community_layouts"])}')

    # Show the results
    rules_mk = '\n'.join(rules_mk_lines) + '\n'

    if cli.args.output:
        cli.args.output.parent.mkdir(parents=True, exist_ok=True)
        if cli.args.output.exists():
            cli.args.output.replace(cli.args.output.name + '.bak')
        cli.args.output.write_text(rules_mk)

        if cli.args.quiet:
            print(cli.args.output)
        else:
            cli.log.info('Wrote info_config.h to %s.', cli.args.output)

    else:
        print(rules_mk)
Beispiel #19
0
def generate_config_h(cli):
    """Generates the info_config.h file.
    """
    # Determine our keyboard(s)
    if not cli.config.generate_config_h.keyboard:
        cli.log.error('Missing parameter: --keyboard')
        cli.subcommands['info'].print_help()
        return False

    if not is_keyboard(cli.config.generate_config_h.keyboard):
        cli.log.error('Invalid keyboard: "%s"',
                      cli.config.generate_config_h.keyboard)
        return False

    # Build the info_config.h file.
    kb_info_json = dotty(info_json(cli.config.generate_config_h.keyboard))
    info_config_map = json_load(Path('data/mappings/info_config.json'))

    config_h_lines = [
        '/* This file was generated by `qmk generate-config-h`. Do not edit or copy.'
        ' */', '', '#pragma once'
    ]

    # Iterate through the info_config map to generate basic things
    for config_key, info_dict in info_config_map.items():
        info_key = info_dict['info_key']
        key_type = info_dict.get('value_type', 'str')
        to_config = info_dict.get('to_config', True)

        if not to_config:
            continue

        try:
            config_value = kb_info_json[info_key]
        except KeyError:
            continue

        if key_type.startswith('array'):
            config_h_lines.append('')
            config_h_lines.append(f'#ifndef {config_key}')
            config_h_lines.append(
                f'#   define {config_key} {{ {", ".join(map(str, config_value))} }}'
            )
            config_h_lines.append(f'#endif // {config_key}')
        elif key_type == 'bool':
            if config_value:
                config_h_lines.append('')
                config_h_lines.append(f'#ifndef {config_key}')
                config_h_lines.append(f'#   define {config_key}')
                config_h_lines.append(f'#endif // {config_key}')
        elif key_type == 'mapping':
            for key, value in config_value.items():
                config_h_lines.append('')
                config_h_lines.append(f'#ifndef {key}')
                config_h_lines.append(f'#   define {key} {value}')
                config_h_lines.append(f'#endif // {key}')
        else:
            config_h_lines.append('')
            config_h_lines.append(f'#ifndef {config_key}')
            config_h_lines.append(f'#   define {config_key} {config_value}')
            config_h_lines.append(f'#endif // {config_key}')

    if 'matrix_pins' in kb_info_json:
        config_h_lines.append(matrix_pins(kb_info_json['matrix_pins']))

    # Show the results
    config_h = '\n'.join(config_h_lines)

    if cli.args.output:
        cli.args.output.parent.mkdir(parents=True, exist_ok=True)
        if cli.args.output.exists():
            cli.args.output.replace(cli.args.output.parent /
                                    (cli.args.output.name + '.bak'))
        cli.args.output.write_text(config_h)

        if not cli.args.quiet:
            cli.log.info('Wrote info_config.h to %s.', cli.args.output)

    else:
        print(config_h)
Beispiel #20
0
def lint(cli):
    """Check keyboard and keymap for common mistakes.
    """
    failed = []

    # 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.')

        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(',')

    # Lint each keyboard
    for kb in keyboard_list:
        if not is_keyboard(kb):
            cli.log.error('No such keyboard: %s', kb)
            continue

        # Gather data about the keyboard.
        ok = True
        keyboard_path = keyboard(kb)
        keyboard_info = info_json(kb)

        # 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)

        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)

        # Check the rules.mk file(s)
        rules_mk_assignment_errors = rules_mk_assignment_only(keyboard_path)
        if rules_mk_assignment_errors:
            ok = False
            cli.log.error('%s: Non-assignment code found in rules.mk. Move it to post_rules.mk instead.', kb)
            for assignment_error in rules_mk_assignment_errors:
                cli.log.error(assignment_error)

        # Keymap specific checks
        if cli.config.lint.keymap:
            if not keymap_check(kb, cli.config.lint.keymap):
                ok = False

        # Report status
        if not ok:
            failed.append(kb)

    # Check and report the overall status
    if failed:
        cli.log.error('Lint check failed for: %s', ', '.join(failed))
        return False

    cli.log.info('Lint check passed!')
    return True