Update cobra and pflag

Signed-off-by: Lantao Liu <lantaol@google.com>
This commit is contained in:
Lantao Liu 2017-10-26 05:57:29 +00:00
parent 1d5cd86207
commit c6fd18ddc3
14 changed files with 1564 additions and 1231 deletions

View File

@ -49,8 +49,8 @@ github.com/PuerkitoBio/purell v1.0.0
github.com/PuerkitoBio/urlesc 5bd2802263f21d8788851d5305584c82a5c75d7e github.com/PuerkitoBio/urlesc 5bd2802263f21d8788851d5305584c82a5c75d7e
github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0 github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
github.com/sirupsen/logrus v1.0.0 github.com/sirupsen/logrus v1.0.0
github.com/spf13/cobra f62e98d28ab7ad31d707ba837a966378465c7b57 github.com/spf13/cobra v0.0.1
github.com/spf13/pflag 9ff6c6923cfffbcd502984b8e0c80539a94968b7 github.com/spf13/pflag v1.0.0
github.com/stretchr/testify v1.1.4 github.com/stretchr/testify v1.1.4
github.com/syndtr/gocapability e7cb7fa329f456b3855136a2642b197bad7366ba github.com/syndtr/gocapability e7cb7fa329f456b3855136a2642b197bad7366ba
github.com/tchap/go-patricia 5ad6cdb7538b0097d5598c7e57f0a24072adf7dc github.com/tchap/go-patricia 5ad6cdb7538b0097d5598c7e57f0a24072adf7dc

60
vendor/github.com/docker/docker/hack/README.md generated vendored Normal file
View File

