def setup(cli): """Guide the user through setting up their QMK environment. """ clone_prompt = 'Would you like to clone {fg_cyan}%s{fg_reset} to {fg_cyan}%s{fg_reset}?' % ( cli.args.fork, shlex.quote(str(cli.args.home))) home_prompt = 'Would you like to set {fg_cyan}%s{fg_reset} as your QMK home?' % ( shlex.quote(str(cli.args.home)), ) # Sanity checks if cli.args.yes and cli.args.no: cli.log.error("Can't use both --yes and --no at the same time.") exit(1) # Check on qmk_firmware, and if it doesn't exist offer to check it out. if is_qmk_firmware(cli.args.home): cli.log.info('Found qmk_firmware at %s.', str(cli.args.home)) elif cli.args.home.exists(): path_str = str(cli.args.home) if cli.args.home.name != 'qmk_firmware': cli.log.warning( 'Warning: %s does not end in "qmk_firmware". Did you mean to use "--home %s/qmk_firmware"?' % (path_str, path_str)) cli.log.error("Path '%s' exists but is not a qmk_firmware clone!", path_str) exit(1) else: cli.log.error('Could not find qmk_firmware!') if yesno(clone_prompt): git_url = '/'.join((cli.config.setup.baseurl, cli.args.fork)) if git_clone(git_url, cli.args.home, cli.config.setup.branch): git_upstream(cli.args.home) else: exit(1) # Offer to set `user.qmk_home` for them. if str(cli.args.home) != os.environ['QMK_HOME'] and yesno(home_prompt): cli.config['user']['qmk_home'] = str(cli.args.home.absolute()) cli.config_source['user']['qmk_home'] = 'config_file' cli.write_config_option('user', 'qmk_home') # Run `qmk doctor` to check the rest of the environment out color = '--color' if cli.config.general.color else '--no-color' unicode = '--unicode' if cli.config.general.unicode else '--no-unicode' doctor_command = [Path(sys.argv[0]).as_posix(), color, unicode, 'doctor'] if cli.args.no: doctor_command.append('--no') if cli.args.yes: doctor_command.append('--yes') cli.run(doctor_command, stdin=None, capture_output=False)
def setup(cli): """Guide the user through setting up their QMK environment. """ clone_prompt = 'Would you like to clone {fg_cyan}%s{fg_reset} to {fg_cyan}%s{fg_reset}?' % ( cli.args.fork, shlex.quote(str(cli.args.home))) home_prompt = 'Would you like to set {fg_cyan}%s{fg_reset} as your QMK home?' % ( shlex.quote(str(cli.args.home)), ) # Sanity checks if cli.args.yes and cli.args.no: cli.log.error("Can't use both --yes and --no at the same time.") exit(1) # Check on qmk_firmware, and if it doesn't exist offer to check it out. if (cli.args.home / 'Makefile').exists(): cli.log.info('Found qmk_firmware at %s.', str(cli.args.home)) else: cli.log.error('Could not find qmk_firmware!') if yesno(clone_prompt): git_url = '/'.join((cli.config.setup.baseurl, cli.args.fork)) if git_clone(git_url, cli.args.home, cli.config.setup.branch): git_upstream(cli.args.home) else: exit(1) # Offer to set `user.qmk_home` for them. if cli.args.home != Path(os.environ['QMK_HOME']) and yesno(home_prompt): cli.config['user']['qmk_home'] = str(cli.args.home.absolute()) cli.write_config_option('user', 'qmk_home') # Run `qmk_firmware/bin/qmk doctor` to check the rest of the environment out qmk_bin = cli.args.home / 'bin/qmk' doctor_cmd = [sys.executable, qmk_bin.as_posix(), 'doctor'] if cli.args.yes: doctor_cmd.append('--yes') if cli.args.no: doctor_cmd.append('--no') subprocess.run(doctor_cmd)
def doctor(cli): """Basic QMK environment checks. This is currently very simple, it just checks that all the expected binaries are on your system. TODO(unclaimed): * [ ] Compile a trivial program with each compiler """ cli.log.info('QMK Doctor is checking your environment.') status = os_tests() cli.log.info('QMK home: {fg_cyan}%s', QMK_FIRMWARE) # Make sure our QMK home is a Git repo git_ok = check_git_repo() if git_ok == CheckStatus.WARNING: cli.log.warning( "QMK home does not appear to be a Git repository! (no .git folder)" ) status = CheckStatus.WARNING # Make sure the basic CLI tools we need are available and can be executed. bin_ok = check_binaries() if not bin_ok: if yesno('Would you like to install dependencies?', default=True): run(['util/qmk_install.sh']) bin_ok = check_binaries() if bin_ok: cli.log.info('All dependencies are installed.') else: status = CheckStatus.ERROR # Make sure the tools are at the correct version ver_ok = check_binary_versions() if CheckStatus.ERROR in ver_ok: status = CheckStatus.ERROR elif CheckStatus.WARNING in ver_ok and status == CheckStatus.OK: status = CheckStatus.WARNING # Check out the QMK submodules sub_ok = check_submodules() if sub_ok == CheckStatus.OK: cli.log.info('Submodules are up to date.') else: if yesno('Would you like to clone the submodules?', default=True): submodules.update() sub_ok = check_submodules() if sub_ok == CheckStatus.ERROR: status = CheckStatus.ERROR elif sub_ok == CheckStatus.WARNING and status == CheckStatus.OK: status = CheckStatus.WARNING # Report a summary of our findings to the user if status == CheckStatus.OK: cli.log.info('{fg_green}QMK is ready to go') return 0 elif status == CheckStatus.WARNING: cli.log.info( '{fg_yellow}QMK is ready to go, but minor problems were found') return 1 else: cli.log.info( '{fg_red}Major problems detected, please fix these problems before proceeding.' ) cli.log.info( '{fg_blue}Check out the FAQ (https://docs.qmk.fm/#/faq_build) or join the QMK Discord (https://discord.gg/Uq7gcHh) for help.' ) return 2
print( f'Your MILC library is too old! Please upgrade: python3 -m pip install -U -r {str(requirements)}' ) exit(127) # Check to make sure we have all our dependencies msg_install = 'Please run `python3 -m pip install -r %s` to install required python dependencies.' args = sys.argv[1:] while args and args[0][0] == '-': del args[0] safe_command = args and args[0] in safe_commands if not safe_command: if _broken_module_imports('requirements.txt'): if yesno('Would you like to install the required Python modules?'): _run_cmd(sys.executable, '-m', 'pip', 'install', '-r', 'requirements.txt') else: print() print(msg_install % (str(Path('requirements.txt').resolve()), )) print() exit(1) if cli.config.user.developer and _broken_module_imports( 'requirements-dev.txt'): if yesno( 'Would you like to install the required developer Python modules?' ): _run_cmd(sys.executable, '-m', 'pip', 'install', '-r', 'requirements-dev.txt')
def main(): """Setup the environment before dispatching to the entrypoint. """ # Warn if they use an outdated python version if sys.version_info < (3, 7): print( 'Warning: Your Python version is out of date! Some subcommands may not work!' ) print('Please upgrade to Python 3.7 or later.') if 'windows' in platform().lower(): msystem = os.environ.get('MSYSTEM', '') if 'mingw64' not in sys.executable or 'MINGW64' not in msystem: print('ERROR: It seems you are not using the MINGW64 terminal.') print( 'Please close this terminal and open a new MSYS2 MinGW 64-bit terminal.' ) print('Python: %s, MSYSTEM: %s' % (sys.executable, msystem)) exit(1) # Environment setup import qmk_cli milc.cli.version = qmk_cli.__version__ qmk_firmware = find_qmk_firmware() os.environ['QMK_HOME'] = str(qmk_firmware) os.environ['ORIG_CWD'] = os.getcwd() import qmk_cli.subcommands # Check out and initialize the qmk_firmware environment if is_qmk_firmware(qmk_firmware): # All subcommands are run relative to the qmk_firmware root to make it easier to use the right copy of qmk_firmware. os.chdir(str(qmk_firmware)) # Check to make sure we have all the requirements broken_modules, broken_dev_modules = broken_module_imports() msg_install = 'Please run `python3 -m pip install -r %s` to install required python dependencies.' if broken_modules: if yesno('Would you like to install the required Python modules?'): run_cmd(sys.executable, '-m', 'pip', 'install', '-r', 'requirements.txt') else: print() print(msg_install % (os.environ['QMK_HOME'] + '/requirements.txt', )) print() exit(1) if broken_dev_modules: if yesno( 'Would you like to install the required developer Python modules?' ): run_cmd(sys.executable, '-m', 'pip', 'install', '-r', 'requirements.txt') else: print() print(msg_install % (os.environ['QMK_HOME'] + '/requirements-dev.txt', )) print( 'You can also turn off developer mode: qmk config user.developer=None' ) print() exit(1) # Environment looks good, include the qmk_firmware subcommands sys.path.append(str(qmk_firmware / 'lib/python')) try: import qmk.cli # noqa except ImportError as e: if qmk_firmware.name != 'qmk_firmware': print( 'Warning: %s does not end in "qmk_firmware". Do you need to set QMK_HOME to "%s/qmk_firmware"?' % (qmk_firmware, qmk_firmware)) print('Error: %s: %s', (e.__class__.__name__, e)) print_exc() sys.exit(1) # Call the entrypoint return_code = milc.cli() if return_code is False: exit(1) elif return_code is not True and isinstance(return_code, int): if return_code < 0 or return_code > 255: milc.cli.log.error('Invalid return_code: %d', return_code) exit(255) exit(return_code) exit(0)
def doctor(cli): """Basic QMK environment checks. This is currently very simple, it just checks that all the expected binaries are on your system. TODO(unclaimed): * [ ] Compile a trivial program with each compiler """ cli.log.info('QMK Doctor is checking your environment.') status = CheckStatus.OK # Determine our OS and run platform specific tests platform_id = platform.platform().lower() if 'darwin' in platform_id or 'macos' in platform_id: status = os_test_macos() elif 'linux' in platform_id: status = os_test_linux() elif 'windows' in platform_id: status = os_test_windows() else: cli.log.warning('Unsupported OS detected: %s', platform_id) status = CheckStatus.WARNING cli.log.info('QMK home: {fg_cyan}%s', QMK_FIRMWARE) # Make sure the basic CLI tools we need are available and can be executed. bin_ok = check_binaries() if not bin_ok: if yesno('Would you like to install dependencies?', default=True): run(['util/qmk_install.sh']) bin_ok = check_binaries() if bin_ok: cli.log.info('All dependencies are installed.') else: status = CheckStatus.ERROR # Make sure the tools are at the correct version ver_ok = [] for check in (check_arm_gcc_version, check_avr_gcc_version, check_avrdude_version, check_dfu_util_version, check_dfu_programmer_version): ver_ok.append(check()) if CheckStatus.ERROR in ver_ok: status = CheckStatus.ERROR elif CheckStatus.WARNING in ver_ok and status == CheckStatus.OK: status = CheckStatus.WARNING # Check out the QMK submodules sub_ok = check_submodules() if sub_ok == CheckStatus.OK: cli.log.info('Submodules are up to date.') else: if yesno('Would you like to clone the submodules?', default=True): submodules.update() sub_ok = check_submodules() if CheckStatus.ERROR in sub_ok: status = CheckStatus.ERROR elif CheckStatus.WARNING in sub_ok and status == CheckStatus.OK: status = CheckStatus.WARNING # Report a summary of our findings to the user if status == CheckStatus.OK: cli.log.info('{fg_green}QMK is ready to go') return 0 elif status == CheckStatus.WARNING: cli.log.info('{fg_yellow}QMK is ready to go, but minor problems were found') return 1 else: cli.log.info('{fg_red}Major problems detected, please fix these problems before proceeding.') cli.log.info('{fg_blue}Check out the FAQ (https://docs.qmk.fm/#/faq_build) or join the QMK Discord (https://discord.gg/Uq7gcHh) for help.') return 2
def _yesno(*args): """Wrapper to only prompt if interactive """ return sys.stdout.isatty() and yesno(*args)