summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorZach White <skullydazed@gmail.com>2020-10-17 21:01:11 -0700
committerGitHub <noreply@github.com>2020-10-17 21:01:11 -0700
commit445cd95d1779709673857c36b752afa6327afff1 (patch)
treef722089d82590e624d29776e41431bcaf69e0314 /lib
parent7d5ba88e6f88979c017bf27e2ad0f4c7d912f9ec (diff)
downloadqmk_firmware-445cd95d1779709673857c36b752afa6327afff1.tar.gz
qmk_firmware-445cd95d1779709673857c36b752afa6327afff1.zip
Improve ANSI support and --no-color (#10537)
* Improve ANSI support and --no-color * tweak when levelname gets stripped of ansi * sync with latest milc * make questions work with both milc versions * pyformat
Diffstat (limited to 'lib')
-rw-r--r--lib/python/milc.py78
-rwxr-xr-xlib/python/qmk/cli/doctor.py22
-rw-r--r--lib/python/qmk/questions.py7
3 files changed, 76 insertions, 31 deletions
diff --git a/lib/python/milc.py b/lib/python/milc.py
index eb18984eb3..0cdd43dc89 100644
--- a/lib/python/milc.py
+++ b/lib/python/milc.py
@@ -18,9 +18,11 @@ import logging
import os
import re
import shlex
+import subprocess
import sys
from decimal import Decimal
from pathlib import Path
+from platform import platform
from tempfile import NamedTemporaryFile
from time import sleep
@@ -94,29 +96,54 @@ def format_ansi(text):
return text + ansi_colors['style_reset_all']
-class ANSIFormatter(logging.Formatter):
- """A log formatter that inserts ANSI color.
+class ANSIFormatterMixin(object):
+ """A log formatter mixin that inserts ANSI color.
"""
def format(self, record):
- msg = super(ANSIFormatter, self).format(record)
+ msg = super(ANSIFormatterMixin, self).format(record)
return format_ansi(msg)
-class ANSIEmojiLoglevelFormatter(ANSIFormatter):
- """A log formatter that makes the loglevel an emoji on UTF capable terminals.
+class ANSIStrippingMixin(object):
+ """A log formatter mixin that strips ANSI.
+ """
+ def format(self, record):
+ msg = super(ANSIStrippingMixin, self).format(record)
+ record.levelname = ansi_escape.sub('', record.levelname)
+ return ansi_escape.sub('', msg)
+
+
+class EmojiLoglevelMixin(object):
+ """A log formatter mixin that makes the loglevel an emoji on UTF capable terminals.
"""
def format(self, record):
if UNICODE_SUPPORT:
record.levelname = EMOJI_LOGLEVELS[record.levelname].format(**ansi_colors)
- return super(ANSIEmojiLoglevelFormatter, self).format(record)
+ return super(EmojiLoglevelMixin, self).format(record)
-class ANSIStrippingFormatter(ANSIFormatter):
- """A log formatter that strips ANSI.
+class ANSIFormatter(ANSIFormatterMixin, logging.Formatter):
+ """A log formatter that colorizes output.
"""
- def format(self, record):
- msg = super(ANSIStrippingFormatter, self).format(record)
- return ansi_escape.sub('', msg)
+ pass
+
+
+class ANSIStrippingFormatter(ANSIStrippingMixin, ANSIFormatterMixin, logging.Formatter):
+ """A log formatter that strips ANSI
+ """
+ pass
+
+
+class ANSIEmojiLoglevelFormatter(EmojiLoglevelMixin, ANSIFormatterMixin, logging.Formatter):
+ """A log formatter that adds Emoji and ANSI
+ """
+ pass
+
+
+class ANSIStrippingEmojiLoglevelFormatter(ANSIStrippingMixin, EmojiLoglevelMixin, ANSIFormatterMixin, logging.Formatter):
+ """A log formatter that adds Emoji and strips ANSI
+ """
+ pass
class Configuration(object):
@@ -288,11 +315,12 @@ class MILC(object):
self.config_file = None
self.default_arguments = {}
self.version = 'unknown'
- self.release_lock()
+ self.platform = platform()
# Figure out our program name
self.prog_name = sys.argv[0][:-3] if sys.argv[0].endswith('.py') else sys.argv[0]
self.prog_name = self.prog_name.split('/')[-1]
+ self.release_lock()
# Initialize all the things
self.read_config_file()
@@ -315,6 +343,8 @@ class MILC(object):
strings.
If *args or **kwargs are passed they will be used to %-format the strings.
+
+ If `self.config.general.color` is False any ANSI escape sequences in the text will be stripped.
"""
if args and kwargs:
raise RuntimeError('You can only specify *args or **kwargs, not both!')
@@ -322,8 +352,27 @@ class MILC(object):
args = args or kwargs
text = format_ansi(text)
+ if not self.config.general.color:
+ text = ansi_escape.sub('', text)
+
print(text % args)
+ def run(self, command, *args, **kwargs):
+ """Run a command with subprocess.run
+ The *args and **kwargs arguments get passed directly to `subprocess.run`.
+ """
+ if isinstance(command, str):
+ raise TypeError('`command` must be a non-text sequence such as list or tuple.')
+
+ if 'windows' in self.platform.lower():
+ safecmd = map(shlex.quote, command)
+ safecmd = ' '.join(safecmd)
+ command = [os.environ['SHELL'], '-c', safecmd]
+
+ self.log.debug('Running command: %s', command)
+
+ return subprocess.run(command, *args, **kwargs)
+
def initialize_argparse(self):
"""Prepare to process arguments from sys.argv.
"""
@@ -678,14 +727,13 @@ class MILC(object):
self.log_print_level = logging.DEBUG
self.log_file = self.config['general']['log_file'] or self.log_file
- self.log_file_format = self.config['general']['log_file_fmt']
self.log_file_format = ANSIStrippingFormatter(self.config['general']['log_file_fmt'], self.config['general']['datetime_fmt'])
self.log_format = self.config['general']['log_fmt']
if self.config.general.color:
- self.log_format = ANSIEmojiLoglevelFormatter(self.args.log_fmt, self.config.general.datetime_fmt)
+ self.log_format = ANSIEmojiLoglevelFormatter(self.config.general.log_fmt, self.config.general.datetime_fmt)
else:
- self.log_format = ANSIStrippingFormatter(self.args.log_fmt, self.config.general.datetime_fmt)
+ self.log_format = ANSIStrippingEmojiLoglevelFormatter(self.config.general.log_fmt, self.config.general.datetime_fmt)
if self.log_file:
self.log_file_handler = logging.FileHandler(self.log_file, self.log_file_mode)
diff --git a/lib/python/qmk/cli/doctor.py b/lib/python/qmk/cli/doctor.py
index 7fafd57575..9983865b31 100755
--- a/lib/python/qmk/cli/doctor.py
+++ b/lib/python/qmk/cli/doctor.py
@@ -156,24 +156,16 @@ def check_udev_rules():
_udev_rule("03EB", "2FF3"), # ATmega16U4
_udev_rule("03EB", "2FF4"), # ATmega32U4
_udev_rule("03EB", "2FF9"), # AT90USB64
- _udev_rule("03EB", "2FFB") # AT90USB128
- },
- 'kiibohd': {
- _udev_rule("1C11", "B007")
+ _udev_rule("03EB", "2FFB") # AT90USB128
},
+ 'kiibohd': {_udev_rule("1C11", "B007")},
'stm32': {
_udev_rule("1EAF", "0003"), # STM32duino
- _udev_rule("0483", "DF11") # STM32 DFU
- },
- 'bootloadhid': {
- _udev_rule("16C0", "05DF")
- },
- 'usbasploader': {
- _udev_rule("16C0", "05DC")
- },
- 'massdrop': {
- _udev_rule("03EB", "6124")
+ _udev_rule("0483", "DF11") # STM32 DFU
},
+ 'bootloadhid': {_udev_rule("16C0", "05DF")},
+ 'usbasploader': {_udev_rule("16C0", "05DC")},
+ 'massdrop': {_udev_rule("03EB", "6124")},
'caterina': {
# Spark Fun Electronics
_udev_rule("1B4F", "9203", 'ENV{ID_MM_DEVICE_IGNORE}="1"'), # Pro Micro 3V3/8MHz
@@ -190,7 +182,7 @@ def check_udev_rules():
_udev_rule("239A", "000E", 'ENV{ID_MM_DEVICE_IGNORE}="1"'), # ItsyBitsy 32U4 5V/16MHz
# dog hunter AG
_udev_rule("2A03", "0036", 'ENV{ID_MM_DEVICE_IGNORE}="1"'), # Leonardo
- _udev_rule("2A03", "0037", 'ENV{ID_MM_DEVICE_IGNORE}="1"') # Micro
+ _udev_rule("2A03", "0037", 'ENV{ID_MM_DEVICE_IGNORE}="1"') # Micro
}
}
diff --git a/lib/python/qmk/questions.py b/lib/python/qmk/questions.py
index 27f43ac1e9..865c6bbdc5 100644
--- a/lib/python/qmk/questions.py
+++ b/lib/python/qmk/questions.py
@@ -1,7 +1,12 @@
"""Functions to collect user input.
"""
-from milc import cli, format_ansi
+from milc import cli
+
+try:
+ from milc import format_ansi
+except ImportError:
+ from milc.ansi import format_ansi
def yesno(prompt, *args, default=None, **kwargs):