mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-16 13:34:48 +02:00
Asynchronously read ssh configuration
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
|||||||
"archive/tar"
|
"archive/tar"
|
||||||
"bytes"
|
"bytes"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
@@ -620,7 +621,7 @@ func change_colors(color_scheme string) (ans string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func run_ssh(ssh_args, server_args, found_extra_args []string, ssh_config *SSHConfig) (rc int, err error) {
|
func run_ssh(ssh_args, server_args, found_extra_args []string, ssh_config_channel <-chan *SSHConfig) (rc int, err error) {
|
||||||
go shell_integration.Data()
|
go shell_integration.Data()
|
||||||
go RelevantKittyOpts()
|
go RelevantKittyOpts()
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -630,14 +631,11 @@ func run_ssh(ssh_args, server_args, found_extra_args []string, ssh_config *SSHCo
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
cmd := append([]string{SSHExe()}, ssh_args...)
|
cmd := append([]string{SSHExe()}, ssh_args...)
|
||||||
cd := connection_data{remote_args: server_args[1:], ssh_config: ssh_config}
|
cd := connection_data{remote_args: server_args[1:]}
|
||||||
hostname := server_args[0]
|
hostname := server_args[0]
|
||||||
if len(cd.remote_args) == 0 {
|
if len(cd.remote_args) == 0 {
|
||||||
cmd = append(cmd, "-t")
|
cmd = append(cmd, "-t")
|
||||||
}
|
}
|
||||||
if cd.ssh_config != nil && cd.ssh_config.RemoteCommand != "" {
|
|
||||||
cmd = append(cmd, "-o", "RemoteCommand=none")
|
|
||||||
}
|
|
||||||
insertion_point := len(cmd)
|
insertion_point := len(cmd)
|
||||||
cmd = append(cmd, "--", hostname)
|
cmd = append(cmd, "--", hostname)
|
||||||
uname, hostname_for_match := get_destination(hostname)
|
uname, hostname_for_match := get_destination(hostname)
|
||||||
@@ -780,6 +778,12 @@ func run_ssh(ssh_args, server_args, found_extra_args []string, ssh_config *SSHCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
// Receive ssh config
|
||||||
|
ssh_config := <-ssh_config_channel
|
||||||
|
if ssh_config != nil && ssh_config.RemoteCommand != "" {
|
||||||
|
cmd = slices.Insert(cmd, insertion_point, "-o", "RemoteCommand=none")
|
||||||
|
}
|
||||||
|
cd.ssh_config = ssh_config
|
||||||
err = get_remote_command(&cd)
|
err = get_remote_command(&cd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 1, err
|
return 1, err
|
||||||
@@ -856,17 +860,18 @@ func main(cmd *cli.Command, o *Options, args []string) (rc int, err error) {
|
|||||||
if passthrough {
|
if passthrough {
|
||||||
return 1, unix.Exec(SSHExe(), utils.Concat([]string{"ssh"}, ssh_args, server_args), os.Environ())
|
return 1, unix.Exec(SSHExe(), utils.Concat([]string{"ssh"}, ssh_args, server_args), os.Environ())
|
||||||
}
|
}
|
||||||
ssh_config, err := LoadSSHConfig(server_args[0])
|
|
||||||
if err != nil {
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
return 1, err
|
defer cancel()
|
||||||
}
|
ssh_config_channel := ReadSSHConfig(ctx, server_args[0])
|
||||||
|
|
||||||
if os.Getenv("KITTY_WINDOW_ID") == "" || os.Getenv("KITTY_PID") == "" {
|
if os.Getenv("KITTY_WINDOW_ID") == "" || os.Getenv("KITTY_PID") == "" {
|
||||||
return 1, fmt.Errorf("The SSH kitten is meant to run inside a kitty window")
|
return 1, fmt.Errorf("The SSH kitten is meant to run inside a kitty window")
|
||||||
}
|
}
|
||||||
if !tty.IsTerminal(os.Stdin.Fd()) {
|
if !tty.IsTerminal(os.Stdin.Fd()) {
|
||||||
return 1, fmt.Errorf("The SSH kitten is meant for interactive use only, STDIN must be a terminal")
|
return 1, fmt.Errorf("The SSH kitten is meant for interactive use only, STDIN must be a terminal")
|
||||||
}
|
}
|
||||||
return run_ssh(ssh_args, server_args, found_extra_args, ssh_config)
|
return run_ssh(ssh_args, server_args, found_extra_args, ssh_config_channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
func EntryPoint(parent *cli.Command) {
|
func EntryPoint(parent *cli.Command) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package ssh
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"regexp"
|
"regexp"
|
||||||
@@ -199,34 +200,53 @@ type SSHConfig struct {
|
|||||||
RemoteCommand string
|
RemoteCommand string
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadSSHConfig(hostname string) (config *SSHConfig, err error) {
|
// ReadSSHConfig Asynchronously read ssh configuration
|
||||||
cmd_args := []string{SSHExe(), hostname, "-G"}
|
func ReadSSHConfig(ctx context.Context, hostname string) <-chan *SSHConfig {
|
||||||
cmd := exec.Command(cmd_args[0], cmd_args[1:]...)
|
ch := make(chan *SSHConfig, 1)
|
||||||
var stdout, stderr bytes.Buffer
|
|
||||||
cmd.Stdout = &stdout
|
|
||||||
cmd.Stderr = &stderr
|
|
||||||
_ = cmd.Run()
|
|
||||||
|
|
||||||
text := stdout.String()
|
go func() {
|
||||||
scanner := bufio.NewScanner(strings.NewReader(text))
|
defer close(ch)
|
||||||
|
|
||||||
config = &SSHConfig{}
|
cmd_args := []string{SSHExe(), hostname, "-G"}
|
||||||
for scanner.Scan() {
|
cmd := exec.CommandContext(ctx, cmd_args[0], cmd_args[1:]...)
|
||||||
line := scanner.Text()
|
var stdout, stderr bytes.Buffer
|
||||||
i := strings.IndexByte(line, ' ')
|
cmd.Stdout = &stdout
|
||||||
if i <= 0 {
|
cmd.Stderr = &stderr
|
||||||
continue
|
if err := cmd.Run(); err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
key, val := line[:i], line[i+1:]
|
text := stdout.String()
|
||||||
switch key {
|
scanner := bufio.NewScanner(strings.NewReader(text))
|
||||||
case "remotecommand":
|
|
||||||
if val != "none" {
|
config := &SSHConfig{}
|
||||||
config.RemoteCommand = val
|
for scanner.Scan() {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
line := scanner.Text()
|
||||||
|
i := strings.IndexByte(line, ' ')
|
||||||
|
if i <= 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
key, val := line[:i], line[i+1:]
|
||||||
|
switch key {
|
||||||
|
case "remotecommand":
|
||||||
|
if val != "none" {
|
||||||
|
config.RemoteCommand = val
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
select {
|
||||||
return config, nil
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case ch <- config:
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return ch
|
||||||
}
|
}
|
||||||
|
|
||||||
type SSHVersion struct{ Major, Minor int }
|
type SSHVersion struct{ Major, Minor int }
|
||||||
|
|||||||
Reference in New Issue
Block a user