|
""" |
|
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): |
|
|
|
return subprocess.list2cmdline(argv) |
|
|
|
@staticmethod |
|
def split(cmd): |
|
import ctypes |
|
try: |
|
ctypes.windll |
|
except AttributeError: |
|
raise NotImplementedError |
|
|
|
|
|
|
|
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) |
|
|
|
|
|
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 |
|
|