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  }