summaryrefslogtreecommitdiffstats
path: root/waflib/extras/build_logs.py
diff options
context:
space:
mode:
Diffstat (limited to 'waflib/extras/build_logs.py')
-rw-r--r--waflib/extras/build_logs.py110
1 files changed, 110 insertions, 0 deletions
diff --git a/waflib/extras/build_logs.py b/waflib/extras/build_logs.py
new file mode 100644
index 0000000..cdf8ed0
--- /dev/null
+++ b/waflib/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)
+