OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2016 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. |
| 5 |
| 6 import os |
| 7 import sys |
| 8 from third_party import colorama |
| 9 |
| 10 IS_TTY = None |
| 11 OUT_TYPE = 'unknown' |
| 12 |
| 13 def init(): |
| 14 # should_wrap instructs colorama to wrap stdout/stderr with an ASNI colorcode |
| 15 # interpreter that converts them to SetConsoleTextAttribute calls. This only |
| 16 # should be True in cases where we're connected to cmd.exe's console. Setting |
| 17 # this to True on non-windows systems has no effect. |
| 18 should_wrap = False |
| 19 global IS_TTY, OUT_TYPE |
| 20 IS_TTY = sys.stdout.isatty() |
| 21 if IS_TTY: |
| 22 # Yay! We detected a console in the normal way. It doesn't really matter |
| 23 # if it's windows or not, we win. |
| 24 OUT_TYPE = 'console' |
| 25 should_wrap = True |
| 26 elif sys.platform.startswith('win'): |
| 27 # assume this is some sort of file |
| 28 OUT_TYPE = 'file (win)' |
| 29 |
| 30 import msvcrt |
| 31 import ctypes |
| 32 h = msvcrt.get_osfhandle(sys.stdout.fileno()) |
| 33 # h is the win32 HANDLE for stdout. |
| 34 ftype = ctypes.windll.kernel32.GetFileType(h) |
| 35 if ftype == 2: # FILE_TYPE_CHAR |
| 36 # This is a normal cmd console, but we'll only get here if we're running |
| 37 # inside a `git command` which is actually git->bash->command. Not sure |
| 38 # why isatty doesn't detect this case. |
| 39 OUT_TYPE = 'console (cmd via msys)' |
| 40 IS_TTY = True |
| 41 should_wrap = True |
| 42 elif ftype == 3: # FILE_TYPE_PIPE |
| 43 OUT_TYPE = 'pipe (win)' |
| 44 # This is some kind of pipe on windows. This could either be a real pipe |
| 45 # or this could be msys using a pipe to emulate a pty. We use the same |
| 46 # algorithm that msys-git uses to determine if it's connected to a pty or |
| 47 # not. |
| 48 |
| 49 # This function and the structures are defined in the MSDN documentation |
| 50 # using the same names. |
| 51 def NT_SUCCESS(status): |
| 52 # The first two bits of status are the severity. The success |
| 53 # severities are 0 and 1, and the !success severities are 2 and 3. |
| 54 # Therefore since ctypes interprets the default restype of the call |
| 55 # to be an 'C int' (which is guaranteed to be signed 32 bits), All |
| 56 # success codes are positive, and all !success codes are negative. |
| 57 return status >= 0 |
| 58 |
| 59 class UNICODE_STRING(ctypes.Structure): |
| 60 _fields_ = [('Length', ctypes.c_ushort), |
| 61 ('MaximumLength', ctypes.c_ushort), |
| 62 ('Buffer', ctypes.c_wchar_p)] |
| 63 |
| 64 class OBJECT_NAME_INFORMATION(ctypes.Structure): |
| 65 _fields_ = [('Name', UNICODE_STRING), |
| 66 ('NameBuffer', ctypes.c_wchar_p)] |
| 67 |
| 68 buf = ctypes.create_string_buffer('\0', 1024) |
| 69 # Ask NT what the name of the object our stdout HANDLE is. It would be |
| 70 # possible to use GetFileInformationByHandleEx, but it's only available |
| 71 # on Vista+. If you're reading this in 2017 or later, feel free to |
| 72 # refactor this out. |
| 73 # |
| 74 # The '1' here is ObjectNameInformation |
| 75 if NT_SUCCESS(ctypes.windll.ntdll.NtQueryObject(h, 1, buf, len(buf)-2, |
| 76 None)): |
| 77 out = OBJECT_NAME_INFORMATION.from_buffer(buf) |
| 78 name = out.Name.Buffer.split('\\')[-1] |
| 79 IS_TTY = name.startswith('msys-') and '-pty' in name |
| 80 if IS_TTY: |
| 81 OUT_TYPE = 'bash (msys)' |
| 82 else: |
| 83 # A normal file, or an unknown file type. |
| 84 pass |
| 85 else: |
| 86 # This is non-windows, so we trust isatty. |
| 87 OUT_TYPE = 'pipe or file' |
| 88 |
| 89 colorama.init(wrap=should_wrap) |
| 90 |
| 91 if __name__ == '__main__': |
| 92 init() |
| 93 print 'IS_TTY:', IS_TTY |
| 94 print 'OUT_TYPE:', OUT_TYPE |
OLD | NEW |