Take two at console decoding.
1 # vim: set sts=2 ts=8 sw=2 tw=99 et:
4 import re, os, sys, locale
7 import __builtin__ as builtins
11 import cPickle as pickle
35 return sys.platform[0:5] == 'linux'
38 return sys.platform[0:7] == 'freebsd'
41 return sys.platform[0:6] == 'netbsd'
44 return sys.platform[0:7] == 'openbsd'
47 return sys.platform == 'win32'
50 return sys.platform == 'cygwin'
53 return sys.platform == 'darwin' or sys.platform[0:6] == 'Darwin'
56 return sys.platform[0:5] == 'sunos'
59 return not IsWindows()
62 return IsMac() or IsFreeBSD() or IsOpenBSD() or IsNetBSD()
64 def ExecutableSuffix():
70 def SharedLibSuffix():
73 elif sys.platform == 'darwin':
78 def StaticLibSuffix():
83 def StaticLibPrefix():
89 def WaitForProcess(process):
90 out, err = process.communicate()
91 process.stdoutText = DecodeConsoleText(sys.stdout, process.stdout, out)
92 process.stderrText = DecodeConsoleText(sys.stderr, process.stderr, err)
93 return process.returncode
95 def CreateProcess(argv, executable = None):
96 pargs = { 'args': argv }
97 pargs['stdout'] = subprocess.PIPE
98 pargs['stderr'] = subprocess.PIPE
99 if executable != None:
100 pargs['executable'] = executable
102 process = subprocess.Popen(**pargs)
108 path = os.path.join(*list)
110 path = path.replace('\\\\', '\\')
113 def RemoveFolderAndContents(path):
114 for file in os.listdir(path):
115 subpath = os.path.join(path, file)
117 if os.path.isfile(subpath) or os.path.islink(subpath):
119 elif os.path.isdir(subpath):
120 RemoveFolderAndContents(subpath)
126 def __init__(self, folder):
127 self.old = os.getcwd()
134 def __exit__(self, type, value, traceback):
138 def __init__(self, obj):
144 def __exit__(self, type, value, traceback):
147 def Execute(argv, shell=False):
148 p = subprocess.Popen(
150 stdout=subprocess.PIPE,
151 stderr=subprocess.PIPE,
154 stdout, stderr = p.communicate()
155 out = stdout.decode('utf8')
156 err = stderr.decode('utf8')
160 return builtins.type(x)
163 # Python 2.7. sqlite blob is buffer
169 if type(blob) != bytes:
171 return pickle.loads(blob)
173 # We don't want to dump Python 3 pickle format since then ambuild couldn't
174 # run it if you using Python 2.
175 PICKLE_PROTOCOL = min(2, pickle.HIGHEST_PROTOCOL)
177 def DiskPickle(obj, fp):
178 return pickle.dump(obj, fp, PICKLE_PROTOCOL)
180 def CompatPickle(obj):
181 return pickle.dumps(obj, PICKLE_PROTOCOL)
186 return bytes(s, 'utf8')
189 sLookForIncludeGuard = 1
190 sFoundIncludeGuard = 2
192 def ParseGCCDeps(text):
197 state = sReadIncludes
198 for line in re.split('\n+', text):
199 if state == sReadIncludes:
200 m = re.match('\.+\s+(.+)\s*$', line)
202 state = sLookForIncludeGuard
205 if os.path.exists(name):
209 state = LookForIncludeGuard
210 if state == sLookForIncludeGuard:
211 if line.startswith('Multiple include guards may be useful for:'):
212 state = sFoundIncludeGuard
215 state = sReadIncludes
217 elif state == sFoundIncludeGuard:
221 if not strip and len(line):
222 new_text += line + '\n'
223 return new_text, deps
225 def ParseMSVCDeps(out):
228 out = out.replace('\r\n', '\n')
229 out = out.replace('\r', '\n')
230 for line in out.split('\n'):
231 m = re.match('Note: including file:\s+(.+)$', line)
233 file = m.groups()[0].strip()
236 new_text += line + '\n'
237 return new_text, deps
239 def ParseSunDeps(text):
243 for line in re.split('\n+', text):
245 if os.path.isfile(name):
248 new_text += line + '\n'
249 return new_text.strip(), deps
251 if hasattr(os, 'symlink'):
252 def symlink(target, link):
253 os.symlink(target, link)
256 def symlink(target, link):
259 '"{0}"'.format(link),
260 '"{0}"'.format(target)
262 p, out, err = Execute(argv, shell=True)
263 return p.returncode, out, err
266 ConsoleGreen = lambda fp: fp.write('\033[92m')
267 ConsoleRed = lambda fp: fp.write('\033[91m')
268 ConsoleNormal = lambda fp: fp.write('\033[0m')
269 ConsoleBlue = lambda fp: fp.write('\033[94m')
270 ConsoleHeader = lambda fp: fp.write('\033[95m')
272 def SwitchColor(fp, color):
273 from ambuild2.ipc import winapi
277 std = winapi.STD_OUTPUT_HANDLE
278 elif fp == sys.stdin:
279 std = winapi.STD_ERROR_HANDLE
283 handle = winapi.GetStdHandle(std)
284 winapi.SetConsoleTextAttribute(handle, color)
286 ConsoleGreen = lambda fp: SwitchColor(fp, 0xA)
287 ConsoleRed = lambda fp: SwitchColor(fp, 0xC)
288 ConsoleNormal = lambda fp: SwitchColor(fp, 0x7)
289 ConsoleBlue = lambda fp: SwitchColor(fp, 0x9)
290 ConsoleHeader = lambda fp: SwitchColor(fp, 0xD)
299 return IsLambda(text)
301 sConsoleColorsEnabled = True
302 def DisableConsoleColors():
303 global sConsoleColorsEnabled
304 sConsoleColorsEnabled = False
306 def con_print(fp, args):
314 def con_print_simple(fp, args):
322 if sys.stdout.isatty():
323 con_print(sys.stdout, args)
325 con_print_simple(sys.stdout, args)
328 if sys.stderr.isatty():
329 con_print(sys.stderr, args)
331 con_print_simple(sys.stderr, args)
333 LambdaType = type(lambda: None)
336 return type(v) == LambdaType
340 return type(v) == str or type(v) == unicode
343 return type(v) == str
345 class Expando(object):
349 assert not os.path.isabs(path)
351 if os.path.exists(path):
352 con_out(ConsoleHeader, 'Removing old output: ',
353 ConsoleBlue, '{0}'.format(path),
358 except OSError as exn:
359 if exn.errno != errno.ENOENT:
360 con_err(ConsoleRed, 'Could not remove file: ',
361 ConsoleBlue, '{0}'.format(path),
363 ConsoleRed, '{0}'.format(exn),
367 def try_decode_with_pipe(pipe, text):
369 if hasattr(pipe, 'encoding') and pipe.encoding:
370 return text.decode(pipe.encoding, 'replace')
374 def DecodeConsoleText(origin, pipe, text):
375 result = try_decode_with_pipe(pipe, text)
377 result = try_decode_with_pipe(origin, text)
380 result = text.decode(locale.getpreferredencoding(), 'replace')
383 return result.encode('utf8')
385 def WriteEncodedText(fd, text):
386 if not hasattr(fd, 'encoding') or fd.encoding == None:
387 text = text.encode(locale.getpreferredencoding(), 'replace')