set error on exit for foriegn shelles

This commit is contained in:
Anthony Scopatz 2016-05-07 16:29:48 -04:00
parent 33785dd9b0
commit 6c2940d8cf
2 changed files with 61 additions and 42 deletions

View file

@ -3,17 +3,17 @@ Static Configuration File
In addition to the run control file, xonsh allows you to have a static config file. In addition to the run control file, xonsh allows you to have a static config file.
This JSON-formatted file lives at ``$XONSH_CONFIG_DIR/config.json``, which is This JSON-formatted file lives at ``$XONSH_CONFIG_DIR/config.json``, which is
normally ``~/.config/xonsh/config.json``. The purpose of this file is to allow normally ``~/.config/xonsh/config.json``. The purpose of this file is to allow
users to set runtime parameters *before* anything else happens. This includes users to set runtime parameters *before* anything else happens. This includes
loading data from various foreign shells or setting critical environment loading data from various foreign shells or setting critical environment
variables. variables.
This is a dictionary or JSON object at its top-level. It has the following This is a dictionary or JSON object at its top-level. It has the following
top-level keys. All top-level keys are optional. top-level keys. All top-level keys are optional.
``env`` ``env``
-------- --------
This is a simple string-keyed dictionary that lets you set environment This is a simple string-keyed dictionary that lets you set environment
variables. For example, variables. For example,
.. code:: json .. code:: json
@ -28,9 +28,9 @@ variables. For example,
-------------------- --------------------
This is a list (JSON Array) of dicts (JSON objects) that represent the This is a list (JSON Array) of dicts (JSON objects) that represent the
foreign shells to inspect for extra start up information, such as environment foreign shells to inspect for extra start up information, such as environment
variables, aliases, and foreign shell functions. The suite of data gathered variables, aliases, and foreign shell functions. The suite of data gathered
may be expanded in the future. Each shell dictionary unpacked and passed into may be expanded in the future. Each shell dictionary unpacked and passed into
the ``xonsh.foreign_shells.foreign_shell_data()`` function. Thus, these the ``xonsh.foreign_shells.foreign_shell_data()`` function. Thus, these
dictionaries have the following structure: dictionaries have the following structure:
:shell: *str, required* - The name or path of the shell, such as "bash" or "/bin/sh". :shell: *str, required* - The name or path of the shell, such as "bash" or "/bin/sh".
@ -42,27 +42,34 @@ dictionaries have the following structure:
``default="env"`` ``default="env"``
:aliascmd: *str, optional* - The command to generate alais output with. :aliascmd: *str, optional* - The command to generate alais output with.
``default="alias"`` ``default="alias"``
:extra_args: *list of str, optional* - Addtional command line options to pass :extra_args: *list of str, optional* - Addtional command line options to pass
into the shell. ``default=[]`` into the shell. ``default=[]``
:currenv: *dict or null, optional* - Manual override for the current environment. :currenv: *dict or null, optional* - Manual override for the current environment.
``default=null`` ``default=null``
:safe: *bool, optional* - Flag for whether or not to safely handle exceptions :safe: *bool, optional* - Flag for whether or not to safely handle exceptions
and other errors. ``default=true`` and other errors. ``default=true``
:prevcmd: *str, optional* - An additional command or script to run before :prevcmd: *str, optional* - An additional command or script to run before
anything else, useful for sourcing and other commands that may require anything else, useful for sourcing and other commands that may require
environment recovery. ``default=''`` environment recovery. ``default=''``
:postcmd: *str, optional* - A command to run after everything else, useful for :postcmd: *str, optional* - A command to run after everything else, useful for
cleaning up any damage that the ``prevcmd`` may have caused. ``default=''`` cleaning up any damage that the ``prevcmd`` may have caused. ``default=''``
:funcscmd: *str or None, optional* - This is a command or script that can be :funcscmd: *str or None, optional* - This is a command or script that can be
used to determine the names and locations of any functions that are native used to determine the names and locations of any functions that are native
to the foreign shell. This command should print *only* a whitespace to the foreign shell. This command should print *only* a whitespace
separated sequence of pairs function name & filenames where the functions separated sequence of pairs function name & filenames where the functions
are defined. If this is None (null), then a default script will attempted are defined. If this is None (null), then a default script will attempted
to be looked up based on the shell name. Callable wrappers for these to be looked up based on the shell name. Callable wrappers for these
functions will be returned in the aliases dictionary. ``default=null`` functions will be returned in the aliases dictionary. ``default=null``
:sourcer: *str or None, optional* - How to source a foreign shell file for :sourcer: *str or None, optional* - How to source a foreign shell file for
purposes of calling functions in that shell. If this is None, a default purposes of calling functions in that shell. If this is None, a default
value will attempt to be looked up based on the shell name. ``default=null`` value will attempt to be looked up based on the shell name. ``default=null``
:runcmd : *str or None, optional* - Command line switches to use when
running the script, such as ``-c`` for Bash and ``/C`` for cmd.exe.
``default=null``
:seterrcmd : *str or None, optional* - Command that enables exit-on-error
for the shell. For example, this is "set -e" in Bash. To disable
exit-on-error behavior, simply pass in an empty string. ``default=null``
Some examples can be seen below: Some examples can be seen below:
@ -77,8 +84,8 @@ Some examples can be seen below:
# load bash as a login shell with custom rcfile # load bash as a login shell with custom rcfile
{"foreign_shells": [ {"foreign_shells": [
{"shell": "bash", {"shell": "bash",
"login": true, "login": true,
"extra_args": ["--rcfile", "/path/to/rcfile"] "extra_args": ["--rcfile", "/path/to/rcfile"]
} }
] ]

View file

@ -15,6 +15,7 @@ from xonsh.tools import to_bool, ensure_string
COMMAND = """ COMMAND = """
{seterrcmd}
{prevcmd} {prevcmd}
echo __XONSH_ENV_BEG__ echo __XONSH_ENV_BEG__
{envcmd} {envcmd}
@ -80,54 +81,52 @@ fi
echo ${namefile} echo ${namefile}
""".strip() """.strip()
# mapping of shell name alises to keys in other lookup dictionaries.
CANON_SHELL_NAMES = {
'bash': 'bash',
'/bin/bash': 'bash',
'zsh': 'zsh',
'/bin/zsh': 'zsh',
'/usr/bin/zsh': 'zsh',
'cmd': 'cmd',
'cmd.exe': 'cmd',
}
DEFAULT_ENVCMDS = { DEFAULT_ENVCMDS = {
'bash': 'env', 'bash': 'env',
'/bin/bash': 'env',
'zsh': 'env', 'zsh': 'env',
'/bin/zsh': 'env',
'/usr/bin/zsh': 'env',
'cmd': 'set', 'cmd': 'set',
} }
DEFAULT_ALIASCMDS = { DEFAULT_ALIASCMDS = {
'bash': 'alias', 'bash': 'alias',
'/bin/bash': 'alias',
'zsh': 'alias -L', 'zsh': 'alias -L',
'/bin/zsh': 'alias -L',
'/usr/bin/zsh': 'alias -L',
'cmd': '', 'cmd': '',
} }
DEFAULT_FUNCSCMDS = { DEFAULT_FUNCSCMDS = {
'bash': DEFAULT_BASH_FUNCSCMD, 'bash': DEFAULT_BASH_FUNCSCMD,
'/bin/bash': DEFAULT_BASH_FUNCSCMD,
'zsh': DEFAULT_ZSH_FUNCSCMD, 'zsh': DEFAULT_ZSH_FUNCSCMD,
'/bin/zsh': DEFAULT_ZSH_FUNCSCMD,
'/usr/bin/zsh': DEFAULT_ZSH_FUNCSCMD,
'cmd': '', 'cmd': '',
} }
DEFAULT_SOURCERS = { DEFAULT_SOURCERS = {
'bash': 'source', 'bash': 'source',
'/bin/bash': 'source',
'zsh': 'source', 'zsh': 'source',
'/bin/zsh': 'source',
'/usr/bin/zsh': 'source',
'cmd': 'call', 'cmd': 'call',
} }
DEFAULT_TMPFILE_EXT = { DEFAULT_TMPFILE_EXT = {
'bash': '.sh', 'bash': '.sh',
'/bin/bash': '.sh',
'zsh': '.zsh', 'zsh': '.zsh',
'/bin/zsh': '.zsh',
'/usr/bin/zsh': '.zsh',
'cmd': '.bat', 'cmd': '.bat',
} }
DEFAULT_RUNCMD = { DEFAULT_RUNCMD = {
'bash': '-c', 'bash': '-c',
'/bin/bash': '-c',
'zsh': '-c', 'zsh': '-c',
'/bin/zsh': '-c',
'/usr/bin/zsh': '-c',
'cmd': '/C', 'cmd': '/C',
} }
DEFAULT_SETERRCMD = {
'bash': 'set -e',
'zsh': 'set -e',
'cmd': '',
}
@lru_cache() @lru_cache()
@ -135,7 +134,7 @@ def foreign_shell_data(shell, interactive=True, login=False, envcmd=None,
aliascmd=None, extra_args=(), currenv=None, aliascmd=None, extra_args=(), currenv=None,
safe=True, prevcmd='', postcmd='', funcscmd=None, safe=True, prevcmd='', postcmd='', funcscmd=None,
sourcer=None, use_tmpfile=False, tmpfile_ext=None, sourcer=None, use_tmpfile=False, tmpfile_ext=None,
runcmd=None): runcmd=None, seterrcmd=None):
"""Extracts data from a foreign (non-xonsh) shells. Currently this gets """Extracts data from a foreign (non-xonsh) shells. Currently this gets
the environment, aliases, and functions but may be extended in the future. the environment, aliases, and functions but may be extended in the future.
@ -180,6 +179,13 @@ def foreign_shell_data(shell, interactive=True, login=False, envcmd=None,
parsed directly to the shell parsed directly to the shell
tmpfile_ext : str or None, optional tmpfile_ext : str or None, optional
If tmpfile is True this sets specifies the extension used. If tmpfile is True this sets specifies the extension used.
runcmd : str or None, optional
Command line switches to use when running the script, such as
-c for Bash and /C for cmd.exe.
seterrcmd : str or None, optional
Command that enables exit-on-error for the shell. For example, this
is "set -e" in Bash. To disable exit-on-error behavior, simply pass
in an empty string.
Returns Returns
------- -------
@ -195,13 +201,16 @@ def foreign_shell_data(shell, interactive=True, login=False, envcmd=None,
cmd.append('-i') cmd.append('-i')
if login: if login:
cmd.append('-l') cmd.append('-l')
envcmd = DEFAULT_ENVCMDS.get(shell, 'env') if envcmd is None else envcmd shkey = CANON_SHELL_NAMES[shell]
aliascmd = DEFAULT_ALIASCMDS.get(shell, 'alias') if aliascmd is None else aliascmd envcmd = DEFAULT_ENVCMDS.get(shkey, 'env') if envcmd is None else envcmd
funcscmd = DEFAULT_FUNCSCMDS.get(shell, 'echo {}') if funcscmd is None else funcscmd aliascmd = DEFAULT_ALIASCMDS.get(shkey, 'alias') if aliascmd is None else aliascmd
tmpfile_ext = DEFAULT_TMPFILE_EXT.get(shell, 'sh') if tmpfile_ext is None else tmpfile_ext funcscmd = DEFAULT_FUNCSCMDS.get(shkey, 'echo {}') if funcscmd is None else funcscmd
runcmd = DEFAULT_RUNCMD.get(shell, '-c') if runcmd is None else runcmd tmpfile_ext = DEFAULT_TMPFILE_EXT.get(shkey, 'sh') if tmpfile_ext is None else tmpfile_ext
runcmd = DEFAULT_RUNCMD.get(shkey, '-c') if runcmd is None else runcmd
seterrcmd = DEFAULT_SETERRCMD.get(shkey, '') if seterrcmd is None else seterrcmd
command = COMMAND.format(envcmd=envcmd, aliascmd=aliascmd, prevcmd=prevcmd, command = COMMAND.format(envcmd=envcmd, aliascmd=aliascmd, prevcmd=prevcmd,
postcmd=postcmd, funcscmd=funcscmd).strip() postcmd=postcmd, funcscmd=funcscmd,
seterrcmd=seterrcmd).strip()
cmd.append(runcmd) cmd.append(runcmd)
@ -424,6 +433,9 @@ def ensure_shell(shell):
if 'sourcer' in shell_keys: if 'sourcer' in shell_keys:
shell['sourcer'] = None if shell['sourcer'] is None \ shell['sourcer'] = None if shell['sourcer'] is None \
else ensure_string(shell['sourcer']) else ensure_string(shell['sourcer'])
if 'seterrcmd' in shell_keys:
shell['seterrcmd'] = None if shell['seterrcmd'] is None \
else ensure_string(shell['seterrcmd'])
return shell return shell