Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve ANSI support and --no-color #10537

Merged
merged 5 commits into from
Oct 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 63 additions & 15 deletions lib/python/milc.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
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

Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -288,11 +315,12 @@ def __init__(self):
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()
Expand All @@ -315,15 +343,36 @@ def echo(self, text, *args, **kwargs):
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!')

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.
"""
Expand Down Expand Up @@ -678,14 +727,13 @@ def setup_logging(self):
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)
Expand Down
22 changes: 7 additions & 15 deletions lib/python/qmk/cli/doctor.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
}

Expand Down
7 changes: 6 additions & 1 deletion lib/python/qmk/questions.py
Original file line number Diff line number Diff line change
@@ -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):
Expand Down