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
This commit is contained in:
parent
7d5ba88e6f
commit
445cd95d17
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue