Beispiel #1
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 #2
0
def keyboard_check(kb):
    """Perform the keyboard level checks.
    """
    ok = True
    kb_info = info_json(kb)

    if not _handle_json_errors(kb, kb_info):
        ok = False

    # Additional checks
    rules_mk_assignment_errors = _rules_mk_assignment_only(kb)
    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)

    invalid_files = git_get_ignored_files(f'keyboards/{kb}/')
    for file in invalid_files:
        if 'keymap' in file:
            continue
        cli.log.error(f'{kb}: The file "{file}" should not exist!')
        ok = False

    return ok
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_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 #5
0
def generate_config_h(cli):
    """Generates the info_config.h file.
    """
    # Determine our keyboard/keymap
    if cli.args.keymap:
        km = locate_keymap(cli.args.keyboard, cli.args.keymap)
        km_json = json_load(km)
        validate(km_json, 'qmk.keymap.v1')
        kb_info_json = dotty(km_json.get('config', {}))
    else:
        kb_info_json = dotty(info_json(cli.args.keyboard))

    # Build the info_config.h file.
    config_h_lines = [
        GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once'
    ]

    generate_config_items(kb_info_json, config_h_lines)

    generate_matrix_size(kb_info_json, config_h_lines)

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

    if 'split' in kb_info_json:
        generate_split_config(kb_info_json, config_h_lines)

    # Show the results
    dump_lines(cli.args.output, config_h_lines, cli.args.quiet)
Beispiel #6
0
def generate_api(cli):
    """Generates the QMK API data.
    """
    api_data_dir = Path('api_data')
    v1_dir = api_data_dir / 'v1'
    keyboard_list = v1_dir / 'keyboard_list.json'
    keyboard_all = v1_dir / 'keyboards.json'
    usb_file = v1_dir / 'usb.json'

    if not api_data_dir.exists():
        api_data_dir.mkdir()

    kb_all = {'last_updated': current_datetime(), 'keyboards': {}}
    usb_list = {'last_updated': current_datetime(), 'devices': {}}

    # Generate and write keyboard specific JSON files
    for keyboard_name in list_keyboards():
        kb_all['keyboards'][keyboard_name] = info_json(keyboard_name)
        keyboard_dir = v1_dir / 'keyboards' / keyboard_name
        keyboard_info = keyboard_dir / 'info.json'
        keyboard_readme = keyboard_dir / 'readme.md'
        keyboard_readme_src = Path('keyboards') / keyboard_name / 'readme.md'

        keyboard_dir.mkdir(parents=True, exist_ok=True)
        keyboard_info.write_text(
            json.dumps({
                'last_updated': current_datetime(),
                'keyboards': {
                    keyboard_name: kb_all['keyboards'][keyboard_name]
                }
            }))

        if keyboard_readme_src.exists():
            copyfile(keyboard_readme_src, keyboard_readme)

        if 'usb' in kb_all['keyboards'][keyboard_name]:
            usb = kb_all['keyboards'][keyboard_name]['usb']

            if 'vid' in usb and usb['vid'] not in usb_list['devices']:
                usb_list['devices'][usb['vid']] = {}

            if 'pid' in usb and usb['pid'] not in usb_list['devices'][
                    usb['vid']]:
                usb_list['devices'][usb['vid']][usb['pid']] = {}

            if 'vid' in usb and 'pid' in usb:
                usb_list['devices'][usb['vid']][
                    usb['pid']][keyboard_name] = usb

    # Write the global JSON files
    keyboard_list.write_text(
        json.dumps(
            {
                'last_updated': current_datetime(),
                'keyboards': sorted(kb_all['keyboards'])
            },
            cls=InfoJSONEncoder))
    keyboard_all.write_text(json.dumps(kb_all, cls=InfoJSONEncoder))
    usb_file.write_text(json.dumps(usb_list, cls=InfoJSONEncoder))
Beispiel #7
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 #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 list_layouts(cli):
    """List the layouts for a specific keyboard
    """
    if not cli.config.list_layouts.keyboard:
        cli.log.error('Missing required arguments: --keyboard')
        cli.subcommands['list-layouts'].print_help()
        return False

    info_data = info_json(cli.config.list_layouts.keyboard)
    for name in sorted(info_data.get('community_layouts', [])):
        print(name)
