Directory reorg: move code into redo/, generate binaries in bin/.
It's time to start preparing for a version of redo that doesn't work unless we build it first (because it will rely on C modules, and eventually be rewritten in C altogether). To get rolling, remove the old-style symlinks to the main programs, and rename those programs from redo-*.py to redo/cmd_*.py. We'll also move all library functions into the redo/ dir, which is a more python-style naming convention. Previously, install.do was generating wrappers for installing in /usr/bin, which extend sys.path and then import+run the right file. This made "installed" redo work quite differently from running redo inside its source tree. Instead, let's always generate the wrappers in bin/, and not make anything executable except those wrappers. Since we're generating wrappers anyway, let's actually auto-detect the right version of python for the running system; distros can't seem to agree on what to call their python2 binaries (sigh). We'll fill in the right #! shebang lines. Since we're doing that, we can stop using /usr/bin/env, which will a) make things slightly faster, and b) let us use "python -S", which tells python not to load a bunch of extra crap we're not using, thus improving startup times. Annoyingly, we now have to build redo using minimal/do, then run the tests using bin/redo. To make this less annoying, we add a toplevel ./do script that knows the right steps, and a Makefile (whee!) for people who are used to typing 'make' and 'make test' and 'make clean'.
This commit is contained in:
parent
5bc7c861b6
commit
f6fe00db5c
140 changed files with 256 additions and 99 deletions
154
redo/logs.py
Normal file
154
redo/logs.py
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
import os, re, sys, time
|
||||
import vars
|
||||
|
||||
RED = GREEN = YELLOW = BOLD = PLAIN = None
|
||||
|
||||
|
||||
def check_tty(file, color):
|
||||
global RED, GREEN, YELLOW, BOLD, PLAIN
|
||||
color_ok = file.isatty() and (os.environ.get('TERM') or 'dumb') != 'dumb'
|
||||
if (color and color_ok) or color >= 2:
|
||||
# ...use ANSI formatting codes.
|
||||
# pylint: disable=bad-whitespace
|
||||
RED = "\x1b[31m"
|
||||
GREEN = "\x1b[32m"
|
||||
YELLOW = "\x1b[33m"
|
||||
BOLD = "\x1b[1m"
|
||||
PLAIN = "\x1b[m"
|
||||
else:
|
||||
RED = ""
|
||||
GREEN = ""
|
||||
YELLOW = ""
|
||||
BOLD = ""
|
||||
PLAIN = ""
|
||||
|
||||
|
||||
class RawLog(object):
|
||||
def __init__(self, file):
|
||||
self.file = file
|
||||
|
||||
def write(self, s):
|
||||
assert '\n' not in s
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
self.file.write(s + '\n')
|
||||
self.file.flush()
|
||||
|
||||
|
||||
REDO_RE = re.compile(r'@@REDO:([^@]+)@@ (.*)$')
|
||||
|
||||
|
||||
class PrettyLog(object):
|
||||
def __init__(self, file):
|
||||
self.topdir = os.getcwd()
|
||||
self.file = file
|
||||
|
||||
def _pretty(self, pid, color, s):
|
||||
if vars.DEBUG_PIDS:
|
||||
redo = '%-6d redo ' % pid
|
||||
else:
|
||||
redo = 'redo '
|
||||
self.file.write(
|
||||
''.join([color, redo, vars.DEPTH,
|
||||
BOLD if color else '', s, PLAIN, '\n']))
|
||||
|
||||
def write(self, s):
|
||||
assert '\n' not in s
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
g = REDO_RE.match(s)
|
||||
if g:
|
||||
all = g.group(0)
|
||||
self.file.write(s[:-len(all)])
|
||||
words = g.group(1).split(':')
|
||||
text = g.group(2)
|
||||
kind, pid, _ = words[0:3]
|
||||
pid = int(pid)
|
||||
if kind == 'unchanged':
|
||||
self._pretty(pid, '', '%s (unchanged)' % text)
|
||||
elif kind == 'check':
|
||||
self._pretty(pid, GREEN, '(%s)' % text)
|
||||
elif kind == 'do':
|
||||
self._pretty(pid, GREEN, text)
|
||||
elif kind == 'done':
|
||||
rv, name = text.split(' ', 1)
|
||||
rv = int(rv)
|
||||
if rv:
|
||||
self._pretty(pid, RED, '%s (exit %d)' % (name, rv))
|
||||
elif vars.VERBOSE or vars.XTRACE or vars.DEBUG:
|
||||
self._pretty(pid, GREEN, '%s (done)' % name)
|
||||
self.file.write('\n')
|
||||
elif kind == 'locked':
|
||||
if vars.DEBUG_LOCKS:
|
||||
self._pretty(pid, GREEN, '%s (locked...)' % text)
|
||||
elif kind == 'waiting':
|
||||
if vars.DEBUG_LOCKS:
|
||||
self._pretty(pid, GREEN, '%s (WAITING)' % text)
|
||||
elif kind == 'unlocked':
|
||||
if vars.DEBUG_LOCKS:
|
||||
self._pretty(pid, GREEN, '%s (...unlocked!)' % text)
|
||||
elif kind == 'error':
|
||||
self.file.write(''.join([RED, 'redo: ',
|
||||
BOLD, text, PLAIN, '\n']))
|
||||
elif kind == 'warning':
|
||||
self.file.write(''.join([YELLOW, 'redo: ',
|
||||
BOLD, text, PLAIN, '\n']))
|
||||
elif kind == 'debug':
|
||||
self._pretty(pid, '', text)
|
||||
else:
|
||||
assert 0, 'Unexpected @@REDO kind: %r' % kind
|
||||
else:
|
||||
self.file.write(s + '\n')
|
||||
self.file.flush()
|
||||
|
||||
|
||||
_log = None
|
||||
|
||||
def setup(file, pretty, color):
|
||||
global _log
|
||||
if pretty or vars.PRETTY:
|
||||
check_tty(file, color=color)
|
||||
_log = PrettyLog(file=file)
|
||||
else:
|
||||
_log = RawLog(file=file)
|
||||
|
||||
|
||||
# FIXME: explicitly initialize in each program, for clarity
|
||||
setup(file=sys.stderr, pretty=vars.PRETTY, color=vars.COLOR)
|
||||
|
||||
|
||||
def write(s):
|
||||
_log.write(s)
|
||||
|
||||
|
||||
def meta(kind, s, pid=None):
|
||||
assert ':' not in kind
|
||||
assert '@' not in kind
|
||||
assert '\n' not in s
|
||||
if pid is None:
|
||||
pid = os.getpid()
|
||||
write('@@REDO:%s:%d:%.4f@@ %s'
|
||||
% (kind, pid, time.time(), s))
|
||||
|
||||
def err(s):
|
||||
s = s.rstrip()
|
||||
meta('error', s)
|
||||
|
||||
def warn(s):
|
||||
s = s.rstrip()
|
||||
meta('warning', s)
|
||||
|
||||
def debug(s):
|
||||
if vars.DEBUG >= 1:
|
||||
s = s.rstrip()
|
||||
meta('debug', s)
|
||||
|
||||
def debug2(s):
|
||||
if vars.DEBUG >= 2:
|
||||
s = s.rstrip()
|
||||
meta('debug', s)
|
||||
|
||||
def debug3(s):
|
||||
if vars.DEBUG >= 3:
|
||||
s = s.rstrip()
|
||||
meta('debug', s)
|
||||
Loading…
Add table
Add a link
Reference in a new issue