Merge pull request #642 from dnephin/use-upstream-spf13-cobra

Use upstream spf13 cobra
This commit is contained in:
Sebastiaan van Stijn 2017-10-26 10:05:11 +02:00 committed by GitHub
commit e59f3e2925
42 changed files with 1940 additions and 1475 deletions

View File

@ -17,6 +17,7 @@ func SetupRootCommand(rootCmd *cobra.Command) {
cobra.AddTemplateFunc("operationSubCommands", operationSubCommands) cobra.AddTemplateFunc("operationSubCommands", operationSubCommands)
cobra.AddTemplateFunc("managementSubCommands", managementSubCommands) cobra.AddTemplateFunc("managementSubCommands", managementSubCommands)
cobra.AddTemplateFunc("wrappedFlagUsages", wrappedFlagUsages) cobra.AddTemplateFunc("wrappedFlagUsages", wrappedFlagUsages)
cobra.AddTemplateFunc("useLine", UseLine)
rootCmd.SetUsageTemplate(usageTemplate) rootCmd.SetUsageTemplate(usageTemplate)
rootCmd.SetHelpTemplate(helpTemplate) rootCmd.SetHelpTemplate(helpTemplate)
@ -97,9 +98,19 @@ func managementSubCommands(cmd *cobra.Command) []*cobra.Command {
return cmds return cmds
} }
// UseLine returns the usage line for a command. This implementation is different
// from the default Command.UseLine in that it does not add a `[flags]` to the
// of the line.
func UseLine(cmd *cobra.Command) string {
if cmd.HasParent() {
return cmd.Parent().CommandPath() + " " + cmd.Use
}
return cmd.Use
}
var usageTemplate = `Usage: var usageTemplate = `Usage:
{{- if not .HasSubCommands}} {{.UseLine}}{{end}} {{- if not .HasSubCommands}} {{ useLine . }}{{end}}
{{- if .HasSubCommands}} {{ .CommandPath}} COMMAND{{end}} {{- if .HasSubCommands}} {{ .CommandPath}} COMMAND{{end}}
{{ .Short | trim }} {{ .Short | trim }}

View File

@ -9,11 +9,11 @@ import (
// NewCheckpointCommand returns the `checkpoint` subcommand (only in experimental) // NewCheckpointCommand returns the `checkpoint` subcommand (only in experimental)
func NewCheckpointCommand(dockerCli command.Cli) *cobra.Command { func NewCheckpointCommand(dockerCli command.Cli) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "checkpoint", Use: "checkpoint",
Short: "Manage checkpoints", Short: "Manage checkpoints",
Args: cli.NoArgs, Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()), RunE: command.ShowHelp(dockerCli.Err()),
Tags: map[string]string{"experimental": "", "version": "1.25"}, Annotations: map[string]string{"experimental": "", "version": "1.25"},
} }
cmd.AddCommand( cmd.AddCommand(
newCreateCommand(dockerCli), newCreateCommand(dockerCli),

View File

@ -11,11 +11,11 @@ import (
// nolint: interfacer // nolint: interfacer
func NewConfigCommand(dockerCli *command.DockerCli) *cobra.Command { func NewConfigCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "config", Use: "config",
Short: "Manage Docker configs", Short: "Manage Docker configs",
Args: cli.NoArgs, Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()), RunE: command.ShowHelp(dockerCli.Err()),
Tags: map[string]string{"version": "1.30"}, Annotations: map[string]string{"version": "1.30"},
} }
cmd.AddCommand( cmd.AddCommand(
newConfigListCommand(dockerCli), newConfigListCommand(dockerCli),

View File

@ -45,10 +45,7 @@ func TestValidateAttach(t *testing.T) {
// nolint: unparam // nolint: unparam
func parseRun(args []string) (*container.Config, *container.HostConfig, *networktypes.NetworkingConfig, error) { func parseRun(args []string) (*container.Config, *container.HostConfig, *networktypes.NetworkingConfig, error) {
flags := pflag.NewFlagSet("run", pflag.ContinueOnError) flags, copts := setupRunFlags()
flags.SetOutput(ioutil.Discard)
flags.Usage = nil
copts := addFlags(flags)
if err := flags.Parse(args); err != nil { if err := flags.Parse(args); err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
@ -60,6 +57,14 @@ func parseRun(args []string) (*container.Config, *container.HostConfig, *network
return containerConfig.Config, containerConfig.HostConfig, containerConfig.NetworkingConfig, err return containerConfig.Config, containerConfig.HostConfig, containerConfig.NetworkingConfig, err
} }
func setupRunFlags() (*pflag.FlagSet, *containerOptions) {
flags := pflag.NewFlagSet("run", pflag.ContinueOnError)
flags.SetOutput(ioutil.Discard)
flags.Usage = nil
copts := addFlags(flags)
return flags, copts
}
func parseMustError(t *testing.T, args string) { func parseMustError(t *testing.T, args string) {
_, _, _, err := parseRun(strings.Split(args+" ubuntu bash", " ")) _, _, _, err := parseRun(strings.Split(args+" ubuntu bash", " "))
assert.Error(t, err, args) assert.Error(t, err, args)
@ -227,20 +232,21 @@ func TestParseWithMacAddress(t *testing.T) {
} }
} }
func TestParseWithMemory(t *testing.T) { func TestRunFlagsParseWithMemory(t *testing.T) {
invalidMemory := "--memory=invalid" flags, _ := setupRunFlags()
_, _, _, err := parseRun([]string{invalidMemory, "img", "cmd"}) args := []string{"--memory=invalid", "img", "cmd"}
testutil.ErrorContains(t, err, invalidMemory) err := flags.Parse(args)
testutil.ErrorContains(t, err, `invalid argument "invalid" for "-m, --memory" flag`)
_, hostconfig := mustParse(t, "--memory=1G") _, hostconfig := mustParse(t, "--memory=1G")
assert.Equal(t, int64(1073741824), hostconfig.Memory) assert.Equal(t, int64(1073741824), hostconfig.Memory)
} }
func TestParseWithMemorySwap(t *testing.T) { func TestParseWithMemorySwap(t *testing.T) {
invalidMemory := "--memory-swap=invalid" flags, _ := setupRunFlags()
args := []string{"--memory-swap=invalid", "img", "cmd"}
_, _, _, err := parseRun([]string{invalidMemory, "img", "cmd"}) err := flags.Parse(args)
testutil.ErrorContains(t, err, invalidMemory) testutil.ErrorContains(t, err, `invalid argument "invalid" for "--memory-swap" flag`)
_, hostconfig := mustParse(t, "--memory-swap=1G") _, hostconfig := mustParse(t, "--memory-swap=1G")
assert.Equal(t, int64(1073741824), hostconfig.MemorySwap) assert.Equal(t, int64(1073741824), hostconfig.MemorySwap)
@ -365,7 +371,10 @@ func TestParseDevice(t *testing.T) {
func TestParseModes(t *testing.T) { func TestParseModes(t *testing.T) {
// pid ko // pid ko
_, _, _, err := parseRun([]string{"--pid=container:", "img", "cmd"}) flags, copts := setupRunFlags()
args := []string{"--pid=container:", "img", "cmd"}
require.NoError(t, flags.Parse(args))
_, err := parse(flags, copts)
testutil.ErrorContains(t, err, "--pid: invalid PID mode") testutil.ErrorContains(t, err, "--pid: invalid PID mode")
// pid ok // pid ok
@ -385,14 +394,18 @@ func TestParseModes(t *testing.T) {
if !hostconfig.UTSMode.Valid() { if !hostconfig.UTSMode.Valid() {
t.Fatalf("Expected a valid UTSMode, got %v", hostconfig.UTSMode) t.Fatalf("Expected a valid UTSMode, got %v", hostconfig.UTSMode)
} }
}
func TestRunFlagsParseShmSize(t *testing.T) {
// shm-size ko // shm-size ko
expectedErr := `invalid argument "a128m" for --shm-size=a128m: invalid size: 'a128m'` flags, _ := setupRunFlags()
_, _, _, err = parseRun([]string{"--shm-size=a128m", "img", "cmd"}) args := []string{"--shm-size=a128m", "img", "cmd"}
expectedErr := `invalid argument "a128m" for "--shm-size" flag: invalid size: 'a128m'`
err := flags.Parse(args)
testutil.ErrorContains(t, err, expectedErr) testutil.ErrorContains(t, err, expectedErr)
// shm-size ok // shm-size ok
_, hostconfig, _, err = parseRun([]string{"--shm-size=128m", "img", "cmd"}) _, hostconfig, _, err := parseRun([]string{"--shm-size=128m", "img", "cmd"})
require.NoError(t, err) require.NoError(t, err)
if hostconfig.ShmSize != 134217728 { if hostconfig.ShmSize != 134217728 {
t.Fatalf("Expected a valid ShmSize, got %d", hostconfig.ShmSize) t.Fatalf("Expected a valid ShmSize, got %d", hostconfig.ShmSize)

View File

@ -35,7 +35,7 @@ func NewPruneCommand(dockerCli command.Cli) *cobra.Command {
fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed))) fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))
return nil return nil
}, },
Tags: map[string]string{"version": "1.25"}, Annotations: map[string]string{"version": "1.25"},
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

@ -37,7 +37,7 @@ func NewPruneCommand(dockerCli command.Cli) *cobra.Command {
fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed))) fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))
return nil return nil
}, },
Tags: map[string]string{"version": "1.25"}, Annotations: map[string]string{"version": "1.25"},
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

@ -33,7 +33,7 @@ func NewPruneCommand(dockerCli command.Cli) *cobra.Command {
} }
return nil return nil
}, },
Tags: map[string]string{"version": "1.25"}, Annotations: map[string]string{"version": "1.25"},
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

@ -14,11 +14,11 @@ import (
// NewNodeCommand returns a cobra command for `node` subcommands // NewNodeCommand returns a cobra command for `node` subcommands
func NewNodeCommand(dockerCli command.Cli) *cobra.Command { func NewNodeCommand(dockerCli command.Cli) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "node", Use: "node",
Short: "Manage Swarm nodes", Short: "Manage Swarm nodes",
Args: cli.NoArgs, Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()), RunE: command.ShowHelp(dockerCli.Err()),
Tags: map[string]string{"version": "1.24"}, Annotations: map[string]string{"version": "1.24"},
} }
cmd.AddCommand( cmd.AddCommand(
newDemoteCommand(dockerCli), newDemoteCommand(dockerCli),

View File

@ -10,11 +10,11 @@ import (
// nolint: interfacer // nolint: interfacer
func NewPluginCommand(dockerCli *command.DockerCli) *cobra.Command { func NewPluginCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "plugin", Use: "plugin",
Short: "Manage plugins", Short: "Manage plugins",
Args: cli.NoArgs, Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()), RunE: command.ShowHelp(dockerCli.Err()),
Tags: map[string]string{"version": "1.25"}, Annotations: map[string]string{"version": "1.25"},
} }
cmd.AddCommand( cmd.AddCommand(

View File

@ -26,7 +26,7 @@ func newUpgradeCommand(dockerCli *command.DockerCli) *cobra.Command {
} }
return runUpgrade(dockerCli, options) return runUpgrade(dockerCli, options)
}, },
Tags: map[string]string{"version": "1.26"}, Annotations: map[string]string{"version": "1.26"},
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

@ -11,11 +11,11 @@ import (
// nolint: interfacer // nolint: interfacer
func NewSecretCommand(dockerCli *command.DockerCli) *cobra.Command { func NewSecretCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "secret", Use: "secret",
Short: "Manage Docker secrets", Short: "Manage Docker secrets",
Args: cli.NoArgs, Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()), RunE: command.ShowHelp(dockerCli.Err()),
Tags: map[string]string{"version": "1.25"}, Annotations: map[string]string{"version": "1.25"},
} }
cmd.AddCommand( cmd.AddCommand(
newSecretListCommand(dockerCli), newSecretListCommand(dockerCli),

View File

@ -11,11 +11,11 @@ import (
// nolint: interfacer // nolint: interfacer
func NewServiceCommand(dockerCli *command.DockerCli) *cobra.Command { func NewServiceCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "service", Use: "service",
Short: "Manage services", Short: "Manage services",
Args: cli.NoArgs, Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()), RunE: command.ShowHelp(dockerCli.Err()),
Tags: map[string]string{"version": "1.24"}, Annotations: map[string]string{"version": "1.24"},
} }
cmd.AddCommand( cmd.AddCommand(
newCreateCommand(dockerCli), newCreateCommand(dockerCli),

View File

@ -48,7 +48,7 @@ func newLogsCommand(dockerCli *command.DockerCli) *cobra.Command {
opts.target = args[0] opts.target = args[0]
return runLogs(dockerCli, &opts) return runLogs(dockerCli, &opts)
}, },
Tags: map[string]string{"version": "1.29"}, Annotations: map[string]string{"version": "1.29"},
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

@ -21,7 +21,7 @@ func newRollbackCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runRollback(dockerCli, options, args[0]) return runRollback(dockerCli, options, args[0])
}, },
Tags: map[string]string{"version": "1.31"}, Annotations: map[string]string{"version": "1.31"},
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

