Browse code

Update unit tests for new cobra root command.

Cleanup cobra integration
Update windows files for cobra and pflags
Cleanup SetupRootcmd, and remove unnecessary SetFlagErrorFunc.
Use cobra command traversal

Signed-off-by: Daniel Nephin <dnephin@docker.com>

Daniel Nephin authored on 2016/06/23 07:36:51
Showing 28 changed files
... ...
@@ -6,6 +6,7 @@ import (
6 6
 	"io"
7 7
 	"net/http"
8 8
 	"os"
9
+	"path/filepath"
9 10
 	"runtime"
10 11
 
11 12
 	"github.com/docker/docker/api"
... ...
@@ -164,22 +165,23 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions) error {
164 164
 	if cli.out != nil {
165 165
 		cli.outFd, cli.isTerminalOut = term.GetFdInfo(cli.out)
166 166
 	}
167
+
168
+	if opts.Common.TrustKey == "" {
169
+		cli.keyFile = filepath.Join(cliconfig.ConfigDir(), cliflags.DefaultTrustKeyFile)
170
+	} else {
171
+		cli.keyFile = opts.Common.TrustKey
172
+	}
173
+
167 174
 	return nil
168 175
 }
169 176
 
170 177
 // NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err.
171
-// The key file, protocol (i.e. unix) and address are passed in as strings, along with the tls.Config. If the tls.Config
172
-// is set the client scheme will be set to https.
173
-// The client will be given a 32-second timeout (see https://github.com/docker/docker/pull/8035).
174
-func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientOpts *cliflags.ClientOptions) *DockerCli {
175
-	cli := &DockerCli{
178
+func NewDockerCli(in io.ReadCloser, out, err io.Writer) *DockerCli {
179
+	return &DockerCli{
176 180
 		in:  in,
177 181
 		out: out,
178 182
 		err: err,
179
-		// TODO: just pass trustKey, not the entire opts struct
180
-		keyFile: clientOpts.Common.TrustKey,
181 183
 	}
182
-	return cli
183 184
 }
184 185
 
185 186
 // LoadDefaultConfigFile attempts to load the default config file and returns
... ...
@@ -36,7 +36,6 @@ func NewAttachCommand(dockerCli *client.DockerCli) *cobra.Command {
36 36
 			return runAttach(dockerCli, &opts)
37 37
 		},
38 38
 	}
39
-	cmd.SetFlagErrorFunc(flagErrorFunc)
40 39
 
41 40
 	flags := cmd.Flags()
42 41
 	flags.BoolVar(&opts.noStdin, "no-stdin", false, "Do not attach STDIN")
... ...
@@ -38,7 +38,6 @@ func NewCommitCommand(dockerCli *client.DockerCli) *cobra.Command {
38 38
 			return runCommit(dockerCli, &opts)
39 39
 		},
40 40
 	}
41
-	cmd.SetFlagErrorFunc(flagErrorFunc)
42 41
 
43 42
 	flags := cmd.Flags()
44 43
 	flags.SetInterspersed(false)
... ...
@@ -43,7 +43,6 @@ func NewCreateCommand(dockerCli *client.DockerCli) *cobra.Command {
43 43
 			return runCreate(dockerCli, cmd.Flags(), &opts, copts)
44 44
 		},
45 45
 	}
46
-	cmd.SetFlagErrorFunc(flagErrorFunc)
47 46
 
48 47
 	flags := cmd.Flags()
49 48
 	flags.SetInterspersed(false)
... ...
@@ -19,7 +19,7 @@ type diffOptions struct {
19 19
 func NewDiffCommand(dockerCli *client.DockerCli) *cobra.Command {
20 20
 	var opts diffOptions
21 21
 
22
-	cmd := &cobra.Command{
22
+	return &cobra.Command{
23 23
 		Use:   "diff CONTAINER",
24 24
 		Short: "Inspect changes on a container's filesystem",
25 25
 		Args:  cli.ExactArgs(1),
... ...
@@ -28,9 +28,6 @@ func NewDiffCommand(dockerCli *client.DockerCli) *cobra.Command {
28 28
 			return runDiff(dockerCli, &opts)
29 29
 		},
30 30
 	}
31
-	cmd.SetFlagErrorFunc(flagErrorFunc)
32
-
33
-	return cmd
34 31
 }
35 32
 
36 33
 func runDiff(dockerCli *client.DockerCli, opts *diffOptions) error {
... ...
@@ -41,7 +41,6 @@ func NewLogsCommand(dockerCli *client.DockerCli) *cobra.Command {
41 41
 			return runLogs(dockerCli, &opts)
42 42
 		},
43 43
 	}
44
-	cmd.SetFlagErrorFunc(flagErrorFunc)
45 44
 
46 45
 	flags := cmd.Flags()
47 46
 	flags.BoolVarP(&opts.follow, "follow", "f", false, "Follow log output")
... ...
@@ -19,7 +19,7 @@ type pauseOptions struct {
19 19
 func NewPauseCommand(dockerCli *client.DockerCli) *cobra.Command {
20 20
 	var opts pauseOptions
21 21
 
22
-	cmd := &cobra.Command{
22
+	return &cobra.Command{
23 23
 		Use:   "pause CONTAINER [CONTAINER...]",
24 24
 		Short: "Pause all processes within one or more containers",
25 25
 		Args:  cli.RequiresMinArgs(1),
... ...
@@ -28,9 +28,6 @@ func NewPauseCommand(dockerCli *client.DockerCli) *cobra.Command {
28 28
 			return runPause(dockerCli, &opts)
29 29
 		},
30 30
 	}
31
-	cmd.SetFlagErrorFunc(flagErrorFunc)
32
-
33
-	return cmd
34 31
 }
35 32
 
36 33
 func runPause(dockerCli *client.DockerCli, opts *pauseOptions) error {
... ...
@@ -34,8 +34,6 @@ func NewPortCommand(dockerCli *client.DockerCli) *cobra.Command {
34 34
 			return runPort(dockerCli, &opts)
35 35
 		},
36 36
 	}
37
-	cmd.SetFlagErrorFunc(flagErrorFunc)
38
-
39 37
 	return cmd
40 38
 }
41 39
 
... ...
@@ -30,8 +30,6 @@ func NewRenameCommand(dockerCli *client.DockerCli) *cobra.Command {
30 30
 			return runRename(dockerCli, &opts)
31 31
 		},
32 32
 	}
33
-	cmd.SetFlagErrorFunc(flagErrorFunc)
34
-
35 33
 	return cmd
36 34
 }
37 35
 
... ...
@@ -14,6 +14,7 @@ import (
14 14
 	"github.com/Sirupsen/logrus"
15 15
 	"github.com/docker/docker/api/client"
16 16
 	"github.com/docker/docker/cli"
17
+	"github.com/docker/docker/cli/cobraadaptor"
17 18
 	opttypes "github.com/docker/docker/opts"
18 19
 	"github.com/docker/docker/pkg/promise"
19 20
 	"github.com/docker/docker/pkg/signal"
... ...
@@ -48,7 +49,6 @@ func NewRunCommand(dockerCli *client.DockerCli) *cobra.Command {
48 48
 			return runRun(dockerCli, cmd.Flags(), &opts, copts)
49 49
 		},
50 50
 	}
51
-	cmd.SetFlagErrorFunc(flagErrorFunc)
52 51
 
53 52
 	flags := cmd.Flags()
54 53
 	flags.SetInterspersed(false)
... ...
@@ -70,7 +70,7 @@ func NewRunCommand(dockerCli *client.DockerCli) *cobra.Command {
70 70
 
71 71
 func flagErrorFunc(cmd *cobra.Command, err error) error {
72 72
 	return cli.StatusError{
73
-		Status:     cli.FlagErrorFunc(cmd, err).Error(),
73
+		Status:     cobraadaptor.FlagErrorFunc(cmd, err).Error(),
74 74
 		StatusCode: 125,
75 75
 	}
76 76
 }
... ...
@@ -37,7 +37,6 @@ func NewStartCommand(dockerCli *client.DockerCli) *cobra.Command {
37 37
 			return runStart(dockerCli, &opts)
38 38
 		},
39 39
 	}
40
-	cmd.SetFlagErrorFunc(flagErrorFunc)
41 40
 
42 41
 	flags := cmd.Flags()
43 42
 	flags.BoolVarP(&opts.attach, "attach", "a", false, "Attach STDOUT/STDERR and forward signals")
... ...
@@ -31,7 +31,6 @@ func NewStopCommand(dockerCli *client.DockerCli) *cobra.Command {
31 31
 			return runStop(dockerCli, &opts)
32 32
 		},
33 33
 	}
34
-	cmd.SetFlagErrorFunc(flagErrorFunc)
35 34
 
36 35
 	flags := cmd.Flags()
37 36
 	flags.IntVarP(&opts.time, "time", "t", 10, "Seconds to wait for stop before killing it")
