Quellcode durchsuchen

Fix some errors and make the CLI more understandable

skullY vor 6 Jahren
Ursprung
Commit
d423e193eb

+ 4 - 0
.editorconfig

@@ -16,6 +16,10 @@ insert_final_newline = true
 trim_trailing_whitespace = false
 indent_size = 4
 
+[{qmk,*.py}]
+charset = utf-8
+max_line_length = 200
+
 # Make these match what we have in .gitattributes
 [*.mk]
 end_of_line = lf

+ 38 - 11
bin/qmk

@@ -2,7 +2,10 @@
 """CLI wrapper for running QMK commands.
 """
 import os
+import subprocess
 import sys
+from glob import glob
+from time import strftime
 from importlib import import_module
 
 # Add the QMK python libs to our path
@@ -11,25 +14,49 @@ qmk_dir = os.path.abspath(os.path.join(script_dir, '..'))
 python_lib_dir = os.path.abspath(os.path.join(qmk_dir, 'lib', 'python'))
 sys.path.append(python_lib_dir)
 
+# Figure out our version
+command = ['git', 'describe', '--abbrev=6', '--dirty', '--always', '--tags']
+result = subprocess.run(command, text=True, capture_output=True)
+
+if result.returncode == 0:
+    os.environ['QMK_VERSION'] = 'QMK ' + result.stdout.strip()
+else:
+    os.environ['QMK_VERSION'] = 'QMK ' + strftime('%Y-%m-%d-%H:%M:%S')
+
+# Setup the CLI
+import milc
+milc.EMOJI_LOGLEVELS['INFO'] = '{fg_blue}ψ{style_reset_all}'
+
 # If we were invoked as `qmk <cmd>` massage sys.argv into `qmk-<cmd>`.
 # This means we can't accept arguments to the qmk script itself.
 script_name = os.path.basename(sys.argv[0])
 if script_name == 'qmk':
-    script_name = '-'.join((script_name, sys.argv[1]))
-    if len(sys.argv) > 1:
-        sys.argv = [script_name] + sys.argv[2:]
-    else:
-        sys.argv = [script_name]
+    if len(sys.argv) == 1:
+        milc.cli.log.error('No subcommand specified!\n')
+
+    if len(sys.argv) == 1 or sys.argv[1] in ['-h', '--help']:
+        milc.cli.echo('usage: qmk <subcommand> [...]')
+        milc.cli.echo('\nsubcommands:')
+        subcommands = glob(os.path.join(qmk_dir, 'bin', 'qmk-*'))
+        for subcommand in sorted(subcommands):
+            subcommand = os.path.basename(subcommand).split('-', 1)[1]
+            milc.cli.echo('\t%s', subcommand)
+        milc.cli.echo('\nqmk <subcommand> --help for more information')
+        exit(1)
+
+    if sys.argv[1] in ['-V', '--version']:
+        milc.cli.echo(os.environ['QMK_VERSION'])
+        exit(0)
 
-# Setup the environment
-from milc import cli
+    sys.argv[0] = script_name = '-'.join((script_name, sys.argv[1]))
+    del sys.argv[1]
 
 # Look for which module to import
 if script_name == 'qmk':
-    cli.print_help()
+    milc.cli.print_help()
     exit(0)
 elif not script_name.startswith('qmk-'):
-    cli.log.error('Invalid symlink, must start with "qmk-": %s', script_name)
+    milc.cli.log.error('Invalid symlink, must start with "qmk-": %s', script_name)
 else:
     subcommand = script_name.replace('-', '.').replace('_', '.').split('.')
     subcommand.insert(1, 'cli')
@@ -38,7 +65,7 @@ else:
     try:
         import_module(subcommand)
     except ModuleNotFoundError:
-        cli.log.error('[!] Invalid symlink! Could not import %s.', subcommand)
+        milc.cli.log.error('Invalid subcommand! Could not import %s.', subcommand)
         exit(1)
 
 # Change to the root of our checkout
@@ -46,4 +73,4 @@ os.environ['ORIG_CWD'] = os.getcwd()
 os.chdir(qmk_dir)
 
 if __name__ == '__main__':
