third_party/waf: upgrade to waf 2.0.8
[samba.git] / third_party / waf / waflib / extras / build_logs.py
1 #!/usr/bin/env python
2 # encoding: utf-8
3 # Thomas Nagy, 2013 (ita)
4
5 """
6 A system for recording all outputs to a log file. Just add the following to your wscript file::
7
8   def init(ctx):
9     ctx.load('build_logs')
10 """
11
12 import atexit, sys, time, os, shutil, threading
13 from waflib import ansiterm, Logs, Context
14
15 # adding the logs under the build/ directory will clash with the clean/ command
16 try:
17         up = os.path.dirname(Context.g_module.__file__)
18 except AttributeError:
19         up = '.'
20 LOGFILE = os.path.join(up, 'logs', time.strftime('%Y_%m_%d_%H_%M.log'))
21
22 wlock = threading.Lock()
23 class log_to_file(object):
24         def __init__(self, stream, fileobj, filename):
25                 self.stream = stream
26                 self.encoding = self.stream.encoding
27                 self.fileobj = fileobj
28                 self.filename = filename
29                 self.is_valid = True
30         def replace_colors(self, data):
31                 for x in Logs.colors_lst.values():
32                         if isinstance(x, str):
33                                 data = data.replace(x, '')
34                 return data
35         def write(self, data):
36                 try:
37                         wlock.acquire()
38                         self.stream.write(data)
39                         self.stream.flush()
40                         if self.is_valid:
41                                 self.fileobj.write(self.replace_colors(data))
42                 finally:
43                         wlock.release()
44         def fileno(self):
45                 return self.stream.fileno()
46         def flush(self):
47                 self.stream.flush()
48                 if self.is_valid:
49                         self.fileobj.flush()
50         def isatty(self):
51                 return self.stream.isatty()
52
53 def init(ctx):
54         global LOGFILE
55         filename = os.path.abspath(LOGFILE)
56         try:
57                 os.makedirs(os.path.dirname(os.path.abspath(filename)))
58         except OSError:
59                 pass
60
61         if hasattr(os, 'O_NOINHERIT'):
62                 fd = os.open(LOGFILE, os.O_CREAT | os.O_TRUNC | os.O_WRONLY | os.O_NOINHERIT)
63                 fileobj = os.fdopen(fd, 'w')
64         else:
65                 fileobj = open(LOGFILE, 'w')
66         old_stderr = sys.stderr
67
68         # sys.stdout has already been replaced, so __stdout__ will be faster
69         #sys.stdout = log_to_file(sys.stdout, fileobj, filename)
70         #sys.stderr = log_to_file(sys.stderr, fileobj, filename)
71         def wrap(stream):
72                 if stream.isatty():
73                         return ansiterm.AnsiTerm(stream)
74                 return stream
75         sys.stdout = log_to_file(wrap(sys.__stdout__), fileobj, filename)
76         sys.stderr = log_to_file(wrap(sys.__stderr__), fileobj, filename)
77
78         # now mess with the logging module...
79         for x in Logs.log.handlers:
80                 try:
81                         stream = x.stream
82                 except AttributeError:
83                         pass
84                 else:
85                         if id(stream) == id(old_stderr):
86                                 x.stream = sys.stderr
87
88 def exit_cleanup():
89         try:
90                 fileobj = sys.stdout.fileobj
91         except AttributeError:
92                 pass
93         else:
94                 sys.stdout.is_valid = False
95                 sys.stderr.is_valid = False
96                 fileobj.close()
97                 filename = sys.stdout.filename
98
99                 Logs.info('Output logged to %r', filename)
100
101                 # then copy the log file to "latest.log" if possible
102                 up = os.path.dirname(os.path.abspath(filename))
103                 try:
104                         shutil.copy(filename, os.path.join(up, 'latest.log'))
105                 except OSError:
106                         # this may fail on windows due to processes spawned
107                         pass
108
109 atexit.register(exit_cleanup)
110