You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

142 lines
5.1 KiB

  1. """This script automates the creation of new keyboard directories using a starter template.
  2. """
  3. from datetime import date
  4. import fileinput
  5. from pathlib import Path
  6. import re
  7. import shutil
  8. from qmk.commands import git_get_username
  9. import qmk.path
  10. from milc import cli
  11. from milc.questions import choice, question
  12. KEYBOARD_TYPES = ['avr', 'ps2avrgb']
  13. def keyboard_name(name):
  14. """Callable for argparse validation.
  15. """
  16. if not validate_keyboard_name(name):
  17. raise ValueError
  18. return name
  19. def validate_keyboard_name(name):
  20. """Returns True if the given keyboard name contains only lowercase a-z, 0-9 and underscore characters.
  21. """
  22. regex = re.compile(r'^[a-z0-9][a-z0-9/_]+$')
  23. return bool(regex.match(name))
  24. @cli.argument('-kb', '--keyboard', help='Specify the name for the new keyboard directory', arg_only=True, type=keyboard_name)
  25. @cli.argument('-t', '--type', help='Specify the keyboard type', arg_only=True, choices=KEYBOARD_TYPES)
  26. @cli.argument('-u', '--username', help='Specify your username (default from Git config)', arg_only=True)
  27. @cli.subcommand('Creates a new keyboard directory')
  28. def new_keyboard(cli):
  29. """Creates a new keyboard.
  30. """
  31. cli.log.info('{style_bright}Generating a new QMK keyboard directory{style_normal}')
  32. cli.echo('')
  33. # Get keyboard name
  34. new_keyboard_name = None
  35. while not new_keyboard_name:
  36. new_keyboard_name = cli.args.keyboard if cli.args.keyboard else question('Keyboard Name:')
  37. if not validate_keyboard_name(new_keyboard_name):
  38. 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.')
  39. # Exit if passed by arg
  40. if cli.args.keyboard:
  41. return False
  42. new_keyboard_name = None
  43. continue
  44. keyboard_path = qmk.path.keyboard(new_keyboard_name)
  45. if keyboard_path.exists():
  46. cli.log.error(f'Keyboard {{fg_cyan}}{new_keyboard_name}{{fg_reset}} already exists! Please choose a different name.')
  47. # Exit if passed by arg
  48. if cli.args.keyboard:
  49. return False
  50. new_keyboard_name = None
  51. # Get keyboard type
  52. keyboard_type = cli.args.type if cli.args.type else choice('Keyboard Type:', KEYBOARD_TYPES, default=0)
  53. # Get username
  54. user_name = None
  55. while not user_name:
  56. user_name = question('Your Name:', default=find_user_name())
  57. if not user_name:
  58. cli.log.error('You didn\'t provide a username, and we couldn\'t find one set in your QMK or Git configs. Please try again.')
  59. # Exit if passed by arg
  60. if cli.args.username:
  61. return False
  62. # Copy all the files
  63. copy_templates(keyboard_type, keyboard_path)
  64. # Replace all the placeholders
  65. keyboard_basename = keyboard_path.name
  66. replacements = [
  67. ('%YEAR%', str(date.today().year)),
  68. ('%KEYBOARD%', keyboard_basename),
  69. ('%YOUR_NAME%', user_name),
  70. ]
  71. filenames = [
  72. keyboard_path / 'config.h',
  73. keyboard_path / 'info.json',
  74. keyboard_path / 'readme.md',
  75. keyboard_path / f'{keyboard_basename}.c',
  76. keyboard_path / f'{keyboard_basename}.h',
  77. keyboard_path / 'keymaps/default/readme.md',
  78. keyboard_path / 'keymaps/default/keymap.c',
  79. ]
  80. replace_placeholders(replacements, filenames)
  81. cli.echo('')
  82. cli.log.info(f'{{fg_green}}Created a new keyboard called {{fg_cyan}}{new_keyboard_name}{{fg_green}}.{{fg_reset}}')
  83. cli.log.info(f'To start working on things, `cd` into {{fg_cyan}}{keyboard_path}{{fg_reset}},')
  84. cli.log.info('or open the directory in your preferred text editor.')
  85. def find_user_name():
  86. if cli.args.username:
  87. return cli.args.username
  88. elif cli.config.user.name:
  89. return cli.config.user.name
  90. else:
  91. return git_get_username()
  92. def copy_templates(keyboard_type, keyboard_path):
  93. """Copies the template files from data/templates to the new keyboard directory.
  94. """
  95. template_base_path = Path('data/templates')
  96. keyboard_basename = keyboard_path.name
  97. cli.log.info('Copying base template files...')
  98. shutil.copytree(template_base_path / 'base', keyboard_path)
  99. cli.log.info(f'Copying {{fg_cyan}}{keyboard_type}{{fg_reset}} template files...')
  100. shutil.copytree(template_base_path / keyboard_type, keyboard_path, dirs_exist_ok=True)
  101. cli.log.info(f'Renaming {{fg_cyan}}keyboard.[ch]{{fg_reset}} to {{fg_cyan}}{keyboard_basename}.[ch]{{fg_reset}}...')
  102. shutil.move(keyboard_path / 'keyboard.c', keyboard_path / f'{keyboard_basename}.c')
  103. shutil.move(keyboard_path / 'keyboard.h', keyboard_path / f'{keyboard_basename}.h')
  104. def replace_placeholders(replacements, filenames):
  105. """Replaces the given placeholders in each template file.
  106. """
  107. for replacement in replacements:
  108. cli.log.info(f'Replacing {{fg_cyan}}{replacement[0]}{{fg_reset}} with {{fg_cyan}}{replacement[1]}{{fg_reset}}...')
  109. with fileinput.input(files=filenames, inplace=True) as file:
  110. for line in file:
  111. print(line.replace(replacement[0], replacement[1]), end='')