示例#1
0
def new_keyboard(cli):
    """Creates a new keyboard.
    """
    cli.log.info('{style_bright}Generating a new QMK keyboard directory{style_normal}')
    cli.echo('')

    kb_name = cli.args.keyboard if cli.args.keyboard else prompt_keyboard()
    user_name = cli.config.new_keyboard.name if cli.config.new_keyboard.name else prompt_user()
    real_name = cli.args.realname or cli.config.new_keyboard.name if cli.args.realname or cli.config.new_keyboard.name else prompt_name(user_name)
    default_layout = cli.args.layout if cli.args.layout else prompt_layout()
    mcu = cli.args.type if cli.args.type else prompt_mcu()
    bootloader = select_default_bootloader(mcu)

    if not validate_keyboard_name(kb_name):
        cli.log.error('Keyboard names must contain only {fg_cyan}lowercase a-z{fg_reset}, {fg_cyan}0-9{fg_reset}, and {fg_cyan}_{fg_reset}! Please choose a different name.')
        return 1

    if keyboard(kb_name).exists():
        cli.log.error(f'Keyboard {{fg_cyan}}{kb_name}{{fg_reset}} already exists! Please choose a different name.')
        return 1

    tokens = {  # Comment here is to force multiline formatting
        'YEAR': str(date.today().year),
        'KEYBOARD': kb_name,
        'USER_NAME': user_name,
        'REAL_NAME': real_name,
        'LAYOUT': default_layout,
        'MCU': mcu,
        'BOOTLOADER': bootloader
    }

    if cli.config.general.verbose:
        cli.log.info("Creating keyboard with:")
        for key, value in tokens.items():
            cli.echo(f"    {key.ljust(10)}:   {value}")

    # TODO: detach community layout and rename to just "LAYOUT"
    if default_layout == 'none of the above':
        default_layout = "ortho_4x4"

    # begin with making the deepest folder in the tree
    keymaps_path = keyboard(kb_name) / 'keymaps/'
    keymaps_path.mkdir(parents=True)

    # copy in keymap.c or keymap.json
    community_keymap = Path(COMMUNITY / f'{default_layout}/default_{default_layout}/')
    shutil.copytree(community_keymap, keymaps_path / 'default')

    # process template files
    for file in list(TEMPLATE.iterdir()):
        replace_placeholders(file, keyboard(kb_name) / file.name, tokens)

    # merge in infos
    community_info = Path(COMMUNITY / f'{default_layout}/info.json')
    augment_community_info(community_info, keyboard(kb_name) / community_info.name)

    cli.log.info(f'{{fg_green}}Created a new keyboard called {{fg_cyan}}{kb_name}{{fg_green}}.{{fg_reset}}')
    cli.log.info(f'To start working on things, `cd` into {{fg_cyan}}keyboards/{kb_name}{{fg_reset}},')
    cli.log.info('or open the directory in your preferred text editor.')
    cli.log.info(f"And build with {{fg_yellow}}qmk compile -kb {kb_name} -km default{{fg_reset}}.")
示例#2
0
def _rules_mk_assignment_only(kb):
    """Check the keyboard-level rules.mk to ensure it only has assignments.
    """
    keyboard_path = keyboard(kb)
    current_path = Path()
    errors = []

    for path_part in keyboard_path.parts:
        current_path = current_path / path_part
        rules_mk = current_path / 'rules.mk'

        if rules_mk.exists():
            continuation = None

            for i, line in enumerate(rules_mk.open()):
                line = line.strip()

                if '#' in line:
                    line = line[:line.index('#')]

                if continuation:
                    line = continuation + line
                    continuation = None

                if line:
                    if line[-1] == '\\':
                        continuation = line[:-1]
                        continue

                    if line and '=' not in line:
                        errors.append(
                            f'Non-assignment code on line +{i} {rules_mk}: {line}'
                        )

    return errors
示例#3
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
示例#4
0
def prompt_keyboard():
    prompt = """{fg_yellow}Name Your Keyboard Project{style_reset_all}
For more infomation, see:
https://docs.qmk.fm/#/hardware_keyboard_guidelines?id=naming-your-keyboardproject

Keyboard Name? """

    errmsg = 'Keyboard already exists! Please choose a different name:'

    return _question(prompt, reprompt=errmsg, validate=lambda x: not keyboard(x).exists())
示例#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 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