You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			134 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			134 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Python
		
	
#!/usr/bin/env python3
 | 
						|
# Copyright (c) 2016 The Chromium Authors. All rights reserved.
 | 
						|
# Use of this source code is governed by a BSD-style license that can be
 | 
						|
# found in the LICENSE file.
 | 
						|
 | 
						|
import ctypes
 | 
						|
import platform
 | 
						|
import subprocess
 | 
						|
import sys
 | 
						|
from third_party import colorama
 | 
						|
 | 
						|
IS_TTY = None
 | 
						|
OUT_TYPE = 'unknown'
 | 
						|
 | 
						|
 | 
						|
def enable_native_ansi():
 | 
						|
    """Enables native ANSI sequences in console. Windows 10 only.
 | 
						|
 | 
						|
    Returns whether successful.
 | 
						|
    """
 | 
						|
    kernel32 = ctypes.windll.kernel32
 | 
						|
    ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x04
 | 
						|
 | 
						|
    out_handle = kernel32.GetStdHandle(subprocess.STD_OUTPUT_HANDLE)
 | 
						|
 | 
						|
    # GetConsoleMode fails if the terminal isn't native.
 | 
						|
    mode = ctypes.wintypes.DWORD()
 | 
						|
    if kernel32.GetConsoleMode(out_handle, ctypes.byref(mode)) == 0:
 | 
						|
        return False
 | 
						|
 | 
						|
    if not (mode.value & ENABLE_VIRTUAL_TERMINAL_PROCESSING):
 | 
						|
        if kernel32.SetConsoleMode(
 | 
						|
                out_handle,
 | 
						|
                mode.value | ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0:
 | 
						|
            print('kernel32.SetConsoleMode to enable ANSI sequences failed',
 | 
						|
                  file=sys.stderr)
 | 
						|
            return False
 | 
						|
 | 
						|
    return True
 | 
						|
 | 
						|
 | 
						|
def init():
 | 
						|
    # should_wrap instructs colorama to wrap stdout/stderr with an ANSI
 | 
						|
    # colorcode interpreter that converts them to SetConsoleTextAttribute calls.
 | 
						|
    # This only should be True in cases where we're connected to cmd.exe's
 | 
						|
    # console. Setting this to True on non-windows systems has no effect.
 | 
						|
    should_wrap = False
 | 
						|
    global IS_TTY, OUT_TYPE
 | 
						|
    IS_TTY = sys.stdout.isatty()
 | 
						|
    is_windows = sys.platform.startswith('win')
 | 
						|
    if IS_TTY:
 | 
						|
        # Yay! We detected a console in the normal way. It doesn't really matter
 | 
						|
        # if it's windows or not, we win.
 | 
						|
        OUT_TYPE = 'console'
 | 
						|
        should_wrap = True
 | 
						|
    elif is_windows:
 | 
						|
        # assume this is some sort of file
 | 
						|
        OUT_TYPE = 'file (win)'
 | 
						|
 | 
						|
        import msvcrt
 | 
						|
        h = msvcrt.get_osfhandle(sys.stdout.fileno())
 | 
						|
        # h is the win32 HANDLE for stdout.
 | 
						|
        ftype = ctypes.windll.kernel32.GetFileType(h)
 | 
						|
        if ftype == 2:  # FILE_TYPE_CHAR
 | 
						|
            # This is a normal cmd console, but we'll only get here if we're
 | 
						|
            # running inside a `git command` which is actually
 | 
						|
            # git->bash->command. Not sure why isatty doesn't detect this case.
 | 
						|
            OUT_TYPE = 'console (cmd via msys)'
 | 
						|
            IS_TTY = True
 | 
						|
            should_wrap = True
 | 
						|
        elif ftype == 3:  # FILE_TYPE_PIPE
 | 
						|
            OUT_TYPE = 'pipe (win)'
 | 
						|
 | 
						|
            # This is some kind of pipe on windows. This could either be a real
 | 
						|
            # pipe or this could be msys using a pipe to emulate a pty. We use
 | 
						|
            # the same algorithm that msys-git uses to determine if it's
 | 
						|
            # connected to a pty or not.
 | 
						|
 | 
						|
            # This function and the structures are defined in the MSDN
 | 
						|
            # documentation using the same names.
 | 
						|
            def NT_SUCCESS(status):
 | 
						|
                # The first two bits of status are the severity. The success
 | 
						|
                # severities are 0 and 1, and the !success severities are 2 and
 | 
						|
                # 3. Therefore since ctypes interprets the default restype of
 | 
						|
                # the call to be an 'C int' (which is guaranteed to be signed 32
 | 
						|
                # bits), All success codes are positive, and all !success codes
 | 
						|
                # are negative.
 | 
						|
                return status >= 0
 | 
						|
 | 
						|
            class UNICODE_STRING(ctypes.Structure):
 | 
						|
                _fields_ = [('Length', ctypes.c_ushort),
 | 
						|
                            ('MaximumLength', ctypes.c_ushort),
 | 
						|
                            ('Buffer', ctypes.c_wchar_p)]
 | 
						|
 | 
						|
            class OBJECT_NAME_INFORMATION(ctypes.Structure):
 | 
						|
                _fields_ = [('Name', UNICODE_STRING),
 | 
						|
                            ('NameBuffer', ctypes.c_wchar_p)]
 | 
						|
 | 
						|
            buf = ctypes.create_string_buffer(1024)
 | 
						|
            # Ask NT what the name of the object our stdout HANDLE is. It would
 | 
						|
            # be possible to use GetFileInformationByHandleEx, but it's only
 | 
						|
            # available on Vista+. If you're reading this in 2017 or later, feel
 | 
						|
            # free to refactor this out.
 | 
						|
            #
 | 
						|
            # The '1' here is ObjectNameInformation
 | 
						|
            if NT_SUCCESS(
 | 
						|
                    ctypes.windll.ntdll.NtQueryObject(h, 1, buf,
 | 
						|
                                                      len(buf) - 2, None)):
 | 
						|
                out = OBJECT_NAME_INFORMATION.from_buffer(buf)
 | 
						|
                name = out.Name.Buffer.split('\\')[-1]
 | 
						|
                IS_TTY = name.startswith('msys-') and '-pty' in name
 | 
						|
                if IS_TTY:
 | 
						|
                    OUT_TYPE = 'bash (msys)'
 | 
						|
        else:
 | 
						|
            # A normal file, or an unknown file type.
 | 
						|
            pass
 | 
						|
    else:
 | 
						|
        # This is non-windows, so we trust isatty.
 | 
						|
        OUT_TYPE = 'pipe or file'
 | 
						|
 | 
						|
    if IS_TTY and is_windows:
 | 
						|
        # Wrapping may cause errors on some Windows versions
 | 
						|
        # (crbug.com/1114548).
 | 
						|
        if platform.release() != '10' or enable_native_ansi():
 | 
						|
            should_wrap = False
 | 
						|
 | 
						|
    colorama.init(wrap=should_wrap)
 | 
						|
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    init()
 | 
						|
    print('IS_TTY:', IS_TTY)
 | 
						|
    print('OUT_TYPE:', OUT_TYPE)
 |