Add --color and --no-color options.

By default, we auto-detect color mode (if it's a tty, color default on,
else off).  But you can force it either way.
This commit is contained in:
Avery Pennarun 2018-11-19 11:22:53 -05:00
commit d82326a39d
6 changed files with 21 additions and 13 deletions

View file

@ -22,7 +22,8 @@ def _try_stat(filename):
log_reader_pid = None log_reader_pid = None
def start_stdin_log_reader(status, details, pretty, debug_locks, debug_pids): def start_stdin_log_reader(status, details, pretty, color,
debug_locks, debug_pids):
if not vars.LOG: return if not vars.LOG: return
global log_reader_pid global log_reader_pid
r, w = os.pipe() # main pipe to redo-log r, w = os.pipe() # main pipe to redo-log
@ -47,7 +48,7 @@ def start_stdin_log_reader(status, details, pretty, debug_locks, debug_pids):
os.dup2(w, 1) os.dup2(w, 1)
os.dup2(w, 2) os.dup2(w, 2)
os.close(w) os.close(w)
check_tty(sys.stderr) check_tty(sys.stderr, vars.COLOR)
else: else:
# child # child
try: try:
@ -64,8 +65,10 @@ def start_stdin_log_reader(status, details, pretty, debug_locks, debug_pids):
('--pretty' if pretty else '--no-pretty'), ('--pretty' if pretty else '--no-pretty'),
('--debug-locks' if debug_locks else '--no-debug-locks'), ('--debug-locks' if debug_locks else '--no-debug-locks'),
('--debug-pids' if debug_pids else '--no-debug-pids'), ('--debug-pids' if debug_pids else '--no-debug-pids'),
'-'
] ]
if color != 1:
argv.append('--color' if color >= 2 else '--no-color')
argv.append('-')
os.execvp(argv[0], argv) os.execvp(argv[0], argv)
except Exception, e: except Exception, e:
sys.stderr.write('redo-log: exec: %s\n' % e) sys.stderr.write('redo-log: exec: %s\n' % e)

13
logs.py
View file

@ -2,9 +2,10 @@ import os, re, sys, time
import vars import vars
def check_tty(file): def check_tty(file, color):
global RED, GREEN, YELLOW, BOLD, PLAIN global RED, GREEN, YELLOW, BOLD, PLAIN
if file.isatty() and (os.environ.get('TERM') or 'dumb') != 'dumb': color_ok = file.isatty() and (os.environ.get('TERM') or 'dumb') != 'dumb'
if (color and color_ok) or color >= 2:
# ...use ANSI formatting codes. # ...use ANSI formatting codes.
RED = "\x1b[31m" RED = "\x1b[31m"
GREEN = "\x1b[32m" GREEN = "\x1b[32m"
@ -98,17 +99,17 @@ class PrettyLog(object):
_log = None _log = None
def setup(file, pretty): def setup(file, pretty, color):
global _log global _log
if pretty or vars.PRETTY: if pretty or vars.PRETTY:
check_tty(file) check_tty(file, color=color)
_log = PrettyLog(file=file) _log = PrettyLog(file=file)
else: else:
_log = RawLog(file=file) _log = RawLog(file=file)
# FIXME: explicitly initialize in each program # FIXME: explicitly initialize in each program, for clarity
setup(file=sys.stderr, pretty=False) setup(file=sys.stderr, pretty=vars.PRETTY, color=vars.COLOR)
def write(s): def write(s):

View file

@ -21,7 +21,7 @@ rv = 202
try: try:
if vars_init.is_toplevel: if vars_init.is_toplevel:
builder.start_stdin_log_reader(status=True, details=True, builder.start_stdin_log_reader(status=True, details=True,
pretty=True, debug_locks=False, debug_pids=False) pretty=True, color=True, debug_locks=False, debug_pids=False)
if vars.TARGET and not vars.UNLOCKED: if vars.TARGET and not vars.UNLOCKED:
me = os.path.join(vars.STARTDIR, me = os.path.join(vars.STARTDIR,
os.path.join(vars.PWD, vars.TARGET)) os.path.join(vars.PWD, vars.TARGET))

View file

