Browse code

Convert dockerd to use cobra and pflag

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

Daniel Nephin authored on 2016/06/22 05:42:47
Showing 15 changed files
... ...
@@ -1,11 +1,13 @@
1 1
 package flags
2 2
 
3
-import flag "github.com/docker/docker/pkg/mflag"
3
+import (
4
+	"github.com/spf13/pflag"
5
+)
4 6
 
5 7
 // ClientFlags represents flags for the docker client.
6 8
 type ClientFlags struct {
7
-	FlagSet   *flag.FlagSet
8
-	Common    *CommonFlags
9
+	FlagSet   *pflag.FlagSet
10
+	Common    *CommonOptions
9 11
 	PostParse func()
10 12
 
11 13
 	ConfigDir string
... ...
@@ -8,8 +8,8 @@ import (
8 8
 	"github.com/Sirupsen/logrus"
9 9
 	"github.com/docker/docker/cliconfig"
10 10
 	"github.com/docker/docker/opts"
11
-	flag "github.com/docker/docker/pkg/mflag"
12 11
 	"github.com/docker/go-connections/tlsconfig"
12
+	"github.com/spf13/pflag"
13 13
 )
14 14
 
15 15
 const (
... ...
@@ -21,8 +21,8 @@ const (
21 21
 	DefaultKeyFile = "key.pem"
22 22
 	// DefaultCertFile is the default filename for the cert pem file
23 23
 	DefaultCertFile = "cert.pem"
24
-	// TLSVerifyKey is the default flag name for the tls verification option
25
-	TLSVerifyKey = "tlsverify"
24
+	// FlagTLSVerify is the flag name for the tls verification option
25
+	FlagTLSVerify = "tlsverify"
26 26
 )
27 27
 
28 28
 var (
... ...
@@ -30,11 +30,8 @@ var (
30 30
 	dockerTLSVerify = os.Getenv("DOCKER_TLS_VERIFY") != ""
31 31
 )
32 32
 
33
-// CommonFlags are flags common to both the client and the daemon.
34
-type CommonFlags struct {
35
-	FlagSet   *flag.FlagSet
36
-	PostParse func()
37
-
33
+// CommonOptions are options common to both the client and the daemon.
34
+type CommonOptions struct {
38 35
 	Debug      bool
39 36
 	Hosts      []string
40 37
 	LogLevel   string
... ...
@@ -44,62 +41,60 @@ type CommonFlags struct {
44 44
 	TrustKey   string
45 45
 }
46 46
 
47
-// InitCommonFlags initializes flags common to both client and daemon
48
-func InitCommonFlags() *CommonFlags {
49
-	var commonFlags = &CommonFlags{FlagSet: new(flag.FlagSet)}
47
+// NewCommonOptions returns a new CommonOptions
48
+func NewCommonOptions() *CommonOptions {
49
+	return &CommonOptions{
50
+		TLSOptions: &tlsconfig.Options{},
51
+	}
52
+}
50 53
 
54
+// InstallFlags adds flags for the common options on the FlagSet
55
+func (commonOpts *CommonOptions) InstallFlags(flags *pflag.FlagSet) {
51 56
 	if dockerCertPath == "" {
52 57
 		dockerCertPath = cliconfig.ConfigDir()
53 58
 	}
54 59
 
55
-	commonFlags.PostParse = func() { postParseCommon(commonFlags) }
56
-
57
-	cmd := commonFlags.FlagSet
60
+	flags.BoolVarP(&commonOpts.Debug, "debug", "D", false, "Enable debug mode")
61
+	flags.StringVarP(&commonOpts.LogLevel, "log-level", "l", "info", "Set the logging level")
62
+	flags.BoolVar(&commonOpts.TLS, "tls", false, "Use TLS; implied by --tlsverify")
63
+	flags.BoolVar(&commonOpts.TLSVerify, FlagTLSVerify, dockerTLSVerify, "Use TLS and verify the remote")
58 64
 
59
-	cmd.BoolVar(&commonFlags.Debug, []string{"D", "-debug"}, false, "Enable debug mode")
60
-	cmd.StringVar(&commonFlags.LogLevel, []string{"l", "-log-level"}, "info", "Set the logging level")
61
-	cmd.BoolVar(&commonFlags.TLS, []string{"-tls"}, false, "Use TLS; implied by --tlsverify")
62
-	cmd.BoolVar(&commonFlags.TLSVerify, []string{"-tlsverify"}, dockerTLSVerify, "Use TLS and verify the remote")
65
+	// TODO use flag flags.String("identity"}, "i", "", "Path to libtrust key file")
63 66
 
64
-	// TODO use flag flag.String([]string{"i", "-identity"}, "", "Path to libtrust key file")
67
+	tlsOptions := commonOpts.TLSOptions
68
+	flags.StringVar(&tlsOptions.CAFile, "tlscacert", filepath.Join(dockerCertPath, DefaultCaFile), "Trust certs signed only by this CA")
69
+	flags.StringVar(&tlsOptions.CertFile, "tlscert", filepath.Join(dockerCertPath, DefaultCertFile), "Path to TLS certificate file")
70
+	flags.StringVar(&tlsOptions.KeyFile, "tlskey", filepath.Join(dockerCertPath, DefaultKeyFile), "Path to TLS key file")
65 71
 
66
-	var tlsOptions tlsconfig.Options
67
-	commonFlags.TLSOptions = &tlsOptions
68
-	cmd.StringVar(&tlsOptions.CAFile, []string{"-tlscacert"}, filepath.Join(dockerCertPath, DefaultCaFile), "Trust certs signed only by this CA")
69
-	cmd.StringVar(&tlsOptions.CertFile, []string{"-tlscert"}, filepath.Join(dockerCertPath, DefaultCertFile), "Path to TLS certificate file")
70
-	cmd.StringVar(&tlsOptions.KeyFile, []string{"-tlskey"}, filepath.Join(dockerCertPath, DefaultKeyFile), "Path to TLS key file")
71
-
72
-	cmd.Var(opts.NewNamedListOptsRef("hosts", &commonFlags.Hosts, opts.ValidateHost), []string{"H", "-host"}, "Daemon socket(s) to connect to")
73
-	return commonFlags
72
+	hostOpt := opts.NewNamedListOptsRef("hosts", &commonOpts.Hosts, opts.ValidateHost)
73
+	flags.VarP(hostOpt, "-host", "H", "Daemon socket(s) to connect to")
74 74
 }
75 75
 
76
-func postParseCommon(commonFlags *CommonFlags) {
77
-	cmd := commonFlags.FlagSet
78
-
79
-	SetDaemonLogLevel(commonFlags.LogLevel)
80
-
76
+// SetDefaultOptions sets default values for options after flag parsing is
77
+// complete
78
+func (commonOpts *CommonOptions) SetDefaultOptions(flags *pflag.FlagSet) {
81 79
 	// Regardless of whether the user sets it to true or false, if they
82 80
 	// specify --tlsverify at all then we need to turn on tls
83 81
 	// TLSVerify can be true even if not set due to DOCKER_TLS_VERIFY env var, so we need
84 82
 	// to check that here as well
85
-	if cmd.IsSet("-"+TLSVerifyKey) || commonFlags.TLSVerify {
86
-		commonFlags.TLS = true
83
+	if flags.Changed(FlagTLSVerify) || commonOpts.TLSVerify {
84
+		commonOpts.TLS = true
87 85
 	}
88 86
 
89
-	if !commonFlags.TLS {
90
-		commonFlags.TLSOptions = nil
87
+	if !commonOpts.TLS {
88
+		commonOpts.TLSOptions = nil
91 89
 	} else {
92
-		tlsOptions := commonFlags.TLSOptions
93
-		tlsOptions.InsecureSkipVerify = !commonFlags.TLSVerify
90
+		tlsOptions := commonOpts.TLSOptions
91
+		tlsOptions.InsecureSkipVerify = !commonOpts.TLSVerify
94 92
 
95 93
 		// Reset CertFile and KeyFile to empty string if the user did not specify
96 94
 		// the respective flags and the respective default files were not found.
97
-		if !cmd.IsSet("-tlscert") {
95
+		if !flags.Changed("tlscert") {
98 96
 			if _, err := os.Stat(tlsOptions.CertFile); os.IsNotExist(err) {
99 97
 				tlsOptions.CertFile = ""
100 98
 			}
101 99
 		}
102
-		if !cmd.IsSet("-tlskey") {
100
+		if !flags.Changed("tlskey") {
103 101
 			if _, err := os.Stat(tlsOptions.KeyFile); os.IsNotExist(err) {
104 102
 				tlsOptions.KeyFile = ""
105 103
 			}
... ...
@@ -101,6 +101,7 @@ func initClientFlags(commonFlags *cliflags.CommonFlags) *cliflags.ClientFlags {
101 101
 
102 102
 	clientFlags.PostParse = func() {
103 103
 		clientFlags.Common.PostParse()
104
+		cliflags.SetDaemonLogLevel(commonOpts.LogLevel)
104 105
 
105 106
 		if clientFlags.ConfigDir != "" {
106 107
 			cliconfig.SetConfigDir(clientFlags.ConfigDir)
... ...
@@ -6,7 +6,6 @@ import (
6 6
 	"io"
7 7
 	"os"
8 8
 	"path/filepath"
9
-	"runtime"
10 9
 	"strings"
11 10
 	"time"
12 11
 
... ...
@@ -31,11 +30,10 @@ import (
31 31
 	"github.com/docker/docker/daemon/logger"
32 32
 	"github.com/docker/docker/dockerversion"
33 33
 	"github.com/docker/docker/libcontainerd"
34
-	"github.com/docker/docker/opts"
34
+	dopts "github.com/docker/docker/opts"
35 35
 	"github.com/docker/docker/pkg/authorization"
36 36
 	"github.com/docker/docker/pkg/jsonlog"
37 37
 	"github.com/docker/docker/pkg/listeners"
38
-	flag "github.com/docker/docker/pkg/mflag"
39 38
 	"github.com/docker/docker/pkg/pidfile"
40 39
 	"github.com/docker/docker/pkg/signal"
41 40
 	"github.com/docker/docker/pkg/system"
... ...
@@ -43,46 +41,27 @@ import (
43 43
 	"github.com/docker/docker/runconfig"
44 44
 	"github.com/docker/docker/utils"
45 45
 	"github.com/docker/go-connections/tlsconfig"
46
+	"github.com/spf13/pflag"
46 47
 )
47 48
 
48 49
 const (
49
-	daemonConfigFileFlag = "-config-file"
50
+	flagDaemonConfigFile = "config-file"
50 51
 )
51 52
 
52 53
 // DaemonCli represents the daemon CLI.
53 54
 type DaemonCli struct {
54 55
 	*daemon.Config
55
-	commonFlags *cliflags.CommonFlags
56
-	configFile  *string
56
+	configFile *string
57
+	flags      *pflag.FlagSet
57 58
 
58 59
 	api             *apiserver.Server
59 60
 	d               *daemon.Daemon
60 61
 	authzMiddleware *authorization.Middleware // authzMiddleware enables to dynamically reload the authorization plugins
61 62
 }
62 63
 
63
-func presentInHelp(usage string) string { return usage }
64
-func absentFromHelp(string) string      { return "" }
65
-
66
-// NewDaemonCli returns a pre-configured daemon CLI
64
+// NewDaemonCli returns a daemon CLI
67 65
 func NewDaemonCli() *DaemonCli {
68
-	// TODO(tiborvass): remove InstallFlags?
69
-	daemonConfig := new(daemon.Config)
70
-	daemonConfig.LogConfig.Config = make(map[string]string)
71
-	daemonConfig.ClusterOpts = make(map[string]string)
72
-
73
-	daemonConfig.InstallFlags(flag.CommandLine, presentInHelp)
74
-	configFile := flag.CommandLine.String([]string{daemonConfigFileFlag}, defaultDaemonConfigFile, "Daemon configuration file")
75
-	flag.CommandLine.Require(flag.Exact, 0)
76
-
77
-	if runtime.GOOS != "linux" {
78
-		daemonConfig.V2Only = true
79
-	}
80
-
81
-	return &DaemonCli{
82
-		Config:      daemonConfig,
83
-		commonFlags: cliflags.InitCommonFlags(),
84
-		configFile:  configFile,
85
-	}
66
+	return &DaemonCli{}
86 67
 }
87 68
 
88 69
 func migrateKey() (err error) {
... ...
@@ -126,24 +105,25 @@ func migrateKey() (err error) {
126 126
 	return nil
127 127
 }
128 128
 
129
-func (cli *DaemonCli) start() (err error) {
129
+func (cli *DaemonCli) start(opts daemonOptions) (err error) {
130 130
 	stopc := make(chan bool)
131 131
 	defer close(stopc)
132 132
 
133 133
 	// warn from uuid package when running the daemon
134 134
 	uuid.Loggerf = logrus.Warnf
135 135
 
136
-	flags := flag.CommandLine
137
-	cli.commonFlags.PostParse()
136
+	opts.common.SetDefaultOptions(opts.flags)
138 137
 
139
-	if cli.commonFlags.TrustKey == "" {
140
-		cli.commonFlags.TrustKey = filepath.Join(getDaemonConfDir(), cliflags.DefaultTrustKeyFile)
138
+	if opts.common.TrustKey == "" {
139
+		opts.common.TrustKey = filepath.Join(
140
+			getDaemonConfDir(),
141
+			cliflags.DefaultTrustKeyFile)
141 142
 	}
142
-	cliConfig, err := loadDaemonCliConfig(cli.Config, flags, cli.commonFlags, *cli.configFile)
143
-	if err != nil {
143
+	if cli.Config, err = loadDaemonCliConfig(opts); err != nil {
144 144
 		return err
145 145
 	}
146
-	cli.Config = cliConfig
146
+	cli.configFile = &opts.configFile
147
+	cli.flags = opts.flags
147 148
 
148 149
 	if cli.Config.Debug {
149 150
 		utils.EnableDebug()
... ...
@@ -215,7 +195,7 @@ func (cli *DaemonCli) start() (err error) {
215 215
 
216 216
 	for i := 0; i < len(cli.Config.Hosts); i++ {
217 217
 		var err error
218
-		if cli.Config.Hosts[i], err = opts.ParseHost(cli.Config.TLS, cli.Config.Hosts[i]); err != nil {
218
+		if cli.Config.Hosts[i], err = dopts.ParseHost(cli.Config.TLS, cli.Config.Hosts[i]); err != nil {
219 219
 			return fmt.Errorf("error parsing -H %s : %v", cli.Config.Hosts[i], err)
220 220
 		}
221 221
 
... ...
@@ -250,7 +230,8 @@ func (cli *DaemonCli) start() (err error) {
250 250
 	if err := migrateKey(); err != nil {
251 251
 		return err
252 252
 	}
253
-	cli.TrustKeyPath = cli.commonFlags.TrustKey
253
+	// FIXME: why is this down here instead of with the other TrustKey logic above?
254
+	cli.TrustKeyPath = opts.common.TrustKey
254 255
 
255 256
 	registryService := registry.NewService(cli.Config.ServiceOptions)
256 257
 	containerdRemote, err := libcontainerd.New(cli.getLibcontainerdRoot(), cli.getPlatformRemoteOptions()...)
... ...
@@ -341,7 +322,7 @@ func (cli *DaemonCli) reloadConfig() {
341 341
 		}
342 342
 	}
343 343
 
344
-	if err := daemon.ReloadConfiguration(*cli.configFile, flag.CommandLine, reload); err != nil {
344
+	if err := daemon.ReloadConfiguration(*cli.configFile, cli.flags, reload); err != nil {
345 345
 		logrus.Error(err)
346 346
 	}
347 347
 }
... ...
@@ -367,25 +348,27 @@ func shutdownDaemon(d *daemon.Daemon, timeout time.Duration) {
367 367
 	}
368 368
 }
369 369
 
370
-func loadDaemonCliConfig(config *daemon.Config, flags *flag.FlagSet, commonConfig *cliflags.CommonFlags, configFile string) (*daemon.Config, error) {
371
-	config.Debug = commonConfig.Debug
372
-	config.Hosts = commonConfig.Hosts
373
-	config.LogLevel = commonConfig.LogLevel
374
-	config.TLS = commonConfig.TLS
375
-	config.TLSVerify = commonConfig.TLSVerify
370
+func loadDaemonCliConfig(opts daemonOptions) (*daemon.Config, error) {
371
+	config := opts.daemonConfig
372
+	flags := opts.flags
373
+	config.Debug = opts.common.Debug
374
+	config.Hosts = opts.common.Hosts
375
+	config.LogLevel = opts.common.LogLevel
376
+	config.TLS = opts.common.TLS
377
+	config.TLSVerify = opts.common.TLSVerify
376 378
 	config.CommonTLSOptions = daemon.CommonTLSOptions{}
377 379
 
378
-	if commonConfig.TLSOptions != nil {
379
-		config.CommonTLSOptions.CAFile = commonConfig.TLSOptions.CAFile
380
-		config.CommonTLSOptions.CertFile = commonConfig.TLSOptions.CertFile
381
-		config.CommonTLSOptions.KeyFile = commonConfig.TLSOptions.KeyFile
380
+	if opts.common.TLSOptions != nil {
381
+		config.CommonTLSOptions.CAFile = opts.common.TLSOptions.CAFile
382
+		config.CommonTLSOptions.CertFile = opts.common.TLSOptions.CertFile
383
+		config.CommonTLSOptions.KeyFile = opts.common.TLSOptions.KeyFile
382 384
 	}
383 385
 
384
-	if configFile != "" {
385
-		c, err := daemon.MergeDaemonConfigurations(config, flags, configFile)
386
+	if opts.configFile != "" {
387
+		c, err := daemon.MergeDaemonConfigurations(config, flags, opts.configFile)
386 388
 		if err != nil {
387
-			if flags.IsSet(daemonConfigFileFlag) || !os.IsNotExist(err) {
388
-				return nil, fmt.Errorf("unable to configure the Docker daemon with file %s: %v\n", configFile, err)
389
+			if flags.Changed(flagDaemonConfigFile) || !os.IsNotExist(err) {
390
+				return nil, fmt.Errorf("unable to configure the Docker daemon with file %s: %v\n", opts.configFile, err)
389 391
 			}
390 392
 		}
391 393
 		// the merged configuration can be nil if the config file didn't exist.
... ...
@@ -401,7 +384,7 @@ func loadDaemonCliConfig(config *daemon.Config, flags *flag.FlagSet, commonConfi
401 401
 
402 402
 	// Regardless of whether the user sets it to true or false, if they
403 403
 	// specify TLSVerify at all then we need to turn on TLS
404
-	if config.IsValueSet(cliflags.TLSVerifyKey) {
404
+	if config.IsValueSet(cliflags.FlagTLSVerify) {
405 405
 		config.TLS = true
406 406
 	}
407 407
 
... ...
@@ -2,59 +2,61 @@ package main
2 2
 
3 3
 import (
4 4
 	"fmt"
5
-	"os"
6 5
 
7 6
 	"github.com/Sirupsen/logrus"
7
+	"github.com/docker/docker/cli"
8
+	cliflags "github.com/docker/docker/cli/flags"
9
+	"github.com/docker/docker/daemon"
8 10
 	"github.com/docker/docker/dockerversion"
9
-	flag "github.com/docker/docker/pkg/mflag"
10 11
 	"github.com/docker/docker/pkg/reexec"
11 12
 	"github.com/docker/docker/pkg/term"
12 13
 	"github.com/docker/docker/utils"
14
+	"github.com/spf13/cobra"
15
+	"github.com/spf13/pflag"
13 16
 )
14 17
 
15
-var (
16
-	daemonCli = NewDaemonCli()
17
-	flHelp    = flag.Bool([]string{"h", "-help"}, false, "Print usage")
18
-	flVersion = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit")
19
-)
18
+type daemonOptions struct {
19
+	version      bool
20
+	configFile   string
21
+	daemonConfig *daemon.Config
22
+	common       *cliflags.CommonOptions
23
+	flags        *pflag.FlagSet
24
+}
20 25
 
21
-func main() {
22
-	if reexec.Init() {
23
-		return
26
+func newDaemonCommand() *cobra.Command {
27
+	opts := daemonOptions{
28
+		daemonConfig: daemon.NewConfig(),
29
+		common:       cliflags.NewCommonOptions(),
24 30
 	}
25 31
 
26
-	// Set terminal emulation based on platform as required.
27
-	_, stdout, stderr := term.StdStreams()
28
-
29
-	logrus.SetOutput(stderr)
30
-
31
-	flag.Merge(flag.CommandLine, daemonCli.commonFlags.FlagSet)
32
-
33
-	flag.Usage = func() {
34
-		fmt.Fprint(stdout, "Usage: dockerd [OPTIONS]\n\n")
35
-		fmt.Fprint(stdout, "A self-sufficient runtime for containers.\n\nOptions:\n")
36
-
37
-		flag.CommandLine.SetOutput(stdout)
38
-		flag.PrintDefaults()
39
-	}
40
-	flag.CommandLine.ShortUsage = func() {
41
-		fmt.Fprint(stderr, "\nUsage:\tdockerd [OPTIONS]\n")
32
+	cmd := &cobra.Command{
33
+		Use:           "dockerd [OPTIONS]",
34
+		Short:         "A self-sufficient runtime for containers.",
35
+		SilenceUsage:  true,
36
+		SilenceErrors: true,
37
+		Args:          cli.NoArgs,
38
+		RunE: func(cmd *cobra.Command, args []string) error {
39
+			opts.flags = cmd.Flags()
40
+			return runDaemon(opts)
41
+		},
42 42
 	}
43
+	// TODO: SetUsageTemplate, SetHelpTemplate, SetFlagErrorFunc
43 44
 
44
-	if err := flag.CommandLine.ParseFlags(os.Args[1:], false); err != nil {
45
-		os.Exit(1)
46
-	}
45
+	flags := cmd.Flags()
46
+	flags.BoolP("help", "h", false, "Print usage")
47
+	flags.MarkShorthandDeprecated("help", "please use --help")
48
+	flags.BoolVarP(&opts.version, "version", "v", false, "Print version information and quit")
49
+	flags.StringVar(&opts.configFile, flagDaemonConfigFile, defaultDaemonConfigFile, "Daemon configuration file")
50
+	opts.common.InstallFlags(flags)
51
+	opts.daemonConfig.InstallFlags(flags)
47 52
 
48
-	if *flVersion {
49
-		showVersion()
50
-		return
51
-	}
53
+	return cmd
54
+}
52 55
 
53
-	if *flHelp {
54
-		// if global flag --help is present, regardless of what other options and commands there are,
55
-		// just print the usage.
56
-		flag.Usage()
57
-		return
56
+func runDaemon(opts daemonOptions) error {
57
+	if opts.version {
58
+		showVersion()
59
+		return nil
58 60
 	}
59 61
 
60 62
 	// On Windows, this may be launching as a service or with an option to
... ...
@@ -64,13 +66,13 @@ func main() {
64 64
 		logrus.Fatal(err)
65 65
 	}
66 66
 
67
-	if !stop {
68
-		err = daemonCli.start()
69
-		notifyShutdown(err)
70
-		if err != nil {
71
-			logrus.Fatal(err)
72
-		}
67
+	if stop {
68
+		return nil
73 69
 	}
70
+
71
+	err = NewDaemonCli().start(opts)
72
+	notifyShutdown(err)
73
+	return err
74 74
 }
75 75
 
76 76
 func showVersion() {
... ...
@@ -80,3 +82,19 @@ func showVersion() {
80 80
 		fmt.Printf("Docker version %s, build %s\n", dockerversion.Version, dockerversion.GitCommit)
81 81
 	}
82 82
 }
83
+
84
+func main() {
85
+	if reexec.Init() {
86
+		return
87
+	}
88
+
89
+	// Set terminal emulation based on platform as required.
90
+	_, stdout, stderr := term.StdStreams()
91
+	logrus.SetOutput(stderr)
92
+
93
+	cmd := newDaemonCommand()
94
+	cmd.SetOutput(stdout)
95
+	if err := cmd.Execute(); err != nil {
96
+		logrus.Fatal(err)
97
+	}
98
+}
... ...
@@ -6,15 +6,16 @@ import (
6 6
 	"fmt"
7 7
 	"io"
8 8
 	"io/ioutil"
9
+	"runtime"
9 10
 	"strings"
10 11
 	"sync"
11 12
 
12 13
 	"github.com/Sirupsen/logrus"
13 14
 	"github.com/docker/docker/opts"
14 15
 	"github.com/docker/docker/pkg/discovery"
15
-	flag "github.com/docker/docker/pkg/mflag"
16 16
 	"github.com/docker/docker/registry"
17 17
 	"github.com/imdario/mergo"
18
+	"github.com/spf13/pflag"
18 19
 )
19 20
 
20 21
 const (
... ...
@@ -145,37 +146,35 @@ type CommonConfig struct {
145 145
 	valuesSet  map[string]interface{}
146 146
 }
147 147
 
148
-// InstallCommonFlags adds command-line options to the top-level flag parser for
149
-// the current process.
150
-// Subsequent calls to `flag.Parse` will populate config with values parsed
151
-// from the command-line.
152
-func (config *Config) InstallCommonFlags(cmd *flag.FlagSet, usageFn func(string) string) {
148
+// InstallCommonFlags adds flags to the pflag.FlagSet to configure the daemon
149
+func (config *Config) InstallCommonFlags(flags *pflag.FlagSet) {
153 150
 	var maxConcurrentDownloads, maxConcurrentUploads int
154 151
 
155
-	config.ServiceOptions.InstallCliFlags(cmd, usageFn)
156
-
157
-	cmd.Var(opts.NewNamedListOptsRef("storage-opts", &config.GraphOptions, nil), []string{"-storage-opt"}, usageFn("Storage driver options"))
158
-	cmd.Var(opts.NewNamedListOptsRef("authorization-plugins", &config.AuthorizationPlugins, nil), []string{"-authorization-plugin"}, usageFn("Authorization plugins to load"))
159
-	cmd.Var(opts.NewNamedListOptsRef("exec-opts", &config.ExecOptions, nil), []string{"-exec-opt"}, usageFn("Runtime execution options"))
160
-	cmd.StringVar(&config.Pidfile, []string{"p", "-pidfile"}, defaultPidFile, usageFn("Path to use for daemon PID file"))
161
-	cmd.StringVar(&config.Root, []string{"g", "-graph"}, defaultGraph, usageFn("Root of the Docker runtime"))
162
-	cmd.BoolVar(&config.AutoRestart, []string{"#r", "#-restart"}, true, usageFn("--restart on the daemon has been deprecated in favor of --restart policies on docker run"))
163
-	cmd.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", usageFn("Storage driver to use"))
164
-	cmd.IntVar(&config.Mtu, []string{"#mtu", "-mtu"}, 0, usageFn("Set the containers network MTU"))
165
-	cmd.BoolVar(&config.RawLogs, []string{"-raw-logs"}, false, usageFn("Full timestamps without ANSI coloring"))
152
+	config.ServiceOptions.InstallCliFlags(flags)
153
+
154
+	flags.Var(opts.NewNamedListOptsRef("storage-opts", &config.GraphOptions, nil), "storage-opt", "Storage driver options")
155
+	flags.Var(opts.NewNamedListOptsRef("authorization-plugins", &config.AuthorizationPlugins, nil), "authorization-plugin", "Authorization plugins to load")
156
+	flags.Var(opts.NewNamedListOptsRef("exec-opts", &config.ExecOptions, nil), "exec-opt", "Runtime execution options")
157
+	flags.StringVarP(&config.Pidfile, "pidfile", "p", defaultPidFile, "Path to use for daemon PID file")
158
+	flags.StringVarP(&config.Root, "graph", "g", defaultGraph, "Root of the Docker runtime")
159
+	flags.BoolVarP(&config.AutoRestart, "restart", "r", true, "--restart on the daemon has been deprecated in favor of --restart policies on docker run")
160
+	flags.MarkDeprecated("restart", "Please use a restart policy on ducker run")
161
+	flags.StringVarP(&config.GraphDriver, "storage-driver", "s", "", "Storage driver to use")
162
+	flags.IntVar(&config.Mtu, "mtu", 0, "Set the containers network MTU")
163
+	flags.BoolVar(&config.RawLogs, "raw-logs", false, "Full timestamps without ANSI coloring")
166 164
 	// FIXME: why the inconsistency between "hosts" and "sockets"?
167
-	cmd.Var(opts.NewListOptsRef(&config.DNS, opts.ValidateIPAddress), []string{"#dns", "-dns"}, usageFn("DNS server to use"))
168
-	cmd.Var(opts.NewNamedListOptsRef("dns-opts", &config.DNSOptions, nil), []string{"-dns-opt"}, usageFn("DNS options to use"))
169
-	cmd.Var(opts.NewListOptsRef(&config.DNSSearch, opts.ValidateDNSSearch), []string{"-dns-search"}, usageFn("DNS search domains to use"))
170
-	cmd.Var(opts.NewNamedListOptsRef("labels", &config.Labels, opts.ValidateLabel), []string{"-label"}, usageFn("Set key=value labels to the daemon"))
171
-	cmd.StringVar(&config.LogConfig.Type, []string{"-log-driver"}, "json-file", usageFn("Default driver for container logs"))
172
-	cmd.Var(opts.NewNamedMapOpts("log-opts", config.LogConfig.Config, nil), []string{"-log-opt"}, usageFn("Default log driver options for containers"))
173
-	cmd.StringVar(&config.ClusterAdvertise, []string{"-cluster-advertise"}, "", usageFn("Address or interface name to advertise"))
174
-	cmd.StringVar(&config.ClusterStore, []string{"-cluster-store"}, "", usageFn("URL of the distributed storage backend"))
175
-	cmd.Var(opts.NewNamedMapOpts("cluster-store-opts", config.ClusterOpts, nil), []string{"-cluster-store-opt"}, usageFn("Set cluster store options"))
176
-	cmd.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", usageFn("Set CORS headers in the remote API"))
177
-	cmd.IntVar(&maxConcurrentDownloads, []string{"-max-concurrent-downloads"}, defaultMaxConcurrentDownloads, usageFn("Set the max concurrent downloads for each pull"))
178
-	cmd.IntVar(&maxConcurrentUploads, []string{"-max-concurrent-uploads"}, defaultMaxConcurrentUploads, usageFn("Set the max concurrent uploads for each push"))
165
+	flags.Var(opts.NewListOptsRef(&config.DNS, opts.ValidateIPAddress), "dns", "DNS server to use")
166
+	flags.Var(opts.NewNamedListOptsRef("dns-opts", &config.DNSOptions, nil), "dns-opt", "DNS options to use")
167
+	flags.Var(opts.NewListOptsRef(&config.DNSSearch, opts.ValidateDNSSearch), "dns-search", "DNS search domains to use")
168
+	flags.Var(opts.NewNamedListOptsRef("labels", &config.Labels, opts.ValidateLabel), "label", "Set key=value labels to the daemon")
169
+	flags.StringVar(&config.LogConfig.Type, "log-driver", "json-file", "Default driver for container logs")
170
+	flags.Var(opts.NewNamedMapOpts("log-opts", config.LogConfig.Config, nil), "log-opt", "Default log driver options for containers")
171
+	flags.StringVar(&config.ClusterAdvertise, "cluster-advertise", "", "Address or interface name to advertise")
172
+	flags.StringVar(&config.ClusterStore, "cluster-store", "", "URL of the distributed storage backend")
173
+	flags.Var(opts.NewNamedMapOpts("cluster-store-opts", config.ClusterOpts, nil), "cluster-store-opt", "Set cluster store options")
174
+	flags.StringVar(&config.CorsHeaders, "api-cors-header", "", "Set CORS headers in the remote API")
175
+	flags.IntVar(&maxConcurrentDownloads, "max-concurrent-downloads", defaultMaxConcurrentDownloads, "Set the max concurrent downloads for each pull")
176
+	flags.IntVar(&maxConcurrentUploads, "max-concurrent-uploads", defaultMaxConcurrentUploads, "Set the max concurrent uploads for each push")
179 177
 
180 178
 	cmd.StringVar(&config.SwarmDefaultAdvertiseAddr, []string{"-swarm-default-advertise-addr"}, "", usageFn("Set default address or interface for swarm advertised address"))
181 179
 
... ...
@@ -193,6 +192,18 @@ func (config *Config) IsValueSet(name string) bool {
193 193
 	return ok
194 194
 }
195 195
 
196
+// NewConfig returns a new fully initialized Config struct
197
+func NewConfig() *Config {
198
+	config := Config{}
199
+	config.LogConfig.Config = make(map[string]string)
200
+	config.ClusterOpts = make(map[string]string)
201
+
202
+	if runtime.GOOS != "linux" {
203
+		config.V2Only = true
204
+	}
205
+	return &config
206
+}
207
+
196 208
 func parseClusterAdvertiseSettings(clusterStore, clusterAdvertise string) (string, error) {
197 209
 	if clusterAdvertise == "" {
198 210
 		return "", errDiscoveryDisabled
... ...
@@ -209,7 +220,7 @@ func parseClusterAdvertiseSettings(clusterStore, clusterAdvertise string) (strin
209 209
 }
210 210
 
211 211
 // ReloadConfiguration reads the configuration in the host and reloads the daemon and server.
212
-func ReloadConfiguration(configFile string, flags *flag.FlagSet, reload func(*Config)) error {
212
+func ReloadConfiguration(configFile string, flags *pflag.FlagSet, reload func(*Config)) error {
213 213
 	logrus.Infof("Got signal to reload configuration, reloading from: %s", configFile)
214 214
 	newConfig, err := getConflictFreeConfiguration(configFile, flags)
215 215
 	if err != nil {
... ...
@@ -234,7 +245,7 @@ type boolValue interface {
234 234
 // loads the file configuration in an isolated structure,
235 235
 // and merges the configuration provided from flags on top
236 236
 // if there are no conflicts.
237
-func MergeDaemonConfigurations(flagsConfig *Config, flags *flag.FlagSet, configFile string) (*Config, error) {
237
+func MergeDaemonConfigurations(flagsConfig *Config, flags *pflag.FlagSet, configFile string) (*Config, error) {
238 238
 	fileConfig, err := getConflictFreeConfiguration(configFile, flags)
239 239
 	if err != nil {
240 240
 		return nil, err
... ...
@@ -261,7 +272,7 @@ func MergeDaemonConfigurations(flagsConfig *Config, flags *flag.FlagSet, configF
261 261
 // getConflictFreeConfiguration loads the configuration from a JSON file.
262 262
 // It compares that configuration with the one provided by the flags,
263 263
 // and returns an error if there are conflicts.
264
-func getConflictFreeConfiguration(configFile string, flags *flag.FlagSet) (*Config, error) {
264
+func getConflictFreeConfiguration(configFile string, flags *pflag.FlagSet) (*Config, error) {
265 265
 	b, err := ioutil.ReadFile(configFile)
266 266
 	if err != nil {
267 267
 		return nil, err
... ...
@@ -301,7 +312,7 @@ func getConflictFreeConfiguration(configFile string, flags *flag.FlagSet) (*Conf
301 301
 		}
302 302
 		if len(namedOptions) > 0 {
303 303
 			// set also default for mergeVal flags that are boolValue at the same time.
304
-			flags.VisitAll(func(f *flag.Flag) {
304
+			flags.VisitAll(func(f *pflag.Flag) {
305 305
 				if opt, named := f.Value.(opts.NamedOption); named {
306 306
 					v, set := namedOptions[opt.Name()]
307 307
 					_, boolean := f.Value.(boolValue)
... ...
@@ -339,7 +350,7 @@ func configValuesSet(config map[string]interface{}) map[string]interface{} {
339 339
 // findConfigurationConflicts iterates over the provided flags searching for
340 340
 // duplicated configurations and unknown keys. It returns an error with all the conflicts if
341 341
 // it finds any.
342
-func findConfigurationConflicts(config map[string]interface{}, flags *flag.FlagSet) error {
342
+func findConfigurationConflicts(config map[string]interface{}, flags *pflag.FlagSet) error {
343 343
 	// 1. Search keys from the file that we don't recognize as flags.
344 344
 	unknownKeys := make(map[string]interface{})
345 345
 	for key, value := range config {
... ...
@@ -352,7 +363,7 @@ func findConfigurationConflicts(config map[string]interface{}, flags *flag.FlagS
352 352
 	// 2. Discard values that implement NamedOption.
353 353
 	// Their configuration name differs from their flag name, like `labels` and `label`.
354 354
 	if len(unknownKeys) > 0 {
355
-		unknownNamedConflicts := func(f *flag.Flag) {
355
+		unknownNamedConflicts := func(f *pflag.Flag) {
356 356
 			if namedOption, ok := f.Value.(opts.NamedOption); ok {
357 357
 				if _, valid := unknownKeys[namedOption.Name()]; valid {
358 358
 					delete(unknownKeys, namedOption.Name())
... ...
@@ -376,15 +387,15 @@ func findConfigurationConflicts(config map[string]interface{}, flags *flag.FlagS
376 376
 	}
377 377
 
378 378
 	// 3. Search keys that are present as a flag and as a file option.
379
-	duplicatedConflicts := func(f *flag.Flag) {
379
+	duplicatedConflicts := func(f *pflag.Flag) {
380 380
 		// search option name in the json configuration payload if the value is a named option
381 381
 		if namedOption, ok := f.Value.(opts.NamedOption); ok {
382 382
 			if optsValue, ok := config[namedOption.Name()]; ok {
383 383
 				conflicts = append(conflicts, printConflict(namedOption.Name(), f.Value.String(), optsValue))
384 384
 			}
385 385
 		} else {
386
-			// search flag name in the json configuration payload without trailing dashes
387
-			for _, name := range f.Names {
386
+			// search flag name in the json configuration payload
387
+			for _, name := range []string{f.Name, f.Shorthand} {
388 388
 				name = strings.TrimLeft(name, "-")
389 389
 
390 390
 				if value, ok := config[name]; ok {
... ...
@@ -2,7 +2,9 @@
2 2
 
3 3
 package daemon
4 4
 
5
-import flag "github.com/docker/docker/pkg/mflag"
5
+import (
6
+	"github.com/spf13/pflag"
7
+)
6 8
 
7
-func (config *Config) attachExperimentalFlags(cmd *flag.FlagSet, usageFn func(string) string) {
9
+func (config *Config) attachExperimentalFlags(cmd *pflag.FlagSet) {
8 10
 }
... ...
@@ -1,7 +1,7 @@
1 1
 package daemon
2 2
 
3 3
 import (
4
-	flag "github.com/docker/docker/pkg/mflag"
4
+	"github.com/spf13/pflag"
5 5
 )
6 6
 
7 7
 var (
... ...
@@ -28,14 +28,12 @@ type bridgeConfig struct {
28 28
 
29 29
 // InstallFlags adds command-line options to the top-level flag parser for
30 30
 // the current process.
31
-// Subsequent calls to `flag.Parse` will populate config with values parsed
32
-// from the command-line.
33
-func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) string) {
31
+func (config *Config) InstallFlags(flags *pflag.FlagSet) {
34 32
 	// First handle install flags which are consistent cross-platform
35
-	config.InstallCommonFlags(cmd, usageFn)
33
+	config.InstallCommonFlags(flags)
36 34
 
37 35
 	// Then platform-specific install flags
38
-	config.attachExperimentalFlags(cmd, usageFn)
36
+	config.attachExperimentalFlags(flags)
39 37
 }
40 38
 
41 39
 // GetExecRoot returns the user configured Exec-root
... ...
@@ -2,7 +2,9 @@
2 2
 
3 3
 package daemon
4 4
 
5
-import flag "github.com/docker/docker/pkg/mflag"
5
+import (
6
+	"github.com/spf13/pflag"
7
+)
6 8
 
7
-func (config *Config) attachExperimentalFlags(cmd *flag.FlagSet, usageFn func(string) string) {
9
+func (config *Config) attachExperimentalFlags(cmd *pflag.FlagSet) {
8 10
 }
... ...
@@ -7,10 +7,10 @@ import (
7 7
 	"net"
8 8
 
9 9
 	"github.com/docker/docker/opts"
10
-	flag "github.com/docker/docker/pkg/mflag"
11 10
 	runconfigopts "github.com/docker/docker/runconfig/opts"
12 11
 	"github.com/docker/engine-api/types"
13
-	"github.com/docker/go-units"
12
+	units "github.com/docker/go-units"
13
+	"github.com/spf13/pflag"
14 14
 )
15 15
 
16 16
 var (
... ...
@@ -56,44 +56,42 @@ type bridgeConfig struct {
56 56
 	InterContainerCommunication bool   `json:"icc,omitempty"`
57 57
 }
58 58
 
59
-// InstallFlags adds command-line options to the top-level flag parser for
60
-// the current process.
61
-// Subsequent calls to `flag.Parse` will populate config with values parsed
62
-// from the command-line.
63
-func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) string) {
59
+// InstallFlags adds flags to the pflag.FlagSet to configure the daemon
60
+func (config *Config) InstallFlags(flags *pflag.FlagSet) {
64 61
 	// First handle install flags which are consistent cross-platform
65
-	config.InstallCommonFlags(cmd, usageFn)
62
+	config.InstallCommonFlags(flags)
66 63
 
67
-	// Then platform-specific install flags
68
-	cmd.BoolVar(&config.EnableSelinuxSupport, []string{"-selinux-enabled"}, false, usageFn("Enable selinux support"))
69
-	cmd.StringVar(&config.SocketGroup, []string{"G", "-group"}, "docker", usageFn("Group for the unix socket"))
70 64
 	config.Ulimits = make(map[string]*units.Ulimit)
71
-	cmd.Var(runconfigopts.NewUlimitOpt(&config.Ulimits), []string{"-default-ulimit"}, usageFn("Default ulimits for containers"))
72
-	cmd.BoolVar(&config.bridgeConfig.EnableIPTables, []string{"#iptables", "-iptables"}, true, usageFn("Enable addition of iptables rules"))
73
-	cmd.BoolVar(&config.bridgeConfig.EnableIPForward, []string{"#ip-forward", "-ip-forward"}, true, usageFn("Enable net.ipv4.ip_forward"))
74
-	cmd.BoolVar(&config.bridgeConfig.EnableIPMasq, []string{"-ip-masq"}, true, usageFn("Enable IP masquerading"))
75
-	cmd.BoolVar(&config.bridgeConfig.EnableIPv6, []string{"-ipv6"}, false, usageFn("Enable IPv6 networking"))
76
-	cmd.StringVar(&config.ExecRoot, []string{"-exec-root"}, defaultExecRoot, usageFn("Root directory for execution state files"))
77
-	cmd.StringVar(&config.bridgeConfig.IP, []string{"#bip", "-bip"}, "", usageFn("Specify network bridge IP"))
78
-	cmd.StringVar(&config.bridgeConfig.Iface, []string{"b", "-bridge"}, "", usageFn("Attach containers to a network bridge"))
79
-	cmd.StringVar(&config.bridgeConfig.FixedCIDR, []string{"-fixed-cidr"}, "", usageFn("IPv4 subnet for fixed IPs"))
80
-	cmd.StringVar(&config.bridgeConfig.FixedCIDRv6, []string{"-fixed-cidr-v6"}, "", usageFn("IPv6 subnet for fixed IPs"))
81
-	cmd.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultGatewayIPv4, ""), []string{"-default-gateway"}, usageFn("Container default gateway IPv4 address"))
82
-	cmd.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultGatewayIPv6, ""), []string{"-default-gateway-v6"}, usageFn("Container default gateway IPv6 address"))
83
-	cmd.BoolVar(&config.bridgeConfig.InterContainerCommunication, []string{"#icc", "-icc"}, true, usageFn("Enable inter-container communication"))
84
-	cmd.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultIP, "0.0.0.0"), []string{"#ip", "-ip"}, usageFn("Default IP when binding container ports"))
85
-	cmd.BoolVar(&config.bridgeConfig.EnableUserlandProxy, []string{"-userland-proxy"}, true, usageFn("Use userland proxy for loopback traffic"))
86
-	cmd.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, usageFn("Enable CORS headers in the remote API, this is deprecated by --api-cors-header"))
87
-	cmd.StringVar(&config.CgroupParent, []string{"-cgroup-parent"}, "", usageFn("Set parent cgroup for all containers"))
88
-	cmd.StringVar(&config.RemappedRoot, []string{"-userns-remap"}, "", usageFn("User/Group setting for user namespaces"))
89
-	cmd.StringVar(&config.ContainerdAddr, []string{"-containerd"}, "", usageFn("Path to containerd socket"))
90
-	cmd.BoolVar(&config.LiveRestoreEnabled, []string{"-live-restore"}, false, usageFn("Enable live restore of docker when containers are still running"))
91 65
 	config.Runtimes = make(map[string]types.Runtime)
92
-	cmd.Var(runconfigopts.NewNamedRuntimeOpt("runtimes", &config.Runtimes, stockRuntimeName), []string{"-add-runtime"}, usageFn("Register an additional OCI compatible runtime"))
93
-	cmd.StringVar(&config.DefaultRuntime, []string{"-default-runtime"}, stockRuntimeName, usageFn("Default OCI runtime for containers"))
94
-	cmd.IntVar(&config.OOMScoreAdjust, []string{"-oom-score-adjust"}, -500, usageFn("Set the oom_score_adj for the daemon"))
95 66
 
96
-	config.attachExperimentalFlags(cmd, usageFn)
67
+	// Then platform-specific install flags
68
+	flags.BoolVar(&config.EnableSelinuxSupport, "selinux-enabled", false, "Enable selinux support")
69
+	flags.Var(runconfigopts.NewUlimitOpt(&config.Ulimits), "default-ulimit", "Default ulimits for containers")
70
+	flags.BoolVar(&config.bridgeConfig.EnableIPTables, "iptables", true, "Enable addition of iptables rules")
71
+	flags.BoolVar(&config.bridgeConfig.EnableIPForward, "ip-forward", true, "Enable net.ipv4.ip_forward")
72
+	flags.BoolVar(&config.bridgeConfig.EnableIPMasq, "ip-masq", true, "Enable IP masquerading")
73
+	flags.BoolVar(&config.bridgeConfig.EnableIPv6, "ipv6", false, "Enable IPv6 networking")
74
+	flags.StringVar(&config.ExecRoot, "exec-root", defaultExecRoot, "Root directory for execution state files")
75
+	flags.StringVar(&config.bridgeConfig.IP, "bip", "", "Specify network bridge IP")
76
+	flags.StringVarP(&config.bridgeConfig.Iface, "bridge", "b", "", "Attach containers to a network bridge")
77
+	flags.StringVar(&config.bridgeConfig.FixedCIDR, "fixed-cidr", "", "IPv4 subnet for fixed IPs")
78
+	flags.StringVar(&config.bridgeConfig.FixedCIDRv6, "fixed-cidr-v6", "", "IPv6 subnet for fixed IPs")
79
+	flags.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultGatewayIPv4, ""), "default-gateway", "Container default gateway IPv4 address")
80
+	flags.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultGatewayIPv6, ""), "default-gateway-v6", "Container default gateway IPv6 address")
81
+	flags.BoolVar(&config.bridgeConfig.InterContainerCommunication, "icc", true, "Enable inter-container communication")
82
+	flags.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultIP, "0.0.0.0"), "ip", "Default IP when binding container ports")
83
+	flags.BoolVar(&config.bridgeConfig.EnableUserlandProxy, "userland-proxy", true, "Use userland proxy for loopback traffic")
84
+	flags.BoolVar(&config.EnableCors, "api-enable-cors", false, "Enable CORS headers in the remote API, this is deprecated by --api-cors-header")
85
+	flags.MarkDeprecated("api-enable-cors", "Please use --api-cors-header")
86
+	flags.StringVar(&config.CgroupParent, "cgroup-parent", "", "Set parent cgroup for all containers")
87
+	flags.StringVar(&config.RemappedRoot, "userns-remap", "", "User/Group setting for user namespaces")
88
+	flags.StringVar(&config.ContainerdAddr, "containerd", "", "Path to containerd socket")
89
+	flags.BoolVar(&config.LiveRestoreEnabled, "live-restore", false, "Enable live restore of docker when containers are still running")
90
+	flags.Var(runconfigopts.NewNamedRuntimeOpt("runtimes", &config.Runtimes, stockRuntimeName), "add-runtime", "Register an additional OCI compatible runtime")
91
+	flags.StringVar(&config.DefaultRuntime, "default-runtime", stockRuntimeName, "Default OCI runtime for containers")
92
+	flags.IntVar(&config.OOMScoreAdjust, "oom-score-adjust", -500, "Set the oom_score_adj for the daemon")
93
+
94
+	config.attachExperimentalFlags(flags)
97 95
 }
98 96
 
99 97
 // GetRuntime returns the runtime path and arguments for a given
... ...
@@ -40,3 +40,8 @@ func (o *IPOpt) String() string {
40 40
 	}
41 41
 	return o.IP.String()
42 42
 }
43
+
44
+// Type returns the type of the option
45
+func (o *IPOpt) Type() string {
46
+	return "ip"
47
+}
... ...
@@ -8,9 +8,9 @@ import (
8 8
 	"strings"
9 9
 
10 10
 	"github.com/docker/docker/opts"
11
-	flag "github.com/docker/docker/pkg/mflag"
12 11
 	"github.com/docker/docker/reference"
13 12
 	registrytypes "github.com/docker/engine-api/types/registry"
13
+	"github.com/spf13/pflag"
14 14
 )
15 15
 
16 16
 // ServiceOptions holds command line options.
... ...
@@ -70,14 +70,14 @@ var lookupIP = net.LookupIP
70 70
 
71 71
 // InstallCliFlags adds command-line options to the top-level flag parser for
72 72
 // the current process.
73
-func (options *ServiceOptions) InstallCliFlags(cmd *flag.FlagSet, usageFn func(string) string) {
73
+func (options *ServiceOptions) InstallCliFlags(flags *pflag.FlagSet) {
74 74
 	mirrors := opts.NewNamedListOptsRef("registry-mirrors", &options.Mirrors, ValidateMirror)
75
-	cmd.Var(mirrors, []string{"-registry-mirror"}, usageFn("Preferred Docker registry mirror"))
76
-
77 75
 	insecureRegistries := opts.NewNamedListOptsRef("insecure-registries", &options.InsecureRegistries, ValidateIndexName)
78
-	cmd.Var(insecureRegistries, []string{"-insecure-registry"}, usageFn("Enable insecure registry communication"))
79 76
 
80
-	options.installCliPlatformFlags(cmd, usageFn)
77
+	flags.Var(mirrors, "registry-mirror", "Preferred Docker registry mirror")
78
+	flags.Var(insecureRegistries, "insecure-registry", "Enable insecure registry communication")
79
+
80
+	options.installCliPlatformFlags(flags)
81 81
 }
82 82
 
83 83
 // newServiceConfig returns a new instance of ServiceConfig
... ...
@@ -20,6 +20,6 @@ func cleanPath(s string) string {
20 20
 }
21 21
 
22 22
 // installCliPlatformFlags handles any platform specific flags for the service.
23
-func (options *ServiceOptions) installCliPlatformFlags(cmd *flag.FlagSet, usageFn func(string) string) {
24
-	cmd.BoolVar(&options.V2Only, []string{"-disable-legacy-registry"}, false, usageFn("Disable contacting legacy registries"))
23
+func (options *ServiceOptions) installCliPlatformFlags(flags *flag.FlagSet) string) {
24
+	flags.BoolVar(&options.V2Only, "disable-legacy-registry", false, "Disable contacting legacy registries")
25 25
 }
... ...
@@ -20,6 +20,6 @@ func cleanPath(s string) string {
20 20
 }
21 21
 
22 22
 // installCliPlatformFlags handles any platform specific flags for the service.
23
-func (options *ServiceOptions) installCliPlatformFlags(cmd *flag.FlagSet, usageFn func(string) string) {
23
+func (options *ServiceOptions) installCliPlatformFlags(flags *flag.FlagSet) string) {
24 24
 	// No Windows specific flags.
25 25
 }
... ...
@@ -72,3 +72,8 @@ func (o *RuntimeOpt) GetMap() map[string]types.Runtime {
72 72
 
73 73
 	return map[string]types.Runtime{}
74 74
 }
75
+
76
+// Type returns the type of the option
77
+func (o *RuntimeOpt) Type() string {
78
+	return "runtime"
79
+}