From 3bc7b5bad9a2968ef559d2578ad092fc11ae6d8c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 27 Sep 2021 10:58:40 +0530 Subject: [PATCH] Remote file transfer: Fix transfer not working is custom ssh port or identity is specified on the SSH command line Fixes #4067 --- docs/changelog.rst | 2 ++ kittens/remote_file/main.py | 4 +++- kittens/ssh/main.py | 30 +++++++++++++++++++++++++----- kitty/utils.py | 1 + kitty/window.py | 2 +- kitty_tests/ssh.py | 25 +++++++++++++++++++++++++ 6 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 kitty_tests/ssh.py diff --git a/docs/changelog.rst b/docs/changelog.rst index 4d08090cc..df302227f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -55,6 +55,8 @@ To update |kitty|, :doc:`follow the instructions `. - Linux: Fix IME with fcitx5 not working after fcitx5 is restarted (:pull:`4059`) +- Remote file transfer: Fix transfer not working is custom ssh port or identity + is specified on the command line (:iss:`4067`) 0.23.1 [2021-08-17] diff --git a/kittens/remote_file/main.py b/kittens/remote_file/main.py index 91b0c428b..fa3255258 100644 --- a/kittens/remote_file/main.py +++ b/kittens/remote_file/main.py @@ -118,7 +118,9 @@ class ControlMaster: '-o', 'TCPKeepAlive=yes', '-o', 'ControlPersist=yes' ] if conn_data.port: - cmd += ['-p', str(conn_data.port)] + cmd.extend(['-p', str(conn_data.port)]) + if conn_data.identity_file: + cmd.extend(['-i', conn_data.identity_file]) self.batch_cmd_prefix = cmd + ['-o', 'BatchMode=yes'] def __enter__(self) -> 'ControlMaster': diff --git a/kittens/ssh/main.py b/kittens/ssh/main.py index 72085ddc9..e6bac3698 100644 --- a/kittens/ssh/main.py +++ b/kittens/ssh/main.py @@ -140,13 +140,13 @@ def get_ssh_cli() -> Tuple[Set[str], Set[str]]: return boolean_ssh_args, other_ssh_args -def get_connection_data(args: List[str]) -> Optional[SSHConnectionData]: +def get_connection_data(args: List[str], cwd: str = '') -> Optional[SSHConnectionData]: boolean_ssh_args, other_ssh_args = get_ssh_cli() - found_ssh = '' port: Optional[int] = None - expecting_port = False + expecting_port = expecting_identity = False expecting_option_val = False expecting_hostname = False + host_name = identity_file = found_ssh = '' for i, arg in enumerate(args): if not found_ssh: @@ -154,7 +154,8 @@ def get_connection_data(args: List[str]) -> Optional[SSHConnectionData]: found_ssh = arg continue if expecting_hostname: - return SSHConnectionData(found_ssh, arg, port) + host_name = arg + continue if arg.startswith('-') and not expecting_option_val: if arg in boolean_ssh_args: continue @@ -164,8 +165,15 @@ def get_connection_data(args: List[str]) -> Optional[SSHConnectionData]: if arg[2:].isdigit(): with suppress(Exception): port = int(arg[2:]) + continue elif arg == '-p': expecting_port = True + elif arg.startswith('-i'): + if arg == '-i': + expecting_identity = True + else: + identity_file = arg[2:] + continue expecting_option_val = True continue @@ -174,10 +182,22 @@ def get_connection_data(args: List[str]) -> Optional[SSHConnectionData]: with suppress(Exception): port = int(arg) expecting_port = False + elif expecting_identity: + identity_file = arg expecting_option_val = False continue - return SSHConnectionData(found_ssh, arg, port) + if not host_name: + host_name = arg + if not host_name: + return None + if identity_file: + if not os.path.isabs(identity_file): + identity_file = os.path.expanduser(identity_file) + if not os.path.isabs(identity_file): + identity_file = os.path.normpath(os.path.join(cwd or os.getcwd(), identity_file)) + + return SSHConnectionData(found_ssh, host_name, port, identity_file) class InvalidSSHArgs(ValueError): diff --git a/kitty/utils.py b/kitty/utils.py index 0edfe3a19..260e32504 100644 --- a/kitty/utils.py +++ b/kitty/utils.py @@ -705,6 +705,7 @@ class SSHConnectionData(NamedTuple): binary: str hostname: str port: Optional[int] = None + identity_file: str = '' def get_new_os_window_size( diff --git a/kitty/window.py b/kitty/window.py index cf7c140b5..c716af4ab 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -649,7 +649,7 @@ class Window: def handle_remote_file(self, netloc: str, remote_path: str) -> None: from kittens.ssh.main import get_connection_data args = self.child.foreground_cmdline - conn_data = get_connection_data(args) + conn_data = get_connection_data(args, self.child.foreground_cwd or self.child.current_cwd or '') if conn_data is None: get_boss().show_error('Could not handle remote file', 'No SSH connection data found in: {args}') return diff --git a/kitty_tests/ssh.py b/kitty_tests/ssh.py new file mode 100644 index 000000000..9c0886b7c --- /dev/null +++ b/kitty_tests/ssh.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +# License: GPLv3 Copyright: 2021, Kovid Goyal + + +import os +from . import BaseTest + +from kittens.ssh.main import get_connection_data +from kitty.utils import SSHConnectionData + + +class SSHTest(BaseTest): + + def test_ssh_connection_data(self): + def t(cmdline, binary='ssh', host='main', port=None, identity_file=''): + if identity_file: + identity_file = os.path.abspath(identity_file) + q = get_connection_data(cmdline.split()) + self.ae(q, SSHConnectionData(binary, host, port, identity_file)) + + t('ssh main') + t('ssh un@ip -i ident -p34', host='un@ip', port=34, identity_file='ident') + t('ssh un@ip -iident -p34', host='un@ip', port=34, identity_file='ident') + t('ssh -p 33 main', port=33)