@ -10,9 +10,9 @@ r,recursive show build logs for dependencies too
u,unchanged show lines for dependencies not needing to be rebuilt u,unchanged show lines for dependencies not needing to be rebuilt
f,follow keep watching for more lines to be appended (like tail -f) f,follow keep watching for more lines to be appended (like tail -f)
no-details only show 'redo' recursion trace, not build output no-details only show 'redo' recursion trace, not build output
no-colorize don't colorize 'redo' log messages
no-status don't display build summary line in --follow no-status don't display build summary line in --follow
no-pretty don't pretty-print logs, show raw @@REDO output instead no-pretty don't pretty-print logs, show raw @@REDO output instead
no-color disable ANSI color; --color to force enable (default: auto)
debug-locks print messages about file locking (useful for debugging) debug-locks print messages about file locking (useful for debugging)
debug-pids print process ids in log messages (useful for debugging) debug-pids print process ids in log messages (useful for debugging)
ack-fd= (internal use only) print REDO-OK to this fd upon starting ack-fd= (internal use only) print REDO-OK to this fd upon starting
@ -211,7 +211,7 @@ try:
sys.exit(1) sys.exit(1)
if opt.status < 2 and not os.isatty(2): if opt.status < 2 and not os.isatty(2):
opt.status = False opt.status = False
logs.setup(file=sys.stdout, pretty=opt.pretty) logs.setup(file=sys.stdout, pretty=opt.pretty, color=opt.color)
if opt.debug_locks: if opt.debug_locks:
vars.DEBUG_LOCKS = 1 vars.DEBUG_LOCKS = 1
if opt.debug_pids: if opt.debug_pids:

View file

@ -16,6 +16,7 @@ no-details only show 'redo' recursion trace (to see more later, use redo-log)
no-status don't display build summary line at the bottom of the screen no-status don't display build summary line at the bottom of the screen
no-log don't capture error output, just let it flow straight to stderr no-log don't capture error output, just let it flow straight to stderr
no-pretty don't pretty-print logs, show raw @@REDO output instead no-pretty don't pretty-print logs, show raw @@REDO output instead
no-color disable ANSI color; --color to force enable (default: auto)
debug-locks print messages about file locking (useful for debugging) debug-locks print messages about file locking (useful for debugging)
debug-pids print process ids as part of log messages (useful for debugging) debug-pids print process ids as part of log messages (useful for debugging)
version print the current version and exit version print the current version and exit
@ -51,6 +52,8 @@ if opt.no_log:
os.environ['REDO_LOG'] = '0' os.environ['REDO_LOG'] = '0'
if opt.no_pretty: if opt.no_pretty:
os.environ['REDO_PRETTY'] = '0' os.environ['REDO_PRETTY'] = '0'
if opt.no_color:
os.environ['REDO_COLOR'] = '0'
import vars_init import vars_init
vars_init.init(targets) vars_init.init(targets)
@ -61,7 +64,7 @@ from logs import warn, err
try: try:
if vars_init.is_toplevel: if vars_init.is_toplevel:
builder.start_stdin_log_reader(status=opt.status, details=opt.details, builder.start_stdin_log_reader(status=opt.status, details=opt.details,
pretty=opt.pretty, pretty=opt.pretty, color=opt.color,
debug_locks=opt.debug_locks, debug_pids=opt.debug_pids) debug_locks=opt.debug_locks, debug_pids=opt.debug_pids)
for t in targets: for t in targets:
if os.path.exists(t): if os.path.exists(t):

View file

@ -17,6 +17,7 @@ VERBOSE = os.environ.get('REDO_VERBOSE', '') and 1 or 0
XTRACE = os.environ.get('REDO_XTRACE', '') and 1 or 0 XTRACE = os.environ.get('REDO_XTRACE', '') and 1 or 0
KEEP_GOING = os.environ.get('REDO_KEEP_GOING', '') and 1 or 0 KEEP_GOING = os.environ.get('REDO_KEEP_GOING', '') and 1 or 0
LOG = atoi(os.environ.get('REDO_LOG', '1')) # defaults on LOG = atoi(os.environ.get('REDO_LOG', '1')) # defaults on
COLOR = atoi(os.environ.get('REDO_COLOR', '1')) # defaults on
# subprocesses mustn't pretty-print if a parent is running redo-log # subprocesses mustn't pretty-print if a parent is running redo-log
PRETTY = (not LOG) and atoi(os.environ.get('REDO_PRETTY', '1')) PRETTY = (not LOG) and atoi(os.environ.get('REDO_PRETTY', '1'))
SHUFFLE = os.environ.get('REDO_SHUFFLE', '') and 1 or 0 SHUFFLE = os.environ.get('REDO_SHUFFLE', '') and 1 or 0