@ -0,0 +1,60 @@
## About
This directory contains a collection of scripts used to build and manage this
repository. If there are any issues regarding the intention of a particular
script (or even part of a certain script), please reach out to us.
It may help us either refine our current scripts, or add on new ones
that are appropriate for a given use case.
## DinD (dind.sh)
DinD is a wrapper script which allows Docker to be run inside a Docker
container. DinD requires the container to
be run with privileged mode enabled.
## Generate Authors (generate-authors.sh)
Generates AUTHORS; a file with all the names and corresponding emails of
individual contributors. AUTHORS can be found in the home directory of
this repository.
## Make
There are two make files, each with different extensions. Neither are supposed
to be called directly; only invoke `make`. Both scripts run inside a Docker
container.
### make.ps1
- The Windows native build script that uses PowerShell semantics; it is limited
unlike `hack\make.sh` since it does not provide support for the full set of
operations provided by the Linux counterpart, `make.sh`. However, `make.ps1`
does provide support for local Windows development and Windows to Windows CI.
More information is found within `make.ps1` by the author, @jhowardmsft
### make.sh
- Referenced via `make test` when running tests on a local machine,
or directly referenced when running tests inside a Docker development container.
- When running on a local machine, `make test` to run all tests found in
`test`, `test-unit`, `test-integration`, and `test-docker-py` on
your local machine. The default timeout is set in `make.sh` to 60 minutes
(`${TIMEOUT:=60m}`), since it currently takes up to an hour to run
all of the tests.
- When running inside a Docker development container, `hack/make.sh` does
not have a single target that runs all the tests. You need to provide a
single command line with multiple targets that performs the same thing.
An example referenced from [Run targets inside a development container](https://docs.docker.com/opensource/project/test-and-docs/#run-targets-inside-a-development-container): `root@5f8630b873fe:/go/src/github.com/moby/moby# hack/make.sh dynbinary binary cross test-unit test-integration test-docker-py`
- For more information related to testing outside the scope of this README,
refer to
[Run tests and test documentation](https://docs.docker.com/opensource/project/test-and-docs/)
## Release (release.sh)
Releases any bundles built by `make` on a public AWS S3 bucket.
For information regarding configuration, please view `release.sh`.
## Vendor (vendor.sh)
A shell script that is a wrapper around Vndr. For information on how to use
this, please refer to [vndr's README](https://github.com/LK4D4/vndr/blob/master/README.md)

View File

@ -0,0 +1,69 @@
# Integration Testing on Swarm
IT on Swarm allows you to execute integration test in parallel across a Docker Swarm cluster
## Architecture
### Master service
- Works as a funker caller
- Calls a worker funker (`-worker-service`) with a chunk of `-check.f` filter strings (passed as a file via `-input` flag, typically `/mnt/input`)
### Worker service
- Works as a funker callee
- Executes an equivalent of `TESTFLAGS=-check.f TestFoo|TestBar|TestBaz ... make test-integration-cli` using the bind-mounted API socket (`docker.sock`)
### Client
- Controls master and workers via `docker stack`
- No need to have a local daemon
Typically, the master and workers are supposed to be running on a cloud environment,
while the client is supposed to be running on a laptop, e.g. Docker for Mac/Windows.
## Requirement
- Docker daemon 1.13 or later
- Private registry for distributed execution with multiple nodes
## Usage
### Step 1: Prepare images
$ make build-integration-cli-on-swarm
Following environment variables are known to work in this step:
- `BUILDFLAGS`
- `DOCKER_INCREMENTAL_BINARY`
Note: during the transition into Moby Project, you might need to create a symbolic link `$GOPATH/src/github.com/docker/docker` to `$GOPATH/src/github.com/moby/moby`.
### Step 2: Execute tests
$ ./hack/integration-cli-on-swarm/integration-cli-on-swarm -replicas 40 -push-worker-image YOUR_REGISTRY.EXAMPLE.COM/integration-cli-worker:latest
Following environment variables are known to work in this step:
- `DOCKER_GRAPHDRIVER`
- `DOCKER_EXPERIMENTAL`
#### Flags
Basic flags:
- `-replicas N`: the number of worker service replicas. i.e. degree of parallelism.
- `-chunks N`: the number of chunks. By default, `chunks` == `replicas`.
- `-push-worker-image REGISTRY/IMAGE:TAG`: push the worker image to the registry. Note that if you have only single node and hence you do not need a private registry, you do not need to specify `-push-worker-image`.
Experimental flags for mitigating makespan nonuniformity:
- `-shuffle`: Shuffle the test filter strings
Flags for debugging IT on Swarm itself:
- `-rand-seed N`: the random seed. This flag is useful for deterministic replaying. By default(0), the timestamp is used.
- `-filters-file FILE`: the file contains `-check.f` strings. By default, the file is automatically generated.
- `-dry-run`: skip the actual workload
- `keep-executor`: do not auto-remove executor containers, which is used for running privileged programs on Swarm

View File

@ -0,0 +1,2 @@
# dependencies specific to worker (i.e. github.com/docker/docker/...) are not vendored here
github.com/bfirsh/funker-go eaa0a2e06f30e72c9a0b7f858951e581e26ef773

View File

@ -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 isnt 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,99 +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.
In order to use the cobra command, compile it using the following command: [Here](https://github.com/spf13/cobra/blob/master/cobra/README.md) you can find more information about it.
> go install github.com/spf13/cobra/cobra ## Using the Cobra Library
This will create the cobra executable under your go path bin directory! To manually implement Cobra you need to create a bare main.go file and a RootCmd file.
### cobra init
The `cobra init [yourApp]` command will create your initial application code
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
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.
@ -285,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)")
@ -301,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
@ -313,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
@ -337,6 +291,7 @@ package cmd
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"fmt"
) )
func init() { func init() {
@ -353,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.
@ -412,6 +343,71 @@ 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")
``` ```
### Local Flag on Parent Commands
By default Cobra only parses local flags on the target command, any local flags on
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.
- `ArbitraryArgs` - the command will accept any args.
- `OnlyValidArgs` - the command will report an error if there are any positional args that are not in the `ValidArgs` field of `Command`.
- `MinimumNArgs(int)` - the command will report an error if there are not at least N positional args.
- `MaximumNArgs(int)` - the command will report an error if there are more than 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.
An example of setting the custom validator:
```go
var cmd = &cobra.Command{
Short: "hello",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
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) {
fmt.Println("Hello, World!")
},
}
```
## Example ## Example
@ -435,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, " "))
}, },
@ -453,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, " "))
}, },
@ -464,7 +459,8 @@ func main() {
Use: "times [# times] [string to echo]", Use: "times [# times] [string to echo]",
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, " "))
@ -483,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
@ -496,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
@ -557,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'.
@ -597,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`
@ -724,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
@ -818,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")

98
vendor/github.com/spf13/cobra/args.go generated vendored Normal file
View File

@ -0,0 +1,98 @@
package cobra
import (
"fmt"
)
type PositionalArgs func(cmd *Command, args []string) error
// Legacy arg validation has the following 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
func legacyArgs(cmd *Command, args []string) error {
// no subcommand, always take args
if !cmd.HasSubCommands() {
return nil
}
// root command with subcommands, do subcommand checking
if !cmd.HasParent() && len(args) > 0 {
return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0]))
}
return nil
}
// NoArgs returns an error if any args are included
func NoArgs(cmd *Command, args []string) error {
if len(args) > 0 {
return fmt.Errorf("unknown command %q for %q", args[0], cmd.CommandPath())
}
return nil
}
// OnlyValidArgs returns an error if any args are not in the list of ValidArgs
func OnlyValidArgs(cmd *Command, args []string) error {
if len(cmd.ValidArgs) > 0 {
for _, v := range args {
if !stringInSlice(v, cmd.ValidArgs) {
return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0]))
}
}
}
return nil
}
func stringInSlice(a string, list []string) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}
// ArbitraryArgs never returns an error
func ArbitraryArgs(cmd *Command, args []string) error {
return nil
}
// MinimumNArgs returns an error if there is not at least N args
func MinimumNArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error {
if len(args) < n {
return fmt.Errorf("requires at least %d arg(s), only received %d", n, len(args))
}
return nil
}
}
// MaximumNArgs returns an error if there are more than N args
func MaximumNArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error {
if len(args) > n {
return fmt.Errorf("accepts at most %d arg(s), received %d", n, len(args))
}
return nil
}
}
// ExactArgs returns an error if there are not exactly n args
func ExactArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error {
if len(args) != n {
return fmt.Errorf("accepts %d arg(s), received %d", n, len(args))
}
return nil
}
}
// RangeArgs returns an error if the number of args is not within the expected range
func RangeArgs(min int, max int) PositionalArgs {
return func(cmd *Command, args []string) error {
if len(args) < min || len(args) > max {
return fmt.Errorf("accepts between %d and %d arg(s), received %d", min, max, len(args))
}
return nil
}
}

View File

@ -1,6 +1,7 @@
package cobra package cobra
import ( import (
"bytes"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -10,19 +11,17 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
// Annotations for Bash completion.
const ( const (
BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extentions" BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extensions"
BashCompCustom = "cobra_annotation_bash_completion_custom" BashCompCustom = "cobra_annotation_bash_completion_custom"
BashCompOneRequiredFlag = "cobra_annotation_bash_completion_one_required_flag" BashCompOneRequiredFlag = "cobra_annotation_bash_completion_one_required_flag"
BashCompSubdirsInDir = "cobra_annotation_bash_completion_subdirs_in_dir" BashCompSubdirsInDir = "cobra_annotation_bash_completion_subdirs_in_dir"
) )
func preamble(out io.Writer, name string) error { func writePreamble(buf *bytes.Buffer, name string) {
_, err := fmt.Fprintf(out, "# bash completion for %-36s -*- shell-script -*-\n", name) buf.WriteString(fmt.Sprintf("# bash completion for %-36s -*- shell-script -*-\n", name))
if err != nil { buf.WriteString(`
return err
}
_, err = fmt.Fprint(out, `
__debug() __debug()
{ {
if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then
@ -87,13 +86,13 @@ __handle_reply()
local index flag local index flag
flag="${cur%%=*}" flag="${cur%%=*}"
__index_of_word "${flag}" "${flags_with_completion[@]}" __index_of_word "${flag}" "${flags_with_completion[@]}"
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
}
_, err = fmt.Fprintf(w, "\n") buf.WriteString("\n")
return err
} }
func writeRequiredFlag(cmd *Command, w io.Writer) error { func writeRequiredFlag(buf *bytes.Buffer, cmd *Command) {
if _, err := fmt.Fprintf(w, " must_have_one_flag=()\n"); err != nil { buf.WriteString(" must_have_one_flag=()\n")
return err
}
flags := cmd.NonInheritedFlags() flags := cmd.NonInheritedFlags()
var visitErr error
flags.VisitAll(func(flag *pflag.Flag) { flags.VisitAll(func(flag *pflag.Flag) {
if nonCompletableFlag(flag) {
return
}
for key := range flag.Annotations { for key := range flag.Annotations {
switch key { switch key {
case BashCompOneRequiredFlag: case BashCompOneRequiredFlag:
format := " must_have_one_flag+=(\"--%s" format := " must_have_one_flag+=(\"--%s"
b := (flag.Value.Type() == "bool") if flag.Value.Type() != "bool" {
if !b {
format += "=" format += "="
} }
format += "\")\n" format += "\")\n"
if _, err := fmt.Fprintf(w, format, flag.Name); err != nil { buf.WriteString(fmt.Sprintf(format, flag.Name))
visitErr = err
return
}
if len(flag.Shorthand) > 0 { if len(flag.Shorthand) > 0 {
if _, err := fmt.Fprintf(w, " must_have_one_flag+=(\"-%s\")\n", flag.Shorthand); err != nil { buf.WriteString(fmt.Sprintf(" must_have_one_flag+=(\"-%s\")\n", flag.Shorthand))
visitErr = err
return
}
} }
} }
} }
}) })
return visitErr
} }
func writeRequiredNouns(cmd *Command, w io.Writer) error { func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) {
if _, err := fmt.Fprintf(w, " must_have_one_noun=()\n"); err != nil { buf.WriteString(" must_have_one_noun=()\n")
return err
}
sort.Sort(sort.StringSlice(cmd.ValidArgs)) sort.Sort(sort.StringSlice(cmd.ValidArgs))
for _, value := range cmd.ValidArgs { for _, value := range cmd.ValidArgs {
if _, err := fmt.Fprintf(w, " must_have_one_noun+=(%q)\n", value); err != nil { buf.WriteString(fmt.Sprintf(" must_have_one_noun+=(%q)\n", value))
return err
} }
}
return nil
} }
func writeArgAliases(cmd *Command, w io.Writer) error { func writeArgAliases(buf *bytes.Buffer, cmd *Command) {
if _, err := fmt.Fprintf(w, " noun_aliases=()\n"); err != nil { buf.WriteString(" noun_aliases=()\n")
return err
}
sort.Sort(sort.StringSlice(cmd.ArgAliases)) sort.Sort(sort.StringSlice(cmd.ArgAliases))
for _, value := range cmd.ArgAliases { for _, value := range cmd.ArgAliases {
if _, err := fmt.Fprintf(w, " noun_aliases+=(%q)\n", value); err != nil { buf.WriteString(fmt.Sprintf(" noun_aliases+=(%q)\n", value))
return err
} }
}
return nil
} }
func gen(cmd *Command, w io.Writer) error { func gen(buf *bytes.Buffer, cmd *Command) {
for _, c := range cmd.Commands() { for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() || c == cmd.helpCommand { if !c.IsAvailableCommand() || c == cmd.helpCommand {
continue continue
} }
if err := gen(c, w); err != nil { gen(buf, c)
return err
}
} }
commandName := cmd.CommandPath() commandName := cmd.CommandPath()
commandName = strings.Replace(commandName, " ", "_", -1) commandName = strings.Replace(commandName, " ", "_", -1)
commandName = strings.Replace(commandName, ":", "__", -1) commandName = strings.Replace(commandName, ":", "__", -1)
if _, err := fmt.Fprintf(w, "_%s()\n{\n", commandName); err != nil { buf.WriteString(fmt.Sprintf("_%s()\n{\n", commandName))
return err buf.WriteString(fmt.Sprintf(" last_command=%q\n", commandName))
} writeCommands(buf, cmd)
if _, err := fmt.Fprintf(w, " last_command=%q\n", commandName); err != nil { writeFlags(buf, cmd)
return err writeRequiredFlag(buf, cmd)
} writeRequiredNouns(buf, cmd)
if err := writeCommands(cmd, w); err != nil { writeArgAliases(buf, cmd)
return err buf.WriteString("}\n\n")
}
if err := writeFlags(cmd, w); err != nil {
return err
}
if err := writeRequiredFlag(cmd, w); err != nil {
return err
}
if err := writeRequiredNouns(cmd, w); err != nil {
return err
}
if err := writeArgAliases(cmd, w); err != nil {
return err
}
if _, err := fmt.Fprintf(w, "}\n\n"); err != nil {
return err
}
return nil
} }
func (cmd *Command) GenBashCompletion(w io.Writer) error { // GenBashCompletion generates bash completion file and writes to the passed writer.
if err := preamble(w, cmd.Name()); err != nil { func (c *Command) GenBashCompletion(w io.Writer) error {
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.

View File

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

File diff suppressed because it is too large Load Diff

View File

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

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

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

View File

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

View File

@ -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)
} }

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

@ -16,9 +16,9 @@ pflag is a drop-in replacement of Go's native flag package. If you import
pflag under the name "flag" then all code should continue to function pflag under the name "flag" then all code should continue to function
with no changes. with no changes.
import flag "github.com/ogier/pflag" import flag "github.com/spf13/pflag"
There is one exception to this: if you directly instantiate the Flag struct There is one exception to this: if you directly instantiate the Flag struct
there is one more field "Shorthand" that you will need to set. there is one more field "Shorthand" that you will need to set.
Most code never instantiates this struct directly, and instead uses Most code never instantiates this struct directly, and instead uses
functions such as String(), BoolVar(), and Var(), and is therefore functions such as String(), BoolVar(), and Var(), and is therefore
@ -134,14 +134,21 @@ type FlagSet struct {
// a custom error handler. // a custom error handler.
Usage func() Usage func()
// SortFlags is used to indicate, if user wants to have sorted flags in
// help/usage messages.
SortFlags bool
name string name string
parsed bool parsed bool
actual map[NormalizedName]*Flag actual map[NormalizedName]*Flag
orderedActual []*Flag
sortedActual []*Flag
formal map[NormalizedName]*Flag formal map[NormalizedName]*Flag
orderedFormal []*Flag
sortedFormal []*Flag
shorthands map[byte]*Flag shorthands map[byte]*Flag
args []string // arguments after flags args []string // arguments after flags
argsLenAtDash int // len(args) when a '--' was located when parsing, or -1 if no -- argsLenAtDash int // len(args) when a '--' was located when parsing, or -1 if no --
exitOnError bool // does the program exit if there's an error?
errorHandling ErrorHandling errorHandling ErrorHandling
output io.Writer // nil means stderr; use out() accessor output io.Writer // nil means stderr; use out() accessor
interspersed bool // allow interspersed option/non-option args interspersed bool // allow interspersed option/non-option args
@ -156,7 +163,7 @@ type Flag struct {
Value Value // value as set Value Value // value as set
DefValue string // default value (as text); for usage message DefValue string // default value (as text); for usage message
Changed bool // If the user set the value (or if left to default) Changed bool // If the user set the value (or if left to default)
NoOptDefVal string //default value (as text); if the flag is on the command line without any options NoOptDefVal string // default value (as text); if the flag is on the command line without any options
Deprecated string // If this flag is deprecated, this string is the new or now thing to use Deprecated string // If this flag is deprecated, this string is the new or now thing to use
Hidden bool // used by cobra.Command to allow flags to be hidden from help/usage text Hidden bool // used by cobra.Command to allow flags to be hidden from help/usage text
ShorthandDeprecated string // If the shorthand of this flag is deprecated, this string is the new or now thing to use ShorthandDeprecated string // If the shorthand of this flag is deprecated, this string is the new or now thing to use
@ -194,11 +201,13 @@ 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 k, v := range f.orderedFormal {
nname := f.normalizeFlagName(string(k)) delete(f.formal, NormalizedName(v.Name))
f.formal[nname] = v nname := f.normalizeFlagName(v.Name)
v.Name = string(nname) v.Name = string(nname)
f.formal[nname] = v
f.orderedFormal[k] = v
} }
} }
@ -229,10 +238,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 +277,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 +319,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 +376,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 +391,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 +415,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 +428,28 @@ func (f *FlagSet) Set(name, value string) error {
if !ok { if !ok {
return fmt.Errorf("no such flag -%v", name) return fmt.Errorf("no such flag -%v", name)
} }
err := flag.Value.Set(value) err := flag.Value.Set(value)
if err != nil { if err != nil {
return err var flagName string
if flag.Shorthand != "" && flag.ShorthandDeprecated == "" {
flagName = fmt.Sprintf("-%s, --%s", flag.Shorthand, flag.Name)
} else {
flagName = fmt.Sprintf("--%s", flag.Name)
} }
return fmt.Errorf("invalid argument %q for %q flag: %v", value, flagName, err)
}
if f.actual == nil { 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
} }
@ -557,28 +631,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)
@ -601,7 +675,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 +688,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 +788,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 +802,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
@ -798,34 +874,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 +881,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 +893,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 +910,8 @@ 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)
return return
} }
@ -868,38 +919,49 @@ 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)
return return
} }
@ -907,6 +969,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,13 +1017,18 @@ 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:
@ -974,7 +1042,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 +1053,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 +1100,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
} }