|
|
# encoding: utf-8
|
|
|
"""
|
|
|
Utilities for working with external processes.
|
|
|
"""
|
|
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
# Copyright (C) 2008-2009 The IPython Development Team
|
|
|
#
|
|
|
# Distributed under the terms of the BSD License. The full license is in
|
|
|
# the file COPYING, distributed as part of this software.
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
# Imports
|
|
|
#-----------------------------------------------------------------------------
|
|
|
from __future__ import print_function
|
|
|
|
|
|
# Stdlib
|
|
|
import os
|
|
|
import sys
|
|
|
import shlex
|
|
|
|
|
|
# Our own
|
|
|
if sys.platform == 'win32':
|
|
|
from ._process_win32 import _find_cmd, system, getoutput, AvoidUNCPath
|
|
|
else:
|
|
|
from ._process_posix import _find_cmd, system, getoutput
|
|
|
|
|
|
from ._process_common import getoutputerror
|
|
|
from IPython.utils import py3compat
|
|
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
# Code
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
class FindCmdError(Exception):
|
|
|
pass
|
|
|
|
|
|
|
|
|
def find_cmd(cmd):
|
|
|
"""Find absolute path to executable cmd in a cross platform manner.
|
|
|
|
|
|
This function tries to determine the full path to a command line program
|
|
|
using `which` on Unix/Linux/OS X and `win32api` on Windows. Most of the
|
|
|
time it will use the version that is first on the users `PATH`. If
|
|
|
cmd is `python` return `sys.executable`.
|
|
|
|
|
|
Warning, don't use this to find IPython command line programs as there
|
|
|
is a risk you will find the wrong one. Instead find those using the
|
|
|
following code and looking for the application itself::
|
|
|
|
|
|
from IPython.utils.path import get_ipython_module_path
|
|
|
from IPython.utils.process import pycmd2argv
|
|
|
argv = pycmd2argv(get_ipython_module_path('IPython.frontend.terminal.ipapp'))
|
|
|
|
|
|
Parameters
|
|
|
----------
|
|
|
cmd : str
|
|
|
The command line program to look for.
|
|
|
"""
|
|
|
if cmd == 'python':
|
|
|
return os.path.abspath(sys.executable)
|
|
|
try:
|
|
|
path = _find_cmd(cmd).rstrip()
|
|
|
except OSError:
|
|
|
raise FindCmdError('command could not be found: %s' % cmd)
|
|
|
# which returns empty if not found
|
|
|
if path == b'':
|
|
|
raise FindCmdError('command could not be found: %s' % cmd)
|
|
|
return os.path.abspath(path)
|
|
|
|
|
|
|
|
|
def pycmd2argv(cmd):
|
|
|
r"""Take the path of a python command and return a list (argv-style).
|
|
|
|
|
|
This only works on Python based command line programs and will find the
|
|
|
location of the ``python`` executable using ``sys.executable`` to make
|
|
|
sure the right version is used.
|
|
|
|
|
|
For a given path ``cmd``, this returns [cmd] if cmd's extension is .exe,
|
|
|
.com or .bat, and [, cmd] otherwise.
|
|
|
|
|
|
Parameters
|
|
|
----------
|
|
|
cmd : string
|
|
|
The path of the command.
|
|
|
|
|
|
Returns
|
|
|
-------
|
|
|
argv-style list.
|
|
|
"""
|
|
|
ext = os.path.splitext(cmd)[1]
|
|
|
if ext in ['.exe', '.com', '.bat']:
|
|
|
return [cmd]
|
|
|
else:
|
|
|
if sys.platform == 'win32':
|
|
|
# The -u option here turns on unbuffered output, which is required
|
|
|
# on Win32 to prevent wierd conflict and problems with Twisted.
|
|
|
# Also, use sys.executable to make sure we are picking up the
|
|
|
# right python exe.
|
|
|
return [sys.executable, '-u', cmd]
|
|
|
else:
|
|
|
return [sys.executable, cmd]
|
|
|
|
|
|
|
|
|
def arg_split(s, posix=False):
|
|
|
"""Split a command line's arguments in a shell-like manner.
|
|
|
|
|
|
This is a modified version of the standard library's shlex.split()
|
|
|
function, but with a default of posix=False for splitting, so that quotes
|
|
|
in inputs are respected."""
|
|
|
|
|
|
# Unfortunately, python's shlex module is buggy with unicode input:
|
|
|
# http://bugs.python.org/issue1170
|
|
|
# At least encoding the input when it's unicode seems to help, but there
|
|
|
# may be more problems lurking. Apparently this is fixed in python3.
|
|
|
is_unicode = False
|
|
|
if (not py3compat.PY3) and isinstance(s, unicode):
|
|
|
is_unicode = True
|
|
|
s = s.encode('utf-8')
|
|
|
lex = shlex.shlex(s, posix=posix)
|
|
|
lex.whitespace_split = True
|
|
|
tokens = list(lex)
|
|
|
if is_unicode:
|
|
|
# Convert the tokens back to unicode.
|
|
|
tokens = [x.decode('utf-8') for x in tokens]
|
|
|
return tokens
|
|
|
|
|
|
|
|
|
def abbrev_cwd():
|
|
|
""" Return abbreviated version of cwd, e.g. d:mydir """
|
|
|
cwd = os.getcwdu().replace('\\','/')
|
|
|
drivepart = ''
|
|
|
tail = cwd
|
|
|
if sys.platform == 'win32':
|
|
|
if len(cwd) < 4:
|
|
|
return cwd
|
|
|
drivepart,tail = os.path.splitdrive(cwd)
|
|
|
|
|
|
|
|
|
parts = tail.split('/')
|
|
|
if len(parts) > 2:
|
|
|
tail = '/'.join(parts[-2:])
|
|
|
|
|
|
return (drivepart + (
|
|
|
cwd == '/' and '/' or tail))
|
|
|
|