github.com/scaleway/scaleway-cli@v1.11.1/pkg/sshcommand/sshcommand.go (about) 1 package sshcommand 2 3 import ( 4 "fmt" 5 "runtime" 6 "strings" 7 ) 8 9 // Command contains settings to build a ssh command 10 type Command struct { 11 Host string 12 User string 13 Port int 14 SSHOptions []string 15 Gateway *Command 16 Command []string 17 Debug bool 18 NoEscapeCommand bool 19 SkipHostKeyChecking bool 20 Quiet bool 21 AllocateTTY bool 22 23 isGateway bool 24 } 25 26 // New returns a minimal Command 27 func New(host string) *Command { 28 return &Command{ 29 Host: host, 30 } 31 } 32 33 func (c *Command) applyDefaults() { 34 if strings.Contains(c.Host, "@") { 35 parts := strings.Split(c.Host, "@") 36 c.User = parts[0] 37 c.Host = parts[1] 38 } 39 40 if c.Port == 0 { 41 c.Port = 22 42 } 43 44 if c.isGateway { 45 c.SSHOptions = []string{"-W", "%h:%p"} 46 } 47 } 48 49 // Slice returns an execve compatible slice of arguments 50 func (c *Command) Slice() []string { 51 c.applyDefaults() 52 53 slice := []string{} 54 55 slice = append(slice, "ssh") 56 57 if c.Quiet { 58 slice = append(slice, "-q") 59 } 60 61 if c.SkipHostKeyChecking { 62 slice = append(slice, "-o", "UserKnownHostsFile=/dev/null", "-o", "StrictHostKeyChecking=no") 63 } 64 65 if len(c.SSHOptions) > 0 { 66 slice = append(slice, c.SSHOptions...) 67 } 68 69 if c.Gateway != nil { 70 c.Gateway.isGateway = true 71 slice = append(slice, "-o", "ProxyCommand="+c.Gateway.String()) 72 } 73 74 if c.User != "" { 75 slice = append(slice, "-l", c.User) 76 } 77 78 slice = append(slice, c.Host) 79 80 if c.AllocateTTY { 81 slice = append(slice, "-t", "-t") 82 } 83 84 slice = append(slice, "-p", fmt.Sprintf("%d", c.Port)) 85 if len(c.Command) > 0 { 86 slice = append(slice, "--", "/bin/sh", "-e") 87 if c.Debug { 88 slice = append(slice, "-x") 89 } 90 slice = append(slice, "-c") 91 92 var escapedCommand []string 93 if c.NoEscapeCommand { 94 escapedCommand = c.Command 95 } else { 96 escapedCommand = []string{} 97 for _, part := range c.Command { 98 escapedCommand = append(escapedCommand, fmt.Sprintf("%q", part)) 99 } 100 } 101 slice = append(slice, fmt.Sprintf("%q", strings.Join(escapedCommand, " "))) 102 } 103 if runtime.GOOS == "windows" { 104 slice[len(slice)-1] = slice[len(slice)-1] + " " // Why ? 105 } 106 return slice 107 } 108 109 // String returns a copy-pasteable command, useful for debugging 110 func (c *Command) String() string { 111 slice := c.Slice() 112 for i := range slice { 113 quoted := fmt.Sprintf("%q", slice[i]) 114 if strings.Contains(slice[i], " ") || len(quoted) != len(slice[i])+2 { 115 slice[i] = quoted 116 } 117 } 118 return strings.Join(slice, " ") 119 }