1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Bump spf13/cobra to v0.0.3, pflag to v1.0.1

Use a tagged release of Cobra. All relevant PR's were merged, so the fork is
no longer needed.

Relevant changes:

- spf13/cobra#552 Add a field to disable [flags] in UseLine()
- spf13/cobra#567 Add `CalledAs` method to cobra.Command
- spf13/cobra#580 Update error message for missing required flags
- spf13/cobra#584 Add support for --version flag
- spf13/cobra#614 If user has a project in symlink, just use its destination folder and work there
- spf13/cobra#649 terminates the flags when -- is found in commandline
- spf13/cobra#662 Add support for ignoring parse errors
- spf13/cobra#686 doc: hide hidden parent flags

Also various improvements were added for generating Bash
completion scripts (currently not used by us)

Fixes usage output for dockerd;

Before this update:

    dockerd --help

    Usage:	dockerd COMMAND

    A self-sufficient runtime for containers.

After this update:

    dockerd --help

    Usage:	dockerd [OPTIONS] [flags]

    A self-sufficient runtime for containers.

Bump spf13/pflag to v1.0.1

Relevant changes:

- spf13/pflag#106 allow lookup by shorthand
- spf13/pflag#113 Add SortFlags option
- spf13/pflag#138 Generate flag error output for errors returned from the parseFunc
- spf13/pflag#141 Fixing Count flag usage string
- spf13/pflag#143 add int16 flag
- spf13/pflag#122 DurationSlice: implementation and tests
- spf13/pflag#115 Implement BytesHex type of argument
- spf13/pflag#150 Add uintSlice and boolSlice to name prettifier
- spf13/pflag#155 Add multiline wrapping support
- spf13/pflag#158 doc: clarify difference between string slice vs. array
- spf13/pflag#160 add ability to ignore unknown flags
- spf13/pflag#163 Allow Users To Show Deprecated Flags

Hide [flags] in usage output

Hides the [flags] in the usage output of commands (present in newer
versions of Cobra), using the `.DisableFlagsInUseLine` option.

Before this change:

    dockerd --help

    Usage:	dockerd [OPTIONS] [flags]

    A self-sufficient runtime for containers.

After this change:

    dockerd --help

    Usage:	dockerd [OPTIONS]

    A self-sufficient runtime for containers.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Â#	modified:   vendor/github.com/spf13/pflag/string_array.go
§

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2018-05-19 01:19:16 +02:00
parent 76e43532f6
commit ed75c7727b
No known key found for this signature in database
GPG key ID: 76698F39D527CE8C
18 changed files with 1957 additions and 1374 deletions

View file

@ -31,6 +31,7 @@ func newDaemonCommand() *cobra.Command {
opts.flags = cmd.Flags() opts.flags = cmd.Flags()
return runDaemon(opts) return runDaemon(opts)
}, },
DisableFlagsInUseLine: true,
} }
cli.SetupRootCommand(cmd) cli.SetupRootCommand(cmd)

View file

