Skip to content

Commit 03c245c

Browse files
committed
Merge pull request docker-archive-public#1033 from ehazlett/env-shell-selection
shell selection for env
2 parents a3eb0d0 + 6fe4331 commit 03c245c

File tree

5 files changed

+246
-36
lines changed

5 files changed

+246
-36
lines changed

commands/commands.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package commands
22

33
import (
4+
"errors"
45
"fmt"
56
"os"
67
"path/filepath"
8+
"runtime"
79
"sort"
810
"strings"
911

@@ -33,6 +35,10 @@ import (
3335
"github.com/docker/machine/utils"
3436
)
3537

38+
var (
39+
ErrUnknownShell = errors.New("unknown shell")
40+
)
41+
3642
type machineConfig struct {
3743
machineName string
3844
machineDir string
@@ -253,6 +259,10 @@ var Commands = []cli.Command{
253259
Name: "swarm",
254260
Usage: "Display the Swarm config instead of the Docker daemon",
255261
},
262+
cli.StringFlag{
263+
Name: "shell",
264+
Usage: "Force environment to be configured for specified shell",
265+
},
256266
cli.BoolFlag{
257267
Name: "unset, u",
258268
Usage: "Unset variables instead of setting them",
@@ -669,3 +679,19 @@ func getCertPathInfo(c *cli.Context) libmachine.CertPathInfo {
669679
ClientKeyPath: clientKeyPath,
670680
}
671681
}
682+
683+
func detectShell() (string, error) {
684+
// attempt to get the SHELL env var
685+
shell := filepath.Base(os.Getenv("SHELL"))
686+
// none detected; check for windows env
687+
if runtime.GOOS == "windows" {
688+
log.Printf("On Windows, please specify either 'cmd' or 'powershell' with the --shell flag.\n\n")
689+
return "", ErrUnknownShell
690+
}
691+
692+
if shell == "" {
693+
return "", ErrUnknownShell
694+
}
695+
696+
return shell, nil
697+
}

commands/create.go

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package commands
22

33
import (
44
"fmt"
5-
"os"
65
"path/filepath"
76

87
log "github.com/Sirupsen/logrus"
@@ -96,21 +95,8 @@ func cmdCreate(c *cli.Context) {
9695
log.Fatalf("error setting active host: %v", err)
9796
}
9897

99-
info := ""
100-
userShell := filepath.Base(os.Getenv("SHELL"))
101-
102-
switch userShell {
103-
case "fish":
104-
info = fmt.Sprintf("%s env %s | source", c.App.Name, name)
105-
default:
106-
info = fmt.Sprintf(`eval "$(%s env %s)"`, c.App.Name, name)
107-
}
108-
109-
log.Infof("%q has been created and is now the active machine.", name)
110-
111-
if info != "" {
112-
log.Infof("To point your Docker client at it, run this in your shell: %s", info)
113-
}
98+
info := fmt.Sprintf("%s env %s", c.App.Name, name)
99+
log.Infof("To point your Docker client at it, run this in your shell: %s", info)
114100
}
115101

116102
// If the user has specified a driver, they should not see the flags for all

commands/env.go

Lines changed: 105 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,81 @@ import (
44
"fmt"
55
"net/url"
66
"os"
7-
"path/filepath"
87
"strings"
8+
"text/template"
99

1010
log "github.com/Sirupsen/logrus"
1111

1212
"github.com/codegangsta/cli"
1313
"github.com/docker/machine/utils"
1414
)
1515

16+
const (
17+
envTmpl = `{{ .Prefix }}DOCKER_TLS_VERIFY{{ .Delimiter }}{{ .DockerTLSVerify }}{{ .Suffix }}{{ .Prefix }}DOCKER_HOST{{ .Delimiter }}{{ .DockerHost }}{{ .Suffix }}{{ .Prefix }}DOCKER_CERT_PATH{{ .Delimiter }}{{ .DockerCertPath }}{{ .Suffix }}{{ .UsageHint }}`
18+
)
19+
20+
type ShellConfig struct {
21+
Prefix string
22+
Delimiter string
23+
Suffix string
24+
DockerCertPath string
25+
DockerHost string
26+
DockerTLSVerify string
27+
UsageHint string
28+
}
29+
1630
func cmdEnv(c *cli.Context) {
17-
userShell := filepath.Base(os.Getenv("SHELL"))
31+
userShell := c.String("shell")
32+
if userShell == "" {
33+
shell, err := detectShell()
34+
if err != nil {
35+
log.Fatal(err)
36+
}
37+
userShell = shell
38+
}
39+
40+
t := template.New("envConfig")
41+
42+
usageHint := generateUsageHint(c.App.Name, c.Args().First(), userShell)
43+
44+
shellCfg := ShellConfig{
45+
DockerCertPath: "",
46+
DockerHost: "",
47+
DockerTLSVerify: "",
48+
}
49+
50+
// unset vars
1851
if c.Bool("unset") {
1952
switch userShell {
2053
case "fish":
21-
fmt.Printf("set -e DOCKER_TLS_VERIFY;\nset -e DOCKER_CERT_PATH;\nset -e DOCKER_HOST;\n")
54+
shellCfg.Prefix = "set -e "
55+
shellCfg.Delimiter = ""
56+
shellCfg.Suffix = ";\n"
57+
case "powershell":
58+
shellCfg.Prefix = "Remove-Item Env:\\\\"
59+
shellCfg.Delimiter = ""
60+
shellCfg.Suffix = "\n"
61+
case "cmd":
62+
// since there is no way to unset vars in cmd just reset to empty
63+
shellCfg.DockerCertPath = ""
64+
shellCfg.DockerHost = ""
65+
shellCfg.DockerTLSVerify = ""
66+
shellCfg.Prefix = "set "
67+
shellCfg.Delimiter = "="
68+
shellCfg.Suffix = "\n"
2269
default:
23-
fmt.Println("unset DOCKER_TLS_VERIFY DOCKER_CERT_PATH DOCKER_HOST")
70+
shellCfg.Prefix = "unset "
71+
shellCfg.Delimiter = " "
72+
shellCfg.Suffix = "\n"
73+
}
74+
75+
tmpl, err := t.Parse(envTmpl)
76+
if err != nil {
77+
log.Fatal(err)
78+
}
79+
80+
if err := tmpl.Execute(os.Stdout, shellCfg); err != nil {
81+
log.Fatal(err)
2482
}
2583
return
2684
}
@@ -31,7 +89,7 @@ func cmdEnv(c *cli.Context) {
3189
}
3290

3391
if cfg.machineUrl == "" {
34-
log.Fatalf("%s is not running. Please start this with docker-machine start %s", cfg.machineName, cfg.machineName)
92+
log.Fatalf("%s is not running. Please start this with %s start %s", cfg.machineName, c.App.Name, cfg.machineName)
3593
}
3694

3795
dockerHost := cfg.machineUrl
@@ -83,32 +141,64 @@ func cmdEnv(c *cli.Context) {
83141
}
84142
}
85143

86-
usageHint := generateUsageHint(c.Args().First(), userShell)
144+
shellCfg = ShellConfig{
145+
DockerCertPath: cfg.machineDir,
146+
DockerHost: dockerHost,
147+
DockerTLSVerify: "1",
148+
UsageHint: usageHint,
149+
}
87150

88151
switch userShell {
89152
case "fish":
90-
fmt.Printf("set -x DOCKER_TLS_VERIFY 1;\nset -x DOCKER_CERT_PATH %q;\nset -x DOCKER_HOST %s;\n\n%s\n",
91-
cfg.machineDir, dockerHost, usageHint)
153+
shellCfg.Prefix = "set -x "
154+
shellCfg.Suffix = "\";\n"
155+
shellCfg.Delimiter = " \""
156+
case "powershell":
157+
shellCfg.Prefix = "$Env:"
158+
shellCfg.Suffix = "\"\n"
159+
shellCfg.Delimiter = " = \""
160+
case "cmd":
161+
shellCfg.Prefix = "set "
162+
shellCfg.Suffix = "\n"
163+
shellCfg.Delimiter = "="
92164
default:
93-
fmt.Printf("export DOCKER_TLS_VERIFY=1\nexport DOCKER_CERT_PATH=%q\nexport DOCKER_HOST=%s\n\n%s\n",
94-
cfg.machineDir, dockerHost, usageHint)
165+
shellCfg.Prefix = "export "
166+
shellCfg.Suffix = "\"\n"
167+
shellCfg.Delimiter = "=\""
168+
}
169+
170+
tmpl, err := t.Parse(envTmpl)
171+
if err != nil {
172+
log.Fatal(err)
173+
}
174+
175+
if err := tmpl.Execute(os.Stdout, shellCfg); err != nil {
176+
log.Fatal(err)
95177
}
96178
}
97179

98-
func generateUsageHint(machineName string, userShell string) string {
180+
func generateUsageHint(appName, machineName, userShell string) string {
99181
cmd := ""
100182
switch userShell {
101183
case "fish":
102184
if machineName != "" {
103-
cmd = fmt.Sprintf("eval (docker-machine env %s)", machineName)
185+
cmd = fmt.Sprintf("eval (%s env %s)", appName, machineName)
186+
} else {
187+
cmd = fmt.Sprintf("eval (%s env)", appName)
188+
}
189+
case "powershell":
190+
if machineName != "" {
191+
cmd = fmt.Sprintf("%s env --shell=powershell %s | Invoke-Expression", appName, machineName)
104192
} else {
105-
cmd = "eval (docker-machine env)"
193+
cmd = fmt.Sprintf("%s env --shell=powershell | Invoke-Expression", appName)
106194
}
195+
case "cmd":
196+
cmd = "copy and paste the above values into your command prompt"
107197
default:
108198
if machineName != "" {
109-
cmd = fmt.Sprintf("eval \"$(docker-machine env %s)\"", machineName)
199+
cmd = fmt.Sprintf("eval \"$(%s env %s)\"", appName, machineName)
110200
} else {
111-
cmd = "eval \"$(docker-machine env)\""
201+
cmd = fmt.Sprintf("eval \"$(%s env)\"", appName)
112202
}
113203
}
114204

0 commit comments

Comments
 (0)