... ...
@@ -32,7 +32,6 @@ func NewTopCommand(dockerCli *client.DockerCli) *cobra.Command {
32 32
 			return runTop(dockerCli, &opts)
33 33
 		},
34 34
 	}
35
-	cmd.SetFlagErrorFunc(flagErrorFunc)
36 35
 
37 36
 	flags := cmd.Flags()
38 37
 	flags.SetInterspersed(false)
... ...
@@ -28,8 +28,6 @@ func NewUnpauseCommand(dockerCli *client.DockerCli) *cobra.Command {
28 28
 			return runUnpause(dockerCli, &opts)
29 29
 		},
30 30
 	}
31
-	cmd.SetFlagErrorFunc(flagErrorFunc)
32
-
33 31
 	return cmd
34 32
 }
35 33
 
... ...
@@ -28,8 +28,6 @@ func NewWaitCommand(dockerCli *client.DockerCli) *cobra.Command {
28 28
 			return runWait(dockerCli, &opts)
29 29
 		},
30 30
 	}
31
-	cmd.SetFlagErrorFunc(flagErrorFunc)
32
-
33 31
 	return cmd
34 32
 }
35 33
 
... ...
@@ -1,81 +1,17 @@
1 1
 package cobraadaptor
2 2
 
3 3
 import (
4
-	"github.com/docker/docker/api/client"
5
-	"github.com/docker/docker/api/client/container"
6
-	"github.com/docker/docker/api/client/image"
7
-	"github.com/docker/docker/api/client/network"
8
-	"github.com/docker/docker/api/client/node"
9
-	"github.com/docker/docker/api/client/plugin"
10
-	"github.com/docker/docker/api/client/registry"
11
-	"github.com/docker/docker/api/client/service"
12
-	"github.com/docker/docker/api/client/stack"
13
-	"github.com/docker/docker/api/client/swarm"
14
-	"github.com/docker/docker/api/client/system"
15
-	"github.com/docker/docker/api/client/volume"
16
-	"github.com/docker/docker/cli"
4
+	"fmt"
5
+
17 6
 	"github.com/spf13/cobra"
18 7
 )
19 8
 
20 9
 // SetupRootCommand sets default usage, help, and error handling for the
21 10
 // root command.
