waf/waflib/extras/build_logs.py

111 lines
2.8 KiB
Python

#!/usr/bin/env python
# encoding: utf-8
# Thomas Nagy, 2013 (ita)
"""
A system for recording all outputs to a log file. Just add the following to your wscript file::
def init(ctx):
ctx.load('build_logs')
"""
import atexit, sys, time, os, shutil, threading
from waflib import ansiterm, Logs, Context
# adding the logs under the build/ directory will clash with the clean/ command
try:
up = os.path.dirname(Context.g_module.__file__)
except AttributeError:
up = '.'
LOGFILE = os.path.join(up, 'logs', time.strftime('%Y_%m_%d_%H_%M.log'))
wlock = threading.Lock()
class log_to_file(object):
def __init__(self, stream, fileobj, filename):
self.stream = stream
self.encoding = self.stream.encoding
self.fileobj = fileobj
self.filename = filename
self.is_valid = True
def replace_colors(self, data):
for x in Logs.colors_lst.values():
if isinstance(x, str):
data = data.replace(x, '')
return data
def write(self, data):
try:
wlock.acquire()
self.stream.write(data)
self.stream.flush()
if self.is_valid:
self.fileobj.write(self.replace_colors(data))
finally:
wlock.release()
def fileno(self):
return self.stream.fileno()
def flush(self):
self.stream.flush()
if self.is_valid:
self.fileobj.flush()
def isatty(self):
return self.stream.isatty()
def init(ctx):
global LOGFILE
filename = os.path.abspath(LOGFILE)
try:
os.makedirs(os.path.dirname(os.path.abspath(filename)))
except OSError:
pass
if hasattr(os, 'O_NOINHERIT'):
fd = os.open(LOGFILE, os.O_CREAT | os.O_TRUNC | os.O_WRONLY | os.O_NOINHERIT)
fileobj = os.fdopen(fd, 'w')
else:
fileobj = open(LOGFILE, 'w')
old_stderr = sys.stderr
# sys.stdout has already been replaced, so __stdout__ will be faster
#sys.stdout = log_to_file(sys.stdout, fileobj, filename)
#sys.stderr = log_to_file(sys.stderr, fileobj, filename)
def wrap(stream):
if stream.isatty():
return ansiterm.AnsiTerm(stream)
return stream
sys.stdout = log_to_file(wrap(sys.__stdout__), fileobj, filename)
sys.stderr = log_to_file(wrap(sys.__stderr__), fileobj, filename)
# now mess with the logging module...
for x in Logs.log.handlers:
try:
stream = x.stream
except AttributeError:
pass
else:
if id(stream) == id(old_stderr):
x.stream = sys.stderr
def exit_cleanup():
try:
fileobj = sys.stdout.fileobj
except AttributeError:
pass
else:
sys.stdout.is_valid = False
sys.stderr.is_valid = False
fileobj.close()
filename = sys.stdout.filename
Logs.info('Output logged to %r', filename)
# then copy the log file to "latest.log" if possible
up = os.path.dirname(os.path.abspath(filename))
try:
shutil.copy(filename, os.path.join(up, 'latest.log'))
except OSError:
# this may fail on windows due to processes spawned
pass
atexit.register(exit_cleanup)