Files
Iristyle a000ce8acc feat(ST2.UtilPackages): bump up all packages
- Refresh PackageCache with latest versions of everything
2013-09-16 22:35:46 -04:00

168 lines
5.2 KiB
Python

import os
import subprocess
import re
if os.name == 'nt':
from ctypes import windll, create_unicode_buffer
from .console_write import console_write
from .unicode import unicode_from_os
from .show_error import show_error
try:
# Python 2
str_cls = unicode
except (NameError):
# Python 3
str_cls = str
def create_cmd(args, basename_binary=False):
"""
Takes an array of strings to be passed to subprocess.Popen and creates
a string that can be pasted into a terminal
:param args:
The array containing the binary name/path and all arguments
:param basename_binary:
If only the basename of the binary should be disabled instead of the full path
:return:
The command string
"""
if basename_binary:
args[0] = os.path.basename(args[0])
if os.name == 'nt':
return subprocess.list2cmdline(args)
else:
escaped_args = []
for arg in args:
if re.search('^[a-zA-Z0-9/_^\\-\\.:=]+$', arg) == None:
arg = u"'" + arg.replace(u"'", u"'\\''") + u"'"
escaped_args.append(arg)
return u' '.join(escaped_args)
class Cli(object):
"""
Base class for running command line apps
:param binary:
The full filesystem path to the executable for the version control
system. May be set to None to allow the code to try and find it.
"""
cli_name = None
def __init__(self, binary, debug):
self.binary = binary
self.debug = debug
def execute(self, args, cwd, input=None):
"""
Creates a subprocess with the executable/args
:param args:
A list of the executable path and all arguments to it
:param cwd:
The directory in which to run the executable
:param input:
The input text to send to the program
:return: A string of the executable output
"""
startupinfo = None
if os.name == 'nt':
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
# Make sure the cwd is ascii
try:
cwd.encode('ascii')
except UnicodeEncodeError:
buf = create_unicode_buffer(512)
if windll.kernel32.GetShortPathNameW(cwd, buf, len(buf)):
cwd = buf.value
if self.debug:
console_write(u"Trying to execute command %s" % create_cmd(args), True)
try:
proc = subprocess.Popen(args, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
startupinfo=startupinfo, cwd=cwd)
if input and isinstance(input, str_cls):
input = input.encode('utf-8')
output, _ = proc.communicate(input)
output = output.decode('utf-8')
output = output.replace('\r\n', '\n').rstrip(' \n\r')
return output
except (OSError) as e:
cmd = create_cmd(args)
error = unicode_from_os(e)
message = u"Error executing: %s\n%s\n\nTry checking your \"%s_binary\" setting?" % (cmd, error, self.cli_name)
show_error(message)
return False
def find_binary(self, name):
"""
Locates the executable by looking in the PATH and well-known directories
:param name:
The string filename of the executable
:return: The filesystem path to the executable, or None if not found
"""
if self.binary:
if self.debug:
error_string = u"Using \"%s_binary\" from settings \"%s\"" % (
self.cli_name, self.binary)
console_write(error_string, True)
return self.binary
# Try the path first
for dir_ in os.environ['PATH'].split(os.pathsep):
path = os.path.join(dir_, name)
if os.path.exists(path):
if self.debug:
console_write(u"Found %s at \"%s\"" % (self.cli_name, path), True)
return path
# This is left in for backwards compatibility and for windows
# users who may have the binary, albeit in a common dir that may
# not be part of the PATH
if os.name == 'nt':
dirs = ['C:\\Program Files\\Git\\bin',
'C:\\Program Files (x86)\\Git\\bin',
'C:\\Program Files\\TortoiseGit\\bin',
'C:\\Program Files\\Mercurial',
'C:\\Program Files (x86)\\Mercurial',
'C:\\Program Files (x86)\\TortoiseHg',
'C:\\Program Files\\TortoiseHg',
'C:\\cygwin\\bin']
else:
# ST seems to launch with a minimal set of environmental variables
# on OS X, so we add some common paths for it
dirs = ['/usr/local/git/bin', '/usr/local/bin']
for dir_ in dirs:
path = os.path.join(dir_, name)
if os.path.exists(path):
if self.debug:
console_write(u"Found %s at \"%s\"" % (self.cli_name, path), True)
return path
if self.debug:
console_write(u"Could not find %s on your machine" % self.cli_name, True)
return None