12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- """
- Helper functions for interacting with the shell, and consuming shell-style
- parameters provided in config files.
- """
- import os
- import shlex
- import subprocess
- try:
- from shlex import quote
- except ImportError:
- from pipes import quote
- __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(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
|