88 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			88 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
								 | 
							
								"""
							 | 
						||
| 
								 | 
							
								Helper functions for interacting with the shell, and consuming shell-style
							 | 
						||
| 
								 | 
							
								parameters provided in config files.
							 | 
						||
| 
								 | 
							
								"""
							 | 
						||
| 
								 | 
							
								import os
							 | 
						||
| 
								 | 
							
								import shlex
							 | 
						||
| 
								 | 
							
								import subprocess
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								__all__ = ['WindowsParser', 'PosixParser', 'NativeParser']
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class CommandLineParser:
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    An object that knows how to split and join command-line arguments.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    It must be true that ``argv == split(join(argv))`` for all ``argv``.
							 | 
						||
| 
								 | 
							
								    The reverse neednt be true - `join(split(cmd))` may result in the addition
							 | 
						||
| 
								 | 
							
								    or removal of unnecessary escaping.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    @staticmethod
							 | 
						||
| 
								 | 
							
								    def join(argv):
							 | 
						||
| 
								 | 
							
								        """ Join a list of arguments into a command line string """
							 | 
						||
| 
								 | 
							
								        raise NotImplementedError
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @staticmethod
							 | 
						||
| 
								 | 
							
								    def split(cmd):
							 | 
						||
| 
								 | 
							
								        """ Split a command line string into a list of arguments """
							 | 
						||
| 
								 | 
							
								        raise NotImplementedError
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class WindowsParser:
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    The parsing behavior used by `subprocess.call("string")` on Windows, which
							 | 
						||
| 
								 | 
							
								    matches the Microsoft C/C++ runtime.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Note that this is _not_ the behavior of cmd.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    @staticmethod
							 | 
						||
| 
								 | 
							
								    def join(argv):
							 | 
						||
| 
								 | 
							
								        # note that list2cmdline is specific to the windows syntax
							 | 
						||
| 
								 | 
							
								        return subprocess.list2cmdline(argv)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @staticmethod
							 | 
						||
| 
								 | 
							
								    def split(cmd):
							 | 
						||
| 
								 | 
							
								        import ctypes  # guarded import for systems without ctypes
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            ctypes.windll
							 | 
						||
| 
								 | 
							
								        except AttributeError:
							 | 
						||
| 
								 | 
							
								            raise NotImplementedError
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # Windows has special parsing rules for the executable (no quotes),
							 | 
						||
| 
								 | 
							
								        # that we do not care about - insert a dummy element
							 | 
						||
| 
								 | 
							
								        if not cmd:
							 | 
						||
| 
								 | 
							
								            return []
							 | 
						||
| 
								 | 
							
								        cmd = 'dummy ' + cmd
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        CommandLineToArgvW = ctypes.windll.shell32.CommandLineToArgvW
							 | 
						||
| 
								 | 
							
								        CommandLineToArgvW.restype = ctypes.POINTER(ctypes.c_wchar_p)
							 | 
						||
| 
								 | 
							
								        CommandLineToArgvW.argtypes = (ctypes.c_wchar_p, ctypes.POINTER(ctypes.c_int))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        nargs = ctypes.c_int()
							 | 
						||
| 
								 | 
							
								        lpargs = CommandLineToArgvW(cmd, ctypes.byref(nargs))
							 | 
						||
| 
								 | 
							
								        args = [lpargs[i] for i in range(nargs.value)]
							 | 
						||
| 
								 | 
							
								        assert not ctypes.windll.kernel32.LocalFree(lpargs)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # strip the element we inserted
							 | 
						||
| 
								 | 
							
								        assert args[0] == "dummy"
							 | 
						||
| 
								 | 
							
								        return args[1:]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class PosixParser:
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    The parsing behavior used by `subprocess.call("string", shell=True)` on Posix.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    @staticmethod
							 | 
						||
| 
								 | 
							
								    def join(argv):
							 | 
						||
| 
								 | 
							
								        return ' '.join(shlex.quote(arg) for arg in argv)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @staticmethod
							 | 
						||
| 
								 | 
							
								    def split(cmd):
							 | 
						||
| 
								 | 
							
								        return shlex.split(cmd, posix=True)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if os.name == 'nt':
							 | 
						||
| 
								 | 
							
								    NativeParser = WindowsParser
							 | 
						||
| 
								 | 
							
								elif os.name == 'posix':
							 | 
						||
| 
								 | 
							
								    NativeParser = PosixParser
							 |