diff options
author | Zach White <skullydazed@gmail.com> | 2020-10-17 21:01:11 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-17 21:01:11 -0700 |
commit | 445cd95d1779709673857c36b752afa6327afff1 (patch) | |
tree | f722089d82590e624d29776e41431bcaf69e0314 /lib/python/milc.py | |
parent | 7d5ba88e6f88979c017bf27e2ad0f4c7d912f9ec (diff) | |
download | qmk_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/python/milc.py')
-rw-r--r-- | lib/python/milc.py | 78 |
1 files changed, 63 insertions, 15 deletions
diff --git a/lib/python/milc.py b/lib/python/milc.py index eb18984eb..0cdd43dc8 100644 --- a/lib/python/milc.py +++ b/lib/python/milc.py | |||
@@ -18,9 +18,11 @@ import logging | |||
18 | import os | 18 | import os |
19 | import re | 19 | import re |
20 | import shlex | 20 | import shlex |
21 | import subprocess | ||
21 | import sys | 22 | import sys |
22 | from decimal import Decimal | 23 | from decimal import Decimal |
23 | from pathlib import Path | 24 | from pathlib import Path |
25 | from platform import platform | ||
24 | from tempfile import NamedTemporaryFile | 26 | from tempfile import NamedTemporaryFile |
25 | from time import sleep | 27 | from time import sleep |
26 | 28 | ||
@@ -94,29 +96,54 @@ def format_ansi(text): | |||
94 | return text + ansi_colors['style_reset_all'] | 96 | return text + ansi_colors['style_reset_all'] |
95 | 97 | ||
96 | 98 | ||
97 | class ANSIFormatter(logging.Formatter): | 99 | class ANSIFormatterMixin(object): |
98 | """A log formatter that inserts ANSI color. | 100 | """A log formatter mixin that inserts ANSI color. |
99 | """ | 101 | """ |
100 | def format(self, record): | 102 | def format(self, record): |
101 | msg = super(ANSIFormatter, self).format(record) | 103 | msg = super(ANSIFormatterMixin, self).format(record) |
102 | return format_ansi(msg) | 104 | return format_ansi(msg) |
103 | 105 | ||
104 | 106 | ||
105 | class ANSIEmojiLoglevelFormatter(ANSIFormatter): | 107 | class ANSIStrippingMixin(object): |
106 | """A log formatter that makes the loglevel an emoji on UTF capable terminals. | 108 | """A log formatter mixin that strips ANSI. |
109 | """ | ||
110 | def format(self, record): | ||
111 | msg = super(ANSIStrippingMixin, self).format(record) | ||
112 | record.levelname = ansi_escape.sub('', record.levelname) | ||
113 | return ansi_escape.sub('', msg) | ||
114 | |||
115 | |||
116 | class EmojiLoglevelMixin(object): | ||
117 | """A log formatter mixin that makes the loglevel an emoji on UTF capable terminals. | ||
107 | """ | 118 | """ |
108 | def format(self, record): | 119 | def format(self, record): |
109 | if UNICODE_SUPPORT: | 120 | if UNICODE_SUPPORT: |
110 | record.levelname = EMOJI_LOGLEVELS[record.levelname].format(**ansi_colors) | 121 | record.levelname = EMOJI_LOGLEVELS[record.levelname].format(**ansi_colors) |
111 | return super(ANSIEmojiLoglevelFormatter, self).format(record) | 122 | return super(EmojiLoglevelMixin, self).format(record) |
112 | 123 | ||
113 | 124 | ||
114 | class ANSIStrippingFormatter(ANSIFormatter): | 125 | class ANSIFormatter(ANSIFormatterMixin, logging.Formatter): |
115 | """A log formatter that strips ANSI. | 126 | """A log formatter that colorizes output. |
116 | """ | 127 | """ |
117 | def format(self, record): | 128 | pass |
118 | msg = super(ANSIStrippingFormatter, self).format(record) | 129 | |
119 | return ansi_escape.sub('', msg) | 130 | |
131 | class ANSIStrippingFormatter(ANSIStrippingMixin, ANSIFormatterMixin, logging.Formatter): | ||
132 | """A log formatter that strips ANSI | ||
133 | """ | ||
134 | pass | ||
135 | |||
136 | |||
137 | class ANSIEmojiLoglevelFormatter(EmojiLoglevelMixin, ANSIFormatterMixin, logging.Formatter): | ||
138 | """A log formatter that adds Emoji and ANSI | ||
139 | """ | ||
140 | pass | ||
141 | |||
142 | |||
143 | class ANSIStrippingEmojiLoglevelFormatter(ANSIStrippingMixin, EmojiLoglevelMixin, ANSIFormatterMixin, logging.Formatter): | ||
144 | """A log formatter that adds Emoji and strips ANSI | ||
145 | """ | ||
146 | pass | ||
120 | 147 | ||
121 | 148 | ||
122 | class Configuration(object): | 149 | class Configuration(object): |
@@ -288,11 +315,12 @@ class MILC(object): | |||
288 | self.config_file = None | 315 | self.config_file = None |
289 | self.default_arguments = {} | 316 | self.default_arguments = {} |
290 | self.version = 'unknown' | 317 | self.version = 'unknown' |
291 | self.release_lock() | 318 | self.platform = platform() |
292 | 319 | ||
293 | # Figure out our program name | 320 | # Figure out our program name |
294 | self.prog_name = sys.argv[0][:-3] if sys.argv[0].endswith('.py') else sys.argv[0] | 321 | self.prog_name = sys.argv[0][:-3] if sys.argv[0].endswith('.py') else sys.argv[0] |
295 | self.prog_name = self.prog_name.split('/')[-1] | 322 | self.prog_name = self.prog_name.split('/')[-1] |
323 | self.release_lock() | ||
296 | 324 | ||
297 | # Initialize all the things | 325 | # Initialize all the things |
298 | self.read_config_file() | 326 | self.read_config_file() |
@@ -315,6 +343,8 @@ class MILC(object): | |||
315 | strings. | 343 | strings. |
316 | 344 | ||
317 | If *args or **kwargs are passed they will be used to %-format the strings. | 345 | If *args or **kwargs are passed they will be used to %-format the strings. |
346 | |||
347 | If `self.config.general.color` is False any ANSI escape sequences in the text will be stripped. | ||
318 | """ | 348 | """ |
319 | if args and kwargs: | 349 | if args and kwargs: |
320 | raise RuntimeError('You can only specify *args or **kwargs, not both!') | 350 | raise RuntimeError('You can only specify *args or **kwargs, not both!') |
@@ -322,8 +352,27 @@ class MILC(object): | |||
322 | args = args or kwargs | 352 | args = args or kwargs |
323 | text = format_ansi(text) | 353 | text = format_ansi(text) |
324 | 354 | ||
355 | if not self.config.general.color: | ||
356 | text = ansi_escape.sub('', text) | ||
357 | |||
325 | print(text % args) | 358 | print(text % args) |
326 | 359 | ||
360 | def run(self, command, *args, **kwargs): | ||
361 | """Run a command with subprocess.run | ||
362 | The *args and **kwargs arguments get passed directly to `subprocess.run`. | ||
363 | """ | ||
364 | if isinstance(command, str): | ||
365 | raise TypeError('`command` must be a non-text sequence such as list or tuple.') | ||
366 | |||
367 | if 'windows' in self.platform.lower(): | ||
368 | safecmd = map(shlex.quote, command) | ||
369 | safecmd = ' '.join(safecmd) | ||
370 | command = [os.environ['SHELL'], '-c', safecmd] | ||
371 | |||
372 | self.log.debug('Running command: %s', command) | ||
373 | |||
374 | return subprocess.run(command, *args, **kwargs) | ||
375 | |||
327 | def initialize_argparse(self): | 376 | def initialize_argparse(self): |
328 | """Prepare to process arguments from sys.argv. | 377 | """Prepare to process arguments from sys.argv. |
329 | """ | 378 | """ |
@@ -678,14 +727,13 @@ class MILC(object): | |||
678 | self.log_print_level = logging.DEBUG | 727 | self.log_print_level = logging.DEBUG |
679 | 728 | ||
680 | self.log_file = self.config['general']['log_file'] or self.log_file | 729 | self.log_file = self.config['general']['log_file'] or self.log_file |
681 | self.log_file_format = self.config['general']['log_file_fmt'] | ||
682 | self.log_file_format = ANSIStrippingFormatter(self.config['general']['log_file_fmt'], self.config['general']['datetime_fmt']) | 730 | self.log_file_format = ANSIStrippingFormatter(self.config['general']['log_file_fmt'], self.config['general']['datetime_fmt']) |
683 | self.log_format = self.config['general']['log_fmt'] | 731 | self.log_format = self.config['general']['log_fmt'] |
684 | 732 | ||
685 | if self.config.general.color: | 733 | if self.config.general.color: |
686 | self.log_format = ANSIEmojiLoglevelFormatter(self.args.log_fmt, self.config.general.datetime_fmt) | 734 | self.log_format = ANSIEmojiLoglevelFormatter(self.config.general.log_fmt, self.config.general.datetime_fmt) |
687 | else: | 735 | else: |
688 | self.log_format = ANSIStrippingFormatter(self.args.log_fmt, self.config.general.datetime_fmt) | 736 | self.log_format = ANSIStrippingEmojiLoglevelFormatter(self.config.general.log_fmt, self.config.general.datetime_fmt) |
689 | 737 | ||
690 | if self.log_file: | 738 | if self.log_file: |
691 | self.log_file_handler = logging.FileHandler(self.log_file, self.log_file_mode) | 739 | self.log_file_handler = logging.FileHandler(self.log_file, self.log_file_mode) |