-    cli()
+    milc.cli()

+ 4 - 3
lib/python/milc.py

@@ -15,7 +15,7 @@ For more details see the MILC documentation:
 from __future__ import division, print_function, unicode_literals
 import argparse
 import logging
-import os.path
+import os
 import re
 import sys
 from decimal import Decimal
@@ -257,7 +257,7 @@ class MILC(object):
         self.config = Configuration()
         self.config_file = None
         self.prog_name = sys.argv[0][:-3] if sys.argv[0].endswith('.py') else sys.argv[0]
-        self.version = 'unknown'
+        self.version = os.environ.get('QMK_VERSION', 'unknown')
         self.release_lock()
 
         # Initialize all the things
@@ -659,7 +659,8 @@ class MILC(object):
         self._inside_context_manager = False
         self.release_lock()
 
-        if exc_type is not None:
+        if exc_type is not None and not isinstance(SystemExit(), exc_type):
+            print(exc_type)
             logging.exception(exc_val)
             exit(255)
 

+ 9 - 8
lib/python/qmk/cli/compile/json.py

@@ -8,6 +8,7 @@ import subprocess
 from milc import cli
 
 import qmk.keymap
+import qmk.path
 
 
 @cli.argument('filename', help='Configurator JSON export')
@@ -16,22 +17,22 @@ def main(cli):
     # Error checking
     if cli.args.filename == ('-'):
         cli.log.error('Reading from STDIN is not (yet) supported.')
-        cli.print_usage()
-    if not os.path.exists(cli.args.filename):
+        exit(1)
+    if not os.path.exists(qmk.path.normpath(cli.args.filename)):
         cli.log.error('JSON file does not exist!')
-        cli.print_usage()
+        exit(1)
 
     # Parse the configurator json
-    with open(cli.args.filename, 'r') as fd:
+    with open(qmk.path.normpath(cli.args.filename), 'r') as fd:
         user_keymap = json.load(fd)
 
     # Generate the keymap
-    keymap_path = qmk.keymap.find_dir(user_keymap['keyboard'])
-    cli.echo('{fg_blue}[QMK]{style_reset_all} Creating {fg_cyan}%s{style_reset_all} keymap in {fg_cyan}%s', user_keymap['keymap'], keymap_path)
+    keymap_path = qmk.path.keymap(user_keymap['keyboard'])
+    cli.log.info('Creating {fg_cyan}%s{style_reset_all} keymap in {fg_cyan}%s', user_keymap['keymap'], keymap_path)
     qmk.keymap.write(user_keymap['keyboard'], user_keymap['keymap'], user_keymap['layout'], user_keymap['layers'])
-    cli.echo('{fg_blue}[QMK]{style_reset_all} Wrote keymap to {fg_cyan}%s/%s/keymap.c', keymap_path, user_keymap['keymap'])
+    cli.log.info('Wrote keymap to {fg_cyan}%s/%s/keymap.c', keymap_path, user_keymap['keymap'])
 
     # Compile the keymap
     command = ['make', ':'.join((user_keymap['keyboard'], user_keymap['keymap']))]
-    cli.echo('{fg_blue}[QMK]{style_reset_all} Compiling keymap with {fg_cyan}%s\n\n', ' '.join(command))
+    cli.log.info('Compiling keymap with {fg_cyan}%s\n\n', ' '.join(command))
     subprocess.run(command)

+ 1 - 1
lib/python/qmk/cli/hello.py

@@ -8,4 +8,4 @@ from milc import cli
 @cli.argument('-n', '--name', default='World', help='Name to greet.')
 @cli.entrypoint('QMK Python Hello World.')
 def main(cli):
-    cli.echo('Hello, %s!', cli.config.general.name)
+    cli.log.info('Hello, %s!', cli.config.general.name)

+ 10 - 8
lib/python/qmk/cli/json/keymap.py

@@ -9,24 +9,26 @@ from milc import cli
 import qmk.keymap
 
 
-@cli.argument('filename', help='Configurator JSON file')
 @cli.argument('-o', '--output', help='File to write to')
