summaryrefslogtreecommitdiff
path: root/lib/python/qmk/cli
diff options
context:
space:
mode:
authorZach White <skullydazed@gmail.com>2021-05-10 12:16:04 -0700
committerZach White <skullydazed@gmail.com>2021-05-10 12:16:04 -0700
commit0e7c66e8917ee470d8a3d3904bd8b55c75c8a0b4 (patch)
treee53a16e0631ac22b68a66bd219d0ff3c107b36ee /lib/python/qmk/cli
parent911b45ce3bcc2cf4c7e12ccf8df7da9621173e32 (diff)
parentbc38c38f8c25dcbe759bc4d9d707a0069b3c6c59 (diff)
Merge remote-tracking branch 'origin/master' into develop
Conflicts: bin/qmk lib/python/qmk/cli/__init__.py Merge conflicts fixed by skullydazed.
Diffstat (limited to 'lib/python/qmk/cli')
-rw-r--r--lib/python/qmk/cli/__init__.py149
1 files changed, 124 insertions, 25 deletions
diff --git a/lib/python/qmk/cli/__init__.py b/lib/python/qmk/cli/__init__.py
index e7a5d5cd84..1fe0657206 100644
--- a/lib/python/qmk/cli/__init__.py
+++ b/lib/python/qmk/cli/__init__.py
@@ -2,34 +2,81 @@
We list each subcommand here explicitly because all the reliable ways of searching for modules are slow and delay startup.
"""
+import os
+import shlex
import sys
+from importlib.util import find_spec
+from pathlib import Path
+from subprocess import run
from milc import cli, __VERSION__
+from milc.questions import yesno
-from . import c2json
-from . import cformat
-from . import chibios
-from . import clean
-from . import compile
-from . import config
-from . import console
-from . import docs
-from . import doctor
-from . import fileformat
-from . import flash
-from . import format
-from . import generate
-from . import hello
-from . import info
-from . import json2c
-from . import lint
-from . import list
-from . import kle2json
-from . import multibuild
-from . import new
-from . import pyformat
-from . import pytest
+def _run_cmd(*command):
+ """Run a command in a subshell.
+ """
+ if 'windows' in cli.platform.lower():
+ safecmd = map(shlex.quote, command)
+ safecmd = ' '.join(safecmd)
+ command = [os.environ['SHELL'], '-c', safecmd]
+
+ return run(command)
+
+
+def _find_broken_requirements(requirements):
+ """ Check if the modules in the given requirements.txt are available.
+
+ Args:
+
+ requirements
+ The path to a requirements.txt file
+
+ Returns a list of modules that couldn't be imported
+ """
+ with Path(requirements).open() as fd:
+ broken_modules = []
+
+ for line in fd.readlines():
+ line = line.strip().replace('<', '=').replace('>', '=')
+
+ if len(line) == 0 or line[0] == '#' or line.startswith('-r'):
+ continue
+
+ if '#' in line:
+ line = line.split('#')[0]
+
+ module_name = line.split('=')[0] if '=' in line else line
+ module_import = module_name.replace('-', '_')
+
+ # Not every module is importable by its own name.
+ if module_name == "pep8-naming":
+ module_import = "pep8ext_naming"
+ elif module_name == 'pyusb':
+ module_import = 'usb.core'
+
+ if not find_spec(module_import):
+ broken_modules.append(module_name)
+
+ return broken_modules
+
+
+def _broken_module_imports(requirements):
+ """Make sure we can import all the python modules.
+ """
+ broken_modules = _find_broken_requirements(requirements)
+
+ for module in broken_modules:
+ print('Could not find module %s!' % module)
+
+ if broken_modules:
+ return True
+
+ return False
+
+
+# Make sure our python is new enough
+#
# Supported version information
#
# Based on the OSes we support these are the minimum python version available by default.
@@ -55,9 +102,61 @@ if sys.version_info[0] != 3 or sys.version_info[1] < 7:
milc_version = __VERSION__.split('.')
if int(milc_version[0]) < 2 and int(milc_version[1]) < 3:
- from pathlib import Path
-
requirements = Path('requirements.txt').resolve()
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.'
+
+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:
+ args = sys.argv[1:]
+ while args and args[0][0] == '-':
+ del args[0]
+ if not args or args[0] != 'config':
+ if _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')
+ elif yesno('Would you like to disable developer mode?'):
+ _run_cmd(sys.argv[0], 'config', 'user.developer=None')
+ else:
+ print()
+ print(msg_install % (str(Path('requirements-dev.txt').resolve()),))
+ print('You can also turn off developer mode: qmk config user.developer=None')
+ print()
+ exit(1)
+
+# Import our subcommands
+from . import c2json # noqa
+from . import cformat # noqa
+from . import chibios # noqa
+from . import clean # noqa
+from . import compile # noqa
+from . import config # noqa
+from . import console # noqa
+from . import docs # noqa
+from . import doctor # noqa
+from . import fileformat # noqa
+from . import flash # noqa
+from . import format # noqa
+from . import generate # noqa
+from . import hello # noqa
+from . import info # noqa
+from . import json2c # noqa
+from . import lint # noqa
+from . import list # noqa
+from . import kle2json # noqa
+from . import multibuild # noqa
+from . import new # noqa
+from . import pyformat # noqa
+from . import pytest # noqa