Browse code

Fix for help when $HOME is /

estesp noticed that when $HOME is / the ~ substitutions messes up
becuase it tries to replace all paths that start with "/" with "~".
This fixes it so that it will only replace it when $HOME isn't "/".

Signed-off-by: Doug Davis <dug@us.ibm.com>

Doug Davis authored on 2015/02/07 07:17:34
Showing 3 changed files
... ...
@@ -1,7 +1,9 @@
1 1
 package main
2 2
 
3 3
 import (
4
+	"os"
4 5
 	"os/exec"
6
+	"runtime"
5 7
 	"strings"
6 8
 	"testing"
7 9
 	"unicode"
... ...
@@ -9,62 +11,44 @@ import (
9 9
 	"github.com/docker/docker/pkg/homedir"
10 10
 )
11 11
 
12
-func TestMainHelpWidth(t *testing.T) {
12
+func TestHelpWidth(t *testing.T) {
13 13
 	// Make sure main help text fits within 80 chars and that
14
-	// on non-windows system we use ~ when possible (to shorten things)
14
+	// on non-windows system we use ~ when possible (to shorten things).
15
+	// Test for HOME set to its default value and set to "/" on linux
16
+	// Yes on windows setting up an array and looping (right now) isn't
17
+	// necessary because we just have one value, but we'll need the
18
+	// array/loop on linux so we might as well set it up so that we can
19
+	// test any number of home dirs later on and all we need to do is
20
+	// modify the array - the rest of the testing infrastructure should work
21
+	homes := []string{homedir.Get()}
15 22
 
16
-	home := homedir.Get()
17
-	helpCmd := exec.Command(dockerBinary, "help")
18
-	out, ec, err := runCommandWithOutput(helpCmd)
19
-	if err != nil || ec != 0 {
20
-		t.Fatalf("docker help should have worked\nout:%s\nec:%d", out, ec)
23
+	// Non-Windows machines need to test for this special case of $HOME
24
+	if runtime.GOOS != "windows" {
25
+		homes = append(homes, "/")
21 26
 	}
22
-	lines := strings.Split(out, "\n")
23
-	for _, line := range lines {
24
-		if len(line) > 80 {
25
-			t.Fatalf("Line is too long(%d chars):\n%s", len(line), line)
26 27
 
27
-		}
28
-		if home != "" && strings.Contains(line, home) {
29
-			t.Fatalf("Line should use '%q' instead of %q:\n%s", homedir.GetShortcutString(), home, line)
30
-		}
31
-	}
32
-	logDone("help - verify main width")
33
-}
28
+	homeKey := homedir.Key()
29
+	baseEnvs := os.Environ()
34 30
 
35
-func TestCmdHelpWidth(t *testing.T) {
36
-	// Make sure main help text fits within 80 chars and that
37
-	// on non-windows system we use ~ when possible (to shorten things)
38
-
39
-	home := homedir.Get()
40
-	// Pull the list of commands from the "Commands:" section of docker help
41
-	helpCmd := exec.Command(dockerBinary, "help")
42
-	out, ec, err := runCommandWithOutput(helpCmd)
43
-	if err != nil || ec != 0 {
44
-		t.Fatalf("docker help should have worked\nout:%s\nec:%d", out, ec)
45
-	}
46
-	i := strings.Index(out, "Commands:")
47
-	if i < 0 {
48
-		t.Fatalf("Missing 'Commands:' in:\n%s", out)
49
-	}
50
-
51
-	// Grab all chars starting at "Commands:"
52
-	// Skip first line, its "Commands:"
53
-	count := 0
54
-	cmds := ""
55
-	for _, command := range strings.Split(out[i:], "\n")[1:] {
56
-		// Stop on blank line or non-idented line
57
-		if command == "" || !unicode.IsSpace(rune(command[0])) {
31
+	// Remove HOME env var from list so we can add a new value later.
32
+	for i, env := range baseEnvs {
33
+		if strings.HasPrefix(env, homeKey+"=") {
34
+			baseEnvs = append(baseEnvs[:i], baseEnvs[i+1:]...)
58 35
 			break
59 36
 		}
37
+	}
60 38
 
61
-		// Grab just the first word of each line
62
-		command = strings.Split(strings.TrimSpace(command), " ")[0]
39
+	for _, home := range homes {
40
+		// Dup baseEnvs and add our new HOME value
41
+		newEnvs := make([]string, len(baseEnvs)+1)
42
+		copy(newEnvs, baseEnvs)
43
+		newEnvs[len(newEnvs)-1] = homeKey + "=" + home
63 44
 
64
-		count++
65
-		cmds = cmds + "\n" + command
45
+		scanForHome := runtime.GOOS != "windows" && home != "/"
66 46
 
67
-		helpCmd := exec.Command(dockerBinary, command, "--help")
47
+		// Check main help text to make sure its not over 80 chars
48
+		helpCmd := exec.Command(dockerBinary, "help")
49
+		helpCmd.Env = newEnvs
68 50
 		out, ec, err := runCommandWithOutput(helpCmd)
69 51
 		if err != nil || ec != 0 {
70 52
 			t.Fatalf("docker help should have worked\nout:%s\nec:%d", out, ec)
... ...
@@ -72,19 +56,75 @@ func TestCmdHelpWidth(t *testing.T) {
72 72
 		lines := strings.Split(out, "\n")
73 73
 		for _, line := range lines {
74 74
 			if len(line) > 80 {
75
-				t.Fatalf("Help for %q is too long(%d chars):\n%s", command, len(line), line)
75
+				t.Fatalf("Line is too long(%d chars):\n%s", len(line), line)
76 76
 			}
77
-			if home != "" && strings.Contains(line, home) {
78
-				t.Fatalf("Help for %q should use home shortcut instead of %q on:\n%s", command, home, line)
77
+			if scanForHome && strings.Contains(line, `=`+home) {
78
+				t.Fatalf("Line should use '%q' instead of %q:\n%s", homedir.GetShortcutString(), home, line)
79
+			}
80
+			if runtime.GOOS != "windows" {
81
+				i := strings.Index(line, homedir.GetShortcutString())
82
+				if i >= 0 && i != len(line)-1 && line[i+1] != '/' {
83
+					t.Fatalf("Main help should not have used home shortcut:\n%s", line)
84
+				}
79 85
 			}
80 86
 		}
81
-	}
82 87
 
83
-	expected := 39
84
-	if count != expected {
85
-		t.Fatalf("Wrong # of commands (%d), it should be: %d\nThe list:\n%s",
86
-			len(cmds), expected, cmds)
88
+		// Make sure each cmd's help text fits within 80 chars and that
89
+		// on non-windows system we use ~ when possible (to shorten things).
90
+		// Pull the list of commands from the "Commands:" section of docker help
91
+		helpCmd = exec.Command(dockerBinary, "help")
92
+		helpCmd.Env = newEnvs
93
+		out, ec, err = runCommandWithOutput(helpCmd)
94
+		if err != nil || ec != 0 {
95
+			t.Fatalf("docker help should have worked\nout:%s\nec:%d", out, ec)
96
+		}
97
+		i := strings.Index(out, "Commands:")
98
+		if i < 0 {
99
+			t.Fatalf("Missing 'Commands:' in:\n%s", out)
100
+		}
101
+
102
+		// Grab all chars starting at "Commands:"
103
+		// Skip first line, its "Commands:"
104
+		cmds := []string{}
105
+		for _, cmd := range strings.Split(out[i:], "\n")[1:] {
106
+			// Stop on blank line or non-idented line
107
+			if cmd == "" || !unicode.IsSpace(rune(cmd[0])) {
108
+				break
109
+			}
110
+
111
+			// Grab just the first word of each line
112
+			cmd = strings.Split(strings.TrimSpace(cmd), " ")[0]
113
+			cmds = append(cmds, cmd)
114
+
115
+			helpCmd := exec.Command(dockerBinary, cmd, "--help")
116
+			helpCmd.Env = newEnvs
117
+			out, ec, err := runCommandWithOutput(helpCmd)
118
+			if err != nil || ec != 0 {
119
+				t.Fatalf("Error on %q help: %s\nexit code:%d", cmd, out, ec)
120
+			}
121
+			lines := strings.Split(out, "\n")
122
+			for _, line := range lines {
123
+				if len(line) > 80 {
124
+					t.Fatalf("Help for %q is too long(%d chars):\n%s", cmd,
125
+						len(line), line)
126
+				}
127
+				if scanForHome && strings.Contains(line, `"`+home) {
128
+					t.Fatalf("Help for %q should use ~ instead of %q on:\n%s",
129
+						cmd, home, line)
130
+				}
131
+				i := strings.Index(line, "~")
132
+				if i >= 0 && i != len(line)-1 && line[i+1] != '/' {
133
+					t.Fatalf("Help for %q should not have used ~:\n%s", cmd, line)
134
+				}
135
+			}
136
+		}
137
+
138
+		expected := 39
139
+		if len(cmds) != expected {
140
+			t.Fatalf("Wrong # of cmds(%d), it should be: %d\nThe list:\n%q",
141
+				len(cmds), expected, cmds)
142
+		}
87 143
 	}
88 144
 
89
-	logDone("help - cmd widths")
145
+	logDone("help - widths")
90 146
 }
... ...
@@ -5,14 +5,20 @@ import (
5 5
 	"runtime"
6 6
 )
7 7
 
8
+// Key returns the env var name for the user's home dir based on
9
+// the platform being run on
10
+func Key() string {
11
+	if runtime.GOOS == "windows" {
12
+		return "USERPROFILE"
13
+	}
14
+	return "HOME"
15
+}
16
+
8 17
 // Get returns the home directory of the current user with the help of
9 18
 // environment variables depending on the target operating system.
10 19
 // Returned path should be used with "path/filepath" to form new paths.
11 20
 func Get() string {
12
-	if runtime.GOOS == "windows" {
13
-		return os.Getenv("USERPROFILE")
14
-	}
15
-	return os.Getenv("HOME")
21
+	return os.Getenv(Key())
16 22
 }
17 23
 
18 24
 // GetShortcutString returns the string that is shortcut to user's home directory
... ...
@@ -86,6 +86,7 @@ import (
86 86
 	"fmt"
87 87
 	"io"
88 88
 	"os"
89
+	"runtime"
89 90
 	"sort"
90 91
 	"strconv"
91 92
 	"strings"
... ...
@@ -505,7 +506,16 @@ func Set(name, value string) error {
505 505
 // otherwise, the default values of all defined flags in the set.
506 506
 func (f *FlagSet) PrintDefaults() {
507 507
 	writer := tabwriter.NewWriter(f.Out(), 20, 1, 3, ' ', 0)
508
-	home := homedir.Get()
508
+	var home string
509
+	if runtime.GOOS != "windows" {
510
+		// Only do this on non-windows systems
511
+		home = homedir.Get()
512
+
513
+		// Don't substitute when HOME is /
514
+		if home == "/" {
515
+			home = ""
516
+		}
517
+	}
509 518
 	f.VisitAll(func(flag *Flag) {
510 519
 		format := "  -%s=%s"
511 520
 		names := []string{}