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.

122 lines
5.3 KiB

  1. """Helpful decorators that subcommands can use.
  2. """
  3. import functools
  4. from pathlib import Path
  5. from time import monotonic
  6. from milc import cli
  7. from qmk.keymap import is_keymap_dir
  8. from qmk.path import is_keyboard, under_qmk_firmware
  9. def automagic_keyboard(func):
  10. """Sets `cli.config.<subcommand>.keyboard` based on environment.
  11. This will rewrite cli.config.<subcommand>.keyboard if the user did not pass `--keyboard` and the directory they are currently in is a keyboard or keymap directory.
  12. """
  13. @functools.wraps(func)
  14. def wrapper(*args, **kwargs):
  15. # Check to make sure their copy of MILC supports config_source
  16. if not hasattr(cli, 'config_source'):
  17. cli.log.error("This subcommand requires a newer version of the QMK CLI. Please upgrade using `pip3 install --upgrade qmk` or your package manager.")
  18. exit(1)
  19. # Ensure that `--keyboard` was not passed and CWD is under `qmk_firmware/keyboards`
  20. if cli.config_source[cli._entrypoint.__name__]['keyboard'] != 'argument':
  21. relative_cwd = under_qmk_firmware()
  22. if relative_cwd and len(relative_cwd.parts) > 1 and relative_cwd.parts[0] == 'keyboards':
  23. # Attempt to extract the keyboard name from the current directory
  24. current_path = Path('/'.join(relative_cwd.parts[1:]))
  25. if 'keymaps' in current_path.parts:
  26. # Strip current_path of anything after `keymaps`
  27. keymap_index = len(current_path.parts) - current_path.parts.index('keymaps') - 1
  28. current_path = current_path.parents[keymap_index]
  29. if is_keyboard(current_path):
  30. cli.config[cli._entrypoint.__name__]['keyboard'] = str(current_path)
  31. cli.config_source[cli._entrypoint.__name__]['keyboard'] = 'keyboard_directory'
  32. return func(*args, **kwargs)
  33. return wrapper
  34. def automagic_keymap(func):
  35. """Sets `cli.config.<subcommand>.keymap` based on environment.
  36. This will rewrite cli.config.<subcommand>.keymap if the user did not pass `--keymap` and the directory they are currently in is a keymap, layout, or user directory.
  37. """
  38. @functools.wraps(func)
  39. def wrapper(*args, **kwargs):
  40. # Check to make sure their copy of MILC supports config_source
  41. if not hasattr(cli, 'config_source'):
  42. cli.log.error("This subcommand requires a newer version of the QMK CLI. Please upgrade using `pip3 install --upgrade qmk` or your package manager.")
  43. exit(1)
  44. # Ensure that `--keymap` was not passed and that we're under `qmk_firmware`
  45. if cli.config_source[cli._entrypoint.__name__]['keymap'] != 'argument':
  46. relative_cwd = under_qmk_firmware()
  47. if relative_cwd and len(relative_cwd.parts) > 1:
  48. # If we're in `qmk_firmware/keyboards` and `keymaps` is in our path, try to find the keyboard name.
  49. if relative_cwd.parts[0] == 'keyboards' and 'keymaps' in relative_cwd.parts:
  50. current_path = Path('/'.join(relative_cwd.parts[1:])) # Strip 'keyboards' from the front
  51. if 'keymaps' in current_path.parts and current_path.name != 'keymaps':
  52. while current_path.parent.name != 'keymaps':
  53. current_path = current_path.parent
  54. cli.config[cli._entrypoint.__name__]['keymap'] = current_path.name
  55. cli.config_source[cli._entrypoint.__name__]['keymap'] = 'keymap_directory'
  56. # If we're in `qmk_firmware/layouts` guess the name from the community keymap they're in
  57. elif relative_cwd.parts[0] == 'layouts' and is_keymap_dir(relative_cwd):
  58. cli.config[cli._entrypoint.__name__]['keymap'] = relative_cwd.name
  59. cli.config_source[cli._entrypoint.__name__]['keymap'] = 'layouts_directory'
  60. # If we're in `qmk_firmware/users` guess the name from the userspace they're in
  61. elif relative_cwd.parts[0] == 'users':
  62. # Guess the keymap name based on which userspace they're in
  63. cli.config[cli._entrypoint.__name__]['keymap'] = relative_cwd.parts[1]
  64. cli.config_source[cli._entrypoint.__name__]['keymap'] = 'users_directory'
  65. return func(*args, **kwargs)
  66. return wrapper
  67. def lru_cache(timeout=10, maxsize=128, typed=False):
  68. """Least Recently Used Cache- cache the result of a function.
  69. Args:
  70. timeout
  71. How many seconds to cache results for.
  72. maxsize
  73. The maximum size of the cache in bytes
  74. typed
  75. When `True` argument types will be taken into consideration, for example `3` and `3.0` will be treated as different keys.
  76. """
  77. def wrapper_cache(func):
  78. func = functools.lru_cache(maxsize=maxsize, typed=typed)(func)
  79. func.expiration = monotonic() + timeout
  80. @functools.wraps(func)
  81. def wrapped_func(*args, **kwargs):
  82. if monotonic() >= func.expiration:
  83. func.expiration = monotonic() + timeout
  84. func.cache_clear()
  85. return func(*args, **kwargs)
  86. wrapped_func.cache_info = func.cache_info
  87. wrapped_func.cache_clear = func.cache_clear
  88. return wrapped_func
  89. return wrapper_cache