-@cli.entrypoint('Generate a keymap.c from a QMK Configurator export.')
+@cli.argument('filename', help='Configurator JSON file')
+@cli.entrypoint('Create a keymap.c from a QMK Configurator export.')
 def main(cli):
     # Error checking
     if cli.args.filename == ('-'):
         cli.log.error('Reading from STDIN is not (yet) supported.')
         cli.print_usage()
-    if not os.path.exists(cli.args.filename):
+        exit(1)
+    if not os.path.exists(qmk.path.normpath(cli.args.filename)):
         cli.log.error('JSON file does not exist!')
         cli.print_usage()
+        exit(1)
 
     # Environment processing
     if cli.args.output == ('-'):
         cli.args.output = None
 
     # Parse the configurator json
-    with open(cli.args.filename, 'r') as fd:
+    with open(qmk.path.normpath(cli.args.filename), 'r') as fd:
         user_keymap = json.load(fd)
 
     # Generate the keymap
@@ -38,11 +40,11 @@ def main(cli):
         if not os.path.exists(output_dir):
             os.makedirs(output_dir)
 
-        with open(cli.args.output, 'w') as keymap_fd:
+        output_file = qmk.path.normpath(cli.args.output)
+        with open(output_file, 'w') as keymap_fd:
             keymap_fd.write(keymap_c)
 
-        if sys.stdout.isatty():
-            cli.echo('Wrote keymap to %s.', cli.args.output)
+        cli.log.info('Wrote keymap to %s.', cli.args.output)
 
     else:
-        cli.echo(keymap_c)
+        print(keymap_c)

+ 2 - 13
lib/python/qmk/keymap.py

@@ -3,6 +3,7 @@ import logging
 import os
 from traceback import format_exc
 
+import qmk.path
 from qmk.errors import NoSuchKeyboardError
 
 # The `keymap.c` template to use when a keyboard doesn't have its own
@@ -21,18 +22,6 @@ __KEYMAP_GOES_HERE__
 
 
 # Helper Functions
-def find_dir(keyboard):
-    """Locate the correct directory for storing a keymap.
-    """
-    for directory in ['.', '..', '../..', '../../..', '../../../..', '../../../../..']:
-        basepath = os.path.normpath(os.path.join('keyboards', keyboard, directory, 'keymaps'))
-        if os.path.exists(basepath):
-            return basepath
-
-    logging.error('Could not find keymaps directory!')
-    raise NoSuchKeyboardError('Could not find keymaps directory for: %s' % keyboard)
-
-
 def template(keyboard, keymap):
     """Returns the `keymap.c` template for a keyboard.
 
@@ -68,7 +57,7 @@ def write(keyboard, keymap, layout, layers):
     """Generate the `keymap.c` and write it to disk.
     """
     keymap_c = generate(keyboard, layout, layers)
-    keymap_path = find_dir(keyboard)
+    keymap_path = qmk.path.keymap(keyboard)
     keymap_dir = os.path.join(keymap_path, keymap)
     keymap_file = os.path.join(keymap_dir, 'keymap.c')
 

+ 28 - 0
lib/python/qmk/path.py

@@ -0,0 +1,28 @@
+"""Functions that help us work with files and folders.
+"""
+import os
+
+
+def keymap(keyboard):
+    """Locate the correct directory for storing a keymap.
+    """
+    for directory in ['.', '..', '../..', '../../..', '../../../..', '../../../../..']:
+        basepath = os.path.normpath(os.path.join('keyboards', keyboard, directory, 'keymaps'))
+
+        if os.path.exists(basepath):
+            return basepath
+
+    logging.error('Could not find keymaps directory!')
+    raise NoSuchKeyboardError('Could not find keymaps directory for: %s' % keyboard)
+
+
+def normpath(path):
+    """Returns the fully resolved absolute path to a file.
+
+    This function will return the absolute path to a file as seen from the
+    directory the script was called from.
+    """
+    if path and path[0] == '/':
+        return os.path.normpath(path)
+
+    return os.path.normpath(os.path.join(os.environ['ORIG_CWD'], path))