@ -141,8 +141,8 @@ github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0 github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
# cli # cli
github.com/spf13/cobra v1.5.1 https://github.com/dnephin/cobra.git github.com/spf13/cobra v0.0.3
github.com/spf13/pflag 9ff6c6923cfffbcd502984b8e0c80539a94968b7 github.com/spf13/pflag v1.0.1
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty

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,37 @@ 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)
* [Pouch](https://github.com/alibaba/pouch)
[![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 +61,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 +89,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 +103,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 +115,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 +133,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,18 +146,20 @@ 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 { cmd.Execute()
fmt.Println(err)
os.Exit(-1)
}
} }
``` ```
@ -172,100 +168,21 @@ func main() {
Cobra provides its own program that will create your application and add any Cobra provides its own program that will create your application and add any
commands you want. It's the easiest way to incorporate Cobra into your application. commands you want. It's the easiest way to incorporate Cobra into your application.
### cobra init [Here](https://github.com/spf13/cobra/blob/master/cobra/README.md) you can find more information about it.
The `cobra init [yourApp]` command will create your initial application code ## Using the Cobra Library
for you. It is a very powerful application that will populate your program with
the right structure so you can immediately enjoy all the benefits of Cobra. It
will also automatically apply the license you specify to your application.
Cobra init is pretty smart. You can provide it a full path, or simply a path To manually implement Cobra you need to create a bare main.go file and a rootCmd file.
similar to what is expected in the import.
```
cobra init github.com/spf13/newAppName
```
### cobra add
Once an application is initialized Cobra can create additional commands for you.
Let's say you created an app and you wanted the following commands for it:
* app serve
* app config
* app config create
In your project directory (where your main.go file is) you would run the following:
```
cobra add serve
cobra add config
cobra add create -p 'configCmd'
```
Once you have run these three commands you would have an app structure that would look like:
```
▾ app/
▾ cmd/
serve.go
config.go
create.go
main.go
```
at this point you can run `go run main.go` and it would run your app. `go run
main.go serve`, `go run main.go config`, `go run main.go config create` along
with `go run main.go help serve`, etc would all work.
Obviously you haven't added your own code to these yet, the commands are ready
for you to give them their tasks. Have fun.
### Configuring the cobra generator
The cobra generator will be easier to use if you provide a simple configuration
file which will help you eliminate providing a bunch of repeated information in
flags over and over.
An example ~/.cobra.yaml file:
```yaml
author: Steve Francia <spf@spf13.com>
license: MIT
```
You can specify no license by setting `license` to `none` or you can specify
a custom license:
```yaml
license:
header: This file is part of {{ .appName }}.
text: |
{{ .copyright }}
This is my license. There are many like it, but this one is mine.
My license is my best friend. It is my life. I must master it as I must
master my life.
```
## Manually implementing Cobra
To manually implement cobra you need to create a bare main.go file and a RootCmd file.
You will optionally provide additional commands as you see fit. You will optionally provide additional commands as you see fit.
### Create the root command ### Create rootCmd
The root command represents your binary itself.
#### Manually create rootCmd
Cobra doesn't require any special constructors. Simply create your commands. Cobra doesn't require any special constructors. Simply create your commands.
Ideally you place this in app/cmd/root.go: Ideally you place this in app/cmd/root.go:
```go ```go
var RootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
Use: "hugo", Use: "hugo",
Short: "Hugo is a very fast static site generator", Short: "Hugo is a very fast static site generator",
Long: `A Fast and Flexible Static Site Generator built with Long: `A Fast and Flexible Static Site Generator built with
@ -275,26 +192,66 @@ var RootCmd = &cobra.Command{
// Do Stuff Here // Do Stuff Here
}, },
} }
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
``` ```
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)")
RootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory eg. github.com/spf13/") rootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory eg. github.com/spf13/")
RootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution") rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution")
RootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `licensetext` in config)") rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `licensetext` in config)")
RootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration") rootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration")
viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author")) viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
viper.BindPFlag("projectbase", RootCmd.PersistentFlags().Lookup("projectbase")) viper.BindPFlag("projectbase", rootCmd.PersistentFlags().Lookup("projectbase"))
viper.BindPFlag("useViper", RootCmd.PersistentFlags().Lookup("viper")) viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper"))
viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>") viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
viper.SetDefault("license", "apache") viper.SetDefault("license", "apache")
} }
func initConfig() {
// Don't forget to read config either from cfgFile or from home directory!
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
home, err := homedir.Dir()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// Search config in home directory with name ".cobra" (without extension).
viper.AddConfigPath(home)
viper.SetConfigName(".cobra")
}
if err := viper.ReadInConfig(); err != nil {
fmt.Println("Can't read config:", err)
os.Exit(1)
}
}
``` ```
### Create your main.go ### Create your main.go
@ -307,17 +264,18 @@ 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 { cmd.Execute()
fmt.Println(err)
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
@ -330,11 +288,13 @@ populate it with the following:
package cmd package cmd
import ( import (
"fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func init() { func init() {
RootCmd.AddCommand(versionCmd) rootCmd.AddCommand(versionCmd)
} }
var versionCmd = &cobra.Command{ var versionCmd = &cobra.Command{
@ -347,30 +307,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.
@ -395,7 +331,7 @@ command it's assigned to as well as every command under that command. For
global flags, assign a flag as a persistent flag on the root. global flags, assign a flag as a persistent flag on the root.
```go ```go
RootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
``` ```
### Local Flags ### Local Flags
@ -403,42 +339,80 @@ RootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose out
A flag can also be assigned locally which will only apply to that specific command. A flag can also be assigned locally which will only apply to that specific command.
```go ```go
RootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") rootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
``` ```
### Positional Arguments ### Local Flag on Parent Commands
Validation of positional arguments can be specified using the `Args` field, which accepts By default Cobra only parses local flags on the target command, any local flags on
one of the following values: parent commands are ignored. By enabling `Command.TraverseChildren` Cobra will
parse local flags on each command before executing the target command.
```go
command := cobra.Command{
Use: "print [OPTIONS] [COMMANDS]",
TraverseChildren: true,
}
```
### Bind Flags with Config
You can also bind your flags with [viper](https://github.com/spf13/viper):
```go
var author string
func init() {
rootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution")
viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
}
```
In this example the persistent flag `author` is bound with `viper`.
**Note**, that the variable `author` will not be set to the value from config,
when the `--author` flag is not provided by user.
More in [viper documentation](https://github.com/spf13/viper#working-with-flags).
### Required flags
Flags are optional by default. If instead you wish your command to report an error
when a flag has not been set, mark it as required:
```go
rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
rootCmd.MarkFlagRequired("region")
```
## Positional and Custom Arguments
Validation of positional arguments can be specified using the `Args` field
of `Command`.
The following validators are built in:
- `NoArgs` - the command will report an error if there are any positional args. - `NoArgs` - the command will report an error if there are any positional args.
- `ArbitraryArgs` - the command will accept any args. - `ArbitraryArgs` - the command will accept any args.
- `OnlyValidArgs` - the command will report an error if there are any positiona - `OnlyValidArgs` - the command will report an error if there are any positional args that are not in the `ValidArgs` field of `Command`.
args that are not in the `ValidArgs` list. - `MinimumNArgs(int)` - the command will report an error if there are not at least N positional args.
- `MinimumNArgs(int)` - the command will report an error if there are not at - `MaximumNArgs(int)` - the command will report an error if there are more than N positional args.
least N positional args. - `ExactArgs(int)` - the command will report an error if there are not exactly N positional args.
- `MaximumNArgs(int)` - the command will report an error if there are more than - `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args.
N positional args.
- `ExactArgs(int)` - the command will report an error if there are not
exactly N positional args.
- `RangeArgs(min, max)` - the command will report an error if the number of args
is not between the minimum and maximum number of expected args.
By default, `Args` uses the following legacy behaviour:
- root commands with no subcommands can take arbitrary arguments
- root commands with subcommands will do subcommand validity checking
- subcommands will always accept arbitrary arguments and do no subsubcommand validity checking
An example of setting the custom validator:
```go ```go
var HugoCmd = &cobra.Command{ var cmd = &cobra.Command{
Use: "hugo", Short: "hello",
Short: "Hugo is a very fast static site generator", Args: func(cmd *cobra.Command, args []string) error {
ValidArgs: []string{"one", "two"} if len(args) < 1 {
Args: cobra.OnlyValidArgs return errors.New("requires at least one arg")
}
if myapp.IsValidColor(args[0]) {
return nil
}
return fmt.Errorf("invalid color specified: %s", args[0])
},
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
// args will only have the values one, two fmt.Println("Hello, World!")
// or the cmd.Execute() will fail.
}, },
} }
``` ```
@ -465,15 +439,14 @@ import (
) )
func main() { func main() {
var echoTimes int var echoTimes int
var cmdPrint = &cobra.Command{ var cmdPrint = &cobra.Command{
Use: "print [string to print]", Use: "print [string to print]",
Short: "Print anything to the screen", Short: "Print anything to the screen",
Long: `print is for printing anything back to the screen. Long: `print is for printing anything back to the screen.
For many years people have printed back to the screen. For many years people have printed back to the screen.`,
`, Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Print: " + strings.Join(args, " ")) fmt.Println("Print: " + strings.Join(args, " "))
}, },
@ -483,8 +456,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, " "))
}, },
@ -494,7 +467,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, " "))
@ -513,7 +487,7 @@ func main() {
For a more complete example of a larger application, please checkout [Hugo](http://gohugo.io/). For a more complete example of a larger application, please checkout [Hugo](http://gohugo.io/).
## The Help Command ## Help Command
Cobra automatically adds a help command to your application when you have subcommands. Cobra automatically adds a help command to your application when you have subcommands.
This will be called when a user runs 'app help'. Additionally, help will also This will be called when a user runs 'app help'. Additionally, help will also
@ -526,60 +500,28 @@ create' is called. Every command will automatically have the '--help' flag adde
The following output is automatically generated by Cobra. Nothing beyond the The following output is automatically generated by Cobra. Nothing beyond the
command and flag definitions are needed. command and flag definitions are needed.
> hugo help $ cobra help
hugo is the main command, used to build your Hugo site. Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
Hugo is a Fast and Flexible Static Site Generator to quickly create a Cobra application.
built with love by spf13 and friends in Go.
Complete documentation is available at http://gohugo.io/.
Usage: Usage:
hugo [flags] cobra [command]
hugo [command]
Available Commands: Available Commands:
server Hugo runs its own webserver to render the files add Add a command to a Cobra Application
version Print the version number of Hugo help Help about any command
config Print the site configuration init Initialize a Cobra Application
check Check content in the source directory
benchmark Benchmark hugo by building a site a number of times.
convert Convert your content to different formats
new Create new content for your site
list Listing out various types of content
undraft Undraft changes the content's draft status from 'True' to 'False'
genautocomplete Generate shell autocompletion script for Hugo
gendoc Generate Markdown documentation for the Hugo CLI.
genman Generate man page for Hugo
import Import your site from others.
Flags: Flags:
-b, --baseURL="": hostname (and path) to the root, e.g. http://spf13.com/ -a, --author string author name for copyright attribution (default "YOUR NAME")
-D, --buildDrafts[=false]: include content marked as draft --config string config file (default is $HOME/.cobra.yaml)
-F, --buildFuture[=false]: include content with publishdate in the future -h, --help help for cobra
--cacheDir="": filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/ -l, --license string name of license for the project
--canonifyURLs[=false]: if true, all relative URLs will be canonicalized using baseURL --viper use Viper for configuration (default true)
--config="": config file (default is path/config.yaml|json|toml)
-d, --destination="": filesystem path to write files to
--disableRSS[=false]: Do not build RSS files
--disableSitemap[=false]: Do not build Sitemap file
--editor="": edit new content with this editor, if provided
--ignoreCache[=false]: Ignores the cache directory for reading but still writes to it
--log[=false]: Enable Logging
--logFile="": Log File path (if set, logging enabled automatically)
--noTimes[=false]: Don't sync modification time of files
--pluralizeListTitles[=true]: Pluralize titles in lists using inflect
--preserveTaxonomyNames[=false]: Preserve taxonomy names as written ("Gérard Depardieu" vs "gerard-depardieu")
-s, --source="": filesystem path to read files relative from
--stepAnalysis[=false]: display memory and timing of different steps of the program
-t, --theme="": theme to use (located in /themes/THEMENAME/)
--uglyURLs[=false]: if true, use /filename.html instead of /filename/
-v, --verbose[=false]: verbose output
--verboseLog[=false]: verbose logging
-w, --watch[=false]: watch filesystem for changes and recreate as needed
Use "hugo [command] --help" for more information about a command. Use "cobra [command] --help" for more information about a command.
Help is just a command like any other. There is no special logic or behavior Help is just a command like any other. There is no special logic or behavior
@ -587,38 +529,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 following functions:
The default help command is
```go ```go
func (c *Command) initHelp() { cmd.SetHelpCommand(cmd *Command)
if c.helpCommand == nil { cmd.SetHelpFunc(f func(*Command, []string))
c.helpCommand = &Command{ cmd.SetHelpTemplate(s string)
Use: "help [command]",
Short: "Help about any command",
Long: `Help provides help for any command in the application.
Simply type ` + c.Name() + ` help [path to command] for full details.`,
Run: c.HelpFunc(),
}
}
c.AddCommand(c.helpCommand)
}
```
You can provide your own command, function or template through the following methods:
```go
command.SetHelpCommand(cmd *Command)
command.SetHelpFunc(f func(*Command, []string))
command.SetHelpTemplate(s string)
``` ```
The latter two will also apply to any children commands. The latter two will also apply to any children commands.
## Usage ## Usage Message
When the user provides an invalid flag or invalid command, Cobra responds by When the user provides an invalid flag or invalid command, Cobra responds by
showing the user the 'usage'. showing the user the 'usage'.
@ -627,73 +549,44 @@ 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 ## Version Flag
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: Cobra adds a top-level '--version' flag if the Version field is set on the root command.
Running an application with the '--version' flag will print the version to stdout using
the version template. The template can be customized using the
`cmd.SetVersionTemplate(s string)` function.
## 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 inherited by children if they do not declare their own. These functions are run in the following order:
- `PersistentPreRun` - `PersistentPreRun`
- `PreRun` - `PreRun`
@ -754,58 +647,26 @@ func main() {
rootCmd.AddCommand(subCmd) rootCmd.AddCommand(subCmd)
rootCmd.SetArgs([]string{""}) rootCmd.SetArgs([]string{""})
_ = rootCmd.Execute() rootCmd.Execute()
fmt.Print("\n") fmt.Println()
rootCmd.SetArgs([]string{"sub", "arg1", "arg2"}) rootCmd.SetArgs([]string{"sub", "arg1", "arg2"})
_ = rootCmd.Execute() rootCmd.Execute()
} }
``` ```
Output:
```
Inside rootCmd PersistentPreRun with args: []
Inside rootCmd PreRun with args: []
Inside rootCmd Run with args: []
Inside rootCmd PostRun with args: []
Inside rootCmd PersistentPostRun with args: []
## Alternative Error Handling Inside rootCmd PersistentPreRun with args: [arg1 arg2]
Inside subCmd PreRun with args: [arg1 arg2]
Cobra also has functions where the return signature is an error. This allows for errors to bubble up to the top, Inside subCmd Run with args: [arg1 arg2]
providing a way to handle the errors in one location. The current list of functions that return an error is: Inside subCmd PostRun with args: [arg1 arg2]
Inside subCmd PersistentPostRun with args: [arg1 arg2]
* PersistentPreRunE
* PreRunE
* RunE
* PostRunE
* PersistentPostRunE
If you would like to silence the default `error` and `usage` output in favor of your own, you can set `SilenceUsage`
and `SilenceErrors` to `false` on the command. A child command respects these flags if they are set on the parent
command.
**Example Usage using RunE:**
```go
package main
import (
"errors"
"log"
"github.com/spf13/cobra"
)
func main() {
var rootCmd = &cobra.Command{
Use: "hugo",
Short: "Hugo is a very fast static site generator",
Long: `A Fast and Flexible Static Site Generator built with
love by spf13 and friends in Go.
Complete documentation is available at http://hugo.spf13.com`,
RunE: func(cmd *cobra.Command, args []string) error {
// Do Stuff Here
return errors.New("some random error")
},
}
if err := rootCmd.Execute(); err != nil {
log.Fatal(err)
}
}
``` ```
## Suggestions when "unknown command" happens ## Suggestions when "unknown command" happens
@ -848,81 +709,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")

View file

@ -16,14 +16,14 @@ func legacyArgs(cmd *Command, args []string) error {
return nil return nil
} }
// root command with subcommands, do subcommand checking // root command with subcommands, do subcommand checking.
if !cmd.HasParent() && len(args) > 0 { if !cmd.HasParent() && len(args) > 0 {
return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0])) return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0]))
} }
return nil return nil
} }
// NoArgs returns an error if any args are included // NoArgs returns an error if any args are included.
func NoArgs(cmd *Command, args []string) error { func NoArgs(cmd *Command, args []string) error {
if len(args) > 0 { if len(args) > 0 {
return fmt.Errorf("unknown command %q for %q", args[0], cmd.CommandPath()) return fmt.Errorf("unknown command %q for %q", args[0], cmd.CommandPath())
@ -31,7 +31,7 @@ func NoArgs(cmd *Command, args []string) error {
return nil return nil
} }
// OnlyValidArgs returns an error if any args are not in the list of ValidArgs // OnlyValidArgs returns an error if any args are not in the list of ValidArgs.
func OnlyValidArgs(cmd *Command, args []string) error { func OnlyValidArgs(cmd *Command, args []string) error {
if len(cmd.ValidArgs) > 0 { if len(cmd.ValidArgs) > 0 {
for _, v := range args { for _, v := range args {
@ -43,21 +43,12 @@ func OnlyValidArgs(cmd *Command, args []string) error {
return nil return nil
} }
func stringInSlice(a string, list []string) bool { // ArbitraryArgs never returns an error.
for _, b := range list {
if b == a {
return true
}
}
return false
}
// ArbitraryArgs never returns an error
func ArbitraryArgs(cmd *Command, args []string) error { func ArbitraryArgs(cmd *Command, args []string) error {
return nil return nil
} }
// MinimumNArgs returns an error if there is not at least N args // MinimumNArgs returns an error if there is not at least N args.
func MinimumNArgs(n int) PositionalArgs { func MinimumNArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error { return func(cmd *Command, args []string) error {
if len(args) < n { if len(args) < n {
@ -67,7 +58,7 @@ func MinimumNArgs(n int) PositionalArgs {
} }
} }
// MaximumNArgs returns an error if there are more than N args // MaximumNArgs returns an error if there are more than N args.
func MaximumNArgs(n int) PositionalArgs { func MaximumNArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error { return func(cmd *Command, args []string) error {
if len(args) > n { if len(args) > n {
@ -77,7 +68,7 @@ func MaximumNArgs(n int) PositionalArgs {
} }
} }
// ExactArgs returns an error if there are not exactly n args // ExactArgs returns an error if there are not exactly n args.
func ExactArgs(n int) PositionalArgs { func ExactArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error { return func(cmd *Command, args []string) error {
if len(args) != n { if len(args) != n {
@ -87,7 +78,7 @@ func ExactArgs(n int) PositionalArgs {
} }
} }
// RangeArgs returns an error if the number of args is not within the expected range // RangeArgs returns an error if the number of args is not within the expected range.
func RangeArgs(min int, max int) PositionalArgs { func RangeArgs(min int, max int) PositionalArgs {
return func(cmd *Command, args []string) error { return func(cmd *Command, args []string) error {
if len(args) < min || len(args) > max { if len(args) < min || len(args) > max {

View file

@ -1,6 +1,7 @@
package cobra package cobra
import ( import (
"bytes"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -10,20 +11,18 @@ 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(fmt.Sprintf(`
return err __%[1]s_debug()
}
_, err = fmt.Fprint(out, `
__debug()
{ {
if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then
echo "$*" >> "${BASH_COMP_DEBUG_FILE}" echo "$*" >> "${BASH_COMP_DEBUG_FILE}"
@ -32,13 +31,13 @@ __debug()
# Homebrew on Macs have version 1.3 of bash-completion which doesn't include # Homebrew on Macs have version 1.3 of bash-completion which doesn't include
# _init_completion. This is a very minimal version of that function. # _init_completion. This is a very minimal version of that function.
__my_init_completion() __%[1]s_init_completion()
{ {
COMPREPLY=() COMPREPLY=()
_get_comp_words_by_ref "$@" cur prev words cword _get_comp_words_by_ref "$@" cur prev words cword
} }
__index_of_word() __%[1]s_index_of_word()
{ {
local w word=$1 local w word=$1
shift shift
@ -50,7 +49,7 @@ __index_of_word()
index=-1 index=-1
} }
__contains_word() __%[1]s_contains_word()
{ {
local w word=$1; shift local w word=$1; shift
for w in "$@"; do for w in "$@"; do
@ -59,9 +58,9 @@ __contains_word()
return 1 return 1
} }
__handle_reply() __%[1]s_handle_reply()
{ {
__debug "${FUNCNAME[0]}" __%[1]s_debug "${FUNCNAME[0]}"
case $cur in case $cur in
-*) -*)
if [[ $(type -t compopt) = "builtin" ]]; then if [[ $(type -t compopt) = "builtin" ]]; then
@ -86,14 +85,14 @@ __handle_reply()
local index flag local index flag
flag="${cur%%=*}" flag="${cur%%=*}"
__index_of_word "${flag}" "${flags_with_completion[@]}" __%[1]s_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
@ -104,7 +103,7 @@ __handle_reply()
# check if we are handling a flag with special work handling # check if we are handling a flag with special work handling
local index local index
__index_of_word "${prev}" "${flags_with_completion[@]}" __%[1]s_index_of_word "${prev}" "${flags_with_completion[@]}"
if [[ ${index} -ge 0 ]]; then if [[ ${index} -ge 0 ]]; then
${flags_completion[${index}]} ${flags_completion[${index}]}
return return
@ -133,25 +132,34 @@ __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
# If there is only 1 completion and it is a flag with an = it will be completed
# but we don't want a space after the =
if [[ "${#COMPREPLY[@]}" -eq "1" ]] && [[ $(type -t compopt) = "builtin" ]] && [[ "${COMPREPLY[0]}" == --*= ]]; then
compopt -o nospace
fi
} }
# The arguments should be in the form "ext1|ext2|extn" # The arguments should be in the form "ext1|ext2|extn"
__handle_filename_extension_flag() __%[1]s_handle_filename_extension_flag()
{ {
local ext="$1" local ext="$1"
_filedir "@(${ext})" _filedir "@(${ext})"
} }
__handle_subdirs_in_dir_flag() __%[1]s_handle_subdirs_in_dir_flag()
{ {
local dir="$1" local dir="$1"
pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1
} }
__handle_flag() __%[1]s_handle_flag()
{ {
__debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" __%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
# if a command required a flag, and we found it, unset must_have_one_flag() # if a command required a flag, and we found it, unset must_have_one_flag()
local flagname=${words[c]} local flagname=${words[c]}
@ -162,17 +170,19 @@ __handle_flag()
flagname=${flagname%%=*} # strip everything after the = flagname=${flagname%%=*} # strip everything after the =
flagname="${flagname}=" # but put the = back flagname="${flagname}=" # but put the = back
fi fi
__debug "${FUNCNAME[0]}: looking for ${flagname}" __%[1]s_debug "${FUNCNAME[0]}: looking for ${flagname}"
if __contains_word "${flagname}" "${must_have_one_flag[@]}"; then if __%[1]s_contains_word "${flagname}" "${must_have_one_flag[@]}"; then
must_have_one_flag=() must_have_one_flag=()
fi fi
# if you set a flag which only applies to this command, don't show subcommands # if you set a flag which only applies to this command, don't show subcommands
if __contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then if __%[1]s_contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then
commands=() commands=()
fi fi
# keep flag value with flagname as flaghash # keep flag value with flagname as flaghash
# flaghash variable is an associative array which is only supported in bash > 3.
if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then
if [ -n "${flagvalue}" ] ; then if [ -n "${flagvalue}" ] ; then
flaghash[${flagname}]=${flagvalue} flaghash[${flagname}]=${flagvalue}
elif [ -n "${words[ $((c+1)) ]}" ] ; then elif [ -n "${words[ $((c+1)) ]}" ] ; then
@ -180,9 +190,10 @@ __handle_flag()
else else
flaghash[${flagname}]="true" # pad "true" for bool flag flaghash[${flagname}]="true" # pad "true" for bool flag
fi fi
fi
# skip the argument to a two word flag # skip the argument to a two word flag
if __contains_word "${words[c]}" "${two_word_flags[@]}"; then if __%[1]s_contains_word "${words[c]}" "${two_word_flags[@]}"; then
c=$((c+1)) c=$((c+1))
# if we are looking for a flags value, don't show commands # if we are looking for a flags value, don't show commands
if [[ $c -eq $cword ]]; then if [[ $c -eq $cword ]]; then
@ -194,13 +205,13 @@ __handle_flag()
} }
__handle_noun() __%[1]s_handle_noun()
{ {
__debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" __%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
if __contains_word "${words[c]}" "${must_have_one_noun[@]}"; then if __%[1]s_contains_word "${words[c]}" "${must_have_one_noun[@]}"; then
must_have_one_noun=() must_have_one_noun=()
elif __contains_word "${words[c]}" "${noun_aliases[@]}"; then elif __%[1]s_contains_word "${words[c]}" "${noun_aliases[@]}"; then
must_have_one_noun=() must_have_one_noun=()
fi fi
@ -208,61 +219,66 @@ __handle_noun()
c=$((c+1)) c=$((c+1))
} }
__handle_command() __%[1]s_handle_command()
{ {
__debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" __%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
local next_command local next_command
if [[ -n ${last_command} ]]; then if [[ -n ${last_command} ]]; then
next_command="_${last_command}_${words[c]//:/__}" next_command="_${last_command}_${words[c]//:/__}"
else else
if [[ $c -eq 0 ]]; then if [[ $c -eq 0 ]]; then
next_command="_$(basename "${words[c]//:/__}")" next_command="_%[1]s_root_command"
else else
next_command="_${words[c]//:/__}" next_command="_${words[c]//:/__}"
fi fi
fi fi
c=$((c+1)) c=$((c+1))
__debug "${FUNCNAME[0]}: looking for ${next_command}" __%[1]s_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() __%[1]s_handle_word()
{ {
if [[ $c -ge $cword ]]; then if [[ $c -ge $cword ]]; then
__handle_reply __%[1]s_handle_reply
return return
fi fi
__debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" __%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
if [[ "${words[c]}" == -* ]]; then if [[ "${words[c]}" == -* ]]; then
__handle_flag __%[1]s_handle_flag
elif __contains_word "${words[c]}" "${commands[@]}"; then elif __%[1]s_contains_word "${words[c]}" "${commands[@]}"; then
__handle_command __%[1]s_handle_command
elif [[ $c -eq 0 ]] && __contains_word "$(basename "${words[c]}")" "${commands[@]}"; then elif [[ $c -eq 0 ]]; then
__handle_command __%[1]s_handle_command
elif __%[1]s_contains_word "${words[c]}" "${command_aliases[@]}"; then
# aliashash variable is an associative array which is only supported in bash > 3.
if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then
words[c]=${aliashash[${words[c]}]}
__%[1]s_handle_command
else else
__handle_noun __%[1]s_handle_noun
fi fi
__handle_word else
__%[1]s_handle_noun
fi
__%[1]s_handle_word
} }
`) `, name))
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 || :
declare -A aliashash 2>/dev/null || :
if declare -F _init_completion >/dev/null 2>&1; then if declare -F _init_completion >/dev/null 2>&1; then
_init_completion -s || return _init_completion -s || return
else else
__my_init_completion -n "=" || return __%[1]s_init_completion -n "=" || return
fi fi
local c=0 local c=0
@ -271,350 +287,288 @@ func postscript(w io.Writer, name string) error {
local local_nonpersistent_flags=() local local_nonpersistent_flags=()
local flags_with_completion=() local flags_with_completion=()
local flags_completion=() local flags_completion=()
local commands=("%s") local commands=("%[1]s")
local must_have_one_flag=() local must_have_one_flag=()
local must_have_one_noun=() local must_have_one_noun=()
local last_command local last_command
local nouns=() local nouns=()
__handle_word __%[1]s_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 writeCmdAliases(buf, c)
} }
} 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, cmd *Command) {
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 = fmt.Sprintf("__%s_handle_filename_extension_flag ", cmd.Root().Name()) + 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 = fmt.Sprintf("__%s_handle_subdirs_in_dir_flag ", cmd.Root().Name()) + 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, cmd *Command) {
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, cmd)
}
return writeFlagHandler("-"+name, flag.Annotations, w)
} }
func writeFlag(flag *pflag.Flag, w io.Writer) error { func writeFlag(buf *bytes.Buffer, flag *pflag.Flag, cmd *Command) {
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, cmd)
}
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, cmd)
if len(flag.Shorthand) > 0 { if len(flag.Shorthand) > 0 {
if err := writeShortFlag(flag, w); err != nil { writeShortFlag(buf, flag, cmd)
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, cmd)
if len(flag.Shorthand) > 0 { if len(flag.Shorthand) > 0 {
if err := writeShortFlag(flag, w); err != nil { writeShortFlag(buf, flag, cmd)
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 writeCmdAliases(buf *bytes.Buffer, cmd *Command) {
if _, err := fmt.Fprintf(w, " noun_aliases=()\n"); err != nil { if len(cmd.Aliases) == 0 {
return err return
} }
sort.Sort(sort.StringSlice(cmd.Aliases))
buf.WriteString(fmt.Sprint(` if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then`, "\n"))
for _, value := range cmd.Aliases {
buf.WriteString(fmt.Sprintf(" command_aliases+=(%q)\n", value))
buf.WriteString(fmt.Sprintf(" aliashash[%q]=%q\n", value, cmd.Name()))
}
buf.WriteString(` fi`)
buf.WriteString("\n")
}
func writeArgAliases(buf *bytes.Buffer, cmd *Command) {
buf.WriteString(" noun_aliases=()\n")
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 {
return err if cmd.Root() == cmd {
buf.WriteString(fmt.Sprintf("_%s_root_command()\n{\n", commandName))
} else {
buf.WriteString(fmt.Sprintf("_%s()\n{\n", commandName))
} }
if _, err := fmt.Fprintf(w, " last_command=%q\n", commandName); err != nil {
return err buf.WriteString(fmt.Sprintf(" last_command=%q\n", commandName))
} buf.WriteString("\n")
if err := writeCommands(cmd, w); err != nil { buf.WriteString(" command_aliases=()\n")
return err buf.WriteString("\n")
}
if err := writeFlags(cmd, w); err != nil { writeCommands(buf, cmd)
return err writeFlags(buf, cmd)
} writeRequiredFlag(buf, cmd)
if err := writeRequiredFlag(cmd, w); err != nil { writeRequiredNouns(buf, cmd)
return err writeArgAliases(buf, cmd)
} buf.WriteString("}\n\n")
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 { // and causes your command to report an error if invoked without the flag.
return MarkFlagRequired(cmd.Flags(), name) func (c *Command) MarkFlagRequired(name string) error {
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 { // and causes your command to report an error if invoked without the flag.
return MarkFlagRequired(cmd.PersistentFlags(), name) func (c *Command) MarkPersistentFlagRequired(name string) error {
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 if it exists,
// and causes your command to report an error if invoked without the flag.
func MarkFlagRequired(flags *pflag.FlagSet, name string) error { func MarkFlagRequired(flags *pflag.FlagSet, name string) error {
return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"}) return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"})
} }
// 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,49 @@ 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 sets the passed functions to be run when each command's
// Execute method is called.
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 +108,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 +130,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 +140,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 +154,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)
@ -173,3 +189,12 @@ func ld(s, t string, ignoreCase bool) int {
} }
return d[len(s)][len(t)] return d[len(s)][len(t)]
} }
func stringInSlice(a string, list []string) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}

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

105
vendor/github.com/spf13/pflag/bytes.go generated vendored Normal file
View file

@ -0,0 +1,105 @@
package pflag
import (
"encoding/hex"
"fmt"
"strings"
)
// BytesHex adapts []byte for use as a flag. Value of flag is HEX encoded
type bytesHexValue []byte
func (bytesHex bytesHexValue) String() string {
return fmt.Sprintf("%X", []byte(bytesHex))
}
func (bytesHex *bytesHexValue) Set(value string) error {
bin, err := hex.DecodeString(strings.TrimSpace(value))
if err != nil {
return err
}
*bytesHex = bin
return nil
}
func (*bytesHexValue) Type() string {
return "bytesHex"
}
func newBytesHexValue(val []byte, p *[]byte) *bytesHexValue {
*p = val
return (*bytesHexValue)(p)
}
func bytesHexConv(sval string) (interface{}, error) {
bin, err := hex.DecodeString(sval)
if err == nil {
return bin, nil
}
return nil, fmt.Errorf("invalid string being converted to Bytes: %s %s", sval, err)
}
// GetBytesHex return the []byte value of a flag with the given name
func (f *FlagSet) GetBytesHex(name string) ([]byte, error) {
val, err := f.getFlagType(name, "bytesHex", bytesHexConv)
if err != nil {
return []byte{}, err
}
return val.([]byte), nil
}
// BytesHexVar defines an []byte flag with specified name, default value, and usage string.
// The argument p points to an []byte variable in which to store the value of the flag.
func (f *FlagSet) BytesHexVar(p *[]byte, name string, value []byte, usage string) {
f.VarP(newBytesHexValue(value, p), name, "", usage)
}
// BytesHexVarP is like BytesHexVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) BytesHexVarP(p *[]byte, name, shorthand string, value []byte, usage string) {
f.VarP(newBytesHexValue(value, p), name, shorthand, usage)
}
// BytesHexVar defines an []byte flag with specified name, default value, and usage string.
// The argument p points to an []byte variable in which to store the value of the flag.
func BytesHexVar(p *[]byte, name string, value []byte, usage string) {
CommandLine.VarP(newBytesHexValue(value, p), name, "", usage)
}
// BytesHexVarP is like BytesHexVar, but accepts a shorthand letter that can be used after a single dash.
func BytesHexVarP(p *[]byte, name, shorthand string, value []byte, usage string) {
CommandLine.VarP(newBytesHexValue(value, p), name, shorthand, usage)
}
// BytesHex defines an []byte flag with specified name, default value, and usage string.
// The return value is the address of an []byte variable that stores the value of the flag.
func (f *FlagSet) BytesHex(name string, value []byte, usage string) *[]byte {
p := new([]byte)
f.BytesHexVarP(p, name, "", value, usage)
return p
}
// BytesHexP is like BytesHex, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) BytesHexP(name, shorthand string, value []byte, usage string) *[]byte {
p := new([]byte)
f.BytesHexVarP(p, name, shorthand, value, usage)
return p
}
// BytesHex defines an []byte flag with specified name, default value, and usage string.
// The return value is the address of an []byte variable that stores the value of the flag.
func BytesHex(name string, value []byte, usage string) *[]byte {
return CommandLine.BytesHexP(name, "", value, usage)
}
// BytesHexP is like BytesHex, but accepts a shorthand letter that can be used after a single dash.
func BytesHexP(name, shorthand string, value []byte, usage string) *[]byte {
return CommandLine.BytesHexP(name, shorthand, value, usage)
}

View file

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

128
vendor/github.com/spf13/pflag/duration_slice.go generated vendored Normal file
View file

@ -0,0 +1,128 @@
package pflag
import (
"fmt"
"strings"
"time"
)
// -- durationSlice Value
type durationSliceValue struct {
value *[]time.Duration
changed bool
}
func newDurationSliceValue(val []time.Duration, p *[]time.Duration) *durationSliceValue {
dsv := new(durationSliceValue)
dsv.value = p
*dsv.value = val
return dsv
}
func (s *durationSliceValue) Set(val string) error {
ss := strings.Split(val, ",")
out := make([]time.Duration, len(ss))
for i, d := range ss {
var err error
out[i], err = time.ParseDuration(d)
if err != nil {
return err
}
}
if !s.changed {
*s.value = out
} else {
*s.value = append(*s.value, out...)
}
s.changed = true
return nil
}
func (s *durationSliceValue) Type() string {
return "durationSlice"
}
func (s *durationSliceValue) String() string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = fmt.Sprintf("%s", d)
}
return "[" + strings.Join(out, ",") + "]"
}
func durationSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
if len(val) == 0 {
return []time.Duration{}, nil
}
ss := strings.Split(val, ",")
out := make([]time.Duration, len(ss))
for i, d := range ss {
var err error
out[i], err = time.ParseDuration(d)
if err != nil {
return nil, err
}
}
return out, nil
}
// GetDurationSlice returns the []time.Duration value of a flag with the given name
func (f *FlagSet) GetDurationSlice(name string) ([]time.Duration, error) {
val, err := f.getFlagType(name, "durationSlice", durationSliceConv)
if err != nil {
return []time.Duration{}, err
}
return val.([]time.Duration), nil
}
// DurationSliceVar defines a durationSlice flag with specified name, default value, and usage string.
// The argument p points to a []time.Duration variable in which to store the value of the flag.
func (f *FlagSet) DurationSliceVar(p *[]time.Duration, name string, value []time.Duration, usage string) {
f.VarP(newDurationSliceValue(value, p), name, "", usage)
}
// DurationSliceVarP is like DurationSliceVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) DurationSliceVarP(p *[]time.Duration, name, shorthand string, value []time.Duration, usage string) {
f.VarP(newDurationSliceValue(value, p), name, shorthand, usage)
}
// DurationSliceVar defines a duration[] flag with specified name, default value, and usage string.
// The argument p points to a duration[] variable in which to store the value of the flag.
func DurationSliceVar(p *[]time.Duration, name string, value []time.Duration, usage string) {
CommandLine.VarP(newDurationSliceValue(value, p), name, "", usage)
}
// DurationSliceVarP is like DurationSliceVar, but accepts a shorthand letter that can be used after a single dash.
func DurationSliceVarP(p *[]time.Duration, name, shorthand string, value []time.Duration, usage string) {
CommandLine.VarP(newDurationSliceValue(value, p), name, shorthand, usage)
}
// DurationSlice defines a []time.Duration flag with specified name, default value, and usage string.
// The return value is the address of a []time.Duration variable that stores the value of the flag.
func (f *FlagSet) DurationSlice(name string, value []time.Duration, usage string) *[]time.Duration {
p := []time.Duration{}
f.DurationSliceVarP(&p, name, "", value, usage)
return &p
}
// DurationSliceP is like DurationSlice, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) DurationSliceP(name, shorthand string, value []time.Duration, usage string) *[]time.Duration {
p := []time.Duration{}
f.DurationSliceVarP(&p, name, shorthand, value, usage)
return &p
}
// DurationSlice defines a []time.Duration flag with specified name, default value, and usage string.
// The return value is the address of a []time.Duration variable that stores the value of the flag.
func DurationSlice(name string, value []time.Duration, usage string) *[]time.Duration {
return CommandLine.DurationSliceP(name, "", value, usage)
}
// DurationSliceP is like DurationSlice, but accepts a shorthand letter that can be used after a single dash.
func DurationSliceP(name, shorthand string, value []time.Duration, usage string) *[]time.Duration {
return CommandLine.DurationSliceP(name, shorthand, value, usage)
}

352
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
@ -101,6 +101,7 @@ package pflag
import ( import (
"bytes" "bytes"
"errors" "errors"
goflag "flag"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -123,6 +124,12 @@ const (
PanicOnError PanicOnError
) )
// ParseErrorsWhitelist defines the parsing errors that can be ignored
type ParseErrorsWhitelist struct {
// UnknownFlags will ignore unknown flags errors and continue parsing rest of the flags
UnknownFlags bool
}
// NormalizedName is a flag name that has been normalized according to rules // NormalizedName is a flag name that has been normalized according to rules
// for the FlagSet (e.g. making '-' and '_' equivalent). // for the FlagSet (e.g. making '-' and '_' equivalent).
type NormalizedName string type NormalizedName string
@ -134,18 +141,30 @@ 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
// ParseErrorsWhitelist is used to configure a whitelist of errors
ParseErrorsWhitelist ParseErrorsWhitelist
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
normalizeNameFunc func(f *FlagSet, name string) NormalizedName normalizeNameFunc func(f *FlagSet, name string) NormalizedName
addedGoFlagSets []*goflag.FlagSet
} }
// A Flag represents the state of a flag. // A Flag represents the state of a flag.
@ -156,7 +175,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 +213,19 @@ func sortFlags(flags map[NormalizedName]*Flag) []*Flag {
// "--getUrl" which may also be translated to "geturl" and everything will work. // "--getUrl" which may also be translated to "geturl" and everything will work.
func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) { func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) {
f.normalizeNameFunc = n f.normalizeNameFunc = n
for k, v := range f.formal { f.sortedFormal = f.sortedFormal[:0]
delete(f.formal, k) for fname, flag := range f.formal {
nname := f.normalizeFlagName(string(k)) nname := f.normalizeFlagName(flag.Name)
f.formal[nname] = v if fname == nname {
v.Name = string(nname) continue
}
flag.Name = string(nname)
delete(f.formal, fname)
f.formal[nname] = flag
if _, set := f.actual[fname]; set {
delete(f.actual, fname)
f.actual[nname] = flag
}
} }
} }
@ -229,46 +256,78 @@ 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)
} }
} }
// HasFlags returns a bool to indicate if the FlagSet has any flags definied. // HasFlags returns a bool to indicate if the FlagSet has any flags defined.
func (f *FlagSet) HasFlags() bool { func (f *FlagSet) HasFlags() bool {
return len(f.formal) > 0 return len(f.formal) > 0
} }
// HasAvailableFlags returns a bool to indicate if the FlagSet has any flags // HasAvailableFlags returns a bool to indicate if the FlagSet has any flags
// definied that are not hidden or deprecated. // that are not hidden.
func (f *FlagSet) HasAvailableFlags() bool { func (f *FlagSet) HasAvailableFlags() bool {
for _, flag := range f.formal { for _, flag := range f.formal {
if !flag.Hidden && len(flag.Deprecated) == 0 { if !flag.Hidden {
return true return true
} }
} }
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 +337,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,10 +394,11 @@ 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
flag.Hidden = true
return nil return nil
} }
@ -334,7 +410,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 +434,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 +447,30 @@ func (f *FlagSet) Set(name, value string) error {
if !ok { if !ok {
return fmt.Errorf("no such flag -%v", name) return fmt.Errorf("no such flag -%v", name)
} }
err := flag.Value.Set(value) err := flag.Value.Set(value)
if err != nil { if err != nil {
return err var flagName string
if flag.Shorthand != "" && flag.ShorthandDeprecated == "" {
flagName = fmt.Sprintf("-%s, --%s", flag.Shorthand, flag.Name)
} else {
flagName = fmt.Sprintf("--%s", flag.Name)
} }
return fmt.Errorf("invalid argument %q for %q flag: %v", value, flagName, err)
}
if !flag.Changed {
if f.actual == nil { if f.actual == nil {
f.actual = make(map[NormalizedName]*Flag) f.actual = make(map[NormalizedName]*Flag)
} }
f.actual[normalName] = flag f.actual[normalName] = flag
f.orderedActual = append(f.orderedActual, flag)
flag.Changed = true flag.Changed = true
if len(flag.Deprecated) > 0 { }
fmt.Fprintf(os.Stderr, "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
if flag.Deprecated != "" {
fmt.Fprintf(f.out(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
} }
return nil return nil
} }
@ -482,6 +577,14 @@ func UnquoteUsage(flag *Flag) (name string, usage string) {
name = "int" name = "int"
case "uint64": case "uint64":
name = "uint" name = "uint"
case "stringSlice":
name = "strings"
case "intSlice":
name = "ints"
case "uintSlice":
name = "uints"
case "boolSlice":
name = "bools"
} }
return return
@ -496,11 +599,14 @@ func wrapN(i, slop int, s string) (string, string) {
return s, "" return s, ""
} }
w := strings.LastIndexAny(s[:i], " \t") w := strings.LastIndexAny(s[:i], " \t\n")
if w <= 0 { if w <= 0 {
return s, "" return s, ""
} }
nlPos := strings.LastIndex(s[:i], "\n")
if nlPos > 0 && nlPos < w {
return s[:nlPos], s[nlPos+1:]
}
return s[:w], s[w+1:] return s[:w], s[w+1:]
} }
@ -509,7 +615,7 @@ func wrapN(i, slop int, s string) (string, string) {
// caller). Pass `w` == 0 to do no wrapping // caller). Pass `w` == 0 to do no wrapping
func wrap(i, w int, s string) string { func wrap(i, w int, s string) string {
if w == 0 { if w == 0 {
return s return strings.Replace(s, "\n", "\n"+strings.Repeat(" ", i), -1)
} }
// space between indent i and end of line width w into which // space between indent i and end of line width w into which
@ -527,7 +633,7 @@ func wrap(i, w int, s string) string {
} }
// If still not enough space then don't even try to wrap. // If still not enough space then don't even try to wrap.
if wrap < 24 { if wrap < 24 {
return s return strings.Replace(s, "\n", r, -1)
} }
// Try to avoid short orphan words on the final line, by // Try to avoid short orphan words on the final line, by
@ -539,14 +645,14 @@ func wrap(i, w int, s string) string {
// Handle first line, which is indented by the caller (or the // Handle first line, which is indented by the caller (or the
// special case above) // special case above)
l, s = wrapN(wrap, slop, s) l, s = wrapN(wrap, slop, s)
r = r + l r = r + strings.Replace(l, "\n", "\n"+strings.Repeat(" ", i), -1)
// Now wrap the rest // Now wrap the rest
for s != "" { for s != "" {
var t string var t string
t, s = wrapN(wrap, slop, s) t, s = wrapN(wrap, slop, s)
r = r + "\n" + strings.Repeat(" ", i) + t r = r + "\n" + strings.Repeat(" ", i) + strings.Replace(t, "\n", "\n"+strings.Repeat(" ", i), -1)
} }
return r return r
@ -557,28 +663,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.Hidden {
return return
} }
line := "" line := ""
if len(flag.Shorthand) > 0 && len(flag.ShorthandDeprecated) == 0 { if flag.Shorthand != "" && flag.ShorthandDeprecated == "" {
line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name) line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name)
} else { } else {
line = fmt.Sprintf(" --%s", flag.Name) line = fmt.Sprintf(" --%s", flag.Name)
} }
varname, usage := UnquoteUsage(flag) varname, usage := UnquoteUsage(flag)
if len(varname) > 0 { if varname != "" {
line += " " + varname line += " " + varname
} }
if len(flag.NoOptDefVal) > 0 { if flag.NoOptDefVal != "" {
switch flag.Value.Type() { switch flag.Value.Type() {
case "string": case "string":
line += fmt.Sprintf("[=\"%s\"]", flag.NoOptDefVal) line += fmt.Sprintf("[=\"%s\"]", flag.NoOptDefVal)
@ -586,6 +692,10 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string {
if flag.NoOptDefVal != "true" { if flag.NoOptDefVal != "true" {
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
} }
case "count":
if flag.NoOptDefVal != "+1" {
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
}
default: default:
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
} }
@ -601,11 +711,14 @@ 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)
} }
} }
if len(flag.Deprecated) != 0 {
line += fmt.Sprintf(" (DEPRECATED: %s)", flag.Deprecated)
}
lines = append(lines, line) lines = append(lines, line)
}) })
@ -614,10 +727,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 +827,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 +841,31 @@ func (f *FlagSet) AddFlag(flag *Flag) {
flag.Name = string(normalizedFlagName) flag.Name = string(normalizedFlagName)
f.formal[normalizedFlagName] = flag f.formal[normalizedFlagName] = flag
f.orderedFormal = append(f.orderedFormal, flag)
if len(flag.Shorthand) == 0 { if flag.Shorthand == "" {
return return
} }
if len(flag.Shorthand) > 1 { if len(flag.Shorthand) > 1 {
fmt.Fprintf(f.out(), "%s shorthand more than ASCII character: %s\n", f.name, flag.Shorthand) msg := fmt.Sprintf("%q shorthand is more than one ASCII character", flag.Shorthand)
panic("shorthand is more than one character") fmt.Fprintf(f.out(), msg)
panic(msg)
} }
if f.shorthands == nil { if f.shorthands == nil {
f.shorthands = make(map[byte]*Flag) f.shorthands = make(map[byte]*Flag)
} }
c := flag.Shorthand[0] c := flag.Shorthand[0]
old, alreadythere := f.shorthands[c] used, alreadyThere := f.shorthands[c]
if alreadythere { if alreadyThere {
fmt.Fprintf(f.out(), "%s shorthand reused: %q for %s already used for %s\n", f.name, c, flag.Name, old.Name) msg := fmt.Sprintf("unable to redefine %q shorthand in %q flagset: it's already used for %q flag", c, f.name, used.Name)
panic("shorthand redefinition") fmt.Fprintf(f.out(), msg)
panic(msg)
} }
f.shorthands[c] = flag f.shorthands[c] = flag
} }
// AddFlagSet adds one FlagSet to another. If a flag is already present in f // AddFlagSet adds one FlagSet to another. If a flag is already present in f
// the flag from newSet will be ignored // the flag from newSet will be ignored.
func (f *FlagSet) AddFlagSet(newSet *FlagSet) { func (f *FlagSet) AddFlagSet(newSet *FlagSet) {
if newSet == nil { if newSet == nil {
return return
@ -781,8 +896,10 @@ func VarP(value Value, name, shorthand, usage string) {
// returns the error. // returns the error.
func (f *FlagSet) failf(format string, a ...interface{}) error { func (f *FlagSet) failf(format string, a ...interface{}) error {
err := fmt.Errorf(format, a...) err := fmt.Errorf(format, a...)
if f.errorHandling != ContinueOnError {
fmt.Fprintln(f.out(), err) fmt.Fprintln(f.out(), err)
f.usage() f.usage()
}
return err return err
} }
@ -798,32 +915,23 @@ func (f *FlagSet) usage() {
} }
} }
func (f *FlagSet) setFlag(flag *Flag, value string, origArg string) error { //--unknown (args will be empty)
if err := flag.Value.Set(value); err != nil { //--unknown --next-flag ... (args will be --next-flag ...)
return f.failf("invalid argument %q for %s: %v", value, origArg, err) //--unknown arg ... (args will be arg ...)
func stripUnknownFlagValue(args []string) []string {
if len(args) == 0 {
//--unknown
return args
} }
// 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 { first := args[0]
// filter out flags --<flag_name> if first[0] == '-' {
if strings.HasPrefix(arg, "-") { //--unknown --next-flag ...
return false return args
} }
arg = strings.SplitN(arg, "=", 2)[0]
return strings.Contains(arg, shorthand) //--unknown arg ... (args will be arg ...)
return args[1:]
} }
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) {
@ -833,22 +941,35 @@ 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 name == "help" { // special case for nice help message. if !exists {
switch {
case name == "help":
f.usage() f.usage()
return a, ErrHelp return a, ErrHelp
case f.ParseErrorsWhitelist.UnknownFlags:
// --unknown=unknownval arg ...
// we do not want to lose arg in this case
if len(split) >= 2 {
return a, nil
} }
return stripUnknownFlagValue(a), nil
default:
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 +981,11 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin
err = f.failf("flag needs an argument: %s", s) err = f.failf("flag needs an argument: %s", s)
return return
} }
err = fn(flag, value, s)
err = fn(flag, value)
if err != nil {
f.failf(err.Error())
}
return return
} }
@ -868,38 +993,64 @@ 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. switch {
case c == 'h':
f.usage() f.usage()
err = ErrHelp err = ErrHelp
return return
case f.ParseErrorsWhitelist.UnknownFlags:
// '-f=arg arg ...'
// we do not want to lose arg in this case
if len(shorthands) > 2 && shorthands[1] == '=' {
outShorts = ""
return
} }
//TODO continue on error
outArgs = stripUnknownFlagValue(outArgs)
return
default:
err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands) err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands)
return return
} }
}
var value string var value string
if len(shorthands) > 2 && shorthands[1] == '=' { if len(shorthands) > 2 && shorthands[1] == '=' {
// '-f=arg'
value = shorthands[2:] value = shorthands[2:]
outShorts = "" outShorts = ""
} else if len(flag.NoOptDefVal) > 0 { } else if flag.NoOptDefVal != "" {
// '-f' (arg was optional)
value = flag.NoOptDefVal value = flag.NoOptDefVal
} else if len(shorthands) > 1 { } else if len(shorthands) > 1 {
// '-farg'
value = shorthands[1:] value = shorthands[1:]
outShorts = "" outShorts = ""
} else if len(args) > 0 { } else if len(args) > 0 {
// '-f arg'
value = args[0] value = args[0]
outArgs = args[1:] outArgs = args[1:]
} else { } else {
// '-f' (arg was required)
err = f.failf("flag needs an argument: %q in -%s", c, shorthands) err = f.failf("flag needs an argument: %q in -%s", c, shorthands)
return return
} }
err = fn(flag, value, shorthands)
if flag.ShorthandDeprecated != "" {
fmt.Fprintf(f.out(), "Flag shorthand -%s has been deprecated, %s\n", flag.Shorthand, flag.ShorthandDeprecated)
}
err = fn(flag, value)
if err != nil {
f.failf(err.Error())
}
return return
} }
@ -907,6 +1058,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 {
@ -953,19 +1105,30 @@ func (f *FlagSet) parseArgs(args []string, fn parseFunc) (err error) {
// are defined and before flags are accessed by the program. // are defined and before flags are accessed by the program.
// 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 {
if f.addedGoFlagSets != nil {
for _, goFlagSet := range f.addedGoFlagSets {
goFlagSet.Parse(nil)
}
}
f.parsed = true f.parsed = true
f.args = make([]string, 0, len(arguments))
assign := func(flag *Flag, value, origArg string) error { if len(arguments) < 0 {
return f.setFlag(flag, value, origArg) return nil
} }
err := f.parseArgs(arguments, assign) f.args = make([]string, 0, len(arguments))
set := func(flag *Flag, value string) error {
return f.Set(flag.Name, value)
}
err := f.parseArgs(arguments, set)
if err != nil { if err != nil {
switch f.errorHandling { switch f.errorHandling {
case ContinueOnError: case ContinueOnError:
return err return err
case ExitOnError: case ExitOnError:
fmt.Println(err)
os.Exit(2) os.Exit(2)
case PanicOnError: case PanicOnError:
panic(err) panic(err)
@ -974,7 +1137,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 +1148,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 +1195,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
} }

View file

@ -98,4 +98,8 @@ func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet) {
newSet.VisitAll(func(goflag *goflag.Flag) { newSet.VisitAll(func(goflag *goflag.Flag) {
f.AddGoFlag(goflag) f.AddGoFlag(goflag)
}) })
if f.addedGoFlagSets == nil {
f.addedGoFlagSets = make([]*goflag.FlagSet, 0)
}
f.addedGoFlagSets = append(f.addedGoFlagSets, newSet)
} }

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

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

View file

@ -52,7 +52,7 @@ func (f *FlagSet) GetStringArray(name string) ([]string, error) {
// StringArrayVar defines a string flag with specified name, default value, and usage string. // StringArrayVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a []string variable in which to store the values of the multiple flags. // The argument p points to a []string variable in which to store the values of the multiple flags.
// The value of each argument will not try to be separated by comma // The value of each argument will not try to be separated by comma. Use a StringSlice for that.
func (f *FlagSet) StringArrayVar(p *[]string, name string, value []string, usage string) { func (f *FlagSet) StringArrayVar(p *[]string, name string, value []string, usage string) {
f.VarP(newStringArrayValue(value, p), name, "", usage) f.VarP(newStringArrayValue(value, p), name, "", usage)
} }
@ -64,7 +64,7 @@ func (f *FlagSet) StringArrayVarP(p *[]string, name, shorthand string, value []s
// StringArrayVar defines a string flag with specified name, default value, and usage string. // StringArrayVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a []string variable in which to store the value of the flag. // The argument p points to a []string variable in which to store the value of the flag.
// The value of each argument will not try to be separated by comma // The value of each argument will not try to be separated by comma. Use a StringSlice for that.
func StringArrayVar(p *[]string, name string, value []string, usage string) { func StringArrayVar(p *[]string, name string, value []string, usage string) {
CommandLine.VarP(newStringArrayValue(value, p), name, "", usage) CommandLine.VarP(newStringArrayValue(value, p), name, "", usage)
} }
@ -76,7 +76,7 @@ func StringArrayVarP(p *[]string, name, shorthand string, value []string, usage
// StringArray defines a string flag with specified name, default value, and usage string. // StringArray defines a string flag with specified name, default value, and usage string.
// The return value is the address of a []string variable that stores the value of the flag. // The return value is the address of a []string variable that stores the value of the flag.
// The value of each argument will not try to be separated by comma // The value of each argument will not try to be separated by comma. Use a StringSlice for that.
func (f *FlagSet) StringArray(name string, value []string, usage string) *[]string { func (f *FlagSet) StringArray(name string, value []string, usage string) *[]string {
p := []string{} p := []string{}
f.StringArrayVarP(&p, name, "", value, usage) f.StringArrayVarP(&p, name, "", value, usage)
@ -92,7 +92,7 @@ func (f *FlagSet) StringArrayP(name, shorthand string, value []string, usage str
// StringArray defines a string flag with specified name, default value, and usage string. // StringArray defines a string flag with specified name, default value, and usage string.
// The return value is the address of a []string variable that stores the value of the flag. // The return value is the address of a []string variable that stores the value of the flag.
// The value of each argument will not try to be separated by comma // The value of each argument will not try to be separated by comma. Use a StringSlice for that.
func StringArray(name string, value []string, usage string) *[]string { func StringArray(name string, value []string, usage string) *[]string {
return CommandLine.StringArrayP(name, "", value, usage) return CommandLine.StringArrayP(name, "", value, usage)
} }

View file

@ -82,6 +82,11 @@ func (f *FlagSet) GetStringSlice(name string) ([]string, error) {
// StringSliceVar defines a string flag with specified name, default value, and usage string. // StringSliceVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a []string variable in which to store the value of the flag. // The argument p points to a []string variable in which to store the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example:
// --ss="v1,v2" -ss="v3"
// will result in
// []string{"v1", "v2", "v3"}
func (f *FlagSet) StringSliceVar(p *[]string, name string, value []string, usage string) { func (f *FlagSet) StringSliceVar(p *[]string, name string, value []string, usage string) {
f.VarP(newStringSliceValue(value, p), name, "", usage) f.VarP(newStringSliceValue(value, p), name, "", usage)
} }
@ -93,6 +98,11 @@ func (f *FlagSet) StringSliceVarP(p *[]string, name, shorthand string, value []s
// StringSliceVar defines a string flag with specified name, default value, and usage string. // StringSliceVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a []string variable in which to store the value of the flag. // The argument p points to a []string variable in which to store the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example:
// --ss="v1,v2" -ss="v3"
// will result in
// []string{"v1", "v2", "v3"}
func StringSliceVar(p *[]string, name string, value []string, usage string) { func StringSliceVar(p *[]string, name string, value []string, usage string) {
CommandLine.VarP(newStringSliceValue(value, p), name, "", usage) CommandLine.VarP(newStringSliceValue(value, p), name, "", usage)
} }
@ -104,6 +114,11 @@ func StringSliceVarP(p *[]string, name, shorthand string, value []string, usage
// StringSlice defines a string flag with specified name, default value, and usage string. // StringSlice defines a string flag with specified name, default value, and usage string.
// The return value is the address of a []string variable that stores the value of the flag. // The return value is the address of a []string variable that stores the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example:
// --ss="v1,v2" -ss="v3"
// will result in
// []string{"v1", "v2", "v3"}
func (f *FlagSet) StringSlice(name string, value []string, usage string) *[]string { func (f *FlagSet) StringSlice(name string, value []string, usage string) *[]string {
p := []string{} p := []string{}
f.StringSliceVarP(&p, name, "", value, usage) f.StringSliceVarP(&p, name, "", value, usage)
@ -119,6 +134,11 @@ func (f *FlagSet) StringSliceP(name, shorthand string, value []string, usage str
// StringSlice defines a string flag with specified name, default value, and usage string. // StringSlice defines a string flag with specified name, default value, and usage string.
// The return value is the address of a []string variable that stores the value of the flag. // The return value is the address of a []string variable that stores the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example:
// --ss="v1,v2" -ss="v3"
// will result in
// []string{"v1", "v2", "v3"}
func StringSlice(name string, value []string, usage string) *[]string { func StringSlice(name string, value []string, usage string) *[]string {
return CommandLine.StringSliceP(name, "", value, usage) return CommandLine.StringSliceP(name, "", value, usage)
} }