mirror of https://github.com/docker/cli.git
Merge pull request #642 from dnephin/use-upstream-spf13-cobra
Use upstream spf13 cobra
This commit is contained in:
commit
e59f3e2925
13
cli/cobra.go
13
cli/cobra.go
|
@ -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 }}
|
||||||
|
|
|
@ -13,7 +13,7 @@ func NewCheckpointCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
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),
|
||||||
|
|
|
@ -15,7 +15,7 @@ func NewConfigCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||||
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),
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -18,7 +18,7 @@ func NewNodeCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
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),
|
||||||
|
|
|
@ -14,7 +14,7 @@ func NewPluginCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||||
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(
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -15,7 +15,7 @@ func NewSecretCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||||
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),
|
||||||
|
|
|
@ -15,7 +15,7 @@ func NewServiceCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||||
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),
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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"}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ func NewStackCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -15,7 +15,7 @@ func NewSwarmCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
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),
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -13,7 +13,7 @@ func NewVolumeCommand(dockerCli command.Cli) *cobra.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),
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -8,6 +8,7 @@ Many of the most widely used Go projects are built using Cobra including:
|
||||||
* [Hugo](http://gohugo.io)
|
* [Hugo](http://gohugo.io)
|
||||||
* [rkt](https://github.com/coreos/rkt)
|
* [rkt](https://github.com/coreos/rkt)
|
||||||
* [etcd](https://github.com/coreos/etcd)
|
* [etcd](https://github.com/coreos/etcd)
|
||||||
|
* [Moby (former Docker)](https://github.com/moby/moby)
|
||||||
* [Docker (distribution)](https://github.com/docker/distribution)
|
* [Docker (distribution)](https://github.com/docker/distribution)
|
||||||
* [OpenShift](https://www.openshift.com/)
|
* [OpenShift](https://www.openshift.com/)
|
||||||
* [Delve](https://github.com/derekparker/delve)
|
* [Delve](https://github.com/derekparker/delve)
|
||||||
|
@ -15,16 +16,36 @@ Many of the most widely used Go projects are built using Cobra including:
|
||||||
* [CockroachDB](http://www.cockroachlabs.com/)
|
* [CockroachDB](http://www.cockroachlabs.com/)
|
||||||
* [Bleve](http://www.blevesearch.com/)
|
* [Bleve](http://www.blevesearch.com/)
|
||||||
* [ProjectAtomic (enterprise)](http://www.projectatomic.io/)
|
* [ProjectAtomic (enterprise)](http://www.projectatomic.io/)
|
||||||
* [Parse (CLI)](https://parse.com/)
|
|
||||||
* [GiantSwarm's swarm](https://github.com/giantswarm/cli)
|
* [GiantSwarm's swarm](https://github.com/giantswarm/cli)
|
||||||
* [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack)
|
* [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack)
|
||||||
|
* [rclone](http://rclone.org/)
|
||||||
|
* [nehm](https://github.com/bogem/nehm)
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/spf13/cobra.svg "Travis CI status")](https://travis-ci.org/spf13/cobra)
|
[![Build Status](https://travis-ci.org/spf13/cobra.svg "Travis CI status")](https://travis-ci.org/spf13/cobra)
|
||||||
[![CircleCI status](https://circleci.com/gh/spf13/cobra.png?circle-token=:circle-token "CircleCI status")](https://circleci.com/gh/spf13/cobra)
|
[![CircleCI status](https://circleci.com/gh/spf13/cobra.png?circle-token=:circle-token "CircleCI status")](https://circleci.com/gh/spf13/cobra)
|
||||||
[![GoDoc](https://godoc.org/github.com/spf13/cobra?status.svg)](https://godoc.org/github.com/spf13/cobra)
|
[![GoDoc](https://godoc.org/github.com/spf13/cobra?status.svg)](https://godoc.org/github.com/spf13/cobra)
|
||||||
|
|
||||||
![cobra](https://cloud.githubusercontent.com/assets/173412/10911369/84832a8e-8212-11e5-9f82-cc96660a4794.gif)
|
# Table of Contents
|
||||||
|
|
||||||
|
- [Overview](#overview)
|
||||||
|
- [Concepts](#concepts)
|
||||||
|
* [Commands](#commands)
|
||||||
|
* [Flags](#flags)
|
||||||
|
- [Installing](#installing)
|
||||||
|
- [Getting Started](#getting-started)
|
||||||
|
* [Using the Cobra Generator](#using-the-cobra-generator)
|
||||||
|
* [Using the Cobra Library](#using-the-cobra-library)
|
||||||
|
* [Working with Flags](#working-with-flags)
|
||||||
|
* [Positional and Custom Arguments](#positional-and-custom-arguments)
|
||||||
|
* [Example](#example)
|
||||||
|
* [Help Command](#help-command)
|
||||||
|
* [Usage Message](#usage-message)
|
||||||
|
* [PreRun and PostRun Hooks](#prerun-and-postrun-hooks)
|
||||||
|
* [Suggestions when "unknown command" happens](#suggestions-when-unknown-command-happens)
|
||||||
|
* [Generating documentation for your command](#generating-documentation-for-your-command)
|
||||||
|
* [Generating bash completions](#generating-bash-completions)
|
||||||
|
- [Contributing](#contributing)
|
||||||
|
- [License](#license)
|
||||||
|
|
||||||
# Overview
|
# Overview
|
||||||
|
|
||||||
|
@ -39,27 +60,16 @@ Cobra provides:
|
||||||
* Fully POSIX-compliant flags (including short & long versions)
|
* Fully POSIX-compliant flags (including short & long versions)
|
||||||
* Nested subcommands
|
* Nested subcommands
|
||||||
* Global, local and cascading flags
|
* Global, local and cascading flags
|
||||||
* Easy generation of applications & commands with `cobra create appname` & `cobra add cmdname`
|
* Easy generation of applications & commands with `cobra init appname` & `cobra add cmdname`
|
||||||
* Intelligent suggestions (`app srver`... did you mean `app server`?)
|
* Intelligent suggestions (`app srver`... did you mean `app server`?)
|
||||||
* Automatic help generation for commands and flags
|
* Automatic help generation for commands and flags
|
||||||
* Automatic detailed help for `app help [command]`
|
|
||||||
* Automatic help flag recognition of `-h`, `--help`, etc.
|
* Automatic help flag recognition of `-h`, `--help`, etc.
|
||||||
* Automatically generated bash autocomplete for your application
|
* Automatically generated bash autocomplete for your application
|
||||||
* Automatically generated man pages for your application
|
* Automatically generated man pages for your application
|
||||||
* Command aliases so you can change things without breaking them
|
* Command aliases so you can change things without breaking them
|
||||||
* The flexibilty to define your own help, usage, etc.
|
* The flexibility to define your own help, usage, etc.
|
||||||
* Optional tight integration with [viper](http://github.com/spf13/viper) for 12-factor apps
|
* Optional tight integration with [viper](http://github.com/spf13/viper) for 12-factor apps
|
||||||
|
|
||||||
Cobra has an exceptionally clean interface and simple design without needless
|
|
||||||
constructors or initialization methods.
|
|
||||||
|
|
||||||
Applications built with Cobra commands are designed to be as user-friendly as
|
|
||||||
possible. Flags can be placed before or after the command (as long as a
|
|
||||||
confusing space isn’t provided). Both short and long flags can be used. A
|
|
||||||
command need not even be fully typed. Help is automatically generated and
|
|
||||||
available for the application or for a specific command using either the help
|
|
||||||
command or the `--help` flag.
|
|
||||||
|
|
||||||
# Concepts
|
# Concepts
|
||||||
|
|
||||||
Cobra is built on a structure of commands, arguments & flags.
|
Cobra is built on a structure of commands, arguments & flags.
|
||||||
|
@ -78,11 +88,11 @@ A few good real world examples may better illustrate this point.
|
||||||
|
|
||||||
In the following example, 'server' is a command, and 'port' is a flag:
|
In the following example, 'server' is a command, and 'port' is a flag:
|
||||||
|
|
||||||
> hugo server --port=1313
|
hugo server --port=1313
|
||||||
|
|
||||||
In this command we are telling Git to clone the url bare.
|
In this command we are telling Git to clone the url bare.
|
||||||
|
|
||||||
> git clone URL --bare
|
git clone URL --bare
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
|
@ -92,20 +102,11 @@ have children commands and optionally run an action.
|
||||||
|
|
||||||
In the example above, 'server' is the command.
|
In the example above, 'server' is the command.
|
||||||
|
|
||||||
A Command has the following structure:
|
[More about cobra.Command](https://godoc.org/github.com/spf13/cobra#Command)
|
||||||
|
|
||||||
```go
|
|
||||||
type Command struct {
|
|
||||||
Use string // The one-line usage message.
|
|
||||||
Short string // The short description shown in the 'help' output.
|
|
||||||
Long string // The long message shown in the 'help <this-command>' output.
|
|
||||||
Run func(cmd *Command, args []string) // Run runs the command.
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Flags
|
## Flags
|
||||||
|
|
||||||
A Flag is a way to modify the behavior of a command. Cobra supports
|
A flag is a way to modify the behavior of a command. Cobra supports
|
||||||
fully POSIX-compliant flags as well as the Go [flag package](https://golang.org/pkg/flag/).
|
fully POSIX-compliant flags as well as the Go [flag package](https://golang.org/pkg/flag/).
|
||||||
A Cobra command can define flags that persist through to children commands
|
A Cobra command can define flags that persist through to children commands
|
||||||
and flags that are only available to that command.
|
and flags that are only available to that command.
|
||||||
|
@ -113,23 +114,15 @@ and flags that are only available to that command.
|
||||||
In the example above, 'port' is the flag.
|
In the example above, 'port' is the flag.
|
||||||
|
|
||||||
Flag functionality is provided by the [pflag
|
Flag functionality is provided by the [pflag
|
||||||
library](https://github.com/ogier/pflag), a fork of the flag standard library
|
library](https://github.com/spf13/pflag), a fork of the flag standard library
|
||||||
which maintains the same interface while adding POSIX compliance.
|
which maintains the same interface while adding POSIX compliance.
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Cobra works by creating a set of commands and then organizing them into a tree.
|
|
||||||
The tree defines the structure of the application.
|
|
||||||
|
|
||||||
Once each command is defined with its corresponding flags, then the
|
|
||||||
tree is assigned to the commander which is finally executed.
|
|
||||||
|
|
||||||
# Installing
|
# Installing
|
||||||
Using Cobra is easy. First, use `go get` to install the latest version
|
Using Cobra is easy. First, use `go get` to install the latest version
|
||||||
of the library. This command will install the `cobra` generator executible
|
of the library. This command will install the `cobra` generator executable
|
||||||
along with the library:
|
along with the library and its dependencies:
|
||||||
|
|
||||||
> go get -v github.com/spf13/cobra/cobra
|
go get -u github.com/spf13/cobra/cobra
|
||||||
|
|
||||||
Next, include Cobra in your application:
|
Next, include Cobra in your application:
|
||||||
|
|
||||||
|
@ -139,8 +132,8 @@ import "github.com/spf13/cobra"
|
||||||
|
|
||||||
# Getting Started
|
# Getting Started
|
||||||
|
|
||||||
While you are welcome to provide your own organization, typically a Cobra based
|
While you are welcome to provide your own organization, typically a Cobra-based
|
||||||
application will follow the following organizational structure.
|
application will follow the following organizational structure:
|
||||||
|
|
||||||
```
|
```
|
||||||
▾ appName/
|
▾ appName/
|
||||||
|
@ -152,17 +145,22 @@ application will follow the following organizational structure.
|
||||||
main.go
|
main.go
|
||||||
```
|
```
|
||||||
|
|
||||||
In a Cobra app, typically the main.go file is very bare. It serves, one purpose, to initialize Cobra.
|
In a Cobra app, typically the main.go file is very bare. It serves one purpose: initializing Cobra.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "{pathToYourApp}/cmd"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"{pathToYourApp}/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if err := cmd.RootCmd.Execute(); err != nil {
|
if err := cmd.RootCmd.Execute(); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(-1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -172,93 +170,14 @@ func main() {
|
||||||
Cobra provides its own program that will create your application and add any
|
Cobra provides its own program that will create your application and add any
|
||||||
commands you want. It's the easiest way to incorporate Cobra into your application.
|
commands you want. It's the easiest way to incorporate Cobra into your application.
|
||||||
|
|
||||||
### cobra init
|
[Here](https://github.com/spf13/cobra/blob/master/cobra/README.md) you can find more information about it.
|
||||||
|
|
||||||
The `cobra init [yourApp]` command will create your initial application code
|
## Using the Cobra Library
|
||||||
for you. It is a very powerful application that will populate your program with
|
|
||||||
the right structure so you can immediately enjoy all the benefits of Cobra. It
|
|
||||||
will also automatically apply the license you specify to your application.
|
|
||||||
|
|
||||||
Cobra init is pretty smart. You can provide it a full path, or simply a path
|
To manually implement Cobra you need to create a bare main.go file and a RootCmd file.
|
||||||
similar to what is expected in the import.
|
|
||||||
|
|
||||||
```
|
|
||||||
cobra init github.com/spf13/newAppName
|
|
||||||
```
|
|
||||||
|
|
||||||
### cobra add
|
|
||||||
|
|
||||||
Once an application is initialized Cobra can create additional commands for you.
|
|
||||||
Let's say you created an app and you wanted the following commands for it:
|
|
||||||
|
|
||||||
* app serve
|
|
||||||
* app config
|
|
||||||
* app config create
|
|
||||||
|
|
||||||
In your project directory (where your main.go file is) you would run the following:
|
|
||||||
|
|
||||||
```
|
|
||||||
cobra add serve
|
|
||||||
cobra add config
|
|
||||||
cobra add create -p 'configCmd'
|
|
||||||
```
|
|
||||||
|
|
||||||
Once you have run these three commands you would have an app structure that would look like:
|
|
||||||
|
|
||||||
```
|
|
||||||
▾ app/
|
|
||||||
▾ cmd/
|
|
||||||
serve.go
|
|
||||||
config.go
|
|
||||||
create.go
|
|
||||||
main.go
|
|
||||||
```
|
|
||||||
|
|
||||||
at this point you can run `go run main.go` and it would run your app. `go run
|
|
||||||
main.go serve`, `go run main.go config`, `go run main.go config create` along
|
|
||||||
with `go run main.go help serve`, etc would all work.
|
|
||||||
|
|
||||||
Obviously you haven't added your own code to these yet, the commands are ready
|
|
||||||
for you to give them their tasks. Have fun.
|
|
||||||
|
|
||||||
### Configuring the cobra generator
|
|
||||||
|
|
||||||
The cobra generator will be easier to use if you provide a simple configuration
|
|
||||||
file which will help you eliminate providing a bunch of repeated information in
|
|
||||||
flags over and over.
|
|
||||||
|
|
||||||
An example ~/.cobra.yaml file:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
author: Steve Francia <spf@spf13.com>
|
|
||||||
license: MIT
|
|
||||||
```
|
|
||||||
|
|
||||||
You can specify no license by setting `license` to `none` or you can specify
|
|
||||||
a custom license:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
license:
|
|
||||||
header: This file is part of {{ .appName }}.
|
|
||||||
text: |
|
|
||||||
{{ .copyright }}
|
|
||||||
|
|
||||||
This is my license. There are many like it, but this one is mine.
|
|
||||||
My license is my best friend. It is my life. I must master it as I must
|
|
||||||
master my life.
|
|
||||||
```
|
|
||||||
|
|
||||||
## Manually implementing Cobra
|
|
||||||
|
|
||||||
To manually implement cobra you need to create a bare main.go file and a RootCmd file.
|
|
||||||
You will optionally provide additional commands as you see fit.
|
You will optionally provide additional commands as you see fit.
|
||||||
|
|
||||||
### Create the root command
|
### Create rootCmd
|
||||||
|
|
||||||
The root command represents your binary itself.
|
|
||||||
|
|
||||||
|
|
||||||
#### Manually create rootCmd
|
|
||||||
|
|
||||||
Cobra doesn't require any special constructors. Simply create your commands.
|
Cobra doesn't require any special constructors. Simply create your commands.
|
||||||
|
|
||||||
|
@ -279,9 +198,18 @@ var RootCmd = &cobra.Command{
|
||||||
|
|
||||||
You will additionally define flags and handle configuration in your init() function.
|
You will additionally define flags and handle configuration in your init() function.
|
||||||
|
|
||||||
for example cmd/root.go:
|
For example cmd/root.go:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
homedir "github.com/mitchellh/go-homedir"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cobra.OnInitialize(initConfig)
|
cobra.OnInitialize(initConfig)
|
||||||
RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
|
RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
|
||||||
|
@ -295,6 +223,34 @@ func init() {
|
||||||
viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
|
viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
|
||||||
viper.SetDefault("license", "apache")
|
viper.SetDefault("license", "apache")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Execute() {
|
||||||
|
RootCmd.Execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
func initConfig() {
|
||||||
|
// Don't forget to read config either from cfgFile or from home directory!
|
||||||
|
if cfgFile != "" {
|
||||||
|
// Use config file from the flag.
|
||||||
|
viper.SetConfigFile(cfgFile)
|
||||||
|
} else {
|
||||||
|
// Find home directory.
|
||||||
|
home, err := homedir.Dir()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search config in home directory with name ".cobra" (without extension).
|
||||||
|
viper.AddConfigPath(home)
|
||||||
|
viper.SetConfigName(".cobra")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := viper.ReadInConfig(); err != nil {
|
||||||
|
fmt.Println("Can't read config:", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Create your main.go
|
### Create your main.go
|
||||||
|
@ -307,17 +263,21 @@ In a Cobra app, typically the main.go file is very bare. It serves, one purpose,
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "{pathToYourApp}/cmd"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"{pathToYourApp}/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if err := cmd.RootCmd.Execute(); err != nil {
|
if err := cmd.RootCmd.Execute(); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(-1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Create additional commands
|
### Create additional commands
|
||||||
|
|
||||||
Additional commands can be defined and typically are each given their own file
|
Additional commands can be defined and typically are each given their own file
|
||||||
|
@ -331,6 +291,7 @@ package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -347,30 +308,6 @@ var versionCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Attach command to its parent
|
|
||||||
|
|
||||||
|
|
||||||
If you notice in the above example we attach the command to its parent. In
|
|
||||||
this case the parent is the rootCmd. In this example we are attaching it to the
|
|
||||||
root, but commands can be attached at any level.
|
|
||||||
|
|
||||||
```go
|
|
||||||
RootCmd.AddCommand(versionCmd)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Remove a command from its parent
|
|
||||||
|
|
||||||
Removing a command is not a common action in simple programs, but it allows 3rd
|
|
||||||
parties to customize an existing command tree.
|
|
||||||
|
|
||||||
In this example, we remove the existing `VersionCmd` command of an existing
|
|
||||||
root command, and we replace it with our own version:
|
|
||||||
|
|
||||||
```go
|
|
||||||
mainlib.RootCmd.RemoveCommand(mainlib.VersionCmd)
|
|
||||||
mainlib.RootCmd.AddCommand(versionCmd)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Working with Flags
|
## Working with Flags
|
||||||
|
|
||||||
Flags provide modifiers to control how the action command operates.
|
Flags provide modifiers to control how the action command operates.
|
||||||
|
@ -406,39 +343,68 @@ A flag can also be assigned locally which will only apply to that specific comma
|
||||||
RootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
|
RootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
|
||||||
```
|
```
|
||||||
|
|
||||||
### Positional Arguments
|
### Local Flag on Parent Commands
|
||||||
|
|
||||||
Validation of positional arguments can be specified using the `Args` field, which accepts
|
By default Cobra only parses local flags on the target command, any local flags on
|
||||||
one of the following values:
|
parent commands are ignored. By enabling `Command.TraverseChildren` Cobra will
|
||||||
|
parse local flags on each command before executing the target command.
|
||||||
|
|
||||||
|
```go
|
||||||
|
command := cobra.Command{
|
||||||
|
Use: "print [OPTIONS] [COMMANDS]",
|
||||||
|
TraverseChildren: true,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bind Flags with Config
|
||||||
|
|
||||||
|
You can also bind your flags with [viper](https://github.com/spf13/viper):
|
||||||
|
```go
|
||||||
|
var author string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution")
|
||||||
|
viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author"))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example the persistent flag `author` is bound with `viper`.
|
||||||
|
**Note**, that the variable `author` will not be set to the value from config,
|
||||||
|
when the `--author` flag is not provided by user.
|
||||||
|
|
||||||
|
More in [viper documentation](https://github.com/spf13/viper#working-with-flags).
|
||||||
|
|
||||||
|
## Positional and Custom Arguments
|
||||||
|
|
||||||
|
Validation of positional arguments can be specified using the `Args` field
|
||||||
|
of `Command`.
|
||||||
|
|
||||||
|
The following validators are built in:
|
||||||
|
|
||||||
- `NoArgs` - the command will report an error if there are any positional args.
|
- `NoArgs` - the command will report an error if there are any positional args.
|
||||||
- `ArbitraryArgs` - the command will accept any args.
|
- `ArbitraryArgs` - the command will accept any args.
|
||||||
- `OnlyValidArgs` - the command will report an error if there are any positiona
|
- `OnlyValidArgs` - the command will report an error if there are any positional args that are not in the `ValidArgs` field of `Command`.
|
||||||
args that are not in the `ValidArgs` list.
|
- `MinimumNArgs(int)` - the command will report an error if there are not at least N positional args.
|
||||||
- `MinimumNArgs(int)` - the command will report an error if there are not at
|
- `MaximumNArgs(int)` - the command will report an error if there are more than N positional args.
|
||||||
least N positional args.
|
- `ExactArgs(int)` - the command will report an error if there are not exactly N positional args.
|
||||||
- `MaximumNArgs(int)` - the command will report an error if there are more than
|
- `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args.
|
||||||
N positional args.
|
|
||||||
- `ExactArgs(int)` - the command will report an error if there are not
|
|
||||||
exactly N positional args.
|
|
||||||
- `RangeArgs(min, max)` - the command will report an error if the number of args
|
|
||||||
is not between the minimum and maximum number of expected args.
|
|
||||||
|
|
||||||
By default, `Args` uses the following legacy behaviour:
|
|
||||||
- root commands with no subcommands can take arbitrary arguments
|
|
||||||
- root commands with subcommands will do subcommand validity checking
|
|
||||||
- subcommands will always accept arbitrary arguments and do no subsubcommand validity checking
|
|
||||||
|
|
||||||
|
An example of setting the custom validator:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
var HugoCmd = &cobra.Command{
|
var cmd = &cobra.Command{
|
||||||
Use: "hugo",
|
Short: "hello",
|
||||||
Short: "Hugo is a very fast static site generator",
|
Args: func(cmd *cobra.Command, args []string) error {
|
||||||
ValidArgs: []string{"one", "two"}
|
if len(args) < 1 {
|
||||||
Args: cobra.OnlyValidArgs
|
return errors.New("requires at least one arg")
|
||||||
|
}
|
||||||
|
if myapp.IsValidColor(args[0]) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("invalid color specified: %s", args[0])
|
||||||
|
},
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
// args will only have the values one, two
|
fmt.Println("Hello, World!")
|
||||||
// or the cmd.Execute() will fail.
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -465,15 +431,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
var echoTimes int
|
var echoTimes int
|
||||||
|
|
||||||
var cmdPrint = &cobra.Command{
|
var cmdPrint = &cobra.Command{
|
||||||
Use: "print [string to print]",
|
Use: "print [string to print]",
|
||||||
Short: "Print anything to the screen",
|
Short: "Print anything to the screen",
|
||||||
Long: `print is for printing anything back to the screen.
|
Long: `print is for printing anything back to the screen.
|
||||||
For many years people have printed back to the screen.
|
For many years people have printed back to the screen.`,
|
||||||
`,
|
Args: cobra.MinimumNArgs(1),
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
fmt.Println("Print: " + strings.Join(args, " "))
|
fmt.Println("Print: " + strings.Join(args, " "))
|
||||||
},
|
},
|
||||||
|
@ -483,8 +448,8 @@ func main() {
|
||||||
Use: "echo [string to echo]",
|
Use: "echo [string to echo]",
|
||||||
Short: "Echo anything to the screen",
|
Short: "Echo anything to the screen",
|
||||||
Long: `echo is for echoing anything back.
|
Long: `echo is for echoing anything back.
|
||||||
Echo works a lot like print, except it has a child command.
|
Echo works a lot like print, except it has a child command.`,
|
||||||
`,
|
Args: cobra.MinimumNArgs(1),
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
fmt.Println("Print: " + strings.Join(args, " "))
|
fmt.Println("Print: " + strings.Join(args, " "))
|
||||||
},
|
},
|
||||||
|
@ -495,6 +460,7 @@ func main() {
|
||||||
Short: "Echo anything to the screen more times",
|
Short: "Echo anything to the screen more times",
|
||||||
Long: `echo things multiple times back to the user by providing
|
Long: `echo things multiple times back to the user by providing
|
||||||
a count and a string.`,
|
a count and a string.`,
|
||||||
|
Args: cobra.MinimumNArgs(1),
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
for i := 0; i < echoTimes; i++ {
|
for i := 0; i < echoTimes; i++ {
|
||||||
fmt.Println("Echo: " + strings.Join(args, " "))
|
fmt.Println("Echo: " + strings.Join(args, " "))
|
||||||
|
@ -513,7 +479,7 @@ func main() {
|
||||||
|
|
||||||
For a more complete example of a larger application, please checkout [Hugo](http://gohugo.io/).
|
For a more complete example of a larger application, please checkout [Hugo](http://gohugo.io/).
|
||||||
|
|
||||||
## The Help Command
|
## Help Command
|
||||||
|
|
||||||
Cobra automatically adds a help command to your application when you have subcommands.
|
Cobra automatically adds a help command to your application when you have subcommands.
|
||||||
This will be called when a user runs 'app help'. Additionally, help will also
|
This will be called when a user runs 'app help'. Additionally, help will also
|
||||||
|
@ -526,60 +492,28 @@ create' is called. Every command will automatically have the '--help' flag adde
|
||||||
The following output is automatically generated by Cobra. Nothing beyond the
|
The following output is automatically generated by Cobra. Nothing beyond the
|
||||||
command and flag definitions are needed.
|
command and flag definitions are needed.
|
||||||
|
|
||||||
> hugo help
|
$ cobra help
|
||||||
|
|
||||||
hugo is the main command, used to build your Hugo site.
|
Cobra is a CLI library for Go that empowers applications.
|
||||||
|
This application is a tool to generate the needed files
|
||||||
Hugo is a Fast and Flexible Static Site Generator
|
to quickly create a Cobra application.
|
||||||
built with love by spf13 and friends in Go.
|
|
||||||
|
|
||||||
Complete documentation is available at http://gohugo.io/.
|
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
hugo [flags]
|
cobra [command]
|
||||||
hugo [command]
|
|
||||||
|
|
||||||
Available Commands:
|
Available Commands:
|
||||||
server Hugo runs its own webserver to render the files
|
add Add a command to a Cobra Application
|
||||||
version Print the version number of Hugo
|
help Help about any command
|
||||||
config Print the site configuration
|
init Initialize a Cobra Application
|
||||||
check Check content in the source directory
|
|
||||||
benchmark Benchmark hugo by building a site a number of times.
|
|
||||||
convert Convert your content to different formats
|
|
||||||
new Create new content for your site
|
|
||||||
list Listing out various types of content
|
|
||||||
undraft Undraft changes the content's draft status from 'True' to 'False'
|
|
||||||
genautocomplete Generate shell autocompletion script for Hugo
|
|
||||||
gendoc Generate Markdown documentation for the Hugo CLI.
|
|
||||||
genman Generate man page for Hugo
|
|
||||||
import Import your site from others.
|
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
-b, --baseURL="": hostname (and path) to the root, e.g. http://spf13.com/
|
-a, --author string author name for copyright attribution (default "YOUR NAME")
|
||||||
-D, --buildDrafts[=false]: include content marked as draft
|
--config string config file (default is $HOME/.cobra.yaml)
|
||||||
-F, --buildFuture[=false]: include content with publishdate in the future
|
-h, --help help for cobra
|
||||||
--cacheDir="": filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/
|
-l, --license string name of license for the project
|
||||||
--canonifyURLs[=false]: if true, all relative URLs will be canonicalized using baseURL
|
--viper use Viper for configuration (default true)
|
||||||
--config="": config file (default is path/config.yaml|json|toml)
|
|
||||||
-d, --destination="": filesystem path to write files to
|
|
||||||
--disableRSS[=false]: Do not build RSS files
|
|
||||||
--disableSitemap[=false]: Do not build Sitemap file
|
|
||||||
--editor="": edit new content with this editor, if provided
|
|
||||||
--ignoreCache[=false]: Ignores the cache directory for reading but still writes to it
|
|
||||||
--log[=false]: Enable Logging
|
|
||||||
--logFile="": Log File path (if set, logging enabled automatically)
|
|
||||||
--noTimes[=false]: Don't sync modification time of files
|
|
||||||
--pluralizeListTitles[=true]: Pluralize titles in lists using inflect
|
|
||||||
--preserveTaxonomyNames[=false]: Preserve taxonomy names as written ("Gérard Depardieu" vs "gerard-depardieu")
|
|
||||||
-s, --source="": filesystem path to read files relative from
|
|
||||||
--stepAnalysis[=false]: display memory and timing of different steps of the program
|
|
||||||
-t, --theme="": theme to use (located in /themes/THEMENAME/)
|
|
||||||
--uglyURLs[=false]: if true, use /filename.html instead of /filename/
|
|
||||||
-v, --verbose[=false]: verbose output
|
|
||||||
--verboseLog[=false]: verbose logging
|
|
||||||
-w, --watch[=false]: watch filesystem for changes and recreate as needed
|
|
||||||
|
|
||||||
Use "hugo [command] --help" for more information about a command.
|
Use "cobra [command] --help" for more information about a command.
|
||||||
|
|
||||||
|
|
||||||
Help is just a command like any other. There is no special logic or behavior
|
Help is just a command like any other. There is no special logic or behavior
|
||||||
|
@ -587,38 +521,18 @@ around it. In fact, you can provide your own if you want.
|
||||||
|
|
||||||
### Defining your own help
|
### Defining your own help
|
||||||
|
|
||||||
You can provide your own Help command or your own template for the default command to use.
|
You can provide your own Help command or your own template for the default command to use
|
||||||
|
with followind functions:
|
||||||
The default help command is
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (c *Command) initHelp() {
|
cmd.SetHelpCommand(cmd *Command)
|
||||||
if c.helpCommand == nil {
|
cmd.SetHelpFunc(f func(*Command, []string))
|
||||||
c.helpCommand = &Command{
|
cmd.SetHelpTemplate(s string)
|
||||||
Use: "help [command]",
|
|
||||||
Short: "Help about any command",
|
|
||||||
Long: `Help provides help for any command in the application.
|
|
||||||
Simply type ` + c.Name() + ` help [path to command] for full details.`,
|
|
||||||
Run: c.HelpFunc(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.AddCommand(c.helpCommand)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You can provide your own command, function or template through the following methods:
|
|
||||||
|
|
||||||
```go
|
|
||||||
command.SetHelpCommand(cmd *Command)
|
|
||||||
|
|
||||||
command.SetHelpFunc(f func(*Command, []string))
|
|
||||||
|
|
||||||
command.SetHelpTemplate(s string)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The latter two will also apply to any children commands.
|
The latter two will also apply to any children commands.
|
||||||
|
|
||||||
## Usage
|
## Usage Message
|
||||||
|
|
||||||
When the user provides an invalid flag or invalid command, Cobra responds by
|
When the user provides an invalid flag or invalid command, Cobra responds by
|
||||||
showing the user the 'usage'.
|
showing the user the 'usage'.
|
||||||
|
@ -627,73 +541,37 @@ showing the user the 'usage'.
|
||||||
You may recognize this from the help above. That's because the default help
|
You may recognize this from the help above. That's because the default help
|
||||||
embeds the usage as part of its output.
|
embeds the usage as part of its output.
|
||||||
|
|
||||||
|
$ cobra --invalid
|
||||||
|
Error: unknown flag: --invalid
|
||||||
Usage:
|
Usage:
|
||||||
hugo [flags]
|
cobra [command]
|
||||||
hugo [command]
|
|
||||||
|
|
||||||
Available Commands:
|
Available Commands:
|
||||||
server Hugo runs its own webserver to render the files
|
add Add a command to a Cobra Application
|
||||||
version Print the version number of Hugo
|
help Help about any command
|
||||||
config Print the site configuration
|
init Initialize a Cobra Application
|
||||||
check Check content in the source directory
|
|
||||||
benchmark Benchmark hugo by building a site a number of times.
|
|
||||||
convert Convert your content to different formats
|
|
||||||
new Create new content for your site
|
|
||||||
list Listing out various types of content
|
|
||||||
undraft Undraft changes the content's draft status from 'True' to 'False'
|
|
||||||
genautocomplete Generate shell autocompletion script for Hugo
|
|
||||||
gendoc Generate Markdown documentation for the Hugo CLI.
|
|
||||||
genman Generate man page for Hugo
|
|
||||||
import Import your site from others.
|
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
-b, --baseURL="": hostname (and path) to the root, e.g. http://spf13.com/
|
-a, --author string author name for copyright attribution (default "YOUR NAME")
|
||||||
-D, --buildDrafts[=false]: include content marked as draft
|
--config string config file (default is $HOME/.cobra.yaml)
|
||||||
-F, --buildFuture[=false]: include content with publishdate in the future
|
-h, --help help for cobra
|
||||||
--cacheDir="": filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/
|
-l, --license string name of license for the project
|
||||||
--canonifyURLs[=false]: if true, all relative URLs will be canonicalized using baseURL
|
--viper use Viper for configuration (default true)
|
||||||
--config="": config file (default is path/config.yaml|json|toml)
|
|
||||||
-d, --destination="": filesystem path to write files to
|
Use "cobra [command] --help" for more information about a command.
|
||||||
--disableRSS[=false]: Do not build RSS files
|
|
||||||
--disableSitemap[=false]: Do not build Sitemap file
|
|
||||||
--editor="": edit new content with this editor, if provided
|
|
||||||
--ignoreCache[=false]: Ignores the cache directory for reading but still writes to it
|
|
||||||
--log[=false]: Enable Logging
|
|
||||||
--logFile="": Log File path (if set, logging enabled automatically)
|
|
||||||
--noTimes[=false]: Don't sync modification time of files
|
|
||||||
--pluralizeListTitles[=true]: Pluralize titles in lists using inflect
|
|
||||||
--preserveTaxonomyNames[=false]: Preserve taxonomy names as written ("Gérard Depardieu" vs "gerard-depardieu")
|
|
||||||
-s, --source="": filesystem path to read files relative from
|
|
||||||
--stepAnalysis[=false]: display memory and timing of different steps of the program
|
|
||||||
-t, --theme="": theme to use (located in /themes/THEMENAME/)
|
|
||||||
--uglyURLs[=false]: if true, use /filename.html instead of /filename/
|
|
||||||
-v, --verbose[=false]: verbose output
|
|
||||||
--verboseLog[=false]: verbose logging
|
|
||||||
-w, --watch[=false]: watch filesystem for changes and recreate as needed
|
|
||||||
|
|
||||||
### Defining your own usage
|
### Defining your own usage
|
||||||
You can provide your own usage function or template for Cobra to use.
|
You can provide your own usage function or template for Cobra to use.
|
||||||
|
|
||||||
The default usage function is:
|
|
||||||
|
|
||||||
```go
|
|
||||||
return func(c *Command) error {
|
|
||||||
err := tmpl(c.Out(), c.UsageTemplate(), c)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Like help, the function and template are overridable through public methods:
|
Like help, the function and template are overridable through public methods:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
command.SetUsageFunc(f func(*Command) error)
|
cmd.SetUsageFunc(f func(*Command) error)
|
||||||
|
cmd.SetUsageTemplate(s string)
|
||||||
command.SetUsageTemplate(s string)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## PreRun or PostRun Hooks
|
## PreRun and PostRun Hooks
|
||||||
|
|
||||||
It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherrited by children if they do not declare their own. These function are run in the following order:
|
It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order:
|
||||||
|
|
||||||
- `PersistentPreRun`
|
- `PersistentPreRun`
|
||||||
- `PreRun`
|
- `PreRun`
|
||||||
|
@ -754,58 +632,26 @@ func main() {
|
||||||
rootCmd.AddCommand(subCmd)
|
rootCmd.AddCommand(subCmd)
|
||||||
|
|
||||||
rootCmd.SetArgs([]string{""})
|
rootCmd.SetArgs([]string{""})
|
||||||
_ = rootCmd.Execute()
|
rootCmd.Execute()
|
||||||
fmt.Print("\n")
|
fmt.Println()
|
||||||
rootCmd.SetArgs([]string{"sub", "arg1", "arg2"})
|
rootCmd.SetArgs([]string{"sub", "arg1", "arg2"})
|
||||||
_ = rootCmd.Execute()
|
rootCmd.Execute()
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
```
|
||||||
|
Inside rootCmd PersistentPreRun with args: []
|
||||||
|
Inside rootCmd PreRun with args: []
|
||||||
|
Inside rootCmd Run with args: []
|
||||||
|
Inside rootCmd PostRun with args: []
|
||||||
|
Inside rootCmd PersistentPostRun with args: []
|
||||||
|
|
||||||
## Alternative Error Handling
|
Inside rootCmd PersistentPreRun with args: [arg1 arg2]
|
||||||
|
Inside subCmd PreRun with args: [arg1 arg2]
|
||||||
Cobra also has functions where the return signature is an error. This allows for errors to bubble up to the top,
|
Inside subCmd Run with args: [arg1 arg2]
|
||||||
providing a way to handle the errors in one location. The current list of functions that return an error is:
|
Inside subCmd PostRun with args: [arg1 arg2]
|
||||||
|
Inside subCmd PersistentPostRun with args: [arg1 arg2]
|
||||||
* PersistentPreRunE
|
|
||||||
* PreRunE
|
|
||||||
* RunE
|
|
||||||
* PostRunE
|
|
||||||
* PersistentPostRunE
|
|
||||||
|
|
||||||
If you would like to silence the default `error` and `usage` output in favor of your own, you can set `SilenceUsage`
|
|
||||||
and `SilenceErrors` to `false` on the command. A child command respects these flags if they are set on the parent
|
|
||||||
command.
|
|
||||||
|
|
||||||
**Example Usage using RunE:**
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var rootCmd = &cobra.Command{
|
|
||||||
Use: "hugo",
|
|
||||||
Short: "Hugo is a very fast static site generator",
|
|
||||||
Long: `A Fast and Flexible Static Site Generator built with
|
|
||||||
love by spf13 and friends in Go.
|
|
||||||
Complete documentation is available at http://hugo.spf13.com`,
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
// Do Stuff Here
|
|
||||||
return errors.New("some random error")
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := rootCmd.Execute(); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Suggestions when "unknown command" happens
|
## Suggestions when "unknown command" happens
|
||||||
|
@ -848,81 +694,28 @@ Did you mean this?
|
||||||
Run 'kubectl help' for usage.
|
Run 'kubectl help' for usage.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Generating Markdown-formatted documentation for your command
|
## Generating documentation for your command
|
||||||
|
|
||||||
Cobra can generate a Markdown-formatted document based on the subcommands, flags, etc. A simple example of how to do this for your command can be found in [Markdown Docs](doc/md_docs.md).
|
Cobra can generate documentation based on subcommands, flags, etc. in the following formats:
|
||||||
|
|
||||||
## Generating man pages for your command
|
- [Markdown](doc/md_docs.md)
|
||||||
|
- [ReStructured Text](doc/rest_docs.md)
|
||||||
|
- [Man Page](doc/man_docs.md)
|
||||||
|
|
||||||
Cobra can generate a man page based on the subcommands, flags, etc. A simple example of how to do this for your command can be found in [Man Docs](doc/man_docs.md).
|
## Generating bash completions
|
||||||
|
|
||||||
## Generating bash completions for your command
|
|
||||||
|
|
||||||
Cobra can generate a bash-completion file. If you add more information to your command, these completions can be amazingly powerful and flexible. Read more about it in [Bash Completions](bash_completions.md).
|
Cobra can generate a bash-completion file. If you add more information to your command, these completions can be amazingly powerful and flexible. Read more about it in [Bash Completions](bash_completions.md).
|
||||||
|
|
||||||
## Debugging
|
# Contributing
|
||||||
|
|
||||||
Cobra provides a ‘DebugFlags’ method on a command which, when called, will print
|
|
||||||
out everything Cobra knows about the flags for each command.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
```go
|
|
||||||
command.DebugFlags()
|
|
||||||
```
|
|
||||||
|
|
||||||
## Release Notes
|
|
||||||
* **0.9.0** June 17, 2014
|
|
||||||
* flags can appears anywhere in the args (provided they are unambiguous)
|
|
||||||
* --help prints usage screen for app or command
|
|
||||||
* Prefix matching for commands
|
|
||||||
* Cleaner looking help and usage output
|
|
||||||
* Extensive test suite
|
|
||||||
* **0.8.0** Nov 5, 2013
|
|
||||||
* Reworked interface to remove commander completely
|
|
||||||
* Command now primary structure
|
|
||||||
* No initialization needed
|
|
||||||
* Usage & Help templates & functions definable at any level
|
|
||||||
* Updated Readme
|
|
||||||
* **0.7.0** Sept 24, 2013
|
|
||||||
* Needs more eyes
|
|
||||||
* Test suite
|
|
||||||
* Support for automatic error messages
|
|
||||||
* Support for help command
|
|
||||||
* Support for printing to any io.Writer instead of os.Stderr
|
|
||||||
* Support for persistent flags which cascade down tree
|
|
||||||
* Ready for integration into Hugo
|
|
||||||
* **0.1.0** Sept 3, 2013
|
|
||||||
* Implement first draft
|
|
||||||
|
|
||||||
## Extensions
|
|
||||||
|
|
||||||
Libraries for extending Cobra:
|
|
||||||
|
|
||||||
* [cmdns](https://github.com/gosuri/cmdns): Enables name spacing a command's immediate children. It provides an alternative way to structure subcommands, similar to `heroku apps:create` and `ovrclk clusters:launch`.
|
|
||||||
|
|
||||||
## ToDo
|
|
||||||
* Launch proper documentation site
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
1. Fork it
|
1. Fork it
|
||||||
2. Create your feature branch (`git checkout -b my-new-feature`)
|
2. Download your fork to your PC (`git clone https://github.com/your_username/cobra && cd cobra`)
|
||||||
3. Commit your changes (`git commit -am 'Add some feature'`)
|
3. Create your feature branch (`git checkout -b my-new-feature`)
|
||||||
4. Push to the branch (`git push origin my-new-feature`)
|
4. Make changes and add them (`git add .`)
|
||||||
5. Create new Pull Request
|
5. Commit your changes (`git commit -m 'Add some feature'`)
|
||||||
|
6. Push to the branch (`git push origin my-new-feature`)
|
||||||
|
7. Create new pull request
|
||||||
|
|
||||||
## Contributors
|
# License
|
||||||
|
|
||||||
Names in no particular order:
|
|
||||||
|
|
||||||
* [spf13](https://github.com/spf13),
|
|
||||||
[eparis](https://github.com/eparis),
|
|
||||||
[bep](https://github.com/bep), and many more!
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
Cobra is released under the Apache 2.0 license. See [LICENSE.txt](https://github.com/spf13/cobra/blob/master/LICENSE.txt)
|
Cobra is released under the Apache 2.0 license. See [LICENSE.txt](https://github.com/spf13/cobra/blob/master/LICENSE.txt)
|
||||||
|
|
||||||
|
|
||||||
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/spf13/cobra/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
|
|
||||||
|
|
|
@ -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[@]}"
|
||||||
if [[ ${index} -ge 0 ]]; then
|
|
||||||
COMPREPLY=()
|
COMPREPLY=()
|
||||||
|
if [[ ${index} -ge 0 ]]; then
|
||||||
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
|
||||||
|
|
||||||
|
# available in bash-completion >= 2, not always present on macOS
|
||||||
|
if declare -F __ltrim_colon_completions >/dev/null; then
|
||||||
__ltrim_colon_completions "$cur"
|
__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
|
|
||||||
}
|
}
|
||||||
}
|
buf.WriteString("\n")
|
||||||
_, err := fmt.Fprintf(w, "\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 {
|
buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", ext))
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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
|
buf.WriteString("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = fmt.Fprintf(w, "\n")
|
func writeRequiredFlag(buf *bytes.Buffer, cmd *Command) {
|
||||||
return err
|
buf.WriteString(" must_have_one_flag=()\n")
|
||||||
}
|
|
||||||
|
|
||||||
func writeRequiredFlag(cmd *Command, w io.Writer) error {
|
|
||||||
if _, err := fmt.Fprintf(w, " must_have_one_flag=()\n"); err != nil {
|
|
||||||
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 {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
writePreamble(buf, c.Name())
|
||||||
|
if len(c.BashCompletionFunction) > 0 {
|
||||||
|
buf.WriteString(c.BashCompletionFunction + "\n")
|
||||||
|
}
|
||||||
|
gen(buf, c)
|
||||||
|
writePostscript(buf, c.Name())
|
||||||
|
|
||||||
|
_, err := buf.WriteTo(w)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(cmd.BashCompletionFunction) > 0 {
|
|
||||||
if _, err := fmt.Fprintf(w, "%s\n", cmd.BashCompletionFunction); err != nil {
|
|
||||||
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.
|
||||||
|
|
|
@ -29,6 +29,7 @@ import (
|
||||||
var templateFuncs = template.FuncMap{
|
var templateFuncs = template.FuncMap{
|
||||||
"trim": strings.TrimSpace,
|
"trim": strings.TrimSpace,
|
||||||
"trimRightSpace": trimRightSpace,
|
"trimRightSpace": trimRightSpace,
|
||||||
|
"trimTrailingWhitespaces": trimRightSpace,
|
||||||
"appendIfNotPresent": appendIfNotPresent,
|
"appendIfNotPresent": appendIfNotPresent,
|
||||||
"rpad": rpad,
|
"rpad": rpad,
|
||||||
"gt": Gt,
|
"gt": Gt,
|
||||||
|
@ -37,21 +38,31 @@ var templateFuncs = template.FuncMap{
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
// MousetrapHelpText enables an information splash screen on Windows
|
||||||
|
// 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
|
// AddTemplateFunc adds a template function that's available to Usage and Help
|
||||||
// template generation.
|
// 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 {
|
||||||
|
@ -61,11 +72,11 @@ func AddTemplateFuncs(tmplFuncs template.FuncMap) {
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME Gt is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra.
|
||||||
|
|
||||||
// Gt takes two types and checks whether the first type is greater than the second. In case of types Arrays, Chans,
|
// 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
|
// Maps and Slices, Gt will compare their lengths. Ints are compared directly while strings are first parsed as
|
||||||
// ints and then compared.
|
// ints and then compared.
|
||||||
|
@ -96,6 +107,8 @@ func Gt(a interface{}, b interface{}) bool {
|
||||||
return left > right
|
return left > right
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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.
|
// 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)
|
||||||
|
@ -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
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
|
}
|
||||||
|
_, err := buf.WriteTo(w)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -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) }
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ 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.
|
||||||
|
@ -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
|
||||||
|
@ -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 !flag.Changed {
|
||||||
if f.actual == nil {
|
if f.actual == nil {
|
||||||
f.actual = make(map[NormalizedName]*Flag)
|
f.actual = make(map[NormalizedName]*Flag)
|
||||||
}
|
}
|
||||||
f.actual[normalName] = flag
|
f.actual[normalName] = flag
|
||||||
|
f.orderedActual = append(f.orderedActual, flag)
|
||||||
|
|
||||||
flag.Changed = true
|
flag.Changed = true
|
||||||
if len(flag.Deprecated) > 0 {
|
}
|
||||||
fmt.Fprintf(os.Stderr, "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
|
|
||||||
|
if flag.Deprecated != "" {
|
||||||
|
fmt.Fprintf(f.out(), "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...)
|
||||||
|
if f.errorHandling != ContinueOnError {
|
||||||
fmt.Fprintln(f.out(), err)
|
fmt.Fprintln(f.out(), err)
|
||||||
f.usage()
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
Loading…
Reference in New Issue