diff options
| author | Zach White <skullydazed@gmail.com> | 2021-05-10 12:00:52 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-05-10 12:00:52 -0700 |
| commit | bc38c38f8c25dcbe759bc4d9d707a0069b3c6c59 (patch) | |
| tree | 57cf7b2c3a9953a52ac333819d934687290d4f4b /lib | |
| parent | a3e7f3e7c58ee98596ead5c213f3a9ed8340cd80 (diff) | |
| download | qmk_firmware-bc38c38f8c25dcbe759bc4d9d707a0069b3c6c59.tar.gz qmk_firmware-bc38c38f8c25dcbe759bc4d9d707a0069b3c6c59.zip | |
Move the module checking and updating to lib/python (#12416)
* move the module checking and updating to lib/python
* make flake8 happy
* Update lib/python/qmk/cli/__init__.py
Co-authored-by: Erovia <Erovia@users.noreply.github.com>
* prompt the user to disable developer mode
* pyformat
* flake8
Co-authored-by: Erovia <Erovia@users.noreply.github.com>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/python/qmk/cli/__init__.py | 145 |
1 files changed, 121 insertions, 24 deletions
diff --git a/lib/python/qmk/cli/__init__.py b/lib/python/qmk/cli/__init__.py index 008e57f76..6fe769fe7 100644 --- a/lib/python/qmk/cli/__init__.py +++ b/lib/python/qmk/cli/__init__.py | |||
| @@ -2,33 +2,79 @@ | |||
| 2 | 2 | ||
| 3 | We list each subcommand here explicitly because all the reliable ways of searching for modules are slow and delay startup. | 3 | We list each subcommand here explicitly because all the reliable ways of searching for modules are slow and delay startup. |
| 4 | """ | 4 | """ |
| 5 | import os | ||
| 6 | import shlex | ||
| 5 | import sys | 7 | import sys |
| 8 | from importlib.util import find_spec | ||
| 9 | from pathlib import Path | ||
| 10 | from subprocess import run | ||
| 6 | 11 | ||
| 7 | from milc import cli, __VERSION__ | 12 | from milc import cli, __VERSION__ |
| 13 | from milc.questions import yesno | ||
| 8 | 14 | ||
| 9 | from . import c2json | ||
| 10 | from . import cformat | ||
| 11 | from . import chibios | ||
| 12 | from . import clean | ||
| 13 | from . import compile | ||
| 14 | from . import config | ||
| 15 | from . import docs | ||
| 16 | from . import doctor | ||
| 17 | from . import fileformat | ||
| 18 | from . import flash | ||
| 19 | from . import format | ||
| 20 | from . import generate | ||
| 21 | from . import hello | ||
| 22 | from . import info | ||
| 23 | from . import json2c | ||
| 24 | from . import lint | ||
| 25 | from . import list | ||
| 26 | from . import kle2json | ||
| 27 | from . import multibuild | ||
| 28 | from . import new | ||
| 29 | from . import pyformat | ||
| 30 | from . import pytest | ||
| 31 | 15 | ||
| 16 | def _run_cmd(*command): | ||
| 17 | """Run a command in a subshell. | ||
| 18 | """ | ||
| 19 | if 'windows' in cli.platform.lower(): | ||
| 20 | safecmd = map(shlex.quote, command) | ||
| 21 | safecmd = ' '.join(safecmd) | ||
| 22 | command = [os.environ['SHELL'], '-c', safecmd] | ||
| 23 | |||
| 24 | return run(command) | ||
| 25 | |||
| 26 | |||
| 27 | def _find_broken_requirements(requirements): | ||
| 28 | """ Check if the modules in the given requirements.txt are available. | ||
| 29 | |||
| 30 | Args: | ||
| 31 | |||
| 32 | requirements | ||
| 33 | The path to a requirements.txt file | ||
| 34 | |||
| 35 | Returns a list of modules that couldn't be imported | ||
| 36 | """ | ||
| 37 | with Path(requirements).open() as fd: | ||
| 38 | broken_modules = [] | ||
| 39 | |||
| 40 | for line in fd.readlines(): | ||
| 41 | line = line.strip().replace('<', '=').replace('>', '=') | ||
| 42 | |||
| 43 | if len(line) == 0 or line[0] == '#' or line.startswith('-r'): | ||
| 44 | continue | ||
| 45 | |||
| 46 | if '#' in line: | ||
| 47 | line = line.split('#')[0] | ||
| 48 | |||
| 49 | module_name = line.split('=')[0] if '=' in line else line | ||
| 50 | module_import = module_name.replace('-', '_') | ||
| 51 | |||
| 52 | # Not every module is importable by its own name. | ||
| 53 | if module_name == "pep8-naming": | ||
| 54 | module_import = "pep8ext_naming" | ||
| 55 | |||
| 56 | if not find_spec(module_import): | ||
| 57 | broken_modules.append(module_name) | ||
| 58 | |||
| 59 | return broken_modules | ||
| 60 | |||
| 61 | |||
| 62 | def _broken_module_imports(requirements): | ||
| 63 | """Make sure we can import all the python modules. | ||
| 64 | """ | ||
| 65 | broken_modules = _find_broken_requirements(requirements) | ||
| 66 | |||
| 67 | for module in broken_modules: | ||
| 68 | print('Could not find module %s!' % module) | ||
| 69 | |||
| 70 | if broken_modules: | ||
| 71 | return True | ||
| 72 | |||
| 73 | return False | ||
| 74 | |||
| 75 | |||
| 76 | # Make sure our python is new enough | ||
| 77 | # | ||
| 32 | # Supported version information | 78 | # Supported version information |
| 33 | # | 79 | # |
| 34 | # Based on the OSes we support these are the minimum python version available by default. | 80 | # Based on the OSes we support these are the minimum python version available by default. |
| @@ -54,9 +100,60 @@ if sys.version_info[0] != 3 or sys.version_info[1] < 7: | |||
| 54 | milc_version = __VERSION__.split('.') | 100 | milc_version = __VERSION__.split('.') |
| 55 | 101 | ||
| 56 | if int(milc_version[0]) < 2 and int(milc_version[1]) < 3: | 102 | if int(milc_version[0]) < 2 and int(milc_version[1]) < 3: |
| 57 | from pathlib import Path | ||
| 58 | |||
| 59 | requirements = Path('requirements.txt').resolve() | 103 | requirements = Path('requirements.txt').resolve() |
| 60 | 104 | ||
| 61 | print(f'Your MILC library is too old! Please upgrade: python3 -m pip install -U -r {str(requirements)}') | 105 | print(f'Your MILC library is too old! Please upgrade: python3 -m pip install -U -r {str(requirements)}') |
| 62 | exit(127) | 106 | exit(127) |
| 107 | |||
| 108 | # Check to make sure we have all our dependencies | ||
| 109 | msg_install = 'Please run `python3 -m pip install -r %s` to install required python dependencies.' | ||
| 110 | |||
| 111 | if _broken_module_imports('requirements.txt'): | ||
| 112 | if yesno('Would you like to install the required Python modules?'): | ||
| 113 | _run_cmd(sys.executable, '-m', 'pip', 'install', '-r', 'requirements.txt') | ||
| 114 | else: | ||
| 115 | print() | ||
| 116 | print(msg_install % (str(Path('requirements.txt').resolve()),)) | ||
| 117 | print() | ||
| 118 | exit(1) | ||
| 119 | |||
| 120 | if cli.config.user.developer: | ||
| 121 | args = sys.argv[1:] | ||
| 122 | while args and args[0][0] == '-': | ||
| 123 | del args[0] | ||
| 124 | if not args or args[0] != 'config': | ||
| 125 | if _broken_module_imports('requirements-dev.txt'): | ||
| 126 | if yesno('Would you like to install the required developer Python modules?'): | ||
| 127 | _run_cmd(sys.executable, '-m', 'pip', 'install', '-r', 'requirements-dev.txt') | ||
| 128 | elif yesno('Would you like to disable developer mode?'): | ||
| 129 | _run_cmd(sys.argv[0], 'config', 'user.developer=None') | ||
| 130 | else: | ||
| 131 | print() | ||
| 132 | print(msg_install % (str(Path('requirements-dev.txt').resolve()),)) | ||
| 133 | print('You can also turn off developer mode: qmk config user.developer=None') | ||
| 134 | print() | ||
| 135 | exit(1) | ||
| 136 | |||
| 137 | # Import our subcommands | ||
| 138 | from . import c2json # noqa | ||
| 139 | from . import cformat # noqa | ||
| 140 | from . import chibios # noqa | ||
| 141 | from . import clean # noqa | ||
| 142 | from . import compile # noqa | ||
| 143 | from . import config # noqa | ||
| 144 | from . import docs # noqa | ||
| 145 | from . import doctor # noqa | ||
| 146 | from . import fileformat # noqa | ||
| 147 | from . import flash # noqa | ||
| 148 | from . import format # noqa | ||
| 149 | from . import generate # noqa | ||
| 150 | from . import hello # noqa | ||
| 151 | from . import info # noqa | ||
| 152 | from . import json2c # noqa | ||
| 153 | from . import lint # noqa | ||
| 154 | from . import list # noqa | ||
| 155 | from . import kle2json # noqa | ||
| 156 | from . import multibuild # noqa | ||
| 157 | from . import new # noqa | ||
| 158 | from . import pyformat # noqa | ||
| 159 | from . import pytest # noqa | ||