@ -6,6 +6,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
mounttypes "github.com/docker/docker/api/types/mount" mounttypes "github.com/docker/docker/api/types/mount"
@ -165,7 +166,7 @@ func TestUpdateDNSConfig(t *testing.T) {
// IPv6 // IPv6
flags.Set("dns-add", "2001:db8:abc8::1") flags.Set("dns-add", "2001:db8:abc8::1")
// Invalid dns record // Invalid dns record
assert.EqualError(t, flags.Set("dns-add", "x.y.z.w"), "x.y.z.w is not an ip address") testutil.ErrorContains(t, flags.Set("dns-add", "x.y.z.w"), "x.y.z.w is not an ip address")
// domains with duplicates // domains with duplicates
flags.Set("dns-search-add", "example.com") flags.Set("dns-search-add", "example.com")
@ -173,7 +174,7 @@ func TestUpdateDNSConfig(t *testing.T) {
flags.Set("dns-search-add", "example.org") flags.Set("dns-search-add", "example.org")
flags.Set("dns-search-rm", "example.org") flags.Set("dns-search-rm", "example.org")
// Invalid dns search domain // Invalid dns search domain
assert.EqualError(t, flags.Set("dns-search-add", "example$com"), "example$com is not a valid domain") testutil.ErrorContains(t, flags.Set("dns-search-add", "example$com"), "example$com is not a valid domain")
flags.Set("dns-option-add", "ndots:9") flags.Set("dns-option-add", "ndots:9")
flags.Set("dns-option-rm", "timeout:3") flags.Set("dns-option-rm", "timeout:3")
@ -362,7 +363,7 @@ func TestUpdateHosts(t *testing.T) {
// just hostname should work as well // just hostname should work as well
flags.Set("host-rm", "example.net") flags.Set("host-rm", "example.net")
// bad format error // bad format error
assert.EqualError(t, flags.Set("host-add", "$example.com$"), `bad format for add-host: "$example.com$"`) testutil.ErrorContains(t, flags.Set("host-add", "$example.com$"), `bad format for add-host: "$example.com$"`)
hosts := []string{"1.2.3.4 example.com", "4.3.2.1 example.org", "2001:db8:abc8::1 example.net"} hosts := []string{"1.2.3.4 example.com", "4.3.2.1 example.org", "2001:db8:abc8::1 example.net"}

View File

@ -10,11 +10,11 @@ import (
// nolint: interfacer // nolint: interfacer
func NewStackCommand(dockerCli *command.DockerCli) *cobra.Command { func NewStackCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "stack", Use: "stack",
Short: "Manage Docker stacks", Short: "Manage Docker stacks",
Args: cli.NoArgs, Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()), RunE: command.ShowHelp(dockerCli.Err()),
Tags: map[string]string{"version": "1.25"}, Annotations: map[string]string{"version": "1.25"},
} }
cmd.AddCommand( cmd.AddCommand(
newDeployCommand(dockerCli), newDeployCommand(dockerCli),
@ -31,6 +31,6 @@ func NewTopLevelDeployCommand(dockerCli command.Cli) *cobra.Command {
cmd := newDeployCommand(dockerCli) cmd := newDeployCommand(dockerCli)
// Remove the aliases at the top level // Remove the aliases at the top level
cmd.Aliases = []string{} cmd.Aliases = []string{}
cmd.Tags = map[string]string{"experimental": "", "version": "1.25"} cmd.Annotations = map[string]string{"experimental": "", "version": "1.25"}
return cmd return cmd
} }

View File

@ -36,7 +36,7 @@ func newCACommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runCA(dockerCli, cmd.Flags(), opts) return runCA(dockerCli, cmd.Flags(), opts)
}, },
Tags: map[string]string{"version": "1.30"}, Annotations: map[string]string{"version": "1.30"},
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

@ -11,11 +11,11 @@ import (
// nolint: interfacer // nolint: interfacer
func NewSwarmCommand(dockerCli command.Cli) *cobra.Command { func NewSwarmCommand(dockerCli command.Cli) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "swarm", Use: "swarm",
Short: "Manage Swarm", Short: "Manage Swarm",
Args: cli.NoArgs, Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()), RunE: command.ShowHelp(dockerCli.Err()),
Tags: map[string]string{"version": "1.24"}, Annotations: map[string]string{"version": "1.24"},
} }
cmd.AddCommand( cmd.AddCommand(
newInitCommand(dockerCli), newInitCommand(dockerCli),

View File

@ -8,6 +8,7 @@ Flags:
--cert-expiry duration Validity period for node certificates (ns|us|ms|s|m|h) (default 2160h0m0s) --cert-expiry duration Validity period for node certificates (ns|us|ms|s|m|h) (default 2160h0m0s)
--dispatcher-heartbeat duration Dispatcher heartbeat period (ns|us|ms|s|m|h) (default 5s) --dispatcher-heartbeat duration Dispatcher heartbeat period (ns|us|ms|s|m|h) (default 5s)
--external-ca external-ca Specifications of one or more certificate signing endpoints --external-ca external-ca Specifications of one or more certificate signing endpoints
-h, --help help for update
--max-snapshots uint Number of additional Raft snapshots to retain --max-snapshots uint Number of additional Raft snapshots to retain
--snapshot-interval uint Number of log entries between Raft snapshots (default 10000) --snapshot-interval uint Number of log entries between Raft snapshots (default 10000)
--task-history-limit int Task history retention limit (default 5) --task-history-limit int Task history retention limit (default 5)

View File

@ -26,7 +26,7 @@ func newDiskUsageCommand(dockerCli *command.DockerCli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runDiskUsage(dockerCli, opts) return runDiskUsage(dockerCli, opts)
}, },
Tags: map[string]string{"version": "1.25"}, Annotations: map[string]string{"version": "1.25"},
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

@ -37,7 +37,7 @@ func newPruneCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runPrune(dockerCli, options) return runPrune(dockerCli, options)
}, },
Tags: map[string]string{"version": "1.25"}, Annotations: map[string]string{"version": "1.25"},
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

@ -9,11 +9,11 @@ import (
// NewVolumeCommand returns a cobra command for `volume` subcommands // NewVolumeCommand returns a cobra command for `volume` subcommands
func NewVolumeCommand(dockerCli command.Cli) *cobra.Command { func NewVolumeCommand(dockerCli command.Cli) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "volume COMMAND", Use: "volume COMMAND",
Short: "Manage volumes", Short: "Manage volumes",
Args: cli.NoArgs, Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()), RunE: command.ShowHelp(dockerCli.Err()),
Tags: map[string]string{"version": "1.21"}, Annotations: map[string]string{"version": "1.21"},
} }
cmd.AddCommand( cmd.AddCommand(
newCreateCommand(dockerCli), newCreateCommand(dockerCli),

View File

@ -35,7 +35,7 @@ func NewPruneCommand(dockerCli command.Cli) *cobra.Command {
fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed))) fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))
return nil return nil
}, },
Tags: map[string]string{"version": "1.25"}, Annotations: map[string]string{"version": "1.25"},
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

