diff options
Diffstat (limited to 'extras/build_logs.py')
-rw-r--r-- | extras/build_logs.py | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/extras/build_logs.py b/extras/build_logs.py new file mode 100644 index 00000000..cdf8ed09 --- /dev/null +++ b/extras/build_logs.py @@ -0,0 +1,110 @@ +#!/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) + |