Beispiel #11
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 #12
0
def generate_rules_mk(cli):
    """Generates a rules.mk file from info.json.
    """
    # Determine our keyboard/keymap
    if cli.args.keymap:
        km = locate_keymap(cli.args.keyboard, cli.args.keymap)
        km_json = json_load(km)
        validate(km_json, 'qmk.keymap.v1')
        kb_info_json = dotty(km_json.get('config', {}))
    else:
        kb_info_json = dotty(info_json(cli.args.keyboard))

    info_rules_map = json_load(Path('data/mappings/info_rules.json'))
    rules_mk_lines = [GPL2_HEADER_SH_LIKE, GENERATED_HEADER_SH_LIKE]

    # 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():
            feature = feature.upper()
            enabled = 'yes' if enabled else 'no'
            rules_mk_lines.append(f'{feature}_ENABLE ?= {enabled}')

    # Set SPLIT_TRANSPORT, if needed
    if kb_info_json.get('split', {}).get('transport', {}).get('protocol') == 'custom':
        rules_mk_lines.append('SPLIT_TRANSPORT ?= custom')

    # Set CUSTOM_MATRIX, if needed
    if kb_info_json.get('matrix_pins', {}).get('custom'):
        if kb_info_json.get('matrix_pins', {}).get('custom_lite'):
            rules_mk_lines.append('CUSTOM_MATRIX ?= lite')
        else:
            rules_mk_lines.append('CUSTOM_MATRIX ?= yes')

    # Show the results
    dump_lines(cli.args.output, rules_mk_lines)

    if cli.args.output:
        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)
Beispiel #13
0
def format_json(cli):
    """Format a json file.
    """
    json_file = json_load(cli.args.json_file)

    if cli.args.format == 'auto':
        try:
            validate(json_file, 'qmk.keyboard.v1')
            json_encoder = InfoJSONEncoder

        except ValidationError as e:
            cli.log.warning('File %s did not validate as a keyboard:\n\t%s',
                            cli.args.json_file, e)
            cli.log.info('Treating %s as a keymap file.', cli.args.json_file)
            json_encoder = KeymapJSONEncoder
    elif cli.args.format == 'keyboard':
        json_encoder = InfoJSONEncoder
    elif cli.args.format == 'keymap':
        json_encoder = KeymapJSONEncoder
    else:
        # This should be impossible
        cli.log.error('Unknown format: %s', cli.args.format)
        return False

    if json_encoder == KeymapJSONEncoder and 'layout' in json_file:
        # Attempt to format the keycodes.
        layout = json_file['layout']
        info_data = info_json(json_file['keyboard'])

        if layout in info_data.get('layout_aliases', {}):
            layout = json_file['layout'] = info_data['layout_aliases'][layout]

        if layout in info_data.get('layouts'):
            for layer_num, layer in enumerate(json_file['layers']):
                current_layer = []
                last_row = 0

                for keymap_key, info_key in zip(
                        layer, info_data['layouts'][layout]['layout']):
                    if last_row != info_key['y']:
                        current_layer.append('JSON_NEWLINE')
                        last_row = info_key['y']

                    current_layer.append(keymap_key)

                json_file['layers'][layer_num] = current_layer

    # Display the results
    print(json.dumps(json_file, cls=json_encoder))
Beispiel #14
0
def generate_keyboard_c(cli):
    """Generates the keyboard.h file.
    """
    kb_info_json = info_json(cli.args.keyboard)

    # Build the layouts.h file.
    keyboard_h_lines = [
        GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#include QMK_KEYBOARD_H',
        ''
    ]

    keyboard_h_lines.extend(_gen_led_config(kb_info_json))

    # Show the results
    dump_lines(cli.args.output, keyboard_h_lines, cli.args.quiet)
Beispiel #15
0
def would_populate_layout_h(keyboard):
    """Detect if a given keyboard is doing data driven layouts
    """
    # Build the info.json file
    kb_info_json = info_json(keyboard)

    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!', keyboard, layout_name)
            continue

        return True

    return False
