make xonsh able to failback to other shells

This commit is contained in:
Hugo Wang 2016-12-17 18:10:29 +08:00
parent 25cf37a090
commit 3980da870e
2 changed files with 49 additions and 4 deletions

View file

@ -1,13 +1,13 @@
# -*- coding: utf-8 -*-
"""Tests the xonsh main function."""
from __future__ import unicode_literals, print_function
from contextlib import contextmanager
import builtins
import os.path
import sys
from unittest.mock import patch
import xonsh.main
import pytest
@ -48,8 +48,8 @@ def test_premain_D(shell):
assert (builtins.__xonsh_env__.get('TEST2') == 'LOL')
@pytest.mark.parametrize('arg',
['', '-i', '-vERSION', '-hAALP','TTTT', '-TT', '--TTT'] )
@pytest.mark.parametrize(
'arg', ['', '-i', '-vERSION', '-hAALP', 'TTTT', '-TT', '--TTT'])
def test_premain_with_file_argument(arg, shell):
xonsh.main.premain(['tests/sample.xsh', arg])
assert not (builtins.__xonsh_env__.get('XONSH_INTERACTIVE'))
@ -65,3 +65,26 @@ def test_premain_invalid_arguments(case, shell, capsys):
with pytest.raises(SystemExit):
xonsh.main.premain([case])
assert 'unrecognized argument' in capsys.readouterr()[1]
def test_main_failback(shell, monkeypatch):
failback_checker = []
monkeypatch.setattr(sys, 'stderr', open(os.devnull, 'w'))
def mocked_main(*args):
raise Exception('A fake failure')
monkeypatch.setattr(xonsh.main, 'main_xonsh', mocked_main)
def mocked_execlp(f, *args):
failback_checker.append(f)
failback_checker.append(args[0])
monkeypatch.setattr(os, 'execlp', mocked_execlp)
monkeypatch.setattr(os.path, 'exists', lambda x: True)
@contextmanager
def mocked_open(*args):
yield ['/bin/xshell']
monkeypatch.setattr(builtins, 'open', mocked_open)
xonsh.main.main()
assert failback_checker == ['/bin/xshell', '/bin/xshell']

View file

@ -6,6 +6,7 @@ import enum
import argparse
import builtins
import contextlib
import traceback
from xonsh import __version__
from xonsh.lazyasd import lazyobject
@ -253,6 +254,27 @@ def premain(argv=None):
def main(argv=None):
try:
return main_xonsh(argv)
except Exception:
traceback.print_exc()
print('Xonsh encountered an issue during launch', file=sys.stderr)
foreign_shell = None
shells_file = '/etc/shells'
if not os.path.exists(shells_file):
return
with open(shells_file) as f:
for line in f:
if not line.strip() or line.strip().startswith('#'):
continue
foreign_shell = line.strip()
break
if foreign_shell:
print('Failback to {}'.format(foreign_shell), file=sys.stderr)
os.execlp(foreign_shell, foreign_shell)
def main_xonsh(argv=None):
"""Main entry point for xonsh cli."""
if argv is None:
argv = sys.argv[1:]