diff --git a/vendor/github.com/spf13/cobra/README.md b/vendor/github.com/spf13/cobra/README.md index 5b97e021c25..b338a0e4424 100644 --- a/vendor/github.com/spf13/cobra/README.md +++ b/vendor/github.com/spf13/cobra/README.md @@ -1,122 +1,385 @@ -# Cobra +![cobra logo](https://cloud.githubusercontent.com/assets/173412/10886352/ad566232-814f-11e5-9cd0-aa101788c117.png) + +Cobra is both a library for creating powerful modern CLI applications as well as a program to generate applications and command files. + +Many of the most widely used Go projects are built using Cobra including: + +* [Kubernetes](http://kubernetes.io/) +* [Hugo](http://gohugo.io) +* [rkt](https://github.com/coreos/rkt) +* [etcd](https://github.com/coreos/etcd) +* [Docker (distribution)](https://github.com/docker/distribution) +* [OpenShift](https://www.openshift.com/) +* [Delve](https://github.com/derekparker/delve) +* [GopherJS](http://www.gopherjs.org/) +* [CockroachDB](http://www.cockroachlabs.com/) +* [Bleve](http://www.blevesearch.com/) +* [ProjectAtomic (enterprise)](http://www.projectatomic.io/) +* [Parse (CLI)](https://parse.com/) +* [GiantSwarm's swarm](https://github.com/giantswarm/cli) +* [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack) + + +[![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) +[![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) + +# Overview + +Cobra is a library providing a simple interface to create powerful modern CLI +interfaces similar to git & go tools. + +Cobra is also an application that will generate your application scaffolding to rapidly +develop a Cobra-based application. + +Cobra provides: +* Easy subcommand-based CLIs: `app server`, `app fetch`, etc. +* Fully POSIX-compliant flags (including short & long versions) +* Nested subcommands +* Global, local and cascading flags +* Easy generation of applications & commands with `cobra create appname` & `cobra add cmdname` +* Intelligent suggestions (`app srver`... did you mean `app server`?) +* Automatic help generation for commands and flags +* Automatic detailed help for `app help [command]` +* Automatic help flag recognition of `-h`, `--help`, etc. +* Automatically generated bash autocomplete for your application +* Automatically generated man pages for your application +* Command aliases so you can change things without breaking them +* The flexibilty to define your own help, usage, etc. +* Optional tight integration with [viper](http://github.com/spf13/viper) for 12-factor apps -A Commander for modern go CLI interactions +Cobra has an exceptionally clean interface and simple design without needless +constructors or initialization methods. -[![Build Status](https://travis-ci.org/spf13/cobra.svg)](https://travis-ci.org/spf13/cobra) +Applications built with Cobra commands are designed to be as user-friendly as +possible. Flags can be placed before or after the command (as long as a +confusing space isn’t provided). Both short and long flags can be used. A +command need not even be fully typed. Help is automatically generated and +available for the application or for a specific command using either the help +command or the `--help` flag. -## Overview +# Concepts -Cobra is a commander providing a simple interface to create powerful modern CLI -interfaces similar to git & go tools. In addition to providing an interface, Cobra -simultaneously provides a controller to organize your application code. +Cobra is built on a structure of commands, arguments & flags. -Inspired by go, go-Commander, gh and subcommand, Cobra improves on these by -providing **fully posix compliant flags** (including short & long versions), -**nesting commands**, and the ability to **define your own help and usage** for any or -all commands. +**Commands** represent actions, **Args** are things and **Flags** are modifiers for those actions. -Cobra has an exceptionally clean interface and simple design without needless -constructors or initialization methods. +The best applications will read like sentences when used. Users will know how +to use the application because they will natively understand how to use it. -Applications built with Cobra commands are designed to be as user friendly as -possible. Flags can be placed before or after the command (as long as a -confusing space isn’t provided). Both short and long flags can be used. A -command need not even be fully typed. The shortest unambiguous string will -suffice. Help is automatically generated and available for the application or -for a specific command using either the help command or the --help flag. +The pattern to follow is +`APPNAME VERB NOUN --ADJECTIVE.` + or +`APPNAME COMMAND ARG --FLAG` -## Concepts +A few good real world examples may better illustrate this point. -Cobra is built on a structure of commands & flags. +In the following example, 'server' is a command, and 'port' is a flag: -**Commands** represent actions and **Flags** are modifiers for those actions. + > hugo server --port=1313 -In the following example 'server' is a command and 'port' is a flag. +In this command we are telling Git to clone the url bare. - hugo server --port=1313 + > git clone URL --bare -### Commands +## Commands Command is the central point of the application. Each interaction that the application supports will be contained in a Command. A command can 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: - 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 ' output. - Run func(cmd *Command, args []string) // Run runs the 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 ' output. + Run func(cmd *Command, args []string) // Run runs the command. +} +``` -### Flags +## Flags -A Flag is a way to modify the behavior of an command. Cobra supports -fully posix compliant flags as well as the go flag package. +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/). A Cobra command can define flags that persist through to children commands 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 library](https://github.com/ogier/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 it's corresponding flags, then the +Once each command is defined with its corresponding flags, then the tree is assigned to the commander which is finally executed. -### Installing -Using Cobra is easy. First use go get to install the latest version -of the library. +# Installing +Using Cobra is easy. First, use `go get` to install the latest version +of the library. This command will install the `cobra` generator executible +along with the library: + + > go get -v github.com/spf13/cobra/cobra + +Next, include Cobra in your application: + +```go +import "github.com/spf13/cobra" +``` + +# Getting Started + +While you are welcome to provide your own organization, typically a Cobra based +application will follow the following organizational structure. + +``` + ▾ appName/ + ▾ cmd/ + add.go + your.go + commands.go + here.go + main.go +``` + +In a Cobra app, typically the main.go file is very bare. It serves, one purpose, to initialize Cobra. + +```go +package main + +import "{pathToYourApp}/cmd" + +func main() { + if err := cmd.RootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(-1) + } +} +``` + +## Using the Cobra Generator + +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. + +In order to use the cobra command, compile it using the following command: + + > go install github.com/spf13/cobra/cobra + +This will create the cobra executable under your go path bin directory! + +### cobra init + +The `cobra init [yourApp]` command will create your initial application code +for you. It is a very powerful application that will populate your program with +the right structure so you can immediately enjoy all the benefits of Cobra. It +will also automatically apply the license you specify to your application. + +Cobra init is pretty smart. You can provide it a full path, or simply a path +similar to what is expected in the import. + +``` +cobra init github.com/spf13/newAppName +``` + +### cobra add + +Once an application is initialized Cobra can create additional commands for you. +Let's say you created an app and you wanted the following commands for it: + +* app serve +* app config +* app config create + +In your project directory (where your main.go file is) you would run the following: + +``` +cobra add serve +cobra add config +cobra add create -p 'configCmd' +``` + +Once you have run these three commands you would have an app structure that would look like: + +``` + ▾ app/ + ▾ cmd/ + serve.go + config.go + create.go + main.go +``` + +at this point you can run `go run main.go` and it would run your app. `go run +main.go serve`, `go run main.go config`, `go run main.go config create` along +with `go run main.go help serve`, etc would all work. + +Obviously you haven't added your own code to these yet, the commands are ready +for you to give them their tasks. Have fun. - $ go get github.com/spf13/cobra +### Configuring the cobra generator -Next include cobra in your application. +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. - import "github.com/spf13/cobra" +An example ~/.cobra.yaml file: + +```yaml +author: Steve Francia +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. ### Create the root command The root command represents your binary itself. + +#### Manually create rootCmd + Cobra doesn't require any special constructors. Simply create your commands. - var HugoCmd = &cobra.Command{ - Use: "hugo", - Short: "Hugo is a very fast static site generator", - Long: `A Fast and Flexible Static Site Generator built with +Ideally you place this in app/cmd/root.go: + +```go +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`, - Run: func(cmd *cobra.Command, args []string) { - // Do Stuff Here - }, - } + Run: func(cmd *cobra.Command, args []string) { + // Do Stuff Here + }, +} +``` + +You will additionally define flags and handle configuration in your init() function. + +for example cmd/root.go: + +```go +func init() { + cobra.OnInitialize(initConfig) + 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().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().Bool("viper", true, "Use Viper for configuration") + viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author")) + viper.BindPFlag("projectbase", RootCmd.PersistentFlags().Lookup("projectbase")) + viper.BindPFlag("useViper", RootCmd.PersistentFlags().Lookup("viper")) + viper.SetDefault("author", "NAME HERE ") + viper.SetDefault("license", "apache") +} +``` + +### Create your main.go + +With the root command you need to have your main function execute it. +Execute should be run on the root for clarity, though it can be called on any command. + +In a Cobra app, typically the main.go file is very bare. It serves, one purpose, to initialize Cobra. + +```go +package main + +import "{pathToYourApp}/cmd" + +func main() { + if err := cmd.RootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(-1) + } +} +``` + ### Create additional commands -Additional commands can be defined. +Additional commands can be defined and typically are each given their own file +inside of the cmd/ directory. + +If you wanted to create a version command you would create cmd/version.go and +populate it with the following: - var versionCmd = &cobra.Command{ - Use: "version", - Short: "Print the version number of Hugo", - Long: `All software has versions. This is Hugo's`, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Hugo Static Site Generator v0.9 -- HEAD") - }, - } +```go +package cmd + +import ( + "github.com/spf13/cobra" +) + +func init() { + RootCmd.AddCommand(versionCmd) +} + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Print the version number of Hugo", + Long: `All software has versions. This is Hugo's`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Hugo Static Site Generator v0.9 -- HEAD") + }, +} +``` ### Attach command to its parent -In this example we are attaching it to the root, but commands can be attached at any level. - HugoCmd.AddCommand(versionCmd) + +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 + +Flags provide modifiers to control how the action command operates. ### Assign flags to a command @@ -124,43 +387,35 @@ Since the flags are defined and used in different locations, we need to define a variable outside with the correct scope to assign the flag to work with. - var Verbose bool - var Source string +```go +var Verbose bool +var Source string +``` There are two different approaches to assign a flag. -#### Persistent Flags +### Persistent Flags A flag can be 'persistent' meaning that this flag will be available to the 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. - HugoCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") +```go +RootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") +``` -#### Local Flags +### Local Flags A flag can also be assigned locally which will only apply to that specific command. - HugoCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") - -### 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 by our own version. - - mainlib.RootCmd.RemoveCommand(mainlib.VersionCmd) - mainlib.RootCmd.AddCommand(versionCmd) - -### Once all commands and flags are defined, Execute the commands - -Execute should be run on the root for clarity, though it can be called on any command. +```go +RootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") +``` - HugoCmd.Execute() ## Example -In the example below we have defined three commands. Two are at the top level +In the example below, we have defined three commands. Two are at the top level and one (cmdTimes) is a child of one of the top commands. In this case the root is not executable meaning that a subcommand is required. This is accomplished by not providing a 'Run' for the 'rootCmd'. @@ -169,196 +424,254 @@ We have only defined one flag for a single command. More documentation about flags is available at https://github.com/spf13/pflag - import( - "github.com/spf13/cobra" - "fmt" - "strings" - ) +```go +package main + +import ( + "fmt" + "strings" + + "github.com/spf13/cobra" +) - func main() { +func main() { - var echoTimes int + var echoTimes int - var cmdPrint = &cobra.Command{ - Use: "print [string to print]", - Short: "Print anything to the screen", - Long: `print is for printing anything back to the screen. + var cmdPrint = &cobra.Command{ + Use: "print [string to print]", + Short: "Print anything to the screen", + Long: `print is for printing anything back to the screen. For many years people have printed back to the screen. `, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Print: " + strings.Join(args, " ")) - }, - } - - var cmdEcho = &cobra.Command{ - Use: "echo [string to echo]", - Short: "Echo anything to the screen", - Long: `echo is for echoing anything back. + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Print: " + strings.Join(args, " ")) + }, + } + + var cmdEcho = &cobra.Command{ + Use: "echo [string to echo]", + Short: "Echo anything to the screen", + Long: `echo is for echoing anything back. Echo works a lot like print, except it has a child command. `, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Print: " + strings.Join(args, " ")) - }, - } - - var cmdTimes = &cobra.Command{ - Use: "times [# times] [string to echo]", - Short: "Echo anything to the screen more times", - Long: `echo things multiple times back to the user by providing + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Print: " + strings.Join(args, " ")) + }, + } + + var cmdTimes = &cobra.Command{ + Use: "times [# times] [string to echo]", + Short: "Echo anything to the screen more times", + Long: `echo things multiple times back to the user by providing a count and a string.`, - Run: func(cmd *cobra.Command, args []string) { - for i:=0; i < echoTimes; i++ { - fmt.Println("Echo: " + strings.Join(args, " ")) - } - }, - } + Run: func(cmd *cobra.Command, args []string) { + for i := 0; i < echoTimes; i++ { + fmt.Println("Echo: " + strings.Join(args, " ")) + } + }, + } - cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input") + cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input") - var rootCmd = &cobra.Command{Use: "app"} - rootCmd.AddCommand(cmdPrint, cmdEcho) - cmdEcho.AddCommand(cmdTimes) - rootCmd.Execute() - } + var rootCmd = &cobra.Command{Use: "app"} + rootCmd.AddCommand(cmdPrint, cmdEcho) + cmdEcho.AddCommand(cmdTimes) + rootCmd.Execute() +} +``` -For a more complete example of a larger application, please checkout [Hugo](http://hugo.spf13.com) +For a more complete example of a larger application, please checkout [Hugo](http://gohugo.io/). ## The Help Command 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 -support all other commands as input. Say for instance you have a command called -'create' without any additional configuration cobra will work when 'app help +This will be called when a user runs 'app help'. Additionally, help will also +support all other commands as input. Say, for instance, you have a command called +'create' without any additional configuration; Cobra will work when 'app help create' is called. Every command will automatically have the '--help' flag added. ### Example -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. > hugo help - A Fast and Flexible Static Site Generator built with - love by spf13 and friends in Go. + hugo is the main command, used to build your Hugo site. - Complete documentation is available at http://hugo.spf13.com + Hugo is a Fast and Flexible Static Site Generator + built with love by spf13 and friends in Go. + + Complete documentation is available at http://gohugo.io/. Usage: hugo [flags] hugo [command] Available Commands: - server :: Hugo runs it's own a webserver to render the files - version :: Print the version number of Hugo - check :: Check content in the source directory - benchmark :: Benchmark hugo by building a site a number of times - help [command] :: Help about any command - - Available Flags: - -b, --base-url="": hostname (and path) to the root eg. http://spf13.com/ - -D, --build-drafts=false: include content marked as draft + server Hugo runs its own webserver to render the files + version Print the version number of Hugo + config Print the site configuration + 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: + -b, --baseURL="": hostname (and path) to the root, e.g. http://spf13.com/ + -D, --buildDrafts[=false]: include content marked as draft + -F, --buildFuture[=false]: include content with publishdate in the future + --cacheDir="": filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/ + --canonifyURLs[=false]: if true, all relative URLs will be canonicalized using baseURL --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 - --uglyurls=false: if true, use /filename.html instead of /filename/ - -v, --verbose=false: verbose output - -w, --watch=false: watch filesystem for changes and recreate as needed - - Use "hugo help [command]" for more information about that command. + --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. Help is just a command like any other. There is no special logic or behavior -around it. In fact you can provide your own if you want. +around it. In fact, you can provide your own if you want. ### Defining your own help -You can provide your own Help command or you 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. -The default help command is +The default help command is - func (c *Command) initHelp() { - if c.helpCommand == nil { - c.helpCommand = &Command{ - Use: "help [command]", - Short: "Help about any command", - Long: `Help provides help for any command in the application. +```go +func (c *Command) initHelp() { + if c.helpCommand == nil { + c.helpCommand = &Command{ + 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) - } + Run: c.HelpFunc(), + } + } + c.AddCommand(c.helpCommand) +} +``` -You can provide your own command, function or template through the following methods. +You can provide your own command, function or template through the following methods: - command.SetHelpCommand(cmd *Command) +```go +command.SetHelpCommand(cmd *Command) - command.SetHelpFunc(f func(*Command, []string)) +command.SetHelpFunc(f func(*Command, []string)) - command.SetHelpTemplate(s string) +command.SetHelpTemplate(s string) +``` The latter two will also apply to any children commands. ## Usage -When the user provides an invalid flag or invalid command Cobra responds by -showing the user the 'usage' +When the user provides an invalid flag or invalid command, Cobra responds by +showing the user the 'usage'. ### Example You may recognize this from the help above. That's because the default help -embeds the usage as part of it's output. +embeds the usage as part of its output. Usage: hugo [flags] hugo [command] Available Commands: - server Hugo runs it's own a webserver to render the files + server Hugo runs its own webserver to render the files version Print the version number of Hugo + config Print the site configuration check Check content in the source directory - benchmark Benchmark hugo by building a site a number of times - help [command] Help about any command - - Available Flags: - -b, --base-url="": hostname (and path) to the root eg. http://spf13.com/ - -D, --build-drafts=false: include content marked as draft + 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: + -b, --baseURL="": hostname (and path) to the root, e.g. http://spf13.com/ + -D, --buildDrafts[=false]: include content marked as draft + -F, --buildFuture[=false]: include content with publishdate in the future + --cacheDir="": filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/ + --canonifyURLs[=false]: if true, all relative URLs will be canonicalized using baseURL --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 - --uglyurls=false: if true, use /filename.html instead of /filename/ - -v, --verbose=false: verbose output - -w, --watch=false: watch filesystem for changes and recreate as needed + --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 -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 +The default usage function is: - return func(c *Command) error { - err := tmpl(c.Out(), c.UsageTemplate(), c) - return err - } +```go +return func(c *Command) error { + err := tmpl(c.Out(), c.UsageTemplate(), c) + return err +} +``` -Like help the function and template are over ridable through public methods. +Like help, the function and template are overridable through public methods: - command.SetUsageFunc(f func(*Command) error) +```go +command.SetUsageFunc(f func(*Command) error) - command.SetUsageTemplate(s string) +command.SetUsageTemplate(s string) +``` ## PreRun or 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`. `PersistendPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherrited by children if they do not declare their own. These function are run in the following order: +It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherrited by children if they do not declare their own. These function are run in the following order: - `PersistentPreRun` - `PreRun` - `Run` - `PostRun` -- `PersistenPostRun` +- `PersistentPostRun` -And example of two commands which use all of these features is below. When the subcommand in executed it will run the root command's `PersistentPreRun` but not the root command's `PersistentPostRun` +An example of two commands which use all of these features is below. When the subcommand is executed, it will run the root command's `PersistentPreRun` but not the root command's `PersistentPostRun`: ```go package main @@ -393,7 +706,7 @@ func main() { var subCmd = &cobra.Command{ Use: "sub [no options!]", - Short: "My sub command", + Short: "My subcommand", PreRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside subCmd PreRun with args: %v\n", args) }, @@ -418,26 +731,115 @@ func main() { } ``` -## Generating markdown formatted 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](md_docs.md) +## Alternative Error Handling + +Cobra also has functions where the return signature is an error. This allows for errors to bubble up to the top, +providing a way to handle the errors in one location. The current list of functions that return an error is: + +* 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 + +Cobra will print automatic suggestions when "unknown command" errors happen. This allows Cobra to behave similarly to the `git` command when a typo happens. For example: + +``` +$ hugo srever +Error: unknown command "srever" for "hugo" + +Did you mean this? + server + +Run 'hugo --help' for usage. +``` + +Suggestions are automatic based on every subcommand registered and use an implementation of [Levenshtein distance](http://en.wikipedia.org/wiki/Levenshtein_distance). Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion. + +If you need to disable suggestions or tweak the string distance in your command, use: + +```go +command.DisableSuggestions = true +``` + +or + +```go +command.SuggestionsMinimumDistance = 1 +``` + +You can also explicitly set names for which a given command will be suggested using the `SuggestFor` attribute. This allows suggestions for strings that are not close in terms of string distance, but makes sense in your set of commands and for some which you don't want aliases. Example: + +``` +$ kubectl remove +Error: unknown command "remove" for "kubectl" + +Did you mean this? + delete + +Run 'kubectl help' for usage. +``` + +## Generating Markdown-formatted 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). ## Generating man pages for your command -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](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 for your command -Cobra can generate a bash completions file. If you add more information to your command these completions can be amazingly powerful and flexible. Read more about [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 -Cobra provides a ‘DebugFlags’ method on a command which when called will print -out everything Cobra knows about the flags for each command +Cobra provides a ‘DebugFlags’ method on a command which, when called, will print +out everything Cobra knows about the flags for each command. ### Example - command.DebugFlags() +```go +command.DebugFlags() +``` ## Release Notes * **0.9.0** June 17, 2014 @@ -463,6 +865,12 @@ out everything Cobra knows about the flags for each command * **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 @@ -478,7 +886,9 @@ out everything Cobra knows about the flags for each command Names in no particular order: -* [spf13](https://github.com/spf13) +* [spf13](https://github.com/spf13), +[eparis](https://github.com/eparis), +[bep](https://github.com/bep), and many more! ## License @@ -486,4 +896,3 @@ Cobra is released under the Apache 2.0 license. See [LICENSE.txt](https://github [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/spf13/cobra/trend.png)](https://bitdeli.com/free "Bitdeli Badge") - diff --git a/vendor/github.com/spf13/cobra/bash_completions.go b/vendor/github.com/spf13/cobra/bash_completions.go index 25c69ec2fe3..5b3e855be12 100644 --- a/vendor/github.com/spf13/cobra/bash_completions.go +++ b/vendor/github.com/spf13/cobra/bash_completions.go @@ -1,8 +1,8 @@ package cobra import ( - "bytes" "fmt" + "io" "os" "sort" "strings" @@ -12,13 +12,17 @@ import ( const ( BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extentions" + BashCompCustom = "cobra_annotation_bash_completion_custom" BashCompOneRequiredFlag = "cobra_annotation_bash_completion_one_required_flag" BashCompSubdirsInDir = "cobra_annotation_bash_completion_subdirs_in_dir" ) -func preamble(out *bytes.Buffer) { - fmt.Fprintf(out, `#!/bin/bash - +func preamble(out io.Writer, name string) error { + _, err := fmt.Fprintf(out, "# bash completion for %-36s -*- shell-script -*-\n", name) + if err != nil { + return err + } + _, err = fmt.Fprint(out, ` __debug() { if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then @@ -31,7 +35,7 @@ __debug() __my_init_completion() { COMPREPLY=() - _get_comp_words_by_ref cur prev words cword + _get_comp_words_by_ref "$@" cur prev words cword } __index_of_word() @@ -57,10 +61,12 @@ __contains_word() __handle_reply() { - __debug "${FUNCNAME}" + __debug "${FUNCNAME[0]}" case $cur in -*) - compopt -o nospace + if [[ $(type -t compopt) = "builtin" ]]; then + compopt -o nospace + fi local allflags if [ ${#must_have_one_flag[@]} -ne 0 ]; then allflags=("${must_have_one_flag[@]}") @@ -68,7 +74,30 @@ __handle_reply() allflags=("${flags[*]} ${two_word_flags[*]}") fi COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") ) - [[ $COMPREPLY == *= ]] || compopt +o nospace + if [[ $(type -t compopt) = "builtin" ]]; then + [[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace + fi + + # complete after --flag=abc + if [[ $cur == *=* ]]; then + if [[ $(type -t compopt) = "builtin" ]]; then + compopt +o nospace + fi + + local index flag + flag="${cur%%=*}" + __index_of_word "${flag}" "${flags_with_completion[@]}" + if [[ ${index} -ge 0 ]]; then + COMPREPLY=() + PREFIX="" + cur="${cur#*=}" + ${flags_completion[${index}]} + if [ -n "${ZSH_VERSION}" ]; then + # zfs completion needs --flag= prefix + eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )" + fi + fi + fi return 0; ;; esac @@ -87,18 +116,24 @@ __handle_reply() fi local completions - if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then - completions=("${must_have_one_flag[@]}") - elif [[ ${#must_have_one_noun[@]} -ne 0 ]]; then + completions=("${commands[@]}") + if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then completions=("${must_have_one_noun[@]}") - else - completions=("${commands[@]}") + fi + if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then + completions+=("${must_have_one_flag[@]}") fi COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") ) + if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then + COMPREPLY=( $(compgen -W "${noun_aliases[*]}" -- "$cur") ) + fi + if [[ ${#COMPREPLY[@]} -eq 0 ]]; then declare -F __custom_func >/dev/null && __custom_func fi + + __ltrim_colon_completions "$cur" } # The arguments should be in the form "ext1|ext2|extn" @@ -116,20 +151,36 @@ __handle_subdirs_in_dir_flag() __handle_flag() { - __debug "${FUNCNAME}: c is $c words[c] is ${words[c]}" + __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() local flagname=${words[c]} + local flagvalue # if the word contained an = if [[ ${words[c]} == *"="* ]]; then + flagvalue=${flagname#*=} # take in as flagvalue after the = flagname=${flagname%%=*} # strip everything after the = flagname="${flagname}=" # but put the = back fi - __debug "${FUNCNAME}: looking for ${flagname}" + __debug "${FUNCNAME[0]}: looking for ${flagname}" if __contains_word "${flagname}" "${must_have_one_flag[@]}"; then must_have_one_flag=() fi + # if you set a flag which only applies to this command, don't show subcommands + if __contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then + commands=() + fi + + # keep flag value with flagname as flaghash + if [ -n "${flagvalue}" ] ; then + flaghash[${flagname}]=${flagvalue} + elif [ -n "${words[ $((c+1)) ]}" ] ; then + flaghash[${flagname}]=${words[ $((c+1)) ]} + else + flaghash[${flagname}]="true" # pad "true" for bool flag + fi + # skip the argument to a two word flag if __contains_word "${words[c]}" "${two_word_flags[@]}"; then c=$((c+1)) @@ -139,17 +190,18 @@ __handle_flag() fi fi - # skip the flag itself c=$((c+1)) } __handle_noun() { - __debug "${FUNCNAME}: c is $c words[c] is ${words[c]}" + __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" if __contains_word "${words[c]}" "${must_have_one_noun[@]}"; then must_have_one_noun=() + elif __contains_word "${words[c]}" "${noun_aliases[@]}"; then + must_have_one_noun=() fi nouns+=("${words[c]}") @@ -158,16 +210,20 @@ __handle_noun() __handle_command() { - __debug "${FUNCNAME}: c is $c words[c] is ${words[c]}" + __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" local next_command if [[ -n ${last_command} ]]; then - next_command="_${last_command}_${words[c]}" + next_command="_${last_command}_${words[c]//:/__}" else - next_command="_${words[c]}" + if [[ $c -eq 0 ]]; then + next_command="_$(basename "${words[c]//:/__}")" + else + next_command="_${words[c]//:/__}" + fi fi c=$((c+1)) - __debug "${FUNCNAME}: looking for ${next_command}" + __debug "${FUNCNAME[0]}: looking for ${next_command}" declare -F $next_command >/dev/null && $next_command } @@ -175,13 +231,15 @@ __handle_word() { if [[ $c -ge $cword ]]; then __handle_reply - return + return fi - __debug "${FUNCNAME}: c is $c words[c] is ${words[c]}" + __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" if [[ "${words[c]}" == -* ]]; then - __handle_flag + __handle_flag elif __contains_word "${words[c]}" "${commands[@]}"; then __handle_command + elif [[ $c -eq 0 ]] && __contains_word "$(basename "${words[c]}")" "${commands[@]}"; then + __handle_command else __handle_noun fi @@ -189,21 +247,28 @@ __handle_word() } `) + return err } -func postscript(out *bytes.Buffer, name string) { - fmt.Fprintf(out, "__start_%s()\n", name) - fmt.Fprintf(out, `{ +func postscript(w io.Writer, name string) error { + name = strings.Replace(name, ":", "__", -1) + _, err := fmt.Fprintf(w, "__start_%s()\n", name) + if err != nil { + return err + } + _, err = fmt.Fprintf(w, `{ local cur prev words cword - if declare -F _init_completions >/dev/null 2>&1; then + declare -A flaghash 2>/dev/null || : + if declare -F _init_completion >/dev/null 2>&1; then _init_completion -s || return else - __my_init_completion || return + __my_init_completion -n "=" || return fi local c=0 local flags=() local two_word_flags=() + local local_nonpersistent_flags=() local flags_with_completion=() local flags_completion=() local commands=("%s") @@ -216,93 +281,202 @@ func postscript(out *bytes.Buffer, name string) { } `, name) - fmt.Fprintf(out, "complete -F __start_%s %s\n", name, name) - fmt.Fprintf(out, "# ex: ts=4 sw=4 et filetype=sh\n") + if err != nil { + return err + } + _, err = fmt.Fprintf(w, `if [[ $(type -t compopt) = "builtin" ]]; then + complete -o default -F __start_%s %s +else + complete -o default -o nospace -F __start_%s %s +fi + +`, name, name, name, name) + if err != nil { + return err + } + _, err = fmt.Fprintf(w, "# ex: ts=4 sw=4 et filetype=sh\n") + return err } -func writeCommands(cmd *Command, out *bytes.Buffer) { - fmt.Fprintf(out, " commands=()\n") +func writeCommands(cmd *Command, w io.Writer) error { + if _, err := fmt.Fprintf(w, " commands=()\n"); err != nil { + return err + } for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c == cmd.helpCommand { continue } - fmt.Fprintf(out, " commands+=(%q)\n", c.Name()) + if _, err := fmt.Fprintf(w, " commands+=(%q)\n", c.Name()); err != nil { + return err + } } - fmt.Fprintf(out, "\n") + _, err := fmt.Fprintf(w, "\n") + return err } -func writeFlagHandler(name string, annotations map[string][]string, out *bytes.Buffer) { +func writeFlagHandler(name string, annotations map[string][]string, w io.Writer) error { for key, value := range annotations { switch key { case BashCompFilenameExt: - fmt.Fprintf(out, " flags_with_completion+=(%q)\n", name) + _, err := fmt.Fprintf(w, " flags_with_completion+=(%q)\n", name) + if err != nil { + return err + } if len(value) > 0 { ext := "__handle_filename_extension_flag " + strings.Join(value, "|") - fmt.Fprintf(out, " flags_completion+=(%q)\n", ext) + _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext) } else { ext := "_filedir" - fmt.Fprintf(out, " flags_completion+=(%q)\n", ext) + _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext) + } + if err != nil { + return err + } + case BashCompCustom: + _, err := fmt.Fprintf(w, " flags_with_completion+=(%q)\n", name) + if err != nil { + return err + } + if len(value) > 0 { + handlers := strings.Join(value, "; ") + _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", handlers) + } else { + _, err = fmt.Fprintf(w, " flags_completion+=(:)\n") + } + if err != nil { + return err } case BashCompSubdirsInDir: - fmt.Fprintf(out, " flags_with_completion+=(%q)\n", name) + _, err := fmt.Fprintf(w, " flags_with_completion+=(%q)\n", name) if len(value) == 1 { ext := "__handle_subdirs_in_dir_flag " + value[0] - fmt.Fprintf(out, " flags_completion+=(%q)\n", ext) + _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext) } else { ext := "_filedir -d" - fmt.Fprintf(out, " flags_completion+=(%q)\n", ext) + _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext) + } + if err != nil { + return err } } } + return nil } -func writeShortFlag(flag *pflag.Flag, out *bytes.Buffer) { - b := (flag.Value.Type() == "bool") +func writeShortFlag(flag *pflag.Flag, w io.Writer) error { + b := (len(flag.NoOptDefVal) > 0) name := flag.Shorthand format := " " if !b { format += "two_word_" } format += "flags+=(\"-%s\")\n" - fmt.Fprintf(out, format, name) - writeFlagHandler("-"+name, flag.Annotations, out) + if _, err := fmt.Fprintf(w, format, name); err != nil { + return err + } + return writeFlagHandler("-"+name, flag.Annotations, w) } -func writeFlag(flag *pflag.Flag, out *bytes.Buffer) { - b := (flag.Value.Type() == "bool") +func writeFlag(flag *pflag.Flag, w io.Writer) error { + b := (len(flag.NoOptDefVal) > 0) name := flag.Name format := " flags+=(\"--%s" if !b { format += "=" } format += "\")\n" - fmt.Fprintf(out, format, name) - writeFlagHandler("--"+name, flag.Annotations, out) + if _, err := fmt.Fprintf(w, format, name); err != nil { + return err + } + return writeFlagHandler("--"+name, flag.Annotations, w) } -func writeFlags(cmd *Command, out *bytes.Buffer) { - fmt.Fprintf(out, ` flags=() +func writeLocalNonPersistentFlag(flag *pflag.Flag, w io.Writer) error { + b := (len(flag.NoOptDefVal) > 0) + name := flag.Name + format := " local_nonpersistent_flags+=(\"--%s" + if !b { + format += "=" + } + format += "\")\n" + if _, err := fmt.Fprintf(w, format, name); err != nil { + return err + } + return nil +} + +func writeFlags(cmd *Command, w io.Writer) error { + _, err := fmt.Fprintf(w, ` flags=() two_word_flags=() + local_nonpersistent_flags=() flags_with_completion=() flags_completion=() `) + if err != nil { + return err + } + localNonPersistentFlags := cmd.LocalNonPersistentFlags() + var visitErr error cmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) { - writeFlag(flag, out) + if nonCompletableFlag(flag) { + return + } + if err := writeFlag(flag, w); err != nil { + visitErr = err + return + } if len(flag.Shorthand) > 0 { - writeShortFlag(flag, out) + if err := writeShortFlag(flag, w); err != nil { + visitErr = err + return + } + } + if localNonPersistentFlags.Lookup(flag.Name) != nil { + if err := writeLocalNonPersistentFlag(flag, w); err != nil { + visitErr = err + return + } + } + }) + if visitErr != nil { + return visitErr + } + cmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) { + if nonCompletableFlag(flag) { + return + } + if err := writeFlag(flag, w); err != nil { + visitErr = err + return + } + if len(flag.Shorthand) > 0 { + if err := writeShortFlag(flag, w); err != nil { + visitErr = err + return + } } }) + if visitErr != nil { + return visitErr + } - fmt.Fprintf(out, "\n") + _, err = fmt.Fprintf(w, "\n") + return err } -func writeRequiredFlag(cmd *Command, out *bytes.Buffer) { - fmt.Fprintf(out, " must_have_one_flag=()\n") +func writeRequiredFlag(cmd *Command, w io.Writer) error { + if _, err := fmt.Fprintf(w, " must_have_one_flag=()\n"); err != nil { + return err + } flags := cmd.NonInheritedFlags() + var visitErr error flags.VisitAll(func(flag *pflag.Flag) { + if nonCompletableFlag(flag) { + return + } for key := range flag.Annotations { switch key { case BashCompOneRequiredFlag: @@ -312,67 +486,115 @@ func writeRequiredFlag(cmd *Command, out *bytes.Buffer) { format += "=" } format += "\")\n" - fmt.Fprintf(out, format, flag.Name) + if _, err := fmt.Fprintf(w, format, flag.Name); err != nil { + visitErr = err + return + } if len(flag.Shorthand) > 0 { - fmt.Fprintf(out, " must_have_one_flag+=(\"-%s\")\n", flag.Shorthand) + if _, err := fmt.Fprintf(w, " must_have_one_flag+=(\"-%s\")\n", flag.Shorthand); err != nil { + visitErr = err + return + } } } } }) + return visitErr } -func writeRequiredNoun(cmd *Command, out *bytes.Buffer) { - fmt.Fprintf(out, " must_have_one_noun=()\n") +func writeRequiredNouns(cmd *Command, w io.Writer) error { + if _, err := fmt.Fprintf(w, " must_have_one_noun=()\n"); err != nil { + return err + } sort.Sort(sort.StringSlice(cmd.ValidArgs)) for _, value := range cmd.ValidArgs { - fmt.Fprintf(out, " must_have_one_noun+=(%q)\n", value) + if _, err := fmt.Fprintf(w, " must_have_one_noun+=(%q)\n", value); err != nil { + return err + } } + return nil +} + +func writeArgAliases(cmd *Command, w io.Writer) error { + if _, err := fmt.Fprintf(w, " noun_aliases=()\n"); err != nil { + return err + } + sort.Sort(sort.StringSlice(cmd.ArgAliases)) + for _, value := range cmd.ArgAliases { + if _, err := fmt.Fprintf(w, " noun_aliases+=(%q)\n", value); err != nil { + return err + } + } + return nil } -func gen(cmd *Command, out *bytes.Buffer) { +func gen(cmd *Command, w io.Writer) error { for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c == cmd.helpCommand { continue } - gen(c, out) + if err := gen(c, w); err != nil { + return err + } } commandName := cmd.CommandPath() commandName = strings.Replace(commandName, " ", "_", -1) - fmt.Fprintf(out, "_%s()\n{\n", commandName) - fmt.Fprintf(out, " last_command=%q\n", commandName) - writeCommands(cmd, out) - writeFlags(cmd, out) - writeRequiredFlag(cmd, out) - writeRequiredNoun(cmd, out) - fmt.Fprintf(out, "}\n\n") + commandName = strings.Replace(commandName, ":", "__", -1) + if _, err := fmt.Fprintf(w, "_%s()\n{\n", commandName); err != nil { + return err + } + if _, err := fmt.Fprintf(w, " last_command=%q\n", commandName); err != nil { + return err + } + if err := writeCommands(cmd, w); err != nil { + return err + } + if err := writeFlags(cmd, w); err != nil { + return err + } + if err := writeRequiredFlag(cmd, w); err != nil { + return err + } + if err := writeRequiredNouns(cmd, w); err != nil { + return err + } + if err := writeArgAliases(cmd, w); err != nil { + return err + } + if _, err := fmt.Fprintf(w, "}\n\n"); err != nil { + return err + } + return nil } -func (cmd *Command) GenBashCompletion(out *bytes.Buffer) { - preamble(out) +func (cmd *Command) GenBashCompletion(w io.Writer) error { + if err := preamble(w, cmd.Name()); err != nil { + return err + } if len(cmd.BashCompletionFunction) > 0 { - fmt.Fprintf(out, "%s\n", cmd.BashCompletionFunction) + if _, err := fmt.Fprintf(w, "%s\n", cmd.BashCompletionFunction); err != nil { + return err + } + } + if err := gen(cmd, w); err != nil { + return err } - gen(cmd, out) - postscript(out, cmd.Name()) + return postscript(w, cmd.Name()) } -func (cmd *Command) GenBashCompletionFile(filename string) error { - out := new(bytes.Buffer) - - cmd.GenBashCompletion(out) +func nonCompletableFlag(flag *pflag.Flag) bool { + return flag.Hidden || len(flag.Deprecated) > 0 +} +func (cmd *Command) GenBashCompletionFile(filename string) error { outFile, err := os.Create(filename) if err != nil { return err } defer outFile.Close() - _, err = outFile.Write(out.Bytes()) - if err != nil { - return err - } - return nil + return cmd.GenBashCompletion(outFile) } // MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag, if it exists. @@ -380,6 +602,11 @@ func (cmd *Command) MarkFlagRequired(name string) error { return MarkFlagRequired(cmd.Flags(), name) } +// MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag, if it exists. +func (cmd *Command) MarkPersistentFlagRequired(name string) error { + return MarkFlagRequired(cmd.PersistentFlags(), name) +} + // MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag in the flag set, if it exists. func MarkFlagRequired(flags *pflag.FlagSet, name string) error { return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"}) @@ -391,8 +618,26 @@ func (cmd *Command) MarkFlagFilename(name string, extensions ...string) error { return MarkFlagFilename(cmd.Flags(), name, extensions...) } +// MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists. +// Generated bash autocompletion will call the bash function f for the flag. +func (cmd *Command) MarkFlagCustom(name string, f string) error { + return MarkFlagCustom(cmd.Flags(), name, f) +} + +// 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. +func (cmd *Command) MarkPersistentFlagFilename(name string, extensions ...string) error { + return MarkFlagFilename(cmd.PersistentFlags(), name, extensions...) +} + // MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag in the flag set, if it exists. // Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error { return flags.SetAnnotation(name, BashCompFilenameExt, extensions) } + +// MarkFlagCustom adds the BashCompCustom annotation to the named flag in the flag set, if it exists. +// Generated bash autocompletion will call the bash function f for the flag. +func MarkFlagCustom(flags *pflag.FlagSet, name string, f string) error { + return flags.SetAnnotation(name, BashCompCustom, []string{f}) +} diff --git a/vendor/github.com/spf13/cobra/bash_completions.md b/vendor/github.com/spf13/cobra/bash_completions.md index 204704efc14..6e3b71f13d5 100644 --- a/vendor/github.com/spf13/cobra/bash_completions.md +++ b/vendor/github.com/spf13/cobra/bash_completions.md @@ -80,7 +80,7 @@ The `BashCompletionFunction` option is really only valid/useful on the root comm In the above example "pod" was assumed to already be typed. But if you want `kubectl get [tab][tab]` to show a list of valid "nouns" you have to set them. Simplified code from `kubectl get` looks like: ```go -validArgs []string = { "pods", "nodes", "services", "replicationControllers" } +validArgs []string = { "pod", "node", "service", "replicationcontroller" } cmd := &cobra.Command{ Use: "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)", @@ -99,9 +99,34 @@ Notice we put the "ValidArgs" on the "get" subcommand. Doing so will give result ```bash # kubectl get [tab][tab] -nodes pods replicationControllers services +node pod replicationcontroller service ``` +## Plural form and shortcuts for nouns + +If your nouns have a number of aliases, you can define them alongside `ValidArgs` using `ArgAliases`: + +```go` +argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" } + +cmd := &cobra.Command{ + ... + ValidArgs: validArgs, + ArgAliases: argAliases +} +``` + +The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by +the completion algorithm if entered manually, e.g. in: + +```bash +# kubectl get rc [tab][tab] +backend frontend database +``` + +Note that without declaring `rc` as an alias, the completion algorithm would show the list of nouns +in this example again instead of the replication controllers. + ## Mark flags as required Most of the time completions will only show subcommands. But if a flag is required to make a subcommand work, you probably want it to show up when the user types [tab][tab]. Marking a flag as 'Required' is incredibly easy. @@ -147,3 +172,35 @@ hello.yml test.json ``` So while there are many other files in the CWD it only shows me subdirs and those with valid extensions. + +# Specifiy custom flag completion + +Similar to the filename completion and filtering using cobra.BashCompFilenameExt, you can specifiy +a custom flag completion function with cobra.BashCompCustom: + +```go + annotation := make(map[string][]string) + annotation[cobra.BashCompFilenameExt] = []string{"__kubectl_get_namespaces"} + + flag := &pflag.Flag{ + Name: "namespace", + Usage: usage, + Annotations: annotation, + } + cmd.Flags().AddFlag(flag) +``` + +In addition add the `__handle_namespace_flag` implementation in the `BashCompletionFunction` +value, e.g.: + +```bash +__kubectl_get_namespaces() +{ + local template + template="{{ range .items }}{{ .metadata.name }} {{ end }}" + local kubectl_out + if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then + COMPREPLY=( $( compgen -W "${kubectl_out}[*]" -- "$cur" ) ) + fi +} +``` diff --git a/vendor/github.com/spf13/cobra/cobra.go b/vendor/github.com/spf13/cobra/cobra.go index 1d66a70eb56..93a2c0f3a77 100644 --- a/vendor/github.com/spf13/cobra/cobra.go +++ b/vendor/github.com/spf13/cobra/cobra.go @@ -23,28 +23,27 @@ import ( "strconv" "strings" "text/template" + "unicode" ) -var templateFuncs template.FuncMap = template.FuncMap{ - "trim": strings.TrimSpace, - "rpad": rpad, - "gt": Gt, - "eq": Eq, +var templateFuncs = template.FuncMap{ + "trim": strings.TrimSpace, + "trimRightSpace": trimRightSpace, + "appendIfNotPresent": appendIfNotPresent, + "rpad": rpad, + "gt": Gt, + "eq": Eq, } var initializers []func() // automatic prefix matching can be a dangerous thing to automatically enable in CLI tools. // Set this to true to enable it -var EnablePrefixMatching bool = false +var EnablePrefixMatching = false -// enables an information splash screen on Windows if the CLI is started from explorer.exe. -var EnableWindowsMouseTrap bool = true - -var MousetrapHelpText string = `This is a command line tool - -You need to open cmd.exe and run it from there. -` +//EnableCommandSorting controls sorting of the slice of commands, which is turned on by default. +//To disable sorting, set it to false. +var EnableCommandSorting = true //AddTemplateFunc adds a template function that's available to Usage and Help //template generation. @@ -113,6 +112,18 @@ func Eq(a interface{}, b interface{}) bool { return false } +func trimRightSpace(s string) string { + 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 +func appendIfNotPresent(s, stringToAppend string) string { + if strings.Contains(s, stringToAppend) { + return s + } + return s + " " + stringToAppend +} + //rpad adds padding to the right of a string func rpad(s string, padding int) string { template := fmt.Sprintf("%%-%ds", padding) @@ -126,3 +137,39 @@ func tmpl(w io.Writer, text string, data interface{}) error { template.Must(t.Parse(text)) return t.Execute(w, data) } + +// ld compares two strings and returns the levenshtein distance between them +func ld(s, t string, ignoreCase bool) int { + if ignoreCase { + s = strings.ToLower(s) + t = strings.ToLower(t) + } + d := make([][]int, len(s)+1) + for i := range d { + d[i] = make([]int, len(t)+1) + } + for i := range d { + d[i][0] = i + } + for j := range d[0] { + d[0][j] = j + } + for j := 1; j <= len(t); j++ { + for i := 1; i <= len(s); i++ { + if s[i-1] == t[j-1] { + d[i][j] = d[i-1][j-1] + } else { + min := d[i-1][j] + if d[i][j-1] < min { + min = d[i][j-1] + } + if d[i-1][j-1] < min { + min = d[i-1][j-1] + } + d[i][j] = min + 1 + } + } + + } + return d[len(s)][len(t)] +} diff --git a/vendor/github.com/spf13/cobra/command.go b/vendor/github.com/spf13/cobra/command.go index df5a4554d83..083e4ea7f47 100644 --- a/vendor/github.com/spf13/cobra/command.go +++ b/vendor/github.com/spf13/cobra/command.go @@ -20,11 +20,10 @@ import ( "fmt" "io" "os" - "runtime" + "path/filepath" + "sort" "strings" - "time" - "github.com/inconshreveable/mousetrap" flag "github.com/spf13/pflag" ) @@ -39,14 +38,19 @@ type Command struct { Use string // An array of aliases that can be used instead of the first word in Use. Aliases []string + // An array of command names for which this command will be suggested - similar to aliases but only suggests. + SuggestFor []string // The short description shown in the 'help' output. Short string // The long message shown in the 'help ' output. Long string // Examples of how to use the command Example string - // List of all valid non-flag arguments, used for bash completions *TODO* actually validate these + // List of all valid non-flag arguments that are accepted in bash completions ValidArgs []string + // List of aliases for ValidArgs. These are not suggested to the user in the bash + // completion, but accepted if entered manually. + ArgAliases []string // Custom functions used by the bash autocompletion generator BashCompletionFunction string // Is this command deprecated and should print this string when used? @@ -59,6 +63,10 @@ type Command struct { pflags *flag.FlagSet // Flags that are declared specifically by this command (not inherited). lflags *flag.FlagSet + // SilenceErrors is an option to quiet errors down stream + SilenceErrors bool + // Silence Usage is an option to silence usage when an error occurs. + SilenceUsage bool // The *Run functions are executed in the following order: // * PersistentPreRun() // * PreRun() @@ -86,6 +94,8 @@ type Command struct { PersistentPostRun func(cmd *Command, args []string) // PersistentPostRunE: PersistentPostRun but returns an error PersistentPostRunE func(cmd *Command, args []string) error + // DisableAutoGenTag remove + DisableAutoGenTag bool // Commands is the list of commands supported by this program. commands []*Command // Parent Command for this command @@ -94,11 +104,13 @@ type Command struct { commandsMaxUseLen int commandsMaxCommandPathLen int commandsMaxNameLen int + // is commands slice are sorted or not + commandsAreSorted bool flagErrorBuf *bytes.Buffer args []string // actual args parsed from flags - output *io.Writer // nil means stderr; use Out() method instead + output *io.Writer // out writer if set in SetOutput(w) usageFunc func(*Command) error // Usage can be defined by application usageTemplate string // Can be defined by Application helpTemplate string // Can be defined by Application @@ -106,6 +118,14 @@ type Command struct { helpCommand *Command // The help command // The global normalization function that we can use on every pFlag set and children commands globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName + + // Disable the suggestions based on Levenshtein distance that go along with 'unknown command' messages + DisableSuggestions bool + // If displaying suggestions, allows to set the minimum levenshtein distance to display, must be > 0 + SuggestionsMinimumDistance int + + // Disable the flag parsing. If this is true all flags will be passed to the command as arguments. + DisableFlagParsing bool } // os.Args[1:] by default, if desired, can be overridden @@ -114,26 +134,6 @@ func (c *Command) SetArgs(a []string) { c.args = a } -func (c *Command) getOut(def io.Writer) io.Writer { - if c.output != nil { - return *c.output - } - - if c.HasParent() { - return c.parent.Out() - } else { - return def - } -} - -func (c *Command) Out() io.Writer { - return c.getOut(os.Stderr) -} - -func (c *Command) getOutOrStdout() io.Writer { - return c.getOut(os.Stdout) -} - // SetOutput sets the destination for usage and error messages. // If output is nil, os.Stderr is used. func (c *Command) SetOutput(output io.Writer) { @@ -176,6 +176,26 @@ func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string } } +func (c *Command) OutOrStdout() io.Writer { + return c.getOut(os.Stdout) +} + +func (c *Command) OutOrStderr() io.Writer { + return c.getOut(os.Stderr) +} + +func (c *Command) getOut(def io.Writer) io.Writer { + if c.output != nil { + return *c.output + } + if c.HasParent() { + return c.parent.getOut(def) + } + return def +} + +// UsageFunc returns either the function set by SetUsageFunc for this command +// or a parent, or it returns a default usage function func (c *Command) UsageFunc() (f func(*Command) error) { if c.usageFunc != nil { return c.usageFunc @@ -183,16 +203,26 @@ func (c *Command) UsageFunc() (f func(*Command) error) { if c.HasParent() { return c.parent.UsageFunc() - } else { - return func(c *Command) error { - err := tmpl(c.Out(), c.UsageTemplate(), c) - return err + } + return func(c *Command) error { + c.mergePersistentFlags() + err := tmpl(c.OutOrStderr(), c.UsageTemplate(), c) + if err != nil { + c.Println(err) } + return err } } +// Output the usage for the command +// Used when a user provides invalid input +// Can be defined by user by overriding UsageFunc +func (c *Command) Usage() error { + return c.UsageFunc()(c) +} + // HelpFunc returns either the function set by SetHelpFunc for this command -// or a parent, or it returns a function which calls c.Help() +// or a parent, or it returns a function with default help behavior func (c *Command) HelpFunc() func(*Command, []string) { cmd := c for cmd != nil { @@ -202,42 +232,57 @@ func (c *Command) HelpFunc() func(*Command, []string) { cmd = cmd.parent } return func(*Command, []string) { - err := c.Help() + c.mergePersistentFlags() + err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c) if err != nil { c.Println(err) } } } -var minUsagePadding int = 25 +// Output the help for the command +// Used when a user calls help [command] +// Can be defined by user by overriding HelpFunc +func (c *Command) Help() error { + c.HelpFunc()(c, []string{}) + return nil +} + +func (c *Command) UsageString() string { + tmpOutput := c.output + bb := new(bytes.Buffer) + c.SetOutput(bb) + c.Usage() + c.output = tmpOutput + return bb.String() +} + +var minUsagePadding = 25 func (c *Command) UsagePadding() int { if c.parent == nil || minUsagePadding > c.parent.commandsMaxUseLen { return minUsagePadding - } else { - return c.parent.commandsMaxUseLen } + return c.parent.commandsMaxUseLen } -var minCommandPathPadding int = 11 +var minCommandPathPadding = 11 // func (c *Command) CommandPathPadding() int { if c.parent == nil || minCommandPathPadding > c.parent.commandsMaxCommandPathLen { return minCommandPathPadding - } else { - return c.parent.commandsMaxCommandPathLen } + return c.parent.commandsMaxCommandPathLen } -var minNamePadding int = 11 +var minNamePadding = 11 func (c *Command) NamePadding() int { if c.parent == nil || minNamePadding > c.parent.commandsMaxNameLen { return minNamePadding - } else { - return c.parent.commandsMaxNameLen } + return c.parent.commandsMaxNameLen } func (c *Command) UsageTemplate() string { @@ -247,10 +292,9 @@ func (c *Command) UsageTemplate() string { if c.HasParent() { return c.parent.UsageTemplate() - } else { - return `{{ $cmd := . }} -Usage: {{if .Runnable}} - {{.UseLine}}{{if .HasFlags}} [flags]{{end}}{{end}}{{if .HasSubCommands}} + } + return `Usage:{{if .Runnable}} + {{if .HasAvailableFlags}}{{appendIfNotPresent .UseLine "[flags]"}}{{else}}{{.UseLine}}{{end}}{{end}}{{if .HasAvailableSubCommands}} {{ .CommandPath}} [command]{{end}}{{if gt .Aliases 0}} Aliases: @@ -260,21 +304,20 @@ Aliases: Examples: {{ .Example }}{{end}}{{ if .HasAvailableSubCommands}} -Available Commands: {{range .Commands}}{{if .IsAvailableCommand}} - {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasLocalFlags}} +Available Commands:{{range .Commands}}{{if .IsAvailableCommand}} + {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableLocalFlags}} Flags: -{{.LocalFlags.FlagUsages}}{{end}}{{ if .HasInheritedFlags}} +{{.LocalFlags.FlagUsages | trimRightSpace}}{{end}}{{ if .HasAvailableInheritedFlags}} Global Flags: -{{.InheritedFlags.FlagUsages}}{{end}}{{if .HasHelpSubCommands}} +{{.InheritedFlags.FlagUsages | trimRightSpace}}{{end}}{{if .HasHelpSubCommands}} -Additional help topics: {{range .Commands}}{{if .IsHelpCommand}} - {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasSubCommands }} +Additional help topics:{{range .Commands}}{{if .IsHelpCommand}} + {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableSubCommands }} -Use "{{.CommandPath}} [command] --help" for more information about a command. -{{end}}` - } +Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} +` } func (c *Command) HelpTemplate() string { @@ -284,11 +327,10 @@ func (c *Command) HelpTemplate() string { if c.HasParent() { return c.parent.HelpTemplate() - } else { - return `{{with or .Long .Short }}{{. | trim}}{{end}} -{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}} -` } + return `{{with or .Long .Short }}{{. | trim}} + +{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` } // Really only used when casting a command to a commander @@ -419,28 +461,83 @@ func (c *Command) Find(args []string) (*Command, []string, error) { if !commandFound.HasSubCommands() { return commandFound, a, nil } + // root command with subcommands, do subcommand checking if commandFound == c && len(argsWOflags) > 0 { - return commandFound, a, fmt.Errorf("unknown command %q for %q", argsWOflags[0], commandFound.CommandPath()) + suggestionsString := "" + if !c.DisableSuggestions { + if c.SuggestionsMinimumDistance <= 0 { + c.SuggestionsMinimumDistance = 2 + } + if suggestions := c.SuggestionsFor(argsWOflags[0]); len(suggestions) > 0 { + suggestionsString += "\n\nDid you mean this?\n" + for _, s := range suggestions { + suggestionsString += fmt.Sprintf("\t%v\n", s) + } + } + } + return commandFound, a, fmt.Errorf("unknown command %q for %q%s", argsWOflags[0], commandFound.CommandPath(), suggestionsString) } return commandFound, a, nil } +func (c *Command) SuggestionsFor(typedName string) []string { + suggestions := []string{} + for _, cmd := range c.commands { + if cmd.IsAvailableCommand() { + levenshteinDistance := ld(typedName, cmd.Name(), true) + suggestByLevenshtein := levenshteinDistance <= c.SuggestionsMinimumDistance + suggestByPrefix := strings.HasPrefix(strings.ToLower(cmd.Name()), strings.ToLower(typedName)) + if suggestByLevenshtein || suggestByPrefix { + suggestions = append(suggestions, cmd.Name()) + } + for _, explicitSuggestion := range cmd.SuggestFor { + if strings.EqualFold(typedName, explicitSuggestion) { + suggestions = append(suggestions, cmd.Name()) + } + } + } + } + return suggestions +} + +func (c *Command) VisitParents(fn func(*Command)) { + var traverse func(*Command) *Command + + traverse = func(x *Command) *Command { + if x != c { + fn(x) + } + if x.HasParent() { + return traverse(x.parent) + } + return x + } + traverse(c) +} + func (c *Command) Root() *Command { var findRoot func(*Command) *Command findRoot = func(x *Command) *Command { if x.HasParent() { return findRoot(x.parent) - } else { - return x } + return x } return findRoot(c) } +// ArgsLenAtDash will return the length of f.Args at the moment when a -- was +// found during arg parsing. This allows your program to know which args were +// before the -- and which came after. (Description from +// https://godoc.org/github.com/spf13/pflag#FlagSet.ArgsLenAtDash). +func (c *Command) ArgsLenAtDash() int { + return c.Flags().ArgsLenAtDash() +} + func (c *Command) execute(a []string) (err error) { if c == nil { return fmt.Errorf("Called Execute() on a nil Command") @@ -467,16 +564,21 @@ func (c *Command) execute(a []string) (err error) { c.Println("\"help\" flag declared as non-bool. Please correct your code") return err } + if helpVal || !c.Runnable() { return flag.ErrHelp } c.preRun() + argWoFlags := c.Flags().Args() + if c.DisableFlagParsing { + argWoFlags = a + } for p := c; p != nil; p = p.Parent() { if p.PersistentPreRunE != nil { - if err := p.PersistentPostRunE(c, argWoFlags); err != nil { + if err := p.PersistentPreRunE(c, argWoFlags); err != nil { return err } break @@ -535,27 +637,28 @@ func (c *Command) errorMsgFromParse() string { if len(x) > 0 { return x[0] - } else { - return "" } + return "" } // Call execute to use the args (os.Args[1:] by default) // and run through the command tree finding appropriate matches // for commands and then corresponding flags. -func (c *Command) Execute() (err error) { +func (c *Command) Execute() error { + _, err := c.ExecuteC() + return err +} + +func (c *Command) ExecuteC() (cmd *Command, err error) { // Regardless of what command execute is called on, run on Root only if c.HasParent() { - return c.Root().Execute() + return c.Root().ExecuteC() } - if EnableWindowsMouseTrap && runtime.GOOS == "windows" { - if mousetrap.StartedByExplorer() { - c.Print(MousetrapHelpText) - time.Sleep(5 * time.Second) - os.Exit(1) - } + // windows hook + if preExecHookFn != nil { + preExecHookFn(c) } // initialize help as the last point possible to allow for user @@ -564,7 +667,8 @@ func (c *Command) Execute() (err error) { var args []string - if len(c.args) == 0 { + // Workaround FAIL with "go test -v" or "cobra.test -test.v", see #155 + if c.args == nil && filepath.Base(os.Args[0]) != "cobra.test" { args = os.Args[1:] } else { args = c.args @@ -576,22 +680,35 @@ func (c *Command) Execute() (err error) { if cmd != nil { c = cmd } - c.Println("Error:", err.Error()) - c.Printf("Run '%v --help' for usage.\n", c.CommandPath()) - return err + if !c.SilenceErrors { + c.Println("Error:", err.Error()) + c.Printf("Run '%v --help' for usage.\n", c.CommandPath()) + } + return c, err } - err = cmd.execute(flags) if err != nil { + // Always show help if requested, even if SilenceErrors is in + // effect if err == flag.ErrHelp { cmd.HelpFunc()(cmd, args) - return nil + return cmd, nil } - c.Println(cmd.UsageString()) - c.Println("Error:", err.Error()) - } - return + // If root command has SilentErrors flagged, + // all subcommands should respect it + if !cmd.SilenceErrors && !c.SilenceErrors { + c.Println("Error:", err.Error()) + } + + // If root command has SilentUsage flagged, + // all subcommands should respect it + if !cmd.SilenceUsage && !c.SilenceUsage { + c.Println(cmd.UsageString()) + } + return cmd, err + } + return cmd, nil } func (c *Command) initHelpFlag() { @@ -620,8 +737,7 @@ func (c *Command) initHelpCmd() { c.Printf("Unknown help topic %#q.", args) c.Root().Usage() } else { - helpFunc := cmd.HelpFunc() - helpFunc(cmd, args) + cmd.Help() } }, } @@ -635,8 +751,20 @@ func (c *Command) ResetCommands() { c.helpCommand = nil } -//Commands returns a slice of child commands. +// Sorts commands by their names +type commandSorterByName []*Command + +func (c commandSorterByName) Len() int { return len(c) } +func (c commandSorterByName) Swap(i, j int) { c[i], c[j] = c[j], c[i] } +func (c commandSorterByName) Less(i, j int) bool { return c[i].Name() < c[j].Name() } + +// Commands returns a sorted slice of child commands. func (c *Command) Commands() []*Command { + // do not sort commands if it already sorted or sorting was disabled + if EnableCommandSorting && !c.commandsAreSorted { + sort.Sort(commandSorterByName(c.commands)) + c.commandsAreSorted = true + } return c.commands } @@ -660,15 +788,16 @@ func (c *Command) AddCommand(cmds ...*Command) { if nameLen > c.commandsMaxNameLen { c.commandsMaxNameLen = nameLen } - // If glabal normalization function exists, update all children + // If global normalization function exists, update all children if c.globNormFunc != nil { x.SetGlobalNormalizationFunc(c.globNormFunc) } c.commands = append(c.commands, x) + c.commandsAreSorted = false } } -// AddCommand removes one or more commands from a parent command. +// RemoveCommand removes one or more commands from a parent command. func (c *Command) RemoveCommand(cmds ...*Command) { commands := []*Command{} main: @@ -702,50 +831,23 @@ main: } } -// Convenience method to Print to the defined output +// Print is a convenience method to Print to the defined output, fallback to Stderr if not set func (c *Command) Print(i ...interface{}) { - fmt.Fprint(c.Out(), i...) + fmt.Fprint(c.OutOrStderr(), i...) } -// Convenience method to Println to the defined output +// Println is a convenience method to Println to the defined output, fallback to Stderr if not set func (c *Command) Println(i ...interface{}) { str := fmt.Sprintln(i...) c.Print(str) } -// Convenience method to Printf to the defined output +// Printf is a convenience method to Printf to the defined output, fallback to Stderr if not set func (c *Command) Printf(format string, i ...interface{}) { str := fmt.Sprintf(format, i...) c.Print(str) } -// Output the usage for the command -// Used when a user provides invalid input -// Can be defined by user by overriding UsageFunc -func (c *Command) Usage() error { - c.mergePersistentFlags() - err := c.UsageFunc()(c) - return err -} - -// Output the help for the command -// Used when a user calls help [command] -// by the default HelpFunc in the commander -func (c *Command) Help() error { - c.mergePersistentFlags() - err := tmpl(c.getOutOrStdout(), c.HelpTemplate(), c) - return err -} - -func (c *Command) UsageString() string { - tmpOutput := c.output - bb := new(bytes.Buffer) - c.SetOutput(bb) - c.Usage() - c.output = tmpOutput - return bb.String() -} - // CommandPath returns the full path to this command. func (c *Command) CommandPath() string { str := c.Name() @@ -824,7 +926,7 @@ func (c *Command) Name() string { return name } -// Determine if a given string is an alias of the command. +// HasAlias determines if a given string is an alias of the command. func (c *Command) HasAlias(s string) bool { for _, a := range c.Aliases { if a == s { @@ -842,12 +944,12 @@ func (c *Command) HasExample() bool { return len(c.Example) > 0 } -// Determine if the command is itself runnable +// Runnable determines if the command is itself runnable func (c *Command) Runnable() bool { return c.Run != nil || c.RunE != nil } -// Determine if the command has children commands +// HasSubCommands determines if the command has children commands func (c *Command) HasSubCommands() bool { return len(c.commands) > 0 } @@ -859,6 +961,10 @@ func (c *Command) IsAvailableCommand() bool { return false } + if c.HasParent() && c.Parent().helpCommand == c { + return false + } + if c.Runnable() || c.HasAvailableSubCommands() { return true } @@ -942,6 +1048,19 @@ func (c *Command) Flags() *flag.FlagSet { return c.flags } +// LocalNonPersistentFlags are flags specific to this command which will NOT persist to subcommands +func (c *Command) LocalNonPersistentFlags() *flag.FlagSet { + persistentFlags := c.PersistentFlags() + + out := flag.NewFlagSet(c.Name(), flag.ContinueOnError) + c.LocalFlags().VisitAll(func(f *flag.Flag) { + if persistentFlags.Lookup(f.Name) == nil { + out.AddFlag(f) + } + }) + return out +} + // Get the local FlagSet specifically set in the current command func (c *Command) LocalFlags() *flag.FlagSet { c.mergePersistentFlags() @@ -1031,11 +1150,35 @@ func (c *Command) HasLocalFlags() bool { return c.LocalFlags().HasFlags() } +// Does the command have flags inherited from its parent command func (c *Command) HasInheritedFlags() bool { return c.InheritedFlags().HasFlags() } -// Climbs up the command tree looking for matching flag +// Does the command contain any flags (local plus persistent from the entire +// structure) which are not hidden or deprecated +func (c *Command) HasAvailableFlags() bool { + return c.Flags().HasAvailableFlags() +} + +// Does the command contain persistent flags which are not hidden or deprecated +func (c *Command) HasAvailablePersistentFlags() bool { + return c.PersistentFlags().HasAvailableFlags() +} + +// Does the command has flags specifically declared locally which are not hidden +// or deprecated +func (c *Command) HasAvailableLocalFlags() bool { + return c.LocalFlags().HasAvailableFlags() +} + +// Does the command have flags inherited from its parent command which are +// not hidden or deprecated +func (c *Command) HasAvailableInheritedFlags() bool { + return c.InheritedFlags().HasAvailableFlags() +} + +// Flag climbs up the command tree looking for matching flag func (c *Command) Flag(name string) (flag *flag.Flag) { flag = c.Flags().Lookup(name) @@ -1058,13 +1201,17 @@ func (c *Command) persistentFlag(name string) (flag *flag.Flag) { return } -// Parses persistent flag tree & local flags +// ParseFlags parses persistent flag tree & local flags func (c *Command) ParseFlags(args []string) (err error) { + if c.DisableFlagParsing { + return nil + } c.mergePersistentFlags() err = c.Flags().Parse(args) return } +// Parent returns a commands parent command func (c *Command) Parent() *Command { return c.parent } diff --git a/vendor/github.com/spf13/cobra/command_notwin.go b/vendor/github.com/spf13/cobra/command_notwin.go new file mode 100644 index 00000000000..6159c1cc19d --- /dev/null +++ b/vendor/github.com/spf13/cobra/command_notwin.go @@ -0,0 +1,5 @@ +// +build !windows + +package cobra + +var preExecHookFn func(*Command) diff --git a/vendor/github.com/spf13/cobra/command_win.go b/vendor/github.com/spf13/cobra/command_win.go new file mode 100644 index 00000000000..4b0eaa1b6bc --- /dev/null +++ b/vendor/github.com/spf13/cobra/command_win.go @@ -0,0 +1,26 @@ +// +build windows + +package cobra + +import ( + "os" + "time" + + "github.com/inconshreveable/mousetrap" +) + +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) { + if mousetrap.StartedByExplorer() { + c.Print(MousetrapHelpText) + time.Sleep(5 * time.Second) + os.Exit(1) + } +} diff --git a/vendor/github.com/spf13/cobra/doc_util.go b/vendor/github.com/spf13/cobra/doc_util.go deleted file mode 100644 index e248216284b..00000000000 --- a/vendor/github.com/spf13/cobra/doc_util.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2015 Red Hat Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cobra - -// Test to see if we have a reason to print See Also information in docs -// Basically this is a test for a parent commend or a subcommand which is -// both not deprecated and not the autogenerated help command. -func (cmd *Command) hasSeeAlso() bool { - if cmd.HasParent() { - return true - } - children := cmd.Commands() - if len(children) == 0 { - return false - } - for _, c := range children { - if !c.IsAvailableCommand() || c == cmd.helpCommand { - continue - } - return true - } - return false -} diff --git a/vendor/github.com/spf13/cobra/man_docs.go b/vendor/github.com/spf13/cobra/man_docs.go deleted file mode 100644 index e61fff18280..00000000000 --- a/vendor/github.com/spf13/cobra/man_docs.go +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright 2015 Red Hat Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cobra - -import ( - "bytes" - "fmt" - "os" - "sort" - "strings" - "time" - - mangen "github.com/cpuguy83/go-md2man/md2man" - "github.com/spf13/pflag" -) - -// GenManTree will call cmd.GenManTree(header, dir) -func GenManTree(cmd *Command, header *GenManHeader, dir string) { - cmd.GenManTree(header, dir) -} - -// GenManTree will generate a man page for this command and all decendants -// in the directory given. The header may be nil. This function may not work -// correctly if your command names have - in them. If you have `cmd` with two -// subcmds, `sub` and `sub-third`. And `sub` has a subcommand called `third` -// it is undefined which help output will be in the file `cmd-sub-third.1`. -func (cmd *Command) GenManTree(header *GenManHeader, dir string) { - if header == nil { - header = &GenManHeader{} - } - for _, c := range cmd.Commands() { - if !c.IsAvailableCommand() || c == cmd.helpCommand { - continue - } - GenManTree(c, header, dir) - } - out := new(bytes.Buffer) - - cmd.GenMan(header, out) - - filename := cmd.CommandPath() - filename = dir + strings.Replace(filename, " ", "-", -1) + ".1" - outFile, err := os.Create(filename) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - defer outFile.Close() - _, err = outFile.Write(out.Bytes()) - if err != nil { - fmt.Println(err) - os.Exit(1) - } -} - -// GenManHeader is a lot like the .TH header at the start of man pages. These -// include the title, section, date, source, and manual. We will use the -// current time if Date if unset and will use "Auto generated by spf13/cobra" -// if the Source is unset. -type GenManHeader struct { - Title string - Section string - Date *time.Time - date string - Source string - Manual string -} - -// GenMan will call cmd.GenMan(header, out) -func GenMan(cmd *Command, header *GenManHeader, out *bytes.Buffer) { - cmd.GenMan(header, out) -} - -// GenMan will generate a man page for the given command in the out buffer. -// The header argument may be nil, however obviously out may not. -func (cmd *Command) GenMan(header *GenManHeader, out *bytes.Buffer) { - if header == nil { - header = &GenManHeader{} - } - buf := genMarkdown(cmd, header) - final := mangen.Render(buf) - out.Write(final) -} - -func fillHeader(header *GenManHeader, name string) { - if header.Title == "" { - header.Title = name - } - if header.Section == "" { - header.Section = "1" - } - if header.Date == nil { - now := time.Now() - header.Date = &now - } - header.date = (*header.Date).Format("Jan 2006") - if header.Source == "" { - header.Source = "Auto generated by spf13/cobra" - } -} - -func manPreamble(out *bytes.Buffer, header *GenManHeader, name, short, long string) { - fmt.Fprintf(out, `%% %s(%s)%s -%% %s -%% %s -# NAME -`, header.Title, header.Section, header.date, header.Source, header.Manual) - fmt.Fprintf(out, "%s \\- %s\n\n", name, short) - fmt.Fprintf(out, "# SYNOPSIS\n") - fmt.Fprintf(out, "**%s** [OPTIONS]\n\n", name) - fmt.Fprintf(out, "# DESCRIPTION\n") - fmt.Fprintf(out, "%s\n\n", long) -} - -func manPrintFlags(out *bytes.Buffer, flags *pflag.FlagSet) { - flags.VisitAll(func(flag *pflag.Flag) { - if len(flag.Deprecated) > 0 || flag.Hidden { - return - } - format := "" - if len(flag.Shorthand) > 0 { - format = "**-%s**, **--%s**" - } else { - format = "%s**--%s**" - } - if len(flag.NoOptDefVal) > 0 { - format = format + "[" - } - if flag.Value.Type() == "string" { - // put quotes on the value - format = format + "=%q" - } else { - format = format + "=%s" - } - if len(flag.NoOptDefVal) > 0 { - format = format + "]" - } - format = format + "\n\t%s\n\n" - fmt.Fprintf(out, format, flag.Shorthand, flag.Name, flag.DefValue, flag.Usage) - }) -} - -func manPrintOptions(out *bytes.Buffer, command *Command) { - flags := command.NonInheritedFlags() - if flags.HasFlags() { - fmt.Fprintf(out, "# OPTIONS\n") - manPrintFlags(out, flags) - fmt.Fprintf(out, "\n") - } - flags = command.InheritedFlags() - if flags.HasFlags() { - fmt.Fprintf(out, "# OPTIONS INHERITED FROM PARENT COMMANDS\n") - manPrintFlags(out, flags) - fmt.Fprintf(out, "\n") - } -} - -func genMarkdown(cmd *Command, header *GenManHeader) []byte { - fillHeader(header, cmd.Name()) - // something like `rootcmd subcmd1 subcmd2` - commandName := cmd.CommandPath() - // something like `rootcmd-subcmd1-subcmd2` - dashCommandName := strings.Replace(commandName, " ", "-", -1) - - buf := new(bytes.Buffer) - - short := cmd.Short - long := cmd.Long - if len(long) == 0 { - long = short - } - - manPreamble(buf, header, commandName, short, long) - manPrintOptions(buf, cmd) - - if len(cmd.Example) > 0 { - fmt.Fprintf(buf, "# EXAMPLE\n") - fmt.Fprintf(buf, "```\n%s\n```\n", cmd.Example) - } - - if cmd.hasSeeAlso() { - fmt.Fprintf(buf, "# SEE ALSO\n") - if cmd.HasParent() { - parentPath := cmd.Parent().CommandPath() - dashParentPath := strings.Replace(parentPath, " ", "-", -1) - fmt.Fprintf(buf, "**%s(%s)**, ", dashParentPath, header.Section) - } - - children := cmd.Commands() - sort.Sort(byName(children)) - for _, c := range children { - if !c.IsAvailableCommand() || c == cmd.helpCommand { - continue - } - fmt.Fprintf(buf, "**%s-%s(%s)**, ", dashCommandName, c.Name(), header.Section) - } - fmt.Fprintf(buf, "\n") - } - - fmt.Fprintf(buf, "# HISTORY\n%s Auto generated by spf13/cobra\n", header.Date.Format("2-Jan-2006")) - return buf.Bytes() -} diff --git a/vendor/github.com/spf13/cobra/man_docs.md b/vendor/github.com/spf13/cobra/man_docs.md deleted file mode 100644 index a764099e503..00000000000 --- a/vendor/github.com/spf13/cobra/man_docs.md +++ /dev/null @@ -1,25 +0,0 @@ -# Generating Man Pages For Your Own cobra.Command - -Generating bash completions from a cobra command is incredibly easy. An example is as follows: - -```go -package main - -import ( - "github.com/spf13/cobra" -) - -func main() { - cmd := &cobra.Command{ - Use: "test", - Short: "my test program", - } - header := &cobra.GenManHeader{ - Title: "MINE", - Section: "3", - } - cmd.GenManTree(header, "/tmp") -} -``` - -That will get you a man page `/tmp/test.1` diff --git a/vendor/github.com/spf13/cobra/md_docs.go b/vendor/github.com/spf13/cobra/md_docs.go deleted file mode 100644 index 3c27f7ae693..00000000000 --- a/vendor/github.com/spf13/cobra/md_docs.go +++ /dev/null @@ -1,157 +0,0 @@ -//Copyright 2015 Red Hat Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cobra - -import ( - "bytes" - "fmt" - "os" - "sort" - "strings" - "time" -) - -func printOptions(out *bytes.Buffer, cmd *Command, name string) { - flags := cmd.NonInheritedFlags() - flags.SetOutput(out) - if flags.HasFlags() { - fmt.Fprintf(out, "### Options\n\n```\n") - flags.PrintDefaults() - fmt.Fprintf(out, "```\n\n") - } - - parentFlags := cmd.InheritedFlags() - parentFlags.SetOutput(out) - if parentFlags.HasFlags() { - fmt.Fprintf(out, "### Options inherited from parent commands\n\n```\n") - parentFlags.PrintDefaults() - fmt.Fprintf(out, "```\n\n") - } -} - -type byName []*Command - -func (s byName) Len() int { return len(s) } -func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() } - -func GenMarkdown(cmd *Command, out *bytes.Buffer) { - cmd.GenMarkdown(out) -} - -func (cmd *Command) GenMarkdown(out *bytes.Buffer) { - cmd.GenMarkdownCustom(out, func(s string) string { return s }) -} - -func GenMarkdownCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string) string) { - cmd.GenMarkdownCustom(out, linkHandler) -} - -func (cmd *Command) GenMarkdownCustom(out *bytes.Buffer, linkHandler func(string) string) { - name := cmd.CommandPath() - - short := cmd.Short - long := cmd.Long - if len(long) == 0 { - long = short - } - - fmt.Fprintf(out, "## %s\n\n", name) - fmt.Fprintf(out, "%s\n\n", short) - fmt.Fprintf(out, "### Synopsis\n\n") - fmt.Fprintf(out, "\n%s\n\n", long) - - if cmd.Runnable() { - fmt.Fprintf(out, "```\n%s\n```\n\n", cmd.UseLine()) - } - - if len(cmd.Example) > 0 { - fmt.Fprintf(out, "### Examples\n\n") - fmt.Fprintf(out, "```\n%s\n```\n\n", cmd.Example) - } - - printOptions(out, cmd, name) - - if cmd.hasSeeAlso() { - fmt.Fprintf(out, "### SEE ALSO\n") - if cmd.HasParent() { - parent := cmd.Parent() - pname := parent.CommandPath() - link := pname + ".md" - link = strings.Replace(link, " ", "_", -1) - fmt.Fprintf(out, "* [%s](%s)\t - %s\n", pname, linkHandler(link), parent.Short) - } - - children := cmd.Commands() - sort.Sort(byName(children)) - - for _, child := range children { - if !child.IsAvailableCommand() || child == cmd.helpCommand { - continue - } - cname := name + " " + child.Name() - link := cname + ".md" - link = strings.Replace(link, " ", "_", -1) - fmt.Fprintf(out, "* [%s](%s)\t - %s\n", cname, linkHandler(link), child.Short) - } - fmt.Fprintf(out, "\n") - } - - fmt.Fprintf(out, "###### Auto generated by spf13/cobra on %s\n", time.Now().Format("2-Jan-2006")) -} - -func GenMarkdownTree(cmd *Command, dir string) { - cmd.GenMarkdownTree(dir) -} - -func (cmd *Command) GenMarkdownTree(dir string) { - identity := func(s string) string { return s } - emptyStr := func(s string) string { return "" } - cmd.GenMarkdownTreeCustom(dir, emptyStr, identity) -} - -func GenMarkdownTreeCustom(cmd *Command, dir string, filePrepender func(string) string, linkHandler func(string) string) { - cmd.GenMarkdownTreeCustom(dir, filePrepender, linkHandler) -} - -func (cmd *Command) GenMarkdownTreeCustom(dir string, filePrepender func(string) string, linkHandler func(string) string) { - for _, c := range cmd.Commands() { - if !c.IsAvailableCommand() || c == cmd.helpCommand { - continue - } - c.GenMarkdownTreeCustom(dir, filePrepender, linkHandler) - } - out := new(bytes.Buffer) - - cmd.GenMarkdownCustom(out, linkHandler) - - filename := cmd.CommandPath() - filename = dir + strings.Replace(filename, " ", "_", -1) + ".md" - outFile, err := os.Create(filename) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - defer outFile.Close() - _, err = outFile.WriteString(filePrepender(filename)) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - _, err = outFile.Write(out.Bytes()) - if err != nil { - fmt.Println(err) - os.Exit(1) - } -} diff --git a/vendor/github.com/spf13/cobra/md_docs.md b/vendor/github.com/spf13/cobra/md_docs.md deleted file mode 100644 index 3a0d55ab902..00000000000 --- a/vendor/github.com/spf13/cobra/md_docs.md +++ /dev/null @@ -1,81 +0,0 @@ -# Generating Markdown Docs For Your Own cobra.Command - -## Generate markdown docs for the entire command tree - -This program can actually generate docs for the kubectl command in the kubernetes project - -```go -package main - -import ( - "io/ioutil" - "os" - - "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd" - "github.com/spf13/cobra" -) - -func main() { - kubectl := cmd.NewFactory(nil).NewKubectlCommand(os.Stdin, ioutil.Discard, ioutil.Discard) - cobra.GenMarkdownTree(kubectl, "./") -} -``` - -This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case "./") - -## Generate markdown docs for a single command - -You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to `GenMarkdown` instead of `GenMarkdownTree` - -```go - out := new(bytes.Buffer) - cobra.GenMarkdown(cmd, out) -``` - -This will write the markdown doc for ONLY "cmd" into the out, buffer. - -## Customize the output - -Both `GenMarkdown` and `GenMarkdownTree` have alternate versions with callbacks to get some control of the output: - -```go -func GenMarkdownTreeCustom(cmd *Command, dir string, filePrepender func(string) string, linkHandler func(string) string) { - //... -} -``` - -```go -func GenMarkdownCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string) string) { - //... -} -``` - -The `filePrepender` will prepend the return value given the full filepath to the rendered Markdown file. A common use case is to add front matter to use the generated documentation with [Hugo](http://gohugo.io/): - -```go -const fmTemplate = `--- -date: %s -title: "%s" -slug: %s -url: %s ---- -` - -filePrepender := func(filename string) string { - now := time.Now().Format(time.RFC3339) - name := filepath.Base(filename) - base := strings.TrimSuffix(name, path.Ext(name)) - url := "/commands/" + strings.ToLower(base) + "/" - return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url) -} -``` - -The `linkHandler` can be used to customize the rendered internal links to the commands, given a filename: - -```go -linkHandler := func(name string) string { - base := strings.TrimSuffix(name, path.Ext(name)) - return "/commands/" + strings.ToLower(base) + "/" -} -``` - diff --git a/vendor/github.com/spf13/pflag/README.md b/vendor/github.com/spf13/pflag/README.md index e74dd50b41c..08ad9456588 100644 --- a/vendor/github.com/spf13/pflag/README.md +++ b/vendor/github.com/spf13/pflag/README.md @@ -85,7 +85,7 @@ fmt.Println("flagvar has value ", flagvar) ``` There are helpers function to get values later if you have the FlagSet but -it was difficult to keep up with all of the the flag pointers in your code. +it was difficult to keep up with all of the flag pointers in your code. If you have a pflag.FlagSet with a flag called 'flagname' of type int you can use GetInt() to get the int value. But notice that 'flagname' must exist and it must be an int. GetString("flagname") will fail. @@ -244,6 +244,25 @@ It is possible to mark a flag as hidden, meaning it will still function as norma flags.MarkHidden("secretFlag") ``` +## 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 +to support flags defined by third-party dependencies (e.g. `golang/glog`). + +**Example**: You want to add the Go flags to the `CommandLine` flagset +```go +import ( + goflag "flag" + flag "github.com/spf13/pflag" +) + +var ip *int = flag.Int("flagname", 1234, "help message for flagname") + +func main() { + flag.CommandLine.AddGoFlagSet(goflag.CommandLine) + flag.Parse() +} +``` + ## More info You can see the full reference documentation of the pflag package diff --git a/vendor/github.com/spf13/pflag/flag.go b/vendor/github.com/spf13/pflag/flag.go index 66ef0966398..965df13797a 100644 --- a/vendor/github.com/spf13/pflag/flag.go +++ b/vendor/github.com/spf13/pflag/flag.go @@ -140,6 +140,7 @@ type FlagSet struct { formal map[NormalizedName]*Flag shorthands map[byte]*Flag args []string // arguments after flags + 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 output io.Writer // nil means stderr; use out() accessor @@ -241,6 +242,17 @@ func (f *FlagSet) HasFlags() bool { return len(f.formal) > 0 } +// HasAvailableFlags returns a bool to indicate if the FlagSet has any flags +// definied that are not hidden or deprecated. +func (f *FlagSet) HasAvailableFlags() bool { + for _, flag := range f.formal { + if !flag.Hidden && len(flag.Deprecated) == 0 { + return true + } + } + return false +} + // VisitAll visits the command-line flags in lexicographical order, calling // fn for each. It visits all flags, even those not set. func VisitAll(fn func(*Flag)) { @@ -292,6 +304,13 @@ func (f *FlagSet) getFlagType(name string, ftype string, convFunc func(sval stri return result, nil } +// ArgsLenAtDash will return the length of f.Args at the moment when a -- was +// found during arg parsing. This allows your program to know which args were +// before the -- and which came after. +func (f *FlagSet) ArgsLenAtDash() int { + return f.argsLenAtDash +} + // MarkDeprecated indicated that a flag is deprecated in your program. It will // continue to function but will not show up in help or usage messages. Using // this flag will also print the given usageMessage. @@ -307,9 +326,9 @@ func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error { return nil } -// Mark the shorthand of a flag deprecated in your program. It will -// continue to function but will not show up in help or usage messages. Using -// this flag will also print the given usageMessage. +// MarkShorthandDeprecated will mark the shorthand of a flag deprecated in your +// program. It will continue to function but will not show up in help or usage +// messages. Using this flag will also print the given usageMessage. func (f *FlagSet) MarkShorthandDeprecated(name string, usageMessage string) error { flag := f.Lookup(name) if flag == nil { @@ -400,41 +419,123 @@ func (f *FlagSet) PrintDefaults() { fmt.Fprintf(f.out(), "%s", usages) } +// isZeroValue guesses whether the string represents the zero +// value for a flag. It is not accurate but in practice works OK. +func isZeroValue(value string) bool { + switch value { + case "false": + return true + case "": + return true + case "": + return true + case "0": + return true + } + return false +} + +// UnquoteUsage extracts a back-quoted name from the usage +// string for a flag and returns it and the un-quoted usage. +// Given "a `name` to show" it returns ("name", "a name to show"). +// If there are no back quotes, the name is an educated guess of the +// type of the flag's value, or the empty string if the flag is boolean. +func UnquoteUsage(flag *Flag) (name string, usage string) { + // Look for a back-quoted name, but avoid the strings package. + usage = flag.Usage + for i := 0; i < len(usage); i++ { + if usage[i] == '`' { + for j := i + 1; j < len(usage); j++ { + if usage[j] == '`' { + name = usage[i+1 : j] + usage = usage[:i] + name + usage[j+1:] + return name, usage + } + } + break // Only one back quote; use type name. + } + } + // No explicit name, so use type if we can find one. + name = "value" + switch flag.Value.(type) { + case boolFlag: + name = "" + case *durationValue: + name = "duration" + case *float64Value: + name = "float" + case *intValue, *int64Value: + name = "int" + case *stringValue: + name = "string" + case *uintValue, *uint64Value: + name = "uint" + } + return +} + // FlagUsages Returns a string containing the usage information for all flags in // the FlagSet func (f *FlagSet) FlagUsages() string { x := new(bytes.Buffer) + lines := make([]string, 0, len(f.formal)) + + maxlen := 0 f.VisitAll(func(flag *Flag) { if len(flag.Deprecated) > 0 || flag.Hidden { return } - format := "" + + line := "" if len(flag.Shorthand) > 0 && len(flag.ShorthandDeprecated) == 0 { - format = " -%s, --%s" + line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name) } else { - format = " %s --%s" - } - if len(flag.NoOptDefVal) > 0 { - format = format + "[" + line = fmt.Sprintf(" --%s", flag.Name) } - if flag.Value.Type() == "string" { - // put quotes on the value - format = format + "=%q" - } else { - format = format + "=%s" + + varname, usage := UnquoteUsage(flag) + if len(varname) > 0 { + line += " " + varname } if len(flag.NoOptDefVal) > 0 { - format = format + "]" + switch flag.Value.Type() { + case "string": + line += fmt.Sprintf("[=%q]", flag.NoOptDefVal) + case "bool": + if flag.NoOptDefVal != "true" { + line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) + } + default: + line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) + } + } + + // This special character will be replaced with spacing once the + // correct alignment is calculated + line += "\x00" + if len(line) > maxlen { + maxlen = len(line) } - format = format + ": %s\n" - shorthand := flag.Shorthand - if len(flag.ShorthandDeprecated) > 0 { - shorthand = "" + + line += usage + if !isZeroValue(flag.DefValue) { + if flag.Value.Type() == "string" { + line += fmt.Sprintf(" (default %q)", flag.DefValue) + } else { + line += fmt.Sprintf(" (default %s)", flag.DefValue) + } } - fmt.Fprintf(x, format, shorthand, flag.Name, flag.DefValue, flag.Usage) + + lines = append(lines, line) }) + for _, line := range lines { + sidx := strings.Index(line, "\x00") + spacing := strings.Repeat(" ", maxlen-sidx) + fmt.Fprintln(x, line[:sidx], spacing, line[sidx+1:]) + } + return x.String() } @@ -455,6 +556,8 @@ func defaultUsage(f *FlagSet) { // Usage prints to standard error a usage message documenting all defined command-line flags. // The function is a variable that may be changed to point to a custom function. +// By default it prints a simple header and calls PrintDefaults; for details about the +// format of the output and how to control it, see the documentation for PrintDefaults. var Usage = func() { fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) PrintDefaults() @@ -675,6 +778,9 @@ func (f *FlagSet) parseLongArg(s string, args []string) (a []string, err error) } func (f *FlagSet) parseSingleShortArg(shorthands string, args []string) (outShorts string, outArgs []string, err error) { + if strings.HasPrefix(shorthands, "test.") { + return + } outArgs = args outShorts = shorthands[1:] c := shorthands[0] @@ -740,6 +846,7 @@ func (f *FlagSet) parseArgs(args []string) (err error) { if s[1] == '-' { if len(s) == 2 { // "--" terminates the flags + f.argsLenAtDash = len(f.args) f.args = append(f.args, args...) break } @@ -797,7 +904,7 @@ func Parsed() bool { return CommandLine.Parsed() } -// 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) // NewFlagSet returns a new, empty flag set with the specified name and @@ -806,12 +913,13 @@ func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet { f := &FlagSet{ name: name, errorHandling: errorHandling, + argsLenAtDash: -1, interspersed: true, } return f } -// SetIntersperesed sets whether to support interspersed option/non-option arguments. +// SetInterspersed sets whether to support interspersed option/non-option arguments. func (f *FlagSet) SetInterspersed(interspersed bool) { f.interspersed = interspersed } @@ -822,4 +930,5 @@ func (f *FlagSet) SetInterspersed(interspersed bool) { func (f *FlagSet) Init(name string, errorHandling ErrorHandling) { f.name = name f.errorHandling = errorHandling + f.argsLenAtDash = -1 } diff --git a/vendor/github.com/spf13/pflag/golangflag.go b/vendor/github.com/spf13/pflag/golangflag.go index 5213dc30609..b056147fd87 100644 --- a/vendor/github.com/spf13/pflag/golangflag.go +++ b/vendor/github.com/spf13/pflag/golangflag.go @@ -60,6 +60,10 @@ func (v *flagValueWrapper) Type() string { return v.flagType } +// PFlagFromGoFlag will return a *pflag.Flag given a *flag.Flag +// If the *flag.Flag.Name was a single character (ex: `v`) it will be accessiblei +// with both `-v` and `--v` in flags. If the golang flag was more than a single +// character (ex: `verbose`) it will only be accessible via `--verbose` func PFlagFromGoFlag(goflag *goflag.Flag) *Flag { // Remember the default value as a string; it won't change. flag := &Flag{ @@ -70,12 +74,17 @@ func PFlagFromGoFlag(goflag *goflag.Flag) *Flag { //DefValue: goflag.DefValue, DefValue: goflag.Value.String(), } + // Ex: if the golang flag was -v, allow both -v and --v to work + if len(flag.Name) == 1 { + flag.Shorthand = flag.Name + } if fv, ok := goflag.Value.(goBoolFlag); ok && fv.IsBoolFlag() { flag.NoOptDefVal = "true" } return flag } +// AddGoFlag will add the given *flag.Flag to the pflag.FlagSet func (f *FlagSet) AddGoFlag(goflag *goflag.Flag) { if f.Lookup(goflag.Name) != nil { return @@ -84,6 +93,7 @@ func (f *FlagSet) AddGoFlag(goflag *goflag.Flag) { f.AddFlag(newflag) } +// AddGoFlagSet will add the given *flag.FlagSet to the pflag.FlagSet func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet) { if newSet == nil { return diff --git a/vendor/github.com/spf13/pflag/string_slice.go b/vendor/github.com/spf13/pflag/string_slice.go index 0b7ddfe3d6f..b53648b2e52 100644 --- a/vendor/github.com/spf13/pflag/string_slice.go +++ b/vendor/github.com/spf13/pflag/string_slice.go @@ -1,6 +1,7 @@ package pflag import ( + "encoding/csv" "fmt" "strings" ) @@ -21,7 +22,12 @@ func newStringSliceValue(val []string, p *[]string) *stringSliceValue { } func (s *stringSliceValue) Set(val string) error { - v := strings.Split(val, ",") + stringReader := strings.NewReader(val) + csvReader := csv.NewReader(stringReader) + v, err := csvReader.Read() + if err != nil { + return err + } if !s.changed { *s.value = v } else { diff --git a/vendor/vendor.json b/vendor/vendor.json index 872d87af7c3..00ec4109c53 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -29,18 +29,6 @@ "revision": "bad654b00c954e31007c5004629e236c06ca4046", "revisionTime": "2016-07-26T09:12:10Z" }, - { - "checksumSHA1": "Ufrex/PpclfqVToYNvjB1y4dg0A=", - "path": "github.com/docker/go-units", - "revision": "f2d77a61e3c169b43402a0a1e84f06daf29b8190", - "revisionTime": "2016-06-13T21:20:13Z" - }, - { - "checksumSHA1": "uhWARwDA6NE60a3/snaz9QBM7Ow=", - "path": "github.com/fsouza/go-dockerclient", - "revision": "d433254bb83b41d7072ce470e312ea3cee257882", - "revisionTime": "2016-07-25T13:44:23Z" - }, { "checksumSHA1": "/Q1GjTd4UDnPMJxI10PTazyN37k=", "path": "github.com/docker/docker/pkg/archive", @@ -125,6 +113,18 @@ "revision": "f2d77a61e3c169b43402a0a1e84f06daf29b8190", "revisionTime": "2016-06-13T21:20:13Z" }, + { + "checksumSHA1": "Ufrex/PpclfqVToYNvjB1y4dg0A=", + "path": "github.com/docker/go-units", + "revision": "f2d77a61e3c169b43402a0a1e84f06daf29b8190", + "revisionTime": "2016-06-13T21:20:13Z" + }, + { + "checksumSHA1": "uhWARwDA6NE60a3/snaz9QBM7Ow=", + "path": "github.com/fsouza/go-dockerclient", + "revision": "d433254bb83b41d7072ce470e312ea3cee257882", + "revisionTime": "2016-07-25T13:44:23Z" + }, { "checksumSHA1": "uhWARwDA6NE60a3/snaz9QBM7Ow=", "path": "github.com/fsouza/go-dockerclient", @@ -184,7 +184,6 @@ }, { "checksumSHA1": "WI+JevQX15p9zqngb1BMHvrPAgU=", - "origin": "github.com/hyperledger/fabric/vendor/github.com/howeyc/gopass", "path": "github.com/howeyc/gopass", "revision": "66487b23f2880ba32e185121d2cd51a338ea069a", "revisionTime": "2016-03-03T20:01:16Z" @@ -251,9 +250,10 @@ "revisionTime": "2015-08-01T19:34:06-07:00" }, { + "checksumSHA1": "hvkXE4HQ2zgWaCkt3CQTki5hvqc=", "path": "github.com/spf13/cobra", - "revision": "4b86c66ef25470e678a4d6a372711d7050344ccc", - "revisionTime": "2015-09-09T14:20:07-05:00" + "revision": "7c674d9e72017ed25f6d2b5e497a1368086b6a6f", + "revisionTime": "2016-08-02T22:37:37Z" }, { "path": "github.com/spf13/jwalterweatherman", @@ -261,9 +261,10 @@ "revisionTime": "2014-09-11T15:55:44-05:00" }, { + "checksumSHA1": "45OZzM/Hyc8mwjG2zn38n6bKZws=", "path": "github.com/spf13/pflag", - "revision": "f735fdff4ffb34299727eb2e3c9abab588742d41", - "revisionTime": "2015-09-08T08:49:52-05:00" + "revision": "1560c1005499d61b80f865c04d39ca7505bf7f0b", + "revisionTime": "2016-07-18T21:50:57Z" }, { "path": "github.com/spf13/viper",