docs/commands/env.go

189 lines
4.5 KiB
Go

package commands
import (
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"text/template"
"github.com/docker/machine/cli"
"github.com/docker/machine/commands/mcndirs"
"github.com/docker/machine/libmachine/log"
)
const (
envTmpl = `{{ .Prefix }}DOCKER_TLS_VERIFY{{ .Delimiter }}{{ .DockerTLSVerify }}{{ .Suffix }}{{ .Prefix }}DOCKER_HOST{{ .Delimiter }}{{ .DockerHost }}{{ .Suffix }}{{ .Prefix }}DOCKER_CERT_PATH{{ .Delimiter }}{{ .DockerCertPath }}{{ .Suffix }}{{ .Prefix }}DOCKER_MACHINE_NAME{{ .Delimiter }}{{ .MachineName }}{{ .Suffix }}{{ if .NoProxyVar }}{{ .Prefix }}{{ .NoProxyVar }}{{ .Delimiter }}{{ .NoProxyValue }}{{ .Suffix }}{{end}}{{ .UsageHint }}`
)
var (
improperEnvArgsError = errors.New("Error: Expected either one machine name, or -u flag to unset the variables in the arguments.")
)
type ShellConfig struct {
Prefix string
Delimiter string
Suffix string
DockerCertPath string
DockerHost string
DockerTLSVerify string
UsageHint string
MachineName string
NoProxyVar string
NoProxyValue string
}
func cmdEnv(c *cli.Context) {
// Ensure that log messages always go to stderr when this command is
// being run (it is intended to be run in a subshell)
log.SetOutWriter(os.Stderr)
if len(c.Args()) != 1 && !c.Bool("unset") {
fatal(improperEnvArgsError)
}
h := getFirstArgHost(c)
dockerHost, _, err := runConnectionBoilerplate(h, c)
if err != nil {
fatalf("Error running connection boilerplate: %s", err)
}
userShell := c.String("shell")
if userShell == "" {
shell, err := detectShell()
if err != nil {
fatal(err)
}
userShell = shell
}
t := template.New("envConfig")
usageHint := generateUsageHint(userShell, os.Args)
shellCfg := &ShellConfig{
DockerCertPath: filepath.Join(mcndirs.GetMachineDir(), h.Name),
DockerHost: dockerHost,
DockerTLSVerify: "1",
UsageHint: usageHint,
MachineName: h.Name,
}
if c.Bool("no-proxy") {
ip, err := h.Driver.GetIP()
if err != nil {
fatalf("Error getting host IP: %s", err)
}
// first check for an existing lower case no_proxy var
noProxyVar := "no_proxy"
noProxyValue := os.Getenv("no_proxy")
// otherwise default to allcaps HTTP_PROXY
if noProxyValue == "" {
noProxyVar = "NO_PROXY"
noProxyValue = os.Getenv("NO_PROXY")
}
// add the docker host to the no_proxy list idempotently
switch {
case noProxyValue == "":
noProxyValue = ip
case strings.Contains(noProxyValue, ip):
//ip already in no_proxy list, nothing to do
default:
noProxyValue = fmt.Sprintf("%s,%s", noProxyValue, ip)
}
shellCfg.NoProxyVar = noProxyVar
shellCfg.NoProxyValue = noProxyValue
}
// unset vars
if c.Bool("unset") {
switch userShell {
case "fish":
shellCfg.Prefix = "set -e "
shellCfg.Delimiter = ""
shellCfg.Suffix = ";\n"
case "powershell":
shellCfg.Prefix = "Remove-Item Env:\\\\"
shellCfg.Delimiter = ""
shellCfg.Suffix = "\n"
case "cmd":
// since there is no way to unset vars in cmd just reset to empty
shellCfg.DockerCertPath = ""
shellCfg.DockerHost = ""
shellCfg.DockerTLSVerify = ""
shellCfg.Prefix = "set "
shellCfg.Delimiter = "="
shellCfg.Suffix = "\n"
default:
shellCfg.Prefix = "unset "
shellCfg.Delimiter = " "
shellCfg.Suffix = "\n"
}
tmpl, err := t.Parse(envTmpl)
if err != nil {
fatal(err)
}
if err := tmpl.Execute(os.Stdout, shellCfg); err != nil {
fatal(err)
}
return
}
switch userShell {
case "fish":
shellCfg.Prefix = "set -x "
shellCfg.Suffix = "\";\n"
shellCfg.Delimiter = " \""
case "powershell":
shellCfg.Prefix = "$Env:"
shellCfg.Suffix = "\"\n"
shellCfg.Delimiter = " = \""
case "cmd":
shellCfg.Prefix = "SET "
shellCfg.Suffix = "\n"
shellCfg.Delimiter = "="
default:
shellCfg.Prefix = "export "
shellCfg.Suffix = "\"\n"
shellCfg.Delimiter = "=\""
}
tmpl, err := t.Parse(envTmpl)
if err != nil {
fatal(err)
}
if err := tmpl.Execute(os.Stdout, shellCfg); err != nil {
fatal(err)
}
}
func generateUsageHint(userShell string, args []string) string {
cmd := ""
comment := "#"
commandLine := strings.Join(args, " ")
switch userShell {
case "fish":
cmd = fmt.Sprintf("eval (%s)", commandLine)
case "powershell":
cmd = fmt.Sprintf("%s | Invoke-Expression", commandLine)
case "cmd":
cmd = fmt.Sprintf("\tFOR /f \"tokens=*\" %%i IN ('%s') DO %%i", commandLine)
comment = "REM"
default:
cmd = fmt.Sprintf("eval \"$(%s)\"", commandLine)
}
return fmt.Sprintf("%s Run this command to configure your shell: \n%s %s\n", comment, comment, cmd)
}