@ -88,6 +88,7 @@ func setFlagErrorFunc(dockerCli *command.DockerCli, cmd *cobra.Command, flags *p
} }
func setHelpFunc(dockerCli *command.DockerCli, cmd *cobra.Command, flags *pflag.FlagSet, opts *cliflags.ClientOptions) { func setHelpFunc(dockerCli *command.DockerCli, cmd *cobra.Command, flags *pflag.FlagSet, opts *cliflags.ClientOptions) {
defaultHelpFunc := cmd.HelpFunc()
cmd.SetHelpFunc(func(ccmd *cobra.Command, args []string) { cmd.SetHelpFunc(func(ccmd *cobra.Command, args []string) {
initializeDockerCli(dockerCli, flags, opts) initializeDockerCli(dockerCli, flags, opts)
if err := isSupported(ccmd, dockerCli); err != nil { if err := isSupported(ccmd, dockerCli); err != nil {
@ -96,10 +97,7 @@ func setHelpFunc(dockerCli *command.DockerCli, cmd *cobra.Command, flags *pflag.
} }
hideUnsupportedFeatures(ccmd, dockerCli) hideUnsupportedFeatures(ccmd, dockerCli)
defaultHelpFunc(ccmd, args)
if err := ccmd.Help(); err != nil {
ccmd.Println(err)
}
}) })
} }
@ -225,13 +223,13 @@ func hideUnsupportedFeatures(cmd *cobra.Command, details versionDetails) {
for _, subcmd := range cmd.Commands() { for _, subcmd := range cmd.Commands() {
// hide experimental subcommands // hide experimental subcommands
if !hasExperimental { if !hasExperimental {
if _, ok := subcmd.Tags["experimental"]; ok { if _, ok := subcmd.Annotations["experimental"]; ok {
subcmd.Hidden = true subcmd.Hidden = true
} }
} }
// hide subcommands not supported by the server // hide subcommands not supported by the server
if subcmdVersion, ok := subcmd.Tags["version"]; ok && versions.LessThan(clientVersion, subcmdVersion) { if subcmdVersion, ok := subcmd.Annotations["version"]; ok && versions.LessThan(clientVersion, subcmdVersion) {
subcmd.Hidden = true subcmd.Hidden = true
} }
} }
@ -244,10 +242,10 @@ func isSupported(cmd *cobra.Command, details versionDetails) error {
// Check recursively so that, e.g., `docker stack ls` returns the same output as `docker stack` // Check recursively so that, e.g., `docker stack ls` returns the same output as `docker stack`
for curr := cmd; curr != nil; curr = curr.Parent() { for curr := cmd; curr != nil; curr = curr.Parent() {
if cmdVersion, ok := curr.Tags["version"]; ok && versions.LessThan(clientVersion, cmdVersion) { if cmdVersion, ok := curr.Annotations["version"]; ok && versions.LessThan(clientVersion, cmdVersion) {
return fmt.Errorf("%s requires API version %s, but the Docker daemon API version is %s", cmd.CommandPath(), cmdVersion, clientVersion) return fmt.Errorf("%s requires API version %s, but the Docker daemon API version is %s", cmd.CommandPath(), cmdVersion, clientVersion)
} }
if _, ok := curr.Tags["experimental"]; ok && !hasExperimental { if _, ok := curr.Annotations["experimental"]; ok && !hasExperimental {
return fmt.Errorf("%s is only supported on a Docker daemon with experimental features enabled", cmd.CommandPath()) return fmt.Errorf("%s is only supported on a Docker daemon with experimental features enabled", cmd.CommandPath())
} }
} }
@ -300,7 +298,7 @@ func isOSTypeSupported(f *pflag.Flag, osType string) bool {
// hasTags return true if any of the command's parents has tags // hasTags return true if any of the command's parents has tags
func hasTags(cmd *cobra.Command) bool { func hasTags(cmd *cobra.Command) bool {
for curr := cmd; curr != nil; curr = curr.Parent() { for curr := cmd; curr != nil; curr = curr.Parent() {
if len(curr.Tags) > 0 { if len(curr.Annotations) > 0 {
return true return true
} }
} }

View File

@ -8,6 +8,7 @@ import (
"sort" "sort"
"strings" "strings"
"github.com/docker/cli/cli"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
@ -53,7 +54,7 @@ func GenYamlTree(cmd *cobra.Command, dir string) error {
// GenYamlTreeCustom creates yaml structured ref files // GenYamlTreeCustom creates yaml structured ref files
func GenYamlTreeCustom(cmd *cobra.Command, dir string, filePrepender func(string) string) error { func GenYamlTreeCustom(cmd *cobra.Command, dir string, filePrepender func(string) string) error {
for _, c := range cmd.Commands() { for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() || c.IsHelpCommand() { if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
continue continue
} }
if err := GenYamlTreeCustom(c, dir, filePrepender); err != nil { if err := GenYamlTreeCustom(c, dir, filePrepender); err != nil {
@ -92,7 +93,7 @@ func GenYamlCustom(cmd *cobra.Command, w io.Writer) error {
} }
if cmd.Runnable() { if cmd.Runnable() {
cliDoc.Usage = cmd.UseLine() cliDoc.Usage = cli.UseLine(cmd)
} }
if len(cmd.Example) > 0 { if len(cmd.Example) > 0 {
@ -103,10 +104,10 @@ func GenYamlCustom(cmd *cobra.Command, w io.Writer) error {
} }
// Check recursively so that, e.g., `docker stack ls` returns the same output as `docker stack` // Check recursively so that, e.g., `docker stack ls` returns the same output as `docker stack`
for curr := cmd; curr != nil; curr = curr.Parent() { for curr := cmd; curr != nil; curr = curr.Parent() {
if v, ok := curr.Tags["version"]; ok && cliDoc.MinAPIVersion == "" { if v, ok := curr.Annotations["version"]; ok && cliDoc.MinAPIVersion == "" {
cliDoc.MinAPIVersion = v cliDoc.MinAPIVersion = v
} }
if _, ok := curr.Tags["experimental"]; ok && !cliDoc.Experimental { if _, ok := curr.Annotations["experimental"]; ok && !cliDoc.Experimental {
cliDoc.Experimental = true cliDoc.Experimental = true
} }
} }
@ -137,7 +138,7 @@ func GenYamlCustom(cmd *cobra.Command, w io.Writer) error {
sort.Sort(byName(children)) sort.Sort(byName(children))
for _, child := range children { for _, child := range children {
if !child.IsAvailableCommand() || child.IsHelpCommand() { if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() {
continue continue
} }
currentChild := cliDoc.Name + " " + child.Name() currentChild := cliDoc.Name + " " + child.Name()
@ -207,7 +208,7 @@ func hasSeeAlso(cmd *cobra.Command) bool {
return true return true
} }
for _, c := range cmd.Commands() { for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() || c.IsHelpCommand() { if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
continue continue
} }
return true return true

View File

@ -37,8 +37,8 @@ github.com/pmezard/go-difflib v1.0.0
github.com/russross/blackfriday 1d6b8e9301e720b08a8938b8c25c018285885438 github.com/russross/blackfriday 1d6b8e9301e720b08a8938b8c25c018285885438
github.com/shurcooL/sanitized_anchor_name 10ef21a441db47d8b13ebcc5fd2310f636973c77 github.com/shurcooL/sanitized_anchor_name 10ef21a441db47d8b13ebcc5fd2310f636973c77
github.com/sirupsen/logrus v1.0.3 github.com/sirupsen/logrus v1.0.3
github.com/spf13/cobra v1.5.1 https://github.com/dnephin/cobra.git github.com/spf13/cobra 7b2c5ac9fc04fc5efafb60700713d4fa609b777b
github.com/spf13/pflag 9ff6c6923cfffbcd502984b8e0c80539a94968b7 github.com/spf13/pflag 97afa5e7ca8a08a383cb259e06636b5e2cc7897f
github.com/stretchr/testify 4d4bfba8f1d1027c4fdbe371823030df51419987 github.com/stretchr/testify 4d4bfba8f1d1027c4fdbe371823030df51419987
github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2 github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2
github.com/xeipuuv/gojsonpointer e0fe6f68307607d540ed8eac07a342c33fa1b54a github.com/xeipuuv/gojsonpointer e0fe6f68307607d540ed8eac07a342c33fa1b54a

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
package cobra package cobra
import ( import (
"bytes"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -10,19 +11,17 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
// Annotations for Bash completion.
const ( const (
BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extentions" BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extensions"
BashCompCustom = "cobra_annotation_bash_completion_custom" BashCompCustom = "cobra_annotation_bash_completion_custom"
BashCompOneRequiredFlag = "cobra_annotation_bash_completion_one_required_flag" BashCompOneRequiredFlag = "cobra_annotation_bash_completion_one_required_flag"
BashCompSubdirsInDir = "cobra_annotation_bash_completion_subdirs_in_dir" BashCompSubdirsInDir = "cobra_annotation_bash_completion_subdirs_in_dir"
) )
func preamble(out io.Writer, name string) error { func writePreamble(buf *bytes.Buffer, name string) {
_, err := fmt.Fprintf(out, "# bash completion for %-36s -*- shell-script -*-\n", name) buf.WriteString(fmt.Sprintf("# bash completion for %-36s -*- shell-script -*-\n", name))
if err != nil { buf.WriteString(`
return err
}
_, err = fmt.Fprint(out, `
__debug() __debug()
{ {
if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then
@ -87,13 +86,13 @@ __handle_reply()
local index flag local index flag
flag="${cur%%=*}" flag="${cur%%=*}"
__index_of_word "${flag}" "${flags_with_completion[@]}" __index_of_word "${flag}" "${flags_with_completion[@]}"
COMPREPLY=()
if [[ ${index} -ge 0 ]]; then if [[ ${index} -ge 0 ]]; then
COMPREPLY=()
PREFIX="" PREFIX=""
cur="${cur#*=}" cur="${cur#*=}"
${flags_completion[${index}]} ${flags_completion[${index}]}
if [ -n "${ZSH_VERSION}" ]; then if [ -n "${ZSH_VERSION}" ]; then
# zfs completion needs --flag= prefix # zsh completion needs --flag= prefix
eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )" eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )"
fi fi
fi fi
@ -133,7 +132,10 @@ __handle_reply()
declare -F __custom_func >/dev/null && __custom_func declare -F __custom_func >/dev/null && __custom_func
fi fi
__ltrim_colon_completions "$cur" # available in bash-completion >= 2, not always present on macOS
if declare -F __ltrim_colon_completions >/dev/null; then
__ltrim_colon_completions "$cur"
fi
} }
# The arguments should be in the form "ext1|ext2|extn" # The arguments should be in the form "ext1|ext2|extn"
@ -224,7 +226,7 @@ __handle_command()
fi fi
c=$((c+1)) c=$((c+1))
__debug "${FUNCNAME[0]}: looking for ${next_command}" __debug "${FUNCNAME[0]}: looking for ${next_command}"
declare -F $next_command >/dev/null && $next_command declare -F "$next_command" >/dev/null && $next_command
} }
__handle_word() __handle_word()
@ -247,16 +249,12 @@ __handle_word()
} }
`) `)
return err
} }
func postscript(w io.Writer, name string) error { func writePostscript(buf *bytes.Buffer, name string) {
name = strings.Replace(name, ":", "__", -1) name = strings.Replace(name, ":", "__", -1)
_, err := fmt.Fprintf(w, "__start_%s()\n", name) buf.WriteString(fmt.Sprintf("__start_%s()\n", name))
if err != nil { buf.WriteString(fmt.Sprintf(`{
return err
}
_, err = fmt.Fprintf(w, `{
local cur prev words cword local cur prev words cword
declare -A flaghash 2>/dev/null || : declare -A flaghash 2>/dev/null || :
if declare -F _init_completion >/dev/null 2>&1; then if declare -F _init_completion >/dev/null 2>&1; then
@ -280,318 +278,227 @@ func postscript(w io.Writer, name string) error {
__handle_word __handle_word
} }
`, name) `, name))
if err != nil { buf.WriteString(fmt.Sprintf(`if [[ $(type -t compopt) = "builtin" ]]; then
return err
}
_, err = fmt.Fprintf(w, `if [[ $(type -t compopt) = "builtin" ]]; then
complete -o default -F __start_%s %s complete -o default -F __start_%s %s
else else
complete -o default -o nospace -F __start_%s %s complete -o default -o nospace -F __start_%s %s
fi fi
`, name, name, name, name) `, name, name, name, name))
if err != nil { buf.WriteString("# ex: ts=4 sw=4 et filetype=sh\n")
return err
}
_, err = fmt.Fprintf(w, "# ex: ts=4 sw=4 et filetype=sh\n")
return err
} }
func writeCommands(cmd *Command, w io.Writer) error { func writeCommands(buf *bytes.Buffer, cmd *Command) {
if _, err := fmt.Fprintf(w, " commands=()\n"); err != nil { buf.WriteString(" commands=()\n")
return err
}
for _, c := range cmd.Commands() { for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() || c == cmd.helpCommand { if !c.IsAvailableCommand() || c == cmd.helpCommand {
continue continue
} }
if _, err := fmt.Fprintf(w, " commands+=(%q)\n", c.Name()); err != nil { buf.WriteString(fmt.Sprintf(" commands+=(%q)\n", c.Name()))
return err
}
} }
_, err := fmt.Fprintf(w, "\n") buf.WriteString("\n")
return err
} }
func writeFlagHandler(name string, annotations map[string][]string, w io.Writer) error { func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]string) {
for key, value := range annotations { for key, value := range annotations {
switch key { switch key {
case BashCompFilenameExt: case BashCompFilenameExt:
_, err := fmt.Fprintf(w, " flags_with_completion+=(%q)\n", name) buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name))
if err != nil {
return err
}
var ext string
if len(value) > 0 { if len(value) > 0 {
ext := "__handle_filename_extension_flag " + strings.Join(value, "|") ext = "__handle_filename_extension_flag " + strings.Join(value, "|")
_, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext)
} else { } else {
ext := "_filedir" ext = "_filedir"
_, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext)
}
if err != nil {
return err
} }
buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", ext))
case BashCompCustom: case BashCompCustom:
_, err := fmt.Fprintf(w, " flags_with_completion+=(%q)\n", name) buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name))
if err != nil {
return err
}
if len(value) > 0 { if len(value) > 0 {
handlers := strings.Join(value, "; ") handlers := strings.Join(value, "; ")
_, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", handlers) buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", handlers))
} else { } else {
_, err = fmt.Fprintf(w, " flags_completion+=(:)\n") buf.WriteString(" flags_completion+=(:)\n")
}
if err != nil {
return err
} }
case BashCompSubdirsInDir: case BashCompSubdirsInDir:
_, err := fmt.Fprintf(w, " flags_with_completion+=(%q)\n", name) buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name))
var ext string
if len(value) == 1 { if len(value) == 1 {
ext := "__handle_subdirs_in_dir_flag " + value[0] ext = "__handle_subdirs_in_dir_flag " + value[0]
_, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext)
} else { } else {
ext := "_filedir -d" ext = "_filedir -d"
_, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext)
}
if err != nil {
return err
} }
buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", ext))
} }
} }
return nil
} }
func writeShortFlag(flag *pflag.Flag, w io.Writer) error { func writeShortFlag(buf *bytes.Buffer, flag *pflag.Flag) {
b := (len(flag.NoOptDefVal) > 0)
name := flag.Shorthand name := flag.Shorthand
format := " " format := " "
if !b { if len(flag.NoOptDefVal) == 0 {
format += "two_word_" format += "two_word_"
} }
format += "flags+=(\"-%s\")\n" format += "flags+=(\"-%s\")\n"
if _, err := fmt.Fprintf(w, format, name); err != nil { buf.WriteString(fmt.Sprintf(format, name))
return err writeFlagHandler(buf, "-"+name, flag.Annotations)
}
return writeFlagHandler("-"+name, flag.Annotations, w)
} }
func writeFlag(flag *pflag.Flag, w io.Writer) error { func writeFlag(buf *bytes.Buffer, flag *pflag.Flag) {
b := (len(flag.NoOptDefVal) > 0)
name := flag.Name name := flag.Name
format := " flags+=(\"--%s" format := " flags+=(\"--%s"
if !b { if len(flag.NoOptDefVal) == 0 {
format += "=" format += "="
} }
format += "\")\n" format += "\")\n"
if _, err := fmt.Fprintf(w, format, name); err != nil { buf.WriteString(fmt.Sprintf(format, name))
return err writeFlagHandler(buf, "--"+name, flag.Annotations)
}
return writeFlagHandler("--"+name, flag.Annotations, w)
} }
func writeLocalNonPersistentFlag(flag *pflag.Flag, w io.Writer) error { func writeLocalNonPersistentFlag(buf *bytes.Buffer, flag *pflag.Flag) {
b := (len(flag.NoOptDefVal) > 0)
name := flag.Name name := flag.Name
format := " local_nonpersistent_flags+=(\"--%s" format := " local_nonpersistent_flags+=(\"--%s"
if !b { if len(flag.NoOptDefVal) == 0 {
format += "=" format += "="
} }
format += "\")\n" format += "\")\n"
if _, err := fmt.Fprintf(w, format, name); err != nil { buf.WriteString(fmt.Sprintf(format, name))
return err
}
return nil
} }
func writeFlags(cmd *Command, w io.Writer) error { func writeFlags(buf *bytes.Buffer, cmd *Command) {
_, err := fmt.Fprintf(w, ` flags=() buf.WriteString(` flags=()
two_word_flags=() two_word_flags=()
local_nonpersistent_flags=() local_nonpersistent_flags=()
flags_with_completion=() flags_with_completion=()
flags_completion=() flags_completion=()
`) `)
if err != nil {
return err
}
localNonPersistentFlags := cmd.LocalNonPersistentFlags() localNonPersistentFlags := cmd.LocalNonPersistentFlags()
var visitErr error
cmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) { cmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) {
if err := writeFlag(flag, w); err != nil { if nonCompletableFlag(flag) {
visitErr = err
return return
} }
writeFlag(buf, flag)
if len(flag.Shorthand) > 0 { if len(flag.Shorthand) > 0 {
if err := writeShortFlag(flag, w); err != nil { writeShortFlag(buf, flag)
visitErr = err
return
}
} }
if localNonPersistentFlags.Lookup(flag.Name) != nil { if localNonPersistentFlags.Lookup(flag.Name) != nil {
if err := writeLocalNonPersistentFlag(flag, w); err != nil { writeLocalNonPersistentFlag(buf, flag)
visitErr = err
return
}
} }
}) })
if visitErr != nil {
return visitErr
}
cmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) { cmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) {
if err := writeFlag(flag, w); err != nil { if nonCompletableFlag(flag) {
visitErr = err
return return
} }
writeFlag(buf, flag)
if len(flag.Shorthand) > 0 { if len(flag.Shorthand) > 0 {
if err := writeShortFlag(flag, w); err != nil { writeShortFlag(buf, flag)
visitErr = err
return
}
} }
}) })
if visitErr != nil {
return visitErr
}
_, err = fmt.Fprintf(w, "\n") buf.WriteString("\n")
return err
} }
func writeRequiredFlag(cmd *Command, w io.Writer) error { func writeRequiredFlag(buf *bytes.Buffer, cmd *Command) {
if _, err := fmt.Fprintf(w, " must_have_one_flag=()\n"); err != nil { buf.WriteString(" must_have_one_flag=()\n")
return err
}
flags := cmd.NonInheritedFlags() flags := cmd.NonInheritedFlags()
var visitErr error
flags.VisitAll(func(flag *pflag.Flag) { flags.VisitAll(func(flag *pflag.Flag) {
if nonCompletableFlag(flag) {
return
}
for key := range flag.Annotations { for key := range flag.Annotations {
switch key { switch key {
case BashCompOneRequiredFlag: case BashCompOneRequiredFlag:
format := " must_have_one_flag+=(\"--%s" format := " must_have_one_flag+=(\"--%s"
b := (flag.Value.Type() == "bool") if flag.Value.Type() != "bool" {
if !b {
format += "=" format += "="
} }
format += "\")\n" format += "\")\n"
if _, err := fmt.Fprintf(w, format, flag.Name); err != nil { buf.WriteString(fmt.Sprintf(format, flag.Name))
visitErr = err
return
}
if len(flag.Shorthand) > 0 { if len(flag.Shorthand) > 0 {
if _, err := fmt.Fprintf(w, " must_have_one_flag+=(\"-%s\")\n", flag.Shorthand); err != nil { buf.WriteString(fmt.Sprintf(" must_have_one_flag+=(\"-%s\")\n", flag.Shorthand))
visitErr = err
return
}
} }
} }
} }
}) })
return visitErr
} }
func writeRequiredNouns(cmd *Command, w io.Writer) error { func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) {
if _, err := fmt.Fprintf(w, " must_have_one_noun=()\n"); err != nil { buf.WriteString(" must_have_one_noun=()\n")
return err
}
sort.Sort(sort.StringSlice(cmd.ValidArgs)) sort.Sort(sort.StringSlice(cmd.ValidArgs))
for _, value := range cmd.ValidArgs { for _, value := range cmd.ValidArgs {
if _, err := fmt.Fprintf(w, " must_have_one_noun+=(%q)\n", value); err != nil { buf.WriteString(fmt.Sprintf(" must_have_one_noun+=(%q)\n", value))
return err
}
} }
return nil
} }
func writeArgAliases(cmd *Command, w io.Writer) error { func writeArgAliases(buf *bytes.Buffer, cmd *Command) {
if _, err := fmt.Fprintf(w, " noun_aliases=()\n"); err != nil { buf.WriteString(" noun_aliases=()\n")
return err
}
sort.Sort(sort.StringSlice(cmd.ArgAliases)) sort.Sort(sort.StringSlice(cmd.ArgAliases))
for _, value := range cmd.ArgAliases { for _, value := range cmd.ArgAliases {
if _, err := fmt.Fprintf(w, " noun_aliases+=(%q)\n", value); err != nil { buf.WriteString(fmt.Sprintf(" noun_aliases+=(%q)\n", value))
return err
}
} }
return nil
} }
func gen(cmd *Command, w io.Writer) error { func gen(buf *bytes.Buffer, cmd *Command) {
for _, c := range cmd.Commands() { for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() || c == cmd.helpCommand { if !c.IsAvailableCommand() || c == cmd.helpCommand {
continue continue
} }
if err := gen(c, w); err != nil { gen(buf, c)
return err
}
} }
commandName := cmd.CommandPath() commandName := cmd.CommandPath()
commandName = strings.Replace(commandName, " ", "_", -1) commandName = strings.Replace(commandName, " ", "_", -1)
commandName = strings.Replace(commandName, ":", "__", -1) commandName = strings.Replace(commandName, ":", "__", -1)
if _, err := fmt.Fprintf(w, "_%s()\n{\n", commandName); err != nil { buf.WriteString(fmt.Sprintf("_%s()\n{\n", commandName))
return err buf.WriteString(fmt.Sprintf(" last_command=%q\n", commandName))
} writeCommands(buf, cmd)
if _, err := fmt.Fprintf(w, " last_command=%q\n", commandName); err != nil { writeFlags(buf, cmd)
return err writeRequiredFlag(buf, cmd)
} writeRequiredNouns(buf, cmd)
if err := writeCommands(cmd, w); err != nil { writeArgAliases(buf, cmd)
return err buf.WriteString("}\n\n")
}
if err := writeFlags(cmd, w); err != nil {
return err
}
if err := writeRequiredFlag(cmd, w); err != nil {
return err
}
if err := writeRequiredNouns(cmd, w); err != nil {
return err
}
if err := writeArgAliases(cmd, w); err != nil {
return err
}
if _, err := fmt.Fprintf(w, "}\n\n"); err != nil {
return err
}
return nil
} }
func (cmd *Command) GenBashCompletion(w io.Writer) error { // GenBashCompletion generates bash completion file and writes to the passed writer.
if err := preamble(w, cmd.Name()); err != nil { func (c *Command) GenBashCompletion(w io.Writer) error {
return err buf := new(bytes.Buffer)
writePreamble(buf, c.Name())
if len(c.BashCompletionFunction) > 0 {
buf.WriteString(c.BashCompletionFunction + "\n")
} }
if len(cmd.BashCompletionFunction) > 0 { gen(buf, c)
if _, err := fmt.Fprintf(w, "%s\n", cmd.BashCompletionFunction); err != nil { writePostscript(buf, c.Name())
return err
} _, err := buf.WriteTo(w)
} return err
if err := gen(cmd, w); err != nil {
return err
}
return postscript(w, cmd.Name())
} }
func (cmd *Command) GenBashCompletionFile(filename string) error { func nonCompletableFlag(flag *pflag.Flag) bool {
return flag.Hidden || len(flag.Deprecated) > 0
}
// GenBashCompletionFile generates bash completion file.
func (c *Command) GenBashCompletionFile(filename string) error {
outFile, err := os.Create(filename) outFile, err := os.Create(filename)
if err != nil { if err != nil {
return err return err
} }
defer outFile.Close() defer outFile.Close()
return cmd.GenBashCompletion(outFile) return c.GenBashCompletion(outFile)
} }
// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag, if it exists. // MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag, if it exists.
func (cmd *Command) MarkFlagRequired(name string) error { func (c *Command) MarkFlagRequired(name string) error {
return MarkFlagRequired(cmd.Flags(), name) return MarkFlagRequired(c.Flags(), name)
} }
// MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag, if it exists. // MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag, if it exists.
func (cmd *Command) MarkPersistentFlagRequired(name string) error { func (c *Command) MarkPersistentFlagRequired(name string) error {
return MarkFlagRequired(cmd.PersistentFlags(), name) return MarkFlagRequired(c.PersistentFlags(), name)
} }
// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag in the flag set, if it exists. // MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag in the flag set, if it exists.
@ -601,20 +508,20 @@ func MarkFlagRequired(flags *pflag.FlagSet, name string) error {
// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists. // MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists.
// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. // Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
func (cmd *Command) MarkFlagFilename(name string, extensions ...string) error { func (c *Command) MarkFlagFilename(name string, extensions ...string) error {
return MarkFlagFilename(cmd.Flags(), name, extensions...) return MarkFlagFilename(c.Flags(), name, extensions...)
} }
// MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists. // MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists.
// Generated bash autocompletion will call the bash function f for the flag. // Generated bash autocompletion will call the bash function f for the flag.
func (cmd *Command) MarkFlagCustom(name string, f string) error { func (c *Command) MarkFlagCustom(name string, f string) error {
return MarkFlagCustom(cmd.Flags(), name, f) return MarkFlagCustom(c.Flags(), name, f)
} }
// MarkPersistentFlagFilename adds the BashCompFilenameExt annotation to the named persistent flag, if it exists. // MarkPersistentFlagFilename adds the BashCompFilenameExt annotation to the named persistent flag, if it exists.
// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. // Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
func (cmd *Command) MarkPersistentFlagFilename(name string, extensions ...string) error { func (c *Command) MarkPersistentFlagFilename(name string, extensions ...string) error {
return MarkFlagFilename(cmd.PersistentFlags(), name, extensions...) return MarkFlagFilename(c.PersistentFlags(), name, extensions...)
} }
// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag in the flag set, if it exists. // MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag in the flag set, if it exists.

View File

@ -27,48 +27,59 @@ import (
) )
var templateFuncs = template.FuncMap{ var templateFuncs = template.FuncMap{
"trim": strings.TrimSpace, "trim": strings.TrimSpace,
"trimRightSpace": trimRightSpace, "trimRightSpace": trimRightSpace,
"appendIfNotPresent": appendIfNotPresent, "trimTrailingWhitespaces": trimRightSpace,
"rpad": rpad, "appendIfNotPresent": appendIfNotPresent,
"gt": Gt, "rpad": rpad,
"eq": Eq, "gt": Gt,
"eq": Eq,
} }
var initializers []func() var initializers []func()
// automatic prefix matching can be a dangerous thing to automatically enable in CLI tools. // EnablePrefixMatching allows to set automatic prefix matching. Automatic prefix matching can be a dangerous thing
// Set this to true to enable it // to automatically enable in CLI tools.
// Set this to true to enable it.
var EnablePrefixMatching = false var EnablePrefixMatching = false
//EnableCommandSorting controls sorting of the slice of commands, which is turned on by default. // EnableCommandSorting controls sorting of the slice of commands, which is turned on by default.
//To disable sorting, set it to false. // To disable sorting, set it to false.
var EnableCommandSorting = true var EnableCommandSorting = true
//AddTemplateFunc adds a template function that's available to Usage and Help // MousetrapHelpText enables an information splash screen on Windows
//template generation. // if the CLI is started from explorer.exe.
// To disable the mousetrap, just set this variable to blank string ("").
// Works only on Microsoft Windows.
var MousetrapHelpText string = `This is a command line tool.
You need to open cmd.exe and run it from there.
`
// AddTemplateFunc adds a template function that's available to Usage and Help
// template generation.
func AddTemplateFunc(name string, tmplFunc interface{}) { func AddTemplateFunc(name string, tmplFunc interface{}) {
templateFuncs[name] = tmplFunc templateFuncs[name] = tmplFunc
} }
//AddTemplateFuncs adds multiple template functions availalble to Usage and // AddTemplateFuncs adds multiple template functions that are available to Usage and
//Help template generation. // Help template generation.
func AddTemplateFuncs(tmplFuncs template.FuncMap) { func AddTemplateFuncs(tmplFuncs template.FuncMap) {
for k, v := range tmplFuncs { for k, v := range tmplFuncs {
templateFuncs[k] = v templateFuncs[k] = v
} }
} }
//OnInitialize takes a series of func() arguments and appends them to a slice of func(). // OnInitialize takes a series of func() arguments and appends them to a slice of func().
func OnInitialize(y ...func()) { func OnInitialize(y ...func()) {
for _, x := range y { initializers = append(initializers, y...)
initializers = append(initializers, x)
}
} }
//Gt takes two types and checks whether the first type is greater than the second. In case of types Arrays, Chans, // FIXME Gt is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra.
//Maps and Slices, Gt will compare their lengths. Ints are compared directly while strings are first parsed as
//ints and then compared. // Gt takes two types and checks whether the first type is greater than the second. In case of types Arrays, Chans,
// Maps and Slices, Gt will compare their lengths. Ints are compared directly while strings are first parsed as
// ints and then compared.
func Gt(a interface{}, b interface{}) bool { func Gt(a interface{}, b interface{}) bool {
var left, right int64 var left, right int64
av := reflect.ValueOf(a) av := reflect.ValueOf(a)
@ -96,7 +107,9 @@ func Gt(a interface{}, b interface{}) bool {
return left > right return left > right
} }
//Eq takes two types and checks whether they are equal. Supported types are int and string. Unsupported types will panic. // FIXME Eq is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra.
// Eq takes two types and checks whether they are equal. Supported types are int and string. Unsupported types will panic.
func Eq(a interface{}, b interface{}) bool { func Eq(a interface{}, b interface{}) bool {
av := reflect.ValueOf(a) av := reflect.ValueOf(a)
bv := reflect.ValueOf(b) bv := reflect.ValueOf(b)
@ -116,7 +129,9 @@ func trimRightSpace(s string) string {
return strings.TrimRightFunc(s, unicode.IsSpace) return strings.TrimRightFunc(s, unicode.IsSpace)
} }
// appendIfNotPresent will append stringToAppend to the end of s, but only if it's not yet present in s // FIXME appendIfNotPresent is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra.
// appendIfNotPresent will append stringToAppend to the end of s, but only if it's not yet present in s.
func appendIfNotPresent(s, stringToAppend string) string { func appendIfNotPresent(s, stringToAppend string) string {
if strings.Contains(s, stringToAppend) { if strings.Contains(s, stringToAppend) {
return s return s
@ -124,7 +139,7 @@ func appendIfNotPresent(s, stringToAppend string) string {
return s + " " + stringToAppend return s + " " + stringToAppend
} }
//rpad adds padding to the right of a string // rpad adds padding to the right of a string.
func rpad(s string, padding int) string { func rpad(s string, padding int) string {
template := fmt.Sprintf("%%-%ds", padding) template := fmt.Sprintf("%%-%ds", padding)
return fmt.Sprintf(template, s) return fmt.Sprintf(template, s)
@ -138,7 +153,7 @@ func tmpl(w io.Writer, text string, data interface{}) error {
return t.Execute(w, data) return t.Execute(w, data)
} }
// ld compares two strings and returns the levenshtein distance between them // ld compares two strings and returns the levenshtein distance between them.
func ld(s, t string, ignoreCase bool) int { func ld(s, t string, ignoreCase bool) int {
if ignoreCase { if ignoreCase {
s = strings.ToLower(s) s = strings.ToLower(s)

File diff suppressed because it is too large Load Diff

View File

@ -11,14 +11,8 @@ import (
var preExecHookFn = preExecHook var preExecHookFn = preExecHook
// enables an information splash screen on Windows if the CLI is started from explorer.exe.
var MousetrapHelpText string = `This is a command line tool
You need to open cmd.exe and run it from there.
`
func preExecHook(c *Command) { func preExecHook(c *Command) {
if mousetrap.StartedByExplorer() { if MousetrapHelpText != "" && mousetrap.StartedByExplorer() {
c.Print(MousetrapHelpText) c.Print(MousetrapHelpText)
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
os.Exit(1) os.Exit(1)

View File

@ -23,21 +23,21 @@ import (
"strings" "strings"
"time" "time"
mangen "github.com/cpuguy83/go-md2man/md2man" "github.com/cpuguy83/go-md2man/md2man"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
// GenManTree will generate a man page for this command and all descendants // GenManTree will generate a man page for this command and all descendants
// in the directory given. The header may be nil. This function may not work // in the directory given. The header may be nil. This function may not work
// correctly if your command names have - in them. If you have `cmd` with two // correctly if your command names have `-` in them. If you have `cmd` with two
// subcmds, `sub` and `sub-third`. And `sub` has a subcommand called `third` // subcmds, `sub` and `sub-third`, and `sub` has a subcommand called `third`
// it is undefined which help output will be in the file `cmd-sub-third.1`. // it is undefined which help output will be in the file `cmd-sub-third.1`.
func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error { func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error {
return GenManTreeFromOpts(cmd, GenManTreeOptions{ return GenManTreeFromOpts(cmd, GenManTreeOptions{
Header: header, Header: header,
Path: dir, Path: dir,
CommandSeparator: "_", CommandSeparator: "-",
}) })
} }
@ -49,7 +49,7 @@ func GenManTreeFromOpts(cmd *cobra.Command, opts GenManTreeOptions) error {
header = &GenManHeader{} header = &GenManHeader{}
} }
for _, c := range cmd.Commands() { for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() || c.IsHelpCommand() { if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
continue continue
} }
if err := GenManTreeFromOpts(c, opts); err != nil { if err := GenManTreeFromOpts(c, opts); err != nil {
@ -77,6 +77,8 @@ func GenManTreeFromOpts(cmd *cobra.Command, opts GenManTreeOptions) error {
return GenMan(cmd, &headerCopy, f) return GenMan(cmd, &headerCopy, f)
} }
// GenManTreeOptions is the options for generating the man pages.
// Used only in GenManTreeFromOpts.
type GenManTreeOptions struct { type GenManTreeOptions struct {
Header *GenManHeader Header *GenManHeader
Path string Path string
@ -105,7 +107,7 @@ func GenMan(cmd *cobra.Command, header *GenManHeader, w io.Writer) error {
fillHeader(header, cmd.CommandPath()) fillHeader(header, cmd.CommandPath())
b := genMan(cmd, header) b := genMan(cmd, header)
_, err := w.Write(mangen.Render(b)) _, err := w.Write(md2man.Render(b))
return err return err
} }
@ -126,25 +128,25 @@ func fillHeader(header *GenManHeader, name string) {
} }
} }
func manPreamble(out io.Writer, header *GenManHeader, cmd *cobra.Command, dashedName string) { func manPreamble(buf *bytes.Buffer, header *GenManHeader, cmd *cobra.Command, dashedName string) {
description := cmd.Long description := cmd.Long
if len(description) == 0 { if len(description) == 0 {
description = cmd.Short description = cmd.Short
} }
fmt.Fprintf(out, `%% %s(%s)%s buf.WriteString(fmt.Sprintf(`%% %s(%s)%s
%% %s %% %s
%% %s %% %s
# NAME # NAME
`, header.Title, header.Section, header.date, header.Source, header.Manual) `, header.Title, header.Section, header.date, header.Source, header.Manual))
fmt.Fprintf(out, "%s \\- %s\n\n", dashedName, cmd.Short) buf.WriteString(fmt.Sprintf("%s \\- %s\n\n", dashedName, cmd.Short))
fmt.Fprintf(out, "# SYNOPSIS\n") buf.WriteString("# SYNOPSIS\n")
fmt.Fprintf(out, "**%s**\n\n", cmd.UseLine()) buf.WriteString(fmt.Sprintf("**%s**\n\n", cmd.UseLine()))
fmt.Fprintf(out, "# DESCRIPTION\n") buf.WriteString("# DESCRIPTION\n")
fmt.Fprintf(out, "%s\n\n", description) buf.WriteString(description + "\n\n")
} }
func manPrintFlags(out io.Writer, flags *pflag.FlagSet) { func manPrintFlags(buf *bytes.Buffer, flags *pflag.FlagSet) {
flags.VisitAll(func(flag *pflag.Flag) { flags.VisitAll(func(flag *pflag.Flag) {
if len(flag.Deprecated) > 0 || flag.Hidden { if len(flag.Deprecated) > 0 || flag.Hidden {
return return
@ -156,38 +158,41 @@ func manPrintFlags(out io.Writer, flags *pflag.FlagSet) {
format = fmt.Sprintf("**--%s**", flag.Name) format = fmt.Sprintf("**--%s**", flag.Name)
} }
if len(flag.NoOptDefVal) > 0 { if len(flag.NoOptDefVal) > 0 {
format = format + "[" format += "["
} }
if flag.Value.Type() == "string" { if flag.Value.Type() == "string" {
// put quotes on the value // put quotes on the value
format = format + "=%q" format += "=%q"
} else { } else {
format = format + "=%s" format += "=%s"
} }
if len(flag.NoOptDefVal) > 0 { if len(flag.NoOptDefVal) > 0 {
format = format + "]" format += "]"
} }
format = format + "\n\t%s\n\n" format += "\n\t%s\n\n"
fmt.Fprintf(out, format, flag.DefValue, flag.Usage) buf.WriteString(fmt.Sprintf(format, flag.DefValue, flag.Usage))
}) })
} }
func manPrintOptions(out io.Writer, command *cobra.Command) { func manPrintOptions(buf *bytes.Buffer, command *cobra.Command) {
flags := command.NonInheritedFlags() flags := command.NonInheritedFlags()
if flags.HasFlags() { if flags.HasFlags() {
fmt.Fprintf(out, "# OPTIONS\n") buf.WriteString("# OPTIONS\n")
manPrintFlags(out, flags) manPrintFlags(buf, flags)
fmt.Fprintf(out, "\n") buf.WriteString("\n")
} }
flags = command.InheritedFlags() flags = command.InheritedFlags()
if flags.HasFlags() { if flags.HasFlags() {
fmt.Fprintf(out, "# OPTIONS INHERITED FROM PARENT COMMANDS\n") buf.WriteString("# OPTIONS INHERITED FROM PARENT COMMANDS\n")
manPrintFlags(out, flags) manPrintFlags(buf, flags)
fmt.Fprintf(out, "\n") buf.WriteString("\n")
} }
} }
func genMan(cmd *cobra.Command, header *GenManHeader) []byte { func genMan(cmd *cobra.Command, header *GenManHeader) []byte {
cmd.InitDefaultHelpCmd()
cmd.InitDefaultHelpFlag()
// something like `rootcmd-subcmd1-subcmd2` // something like `rootcmd-subcmd1-subcmd2`
dashCommandName := strings.Replace(cmd.CommandPath(), " ", "-", -1) dashCommandName := strings.Replace(cmd.CommandPath(), " ", "-", -1)
@ -196,11 +201,11 @@ func genMan(cmd *cobra.Command, header *GenManHeader) []byte {
manPreamble(buf, header, cmd, dashCommandName) manPreamble(buf, header, cmd, dashCommandName)
manPrintOptions(buf, cmd) manPrintOptions(buf, cmd)
if len(cmd.Example) > 0 { if len(cmd.Example) > 0 {
fmt.Fprintf(buf, "# EXAMPLE\n") buf.WriteString("# EXAMPLE\n")
fmt.Fprintf(buf, "\n%s\n\n", cmd.Example) buf.WriteString(fmt.Sprintf("```\n%s\n```\n", cmd.Example))
} }
if hasSeeAlso(cmd) { if hasSeeAlso(cmd) {
fmt.Fprintf(buf, "# SEE ALSO\n") buf.WriteString("# SEE ALSO\n")
seealsos := make([]string, 0) seealsos := make([]string, 0)
if cmd.HasParent() { if cmd.HasParent() {
parentPath := cmd.Parent().CommandPath() parentPath := cmd.Parent().CommandPath()
@ -216,16 +221,16 @@ func genMan(cmd *cobra.Command, header *GenManHeader) []byte {
children := cmd.Commands() children := cmd.Commands()
sort.Sort(byName(children)) sort.Sort(byName(children))
for _, c := range children { for _, c := range children {
if !c.IsAvailableCommand() || c.IsHelpCommand() { if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
continue continue
} }
seealso := fmt.Sprintf("**%s-%s(%s)**", dashCommandName, c.Name(), header.Section) seealso := fmt.Sprintf("**%s-%s(%s)**", dashCommandName, c.Name(), header.Section)
seealsos = append(seealsos, seealso) seealsos = append(seealsos, seealso)
} }
fmt.Fprintf(buf, "%s\n", strings.Join(seealsos, ", ")) buf.WriteString(strings.Join(seealsos, ", ") + "\n")
} }
if !cmd.DisableAutoGenTag { if !cmd.DisableAutoGenTag {
fmt.Fprintf(buf, "# HISTORY\n%s Auto generated by spf13/cobra\n", header.Date.Format("2-Jan-2006")) buf.WriteString(fmt.Sprintf("# HISTORY\n%s Auto generated by spf13/cobra\n", header.Date.Format("2-Jan-2006")))
} }
return buf.Bytes() return buf.Bytes()
} }

View File

@ -14,6 +14,7 @@
package doc package doc
import ( import (
"bytes"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -25,38 +26,36 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func printOptions(w io.Writer, cmd *cobra.Command, name string) error { func printOptions(buf *bytes.Buffer, cmd *cobra.Command, name string) error {
flags := cmd.NonInheritedFlags() flags := cmd.NonInheritedFlags()
flags.SetOutput(w) flags.SetOutput(buf)
if flags.HasFlags() { if flags.HasFlags() {
if _, err := fmt.Fprintf(w, "### Options\n\n```\n"); err != nil { buf.WriteString("### Options\n\n```\n")
return err
}
flags.PrintDefaults() flags.PrintDefaults()
if _, err := fmt.Fprintf(w, "```\n\n"); err != nil { buf.WriteString("```\n\n")
return err
}
} }
parentFlags := cmd.InheritedFlags() parentFlags := cmd.InheritedFlags()
parentFlags.SetOutput(w) parentFlags.SetOutput(buf)
if parentFlags.HasFlags() { if parentFlags.HasFlags() {
if _, err := fmt.Fprintf(w, "### Options inherited from parent commands\n\n```\n"); err != nil { buf.WriteString("### Options inherited from parent commands\n\n```\n")
return err
}
parentFlags.PrintDefaults() parentFlags.PrintDefaults()
if _, err := fmt.Fprintf(w, "```\n\n"); err != nil { buf.WriteString("```\n\n")
return err
}
} }
return nil return nil
} }
// GenMarkdown creates markdown output.
func GenMarkdown(cmd *cobra.Command, w io.Writer) error { func GenMarkdown(cmd *cobra.Command, w io.Writer) error {
return GenMarkdownCustom(cmd, w, func(s string) string { return s }) return GenMarkdownCustom(cmd, w, func(s string) string { return s })
} }
// GenMarkdownCustom creates custom markdown output.
func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) string) error { func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) string) error {
cmd.InitDefaultHelpCmd()
cmd.InitDefaultHelpFlag()
buf := new(bytes.Buffer)
name := cmd.CommandPath() name := cmd.CommandPath()
short := cmd.Short short := cmd.Short
@ -65,49 +64,31 @@ func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string)
long = short long = short
} }
if _, err := fmt.Fprintf(w, "## %s\n\n", name); err != nil { buf.WriteString("## " + name + "\n\n")
return err buf.WriteString(short + "\n\n")
} buf.WriteString("### Synopsis\n\n")
if _, err := fmt.Fprintf(w, "%s\n\n", short); err != nil { buf.WriteString("\n" + long + "\n\n")
return err
}
if _, err := fmt.Fprintf(w, "### Synopsis\n\n"); err != nil {
return err
}
if _, err := fmt.Fprintf(w, "\n%s\n\n", long); err != nil {
return err
}
if cmd.Runnable() { if cmd.Runnable() {
if _, err := fmt.Fprintf(w, "```\n%s\n```\n\n", cmd.UseLine()); err != nil { buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.UseLine()))
return err
}
} }
if len(cmd.Example) > 0 { if len(cmd.Example) > 0 {
if _, err := fmt.Fprintf(w, "### Examples\n\n"); err != nil { buf.WriteString("### Examples\n\n")
return err buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.Example))
}
if _, err := fmt.Fprintf(w, "```\n%s\n```\n\n", cmd.Example); err != nil {
return err
}
} }
if err := printOptions(w, cmd, name); err != nil { if err := printOptions(buf, cmd, name); err != nil {
return err return err
} }
if hasSeeAlso(cmd) { if hasSeeAlso(cmd) {
if _, err := fmt.Fprintf(w, "### SEE ALSO\n"); err != nil { buf.WriteString("### SEE ALSO\n")
return err
}
if cmd.HasParent() { if cmd.HasParent() {
parent := cmd.Parent() parent := cmd.Parent()
pname := parent.CommandPath() pname := parent.CommandPath()
link := pname + ".md" link := pname + ".md"
link = strings.Replace(link, " ", "_", -1) link = strings.Replace(link, " ", "_", -1)
if _, err := fmt.Fprintf(w, "* [%s](%s)\t - %s\n", pname, linkHandler(link), parent.Short); err != nil { buf.WriteString(fmt.Sprintf("* [%s](%s)\t - %s\n", pname, linkHandler(link), parent.Short))
return err
}
cmd.VisitParents(func(c *cobra.Command) { cmd.VisitParents(func(c *cobra.Command) {
if c.DisableAutoGenTag { if c.DisableAutoGenTag {
cmd.DisableAutoGenTag = c.DisableAutoGenTag cmd.DisableAutoGenTag = c.DisableAutoGenTag
@ -119,37 +100,40 @@ func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string)
sort.Sort(byName(children)) sort.Sort(byName(children))
for _, child := range children { for _, child := range children {
if !child.IsAvailableCommand() || child.IsHelpCommand() { if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() {
continue continue
} }
cname := name + " " + child.Name() cname := name + " " + child.Name()
link := cname + ".md" link := cname + ".md"
link = strings.Replace(link, " ", "_", -1) link = strings.Replace(link, " ", "_", -1)
if _, err := fmt.Fprintf(w, "* [%s](%s)\t - %s\n", cname, linkHandler(link), child.Short); err != nil { buf.WriteString(fmt.Sprintf("* [%s](%s)\t - %s\n", cname, linkHandler(link), child.Short))
return err
}
}
if _, err := fmt.Fprintf(w, "\n"); err != nil {
return err
} }
buf.WriteString("\n")
} }
if !cmd.DisableAutoGenTag { if !cmd.DisableAutoGenTag {
if _, err := fmt.Fprintf(w, "###### Auto generated by spf13/cobra on %s\n", time.Now().Format("2-Jan-2006")); err != nil { buf.WriteString("###### Auto generated by spf13/cobra on " + time.Now().Format("2-Jan-2006") + "\n")
return err
}
} }
return nil _, err := buf.WriteTo(w)
return err
} }
// GenMarkdownTree will generate a markdown page for this command and all
// descendants in the directory given. The header may be nil.
// This function may not work correctly if your command names have `-` in them.
// If you have `cmd` with two subcmds, `sub` and `sub-third`,
// and `sub` has a subcommand called `third`, it is undefined which
// help output will be in the file `cmd-sub-third.1`.
func GenMarkdownTree(cmd *cobra.Command, dir string) error { func GenMarkdownTree(cmd *cobra.Command, dir string) error {
identity := func(s string) string { return s } identity := func(s string) string { return s }
emptyStr := func(s string) string { return "" } emptyStr := func(s string) string { return "" }
return GenMarkdownTreeCustom(cmd, dir, emptyStr, identity) return GenMarkdownTreeCustom(cmd, dir, emptyStr, identity)
} }
// GenMarkdownTreeCustom is the the same as GenMarkdownTree, but
// with custom filePrepender and linkHandler.
func GenMarkdownTreeCustom(cmd *cobra.Command, dir string, filePrepender, linkHandler func(string) string) error { func GenMarkdownTreeCustom(cmd *cobra.Command, dir string, filePrepender, linkHandler func(string) string) error {
for _, c := range cmd.Commands() { for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() || c.IsHelpCommand() { if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
continue continue
} }
if err := GenMarkdownTreeCustom(c, dir, filePrepender, linkHandler); err != nil { if err := GenMarkdownTreeCustom(c, dir, filePrepender, linkHandler); err != nil {

185
vendor/github.com/spf13/cobra/doc/rest_docs.go generated vendored Normal file
View File

@ -0,0 +1,185 @@
//Copyright 2015 Red Hat Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package doc
import (
"bytes"
"fmt"
"io"
"os"
"path/filepath"
"sort"
"strings"
"time"
"github.com/spf13/cobra"
)
func printOptionsReST(buf *bytes.Buffer, cmd *cobra.Command, name string) error {
flags := cmd.NonInheritedFlags()
flags.SetOutput(buf)
if flags.HasFlags() {
buf.WriteString("Options\n")
buf.WriteString("~~~~~~~\n\n::\n\n")
flags.PrintDefaults()
buf.WriteString("\n")
}
parentFlags := cmd.InheritedFlags()
parentFlags.SetOutput(buf)
if parentFlags.HasFlags() {
buf.WriteString("Options inherited from parent commands\n")
buf.WriteString("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n")
parentFlags.PrintDefaults()
buf.WriteString("\n")
}
return nil
}
// linkHandler for default ReST hyperlink markup
func defaultLinkHandler(name, ref string) string {
return fmt.Sprintf("`%s <%s.rst>`_", name, ref)
}
// GenReST creates reStructured Text output.
func GenReST(cmd *cobra.Command, w io.Writer) error {
return GenReSTCustom(cmd, w, defaultLinkHandler)
}
// GenReSTCustom creates custom reStructured Text output.
func GenReSTCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string, string) string) error {
cmd.InitDefaultHelpCmd()
cmd.InitDefaultHelpFlag()
buf := new(bytes.Buffer)
name := cmd.CommandPath()
short := cmd.Short
long := cmd.Long
if len(long) == 0 {
long = short
}
ref := strings.Replace(name, " ", "_", -1)
buf.WriteString(".. _" + ref + ":\n\n")
buf.WriteString(name + "\n")
buf.WriteString(strings.Repeat("-", len(name)) + "\n\n")
buf.WriteString(short + "\n\n")
buf.WriteString("Synopsis\n")
buf.WriteString("~~~~~~~~\n\n")
buf.WriteString("\n" + long + "\n\n")
if cmd.Runnable() {
buf.WriteString(fmt.Sprintf("::\n\n %s\n\n", cmd.UseLine()))
}
if len(cmd.Example) > 0 {
buf.WriteString("Examples\n")
buf.WriteString("~~~~~~~~\n\n")
buf.WriteString(fmt.Sprintf("::\n\n%s\n\n", indentString(cmd.Example, " ")))
}
if err := printOptionsReST(buf, cmd, name); err != nil {
return err
}
if hasSeeAlso(cmd) {
buf.WriteString("SEE ALSO\n")
buf.WriteString("~~~~~~~~\n\n")
if cmd.HasParent() {
parent := cmd.Parent()
pname := parent.CommandPath()
ref = strings.Replace(pname, " ", "_", -1)
buf.WriteString(fmt.Sprintf("* %s \t - %s\n", linkHandler(pname, ref), parent.Short))
cmd.VisitParents(func(c *cobra.Command) {
if c.DisableAutoGenTag {
cmd.DisableAutoGenTag = c.DisableAutoGenTag
}
})
}
children := cmd.Commands()
sort.Sort(byName(children))
for _, child := range children {
if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() {
continue
}
cname := name + " " + child.Name()
ref = strings.Replace(cname, " ", "_", -1)
buf.WriteString(fmt.Sprintf("* %s \t - %s\n", linkHandler(cname, ref), child.Short))
}
buf.WriteString("\n")
}
if !cmd.DisableAutoGenTag {
buf.WriteString("*Auto generated by spf13/cobra on " + time.Now().Format("2-Jan-2006") + "*\n")
}
_, err := buf.WriteTo(w)
return err
}
// GenReSTTree will generate a ReST page for this command and all
// descendants in the directory given.
// This function may not work correctly if your command names have `-` in them.
// If you have `cmd` with two subcmds, `sub` and `sub-third`,
// and `sub` has a subcommand called `third`, it is undefined which
// help output will be in the file `cmd-sub-third.1`.
func GenReSTTree(cmd *cobra.Command, dir string) error {
emptyStr := func(s string) string { return "" }
return GenReSTTreeCustom(cmd, dir, emptyStr, defaultLinkHandler)
}
// GenReSTTreeCustom is the the same as GenReSTTree, but
// with custom filePrepender and linkHandler.
func GenReSTTreeCustom(cmd *cobra.Command, dir string, filePrepender func(string) string, linkHandler func(string, string) string) error {
for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
continue
}
if err := GenReSTTreeCustom(c, dir, filePrepender, linkHandler); err != nil {
return err
}
}
basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + ".rst"
filename := filepath.Join(dir, basename)
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
if _, err := io.WriteString(f, filePrepender(filename)); err != nil {
return err
}
if err := GenReSTCustom(cmd, f, linkHandler); err != nil {
return err
}
return nil
}
// adapted from: https://github.com/kr/text/blob/main/indent.go
func indentString(s, p string) string {
var res []byte
b := []byte(s)
prefix := []byte(p)
bol := true
for _, c := range b {
if bol && c != '\n' {
res = append(res, prefix...)
}
res = append(res, c)
bol = c == '\n'
}
return string(res)
}

View File

@ -13,7 +13,11 @@
package doc package doc
import "github.com/spf13/cobra" import (
"strings"
"github.com/spf13/cobra"
)
// Test to see if we have a reason to print See Also information in docs // Test to see if we have a reason to print See Also information in docs
// Basically this is a test for a parent commend or a subcommand which is // Basically this is a test for a parent commend or a subcommand which is
@ -23,7 +27,7 @@ func hasSeeAlso(cmd *cobra.Command) bool {
return true return true
} }
for _, c := range cmd.Commands() { for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() || c.IsHelpCommand() { if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
continue continue
} }
return true return true
@ -31,6 +35,15 @@ func hasSeeAlso(cmd *cobra.Command) bool {
return false return false
} }
// Temporary workaround for yaml lib generating incorrect yaml with long strings
// that do not contain \n.
func forceMultiLine(s string) string {
if len(s) > 60 && !strings.Contains(s, "\n") {
s = s + "\n"
}
return s
}
type byName []*cobra.Command type byName []*cobra.Command
func (s byName) Len() int { return len(s) } func (s byName) Len() int { return len(s) }

169
vendor/github.com/spf13/cobra/doc/yaml_docs.go generated vendored Normal file
View File

@ -0,0 +1,169 @@
// Copyright 2016 French Ben. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package doc
import (
"fmt"
"io"
"os"
"path/filepath"
"sort"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"gopkg.in/yaml.v2"
)
type cmdOption struct {
Name string
Shorthand string `yaml:",omitempty"`
DefaultValue string `yaml:"default_value,omitempty"`
Usage string `yaml:",omitempty"`
}
type cmdDoc struct {
Name string
Synopsis string `yaml:",omitempty"`
Description string `yaml:",omitempty"`
Options []cmdOption `yaml:",omitempty"`
InheritedOptions []cmdOption `yaml:"inherited_options,omitempty"`
Example string `yaml:",omitempty"`
SeeAlso []string `yaml:"see_also,omitempty"`
}
// GenYamlTree creates yaml structured ref files for this command and all descendants
// in the directory given. This function may not work
// correctly if your command names have `-` in them. If you have `cmd` with two
// subcmds, `sub` and `sub-third`, and `sub` has a subcommand called `third`
// it is undefined which help output will be in the file `cmd-sub-third.1`.
func GenYamlTree(cmd *cobra.Command, dir string) error {
identity := func(s string) string { return s }
emptyStr := func(s string) string { return "" }
return GenYamlTreeCustom(cmd, dir, emptyStr, identity)
}
// GenYamlTreeCustom creates yaml structured ref files.
func GenYamlTreeCustom(cmd *cobra.Command, dir string, filePrepender, linkHandler func(string) string) error {
for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
continue
}
if err := GenYamlTreeCustom(c, dir, filePrepender, linkHandler); err != nil {
return err
}
}
basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + ".yaml"
filename := filepath.Join(dir, basename)
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
if _, err := io.WriteString(f, filePrepender(filename)); err != nil {
return err
}
if err := GenYamlCustom(cmd, f, linkHandler); err != nil {
return err
}
return nil
}
// GenYaml creates yaml output.
func GenYaml(cmd *cobra.Command, w io.Writer) error {
return GenYamlCustom(cmd, w, func(s string) string { return s })
}
// GenYamlCustom creates custom yaml output.
func GenYamlCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) string) error {
cmd.InitDefaultHelpCmd()
cmd.InitDefaultHelpFlag()
yamlDoc := cmdDoc{}
yamlDoc.Name = cmd.CommandPath()
yamlDoc.Synopsis = forceMultiLine(cmd.Short)
yamlDoc.Description = forceMultiLine(cmd.Long)
if len(cmd.Example) > 0 {
yamlDoc.Example = cmd.Example
}
flags := cmd.NonInheritedFlags()
if flags.HasFlags() {
yamlDoc.Options = genFlagResult(flags)
}
flags = cmd.InheritedFlags()
if flags.HasFlags() {
yamlDoc.InheritedOptions = genFlagResult(flags)
}
if hasSeeAlso(cmd) {
result := []string{}
if cmd.HasParent() {
parent := cmd.Parent()
result = append(result, parent.CommandPath()+" - "+parent.Short)
}
children := cmd.Commands()
sort.Sort(byName(children))
for _, child := range children {
if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() {
continue
}
result = append(result, child.Name()+" - "+child.Short)
}
yamlDoc.SeeAlso = result
}
final, err := yaml.Marshal(&yamlDoc)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if _, err := w.Write(final); err != nil {
return err
}
return nil
}
func genFlagResult(flags *pflag.FlagSet) []cmdOption {
var result []cmdOption
flags.VisitAll(func(flag *pflag.Flag) {
// Todo, when we mark a shorthand is deprecated, but specify an empty message.
// The flag.ShorthandDeprecated is empty as the shorthand is deprecated.
// Using len(flag.ShorthandDeprecated) > 0 can't handle this, others are ok.
if !(len(flag.ShorthandDeprecated) > 0) && len(flag.Shorthand) > 0 {
opt := cmdOption{
flag.Name,
flag.Shorthand,
flag.DefValue,
forceMultiLine(flag.Usage),
}
result = append(result, opt)
} else {
opt := cmdOption{
Name: flag.Name,
DefaultValue: forceMultiLine(flag.DefValue),
Usage: forceMultiLine(flag.Usage),
}
result = append(result, opt)
}
})
return result
}

126
vendor/github.com/spf13/cobra/zsh_completions.go generated vendored Normal file
View File

@ -0,0 +1,126 @@
package cobra
import (
"bytes"
"fmt"
"io"
"os"
"strings"
)
// GenZshCompletionFile generates zsh completion file.
func (c *Command) GenZshCompletionFile(filename string) error {
outFile, err := os.Create(filename)
if err != nil {
return err
}
defer outFile.Close()
return c.GenZshCompletion(outFile)
}
// GenZshCompletion generates a zsh completion file and writes to the passed writer.
func (c *Command) GenZshCompletion(w io.Writer) error {
buf := new(bytes.Buffer)
writeHeader(buf, c)
maxDepth := maxDepth(c)
writeLevelMapping(buf, maxDepth)
writeLevelCases(buf, maxDepth, c)
_, err := buf.WriteTo(w)
return err
}
func writeHeader(w io.Writer, cmd *Command) {
fmt.Fprintf(w, "#compdef %s\n\n", cmd.Name())
}
func maxDepth(c *Command) int {
if len(c.Commands()) == 0 {
return 0
}
maxDepthSub := 0
for _, s := range c.Commands() {
subDepth := maxDepth(s)
if subDepth > maxDepthSub {
maxDepthSub = subDepth
}
}
return 1 + maxDepthSub
}
func writeLevelMapping(w io.Writer, numLevels int) {
fmt.Fprintln(w, `_arguments \`)
for i := 1; i <= numLevels; i++ {
fmt.Fprintf(w, ` '%d: :->level%d' \`, i, i)
fmt.Fprintln(w)
}
fmt.Fprintf(w, ` '%d: :%s'`, numLevels+1, "_files")
fmt.Fprintln(w)
}
func writeLevelCases(w io.Writer, maxDepth int, root *Command) {
fmt.Fprintln(w, "case $state in")
defer fmt.Fprintln(w, "esac")
for i := 1; i <= maxDepth; i++ {
fmt.Fprintf(w, " level%d)\n", i)
writeLevel(w, root, i)
fmt.Fprintln(w, " ;;")
}
fmt.Fprintln(w, " *)")
fmt.Fprintln(w, " _arguments '*: :_files'")
fmt.Fprintln(w, " ;;")
}
func writeLevel(w io.Writer, root *Command, i int) {
fmt.Fprintf(w, " case $words[%d] in\n", i)
defer fmt.Fprintln(w, " esac")
commands := filterByLevel(root, i)
byParent := groupByParent(commands)
for p, c := range byParent {
names := names(c)
fmt.Fprintf(w, " %s)\n", p)
fmt.Fprintf(w, " _arguments '%d: :(%s)'\n", i, strings.Join(names, " "))
fmt.Fprintln(w, " ;;")
}
fmt.Fprintln(w, " *)")
fmt.Fprintln(w, " _arguments '*: :_files'")
fmt.Fprintln(w, " ;;")
}
func filterByLevel(c *Command, l int) []*Command {
cs := make([]*Command, 0)
if l == 0 {
cs = append(cs, c)
return cs
}
for _, s := range c.Commands() {
cs = append(cs, filterByLevel(s, l-1)...)
}
return cs
}
func groupByParent(commands []*Command) map[string][]*Command {
m := make(map[string][]*Command)
for _, c := range commands {
parent := c.Parent()
if parent == nil {
continue
}
m[parent.Name()] = append(m[parent.Name()], c)
}
return m
}
func names(commands []*Command) []string {
ns := make([]string, len(commands))
for i, c := range commands {
ns[i] = c.Name()
}
return ns
}

View File

@ -246,6 +246,25 @@ It is possible to mark a flag as hidden, meaning it will still function as norma
flags.MarkHidden("secretFlag") flags.MarkHidden("secretFlag")
``` ```
## Disable sorting of flags
`pflag` allows you to disable sorting of flags for help and usage message.
**Example**:
```go
flags.BoolP("verbose", "v", false, "verbose output")
flags.String("coolflag", "yeaah", "it's really cool flag")
flags.Int("usefulflag", 777, "sometimes it's very useful")
flags.SortFlags = false
flags.PrintDefaults()
```
**Output**:
```
-v, --verbose verbose output
--coolflag string it's really cool flag (default "yeaah")
--usefulflag int sometimes it's very useful (default 777)
```
## Supporting Go flags when using pflag ## Supporting Go flags when using pflag
In order to support flags defined using Go's `flag` package, they must be added to the `pflag` flagset. This is usually necessary In order to support flags defined using Go's `flag` package, they must be added to the `pflag` flagset. This is usually necessary
to support flags defined by third-party dependencies (e.g. `golang/glog`). to support flags defined by third-party dependencies (e.g. `golang/glog`).
@ -270,8 +289,8 @@ func main() {
You can see the full reference documentation of the pflag package You can see the full reference documentation of the pflag package
[at godoc.org][3], or through go's standard documentation system by [at godoc.org][3], or through go's standard documentation system by
running `godoc -http=:6060` and browsing to running `godoc -http=:6060` and browsing to
[http://localhost:6060/pkg/github.com/ogier/pflag][2] after [http://localhost:6060/pkg/github.com/spf13/pflag][2] after
installation. installation.
[2]: http://localhost:6060/pkg/github.com/ogier/pflag [2]: http://localhost:6060/pkg/github.com/spf13/pflag
[3]: http://godoc.org/github.com/ogier/pflag [3]: http://godoc.org/github.com/spf13/pflag

View File

@ -11,13 +11,13 @@ func newCountValue(val int, p *int) *countValue {
} }
func (i *countValue) Set(s string) error { func (i *countValue) Set(s string) error {
v, err := strconv.ParseInt(s, 0, 64) // "+1" means that no specific value was passed, so increment
// -1 means that no specific value was passed, so increment if s == "+1" {
if v == -1 {
*i = countValue(*i + 1) *i = countValue(*i + 1)
} else { return nil
*i = countValue(v)
} }
v, err := strconv.ParseInt(s, 0, 0)
*i = countValue(v)
return err return err
} }
@ -54,7 +54,7 @@ func (f *FlagSet) CountVar(p *int, name string, usage string) {
// CountVarP is like CountVar only take a shorthand for the flag name. // CountVarP is like CountVar only take a shorthand for the flag name.
func (f *FlagSet) CountVarP(p *int, name, shorthand string, usage string) { func (f *FlagSet) CountVarP(p *int, name, shorthand string, usage string) {
flag := f.VarPF(newCountValue(0, p), name, shorthand, usage) flag := f.VarPF(newCountValue(0, p), name, shorthand, usage)
flag.NoOptDefVal = "-1" flag.NoOptDefVal = "+1"
} }
// CountVar like CountVar only the flag is placed on the CommandLine instead of a given flag set // CountVar like CountVar only the flag is placed on the CommandLine instead of a given flag set
@ -83,7 +83,9 @@ func (f *FlagSet) CountP(name, shorthand string, usage string) *int {
return p return p
} }
// Count like Count only the flag is placed on the CommandLine isntead of a given flag set // Count defines a count flag with specified name, default value, and usage string.
// The return value is the address of an int variable that stores the value of the flag.
// A count flag will add 1 to its value evey time it is found on the command line
func Count(name string, usage string) *int { func Count(name string, usage string) *int {
return CommandLine.CountP(name, "", usage) return CommandLine.CountP(name, "", usage)
} }

282
vendor/github.com/spf13/pflag/flag.go generated vendored
View File

@ -16,9 +16,9 @@ pflag is a drop-in replacement of Go's native flag package. If you import
pflag under the name "flag" then all code should continue to function pflag under the name "flag" then all code should continue to function
with no changes. with no changes.
import flag "github.com/ogier/pflag" import flag "github.com/spf13/pflag"
There is one exception to this: if you directly instantiate the Flag struct There is one exception to this: if you directly instantiate the Flag struct
there is one more field "Shorthand" that you will need to set. there is one more field "Shorthand" that you will need to set.
Most code never instantiates this struct directly, and instead uses Most code never instantiates this struct directly, and instead uses
functions such as String(), BoolVar(), and Var(), and is therefore functions such as String(), BoolVar(), and Var(), and is therefore
@ -134,14 +134,21 @@ type FlagSet struct {
// a custom error handler. // a custom error handler.
Usage func() Usage func()
// SortFlags is used to indicate, if user wants to have sorted flags in
// help/usage messages.
SortFlags bool
name string name string
parsed bool parsed bool
actual map[NormalizedName]*Flag actual map[NormalizedName]*Flag
orderedActual []*Flag
sortedActual []*Flag
formal map[NormalizedName]*Flag formal map[NormalizedName]*Flag
orderedFormal []*Flag
sortedFormal []*Flag
shorthands map[byte]*Flag shorthands map[byte]*Flag
args []string // arguments after flags args []string // arguments after flags
argsLenAtDash int // len(args) when a '--' was located when parsing, or -1 if no -- argsLenAtDash int // len(args) when a '--' was located when parsing, or -1 if no --
exitOnError bool // does the program exit if there's an error?
errorHandling ErrorHandling errorHandling ErrorHandling
output io.Writer // nil means stderr; use out() accessor output io.Writer // nil means stderr; use out() accessor
interspersed bool // allow interspersed option/non-option args interspersed bool // allow interspersed option/non-option args
@ -156,7 +163,7 @@ type Flag struct {
Value Value // value as set Value Value // value as set
DefValue string // default value (as text); for usage message DefValue string // default value (as text); for usage message
Changed bool // If the user set the value (or if left to default) Changed bool // If the user set the value (or if left to default)
NoOptDefVal string //default value (as text); if the flag is on the command line without any options NoOptDefVal string // default value (as text); if the flag is on the command line without any options
Deprecated string // If this flag is deprecated, this string is the new or now thing to use Deprecated string // If this flag is deprecated, this string is the new or now thing to use
Hidden bool // used by cobra.Command to allow flags to be hidden from help/usage text Hidden bool // used by cobra.Command to allow flags to be hidden from help/usage text
ShorthandDeprecated string // If the shorthand of this flag is deprecated, this string is the new or now thing to use ShorthandDeprecated string // If the shorthand of this flag is deprecated, this string is the new or now thing to use
@ -194,11 +201,19 @@ func sortFlags(flags map[NormalizedName]*Flag) []*Flag {
// "--getUrl" which may also be translated to "geturl" and everything will work. // "--getUrl" which may also be translated to "geturl" and everything will work.
func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) { func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) {
f.normalizeNameFunc = n f.normalizeNameFunc = n
for k, v := range f.formal { f.sortedFormal = f.sortedFormal[:0]
delete(f.formal, k) for fname, flag := range f.formal {
nname := f.normalizeFlagName(string(k)) nname := f.normalizeFlagName(flag.Name)
f.formal[nname] = v if fname == nname {
v.Name = string(nname) continue
}
flag.Name = string(nname)
delete(f.formal, fname)
f.formal[nname] = flag
if _, set := f.actual[fname]; set {
delete(f.actual, fname)
f.actual[nname] = flag
}
} }
} }
@ -229,10 +244,25 @@ func (f *FlagSet) SetOutput(output io.Writer) {
f.output = output f.output = output
} }
// VisitAll visits the flags in lexicographical order, calling fn for each. // VisitAll visits the flags in lexicographical order or
// in primordial order if f.SortFlags is false, calling fn for each.
// It visits all flags, even those not set. // It visits all flags, even those not set.
func (f *FlagSet) VisitAll(fn func(*Flag)) { func (f *FlagSet) VisitAll(fn func(*Flag)) {
for _, flag := range sortFlags(f.formal) { if len(f.formal) == 0 {
return
}
var flags []*Flag
if f.SortFlags {
if len(f.formal) != len(f.sortedFormal) {
f.sortedFormal = sortFlags(f.formal)
}
flags = f.sortedFormal
} else {
flags = f.orderedFormal
}
for _, flag := range flags {
fn(flag) fn(flag)
} }
} }
@ -253,22 +283,39 @@ func (f *FlagSet) HasAvailableFlags() bool {
return false return false
} }
// VisitAll visits the command-line flags in lexicographical order, calling // VisitAll visits the command-line flags in lexicographical order or
// fn for each. It visits all flags, even those not set. // in primordial order if f.SortFlags is false, calling fn for each.
// It visits all flags, even those not set.
func VisitAll(fn func(*Flag)) { func VisitAll(fn func(*Flag)) {
CommandLine.VisitAll(fn) CommandLine.VisitAll(fn)
} }
// Visit visits the flags in lexicographical order, calling fn for each. // Visit visits the flags in lexicographical order or
// in primordial order if f.SortFlags is false, calling fn for each.
// It visits only those flags that have been set. // It visits only those flags that have been set.
func (f *FlagSet) Visit(fn func(*Flag)) { func (f *FlagSet) Visit(fn func(*Flag)) {
for _, flag := range sortFlags(f.actual) { if len(f.actual) == 0 {
return
}
var flags []*Flag
if f.SortFlags {
if len(f.actual) != len(f.sortedActual) {
f.sortedActual = sortFlags(f.actual)
}
flags = f.sortedActual
} else {
flags = f.orderedActual
}
for _, flag := range flags {
fn(flag) fn(flag)
} }
} }
// Visit visits the command-line flags in lexicographical order, calling fn // Visit visits the command-line flags in lexicographical order or
// for each. It visits only those flags that have been set. // in primordial order if f.SortFlags is false, calling fn for each.
// It visits only those flags that have been set.
func Visit(fn func(*Flag)) { func Visit(fn func(*Flag)) {
CommandLine.Visit(fn) CommandLine.Visit(fn)
} }
@ -278,6 +325,22 @@ func (f *FlagSet) Lookup(name string) *Flag {
return f.lookup(f.normalizeFlagName(name)) return f.lookup(f.normalizeFlagName(name))
} }
// ShorthandLookup returns the Flag structure of the short handed flag,
// returning nil if none exists.
// It panics, if len(name) > 1.
func (f *FlagSet) ShorthandLookup(name string) *Flag {
if name == "" {
return nil
}
if len(name) > 1 {
msg := fmt.Sprintf("can not look up shorthand which is more than one ASCII character: %q", name)
fmt.Fprintf(f.out(), msg)
panic(msg)
}
c := name[0]
return f.shorthands[c]
}
// lookup returns the Flag structure of the named flag, returning nil if none exists. // lookup returns the Flag structure of the named flag, returning nil if none exists.
func (f *FlagSet) lookup(name NormalizedName) *Flag { func (f *FlagSet) lookup(name NormalizedName) *Flag {
return f.formal[name] return f.formal[name]
@ -319,7 +382,7 @@ func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error {
if flag == nil { if flag == nil {
return fmt.Errorf("flag %q does not exist", name) return fmt.Errorf("flag %q does not exist", name)
} }
if len(usageMessage) == 0 { if usageMessage == "" {
return fmt.Errorf("deprecated message for flag %q must be set", name) return fmt.Errorf("deprecated message for flag %q must be set", name)
} }
flag.Deprecated = usageMessage flag.Deprecated = usageMessage
@ -334,7 +397,7 @@ func (f *FlagSet) MarkShorthandDeprecated(name string, usageMessage string) erro
if flag == nil { if flag == nil {
return fmt.Errorf("flag %q does not exist", name) return fmt.Errorf("flag %q does not exist", name)
} }
if len(usageMessage) == 0 { if usageMessage == "" {
return fmt.Errorf("deprecated message for flag %q must be set", name) return fmt.Errorf("deprecated message for flag %q must be set", name)
} }
flag.ShorthandDeprecated = usageMessage flag.ShorthandDeprecated = usageMessage
@ -358,6 +421,12 @@ func Lookup(name string) *Flag {
return CommandLine.Lookup(name) return CommandLine.Lookup(name)
} }
// ShorthandLookup returns the Flag structure of the short handed flag,
// returning nil if none exists.
func ShorthandLookup(name string) *Flag {
return CommandLine.ShorthandLookup(name)
}
// Set sets the value of the named flag. // Set sets the value of the named flag.
func (f *FlagSet) Set(name, value string) error { func (f *FlagSet) Set(name, value string) error {
normalName := f.normalizeFlagName(name) normalName := f.normalizeFlagName(name)
@ -365,17 +434,30 @@ func (f *FlagSet) Set(name, value string) error {
if !ok { if !ok {
return fmt.Errorf("no such flag -%v", name) return fmt.Errorf("no such flag -%v", name)
} }
err := flag.Value.Set(value) err := flag.Value.Set(value)
if err != nil { if err != nil {
return err var flagName string
if flag.Shorthand != "" && flag.ShorthandDeprecated == "" {
flagName = fmt.Sprintf("-%s, --%s", flag.Shorthand, flag.Name)
} else {
flagName = fmt.Sprintf("--%s", flag.Name)
}
return fmt.Errorf("invalid argument %q for %q flag: %v", value, flagName, err)
} }
if f.actual == nil {
f.actual = make(map[NormalizedName]*Flag) if !flag.Changed {
if f.actual == nil {
f.actual = make(map[NormalizedName]*Flag)
}
f.actual[normalName] = flag
f.orderedActual = append(f.orderedActual, flag)
flag.Changed = true
} }
f.actual[normalName] = flag
flag.Changed = true if flag.Deprecated != "" {
if len(flag.Deprecated) > 0 { fmt.Fprintf(f.out(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
fmt.Fprintf(os.Stderr, "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
} }
return nil return nil
} }
@ -482,6 +564,10 @@ func UnquoteUsage(flag *Flag) (name string, usage string) {
name = "int" name = "int"
case "uint64": case "uint64":
name = "uint" name = "uint"
case "stringSlice":
name = "strings"
case "intSlice":
name = "ints"
} }
return return
@ -557,28 +643,28 @@ func wrap(i, w int, s string) string {
// for all flags in the FlagSet. Wrapped to `cols` columns (0 for no // for all flags in the FlagSet. Wrapped to `cols` columns (0 for no
// wrapping) // wrapping)
func (f *FlagSet) FlagUsagesWrapped(cols int) string { func (f *FlagSet) FlagUsagesWrapped(cols int) string {
x := new(bytes.Buffer) buf := new(bytes.Buffer)
lines := make([]string, 0, len(f.formal)) lines := make([]string, 0, len(f.formal))
maxlen := 0 maxlen := 0
f.VisitAll(func(flag *Flag) { f.VisitAll(func(flag *Flag) {
if len(flag.Deprecated) > 0 || flag.Hidden { if flag.Deprecated != "" || flag.Hidden {
return return
} }
line := "" line := ""
if len(flag.Shorthand) > 0 && len(flag.ShorthandDeprecated) == 0 { if flag.Shorthand != "" && flag.ShorthandDeprecated == "" {
line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name) line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name)
} else { } else {
line = fmt.Sprintf(" --%s", flag.Name) line = fmt.Sprintf(" --%s", flag.Name)
} }
varname, usage := UnquoteUsage(flag) varname, usage := UnquoteUsage(flag)
if len(varname) > 0 { if varname != "" {
line += " " + varname line += " " + varname
} }
if len(flag.NoOptDefVal) > 0 { if flag.NoOptDefVal != "" {
switch flag.Value.Type() { switch flag.Value.Type() {
case "string": case "string":
line += fmt.Sprintf("[=\"%s\"]", flag.NoOptDefVal) line += fmt.Sprintf("[=\"%s\"]", flag.NoOptDefVal)
@ -586,6 +672,10 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string {
if flag.NoOptDefVal != "true" { if flag.NoOptDefVal != "true" {
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
} }
case "count":
if flag.NoOptDefVal != "+1" {
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
}
default: default:
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
} }
@ -601,7 +691,7 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string {
line += usage line += usage
if !flag.defaultIsZeroValue() { if !flag.defaultIsZeroValue() {
if flag.Value.Type() == "string" { if flag.Value.Type() == "string" {
line += fmt.Sprintf(" (default \"%s\")", flag.DefValue) line += fmt.Sprintf(" (default %q)", flag.DefValue)
} else { } else {
line += fmt.Sprintf(" (default %s)", flag.DefValue) line += fmt.Sprintf(" (default %s)", flag.DefValue)
} }
@ -614,10 +704,10 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string {
sidx := strings.Index(line, "\x00") sidx := strings.Index(line, "\x00")
spacing := strings.Repeat(" ", maxlen-sidx) spacing := strings.Repeat(" ", maxlen-sidx)
// maxlen + 2 comes from + 1 for the \x00 and + 1 for the (deliberate) off-by-one in maxlen-sidx // maxlen + 2 comes from + 1 for the \x00 and + 1 for the (deliberate) off-by-one in maxlen-sidx
fmt.Fprintln(x, line[:sidx], spacing, wrap(maxlen+2, cols, line[sidx+1:])) fmt.Fprintln(buf, line[:sidx], spacing, wrap(maxlen+2, cols, line[sidx+1:]))
} }
return x.String() return buf.String()
} }
// FlagUsages returns a string containing the usage information for all flags in // FlagUsages returns a string containing the usage information for all flags in
@ -714,11 +804,10 @@ func (f *FlagSet) VarP(value Value, name, shorthand, usage string) {
// AddFlag will add the flag to the FlagSet // AddFlag will add the flag to the FlagSet
func (f *FlagSet) AddFlag(flag *Flag) { func (f *FlagSet) AddFlag(flag *Flag) {
// Call normalizeFlagName function only once
normalizedFlagName := f.normalizeFlagName(flag.Name) normalizedFlagName := f.normalizeFlagName(flag.Name)
_, alreadythere := f.formal[normalizedFlagName] _, alreadyThere := f.formal[normalizedFlagName]
if alreadythere { if alreadyThere {
msg := fmt.Sprintf("%s flag redefined: %s", f.name, flag.Name) msg := fmt.Sprintf("%s flag redefined: %s", f.name, flag.Name)
fmt.Fprintln(f.out(), msg) fmt.Fprintln(f.out(), msg)
panic(msg) // Happens only if flags are declared with identical names panic(msg) // Happens only if flags are declared with identical names
@ -729,28 +818,31 @@ func (f *FlagSet) AddFlag(flag *Flag) {
flag.Name = string(normalizedFlagName) flag.Name = string(normalizedFlagName)
f.formal[normalizedFlagName] = flag f.formal[normalizedFlagName] = flag
f.orderedFormal = append(f.orderedFormal, flag)
if len(flag.Shorthand) == 0 { if flag.Shorthand == "" {
return return
} }
if len(flag.Shorthand) > 1 { if len(flag.Shorthand) > 1 {
fmt.Fprintf(f.out(), "%s shorthand more than ASCII character: %s\n", f.name, flag.Shorthand) msg := fmt.Sprintf("%q shorthand is more than one ASCII character", flag.Shorthand)
panic("shorthand is more than one character") fmt.Fprintf(f.out(), msg)
panic(msg)
} }
if f.shorthands == nil { if f.shorthands == nil {
f.shorthands = make(map[byte]*Flag) f.shorthands = make(map[byte]*Flag)
} }
c := flag.Shorthand[0] c := flag.Shorthand[0]
old, alreadythere := f.shorthands[c] used, alreadyThere := f.shorthands[c]
if alreadythere { if alreadyThere {
fmt.Fprintf(f.out(), "%s shorthand reused: %q for %s already used for %s\n", f.name, c, flag.Name, old.Name) msg := fmt.Sprintf("unable to redefine %q shorthand in %q flagset: it's already used for %q flag", c, f.name, used.Name)
panic("shorthand redefinition") fmt.Fprintf(f.out(), msg)
panic(msg)
} }
f.shorthands[c] = flag f.shorthands[c] = flag
} }
// AddFlagSet adds one FlagSet to another. If a flag is already present in f // AddFlagSet adds one FlagSet to another. If a flag is already present in f
// the flag from newSet will be ignored // the flag from newSet will be ignored.
func (f *FlagSet) AddFlagSet(newSet *FlagSet) { func (f *FlagSet) AddFlagSet(newSet *FlagSet) {
if newSet == nil { if newSet == nil {
return return
@ -781,8 +873,10 @@ func VarP(value Value, name, shorthand, usage string) {
// returns the error. // returns the error.
func (f *FlagSet) failf(format string, a ...interface{}) error { func (f *FlagSet) failf(format string, a ...interface{}) error {
err := fmt.Errorf(format, a...) err := fmt.Errorf(format, a...)
fmt.Fprintln(f.out(), err) if f.errorHandling != ContinueOnError {
f.usage() fmt.Fprintln(f.out(), err)
f.usage()
}
return err return err
} }
@ -798,34 +892,6 @@ func (f *FlagSet) usage() {
} }
} }
func (f *FlagSet) setFlag(flag *Flag, value string, origArg string) error {
if err := flag.Value.Set(value); err != nil {
return f.failf("invalid argument %q for %s: %v", value, origArg, err)
}
// mark as visited for Visit()
if f.actual == nil {
f.actual = make(map[NormalizedName]*Flag)
}
f.actual[f.normalizeFlagName(flag.Name)] = flag
flag.Changed = true
if len(flag.Deprecated) > 0 {
fmt.Fprintf(os.Stderr, "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
}
if len(flag.ShorthandDeprecated) > 0 && containsShorthand(origArg, flag.Shorthand) {
fmt.Fprintf(os.Stderr, "Flag shorthand -%s has been deprecated, %s\n", flag.Shorthand, flag.ShorthandDeprecated)
}
return nil
}
func containsShorthand(arg, shorthand string) bool {
// filter out flags --<flag_name>
if strings.HasPrefix(arg, "-") {
return false
}
arg = strings.SplitN(arg, "=", 2)[0]
return strings.Contains(arg, shorthand)
}
func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []string, err error) { func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []string, err error) {
a = args a = args
name := s[2:] name := s[2:]
@ -833,10 +899,11 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin
err = f.failf("bad flag syntax: %s", s) err = f.failf("bad flag syntax: %s", s)
return return
} }
split := strings.SplitN(name, "=", 2) split := strings.SplitN(name, "=", 2)
name = split[0] name = split[0]
flag, alreadythere := f.formal[f.normalizeFlagName(name)] flag, exists := f.formal[f.normalizeFlagName(name)]
if !alreadythere { if !exists {
if name == "help" { // special case for nice help message. if name == "help" { // special case for nice help message.
f.usage() f.usage()
return a, ErrHelp return a, ErrHelp
@ -844,11 +911,12 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin
err = f.failf("unknown flag: --%s", name) err = f.failf("unknown flag: --%s", name)
return return
} }
var value string var value string
if len(split) == 2 { if len(split) == 2 {
// '--flag=arg' // '--flag=arg'
value = split[1] value = split[1]
} else if len(flag.NoOptDefVal) > 0 { } else if flag.NoOptDefVal != "" {
// '--flag' (arg was optional) // '--flag' (arg was optional)
value = flag.NoOptDefVal value = flag.NoOptDefVal
} else if len(a) > 0 { } else if len(a) > 0 {
@ -860,7 +928,11 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin
err = f.failf("flag needs an argument: %s", s) err = f.failf("flag needs an argument: %s", s)
return return
} }
err = fn(flag, value, s)
err = fn(flag, value)
if err != nil {
f.failf(err.Error())
}
return return
} }
@ -868,38 +940,52 @@ func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parse
if strings.HasPrefix(shorthands, "test.") { if strings.HasPrefix(shorthands, "test.") {
return return
} }
outArgs = args outArgs = args
outShorts = shorthands[1:] outShorts = shorthands[1:]
c := shorthands[0] c := shorthands[0]
flag, alreadythere := f.shorthands[c] flag, exists := f.shorthands[c]
if !alreadythere { if !exists {
if c == 'h' { // special case for nice help message. if c == 'h' { // special case for nice help message.
f.usage() f.usage()
err = ErrHelp err = ErrHelp
return return
} }
//TODO continue on error
err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands) err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands)
return return
} }
var value string var value string
if len(shorthands) > 2 && shorthands[1] == '=' { if len(shorthands) > 2 && shorthands[1] == '=' {
// '-f=arg'
value = shorthands[2:] value = shorthands[2:]
outShorts = "" outShorts = ""
} else if len(flag.NoOptDefVal) > 0 { } else if flag.NoOptDefVal != "" {
// '-f' (arg was optional)
value = flag.NoOptDefVal value = flag.NoOptDefVal
} else if len(shorthands) > 1 { } else if len(shorthands) > 1 {
// '-farg'
value = shorthands[1:] value = shorthands[1:]
outShorts = "" outShorts = ""
} else if len(args) > 0 { } else if len(args) > 0 {
// '-f arg'
value = args[0] value = args[0]
outArgs = args[1:] outArgs = args[1:]
} else { } else {
// '-f' (arg was required)
err = f.failf("flag needs an argument: %q in -%s", c, shorthands) err = f.failf("flag needs an argument: %q in -%s", c, shorthands)
return return
} }
err = fn(flag, value, shorthands)
if flag.ShorthandDeprecated != "" {
fmt.Fprintf(f.out(), "Flag shorthand -%s has been deprecated, %s\n", flag.Shorthand, flag.ShorthandDeprecated)
}
err = fn(flag, value)
if err != nil {
f.failf(err.Error())
}
return return
} }
@ -907,6 +993,7 @@ func (f *FlagSet) parseShortArg(s string, args []string, fn parseFunc) (a []stri
a = args a = args
shorthands := s[1:] shorthands := s[1:]
// "shorthands" can be a series of shorthand letters of flags (e.g. "-vvv").
for len(shorthands) > 0 { for len(shorthands) > 0 {
shorthands, a, err = f.parseSingleShortArg(shorthands, args, fn) shorthands, a, err = f.parseSingleShortArg(shorthands, args, fn)
if err != nil { if err != nil {
@ -954,18 +1041,24 @@ func (f *FlagSet) parseArgs(args []string, fn parseFunc) (err error) {
// The return value will be ErrHelp if -help was set but not defined. // The return value will be ErrHelp if -help was set but not defined.
func (f *FlagSet) Parse(arguments []string) error { func (f *FlagSet) Parse(arguments []string) error {
f.parsed = true f.parsed = true
f.args = make([]string, 0, len(arguments))
assign := func(flag *Flag, value, origArg string) error { if len(arguments) < 0 {
return f.setFlag(flag, value, origArg) return nil
} }
err := f.parseArgs(arguments, assign) f.args = make([]string, 0, len(arguments))
set := func(flag *Flag, value string) error {
return f.Set(flag.Name, value)
}
err := f.parseArgs(arguments, set)
if err != nil { if err != nil {
switch f.errorHandling { switch f.errorHandling {
case ContinueOnError: case ContinueOnError:
return err return err
case ExitOnError: case ExitOnError:
fmt.Println(err)
os.Exit(2) os.Exit(2)
case PanicOnError: case PanicOnError:
panic(err) panic(err)
@ -974,7 +1067,7 @@ func (f *FlagSet) Parse(arguments []string) error {
return nil return nil
} }
type parseFunc func(flag *Flag, value, origArg string) error type parseFunc func(flag *Flag, value string) error
// ParseAll parses flag definitions from the argument list, which should not // ParseAll parses flag definitions from the argument list, which should not
// include the command name. The arguments for fn are flag and value. Must be // include the command name. The arguments for fn are flag and value. Must be
@ -985,11 +1078,7 @@ func (f *FlagSet) ParseAll(arguments []string, fn func(flag *Flag, value string)
f.parsed = true f.parsed = true
f.args = make([]string, 0, len(arguments)) f.args = make([]string, 0, len(arguments))
assign := func(flag *Flag, value, origArg string) error { err := f.parseArgs(arguments, fn)
return fn(flag, value)
}
err := f.parseArgs(arguments, assign)
if err != nil { if err != nil {
switch f.errorHandling { switch f.errorHandling {
case ContinueOnError: case ContinueOnError:
@ -1036,14 +1125,15 @@ func Parsed() bool {
// CommandLine is the default set of command-line flags, parsed from os.Args. // CommandLine is the default set of command-line flags, parsed from os.Args.
var CommandLine = NewFlagSet(os.Args[0], ExitOnError) var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
// NewFlagSet returns a new, empty flag set with the specified name and // NewFlagSet returns a new, empty flag set with the specified name,
// error handling property. // error handling property and SortFlags set to true.
func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet { func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
f := &FlagSet{ f := &FlagSet{
name: name, name: name,
errorHandling: errorHandling, errorHandling: errorHandling,
argsLenAtDash: -1, argsLenAtDash: -1,
interspersed: true, interspersed: true,
SortFlags: true,
} }
return f return f
} }

88
vendor/github.com/spf13/pflag/int16.go generated vendored Normal file
View File

@ -0,0 +1,88 @@
package pflag
import "strconv"
// -- int16 Value
type int16Value int16
func newInt16Value(val int16, p *int16) *int16Value {
*p = val
return (*int16Value)(p)
}
func (i *int16Value) Set(s string) error {
v, err := strconv.ParseInt(s, 0, 16)
*i = int16Value(v)
return err
}
func (i *int16Value) Type() string {
return "int16"
}
func (i *int16Value) String() string { return strconv.FormatInt(int64(*i), 10) }
func int16Conv(sval string) (interface{}, error) {
v, err := strconv.ParseInt(sval, 0, 16)
if err != nil {
return 0, err
}
return int16(v), nil
}
// GetInt16 returns the int16 value of a flag with the given name
func (f *FlagSet) GetInt16(name string) (int16, error) {
val, err := f.getFlagType(name, "int16", int16Conv)
if err != nil {
return 0, err
}
return val.(int16), nil
}
// Int16Var defines an int16 flag with specified name, default value, and usage string.
// The argument p points to an int16 variable in which to store the value of the flag.
func (f *FlagSet) Int16Var(p *int16, name string, value int16, usage string) {
f.VarP(newInt16Value(value, p), name, "", usage)
}
// Int16VarP is like Int16Var, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Int16VarP(p *int16, name, shorthand string, value int16, usage string) {
f.VarP(newInt16Value(value, p), name, shorthand, usage)
}
// Int16Var defines an int16 flag with specified name, default value, and usage string.
// The argument p points to an int16 variable in which to store the value of the flag.
func Int16Var(p *int16, name string, value int16, usage string) {
CommandLine.VarP(newInt16Value(value, p), name, "", usage)
}
// Int16VarP is like Int16Var, but accepts a shorthand letter that can be used after a single dash.
func Int16VarP(p *int16, name, shorthand string, value int16, usage string) {
CommandLine.VarP(newInt16Value(value, p), name, shorthand, usage)
}
// Int16 defines an int16 flag with specified name, default value, and usage string.
// The return value is the address of an int16 variable that stores the value of the flag.
func (f *FlagSet) Int16(name string, value int16, usage string) *int16 {
p := new(int16)
f.Int16VarP(p, name, "", value, usage)
return p
}
// Int16P is like Int16, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Int16P(name, shorthand string, value int16, usage string) *int16 {
p := new(int16)
f.Int16VarP(p, name, shorthand, value, usage)
return p
}
// Int16 defines an int16 flag with specified name, default value, and usage string.
// The return value is the address of an int16 variable that stores the value of the flag.
func Int16(name string, value int16, usage string) *int16 {
return CommandLine.Int16P(name, "", value, usage)
}
// Int16P is like Int16, but accepts a shorthand letter that can be used after a single dash.
func Int16P(name, shorthand string, value int16, usage string) *int16 {
return CommandLine.Int16P(name, shorthand, value, usage)
}