logo

qmk_firmware

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

main.py (7872B)


  1. """QMK Doctor
  2. Check out the user's QMK environment and make sure it's ready to compile.
  3. """
  4. import platform
  5. from subprocess import DEVNULL
  6. from milc import cli
  7. from milc.questions import yesno
  8. from qmk import submodules
  9. from qmk.constants import QMK_FIRMWARE, QMK_FIRMWARE_UPSTREAM, QMK_USERSPACE, HAS_QMK_USERSPACE
  10. from .check import CheckStatus, check_binaries, check_binary_versions, check_submodules
  11. from qmk.git import git_check_repo, git_get_branch, git_get_tag, git_get_last_log_entry, git_get_common_ancestor, git_is_dirty, git_get_remotes, git_check_deviation
  12. from qmk.commands import in_virtualenv
  13. from qmk.userspace import qmk_userspace_paths, qmk_userspace_validate, UserspaceValidationError
  14. def os_tests():
  15. """Determine our OS and run platform specific tests
  16. """
  17. platform_id = platform.platform().lower()
  18. if 'darwin' in platform_id or 'macos' in platform_id:
  19. from .macos import os_test_macos
  20. return os_test_macos()
  21. elif 'linux' in platform_id:
  22. from .linux import os_test_linux
  23. return os_test_linux()
  24. elif 'windows' in platform_id:
  25. from .windows import os_test_windows
  26. return os_test_windows()
  27. else:
  28. cli.log.warning('Unsupported OS detected: %s', platform_id)
  29. return CheckStatus.WARNING
  30. def git_tests():
  31. """Run Git-related checks
  32. """
  33. status = CheckStatus.OK
  34. # Make sure our QMK home is a Git repo
  35. git_ok = git_check_repo()
  36. if not git_ok:
  37. cli.log.warning("{fg_yellow}QMK home does not appear to be a Git repository! (no .git folder)")
  38. status = CheckStatus.WARNING
  39. else:
  40. git_branch = git_get_branch()
  41. if git_branch:
  42. cli.log.info('Git branch: %s', git_branch)
  43. repo_version = git_get_tag()
  44. if repo_version:
  45. cli.log.info('Repo version: %s', repo_version)
  46. git_dirty = git_is_dirty()
  47. if git_dirty:
  48. cli.log.warning('{fg_yellow}Git has unstashed/uncommitted changes.')
  49. status = CheckStatus.WARNING
  50. git_remotes = git_get_remotes()
  51. if 'upstream' not in git_remotes.keys() or QMK_FIRMWARE_UPSTREAM not in git_remotes['upstream'].get('url', ''):
  52. cli.log.warning('{fg_yellow}The official repository does not seem to be configured as git remote "upstream".')
  53. status = CheckStatus.WARNING
  54. else:
  55. git_deviation = git_check_deviation(git_branch)
  56. if git_branch in ['master', 'develop'] and git_deviation:
  57. cli.log.warning('{fg_yellow}The local "%s" branch contains commits not found in the upstream branch.', git_branch)
  58. status = CheckStatus.WARNING
  59. for branch in [git_branch, 'upstream/master', 'upstream/develop']:
  60. cli.log.info('- Latest %s: %s', branch, git_get_last_log_entry(branch))
  61. for branch in ['upstream/master', 'upstream/develop']:
  62. cli.log.info('- Common ancestor with %s: %s', branch, git_get_common_ancestor(branch, 'HEAD'))
  63. return status
  64. def output_submodule_status():
  65. """Prints out information related to the submodule status.
  66. """
  67. cli.log.info('Submodule status:')
  68. sub_status = submodules.status()
  69. for s in sub_status.keys():
  70. sub_info = sub_status[s]
  71. if 'name' in sub_info:
  72. sub_name = sub_info['name']
  73. sub_shorthash = sub_info['shorthash'] if 'shorthash' in sub_info else ''
  74. sub_describe = sub_info['describe'] if 'describe' in sub_info else ''
  75. sub_last_log_timestamp = sub_info['last_log_timestamp'] if 'last_log_timestamp' in sub_info else ''
  76. if sub_last_log_timestamp != '':
  77. cli.log.info(f'- {sub_name}: {sub_last_log_timestamp} -- {sub_describe} ({sub_shorthash})')
  78. else:
  79. cli.log.error(f'- {sub_name}: <<< missing or unknown >>>')
  80. def userspace_tests(qmk_firmware):
  81. if qmk_firmware:
  82. cli.log.info(f'QMK home: {{fg_cyan}}{qmk_firmware}')
  83. for path in qmk_userspace_paths():
  84. try:
  85. qmk_userspace_validate(path)
  86. cli.log.info(f'Testing userspace candidate: {{fg_cyan}}{path}{{fg_reset}} -- {{fg_green}}Valid `qmk.json`')
  87. except FileNotFoundError:
  88. cli.log.warning(f'Testing userspace candidate: {{fg_cyan}}{path}{{fg_reset}} -- {{fg_red}}Missing `qmk.json`')
  89. except UserspaceValidationError as err:
  90. cli.log.warning(f'Testing userspace candidate: {{fg_cyan}}{path}{{fg_reset}} -- {{fg_red}}Invalid `qmk.json`')
  91. cli.log.warning(f' -- {{fg_cyan}}{path}/qmk.json{{fg_reset}} validation error: {err}')
  92. if QMK_USERSPACE is not None:
  93. cli.log.info(f'QMK userspace: {{fg_cyan}}{QMK_USERSPACE}')
  94. cli.log.info(f'Userspace enabled: {{fg_cyan}}{HAS_QMK_USERSPACE}')
  95. @cli.argument('-y', '--yes', action='store_true', arg_only=True, help='Answer yes to all questions.')
  96. @cli.argument('-n', '--no', action='store_true', arg_only=True, help='Answer no to all questions.')
  97. @cli.subcommand('Basic QMK environment checks')
  98. def doctor(cli):
  99. """Basic QMK environment checks.
  100. This is currently very simple, it just checks that all the expected binaries are on your system.
  101. TODO(unclaimed):
  102. * [ ] Compile a trivial program with each compiler
  103. """
  104. cli.log.info('QMK Doctor is checking your environment.')
  105. cli.log.info('CLI version: %s', cli.version)
  106. cli.log.info('QMK home: {fg_cyan}%s', QMK_FIRMWARE)
  107. status = os_status = os_tests()
  108. userspace_tests(None)
  109. git_status = git_tests()
  110. if git_status == CheckStatus.ERROR or (os_status == CheckStatus.OK and git_status == CheckStatus.WARNING):
  111. status = git_status
  112. if in_virtualenv():
  113. cli.log.info('CLI installed in virtualenv.')
  114. # Make sure the basic CLI tools we need are available and can be executed.
  115. bin_ok = check_binaries()
  116. if bin_ok == CheckStatus.ERROR:
  117. if yesno('Would you like to install dependencies?', default=True):
  118. cli.run(['util/qmk_install.sh', '-y'], stdin=DEVNULL, capture_output=False)
  119. bin_ok = check_binaries()
  120. if bin_ok == CheckStatus.OK:
  121. cli.log.info('All dependencies are installed.')
  122. elif bin_ok == CheckStatus.WARNING:
  123. cli.log.warning('Issues encountered while checking dependencies.')
  124. else:
  125. status = CheckStatus.ERROR
  126. # Make sure the tools are at the correct version
  127. ver_ok = check_binary_versions()
  128. if CheckStatus.ERROR in ver_ok:
  129. status = CheckStatus.ERROR
  130. elif CheckStatus.WARNING in ver_ok and status == CheckStatus.OK:
  131. status = CheckStatus.WARNING
  132. # Check out the QMK submodules
  133. sub_ok = check_submodules()
  134. if sub_ok == CheckStatus.OK:
  135. cli.log.info('Submodules are up to date.')
  136. else:
  137. if git_check_repo() and yesno('Would you like to clone the submodules?', default=True):
  138. submodules.update()
  139. sub_ok = check_submodules()
  140. if sub_ok == CheckStatus.ERROR:
  141. status = CheckStatus.ERROR
  142. elif sub_ok == CheckStatus.WARNING and status == CheckStatus.OK:
  143. status = CheckStatus.WARNING
  144. output_submodule_status()
  145. # Report a summary of our findings to the user
  146. if status == CheckStatus.OK:
  147. cli.log.info('{fg_green}QMK is ready to go')
  148. return 0
  149. elif status == CheckStatus.WARNING:
  150. cli.log.info('{fg_yellow}QMK is ready to go, but minor problems were found')
  151. return 1
  152. else:
  153. cli.log.info('{fg_red}Major problems detected, please fix these problems before proceeding.')
  154. cli.log.info('{fg_blue}Check out the FAQ (https://docs.qmk.fm/#/faq_build) or join the QMK Discord (https://discord.gg/qmk) for help.')
  155. return 2