diff --git a/pipenv/core.py b/pipenv/core.py index 4c8667e7..f9405448 100644 --- a/pipenv/core.py +++ b/pipenv/core.py @@ -2028,6 +2028,7 @@ def do_uninstall( def do_shell(three=None, python=False, fancy=False, shell_args=None): + from pipenv.patched.pew import pew # Ensure that virtualenv is available. ensure_project(three=three, python=python, validate=False) @@ -2097,14 +2098,13 @@ def do_shell(three=None, python=False, fancy=False, shell_args=None): # Windows! except AttributeError: - import subprocess + # import subprocess # Tell pew to use the project directory as its workon_home with temp_environ(): if PIPENV_VENV_IN_PROJECT: os.environ['WORKON_HOME'] = project.project_directory - p = subprocess.Popen([cmd] + list(args), shell=True, universal_newlines=True) - p.communicate() - sys.exit(p.returncode) + pew.workon_cmd([workon_name]) + sys.exit(0) # Activate the virtualenv if in compatibility mode. if compat: diff --git a/pipenv/patched/pew/_win_utils.py b/pipenv/patched/pew/_win_utils.py index 4d55b020..9f7b18b9 100644 --- a/pipenv/patched/pew/_win_utils.py +++ b/pipenv/patched/pew/_win_utils.py @@ -14,7 +14,7 @@ from ctypes.wintypes import DWORD, LONG ERROR_NO_MORE_FILES = 18 INVALID_HANDLE_VALUE = c_void_p(-1).value - +SHELL_NAMES = ['cmd', 'powershell', 'cmder'] class PROCESSENTRY32(Structure): _fields_ = [ @@ -92,16 +92,20 @@ def get_all_processes(): return pids -def get_grandparent_process(pid=None): - """Get grandparent process name of the supplied pid or os.getpid(). - - :param int pid: The pid to track. - :return: Name of the grandparent process. +def get_shell(pid=None, max_depth=4): + """Get the shell that the supplied pid or os.getpid() is running in. """ if not pid: pid = os.getpid() processes = get_all_processes() - ppid = processes[pid]['parent_pid'] - parent = processes[ppid] - grandparent = processes[parent['parent_pid']] - return grandparent['executable'] + + def check_parent(pid, lvl=0): + ppid = processes[pid].get('parent_pid') + if ppid and processes[ppid]['executable'].lower().rsplit('.', 1)[0] in SHELL_NAMES: + return processes[ppid]['executable'] + if lvl >= max_depth: + return + return check_parent(ppid, lvl=lvl+1) + if processes[pid]['executable'].lower().rsplit('.', 1)[0] in SHELL_NAMES: + return processes[pid]['executable'] + return check_parent(pid) diff --git a/pipenv/patched/pew/pew.py b/pipenv/patched/pew/pew.py index 470dfd3d..a6440919 100644 --- a/pipenv/patched/pew/pew.py +++ b/pipenv/patched/pew/pew.py @@ -36,7 +36,7 @@ else: InstallCommand = ListPythons = LocatePython = UninstallCommand = \ lambda : sys.exit('Command not supported on this platform') - from ._win_utils import get_grandparent_process + from ._win_utils import get_shell from pew._utils import (check_call, invoke, expandpath, own, env_bin_dir, check_path, temp_environ, NamedTemporaryFile, to_unicode) @@ -184,7 +184,7 @@ def _detect_shell(): if 'CMDER_ROOT' in os.environ: shell = 'Cmder' elif windows: - shell = get_grandparent_process(os.getpid()) + shell = get_shell(os.getpid()) else: shell = 'sh' return shell @@ -196,7 +196,7 @@ def shell(env, cwd=None): if shell_name not in ('Cmder', 'bash', 'elvish', 'powershell', 'klingon', 'cmd'): # On Windows the PATH is usually set with System Utility # so we won't worry about trying to check mistakes there - shell_check = (sys.executable + ' -c "from pew.pew import ' + shell_check = (sys.executable + ' -c "from pipenv.patched.pew import ' 'prevent_path_errors; prevent_path_errors()"') try: inve(env, shell, '-c', shell_check)