mirror of https://github.com/pypa/hatch.git
152 lines
4.2 KiB
Python
152 lines
4.2 KiB
Python
import os
|
|
import pexpect
|
|
import shutil
|
|
import signal
|
|
import subprocess
|
|
|
|
from hatch.settings import load_settings
|
|
from hatch.utils import NEED_SUBPROCESS_SHELL, ON_WINDOWS, basepath
|
|
|
|
DEFAULT_SHELL = 'cmd' if ON_WINDOWS else 'bash'
|
|
|
|
|
|
def get_terminal_dimensions():
|
|
columns, lines = shutil.get_terminal_size()
|
|
return lines, columns
|
|
|
|
|
|
def cmd_shell(exe_dir, shell_path):
|
|
result = subprocess.run(
|
|
[shell_path or 'cmd', '/k', os.path.join(exe_dir, 'activate.bat')],
|
|
shell=NEED_SUBPROCESS_SHELL
|
|
)
|
|
return result.returncode
|
|
|
|
|
|
def ps_shell(exe_dir, shell_path):
|
|
result = subprocess.run(
|
|
[shell_path or 'powershell', '-executionpolicy', 'bypass', '-NoExit',
|
|
'-NoLogo', '-File', os.path.join(exe_dir, 'activate.ps1')],
|
|
shell=NEED_SUBPROCESS_SHELL
|
|
)
|
|
return result.returncode
|
|
|
|
|
|
def bash_shell(exe_dir, shell_path):
|
|
terminal = pexpect.spawn(
|
|
shell_path or 'bash',
|
|
args=['-i'],
|
|
dimensions=get_terminal_dimensions()
|
|
)
|
|
|
|
def sigwinch_passthrough(sig, data):
|
|
terminal.setwinsize(*get_terminal_dimensions())
|
|
signal.signal(signal.SIGWINCH, sigwinch_passthrough)
|
|
|
|
terminal.sendline('source "{}"'.format(os.path.join(exe_dir, 'activate')))
|
|
terminal.interact(escape_character=None)
|
|
terminal.close()
|
|
return terminal.exitstatus
|
|
|
|
|
|
def fish_shell(exe_dir, shell_path):
|
|
terminal = pexpect.spawn(
|
|
shell_path or 'fish',
|
|
args=['-i'],
|
|
dimensions=get_terminal_dimensions()
|
|
)
|
|
|
|
def sigwinch_passthrough(sig, data):
|
|
terminal.setwinsize(*get_terminal_dimensions())
|
|
signal.signal(signal.SIGWINCH, sigwinch_passthrough)
|
|
|
|
terminal.sendline('. "{}"'.format(os.path.join(exe_dir, 'activate.fish')))
|
|
terminal.interact(escape_character=None)
|
|
terminal.close()
|
|
return terminal.exitstatus
|
|
|
|
|
|
def zsh_shell(exe_dir, shell_path):
|
|
terminal = pexpect.spawn(
|
|
shell_path or 'zsh',
|
|
args=['-i'],
|
|
dimensions=get_terminal_dimensions()
|
|
)
|
|
|
|
def sigwinch_passthrough(sig, data):
|
|
terminal.setwinsize(*get_terminal_dimensions())
|
|
signal.signal(signal.SIGWINCH, sigwinch_passthrough)
|
|
|
|
terminal.sendline('source "{}"'.format(os.path.join(exe_dir, 'activate')))
|
|
terminal.interact(escape_character=None)
|
|
terminal.close()
|
|
return terminal.exitstatus
|
|
|
|
|
|
def xonsh_shell(exe_dir, shell_path):
|
|
if ON_WINDOWS:
|
|
result = subprocess.run(
|
|
[shell_path or 'xonsh', '-i', '-D',
|
|
'VIRTUAL_ENV={}'.format(os.path.dirname(exe_dir))],
|
|
shell=NEED_SUBPROCESS_SHELL
|
|
)
|
|
return result.returncode
|
|
else:
|
|
terminal = pexpect.spawn(
|
|
shell_path or 'xonsh',
|
|
args=['-i', '-D', 'VIRTUAL_ENV={}'.format(os.path.dirname(exe_dir))],
|
|
dimensions=get_terminal_dimensions()
|
|
)
|
|
|
|
def sigwinch_passthrough(sig, data):
|
|
terminal.setwinsize(*get_terminal_dimensions())
|
|
signal.signal(signal.SIGWINCH, sigwinch_passthrough)
|
|
|
|
# Just in case pyenv works with xonsh, supersede it.
|
|
terminal.sendline('$PATH.insert(0, "{}")'.format(exe_dir))
|
|
|
|
terminal.interact(escape_character=None)
|
|
terminal.close()
|
|
return terminal.exitstatus
|
|
|
|
|
|
def unknown_shell(shell_name):
|
|
result = subprocess.run(shell_name.split(), shell=NEED_SUBPROCESS_SHELL)
|
|
return result.returncode
|
|
|
|
|
|
SHELL_COMMANDS = {
|
|
'cmd': cmd_shell,
|
|
'powershell': ps_shell,
|
|
'ps': ps_shell,
|
|
'bash': bash_shell,
|
|
'fish': fish_shell,
|
|
'zsh': zsh_shell,
|
|
'xonsh': xonsh_shell,
|
|
}
|
|
|
|
|
|
def get_default_shell_info(shell_name=None, settings=None):
|
|
if not shell_name:
|
|
settings = settings or load_settings(lazy=True)
|
|
|
|
shell_name = settings.get('shell')
|
|
if shell_name:
|
|
return shell_name, None
|
|
|
|
shell_path = os.environ.get('SHELL')
|
|
if shell_path:
|
|
shell_name = basepath(shell_path)
|
|
else:
|
|
shell_name = DEFAULT_SHELL
|
|
|
|
return shell_name, shell_path
|
|
|
|
return shell_name, None
|
|
|
|
|
|
def run_shell(exe_dir, shell_name=None):
|
|
shell_name, shell_path = get_default_shell_info(shell_name)
|
|
shell = SHELL_COMMANDS.get(shell_name)
|
|
return shell(exe_dir, shell_path) if shell else unknown_shell(shell_name)
|