diff --git a/kittens/ssh/main.py b/kittens/ssh/main.py index 1daa82a3d..7bebbe8d7 100644 --- a/kittens/ssh/main.py +++ b/kittens/ssh/main.py @@ -26,6 +26,7 @@ from kitty.types import run_once from kitty.utils import SSHConnectionData from .completion import complete, ssh_options +from .config import options_for_host from .options.types import Options as SSHOptions from .options.utils import DELETE_ENV_VAR @@ -115,7 +116,6 @@ def load_ssh_options() -> Dict[str, SSHOptions]: def get_ssh_data(msg: str, ssh_opts: Optional[Dict[str, SSHOptions]] = None) -> Iterator[bytes]: - from .config import options_for_host record_sep = b'\036' if ssh_opts is None: @@ -319,7 +319,7 @@ def parse_ssh_args(args: List[str]) -> Tuple[List[str], List[str], bool]: return ssh_args, server_args, passthrough -def get_posix_cmd(remote_args: List[str]) -> List[str]: +def get_remote_command(remote_args: List[str], hostname: str = 'localhost', interpreter: str = 'sh') -> List[str]: command_to_execute = '' if remote_args: # ssh simply concatenates multiple commands using a space see @@ -328,7 +328,7 @@ def get_posix_cmd(remote_args: List[str]) -> List[str]: args = [c.replace("'", """'"'"'""") for c in remote_args] command_to_execute = "exec \"$login_shell\" -c '{}'".format(' '.join(args)) sh_script = load_script(exec_cmd=command_to_execute) - return [f'sh -c {shlex.quote(sh_script)}'] + return [f'{interpreter} -c {shlex.quote(sh_script)}'] def main(args: List[str]) -> NoReturn: @@ -348,8 +348,8 @@ def main(args: List[str]) -> NoReturn: cmd.append('-t') cmd.append('--') cmd.append(hostname) - f = get_posix_cmd - cmd += f(remote_args) + hostname_for_match = hostname.split('@', 1)[-1].split(':', 1)[0] + cmd += get_remote_command(remote_args, hostname, options_for_host(hostname_for_match, load_ssh_options()).interpreter) os.execvp('ssh', cmd) diff --git a/kittens/ssh/options/definition.py b/kittens/ssh/options/definition.py index d1159abb5..1bd6a924e 100644 --- a/kittens/ssh/options/definition.py +++ b/kittens/ssh/options/definition.py @@ -70,6 +70,14 @@ are processed alphabetically. The special value :code:`_kitty_copy_env_var_` will cause the value of the variable to be copied from the local machine. ''') +opt('interpreter', 'sh', long_text=''' +The interpreter to use on the remote host. Must be either a POSIX complaint shell +or a python executable. If the default sh is not available for broken, using +an alternate interpreter can be useful. Note that as the interpreter is used for +bootstrapping, hostname specific values are matched again the hostname from the +command line args rather than the actual remote hostname. +''') + opt('remote_dir', '.local/share/kitty-ssh-kitten', option_type='relative_dir', long_text=''' The location on the remote computer where the files needed for this kitten are installed. The location is relative to the HOME directory. Absolute paths or paths diff --git a/kittens/ssh/options/parse.py b/kittens/ssh/options/parse.py index 69fe7adbb..c6a79ac86 100644 --- a/kittens/ssh/options/parse.py +++ b/kittens/ssh/options/parse.py @@ -18,6 +18,9 @@ class Parser: def hostname(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: hostname(val, ans) + def interpreter(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['interpreter'] = str(val) + def remote_dir(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: ans['remote_dir'] = relative_dir(val) diff --git a/kittens/ssh/options/types.py b/kittens/ssh/options/types.py index 03922bafb..94efcde36 100644 --- a/kittens/ssh/options/types.py +++ b/kittens/ssh/options/types.py @@ -5,11 +5,12 @@ import kittens.ssh.copy option_names = ( # {{{ - 'copy', 'env', 'hostname', 'remote_dir', 'shell_integration') # }}} + 'copy', 'env', 'hostname', 'interpreter', 'remote_dir', 'shell_integration') # }}} class Options: hostname: str = '*' + interpreter: str = 'sh' remote_dir: str = '.local/share/kitty-ssh-kitten' shell_integration: str = 'inherit' copy: typing.Dict[str, kittens.ssh.copy.CopyInstruction] = {}