logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

path.py (5850B)


  1. """Functions that help us work with files and folders.
  2. """
  3. import logging
  4. import os
  5. import argparse
  6. from pathlib import Path, PureWindowsPath, PurePosixPath
  7. from qmk.constants import MAX_KEYBOARD_SUBFOLDERS, QMK_FIRMWARE, QMK_USERSPACE, HAS_QMK_USERSPACE
  8. from qmk.errors import NoSuchKeyboardError
  9. def is_keyboard(keyboard_name):
  10. """Returns True if `keyboard_name` is a keyboard we can compile.
  11. """
  12. if not keyboard_name:
  13. return False
  14. # keyboard_name values of 'c:/something' or '/something' trigger append issues
  15. # due to "If the argument is an absolute path, the previous path is ignored"
  16. # however it should always be a folder located under qmk_firmware/keyboards
  17. if Path(keyboard_name).is_absolute():
  18. return False
  19. keyboard_path = QMK_FIRMWARE / 'keyboards' / keyboard_name
  20. rules_mk = keyboard_path / 'rules.mk'
  21. keyboard_json = keyboard_path / 'keyboard.json'
  22. return rules_mk.exists() or keyboard_json.exists()
  23. def under_qmk_firmware(path=Path(os.environ['ORIG_CWD'])):
  24. """Returns a Path object representing the relative path under qmk_firmware, or None.
  25. """
  26. try:
  27. return path.relative_to(QMK_FIRMWARE)
  28. except ValueError:
  29. return None
  30. def under_qmk_userspace(path=Path(os.environ['ORIG_CWD'])):
  31. """Returns a Path object representing the relative path under $QMK_USERSPACE, or None.
  32. """
  33. try:
  34. if HAS_QMK_USERSPACE:
  35. return path.relative_to(QMK_USERSPACE)
  36. except ValueError:
  37. pass
  38. return None
  39. def is_under_qmk_firmware(path=Path(os.environ['ORIG_CWD'])):
  40. """Returns a boolean if the input path is a child under qmk_firmware.
  41. """
  42. if path is None:
  43. return False
  44. try:
  45. return Path(os.path.commonpath([Path(path), QMK_FIRMWARE])) == QMK_FIRMWARE
  46. except ValueError:
  47. return False
  48. def is_under_qmk_userspace(path=Path(os.environ['ORIG_CWD'])):
  49. """Returns a boolean if the input path is a child under $QMK_USERSPACE.
  50. """
  51. if path is None:
  52. return False
  53. try:
  54. if HAS_QMK_USERSPACE:
  55. return Path(os.path.commonpath([Path(path), QMK_USERSPACE])) == QMK_USERSPACE
  56. except ValueError:
  57. return False
  58. def keyboard(keyboard_name):
  59. """Returns the path to a keyboard's directory relative to the qmk root.
  60. """
  61. return Path('keyboards') / keyboard_name
  62. def keymaps(keyboard_name):
  63. """Returns all of the `keymaps/` directories for a given keyboard.
  64. Args:
  65. keyboard_name
  66. The name of the keyboard. Example: clueboard/66/rev3
  67. """
  68. keyboard_folder = keyboard(keyboard_name)
  69. found_dirs = []
  70. if HAS_QMK_USERSPACE:
  71. this_keyboard_folder = Path(QMK_USERSPACE) / keyboard_folder
  72. for _ in range(MAX_KEYBOARD_SUBFOLDERS):
  73. if (this_keyboard_folder / 'keymaps').exists():
  74. found_dirs.append((this_keyboard_folder / 'keymaps').resolve())
  75. this_keyboard_folder = this_keyboard_folder.parent
  76. if this_keyboard_folder.resolve() == QMK_USERSPACE.resolve():
  77. break
  78. # We don't have any relevant keymap directories in userspace, so we'll use the fully-qualified path instead.
  79. if len(found_dirs) == 0:
  80. found_dirs.append((QMK_USERSPACE / keyboard_folder / 'keymaps').resolve())
  81. this_keyboard_folder = QMK_FIRMWARE / keyboard_folder
  82. for _ in range(MAX_KEYBOARD_SUBFOLDERS):
  83. if (this_keyboard_folder / 'keymaps').exists():
  84. found_dirs.append((this_keyboard_folder / 'keymaps').resolve())
  85. this_keyboard_folder = this_keyboard_folder.parent
  86. if this_keyboard_folder.resolve() == QMK_FIRMWARE.resolve():
  87. break
  88. if len(found_dirs) > 0:
  89. return found_dirs
  90. logging.error('Could not find the keymaps directory!')
  91. raise NoSuchKeyboardError('Could not find keymaps directory for: %s' % keyboard_name)
  92. def keymap(keyboard_name, keymap_name):
  93. """Locate the directory of a given keymap.
  94. Args:
  95. keyboard_name
  96. The name of the keyboard. Example: clueboard/66/rev3
  97. keymap_name
  98. The name of the keymap. Example: default
  99. """
  100. for keymap_dir in keymaps(keyboard_name):
  101. if (keymap_dir / keymap_name).exists():
  102. return (keymap_dir / keymap_name).resolve()
  103. def normpath(path):
  104. """Returns a `pathlib.Path()` object for a given path.
  105. This will use the path to a file as seen from the directory the script was called from. You should use this to normalize filenames supplied from the command line.
  106. """
  107. path = Path(path)
  108. if path.is_absolute():
  109. return path
  110. return Path(os.environ['ORIG_CWD']) / path
  111. def unix_style_path(path):
  112. """Converts a Windows-style path with drive letter to a Unix path.
  113. Path().as_posix() normally returns the path with drive letter and forward slashes, so is inappropriate for `Makefile` paths.
  114. Passes through unadulterated if the path is not a Windows-style path.
  115. Args:
  116. path
  117. The path to convert.
  118. Returns:
  119. The input path converted to Unix format.
  120. """
  121. if isinstance(path, PureWindowsPath):
  122. p = list(path.parts)
  123. p[0] = f'/{p[0][0].lower()}' # convert from `X:/` to `/x`
  124. path = PurePosixPath(*p)
  125. return path
  126. class FileType(argparse.FileType):
  127. def __init__(self, *args, **kwargs):
  128. # Use UTF8 by default for stdin
  129. if 'encoding' not in kwargs:
  130. kwargs['encoding'] = 'UTF-8'
  131. return super().__init__(*args, **kwargs)
  132. def __call__(self, string):
  133. """normalize and check exists
  134. otherwise magic strings like '-' for stdin resolve to bad paths
  135. """
  136. norm = normpath(string)
  137. return norm if norm.exists() else super().__call__(string)