22
-// TODO: move to cmd/docker/docker?
23
-// TODO: split into common setup and client setup
24
-func SetupRootCommand(rootCmd *cobra.Command, dockerCli *client.DockerCli) {
11
+func SetupRootCommand(rootCmd *cobra.Command) {
25 12
 	rootCmd.SetUsageTemplate(usageTemplate)
26 13
 	rootCmd.SetHelpTemplate(helpTemplate)
27
-	rootCmd.SetFlagErrorFunc(cli.FlagErrorFunc)
28
-	rootCmd.SetOutput(dockerCli.Out())
29
-	rootCmd.AddCommand(
30
-		node.NewNodeCommand(dockerCli),
31
-		service.NewServiceCommand(dockerCli),
32
-		stack.NewStackCommand(dockerCli),
33
-		stack.NewTopLevelDeployCommand(dockerCli),
34
-		swarm.NewSwarmCommand(dockerCli),
35
-		container.NewAttachCommand(dockerCli),
36
-		container.NewCommitCommand(dockerCli),
37
-		container.NewCopyCommand(dockerCli),
38
-		container.NewCreateCommand(dockerCli),
39
-		container.NewDiffCommand(dockerCli),
40
-		container.NewExecCommand(dockerCli),
41
-		container.NewExportCommand(dockerCli),
42
-		container.NewKillCommand(dockerCli),
43
-		container.NewLogsCommand(dockerCli),
44
-		container.NewPauseCommand(dockerCli),
45
-		container.NewPortCommand(dockerCli),
46
-		container.NewPsCommand(dockerCli),
47
-		container.NewRenameCommand(dockerCli),
48
-		container.NewRestartCommand(dockerCli),
49
-		container.NewRmCommand(dockerCli),
50
-		container.NewRunCommand(dockerCli),
51
-		container.NewStartCommand(dockerCli),
52
-		container.NewStatsCommand(dockerCli),
53
-		container.NewStopCommand(dockerCli),
54
-		container.NewTopCommand(dockerCli),
55
-		container.NewUnpauseCommand(dockerCli),
56
-		container.NewUpdateCommand(dockerCli),
57
-		container.NewWaitCommand(dockerCli),
58
-		image.NewBuildCommand(dockerCli),
59
-		image.NewHistoryCommand(dockerCli),
60
-		image.NewImagesCommand(dockerCli),
61
-		image.NewLoadCommand(dockerCli),
62
-		image.NewRemoveCommand(dockerCli),
63
-		image.NewSaveCommand(dockerCli),
64
-		image.NewPullCommand(dockerCli),
65
-		image.NewPushCommand(dockerCli),
66
-		image.NewSearchCommand(dockerCli),
67
-		image.NewImportCommand(dockerCli),
68
-		image.NewTagCommand(dockerCli),
69
-		network.NewNetworkCommand(dockerCli),
70
-		system.NewEventsCommand(dockerCli),
71
-		system.NewInspectCommand(dockerCli),
72
-		registry.NewLoginCommand(dockerCli),
73
-		registry.NewLogoutCommand(dockerCli),
74
-		system.NewVersionCommand(dockerCli),
75
-		volume.NewVolumeCommand(dockerCli),
76
-		system.NewInfoCommand(dockerCli),
77
-	)
78
-	plugin.NewPluginCommand(rootCmd, dockerCli)
14
+	rootCmd.SetFlagErrorFunc(FlagErrorFunc)
79 15
 
80 16
 	rootCmd.PersistentFlags().BoolP("help", "h", false, "Print usage")
81 17
 	rootCmd.PersistentFlags().MarkShorthandDeprecated("help", "please use --help")
... ...
@@ -87,6 +23,20 @@ func (c CobraAdaptor) GetRootCommand() *cobra.Command {
87 87
 	return c.rootCmd
88 88
 }
89 89
 
90
+// FlagErrorFunc prints an error messages which matches the format of the
91
+// docker/docker/cli error messages
92
+func FlagErrorFunc(cmd *cobra.Command, err error) error {
93
+	if err == nil {
94
+		return err
95
+	}
96
+
97
+	usage := ""
98
+	if cmd.HasSubCommands() {
99
+		usage = "\n\n" + cmd.UsageString()
100
+	}
101
+	return fmt.Errorf("%s\nSee '%s --help'.%s", err, cmd.CommandPath(), usage)
102
+}
103
+
90 104
 var usageTemplate = `Usage:	{{if not .HasSubCommands}}{{.UseLine}}{{end}}{{if .HasSubCommands}}{{ .CommandPath}} COMMAND{{end}}
91 105
 
92 106
 {{ .Short | trim }}{{if gt .Aliases 0}}
93 107
deleted file mode 100644
... ...
@@ -1,21 +0,0 @@
1
-package cli
2
-
3
-import (
4
-	"fmt"
5
-
6
-	"github.com/spf13/cobra"
7
-)
8
-
9
-// FlagErrorFunc prints an error messages which matches the format of the
10
-// docker/docker/cli error messages
11
-func FlagErrorFunc(cmd *cobra.Command, err error) error {
12
-	if err == nil {
13
-		return err
14
-	}
15
-
16
-	usage := ""
17
-	if cmd.HasSubCommands() {
18
-		usage = "\n\n" + cmd.UsageString()
19
-	}
20
-	return fmt.Errorf("%s\nSee '%s --help'.%s", err, cmd.CommandPath(), usage)
21
-}
... ...
@@ -43,9 +43,7 @@ type CommonOptions struct {
43 43
 
44 44
 // NewCommonOptions returns a new CommonOptions
45 45
 func NewCommonOptions() *CommonOptions {
46
-	return &CommonOptions{
47
-		TLSOptions: &tlsconfig.Options{},
48
-	}
46
+	return &CommonOptions{}
49 47
 }
50 48
 
51 49
 // InstallFlags adds flags for the common options on the FlagSet
... ...
@@ -61,13 +59,14 @@ func (commonOpts *CommonOptions) InstallFlags(flags *pflag.FlagSet) {
61 61
 
62 62
 	// TODO use flag flags.String("identity"}, "i", "", "Path to libtrust key file")
63 63
 
64
+	commonOpts.TLSOptions = &tlsconfig.Options{}
64 65
 	tlsOptions := commonOpts.TLSOptions
65 66
 	flags.StringVar(&tlsOptions.CAFile, "tlscacert", filepath.Join(dockerCertPath, DefaultCaFile), "Trust certs signed only by this CA")
66 67
 	flags.StringVar(&tlsOptions.CertFile, "tlscert", filepath.Join(dockerCertPath, DefaultCertFile), "Path to TLS certificate file")
67 68
 	flags.StringVar(&tlsOptions.KeyFile, "tlskey", filepath.Join(dockerCertPath, DefaultKeyFile), "Path to TLS key file")
68 69
 
69 70
 	hostOpt := opts.NewNamedListOptsRef("hosts", &commonOpts.Hosts, opts.ValidateHost)
70
-	flags.VarP(hostOpt, "-host", "H", "Daemon socket(s) to connect to")
71
+	flags.VarP(hostOpt, "host", "H", "Daemon socket(s) to connect to")
71 72
 }
72 73
 
73 74
 // SetDefaultOptions sets default values for options after flag parsing is
... ...
@@ -3,10 +3,20 @@ package main
3 3
 import (
4 4
 	"fmt"
5 5
 	"os"
6
-	"path/filepath"
7 6
 
8 7
 	"github.com/Sirupsen/logrus"
9 8
 	"github.com/docker/docker/api/client"
9
+	"github.com/docker/docker/api/client/container"
10
+	"github.com/docker/docker/api/client/image"
11
+	"github.com/docker/docker/api/client/network"
12
+	"github.com/docker/docker/api/client/node"
13
+	"github.com/docker/docker/api/client/plugin"
14
+	"github.com/docker/docker/api/client/registry"
15
+	"github.com/docker/docker/api/client/service"
16
+	"github.com/docker/docker/api/client/stack"
17
+	"github.com/docker/docker/api/client/swarm"
18
+	"github.com/docker/docker/api/client/system"
19
+	"github.com/docker/docker/api/client/volume"
10 20
 	"github.com/docker/docker/cli"
11 21
 	"github.com/docker/docker/cli/cobraadaptor"
12 22
 	cliflags "github.com/docker/docker/cli/flags"
... ...
@@ -18,13 +28,15 @@ import (
18 18
 	"github.com/spf13/pflag"
19 19
 )
20 20
 
21
-func newDockerCommand(dockerCli *client.DockerCli, opts *cliflags.ClientOptions) *cobra.Command {
21
+func newDockerCommand(dockerCli *client.DockerCli) *cobra.Command {
22
+	opts := cliflags.NewClientOptions()
22 23
 	cmd := &cobra.Command{
23
-		Use:           "docker [OPTIONS] COMMAND [arg...]",
24
-		Short:         "A self-sufficient runtime for containers.",
25
-		SilenceUsage:  true,
26
-		SilenceErrors: true,
27
-		Args:          cli.NoArgs,
24
+		Use:              "docker [OPTIONS] COMMAND [arg...]",
25
+		Short:            "A self-sufficient runtime for containers.",
26
+		SilenceUsage:     true,
27
+		SilenceErrors:    true,
28
+		TraverseChildren: true,
29
+		Args:             cli.NoArgs,
28 30
 		RunE: func(cmd *cobra.Command, args []string) error {
29 31
 			if opts.Version {
30 32
 				showVersion()
... ...
@@ -38,13 +50,66 @@ func newDockerCommand(dockerCli *client.DockerCli, opts *cliflags.ClientOptions)
38 38
 			return dockerCli.Initialize(opts)
39 39
 		},
40 40
 	}
41
-	cobraadaptor.SetupRootCommand(cmd, dockerCli)
41
+	cobraadaptor.SetupRootCommand(cmd)
42 42
 
43 43
 	flags := cmd.Flags()
44 44
 	flags.BoolVarP(&opts.Version, "version", "v", false, "Print version information and quit")
45 45
 	flags.StringVar(&opts.ConfigDir, "config", cliconfig.ConfigDir(), "Location of client config files")
46 46
 	opts.Common.InstallFlags(flags)
47 47
 
48
+	cmd.SetOutput(dockerCli.Out())
49
+	cmd.AddCommand(
50
+		newDaemonCommand(),
51
+		node.NewNodeCommand(dockerCli),
52
+		service.NewServiceCommand(dockerCli),
53
+		stack.NewStackCommand(dockerCli),
54
+		stack.NewTopLevelDeployCommand(dockerCli),
55
+		swarm.NewSwarmCommand(dockerCli),
56
+		container.NewAttachCommand(dockerCli),
57
+		container.NewCommitCommand(dockerCli),
58
+		container.NewCopyCommand(dockerCli),
59
+		container.NewCreateCommand(dockerCli),
60
+		container.NewDiffCommand(dockerCli),
61
+		container.NewExecCommand(dockerCli),
62
+		container.NewExportCommand(dockerCli),
63
+		container.NewKillCommand(dockerCli),
64
+		container.NewLogsCommand(dockerCli),
65
+		container.NewPauseCommand(dockerCli),
66
+		container.NewPortCommand(dockerCli),
67
+		container.NewPsCommand(dockerCli),
68
+		container.NewRenameCommand(dockerCli),
69
+		container.NewRestartCommand(dockerCli),
70
+		container.NewRmCommand(dockerCli),
71
+		container.NewRunCommand(dockerCli),
72
+		container.NewStartCommand(dockerCli),
73
+		container.NewStatsCommand(dockerCli),
74
+		container.NewStopCommand(dockerCli),
75
+		container.NewTopCommand(dockerCli),
76
+		container.NewUnpauseCommand(dockerCli),
77
+		container.NewUpdateCommand(dockerCli),
78
+		container.NewWaitCommand(dockerCli),
79
+		image.NewBuildCommand(dockerCli),
80
+		image.NewHistoryCommand(dockerCli),
81
+		image.NewImagesCommand(dockerCli),
82
+		image.NewLoadCommand(dockerCli),
83
+		image.NewRemoveCommand(dockerCli),
84
+		image.NewSaveCommand(dockerCli),
85
+		image.NewPullCommand(dockerCli),
86
+		image.NewPushCommand(dockerCli),
87
+		image.NewSearchCommand(dockerCli),
88
+		image.NewImportCommand(dockerCli),
89
+		image.NewTagCommand(dockerCli),
90
+		network.NewNetworkCommand(dockerCli),
91
+		system.NewEventsCommand(dockerCli),
92
+		system.NewInspectCommand(dockerCli),
93
+		registry.NewLoginCommand(dockerCli),
94
+		registry.NewLogoutCommand(dockerCli),
95
+		system.NewVersionCommand(dockerCli),
96
+		volume.NewVolumeCommand(dockerCli),
97
+		system.NewInfoCommand(dockerCli),
98
+	)
99
+	plugin.NewPluginCommand(cmd, dockerCli)
100
+
48 101
 	return cmd
49 102
 }
50 103
 
... ...
@@ -53,9 +118,8 @@ func main() {
53 53
 	stdin, stdout, stderr := term.StdStreams()
54 54
 	logrus.SetOutput(stderr)
55 55
 
56
-	opts := cliflags.NewClientOptions()
57
-	dockerCli := client.NewDockerCli(stdin, stdout, stderr, opts)
58
-	cmd := newDockerCommand(dockerCli, opts)
56
+	dockerCli := client.NewDockerCli(stdin, stdout, stderr)
57
+	cmd := newDockerCommand(dockerCli)
59 58
 
60 59
 	if err := cmd.Execute(); err != nil {
61 60
 		if sterr, ok := err.(cli.StatusError); ok {
... ...
@@ -86,17 +150,10 @@ func dockerPreRun(flags *pflag.FlagSet, opts *cliflags.ClientOptions) {
86 86
 	opts.Common.SetDefaultOptions(flags)
87 87
 	cliflags.SetDaemonLogLevel(opts.Common.LogLevel)
88 88
 
89
-	// TODO: remove this, set a default in New, and pass it in opts
90 89
 	if opts.ConfigDir != "" {
91 90
 		cliconfig.SetConfigDir(opts.ConfigDir)
92 91
 	}
93 92
 
94
-	if opts.Common.TrustKey == "" {
95
-		opts.Common.TrustKey = filepath.Join(
96
-			cliconfig.ConfigDir(),
97
-			cliflags.DefaultTrustKeyFile)
98
-	}
99
-
100 93
 	if opts.Common.Debug {
101 94
 		utils.EnableDebug()
102 95
 	}
... ...
@@ -8,16 +8,14 @@ import (
8 8
 	"github.com/docker/docker/utils"
9 9
 
10 10
 	"github.com/docker/docker/api/client"
11
-	cliflags "github.com/docker/docker/cli/flags"
12 11
 )
13 12
 
14 13
 func TestClientDebugEnabled(t *testing.T) {
15 14
 	defer utils.DisableDebug()
16 15
 
17
-	opts := cliflags.NewClientOptions()
18
-	cmd := newDockerCommand(&client.DockerCli{}, opts)
16
+	cmd := newDockerCommand(&client.DockerCli{})
17
+	cmd.Flags().Set("debug", "true")
19 18
 
20
-	opts.Common.Debug = true
21 19
 	if err := cmd.PersistentPreRunE(cmd, []string{}); err != nil {
22 20
 		t.Fatalf("Unexpected error: %s", err.Error())
23 21
 	}
... ...
@@ -1,290 +1,145 @@
1 1
 package main
2 2
 
3 3
 import (
4
-	"io/ioutil"
5
-	"os"
6
-	"strings"
7 4
 	"testing"
8 5
 
9 6
 	"github.com/Sirupsen/logrus"
10 7
 	cliflags "github.com/docker/docker/cli/flags"
11 8
 	"github.com/docker/docker/daemon"
12
-	"github.com/docker/docker/opts"
13
-	"github.com/docker/docker/pkg/mflag"
14
-	"github.com/docker/go-connections/tlsconfig"
9
+	"github.com/docker/docker/pkg/testutil/assert"
10
+	"github.com/docker/docker/pkg/testutil/tempfile"
11
+	"github.com/spf13/pflag"
15 12
 )
16 13
 
14
+func defaultOptions(configFile string) daemonOptions {
15
+	opts := daemonOptions{
16
+		daemonConfig: &daemon.Config{},
17
+		flags:        &pflag.FlagSet{},
18
+		common:       cliflags.NewCommonOptions(),
19
+	}
20
+	opts.common.InstallFlags(opts.flags)
21
+	opts.daemonConfig.InstallFlags(opts.flags)
22
+	opts.flags.StringVar(&opts.configFile, flagDaemonConfigFile, defaultDaemonConfigFile, "")
23
+	opts.configFile = configFile
24
+	return opts
25
+}
26
+
17 27
 func TestLoadDaemonCliConfigWithoutOverriding(t *testing.T) {
18
-	c := &daemon.Config{}
19
-	common := &cliflags.CommonFlags{
20
-		Debug: true,
21
-	}
28
+	opts := defaultOptions("")
29
+	opts.common.Debug = true
22 30
 
23
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
24
-	loadedConfig, err := loadDaemonCliConfig(c, flags, common, "/tmp/fooobarbaz")
25
-	if err != nil {
26
-		t.Fatal(err)
27
-	}
28
-	if loadedConfig == nil {
29
-		t.Fatalf("expected configuration %v, got nil", c)
30
-	}
31
+	loadedConfig, err := loadDaemonCliConfig(opts)
32
+	assert.NilError(t, err)
33
+	assert.NotNil(t, loadedConfig)
31 34
 	if !loadedConfig.Debug {
32 35
 		t.Fatalf("expected debug to be copied from the common flags, got false")
33 36
 	}
34 37
 }
35 38
 
36 39
 func TestLoadDaemonCliConfigWithTLS(t *testing.T) {
37
-	c := &daemon.Config{}
38
-	common := &cliflags.CommonFlags{
39
-		TLS: true,
40
-		TLSOptions: &tlsconfig.Options{
41
-			CAFile: "/tmp/ca.pem",
42
-		},
43
-	}
44
-
45
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
46
-	loadedConfig, err := loadDaemonCliConfig(c, flags, common, "/tmp/fooobarbaz")
47
-	if err != nil {
48
-		t.Fatal(err)
49
-	}
50
-	if loadedConfig == nil {
51
-		t.Fatalf("expected configuration %v, got nil", c)
52
-	}
53
-	if loadedConfig.CommonTLSOptions.CAFile != "/tmp/ca.pem" {
54
-		t.Fatalf("expected /tmp/ca.pem, got %s: %q", loadedConfig.CommonTLSOptions.CAFile, loadedConfig)
55
-	}
40
+	opts := defaultOptions("")
41
+	opts.common.TLSOptions.CAFile = "/tmp/ca.pem"
42
+	opts.common.TLS = true
43
+
44
+	loadedConfig, err := loadDaemonCliConfig(opts)
45
+	assert.NilError(t, err)
46
+	assert.NotNil(t, loadedConfig)
47
+	assert.Equal(t, loadedConfig.CommonTLSOptions.CAFile, "/tmp/ca.pem")
56 48
 }
57 49
 
58 50
 func TestLoadDaemonCliConfigWithConflicts(t *testing.T) {
59
-	c := &daemon.Config{}
60
-	common := &cliflags.CommonFlags{}
61
-	f, err := ioutil.TempFile("", "docker-config-")
62
-	if err != nil {
63
-		t.Fatal(err)
64
-	}
65
-	configFile := f.Name()
66
-	defer os.Remove(configFile)
67
-
68
-	f.Write([]byte(`{"labels": ["l3=foo"]}`))
69
-	f.Close()
70
-
71
-	var labels []string
51
+	tempFile := tempfile.NewTempFile(t, "config", `{"labels": ["l3=foo"]}`)
52
+	defer tempFile.Remove()
53
+	configFile := tempFile.Name()
72 54
 
73
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
74
-	flags.String([]string{daemonConfigFileFlag}, "", "")
75
-	flags.Var(opts.NewNamedListOptsRef("labels", &labels, opts.ValidateLabel), []string{"-label"}, "")
55
+	opts := defaultOptions(configFile)
56
+	flags := opts.flags
76 57
 
77
-	flags.Set(daemonConfigFileFlag, configFile)
78
-	if err := flags.Set("-label", "l1=bar"); err != nil {
79
-		t.Fatal(err)
80
-	}
81
-	if err := flags.Set("-label", "l2=baz"); err != nil {
82
-		t.Fatal(err)
83
-	}
58
+	assert.NilError(t, flags.Set(flagDaemonConfigFile, configFile))
59
+	assert.NilError(t, flags.Set("label", "l1=bar"))
60
+	assert.NilError(t, flags.Set("label", "l2=baz"))
84 61
 
85
-	_, err = loadDaemonCliConfig(c, flags, common, configFile)
86
-	if err == nil {
87
-		t.Fatalf("expected configuration error, got nil")
88
-	}
89
-	if !strings.Contains(err.Error(), "labels") {
90
-		t.Fatalf("expected labels conflict, got %v", err)
91
-	}
62
+	_, err := loadDaemonCliConfig(opts)
63
+	assert.Error(t, err, "as a flag and in the configuration file: labels")
92 64
 }
93 65
 
94 66
 func TestLoadDaemonCliConfigWithTLSVerify(t *testing.T) {
95
-	c := &daemon.Config{}
96
-	common := &cliflags.CommonFlags{
97
-		TLSOptions: &tlsconfig.Options{
98
-			CAFile: "/tmp/ca.pem",
99
-		},
100
-	}
101
-
102
-	f, err := ioutil.TempFile("", "docker-config-")
103
-	if err != nil {
104
-		t.Fatal(err)
105
-	}
106
-	configFile := f.Name()
107
-	defer os.Remove(configFile)
108
-
109
-	f.Write([]byte(`{"tlsverify": true}`))
110
-	f.Close()
67
+	tempFile := tempfile.NewTempFile(t, "config", `{"tlsverify": true}`)
68
+	defer tempFile.Remove()
111 69
 
112
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
113
-	flags.Bool([]string{"-tlsverify"}, false, "")
114
-	loadedConfig, err := loadDaemonCliConfig(c, flags, common, configFile)
115
-	if err != nil {
116
-		t.Fatal(err)
117
-	}
118
-	if loadedConfig == nil {
119
-		t.Fatalf("expected configuration %v, got nil", c)
120
-	}
70
+	opts := defaultOptions(tempFile.Name())
71
+	opts.common.TLSOptions.CAFile = "/tmp/ca.pem"
121 72
 
122
-	if !loadedConfig.TLS {
123
-		t.Fatalf("expected TLS enabled, got %q", loadedConfig)
124
-	}
73
+	loadedConfig, err := loadDaemonCliConfig(opts)
74
+	assert.NilError(t, err)
75
+	assert.NotNil(t, loadedConfig)
76
+	assert.Equal(t, loadedConfig.TLS, true)
125 77
 }
126 78
 
127 79
 func TestLoadDaemonCliConfigWithExplicitTLSVerifyFalse(t *testing.T) {
128
-	c := &daemon.Config{}
129
-	common := &cliflags.CommonFlags{
130
-		TLSOptions: &tlsconfig.Options{
131
-			CAFile: "/tmp/ca.pem",
132
-		},
133
-	}
80
+	tempFile := tempfile.NewTempFile(t, "config", `{"tlsverify": false}`)
81
+	defer tempFile.Remove()
134 82
 
135
-	f, err := ioutil.TempFile("", "docker-config-")
136
-	if err != nil {
137
-		t.Fatal(err)
138
-	}
139
-	configFile := f.Name()
140
-	defer os.Remove(configFile)
141
-
142
-	f.Write([]byte(`{"tlsverify": false}`))
143
-	f.Close()
144
-
145
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
146
-	flags.Bool([]string{"-tlsverify"}, false, "")
147
-	loadedConfig, err := loadDaemonCliConfig(c, flags, common, configFile)
148
-	if err != nil {
149
-		t.Fatal(err)
150
-	}
151
-	if loadedConfig == nil {
152
-		t.Fatalf("expected configuration %v, got nil", c)
153
-	}
83
+	opts := defaultOptions(tempFile.Name())
84
+	opts.common.TLSOptions.CAFile = "/tmp/ca.pem"
154 85
 
155
-	if !loadedConfig.TLS {
156
-		t.Fatalf("expected TLS enabled, got %q", loadedConfig)
157
-	}
86
+	loadedConfig, err := loadDaemonCliConfig(opts)
87
+	assert.NilError(t, err)
88
+	assert.NotNil(t, loadedConfig)
89
+	assert.Equal(t, loadedConfig.TLS, true)
158 90
 }
159 91
 
160 92
 func TestLoadDaemonCliConfigWithoutTLSVerify(t *testing.T) {
161
-	c := &daemon.Config{}
162
-	common := &cliflags.CommonFlags{
163
-		TLSOptions: &tlsconfig.Options{
164
-			CAFile: "/tmp/ca.pem",
165
-		},
166
-	}
167
-
168
-	f, err := ioutil.TempFile("", "docker-config-")
169
-	if err != nil {
170
-		t.Fatal(err)
171
-	}
172
-	configFile := f.Name()
173
-	defer os.Remove(configFile)
93
+	tempFile := tempfile.NewTempFile(t, "config", `{}`)
94
+	defer tempFile.Remove()
174 95
 
175
-	f.Write([]byte(`{}`))
176
-	f.Close()
96
+	opts := defaultOptions(tempFile.Name())
97
+	opts.common.TLSOptions.CAFile = "/tmp/ca.pem"
177 98
 
178
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
179
-	loadedConfig, err := loadDaemonCliConfig(c, flags, common, configFile)
180
-	if err != nil {
181
-		t.Fatal(err)
182
-	}
183
-	if loadedConfig == nil {
184
-		t.Fatalf("expected configuration %v, got nil", c)
185
-	}
186
-
187
-	if loadedConfig.TLS {
188
-		t.Fatalf("expected TLS disabled, got %q", loadedConfig)
189
-	}
99
+	loadedConfig, err := loadDaemonCliConfig(opts)
100
+	assert.NilError(t, err)
101
+	assert.NotNil(t, loadedConfig)
102
+	assert.Equal(t, loadedConfig.TLS, false)
190 103
 }
191 104
 
192 105
 func TestLoadDaemonCliConfigWithLogLevel(t *testing.T) {
193
-	c := &daemon.Config{}
194
-	common := &cliflags.CommonFlags{}
195
-
196
-	f, err := ioutil.TempFile("", "docker-config-")
197
-	if err != nil {
198
-		t.Fatal(err)
199
-	}
200
-	configFile := f.Name()
201
-	defer os.Remove(configFile)
202
-
203
-	f.Write([]byte(`{"log-level": "warn"}`))
204
-	f.Close()
205
-
206
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
207
-	flags.String([]string{"-log-level"}, "", "")
208
-	loadedConfig, err := loadDaemonCliConfig(c, flags, common, configFile)
209
-	if err != nil {
210
-		t.Fatal(err)
211
-	}
212
-	if loadedConfig == nil {
213
-		t.Fatalf("expected configuration %v, got nil", c)
214
-	}
215
-	if loadedConfig.LogLevel != "warn" {
216
-		t.Fatalf("expected warn log level, got %v", loadedConfig.LogLevel)
217
-	}
218
-
219
-	if logrus.GetLevel() != logrus.WarnLevel {
220
-		t.Fatalf("expected warn log level, got %v", logrus.GetLevel())
221
-	}
106
+	tempFile := tempfile.NewTempFile(t, "config", `{"log-level": "warn"}`)
107
+	defer tempFile.Remove()
108
+
109
+	opts := defaultOptions(tempFile.Name())
110
+	loadedConfig, err := loadDaemonCliConfig(opts)
111
+	assert.NilError(t, err)
112
+	assert.NotNil(t, loadedConfig)
113
+	assert.Equal(t, loadedConfig.LogLevel, "warn")
114
+	assert.Equal(t, logrus.GetLevel(), logrus.WarnLevel)
222 115
 }
223 116
 
224 117
 func TestLoadDaemonConfigWithEmbeddedOptions(t *testing.T) {
225
-	c := &daemon.Config{}
226
-	common := &cliflags.CommonFlags{}
227
-
228
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
229
-	flags.String([]string{"-tlscacert"}, "", "")
230
-	flags.String([]string{"-log-driver"}, "", "")
231
-
232
-	f, err := ioutil.TempFile("", "docker-config-")
233
-	if err != nil {
234
-		t.Fatal(err)
235
-	}
236
-	configFile := f.Name()
237
-	defer os.Remove(configFile)
238
-
239
-	f.Write([]byte(`{"tlscacert": "/etc/certs/ca.pem", "log-driver": "syslog"}`))
240
-	f.Close()
241
-
242
-	loadedConfig, err := loadDaemonCliConfig(c, flags, common, configFile)
243
-	if err != nil {
244
-		t.Fatal(err)
245
-	}
246
-	if loadedConfig == nil {
247
-		t.Fatal("expected configuration, got nil")
248
-	}
249
-	if loadedConfig.CommonTLSOptions.CAFile != "/etc/certs/ca.pem" {
250
-		t.Fatalf("expected CA file path /etc/certs/ca.pem, got %v", loadedConfig.CommonTLSOptions.CAFile)
251
-	}
252
-	if loadedConfig.LogConfig.Type != "syslog" {
253
-		t.Fatalf("expected LogConfig type syslog, got %v", loadedConfig.LogConfig.Type)
254
-	}
118
+	content := `{"tlscacert": "/etc/certs/ca.pem", "log-driver": "syslog"}`
119
+	tempFile := tempfile.NewTempFile(t, "config", content)
120
+	defer tempFile.Remove()
121
+
122
+	opts := defaultOptions(tempFile.Name())
123
+	loadedConfig, err := loadDaemonCliConfig(opts)
124
+	assert.NilError(t, err)
125
+	assert.NotNil(t, loadedConfig)
126
+	assert.Equal(t, loadedConfig.CommonTLSOptions.CAFile, "/etc/certs/ca.pem")
127
+	assert.Equal(t, loadedConfig.LogConfig.Type, "syslog")
255 128
 }
256 129
 
257 130
 func TestLoadDaemonConfigWithRegistryOptions(t *testing.T) {
258
-	c := &daemon.Config{}
259
-	common := &cliflags.CommonFlags{}
260
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
261
-	c.ServiceOptions.InstallCliFlags(flags, absentFromHelp)
262
-
263
-	f, err := ioutil.TempFile("", "docker-config-")
264
-	if err != nil {
265
-		t.Fatal(err)
266
-	}
267
-	configFile := f.Name()
268
-	defer os.Remove(configFile)
269
-
270
-	f.Write([]byte(`{"registry-mirrors": ["https://mirrors.docker.com"], "insecure-registries": ["https://insecure.docker.com"]}`))
271
-	f.Close()
272
-
273
-	loadedConfig, err := loadDaemonCliConfig(c, flags, common, configFile)
274
-	if err != nil {
275
-		t.Fatal(err)
276
-	}
277
-	if loadedConfig == nil {
278
-		t.Fatal("expected configuration, got nil")
279
-	}
280
-
281
-	m := loadedConfig.Mirrors
282
-	if len(m) != 1 {
283
-		t.Fatalf("expected 1 mirror, got %d", len(m))
284
-	}
285
-
286
-	r := loadedConfig.InsecureRegistries
287
-	if len(r) != 1 {
288
-		t.Fatalf("expected 1 insecure registries, got %d", len(r))
289
-	}
131
+	content := `{
132
+		"registry-mirrors": ["https://mirrors.docker.com"],
133
+		"insecure-registries": ["https://insecure.docker.com"],
134
+	}`
135
+	tempFile := tempfile.NewTempFile(t, "config", content)
136
+	defer tempFile.Remove()
137
+
138
+	opts := defaultOptions(tempFile.Name())
139
+	loadedConfig, err := loadDaemonCliConfig(opts)
140
+	assert.NilError(t, err)
141
+	assert.NotNil(t, loadedConfig)
142
+
143
+	assert.Equal(t, len(loadedConfig.Mirrors), 1)
144
+	assert.Equal(t, len(loadedConfig.InsecureRegistries), 1)
290 145
 }
... ...
@@ -7,209 +7,98 @@ import (
7 7
 	"os"
8 8
 	"testing"
9 9
 
10
-	cliflags "github.com/docker/docker/cli/flags"
11 10
 	"github.com/docker/docker/daemon"
12
-	"github.com/docker/docker/opts"
13
-	"github.com/docker/docker/pkg/mflag"
11
+	"github.com/docker/docker/pkg/testutil/assert"
12
+	"github.com/docker/docker/pkg/testutil/tempfile"
14 13
 )
15 14
 
16 15
 func TestLoadDaemonCliConfigWithDaemonFlags(t *testing.T) {
17
-	c := &daemon.Config{}
18
-	common := &cliflags.CommonFlags{
19
-		Debug:    true,
20
-		LogLevel: "info",
21
-	}
22
-
23
-	f, err := ioutil.TempFile("", "docker-config-")
24
-	if err != nil {
25
-		t.Fatal(err)
26
-	}
27
-
28
-	configFile := f.Name()
29
-	f.Write([]byte(`{"log-opts": {"max-size": "1k"}}`))
30
-	f.Close()
31
-
32
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
33
-	flags.String([]string{daemonConfigFileFlag}, "", "")
34
-	flags.BoolVar(&c.EnableSelinuxSupport, []string{"-selinux-enabled"}, true, "")
35
-	flags.StringVar(&c.LogConfig.Type, []string{"-log-driver"}, "json-file", "")
36
-	flags.Var(opts.NewNamedMapOpts("log-opts", c.LogConfig.Config, nil), []string{"-log-opt"}, "")
37
-	flags.Set(daemonConfigFileFlag, configFile)
38
-
39
-	loadedConfig, err := loadDaemonCliConfig(c, flags, common, configFile)
40
-	if err != nil {
41
-		t.Fatal(err)
42
-	}
43
-	if loadedConfig == nil {
44
-		t.Fatalf("expected configuration %v, got nil", c)
45
-	}
46
-	if !loadedConfig.Debug {
47
-		t.Fatalf("expected debug mode, got false")
48
-	}
49
-	if loadedConfig.LogLevel != "info" {
50
-		t.Fatalf("expected info log level, got %v", loadedConfig.LogLevel)
51
-	}
52
-	if !loadedConfig.EnableSelinuxSupport {
53
-		t.Fatalf("expected enabled selinux support, got disabled")
54
-	}
55
-	if loadedConfig.LogConfig.Type != "json-file" {
56
-		t.Fatalf("expected LogConfig type json-file, got %v", loadedConfig.LogConfig.Type)
57
-	}
58
-	if maxSize := loadedConfig.LogConfig.Config["max-size"]; maxSize != "1k" {
59
-		t.Fatalf("expected log max-size `1k`, got %s", maxSize)
60
-	}
16
+	content := `{"log-opts": {"max-size": "1k"}}`
17
+	tempFile := tempfile.NewTempFile(t, "config", content)
18
+	defer tempFile.Remove()
19
+
20
+	opts := defaultOptions(tempFile.Name())
21
+	opts.common.Debug = true
22
+	opts.common.LogLevel = "info"
23
+	assert.NilError(t, opts.flags.Set("selinux-enabled", "true"))
24
+
25
+	loadedConfig, err := loadDaemonCliConfig(opts)
26
+	assert.NilError(t, err)
27
+	assert.NotNil(t, loadedConfig)
28
+
29
+	assert.Equal(t, loadedConfig.Debug, true)
30
+	assert.Equal(t, loadedConfig.LogLevel, "info")
31
+	assert.Equal(t, loadedConfig.EnableSelinuxSupport, true)
32
+	assert.Equal(t, loadedConfig.LogConfig.Type, "json-file")
33
+	assert.Equal(t, loadedConfig.LogConfig.Config["max-size"], "1k")
61 34
 }
62 35
 
63 36
 func TestLoadDaemonConfigWithNetwork(t *testing.T) {
64
-	c := &daemon.Config{}
65
-	common := &cliflags.CommonFlags{}
66
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
67
-	flags.String([]string{"-bip"}, "", "")
68
-	flags.String([]string{"-ip"}, "", "")
69
-
70
-	f, err := ioutil.TempFile("", "docker-config-")
71
-	if err != nil {
72
-		t.Fatal(err)
73
-	}
37
+	content := `{"bip": "127.0.0.2", "ip": "127.0.0.1"}`
38
+	tempFile := tempfile.NewTempFile(t, "config", content)
39
+	defer tempFile.Remove()
74 40
 
75
-	configFile := f.Name()
76
-	f.Write([]byte(`{"bip": "127.0.0.2", "ip": "127.0.0.1"}`))
77
-	f.Close()
41
+	opts := defaultOptions(tempFile.Name())
42
+	loadedConfig, err := loadDaemonCliConfig(opts)
43
+	assert.NilError(t, err)
44
+	assert.NotNil(t, loadedConfig)
78 45
 
79
-	loadedConfig, err := loadDaemonCliConfig(c, flags, common, configFile)
80
-	if err != nil {
81
-		t.Fatal(err)
82
-	}
83
-	if loadedConfig == nil {
84
-		t.Fatalf("expected configuration %v, got nil", c)
85
-	}
86
-	if loadedConfig.IP != "127.0.0.2" {
87
-		t.Fatalf("expected IP 127.0.0.2, got %v", loadedConfig.IP)
88
-	}
89
-	if loadedConfig.DefaultIP.String() != "127.0.0.1" {
90
-		t.Fatalf("expected DefaultIP 127.0.0.1, got %s", loadedConfig.DefaultIP)
91
-	}
46
+	assert.Equal(t, loadedConfig.IP, "127.0.0.2")
47
+	assert.Equal(t, loadedConfig.DefaultIP.String(), "127.0.0.1")
92 48
 }
93 49
 
94 50
 func TestLoadDaemonConfigWithMapOptions(t *testing.T) {
95
-	c := &daemon.Config{}
96
-	common := &cliflags.CommonFlags{}
97
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
98
-
99
-	flags.Var(opts.NewNamedMapOpts("cluster-store-opts", c.ClusterOpts, nil), []string{"-cluster-store-opt"}, "")
100
-	flags.Var(opts.NewNamedMapOpts("log-opts", c.LogConfig.Config, nil), []string{"-log-opt"}, "")
101
-
102
-	f, err := ioutil.TempFile("", "docker-config-")
103
-	if err != nil {
104
-		t.Fatal(err)
105
-	}
106
-
107
-	configFile := f.Name()
108
-	f.Write([]byte(`{
51
+	content := `{
109 52
 		"cluster-store-opts": {"kv.cacertfile": "/var/lib/docker/discovery_certs/ca.pem"},
110 53
 		"log-opts": {"tag": "test"}
111
-}`))
112
-	f.Close()
54
+}`
55
+	tempFile := tempfile.NewTempFile(t, "config", content)
56
+	defer tempFile.Remove()
113 57
 
114
-	loadedConfig, err := loadDaemonCliConfig(c, flags, common, configFile)
115
-	if err != nil {
116
-		t.Fatal(err)
117
-	}
118
-	if loadedConfig == nil {
119
-		t.Fatal("expected configuration, got nil")
120
-	}
121
-	if loadedConfig.ClusterOpts == nil {
122
-		t.Fatal("expected cluster options, got nil")
123
-	}
58
+	opts := defaultOptions(tempFile.Name())
59
+	loadedConfig, err := loadDaemonCliConfig(opts)
60
+	assert.NilError(t, err)
61
+	assert.NotNil(t, loadedConfig)
62
+	assert.NotNil(t, loadedConfig.ClusterOpts)
124 63
 
125 64
 	expectedPath := "/var/lib/docker/discovery_certs/ca.pem"
126
-	if caPath := loadedConfig.ClusterOpts["kv.cacertfile"]; caPath != expectedPath {
127
-		t.Fatalf("expected %s, got %s", expectedPath, caPath)
128
-	}
129
-
130
-	if loadedConfig.LogConfig.Config == nil {
131
-		t.Fatal("expected log config options, got nil")
132
-	}
133
-	if tag := loadedConfig.LogConfig.Config["tag"]; tag != "test" {
134
-		t.Fatalf("expected log tag `test`, got %s", tag)
135
-	}
65
+	assert.Equal(t, loadedConfig.ClusterOpts["kv.cacertfile"], expectedPath)
66
+	assert.NotNil(t, loadedConfig.LogConfig.Config)
67
+	assert.Equal(t, loadedConfig.LogConfig.Config["tag"], "test")
136 68
 }
137 69
 
138 70
 func TestLoadDaemonConfigWithTrueDefaultValues(t *testing.T) {
139
-	c := &daemon.Config{}
140
-	common := &cliflags.CommonFlags{}
141
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
142
-	flags.BoolVar(&c.EnableUserlandProxy, []string{"-userland-proxy"}, true, "")
143
-
144
-	f, err := ioutil.TempFile("", "docker-config-")
145
-	if err != nil {
146
-		t.Fatal(err)
147
-	}
148
-
149
-	if err := flags.ParseFlags([]string{}, false); err != nil {
150
-		t.Fatal(err)
151
-	}
71
+	content := `{ "userland-proxy": false }`
72
+	tempFile := tempfile.NewTempFile(t, "config", content)
73
+	defer tempFile.Remove()
152 74
 
153
-	configFile := f.Name()
154
-	f.Write([]byte(`{
155
-		"userland-proxy": false
156
-}`))
157
-	f.Close()
158
-
159
-	loadedConfig, err := loadDaemonCliConfig(c, flags, common, configFile)
160
-	if err != nil {
161
-		t.Fatal(err)
162
-	}
163
-	if loadedConfig == nil {
164
-		t.Fatal("expected configuration, got nil")
165
-	}
75
+	opts := defaultOptions(tempFile.Name())
76
+	loadedConfig, err := loadDaemonCliConfig(opts)
77
+	assert.NilError(t, err)
78
+	assert.NotNil(t, loadedConfig)
79
+	assert.NotNil(t, loadedConfig.ClusterOpts)
166 80
 
167
-	if loadedConfig.EnableUserlandProxy {
168
-		t.Fatal("expected userland proxy to be disabled, got enabled")
169
-	}
81
+	assert.Equal(t, loadedConfig.EnableUserlandProxy, false)
170 82
 
171 83
 	// make sure reloading doesn't generate configuration
172 84
 	// conflicts after normalizing boolean values.
173
-	err = daemon.ReloadConfiguration(configFile, flags, func(reloadedConfig *daemon.Config) {
174
-		if reloadedConfig.EnableUserlandProxy {
175
-			t.Fatal("expected userland proxy to be disabled, got enabled")
176
-		}
177
-	})
178
-	if err != nil {
179
-		t.Fatal(err)
85
+	reload := func(reloadedConfig *daemon.Config) {
86
+		assert.Equal(t, reloadedConfig.EnableUserlandProxy, false)
180 87
 	}
88
+	assert.NilError(t, daemon.ReloadConfiguration(opts.configFile, opts.flags, reload))
181 89
 }
182 90
 
183 91
 func TestLoadDaemonConfigWithTrueDefaultValuesLeaveDefaults(t *testing.T) {
184
-	c := &daemon.Config{}
185
-	common := &cliflags.CommonFlags{}
186
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
187
-	flags.BoolVar(&c.EnableUserlandProxy, []string{"-userland-proxy"}, true, "")
188
-
189
-	f, err := ioutil.TempFile("", "docker-config-")
190
-	if err != nil {
191
-		t.Fatal(err)
192
-	}
92
+	tempFile := tempfile.NewTempFile(t, "config", `{}`)
93
+	defer tempFile.Remove()
193 94
 
194
-	if err := flags.ParseFlags([]string{}, false); err != nil {
195
-		t.Fatal(err)
196
-	}
197
-
198
-	configFile := f.Name()
199
-	f.Write([]byte(`{}`))
200
-	f.Close()
201
-
202
-	loadedConfig, err := loadDaemonCliConfig(c, flags, common, configFile)
203
-	if err != nil {
204
-		t.Fatal(err)
205
-	}
206
-	if loadedConfig == nil {
207
-		t.Fatal("expected configuration, got nil")
208
-	}
95
+	opts := defaultOptions(tempFile.Name())
96
+	loadedConfig, err := loadDaemonCliConfig(opts)
97
+	assert.NilError(t, err)
98
+	assert.NotNil(t, loadedConfig)
99
+	assert.NotNil(t, loadedConfig.ClusterOpts)
209 100
 
210
-	if !loadedConfig.EnableUserlandProxy {
211
-		t.Fatal("expected userland proxy to be enabled, got disabled")
212
-	}
101
+	assert.Equal(t, loadedConfig.EnableUserlandProxy, true)
213 102
 }
214 103
 
215 104
 func TestLoadDaemonConfigWithLegacyRegistryOptions(t *testing.T) {
... ...
@@ -5,6 +5,7 @@ import (
5 5
 
6 6
 	"github.com/Sirupsen/logrus"
7 7
 	"github.com/docker/docker/cli"
8
+	"github.com/docker/docker/cli/cobraadaptor"
8 9
 	cliflags "github.com/docker/docker/cli/flags"
9 10
 	"github.com/docker/docker/daemon"
10 11
 	"github.com/docker/docker/dockerversion"
... ...
@@ -40,15 +41,14 @@ func newDaemonCommand() *cobra.Command {
40 40
 			return runDaemon(opts)
41 41
 		},
42 42
 	}
43
-	// TODO: SetUsageTemplate, SetHelpTemplate, SetFlagErrorFunc
43
+	cobraadaptor.SetupRootCommand(cmd)
44 44
 
45 45
 	flags := cmd.Flags()
46
-	flags.BoolP("help", "h", false, "Print usage")
47
-	flags.MarkShorthandDeprecated("help", "please use --help")
48 46
 	flags.BoolVarP(&opts.version, "version", "v", false, "Print version information and quit")
49 47
 	flags.StringVar(&opts.configFile, flagDaemonConfigFile, defaultDaemonConfigFile, "Daemon configuration file")
50 48
 	opts.common.InstallFlags(flags)
51 49
 	opts.daemonConfig.InstallFlags(flags)
50
+	installServiceFlags(flags)
52 51
 
53 52
 	return cmd
54 53
 }
... ...
@@ -2,6 +2,13 @@
2 2
 
3 3
 package main
4 4
 
5
+import (
6
+	"github.com/spf13/pflag"
7
+)
8
+
5 9
 func initService() (bool, error) {
6 10
 	return false, nil
7 11
 }
12
+
13
+func installServiceFlags(flags *pflag.FlagSet) {
14
+}
... ...
@@ -3,6 +3,7 @@ package main
3 3
 import (
4 4
 	"bytes"
5 5
 	"errors"
6
+	"flag"
6 7
 	"fmt"
7 8
 	"io/ioutil"
8 9
 	"os"
... ...
@@ -11,7 +12,7 @@ import (
11 11
 	"syscall"
12 12
 
13 13
 	"github.com/Sirupsen/logrus"
14
-	flag "github.com/docker/docker/pkg/mflag"
14
+	"github.com/spf13/pflag"
15 15
 	"golang.org/x/sys/windows"
16 16
 	"golang.org/x/sys/windows/svc"
17 17
 	"golang.org/x/sys/windows/svc/debug"
... ...
@@ -20,10 +21,10 @@ import (
20 20
 )
21 21
 
22 22
 var (
23
-	flServiceName       = flag.String([]string{"-service-name"}, "docker", "Set the Windows service name")
24
-	flRegisterService   = flag.Bool([]string{"-register-service"}, false, "Register the service and exit")
25
-	flUnregisterService = flag.Bool([]string{"-unregister-service"}, false, "Unregister the service and exit")
26
-	flRunService        = flag.Bool([]string{"-run-service"}, false, "")
23
+	flServiceName       *string
24
+	flRegisterService   *bool
25
+	flUnregisterService *bool
26
+	flRunService        *bool
27 27
 
28 28
 	setStdHandle = syscall.NewLazyDLL("kernel32.dll").NewProc("SetStdHandle")
29 29
 	oldStderr    syscall.Handle
... ...
@@ -44,6 +45,13 @@ const (
44 44
 	eventExtraOffset = 10 // Add this to any event to get a string that supports extended data
45 45
 )
46 46
 
47
+func installServiceFlags(flags *pflag.FlagSet) {
48
+	flServiceName = flags.String("service-name", "docker", "Set the Windows service name")
49
+	flRegisterService = flags.Bool("register-service", false, "Register the service and exit")
50
+	flUnregisterService = flags.Bool("unregister-service", false, "Unregister the service and exit")
51
+	flRunService = flags.Bool("run-service", false, "")
52
+}
53
+
47 54
 type handler struct {
48 55
 	tosvc   chan bool
49 56
 	fromsvc chan error
... ...
@@ -158,7 +158,7 @@ func (config *Config) InstallCommonFlags(flags *pflag.FlagSet) {
158 158
 	flags.StringVarP(&config.Pidfile, "pidfile", "p", defaultPidFile, "Path to use for daemon PID file")
159 159
 	flags.StringVarP(&config.Root, "graph", "g", defaultGraph, "Root of the Docker runtime")
160 160
 	flags.BoolVarP(&config.AutoRestart, "restart", "r", true, "--restart on the daemon has been deprecated in favor of --restart policies on docker run")
161
-	flags.MarkDeprecated("restart", "Please use a restart policy on ducker run")
161
+	flags.MarkDeprecated("restart", "Please use a restart policy on docker run")
162 162
 	flags.StringVarP(&config.GraphDriver, "storage-driver", "s", "", "Storage driver to use")
163 163
 	flags.IntVar(&config.Mtu, "mtu", 0, "Set the containers network MTU")
164 164
 	flags.BoolVar(&config.RawLogs, "raw-logs", false, "Full timestamps without ANSI coloring")
... ...
@@ -300,7 +300,7 @@ func getConflictFreeConfiguration(configFile string, flags *pflag.FlagSet) (*Con
300 300
 		// TODO: Rewrite configuration logic to avoid same issue with other nullable values, like numbers.
301 301
 		namedOptions := make(map[string]interface{})
302 302
 		for key, value := range configSet {
303
-			f := flags.Lookup("-" + key)
303
+			f := flags.Lookup(key)
304 304
 			if f == nil { // ignore named flags that don't match
305 305
 				namedOptions[key] = value
306 306
 				continue
... ...
@@ -354,8 +354,7 @@ func findConfigurationConflicts(config map[string]interface{}, flags *pflag.Flag
354 354
 	// 1. Search keys from the file that we don't recognize as flags.
355 355
 	unknownKeys := make(map[string]interface{})
356 356
 	for key, value := range config {
357
-		flagName := "-" + key
358
-		if flag := flags.Lookup(flagName); flag == nil {
357
+		if flag := flags.Lookup(key); flag == nil {
359 358
 			unknownKeys[key] = value
360 359
 		}
361 360
 	}
... ...
@@ -396,8 +395,6 @@ func findConfigurationConflicts(config map[string]interface{}, flags *pflag.Flag
396 396
 		} else {
397 397
 			// search flag name in the json configuration payload
398 398
 			for _, name := range []string{f.Name, f.Shorthand} {
399
-				name = strings.TrimLeft(name, "-")
400
-
401 399
 				if value, ok := config[name]; ok {
402 400
 					conflicts = append(conflicts, printConflict(name, f.Value.String(), value))
403 401
 					break
... ...
@@ -7,7 +7,8 @@ import (
7 7
 	"testing"
8 8
 
9 9
 	"github.com/docker/docker/opts"
10
-	"github.com/docker/docker/pkg/mflag"
10
+	"github.com/docker/docker/pkg/testutil/assert"
11
+	"github.com/spf13/pflag"
11 12
 )
12 13
 
13 14
 func TestDaemonConfigurationMerge(t *testing.T) {
... ...
@@ -87,42 +88,26 @@ func TestParseClusterAdvertiseSettings(t *testing.T) {
87 87
 
88 88
 func TestFindConfigurationConflicts(t *testing.T) {
89 89
 	config := map[string]interface{}{"authorization-plugins": "foobar"}
90
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
90
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
91 91
 
92
-	flags.String([]string{"-authorization-plugins"}, "", "")
93
-	if err := flags.Set("-authorization-plugins", "asdf"); err != nil {
94
-		t.Fatal(err)
95
-	}
92
+	flags.String("authorization-plugins", "", "")
93
+	assert.NilError(t, flags.Set("authorization-plugins", "asdf"))
96 94
 
97
-	err := findConfigurationConflicts(config, flags)
98
-	if err == nil {
99
-		t.Fatal("expected error, got nil")
100
-	}
101
-	if !strings.Contains(err.Error(), "authorization-plugins: (from flag: asdf, from file: foobar)") {
102
-		t.Fatalf("expected authorization-plugins conflict, got %v", err)
103
-	}
95
+	assert.Error(t,
96
+		findConfigurationConflicts(config, flags),
97
+		"authorization-plugins: (from flag: asdf, from file: foobar)")
104 98
 }
105 99
 
106 100
 func TestFindConfigurationConflictsWithNamedOptions(t *testing.T) {
107 101
 	config := map[string]interface{}{"hosts": []string{"qwer"}}
108
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
102
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
109 103
 
110 104
 	var hosts []string
111
-	flags.Var(opts.NewNamedListOptsRef("hosts", &hosts, opts.ValidateHost), []string{"H", "-host"}, "Daemon socket(s) to connect to")
112
-	if err := flags.Set("-host", "tcp://127.0.0.1:4444"); err != nil {
113
-		t.Fatal(err)
114
-	}
115
-	if err := flags.Set("H", "unix:///var/run/docker.sock"); err != nil {
116
-		t.Fatal(err)
117
-	}
105
+	flags.VarP(opts.NewNamedListOptsRef("hosts", &hosts, opts.ValidateHost), "host", "H", "Daemon socket(s) to connect to")
106
+	assert.NilError(t, flags.Set("host", "tcp://127.0.0.1:4444"))
107
+	assert.NilError(t, flags.Set("host", "unix:///var/run/docker.sock"))
118 108
 
119
-	err := findConfigurationConflicts(config, flags)
120
-	if err == nil {
121
-		t.Fatal("expected error, got nil")
122
-	}
123
-	if !strings.Contains(err.Error(), "hosts") {
124
-		t.Fatalf("expected hosts conflict, got %v", err)
125
-	}
109
+	assert.Error(t, findConfigurationConflicts(config, flags), "hosts")
126 110
 }
127 111
 
128 112
 func TestDaemonConfigurationMergeConflicts(t *testing.T) {
... ...
@@ -135,8 +120,8 @@ func TestDaemonConfigurationMergeConflicts(t *testing.T) {
135 135
 	f.Write([]byte(`{"debug": true}`))
136 136
 	f.Close()
137 137
 
138
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
139
-	flags.Bool([]string{"debug"}, false, "")
138
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
139
+	flags.Bool("debug", false, "")
140 140
 	flags.Set("debug", "false")
141 141
 
142 142
 	_, err = MergeDaemonConfigurations(&Config{}, flags, configFile)
... ...
@@ -158,8 +143,8 @@ func TestDaemonConfigurationMergeConflictsWithInnerStructs(t *testing.T) {
158 158
 	f.Write([]byte(`{"tlscacert": "/etc/certificates/ca.pem"}`))
159 159
 	f.Close()
160 160
 
161
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
162
-	flags.String([]string{"tlscacert"}, "", "")
161
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
162
+	flags.String("tlscacert", "", "")
163 163
 	flags.Set("tlscacert", "~/.docker/ca.pem")
164 164
 
165 165
 	_, err = MergeDaemonConfigurations(&Config{}, flags, configFile)
... ...
@@ -173,9 +158,9 @@ func TestDaemonConfigurationMergeConflictsWithInnerStructs(t *testing.T) {
173 173
 
174 174
 func TestFindConfigurationConflictsWithUnknownKeys(t *testing.T) {
175 175
 	config := map[string]interface{}{"tls-verify": "true"}
176
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
176
+	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
177 177
 
178
-	flags.Bool([]string{"-tlsverify"}, false, "")
178
+	flags.Bool("tlsverify", false, "")
179 179
 	err := findConfigurationConflicts(config, flags)
180 180
 	if err == nil {
181 181
 		t.Fatal("expected error, got nil")
... ...
@@ -188,18 +173,15 @@ func TestFindConfigurationConflictsWithUnknownKeys(t *testing.T) {
188 188
 func TestFindConfigurationConflictsWithMergedValues(t *testing.T) {
189 189
 	var hosts []string
190 190
 	config := map[string]interface{}{"hosts": "tcp://127.0.0.1:2345"}
191
-	base := mflag.NewFlagSet("base", mflag.ContinueOnError)
192
-	base.Var(opts.NewNamedListOptsRef("hosts", &hosts, nil), []string{"H", "-host"}, "")
193
-
194
-	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
195
-	mflag.Merge(flags, base)
191
+	flags := pflag.NewFlagSet("base", pflag.ContinueOnError)
192
+	flags.VarP(opts.NewNamedListOptsRef("hosts", &hosts, nil), "host", "H", "")
196 193
 
197 194
 	err := findConfigurationConflicts(config, flags)
198 195
 	if err != nil {
199 196
 		t.Fatal(err)
200 197
 	}
201 198
 
202
-	flags.Set("-host", "unix:///var/run/docker.sock")
199
+	flags.Set("host", "unix:///var/run/docker.sock")
203 200
 	err = findConfigurationConflicts(config, flags)
204 201
 	if err == nil {
205 202
 		t.Fatal("expected error, got nil")
... ...
@@ -3,8 +3,8 @@ package daemon
3 3
 import (
4 4
 	"os"
5 5
 
6
-	flag "github.com/docker/docker/pkg/mflag"
7 6
 	"github.com/docker/engine-api/types"
7
+	"github.com/spf13/pflag"
8 8
 )
9 9
 
10 10
 var (
... ...
@@ -28,18 +28,15 @@ type Config struct {
28 28
 	// for the Windows daemon.)
29 29
 }
30 30
 
31
-// InstallFlags adds command-line options to the top-level flag parser for
32
-// the current process.
33
-// Subsequent calls to `flag.Parse` will populate config with values parsed
34
-// from the command-line.
35
-func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) string) {
31
+// InstallFlags adds flags to the pflag.FlagSet to configure the daemon
32
+func (config *Config) InstallFlags(flags *pflag.FlagSet) {
36 33
 	// First handle install flags which are consistent cross-platform
37
-	config.InstallCommonFlags(cmd, usageFn)
34
+	config.InstallCommonFlags(flags)
38 35
 
39 36
 	// Then platform-specific install flags.
40
-	cmd.StringVar(&config.bridgeConfig.FixedCIDR, []string{"-fixed-cidr"}, "", usageFn("IPv4 subnet for fixed IPs"))
41
-	cmd.StringVar(&config.bridgeConfig.Iface, []string{"b", "-bridge"}, "", "Attach containers to a virtual switch")
42
-	cmd.StringVar(&config.SocketGroup, []string{"G", "-group"}, "", usageFn("Users or groups that can access the named pipe"))
37
+	flags.StringVar(&config.bridgeConfig.FixedCIDR, "fixed-cidr", "", "IPv4 subnet for fixed IPs")
38
+	flags.StringVarP(&config.bridgeConfig.Iface, "bridge", "b", "", "Attach containers to a virtual switch")
39
+	flags.StringVarP(&config.SocketGroup, "group", "G", "", "Users or groups that can access the named pipe")
43 40
 }
44 41
 
45 42
 // GetRuntime returns the runtime path and arguments for a given