github.com/panekj/cli@v0.0.0-20230304125325-467dd2f3797e/cli/connhelper/ssh/ssh.go (about) 1 // Package ssh provides the connection helper for ssh:// URL. 2 package ssh 3 4 import ( 5 "fmt" 6 "net/url" 7 8 "github.com/pkg/errors" 9 ) 10 11 // ParseURL parses URL 12 func ParseURL(daemonURL string) (*Spec, error) { 13 u, err := url.Parse(daemonURL) 14 if err != nil { 15 return nil, err 16 } 17 if u.Scheme != "ssh" { 18 return nil, errors.Errorf("expected scheme ssh, got %q", u.Scheme) 19 } 20 21 var sp Spec 22 23 if u.User != nil { 24 sp.User = u.User.Username() 25 if _, ok := u.User.Password(); ok { 26 return nil, errors.New("plain-text password is not supported") 27 } 28 } 29 sp.Host = u.Hostname() 30 if sp.Host == "" { 31 return nil, errors.Errorf("no host specified") 32 } 33 sp.Port = u.Port() 34 sp.Path = u.Path 35 if u.RawQuery != "" { 36 return nil, errors.Errorf("extra query after the host: %q", u.RawQuery) 37 } 38 if u.Fragment != "" { 39 return nil, errors.Errorf("extra fragment after the host: %q", u.Fragment) 40 } 41 return &sp, err 42 } 43 44 // Spec of SSH URL 45 type Spec struct { 46 User string 47 Host string 48 Port string 49 Path string 50 } 51 52 // Args returns args except "ssh" itself combined with optional additional command args 53 func (sp *Spec) Args(add ...string) []string { 54 var args []string 55 if sp.User != "" { 56 args = append(args, "-l", sp.User) 57 } 58 if sp.Port != "" { 59 args = append(args, "-p", sp.Port) 60 } 61 args = append(args, "--", sp.Host) 62 if len(add) > 0 { 63 args = append(args, add[0]) 64 if sp.Path != "" { 65 args = append(args, "--host", fmt.Sprintf("unix://%s", sp.Path)) 66 } 67 if len(add) > 1 { 68 args = append(args, add[1:]...) 69 } 70 } 71 return args 72 }