Beispiel #16
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 #17
0
def generate_config_h(cli):
    """Generates the info_config.h file.
    """
    # Determine our keyboard/keymap
    if cli.args.keymap:
        km = locate_keymap(cli.args.keyboard, cli.args.keymap)
        km_json = json_load(km)
        validate(km_json, 'qmk.keymap.v1')
        kb_info_json = dotty(km_json.get('config', {}))
    else:
        kb_info_json = dotty(info_json(cli.args.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'
    ]

    generate_config_items(kb_info_json, config_h_lines)

    generate_matrix_size(kb_info_json, config_h_lines)

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

    if 'split' in kb_info_json:
        generate_split_config(kb_info_json, config_h_lines)

    # 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 #18
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 #19
0
def via2json(cli):
    """Convert a VIA backup json to keymap.json format.

    This command uses the `qmk.keymap` module to generate a keymap.json from a VIA backup json. The generated keymap is written to stdout, or to a file if -o is provided.
    """
    # Find appropriate layout macro
    keymap_layout = cli.args.layout if cli.args.layout else _find_via_layout_macro(
        cli.args.keyboard)
    if not keymap_layout:
        cli.log.error(
            f"Couldn't find LAYOUT macro for keyboard {cli.args.keyboard}. Please specify it with the '-l' argument."
        )
        exit(1)

    # Load the VIA backup json
    with cli.args.filename.open('r') as fd:
        via_backup = json.load(fd)

    # Generate keyboard metadata
    keyboard_data = info_json(cli.args.keyboard)

    # Get keycode array
    keymap_data = _via_to_keymap(via_backup, keyboard_data, keymap_layout)

    # Convert macros
    macro_data = list()
    if via_backup.get('macros'):
        macro_data = _convert_macros(via_backup['macros'])

        # Replace VIA macro keys with JSON keymap ones
        keymap_data = _fix_macro_keys(keymap_data)

    # Generate the keymap.json
    keymap_json = generate_json(cli.args.keymap, cli.args.keyboard,
                                keymap_layout, keymap_data, macro_data)

    keymap_lines = [json.dumps(keymap_json, cls=KeymapJSONEncoder)]
    dump_lines(cli.args.output, keymap_lines, cli.args.quiet)
Beispiel #20
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 #21
0
def generate_api(cli):
    """Generates the QMK API data.
    """
    api_data_dir = Path('api_data')
    v1_dir = api_data_dir / 'v1'
    keyboard_all_file = v1_dir / 'keyboards.json'  # A massive JSON containing everything
    keyboard_list_file = v1_dir / 'keyboard_list.json'  # A simple list of keyboard targets
    keyboard_aliases_file = v1_dir / 'keyboard_aliases.json'  # A list of historical keyboard names and their new name
    keyboard_metadata_file = v1_dir / 'keyboard_metadata.json'  # All the data configurator/via needs for initialization
    usb_file = v1_dir / 'usb.json'  # A mapping of USB VID/PID -> keyboard target

    if not api_data_dir.exists():
        api_data_dir.mkdir()

    kb_all = {}
    usb_list = {}

    # Generate and write keyboard specific JSON files
    for keyboard_name in list_keyboards():
        kb_all[keyboard_name] = info_json(keyboard_name)
        keyboard_dir = v1_dir / 'keyboards' / keyboard_name
        keyboard_info = keyboard_dir / 'info.json'
        keyboard_readme = keyboard_dir / 'readme.md'
        keyboard_readme_src = find_readme(keyboard_name)

        keyboard_dir.mkdir(parents=True, exist_ok=True)
        keyboard_json = json.dumps({'last_updated': current_datetime(), 'keyboards': {keyboard_name: kb_all[keyboard_name]}})
        if not cli.args.dry_run:
            keyboard_info.write_text(keyboard_json)
            cli.log.debug('Wrote file %s', keyboard_info)

            if keyboard_readme_src:
                copyfile(keyboard_readme_src, keyboard_readme)
                cli.log.debug('Copied %s -> %s', keyboard_readme_src, keyboard_readme)

        if 'usb' in kb_all[keyboard_name]:
            usb = kb_all[keyboard_name]['usb']

            if 'vid' in usb and usb['vid'] not in usb_list:
                usb_list[usb['vid']] = {}

            if 'pid' in usb and usb['pid'] not in usb_list[usb['vid']]:
                usb_list[usb['vid']][usb['pid']] = {}

            if 'vid' in usb and 'pid' in usb:
                usb_list[usb['vid']][usb['pid']][keyboard_name] = usb

    # Generate data for the global files
    keyboard_list = sorted(kb_all)
    keyboard_aliases = json_load(Path('data/mappings/keyboard_aliases.json'))
    keyboard_metadata = {
        'last_updated': current_datetime(),
        'keyboards': keyboard_list,
        'keyboard_aliases': keyboard_aliases,
        'usb': usb_list,
    }

    # Write the global JSON files
    keyboard_all_json = json.dumps({'last_updated': current_datetime(), 'keyboards': kb_all}, cls=InfoJSONEncoder)
    usb_json = json.dumps({'last_updated': current_datetime(), 'usb': usb_list}, cls=InfoJSONEncoder)
    keyboard_list_json = json.dumps({'last_updated': current_datetime(), 'keyboards': keyboard_list}, cls=InfoJSONEncoder)
    keyboard_aliases_json = json.dumps({'last_updated': current_datetime(), 'keyboard_aliases': keyboard_aliases}, cls=InfoJSONEncoder)
    keyboard_metadata_json = json.dumps(keyboard_metadata, cls=InfoJSONEncoder)

    if not cli.args.dry_run:
        keyboard_all_file.write_text(keyboard_all_json)
        usb_file.write_text(usb_json)
        keyboard_list_file.write_text(keyboard_list_json)
        keyboard_aliases_file.write_text(keyboard_aliases_json)
        keyboard_metadata_file.write_text(keyboard_metadata_json)
Beispiel #22
0
def compile_json(keyboard_keymap_data, source_ip=None, send_metrics=True, public_firmware=False):
    """Compile a keymap.

    Arguments:

        keyboard_keymap_data
            A configurator export file that's been deserialized

        source_ip
            The IP that submitted the compile job
    """
    start_time = time()
    base_metric = f'{gethostname()}.qmk_compiler.compile_json'
    result = {
        'keyboard': 'unknown',
        'returncode': -2,
        'output': '',
        'firmware': None,
        'firmware_filename': '',
        'source_ip': source_ip,
        'output': 'Unknown error',
        'public_firmware': public_firmware,
    }

    if DEBUG:
        print('Pointing graphite at', GRAPHITE_HOST)

    graphyte.init(GRAPHITE_HOST, GRAPHITE_PORT)

    try:
        for key in ('keyboard', 'layout', 'keymap'):
            result[key] = keyboard_keymap_data[key]

        # Gather information
        result['keymap_archive'] = '%s-%s.json' % (result['keyboard'].replace('/', '-'), result['keymap'].replace('/', '-'))
        result['keymap_json'] = json.dumps(keyboard_keymap_data)
        result['command'] = ['bin/qmk', 'compile', result['keymap_archive']]
        job = get_current_job()
        result['id'] = job.id
        branch = keyboard_keymap_data.get('branch', QMK_GIT_BRANCH)

        # Fetch the appropriate version of QMK
        git_start_time = time()
        checkout_qmk(branch=branch)
        git_time = time() - git_start_time
        chdir('qmk_firmware')

        # Sanity check
        if not path.exists('keyboards/' + result['keyboard']):
            print('Unknown keyboard: %s' % (result['keyboard'],))
            return {'returncode': -1, 'command': '', 'output': 'Unknown keyboard!', 'firmware': None}

        # Pull in the modules from the QMK we just checked out
        if './lib/python' not in sys.path:
            sys.path.append('./lib/python')

        from qmk.info import info_json

        # If this keyboard needs a submodule check it out
        submodule_start_time = time()
        kb_info = info_json(result['keyboard'])
        if 'protocol' not in kb_info:
            kb_info['protocol'] = 'unknown'

        if kb_info['protocol'] in ['ChibiOS', 'LUFA']:
            checkout_lufa()

        if kb_info['protocol'] == 'ChibiOS':
            checkout_chibios()

        if kb_info['protocol'] == 'V-USB':
            checkout_vusb()
        submodule_time = time() - submodule_start_time

        # Write the keymap file
        with open(result['keymap_archive'], 'w') as fd:
            fd.write(result['keymap_json'] + '\n')

        # Compile the firmware
        compile_start_time = time()
        compile_keymap(job, result)
        compile_time = time() - compile_start_time

        # Store the source in S3
        storage_start_time = time()
        store_firmware_binary(result)
        chdir('..')
        store_firmware_source(result)
        remove(result['source_archive'])
        storage_time = time() - storage_start_time

        # Send metrics about this build
        if send_metrics:
            graphyte.send(f'{base_metric}.{result["keyboard"]}.all_layouts', 1)
            graphyte.send(f'{base_metric}.{result["keyboard"]}.{result["layout"]}', 1)
            graphyte.send(f'{base_metric}.{result["keyboard"]}.git_time', git_time)
            graphyte.send(f'{base_metric}.all_keyboards.git_time', git_time)
            graphyte.send(f'{base_metric}.{result["keyboard"]}.submodule_time', submodule_time)
            graphyte.send(f'{base_metric}.all_keyboards.submodule_time', submodule_time)
            graphyte.send(f'{base_metric}.{result["keyboard"]}.compile_time', compile_time)
            graphyte.send(f'{base_metric}.all_keyboards.compile_time', compile_time)

            if result['returncode'] == 0:
                graphyte.send(f'{base_metric}.{result["keyboard"]}.compile_time', compile_time)
                graphyte.send(f'{base_metric}.all_keyboards.compile_time', compile_time)
            else:
                graphyte.send(f'{base_metric}.{result["keyboard"]}.errors', 1)

            if source_ip:
                ip_location = geolite2.lookup(source_ip)

                if ip_location:
                    if ip_location.subdivisions:
                        location_key = f'{ip_location.country}_{"_".join(ip_location.subdivisions)}'
                    else:
                        location_key = ip_location.country

                    graphyte.send(f'{gethostname()}.qmk_compiler.geoip.{location_key}', 1)

            total_time = time() - start_time
            graphyte.send(f'{base_metric}.{result["keyboard"]}.storage_time', storage_time)
            graphyte.send(f'{base_metric}.all_keyboards.storage_time', storage_time)
            graphyte.send(f'{base_metric}.{result["keyboard"]}.total_time', total_time)
            graphyte.send(f'{base_metric}.all_keyboards.total_time', total_time)

    except Exception as e:
        result['returncode'] = -3
        result['exception'] = e.__class__.__name__
        result['stacktrace'] = format_exc()

        if send_metrics:
            graphyte.send(f'{base_metric}.{result["keyboard"]}.errors', 1)

    store_firmware_metadata(job, result)

    return result
Beispiel #23
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 #24
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 #25
0
def generate_rules_mk(cli):
    """Generates a rules.mk file from info.json.
    """
    # Determine our keyboard/keymap
    if cli.args.keymap:
        km = locate_keymap(cli.args.keyboard, cli.args.keymap)
        km_json = json_load(km)
        validate(km_json, 'qmk.keymap.v1')
        kb_info_json = dotty(km_json.get('config', {}))
    else:
        kb_info_json = dotty(info_json(cli.args.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}')

    # Set SPLIT_TRANSPORT, if needed
    if kb_info_json.get('split', {}).get('transport',
                                         {}).get('protocol') == 'custom':
        rules_mk_lines.append('SPLIT_TRANSPORT ?= custom')

    # Set CUSTOM_MATRIX, if needed
    if kb_info_json.get('matrix_pins', {}).get('custom'):
        if kb_info_json.get('matrix_pins', {}).get('custom_lite'):
            rules_mk_lines.append('CUSTOM_MATRIX ?= lite')
        else:
            rules_mk_lines.append('CUSTOM_MATRIX ?= yes')

    # 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 #26
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 #27
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
Beispiel #28
0
def list_layouts(cli):
    """List the layouts for a specific keyboard
    """
    info_data = info_json(cli.config.list_layouts.keyboard)
    for name in sorted(info_data.get('community_layouts', [])):
        print(name)