diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 691bd76f46e..592545de505 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -2470,11 +2470,11 @@ }, { "ImportPath": "github.com/spf13/cobra", - "Rev": "f62e98d28ab7ad31d707ba837a966378465c7b57" + "Rev": "19e54c4a2b8a78c9d54b2bed61b1a6c5e1bfcf6f" }, { "ImportPath": "github.com/spf13/cobra/doc", - "Rev": "f62e98d28ab7ad31d707ba837a966378465c7b57" + "Rev": "19e54c4a2b8a78c9d54b2bed61b1a6c5e1bfcf6f" }, { "ImportPath": "github.com/spf13/jwalterweatherman", diff --git a/staging/src/k8s.io/apiextensions-apiserver/Godeps/Godeps.json b/staging/src/k8s.io/apiextensions-apiserver/Godeps/Godeps.json index 08607c1ddcf..f792000d584 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/Godeps/Godeps.json +++ b/staging/src/k8s.io/apiextensions-apiserver/Godeps/Godeps.json @@ -328,7 +328,7 @@ }, { "ImportPath": "github.com/spf13/cobra", - "Rev": "f62e98d28ab7ad31d707ba837a966378465c7b57" + "Rev": "19e54c4a2b8a78c9d54b2bed61b1a6c5e1bfcf6f" }, { "ImportPath": "github.com/spf13/pflag", diff --git a/staging/src/k8s.io/kube-aggregator/Godeps/Godeps.json b/staging/src/k8s.io/kube-aggregator/Godeps/Godeps.json index ec78f699e49..32d1debb00a 100644 --- a/staging/src/k8s.io/kube-aggregator/Godeps/Godeps.json +++ b/staging/src/k8s.io/kube-aggregator/Godeps/Godeps.json @@ -308,7 +308,7 @@ }, { "ImportPath": "github.com/spf13/cobra", - "Rev": "f62e98d28ab7ad31d707ba837a966378465c7b57" + "Rev": "19e54c4a2b8a78c9d54b2bed61b1a6c5e1bfcf6f" }, { "ImportPath": "github.com/spf13/pflag", diff --git a/staging/src/k8s.io/sample-apiserver/Godeps/Godeps.json b/staging/src/k8s.io/sample-apiserver/Godeps/Godeps.json index 3281bf2fb31..a8c8d2a5cad 100644 --- a/staging/src/k8s.io/sample-apiserver/Godeps/Godeps.json +++ b/staging/src/k8s.io/sample-apiserver/Godeps/Godeps.json @@ -296,7 +296,7 @@ }, { "ImportPath": "github.com/spf13/cobra", - "Rev": "f62e98d28ab7ad31d707ba837a966378465c7b57" + "Rev": "19e54c4a2b8a78c9d54b2bed61b1a6c5e1bfcf6f" }, { "ImportPath": "github.com/spf13/pflag", diff --git a/vendor/github.com/spf13/cobra/.travis.yml b/vendor/github.com/spf13/cobra/.travis.yml index 6e84be54d16..68efa136331 100644 --- a/vendor/github.com/spf13/cobra/.travis.yml +++ b/vendor/github.com/spf13/cobra/.travis.yml @@ -1,11 +1,10 @@ language: go -go: - - 1.4.3 - - 1.5.4 - - 1.6.3 - - tip matrix: + include: + - go: 1.7.6 + - go: 1.8.3 + - go: tip allow_failures: - go: tip @@ -16,3 +15,7 @@ before_install: script: - PATH=$PATH:$PWD/bin go test -v ./... - go build + - diff -u <(echo -n) <(gofmt -d -s .) + - if [ -z $NOVET ]; then + diff -u <(echo -n) <(go tool vet . 2>&1 | grep -vE 'ExampleCommand|bash_completions.*Fprint'); + fi diff --git a/vendor/github.com/spf13/cobra/BUILD b/vendor/github.com/spf13/cobra/BUILD index 5c16bacbce2..158c8f10692 100644 --- a/vendor/github.com/spf13/cobra/BUILD +++ b/vendor/github.com/spf13/cobra/BUILD @@ -3,9 +3,11 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = [ + "args.go", "bash_completions.go", "cobra.go", "command.go", + "zsh_completions.go", ] + select({ "@io_bazel_rules_go//go/platform:android": [ "command_notwin.go", diff --git a/vendor/github.com/spf13/cobra/README.md b/vendor/github.com/spf13/cobra/README.md index b338a0e4424..d7279e4f9f9 100644 --- a/vendor/github.com/spf13/cobra/README.md +++ b/vendor/github.com/spf13/cobra/README.md @@ -8,6 +8,7 @@ Many of the most widely used Go projects are built using Cobra including: * [Hugo](http://gohugo.io) * [rkt](https://github.com/coreos/rkt) * [etcd](https://github.com/coreos/etcd) +* [Moby (former Docker)](https://github.com/moby/moby) * [Docker (distribution)](https://github.com/docker/distribution) * [OpenShift](https://www.openshift.com/) * [Delve](https://github.com/derekparker/delve) @@ -15,16 +16,36 @@ Many of the most widely used Go projects are built using Cobra including: * [CockroachDB](http://www.cockroachlabs.com/) * [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) - +* [rclone](http://rclone.org/) +* [nehm](https://github.com/bogem/nehm) [![Build Status](https://travis-ci.org/spf13/cobra.svg "Travis CI status")](https://travis-ci.org/spf13/cobra) [![CircleCI status](https://circleci.com/gh/spf13/cobra.png?circle-token=:circle-token "CircleCI status")](https://circleci.com/gh/spf13/cobra) -[![GoDoc](https://godoc.org/github.com/spf13/cobra?status.svg)](https://godoc.org/github.com/spf13/cobra) +[![GoDoc](https://godoc.org/github.com/spf13/cobra?status.svg)](https://godoc.org/github.com/spf13/cobra) -![cobra](https://cloud.githubusercontent.com/assets/173412/10911369/84832a8e-8212-11e5-9f82-cc96660a4794.gif) +# Table of Contents + +- [Overview](#overview) +- [Concepts](#concepts) + * [Commands](#commands) + * [Flags](#flags) +- [Installing](#installing) +- [Getting Started](#getting-started) + * [Using the Cobra Generator](#using-the-cobra-generator) + * [Using the Cobra Library](#using-the-cobra-library) + * [Working with Flags](#working-with-flags) + * [Positional and Custom Arguments](#positional-and-custom-arguments) + * [Example](#example) + * [Help Command](#help-command) + * [Usage Message](#usage-message) + * [PreRun and PostRun Hooks](#prerun-and-postrun-hooks) + * [Suggestions when "unknown command" happens](#suggestions-when-unknown-command-happens) + * [Generating documentation for your command](#generating-documentation-for-your-command) + * [Generating bash completions](#generating-bash-completions) +- [Contributing](#contributing) +- [License](#license) # Overview @@ -39,27 +60,16 @@ Cobra provides: * 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` +* Easy generation of applications & commands with `cobra init 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. +* The flexibility to define your own help, usage, etc. * Optional tight integration with [viper](http://github.com/spf13/viper) for 12-factor apps -Cobra has an exceptionally clean interface and simple design without needless -constructors or initialization methods. - -Applications built with Cobra commands are designed to be as user-friendly as -possible. Flags can be placed before or after the command (as long as a -confusing space isn’t provided). Both short and long flags can be used. A -command need not even be fully typed. Help is automatically generated and -available for the application or for a specific command using either the help -command or the `--help` flag. - # Concepts Cobra is built on a structure of commands, arguments & flags. @@ -78,11 +88,11 @@ A few good real world examples may better illustrate this point. In the following example, 'server' is a command, and 'port' is a flag: - > hugo server --port=1313 + hugo server --port=1313 In this command we are telling Git to clone the url bare. - > git clone URL --bare + git clone URL --bare ## Commands @@ -92,20 +102,11 @@ have children commands and optionally run an action. In the example above, 'server' is the command. -A Command has the following structure: - -```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. -} -``` +[More about cobra.Command](https://godoc.org/github.com/spf13/cobra#Command) ## Flags -A Flag is a way to modify the behavior of a command. Cobra supports +A flag is a way to modify the behavior of a command. Cobra supports fully POSIX-compliant flags as well as the Go [flag package](https://golang.org/pkg/flag/). A Cobra command can define flags that persist through to children commands and flags that are only available to that command. @@ -113,23 +114,15 @@ and flags that are only available to that command. In the example above, 'port' is the flag. Flag functionality is provided by the [pflag -library](https://github.com/ogier/pflag), a fork of the flag standard library +library](https://github.com/spf13/pflag), a fork of the flag standard library which maintains the same interface while adding POSIX compliance. -## Usage - -Cobra works by creating a set of commands and then organizing them into a tree. -The tree defines the structure of the application. - -Once each command is defined with its corresponding flags, then the -tree is assigned to the commander which is finally executed. - # Installing 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: +of the library. This command will install the `cobra` generator executable +along with the library and its dependencies: - > go get -v github.com/spf13/cobra/cobra + go get -u github.com/spf13/cobra/cobra Next, include Cobra in your application: @@ -139,8 +132,8 @@ 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. +While you are welcome to provide your own organization, typically a Cobra-based +application will follow the following organizational structure: ``` ▾ appName/ @@ -152,18 +145,23 @@ application will follow the following organizational structure. main.go ``` -In a Cobra app, typically the main.go file is very bare. It serves, one purpose, to initialize Cobra. +In a Cobra app, typically the main.go file is very bare. It serves one purpose: initializing Cobra. ```go package main -import "{pathToYourApp}/cmd" +import ( + "fmt" + "os" + + "{pathToYourApp}/cmd" +) func main() { - if err := cmd.RootCmd.Execute(); err != nil { - fmt.Println(err) - os.Exit(-1) - } + if err := cmd.RootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } } ``` @@ -172,99 +170,14 @@ func main() { 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: +[Here](https://github.com/spf13/cobra/blob/master/cobra/README.md) you can find more information about it. - > go install github.com/spf13/cobra/cobra +## Using the Cobra Library -This will create the cobra executable under your go path bin directory! - -### cobra init - -The `cobra init [yourApp]` command will create your initial application code -for you. It is a very powerful application that will populate your program with -the right structure so you can immediately enjoy all the benefits of Cobra. It -will also automatically apply the license you specify to your application. - -Cobra init is pretty smart. You can provide it a full path, or simply a path -similar to what is expected in the import. - -``` -cobra init github.com/spf13/newAppName -``` - -### cobra add - -Once an application is initialized Cobra can create additional commands for you. -Let's say you created an app and you wanted the following commands for it: - -* app serve -* app config -* app config create - -In your project directory (where your main.go file is) you would run the following: - -``` -cobra add serve -cobra add config -cobra add create -p 'configCmd' -``` - -Once you have run these three commands you would have an app structure that would look like: - -``` - ▾ app/ - ▾ cmd/ - serve.go - config.go - create.go - main.go -``` - -at this point you can run `go run main.go` and it would run your app. `go run -main.go serve`, `go run main.go config`, `go run main.go config create` along -with `go run main.go help serve`, etc would all work. - -Obviously you haven't added your own code to these yet, the commands are ready -for you to give them their tasks. Have fun. - -### Configuring the cobra generator - -The cobra generator will be easier to use if you provide a simple configuration -file which will help you eliminate providing a bunch of repeated information in -flags over and over. - -An example ~/.cobra.yaml file: - -```yaml -author: Steve Francia -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. +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 +### Create rootCmd Cobra doesn't require any special constructors. Simply create your commands. @@ -272,34 +185,67 @@ 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 + 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: +For example cmd/root.go: ```go +import ( + "fmt" + "os" + + homedir "github.com/mitchellh/go-homedir" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + 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") + 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") +} + +func initConfig() { + // Don't forget to read config either from cfgFile or from home directory! + if cfgFile != "" { + // Use config file from the flag. + viper.SetConfigFile(cfgFile) + } else { + // Find home directory. + home, err := homedir.Dir() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + // Search config in home directory with name ".cobra" (without extension). + viper.AddConfigPath(home) + viper.SetConfigName(".cobra") + } + + if err := viper.ReadInConfig(); err != nil { + fmt.Println("Can't read config:", err) + os.Exit(1) + } } ``` @@ -313,17 +259,21 @@ In a Cobra app, typically the main.go file is very bare. It serves, one purpose, ```go package main -import "{pathToYourApp}/cmd" +import ( + "fmt" + "os" + + "{pathToYourApp}/cmd" +) func main() { - if err := cmd.RootCmd.Execute(); err != nil { - fmt.Println(err) - os.Exit(-1) - } + if err := cmd.RootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } } ``` - ### Create additional commands Additional commands can be defined and typically are each given their own file @@ -336,47 +286,24 @@ populate it with the following: package cmd import ( - "github.com/spf13/cobra" + "github.com/spf13/cobra" + "fmt" ) func init() { - RootCmd.AddCommand(versionCmd) + 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") - }, + 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 - - -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. @@ -412,6 +339,71 @@ A flag can also be assigned locally which will only apply to that specific comma RootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") ``` +### Local Flag on Parent Commands + +By default Cobra only parses local flags on the target command, any local flags on +parent commands are ignored. By enabling `Command.TraverseChildren` Cobra will +parse local flags on each command before executing the target command. + +```go +command := cobra.Command{ + Use: "print [OPTIONS] [COMMANDS]", + TraverseChildren: true, +} +``` + +### Bind Flags with Config + +You can also bind your flags with [viper](https://github.com/spf13/viper): +```go +var author string + +func init() { + RootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution") + viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author")) +} +``` + +In this example the persistent flag `author` is bound with `viper`. +**Note**, that the variable `author` will not be set to the value from config, +when the `--author` flag is not provided by user. + +More in [viper documentation](https://github.com/spf13/viper#working-with-flags). + +## Positional and Custom Arguments + +Validation of positional arguments can be specified using the `Args` field +of `Command`. + +The following validators are built in: + +- `NoArgs` - the command will report an error if there are any positional args. +- `ArbitraryArgs` - the command will accept any args. +- `OnlyValidArgs` - the command will report an error if there are any positional args that are not in the `ValidArgs` field of `Command`. +- `MinimumNArgs(int)` - the command will report an error if there are not at least N positional args. +- `MaximumNArgs(int)` - the command will report an error if there are more than N positional args. +- `ExactArgs(int)` - the command will report an error if there are not exactly N positional args. +- `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args. + +An example of setting the custom validator: + +```go +var cmd = &cobra.Command{ + Short: "hello", + Args: func(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return errors.New("requires at least one arg") + } + if myapp.IsValidColor(args[0]) { + return nil + } + return fmt.Errorf("invalid color specified: %s", args[0]) + }, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Hello, World!") + }, +} +``` ## Example @@ -428,62 +420,62 @@ More documentation about flags is available at https://github.com/spf13/pflag package main import ( - "fmt" - "strings" + "fmt" + "strings" - "github.com/spf13/cobra" + "github.com/spf13/cobra" ) 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. +For many years people have printed back to the screen.`, + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Print: " + strings.Join(args, " ")) + }, + } - 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. +Echo works a lot like print, except it has a child command.`, + Args: cobra.MinimumNArgs(1), + 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 +a count and a string.`, + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + for i := 0; i < echoTimes; i++ { + fmt.Println("Echo: " + 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, " ")) - } - }, - } + 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://gohugo.io/). -## The Help Command +## 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 @@ -496,60 +488,28 @@ create' is called. Every command will automatically have the '--help' flag adde The following output is automatically generated by Cobra. Nothing beyond the command and flag definitions are needed. - > hugo help + $ cobra help - hugo is the main command, used to build your Hugo site. - - 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/. + Cobra is a CLI library for Go that empowers applications. + This application is a tool to generate the needed files + to quickly create a Cobra application. Usage: - hugo [flags] - hugo [command] + cobra [command] Available Commands: - 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. + add Add a command to a Cobra Application + help Help about any command + init Initialize a Cobra Application 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 - -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 + -a, --author string author name for copyright attribution (default "YOUR NAME") + --config string config file (default is $HOME/.cobra.yaml) + -h, --help help for cobra + -l, --license string name of license for the project + --viper use Viper for configuration (default true) - Use "hugo [command] --help" for more information about a command. + Use "cobra [command] --help" for more information about a command. Help is just a command like any other. There is no special logic or behavior @@ -557,38 +517,18 @@ around it. In fact, you can provide your own if you want. ### Defining your own help -You can provide your own Help command or your own template for the default command to use. - -The default help command is +You can provide your own Help command or your own template for the default command to use +with following functions: ```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) -} -``` - -You can provide your own command, function or template through the following methods: - -```go -command.SetHelpCommand(cmd *Command) - -command.SetHelpFunc(f func(*Command, []string)) - -command.SetHelpTemplate(s string) +cmd.SetHelpCommand(cmd *Command) +cmd.SetHelpFunc(f func(*Command, []string)) +cmd.SetHelpTemplate(s string) ``` The latter two will also apply to any children commands. -## Usage +## Usage Message When the user provides an invalid flag or invalid command, Cobra responds by showing the user the 'usage'. @@ -597,73 +537,37 @@ showing the user the 'usage'. You may recognize this from the help above. That's because the default help embeds the usage as part of its output. + $ cobra --invalid + Error: unknown flag: --invalid Usage: - hugo [flags] - hugo [command] + cobra [command] Available Commands: - 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. + add Add a command to a Cobra Application + help Help about any command + init Initialize a Cobra Application 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 - -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 + -a, --author string author name for copyright attribution (default "YOUR NAME") + --config string config file (default is $HOME/.cobra.yaml) + -h, --help help for cobra + -l, --license string name of license for the project + --viper use Viper for configuration (default true) + + Use "cobra [command] --help" for more information about a command. ### Defining your own usage You can provide your own usage function or template for Cobra to use. - -The default usage function is: - -```go -return func(c *Command) error { - err := tmpl(c.Out(), c.UsageTemplate(), c) - return err -} -``` - Like help, the function and template are overridable through public methods: ```go -command.SetUsageFunc(f func(*Command) error) - -command.SetUsageTemplate(s string) +cmd.SetUsageFunc(f func(*Command) error) +cmd.SetUsageTemplate(s string) ``` -## PreRun or PostRun Hooks +## PreRun and PostRun Hooks -It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherrited by children if they do not declare their own. These function are run in the following order: +It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order: - `PersistentPreRun` - `PreRun` @@ -677,105 +581,73 @@ An example of two commands which use all of these features is below. When the s package main import ( - "fmt" + "fmt" - "github.com/spf13/cobra" + "github.com/spf13/cobra" ) func main() { - var rootCmd = &cobra.Command{ - Use: "root [sub]", - Short: "My root command", - PersistentPreRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args) - }, - PreRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd PreRun with args: %v\n", args) - }, - Run: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd Run with args: %v\n", args) - }, - PostRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd PostRun with args: %v\n", args) - }, - PersistentPostRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args) - }, - } + var rootCmd = &cobra.Command{ + Use: "root [sub]", + Short: "My root command", + PersistentPreRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args) + }, + PreRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd PreRun with args: %v\n", args) + }, + Run: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd Run with args: %v\n", args) + }, + PostRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd PostRun with args: %v\n", args) + }, + PersistentPostRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args) + }, + } - var subCmd = &cobra.Command{ - Use: "sub [no options!]", - Short: "My subcommand", - PreRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside subCmd PreRun with args: %v\n", args) - }, - Run: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside subCmd Run with args: %v\n", args) - }, - PostRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside subCmd PostRun with args: %v\n", args) - }, - PersistentPostRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args) - }, - } + var subCmd = &cobra.Command{ + Use: "sub [no options!]", + Short: "My subcommand", + PreRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside subCmd PreRun with args: %v\n", args) + }, + Run: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside subCmd Run with args: %v\n", args) + }, + PostRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside subCmd PostRun with args: %v\n", args) + }, + PersistentPostRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args) + }, + } - rootCmd.AddCommand(subCmd) + rootCmd.AddCommand(subCmd) - rootCmd.SetArgs([]string{""}) - _ = rootCmd.Execute() - fmt.Print("\n") - rootCmd.SetArgs([]string{"sub", "arg1", "arg2"}) - _ = rootCmd.Execute() + rootCmd.SetArgs([]string{""}) + rootCmd.Execute() + fmt.Println() + rootCmd.SetArgs([]string{"sub", "arg1", "arg2"}) + rootCmd.Execute() } ``` +Output: +``` +Inside rootCmd PersistentPreRun with args: [] +Inside rootCmd PreRun with args: [] +Inside rootCmd Run with args: [] +Inside rootCmd PostRun with args: [] +Inside rootCmd PersistentPostRun with args: [] -## Alternative Error Handling - -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) - } -} +Inside rootCmd PersistentPreRun with args: [arg1 arg2] +Inside subCmd PreRun with args: [arg1 arg2] +Inside subCmd Run with args: [arg1 arg2] +Inside subCmd PostRun with args: [arg1 arg2] +Inside subCmd PersistentPostRun with args: [arg1 arg2] ``` ## Suggestions when "unknown command" happens @@ -818,81 +690,28 @@ Did you mean this? Run 'kubectl help' for usage. ``` -## Generating Markdown-formatted documentation for your command +## Generating documentation for your command -Cobra can generate a Markdown-formatted document based on the subcommands, flags, etc. A simple example of how to do this for your command can be found in [Markdown Docs](doc/md_docs.md). +Cobra can generate documentation based on subcommands, flags, etc. in the following formats: -## Generating man pages for your command +- [Markdown](doc/md_docs.md) +- [ReStructured Text](doc/rest_docs.md) +- [Man Page](doc/man_docs.md) -Cobra can generate a man page based on the subcommands, flags, etc. A simple example of how to do this for your command can be found in [Man Docs](doc/man_docs.md). - -## Generating bash completions for your command +## Generating bash completions 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. - -### Example - -```go -command.DebugFlags() -``` - -## Release Notes -* **0.9.0** June 17, 2014 - * flags can appears anywhere in the args (provided they are unambiguous) - * --help prints usage screen for app or command - * Prefix matching for commands - * Cleaner looking help and usage output - * Extensive test suite -* **0.8.0** Nov 5, 2013 - * Reworked interface to remove commander completely - * Command now primary structure - * No initialization needed - * Usage & Help templates & functions definable at any level - * Updated Readme -* **0.7.0** Sept 24, 2013 - * Needs more eyes - * Test suite - * Support for automatic error messages - * Support for help command - * Support for printing to any io.Writer instead of os.Stderr - * Support for persistent flags which cascade down tree - * Ready for integration into Hugo -* **0.1.0** Sept 3, 2013 - * Implement first draft - -## Extensions - -Libraries for extending Cobra: - -* [cmdns](https://github.com/gosuri/cmdns): Enables name spacing a command's immediate children. It provides an alternative way to structure subcommands, similar to `heroku apps:create` and `ovrclk clusters:launch`. - -## ToDo -* Launch proper documentation site - -## Contributing +# Contributing 1. Fork it -2. Create your feature branch (`git checkout -b my-new-feature`) -3. Commit your changes (`git commit -am 'Add some feature'`) -4. Push to the branch (`git push origin my-new-feature`) -5. Create new Pull Request +2. Download your fork to your PC (`git clone https://github.com/your_username/cobra && cd cobra`) +3. Create your feature branch (`git checkout -b my-new-feature`) +4. Make changes and add them (`git add .`) +5. Commit your changes (`git commit -m 'Add some feature'`) +6. Push to the branch (`git push origin my-new-feature`) +7. Create new pull request -## Contributors - -Names in no particular order: - -* [spf13](https://github.com/spf13), -[eparis](https://github.com/eparis), -[bep](https://github.com/bep), and many more! - -## License +# License Cobra is released under the Apache 2.0 license. See [LICENSE.txt](https://github.com/spf13/cobra/blob/master/LICENSE.txt) - - -[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/spf13/cobra/trend.png)](https://bitdeli.com/free "Bitdeli Badge") diff --git a/vendor/github.com/spf13/cobra/args.go b/vendor/github.com/spf13/cobra/args.go new file mode 100644 index 00000000000..a5d8a9273ea --- /dev/null +++ b/vendor/github.com/spf13/cobra/args.go @@ -0,0 +1,89 @@ +package cobra + +import ( + "fmt" +) + +type PositionalArgs func(cmd *Command, args []string) error + +// Legacy arg validation has the following behaviour: +// - root commands with no subcommands can take arbitrary arguments +// - root commands with subcommands will do subcommand validity checking +// - subcommands will always accept arbitrary arguments +func legacyArgs(cmd *Command, args []string) error { + // no subcommand, always take args + if !cmd.HasSubCommands() { + return nil + } + + // root command with subcommands, do subcommand checking. + if !cmd.HasParent() && len(args) > 0 { + return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0])) + } + return nil +} + +// NoArgs returns an error if any args are included. +func NoArgs(cmd *Command, args []string) error { + if len(args) > 0 { + return fmt.Errorf("unknown command %q for %q", args[0], cmd.CommandPath()) + } + return nil +} + +// OnlyValidArgs returns an error if any args are not in the list of ValidArgs. +func OnlyValidArgs(cmd *Command, args []string) error { + if len(cmd.ValidArgs) > 0 { + for _, v := range args { + if !stringInSlice(v, cmd.ValidArgs) { + return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0])) + } + } + } + return nil +} + +// ArbitraryArgs never returns an error. +func ArbitraryArgs(cmd *Command, args []string) error { + return nil +} + +// MinimumNArgs returns an error if there is not at least N args. +func MinimumNArgs(n int) PositionalArgs { + return func(cmd *Command, args []string) error { + if len(args) < n { + return fmt.Errorf("requires at least %d arg(s), only received %d", n, len(args)) + } + return nil + } +} + +// MaximumNArgs returns an error if there are more than N args. +func MaximumNArgs(n int) PositionalArgs { + return func(cmd *Command, args []string) error { + if len(args) > n { + return fmt.Errorf("accepts at most %d arg(s), received %d", n, len(args)) + } + return nil + } +} + +// ExactArgs returns an error if there are not exactly n args. +func ExactArgs(n int) PositionalArgs { + return func(cmd *Command, args []string) error { + if len(args) != n { + return fmt.Errorf("accepts %d arg(s), received %d", n, len(args)) + } + return nil + } +} + +// RangeArgs returns an error if the number of args is not within the expected range. +func RangeArgs(min int, max int) PositionalArgs { + return func(cmd *Command, args []string) error { + if len(args) < min || len(args) > max { + return fmt.Errorf("accepts between %d and %d arg(s), received %d", min, max, len(args)) + } + return nil + } +} diff --git a/vendor/github.com/spf13/cobra/bash_completions.go b/vendor/github.com/spf13/cobra/bash_completions.go index 236dee67f21..c19fe7a068b 100644 --- a/vendor/github.com/spf13/cobra/bash_completions.go +++ b/vendor/github.com/spf13/cobra/bash_completions.go @@ -1,6 +1,7 @@ package cobra import ( + "bytes" "fmt" "io" "os" @@ -10,19 +11,17 @@ import ( "github.com/spf13/pflag" ) +// Annotations for Bash completion. const ( - BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extentions" + BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extensions" 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 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, ` +func writePreamble(buf *bytes.Buffer, name string) { + buf.WriteString(fmt.Sprintf("# bash completion for %-36s -*- shell-script -*-\n", name)) + buf.WriteString(` __debug() { if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then @@ -87,13 +86,13 @@ __handle_reply() local index flag flag="${cur%%=*}" __index_of_word "${flag}" "${flags_with_completion[@]}" + COMPREPLY=() if [[ ${index} -ge 0 ]]; then - COMPREPLY=() PREFIX="" cur="${cur#*=}" ${flags_completion[${index}]} if [ -n "${ZSH_VERSION}" ]; then - # zfs completion needs --flag= prefix + # zsh completion needs --flag= prefix eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )" fi fi @@ -133,7 +132,10 @@ __handle_reply() declare -F __custom_func >/dev/null && __custom_func fi - __ltrim_colon_completions "$cur" + # available in bash-completion >= 2, not always present on macOS + if declare -F __ltrim_colon_completions >/dev/null; then + __ltrim_colon_completions "$cur" + fi } # The arguments should be in the form "ext1|ext2|extn" @@ -224,7 +226,7 @@ __handle_command() fi c=$((c+1)) __debug "${FUNCNAME[0]}: looking for ${next_command}" - declare -F $next_command >/dev/null && $next_command + declare -F "$next_command" >/dev/null && $next_command } __handle_word() @@ -247,16 +249,12 @@ __handle_word() } `) - return err } -func postscript(w io.Writer, name string) error { +func writePostscript(buf *bytes.Buffer, name string) { name = strings.Replace(name, ":", "__", -1) - _, err := fmt.Fprintf(w, "__start_%s()\n", name) - if err != nil { - return err - } - _, err = fmt.Fprintf(w, `{ + buf.WriteString(fmt.Sprintf("__start_%s()\n", name)) + buf.WriteString(fmt.Sprintf(`{ local cur prev words cword declare -A flaghash 2>/dev/null || : if declare -F _init_completion >/dev/null 2>&1; then @@ -280,318 +278,227 @@ func postscript(w io.Writer, name string) error { __handle_word } -`, name) - if err != nil { - return err - } - _, err = fmt.Fprintf(w, `if [[ $(type -t compopt) = "builtin" ]]; then +`, name)) + buf.WriteString(fmt.Sprintf(`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 +`, name, name, name, name)) + buf.WriteString("# ex: ts=4 sw=4 et filetype=sh\n") } -func writeCommands(cmd *Command, w io.Writer) error { - if _, err := fmt.Fprintf(w, " commands=()\n"); err != nil { - return err - } +func writeCommands(buf *bytes.Buffer, cmd *Command) { + buf.WriteString(" commands=()\n") for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c == cmd.helpCommand { continue } - if _, err := fmt.Fprintf(w, " commands+=(%q)\n", c.Name()); err != nil { - return err - } + buf.WriteString(fmt.Sprintf(" commands+=(%q)\n", c.Name())) } - _, err := fmt.Fprintf(w, "\n") - return err + buf.WriteString("\n") } -func writeFlagHandler(name string, annotations map[string][]string, w io.Writer) error { +func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]string) { for key, value := range annotations { switch key { case BashCompFilenameExt: - _, err := fmt.Fprintf(w, " flags_with_completion+=(%q)\n", name) - if err != nil { - return err - } + buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) + var ext string if len(value) > 0 { - ext := "__handle_filename_extension_flag " + strings.Join(value, "|") - _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext) + ext = "__handle_filename_extension_flag " + strings.Join(value, "|") } else { - ext := "_filedir" - _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext) - } - if err != nil { - return err + ext = "_filedir" } + buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", ext)) case BashCompCustom: - _, err := fmt.Fprintf(w, " flags_with_completion+=(%q)\n", name) - if err != nil { - return err - } + buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) if len(value) > 0 { handlers := strings.Join(value, "; ") - _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", handlers) + buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", handlers)) } else { - _, err = fmt.Fprintf(w, " flags_completion+=(:)\n") - } - if err != nil { - return err + buf.WriteString(" flags_completion+=(:)\n") } case BashCompSubdirsInDir: - _, err := fmt.Fprintf(w, " flags_with_completion+=(%q)\n", name) + buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) + var ext string if len(value) == 1 { - ext := "__handle_subdirs_in_dir_flag " + value[0] - _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext) + ext = "__handle_subdirs_in_dir_flag " + value[0] } else { - ext := "_filedir -d" - _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext) - } - if err != nil { - return err + ext = "_filedir -d" } + buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", ext)) } } - return nil } -func writeShortFlag(flag *pflag.Flag, w io.Writer) error { - b := (len(flag.NoOptDefVal) > 0) +func writeShortFlag(buf *bytes.Buffer, flag *pflag.Flag) { name := flag.Shorthand format := " " - if !b { + if len(flag.NoOptDefVal) == 0 { format += "two_word_" } format += "flags+=(\"-%s\")\n" - if _, err := fmt.Fprintf(w, format, name); err != nil { - return err - } - return writeFlagHandler("-"+name, flag.Annotations, w) + buf.WriteString(fmt.Sprintf(format, name)) + writeFlagHandler(buf, "-"+name, flag.Annotations) } -func writeFlag(flag *pflag.Flag, w io.Writer) error { - b := (len(flag.NoOptDefVal) > 0) +func writeFlag(buf *bytes.Buffer, flag *pflag.Flag) { name := flag.Name format := " flags+=(\"--%s" - if !b { + if len(flag.NoOptDefVal) == 0 { format += "=" } format += "\")\n" - if _, err := fmt.Fprintf(w, format, name); err != nil { - return err - } - return writeFlagHandler("--"+name, flag.Annotations, w) + buf.WriteString(fmt.Sprintf(format, name)) + writeFlagHandler(buf, "--"+name, flag.Annotations) } -func writeLocalNonPersistentFlag(flag *pflag.Flag, w io.Writer) error { - b := (len(flag.NoOptDefVal) > 0) +func writeLocalNonPersistentFlag(buf *bytes.Buffer, flag *pflag.Flag) { name := flag.Name format := " local_nonpersistent_flags+=(\"--%s" - if !b { + if len(flag.NoOptDefVal) == 0 { format += "=" } format += "\")\n" - if _, err := fmt.Fprintf(w, format, name); err != nil { - return err - } - return nil + buf.WriteString(fmt.Sprintf(format, name)) } -func writeFlags(cmd *Command, w io.Writer) error { - _, err := fmt.Fprintf(w, ` flags=() +func writeFlags(buf *bytes.Buffer, cmd *Command) { + buf.WriteString(` 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) { - if err := writeFlag(flag, w); err != nil { - visitErr = err + if nonCompletableFlag(flag) { return } + writeFlag(buf, flag) if len(flag.Shorthand) > 0 { - if err := writeShortFlag(flag, w); err != nil { - visitErr = err - return - } + writeShortFlag(buf, flag) } if localNonPersistentFlags.Lookup(flag.Name) != nil { - if err := writeLocalNonPersistentFlag(flag, w); err != nil { - visitErr = err - return - } + writeLocalNonPersistentFlag(buf, flag) } }) - if visitErr != nil { - return visitErr - } cmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) { - if err := writeFlag(flag, w); err != nil { - visitErr = err + if nonCompletableFlag(flag) { return } + writeFlag(buf, flag) if len(flag.Shorthand) > 0 { - if err := writeShortFlag(flag, w); err != nil { - visitErr = err - return - } + writeShortFlag(buf, flag) } }) - if visitErr != nil { - return visitErr - } - _, err = fmt.Fprintf(w, "\n") - return err + buf.WriteString("\n") } -func writeRequiredFlag(cmd *Command, w io.Writer) error { - if _, err := fmt.Fprintf(w, " must_have_one_flag=()\n"); err != nil { - return err - } +func writeRequiredFlag(buf *bytes.Buffer, cmd *Command) { + buf.WriteString(" must_have_one_flag=()\n") 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: format := " must_have_one_flag+=(\"--%s" - b := (flag.Value.Type() == "bool") - if !b { + if flag.Value.Type() != "bool" { format += "=" } format += "\")\n" - if _, err := fmt.Fprintf(w, format, flag.Name); err != nil { - visitErr = err - return - } + buf.WriteString(fmt.Sprintf(format, flag.Name)) if len(flag.Shorthand) > 0 { - if _, err := fmt.Fprintf(w, " must_have_one_flag+=(\"-%s\")\n", flag.Shorthand); err != nil { - visitErr = err - return - } + buf.WriteString(fmt.Sprintf(" must_have_one_flag+=(\"-%s\")\n", flag.Shorthand)) } } } }) - return visitErr } -func writeRequiredNouns(cmd *Command, w io.Writer) error { - if _, err := fmt.Fprintf(w, " must_have_one_noun=()\n"); err != nil { - return err - } +func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) { + buf.WriteString(" must_have_one_noun=()\n") sort.Sort(sort.StringSlice(cmd.ValidArgs)) for _, value := range cmd.ValidArgs { - if _, err := fmt.Fprintf(w, " must_have_one_noun+=(%q)\n", value); err != nil { - return err - } + buf.WriteString(fmt.Sprintf(" must_have_one_noun+=(%q)\n", value)) } - return nil } -func writeArgAliases(cmd *Command, w io.Writer) error { - if _, err := fmt.Fprintf(w, " noun_aliases=()\n"); err != nil { - return err - } +func writeArgAliases(buf *bytes.Buffer, cmd *Command) { + buf.WriteString(" noun_aliases=()\n") 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 - } + buf.WriteString(fmt.Sprintf(" noun_aliases+=(%q)\n", value)) } - return nil } -func gen(cmd *Command, w io.Writer) error { +func gen(buf *bytes.Buffer, cmd *Command) { for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c == cmd.helpCommand { continue } - if err := gen(c, w); err != nil { - return err - } + gen(buf, c) } commandName := cmd.CommandPath() commandName = strings.Replace(commandName, " ", "_", -1) 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 + buf.WriteString(fmt.Sprintf("_%s()\n{\n", commandName)) + buf.WriteString(fmt.Sprintf(" last_command=%q\n", commandName)) + writeCommands(buf, cmd) + writeFlags(buf, cmd) + writeRequiredFlag(buf, cmd) + writeRequiredNouns(buf, cmd) + writeArgAliases(buf, cmd) + buf.WriteString("}\n\n") } -func (cmd *Command) GenBashCompletion(w io.Writer) error { - if err := preamble(w, cmd.Name()); err != nil { - return err +// GenBashCompletion generates bash completion file and writes to the passed writer. +func (c *Command) GenBashCompletion(w io.Writer) error { + buf := new(bytes.Buffer) + writePreamble(buf, c.Name()) + if len(c.BashCompletionFunction) > 0 { + buf.WriteString(c.BashCompletionFunction + "\n") } - if len(cmd.BashCompletionFunction) > 0 { - if _, err := fmt.Fprintf(w, "%s\n", cmd.BashCompletionFunction); err != nil { - return err - } - } - if err := gen(cmd, w); err != nil { - return err - } - return postscript(w, cmd.Name()) + gen(buf, c) + writePostscript(buf, c.Name()) + + _, err := buf.WriteTo(w) + return err } -func (cmd *Command) GenBashCompletionFile(filename string) error { +func nonCompletableFlag(flag *pflag.Flag) bool { + return flag.Hidden || len(flag.Deprecated) > 0 +} + +// GenBashCompletionFile generates bash completion file. +func (c *Command) GenBashCompletionFile(filename string) error { outFile, err := os.Create(filename) if err != nil { return err } defer outFile.Close() - return cmd.GenBashCompletion(outFile) + return c.GenBashCompletion(outFile) } // MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag, if it exists. -func (cmd *Command) MarkFlagRequired(name string) error { - return MarkFlagRequired(cmd.Flags(), name) +func (c *Command) MarkFlagRequired(name string) error { + return MarkFlagRequired(c.Flags(), name) } // MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag, if it exists. -func (cmd *Command) MarkPersistentFlagRequired(name string) error { - return MarkFlagRequired(cmd.PersistentFlags(), name) +func (c *Command) MarkPersistentFlagRequired(name string) error { + return MarkFlagRequired(c.PersistentFlags(), name) } // MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag in the flag set, if it exists. @@ -601,20 +508,20 @@ func MarkFlagRequired(flags *pflag.FlagSet, name string) error { // MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists. // Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. -func (cmd *Command) MarkFlagFilename(name string, extensions ...string) error { - return MarkFlagFilename(cmd.Flags(), name, extensions...) +func (c *Command) MarkFlagFilename(name string, extensions ...string) error { + return MarkFlagFilename(c.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) +func (c *Command) MarkFlagCustom(name string, f string) error { + return MarkFlagCustom(c.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...) +func (c *Command) MarkPersistentFlagFilename(name string, extensions ...string) error { + return MarkFlagFilename(c.PersistentFlags(), name, extensions...) } // MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag in the flag set, if it exists. diff --git a/vendor/github.com/spf13/cobra/bash_completions.md b/vendor/github.com/spf13/cobra/bash_completions.md index 6e3b71f13d5..52bd39ddb1d 100644 --- a/vendor/github.com/spf13/cobra/bash_completions.md +++ b/vendor/github.com/spf13/cobra/bash_completions.md @@ -18,7 +18,7 @@ func main() { } ``` -That will get you completions of subcommands and flags. If you make additional annotations to your code, you can get even more intelligent and flexible behavior. +`out.sh` will get you completions of subcommands and flags. Copy it to `/etc/bash_completion.d/` as described [here](https://debian-administration.org/article/316/An_introduction_to_bash_completion_part_1) and reset your terminal to use autocompletion. If you make additional annotations to your code, you can get even more intelligent and flexible behavior. ## Creating your own custom functions @@ -106,7 +106,7 @@ node pod replicationcontroller service If your nouns have a number of aliases, you can define them alongside `ValidArgs` using `ArgAliases`: -```go` +```go argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" } cmd := &cobra.Command{ diff --git a/vendor/github.com/spf13/cobra/cobra.go b/vendor/github.com/spf13/cobra/cobra.go index 93a2c0f3a77..e4b910c5d7a 100644 --- a/vendor/github.com/spf13/cobra/cobra.go +++ b/vendor/github.com/spf13/cobra/cobra.go @@ -27,48 +27,59 @@ import ( ) var templateFuncs = template.FuncMap{ - "trim": strings.TrimSpace, - "trimRightSpace": trimRightSpace, - "appendIfNotPresent": appendIfNotPresent, - "rpad": rpad, - "gt": Gt, - "eq": Eq, + "trim": strings.TrimSpace, + "trimRightSpace": trimRightSpace, + "trimTrailingWhitespaces": 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 +// EnablePrefixMatching allows to set automatic prefix matching. Automatic prefix matching can be a dangerous thing +// to automatically enable in CLI tools. +// Set this to true to enable it. var EnablePrefixMatching = false -//EnableCommandSorting controls sorting of the slice of commands, which is turned on by default. -//To disable sorting, set it to false. +// 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. +// MousetrapHelpText enables an information splash screen on Windows +// if the CLI is started from explorer.exe. +// To disable the mousetrap, just set this variable to blank string (""). +// Works only on Microsoft Windows. +var MousetrapHelpText string = `This is a command line tool. + +You need to open cmd.exe and run it from there. +` + +// AddTemplateFunc adds a template function that's available to Usage and Help +// template generation. func AddTemplateFunc(name string, tmplFunc interface{}) { templateFuncs[name] = tmplFunc } -//AddTemplateFuncs adds multiple template functions availalble to Usage and -//Help template generation. +// AddTemplateFuncs adds multiple template functions that are available to Usage and +// Help template generation. func AddTemplateFuncs(tmplFuncs template.FuncMap) { for k, v := range tmplFuncs { templateFuncs[k] = v } } -//OnInitialize takes a series of func() arguments and appends them to a slice of func(). +// OnInitialize takes a series of func() arguments and appends them to a slice of func(). func OnInitialize(y ...func()) { - for _, x := range y { - initializers = append(initializers, x) - } + initializers = append(initializers, y...) } -//Gt takes two types and checks whether the first type is greater than the second. In case of types Arrays, Chans, -//Maps and Slices, Gt will compare their lengths. Ints are compared directly while strings are first parsed as -//ints and then compared. +// FIXME Gt is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra. + +// Gt takes two types and checks whether the first type is greater than the second. In case of types Arrays, Chans, +// Maps and Slices, Gt will compare their lengths. Ints are compared directly while strings are first parsed as +// ints and then compared. func Gt(a interface{}, b interface{}) bool { var left, right int64 av := reflect.ValueOf(a) @@ -96,7 +107,9 @@ func Gt(a interface{}, b interface{}) bool { return left > right } -//Eq takes two types and checks whether they are equal. Supported types are int and string. Unsupported types will panic. +// FIXME Eq is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra. + +// Eq takes two types and checks whether they are equal. Supported types are int and string. Unsupported types will panic. func Eq(a interface{}, b interface{}) bool { av := reflect.ValueOf(a) bv := reflect.ValueOf(b) @@ -116,7 +129,9 @@ 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 +// FIXME appendIfNotPresent is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra. + +// appendIfNotPresent will append stringToAppend to the end of s, but only if it's not yet present in s. func appendIfNotPresent(s, stringToAppend string) string { if strings.Contains(s, stringToAppend) { return s @@ -124,7 +139,7 @@ func appendIfNotPresent(s, stringToAppend string) string { return s + " " + stringToAppend } -//rpad adds padding to the right of a string +// rpad adds padding to the right of a string. func rpad(s string, padding int) string { template := fmt.Sprintf("%%-%ds", padding) return fmt.Sprintf(template, s) @@ -138,7 +153,7 @@ func tmpl(w io.Writer, text string, data interface{}) error { return t.Execute(w, data) } -// ld compares two strings and returns the levenshtein distance between them +// ld compares two strings and returns the levenshtein distance between them. func ld(s, t string, ignoreCase bool) int { if ignoreCase { s = strings.ToLower(s) @@ -173,3 +188,12 @@ func ld(s, t string, ignoreCase bool) int { } return d[len(s)][len(t)] } + +func stringInSlice(a string, list []string) bool { + for _, b := range list { + if b == a { + return true + } + } + return false +} diff --git a/vendor/github.com/spf13/cobra/command.go b/vendor/github.com/spf13/cobra/command.go index 083e4ea7f47..eb311a7373a 100644 --- a/vendor/github.com/spf13/cobra/command.go +++ b/vendor/github.com/spf13/cobra/command.go @@ -11,8 +11,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -//Package cobra is a commander providing a simple interface to create powerful modern CLI interfaces. -//In addition to providing an interface, Cobra simultaneously provides a controller to organize your application code. +// Package cobra is a commander providing a simple interface to create powerful modern CLI interfaces. +// In addition to providing an interface, Cobra simultaneously provides a controller to organize your application code. package cobra import ( @@ -28,107 +28,158 @@ import ( ) // Command is just that, a command for your application. -// eg. 'go run' ... 'run' is the command. Cobra requires +// E.g. 'go run ...' - 'run' is the command. Cobra requires // you to define the usage and description as part of your command // definition to ensure usability. type Command struct { - // Name is the command name, usually the executable's name. - name string - // The one-line usage message. + // Use is the one-line usage message. Use string - // An array of aliases that can be used instead of the first word in Use. + + // Aliases is 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 is 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 is the short description shown in the 'help' output. Short string - // The long message shown in the 'help ' output. + + // Long is the long message shown in the 'help ' output. Long string - // Examples of how to use the command + + // Example is examples of how to use the command. Example string - // List of all valid non-flag arguments that are accepted in bash completions + + // ValidArgs is 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. + + // Expected arguments + Args PositionalArgs + + // ArgAliases is 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 is custom functions used by the bash autocompletion generator. BashCompletionFunction string - // Is this command deprecated and should print this string when used? + + // Deprecated defines, if this command is deprecated and should print this string when used. Deprecated string - // Is this command hidden and should NOT show up in the list of available commands? + + // Hidden defines, if this command is hidden and should NOT show up in the list of available commands. Hidden bool - // Full set of flags - flags *flag.FlagSet - // Set of flags childrens of this command will inherit - 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 + + // Annotations are key/value pairs that can be used by applications to identify or + // group commands. + Annotations map[string]string + // The *Run functions are executed in the following order: // * PersistentPreRun() // * PreRun() // * Run() // * PostRun() // * PersistentPostRun() - // All functions get the same args, the arguments after the command name - // PersistentPreRun: children of this command will inherit and execute + // All functions get the same args, the arguments after the command name. + // + // PersistentPreRun: children of this command will inherit and execute. PersistentPreRun func(cmd *Command, args []string) - // PersistentPreRunE: PersistentPreRun but returns an error + // PersistentPreRunE: PersistentPreRun but returns an error. PersistentPreRunE func(cmd *Command, args []string) error // PreRun: children of this command will not inherit. PreRun func(cmd *Command, args []string) - // PreRunE: PreRun but returns an error + // PreRunE: PreRun but returns an error. PreRunE func(cmd *Command, args []string) error - // Run: Typically the actual work function. Most commands will only implement this + // Run: Typically the actual work function. Most commands will only implement this. Run func(cmd *Command, args []string) - // RunE: Run but returns an error + // RunE: Run but returns an error. RunE func(cmd *Command, args []string) error // PostRun: run after the Run command. PostRun func(cmd *Command, args []string) - // PostRunE: PostRun but returns an error + // PostRunE: PostRun but returns an error. PostRunE func(cmd *Command, args []string) error - // PersistentPostRun: children of this command will inherit and execute after PostRun + // PersistentPostRun: children of this command will inherit and execute after PostRun. PersistentPostRun func(cmd *Command, args []string) - // PersistentPostRunE: PersistentPostRun but returns an error + // PersistentPostRunE: PersistentPostRun but returns an error. PersistentPostRunE func(cmd *Command, args []string) error - // DisableAutoGenTag remove + + // SilenceErrors is an option to quiet errors down stream. + SilenceErrors bool + + // SilenceUsage is an option to silence usage when an error occurs. + SilenceUsage bool + + // DisableFlagParsing disables the flag parsing. + // If this is true all flags will be passed to the command as arguments. + DisableFlagParsing bool + + // DisableAutoGenTag defines, if gen tag ("Auto generated by spf13/cobra...") + // will be printed by generating docs for this command. DisableAutoGenTag bool - // Commands is the list of commands supported by this program. + + // DisableFlagsInUseLine will disable the addition of [flags] to the usage + // line of a command when printing help or generating docs + DisableFlagsInUseLine bool + + // DisableSuggestions disables the suggestions based on Levenshtein distance + // that go along with 'unknown command' messages. + DisableSuggestions bool + // SuggestionsMinimumDistance defines minimum levenshtein distance to display suggestions. + // Must be > 0. + SuggestionsMinimumDistance int + + // TraverseChildren parses flags on all parents before executing child command. + TraverseChildren bool + + // commands is the list of commands supported by this program. commands []*Command - // Parent Command for this command + // parent is a parent command for this command. parent *Command - // max lengths of commands' string lengths for use in padding + // Max lengths of commands' string lengths for use in padding. commandsMaxUseLen int commandsMaxCommandPathLen int commandsMaxNameLen int - // is commands slice are sorted or not + // commandsAreSorted defines, if command slice are sorted or not. commandsAreSorted bool + // args is actual args parsed from flags. + args []string + // flagErrorBuf contains all error messages from pflag. flagErrorBuf *bytes.Buffer - - args []string // actual args parsed from flags - 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 - helpFunc func(*Command, []string) // Help can be defined by application - helpCommand *Command // The help command - // The global normalization function that we can use on every pFlag set and children commands + // flags is full set of flags. + flags *flag.FlagSet + // pflags contains persistent flags. + pflags *flag.FlagSet + // lflags contains local flags. + lflags *flag.FlagSet + // iflags contains inherited flags. + iflags *flag.FlagSet + // parentsPflags is all persistent flags of cmd's parents. + parentsPflags *flag.FlagSet + // globNormFunc is 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 + // output is an output writer defined by user. + output io.Writer + // usageFunc is usage func defined by user. + usageFunc func(*Command) error + // usageTemplate is usage template defined by user. + usageTemplate string + // flagErrorFunc is func defined by user and it's called when the parsing of + // flags returns an error. + flagErrorFunc func(*Command, error) error + // helpTemplate is help template defined by user. + helpTemplate string + // helpFunc is help func defined by user. + helpFunc func(*Command, []string) + // helpCommand is command with usage 'help'. If it's not defined by user, + // cobra uses default help command. + helpCommand *Command } -// os.Args[1:] by default, if desired, can be overridden +// SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden // particularly useful when testing. func (c *Command) SetArgs(a []string) { c.args = a @@ -137,29 +188,36 @@ func (c *Command) SetArgs(a []string) { // SetOutput sets the destination for usage and error messages. // If output is nil, os.Stderr is used. func (c *Command) SetOutput(output io.Writer) { - c.output = &output + c.output = output } -// Usage can be defined by application +// SetUsageFunc sets usage function. Usage can be defined by application. func (c *Command) SetUsageFunc(f func(*Command) error) { c.usageFunc = f } -// Can be defined by Application +// SetUsageTemplate sets usage template. Can be defined by Application. func (c *Command) SetUsageTemplate(s string) { c.usageTemplate = s } -// Can be defined by Application +// SetFlagErrorFunc sets a function to generate an error when flag parsing +// fails. +func (c *Command) SetFlagErrorFunc(f func(*Command, error) error) { + c.flagErrorFunc = f +} + +// SetHelpFunc sets help function. Can be defined by Application. func (c *Command) SetHelpFunc(f func(*Command, []string)) { c.helpFunc = f } +// SetHelpCommand sets help command. func (c *Command) SetHelpCommand(cmd *Command) { c.helpCommand = cmd } -// Can be defined by Application +// SetHelpTemplate sets help template to be used. Application can use it to set custom template. func (c *Command) SetHelpTemplate(s string) { c.helpTemplate = s } @@ -176,17 +234,19 @@ func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string } } +// OutOrStdout returns output to stdout. func (c *Command) OutOrStdout() io.Writer { return c.getOut(os.Stdout) } +// OutOrStderr returns output to stderr 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 + return c.output } if c.HasParent() { return c.parent.getOut(def) @@ -195,14 +255,13 @@ func (c *Command) getOut(def io.Writer) io.Writer { } // UsageFunc returns either the function set by SetUsageFunc for this command -// or a parent, or it returns a default usage function +// 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 } - if c.HasParent() { - return c.parent.UsageFunc() + return c.Parent().UsageFunc() } return func(c *Command) error { c.mergePersistentFlags() @@ -214,24 +273,23 @@ func (c *Command) UsageFunc() (f func(*Command) error) { } } -// Output the usage for the command -// Used when a user provides invalid input -// Can be defined by user by overriding UsageFunc +// Usage puts out 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 with default help behavior +// or a parent, or it returns a function with default help behavior. func (c *Command) HelpFunc() func(*Command, []string) { - cmd := c - for cmd != nil { - if cmd.helpFunc != nil { - return cmd.helpFunc - } - cmd = cmd.parent + if c.helpFunc != nil { + return c.helpFunc } - return func(*Command, []string) { + if c.HasParent() { + return c.Parent().HelpFunc() + } + return func(c *Command, a []string) { c.mergePersistentFlags() err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c) if err != nil { @@ -240,14 +298,15 @@ func (c *Command) HelpFunc() func(*Command, []string) { } } -// Output the help for the command -// Used when a user calls help [command] -// Can be defined by user by overriding HelpFunc +// Help puts out 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 } +// UsageString return usage string. func (c *Command) UsageString() string { tmpOutput := c.output bb := new(bytes.Buffer) @@ -257,8 +316,25 @@ func (c *Command) UsageString() string { return bb.String() } +// FlagErrorFunc returns either the function set by SetFlagErrorFunc for this +// command or a parent, or it returns a function which returns the original +// error. +func (c *Command) FlagErrorFunc() (f func(*Command, error) error) { + if c.flagErrorFunc != nil { + return c.flagErrorFunc + } + + if c.HasParent() { + return c.parent.FlagErrorFunc() + } + return func(c *Command, err error) error { + return err + } +} + var minUsagePadding = 25 +// UsagePadding return padding for the usage. func (c *Command) UsagePadding() int { if c.parent == nil || minUsagePadding > c.parent.commandsMaxUseLen { return minUsagePadding @@ -268,7 +344,7 @@ func (c *Command) UsagePadding() int { var minCommandPathPadding = 11 -// +// CommandPathPadding return padding for the command path. func (c *Command) CommandPathPadding() int { if c.parent == nil || minCommandPathPadding > c.parent.commandsMaxCommandPathLen { return minCommandPathPadding @@ -278,6 +354,7 @@ func (c *Command) CommandPathPadding() int { var minNamePadding = 11 +// NamePadding returns padding for the name. func (c *Command) NamePadding() int { if c.parent == nil || minNamePadding > c.parent.commandsMaxNameLen { return minNamePadding @@ -285,6 +362,7 @@ func (c *Command) NamePadding() int { return c.parent.commandsMaxNameLen } +// UsageTemplate returns usage template for the command. func (c *Command) UsageTemplate() string { if c.usageTemplate != "" { return c.usageTemplate @@ -294,32 +372,32 @@ func (c *Command) UsageTemplate() string { return c.parent.UsageTemplate() } return `Usage:{{if .Runnable}} - {{if .HasAvailableFlags}}{{appendIfNotPresent .UseLine "[flags]"}}{{else}}{{.UseLine}}{{end}}{{end}}{{if .HasAvailableSubCommands}} - {{ .CommandPath}} [command]{{end}}{{if gt .Aliases 0}} + {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} + {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}} Aliases: - {{.NameAndAliases}} -{{end}}{{if .HasExample}} + {{.NameAndAliases}}{{end}}{{if .HasExample}} Examples: -{{ .Example }}{{end}}{{ if .HasAvailableSubCommands}} +{{.Example}}{{end}}{{if .HasAvailableSubCommands}} -Available Commands:{{range .Commands}}{{if .IsAvailableCommand}} - {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableLocalFlags}} +Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} + {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} Flags: -{{.LocalFlags.FlagUsages | trimRightSpace}}{{end}}{{ if .HasAvailableInheritedFlags}} +{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} Global Flags: -{{.InheritedFlags.FlagUsages | trimRightSpace}}{{end}}{{if .HasHelpSubCommands}} +{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} -Additional help topics:{{range .Commands}}{{if .IsHelpCommand}} - {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableSubCommands }} +Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} + {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} ` } +// HelpTemplate return help template for the command. func (c *Command) HelpTemplate() string { if c.helpTemplate != "" { return c.helpTemplate @@ -328,72 +406,60 @@ func (c *Command) HelpTemplate() string { if c.HasParent() { return c.parent.HelpTemplate() } - return `{{with or .Long .Short }}{{. | trim}} + return `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}} {{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` } -// Really only used when casting a command to a commander -func (c *Command) resetChildrensParents() { - for _, x := range c.commands { - x.parent = c - } -} - -// Test if the named flag is a boolean flag. -func isBooleanFlag(name string, f *flag.FlagSet) bool { - flag := f.Lookup(name) +func hasNoOptDefVal(name string, fs *flag.FlagSet) bool { + flag := fs.Lookup(name) if flag == nil { return false } - return flag.Value.Type() == "bool" + return flag.NoOptDefVal != "" } -// Test if the named flag is a boolean flag. -func isBooleanShortFlag(name string, f *flag.FlagSet) bool { - result := false - f.VisitAll(func(f *flag.Flag) { - if f.Shorthand == name && f.Value.Type() == "bool" { - result = true - } - }) - return result +func shortHasNoOptDefVal(name string, fs *flag.FlagSet) bool { + if len(name) == 0 { + return false + } + + flag := fs.ShorthandLookup(name[:1]) + if flag == nil { + return false + } + return flag.NoOptDefVal != "" } func stripFlags(args []string, c *Command) []string { - if len(args) < 1 { + if len(args) == 0 { return args } c.mergePersistentFlags() commands := []string{} + flags := c.Flags() - inQuote := false - inFlag := false - for _, y := range args { - if !inQuote { - switch { - case strings.HasPrefix(y, "\""): - inQuote = true - case strings.Contains(y, "=\""): - inQuote = true - case strings.HasPrefix(y, "--") && !strings.Contains(y, "="): - // TODO: this isn't quite right, we should really check ahead for 'true' or 'false' - inFlag = !isBooleanFlag(y[2:], c.Flags()) - case strings.HasPrefix(y, "-") && !strings.Contains(y, "=") && len(y) == 2 && !isBooleanShortFlag(y[1:], c.Flags()): - inFlag = true - case inFlag: - inFlag = false - case y == "": - // strip empty commands, as the go tests expect this to be ok.... - case !strings.HasPrefix(y, "-"): - commands = append(commands, y) - inFlag = false +Loop: + for len(args) > 0 { + s := args[0] + args = args[1:] + switch { + case strings.HasPrefix(s, "--") && !strings.Contains(s, "=") && !hasNoOptDefVal(s[2:], flags): + // If '--flag arg' then + // delete arg from args. + fallthrough // (do the same as below) + case strings.HasPrefix(s, "-") && !strings.Contains(s, "=") && len(s) == 2 && !shortHasNoOptDefVal(s[1:], flags): + // If '-f arg' then + // delete 'arg' from args or break the loop if len(args) <= 1. + if len(args) <= 1 { + break Loop + } else { + args = args[1:] + continue } - } - - if strings.HasSuffix(y, "\"") && !strings.HasSuffix(y, "\\\"") { - inQuote = false + case s != "" && !strings.HasPrefix(s, "-"): + commands = append(commands, s) } } @@ -414,13 +480,14 @@ func argsMinusFirstX(args []string, x string) []string { return args } -// find the target command given the args and command tree +func isFlagArg(arg string) bool { + return ((len(arg) >= 3 && arg[1] == '-') || + (len(arg) >= 2 && arg[0] == '-' && arg[1] != '-')) +} + +// Find the target command given the args and command tree // Meant to be run on the highest node. Only searches down. func (c *Command) Find(args []string) (*Command, []string, error) { - if c == nil { - return nil, nil, fmt.Errorf("Called find() on a nil Command") - } - var innerfind func(*Command, []string) (*Command, []string) innerfind = func(c *Command, innerArgs []string) (*Command, []string) { @@ -429,59 +496,99 @@ func (c *Command) Find(args []string) (*Command, []string, error) { return c, innerArgs } nextSubCmd := argsWOflags[0] - matches := make([]*Command, 0) - for _, cmd := range c.commands { - if cmd.Name() == nextSubCmd || cmd.HasAlias(nextSubCmd) { // exact name or alias match - return innerfind(cmd, argsMinusFirstX(innerArgs, nextSubCmd)) - } - if EnablePrefixMatching { - if strings.HasPrefix(cmd.Name(), nextSubCmd) { // prefix match - matches = append(matches, cmd) - } - for _, x := range cmd.Aliases { - if strings.HasPrefix(x, nextSubCmd) { - matches = append(matches, cmd) - } - } - } - } - // only accept a single prefix match - multiple matches would be ambiguous - if len(matches) == 1 { - return innerfind(matches[0], argsMinusFirstX(innerArgs, argsWOflags[0])) + cmd := c.findNext(nextSubCmd) + if cmd != nil { + return innerfind(cmd, argsMinusFirstX(innerArgs, nextSubCmd)) } - return c, innerArgs } commandFound, a := innerfind(c, args) - argsWOflags := stripFlags(a, commandFound) - - // no subcommand, always take args - if !commandFound.HasSubCommands() { - return commandFound, a, nil + if commandFound.Args == nil { + return commandFound, a, legacyArgs(commandFound, stripFlags(a, commandFound)) } - - // root command with subcommands, do subcommand checking - if commandFound == c && len(argsWOflags) > 0 { - 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) findSuggestions(arg string) string { + if c.DisableSuggestions { + return "" + } + if c.SuggestionsMinimumDistance <= 0 { + c.SuggestionsMinimumDistance = 2 + } + suggestionsString := "" + if suggestions := c.SuggestionsFor(arg); len(suggestions) > 0 { + suggestionsString += "\n\nDid you mean this?\n" + for _, s := range suggestions { + suggestionsString += fmt.Sprintf("\t%v\n", s) + } + } + return suggestionsString +} + +func (c *Command) findNext(next string) *Command { + matches := make([]*Command, 0) + for _, cmd := range c.commands { + if cmd.Name() == next || cmd.HasAlias(next) { + return cmd + } + if EnablePrefixMatching && cmd.hasNameOrAliasPrefix(next) { + matches = append(matches, cmd) + } + } + + if len(matches) == 1 { + return matches[0] + } + return nil +} + +// Traverse the command tree to find the command, and parse args for +// each parent. +func (c *Command) Traverse(args []string) (*Command, []string, error) { + flags := []string{} + inFlag := false + + for i, arg := range args { + switch { + // A long flag with a space separated value + case strings.HasPrefix(arg, "--") && !strings.Contains(arg, "="): + // TODO: this isn't quite right, we should really check ahead for 'true' or 'false' + inFlag = !hasNoOptDefVal(arg[2:], c.Flags()) + flags = append(flags, arg) + continue + // A short flag with a space separated value + case strings.HasPrefix(arg, "-") && !strings.Contains(arg, "=") && len(arg) == 2 && !shortHasNoOptDefVal(arg[1:], c.Flags()): + inFlag = true + flags = append(flags, arg) + continue + // The value for a flag + case inFlag: + inFlag = false + flags = append(flags, arg) + continue + // A flag without a value, or with an `=` separated value + case isFlagArg(arg): + flags = append(flags, arg) + continue + } + + cmd := c.findNext(arg) + if cmd == nil { + return c, args, nil + } + + if err := c.ParseFlags(flags); err != nil { + return nil, args, err + } + return cmd.Traverse(args[i+1:]) + } + return c, args, nil +} + +// SuggestionsFor provides suggestions for the typedName. func (c *Command) SuggestionsFor(typedName string) []string { suggestions := []string{} for _, cmd := range c.commands { @@ -502,38 +609,24 @@ func (c *Command) SuggestionsFor(typedName string) []string { return suggestions } +// VisitParents visits all parents of the command and invokes fn on each parent. 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 + if c.HasParent() { + fn(c.Parent()) + c.Parent().VisitParents(fn) } - traverse(c) } +// Root finds root command. func (c *Command) Root() *Command { - var findRoot func(*Command) *Command - - findRoot = func(x *Command) *Command { - if x.HasParent() { - return findRoot(x.parent) - } - return x + if c.HasParent() { + return c.Parent().Root() } - - return findRoot(c) + return 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). +// ArgsLenAtDash will return the length of c.Flags().Args at the moment +// when a -- was found during args parsing. func (c *Command) ArgsLenAtDash() int { return c.Flags().ArgsLenAtDash() } @@ -549,18 +642,19 @@ func (c *Command) execute(a []string) (err error) { // initialize help flag as the last point possible to allow for user // overriding - c.initHelpFlag() + c.InitDefaultHelpFlag() err = c.ParseFlags(a) if err != nil { - return err + return c.FlagErrorFunc()(c, err) } - // If help is called, regardless of other flags, return we want help + + // If help is called, regardless of other flags, return we want help. // Also say we need help if the command isn't runnable. helpVal, err := c.Flags().GetBool("help") if err != nil { // should be impossible to get here as we always declare a help - // flag in initHelpFlag() + // flag in InitDefaultHelpFlag() c.Println("\"help\" flag declared as non-bool. Please correct your code") return err } @@ -576,6 +670,10 @@ func (c *Command) execute(a []string) (err error) { argWoFlags = a } + if err := c.ValidateArgs(argWoFlags); err != nil { + return err + } + for p := c; p != nil; p = p.Parent() { if p.PersistentPreRunE != nil { if err := p.PersistentPreRunE(c, argWoFlags); err != nil { @@ -595,6 +693,9 @@ func (c *Command) execute(a []string) (err error) { c.PreRun(c, argWoFlags) } + if err := c.validateRequiredFlags(); err != nil { + return err + } if c.RunE != nil { if err := c.RunE(c, argWoFlags); err != nil { return err @@ -630,18 +731,7 @@ func (c *Command) preRun() { } } -func (c *Command) errorMsgFromParse() string { - s := c.flagErrorBuf.String() - - x := strings.Split(s, "\n") - - if len(x) > 0 { - return x[0] - } - return "" -} - -// Call execute to use the args (os.Args[1:] by default) +// Execute uses 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() error { @@ -649,8 +739,8 @@ func (c *Command) Execute() error { return err } +// ExecuteC executes the command. 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().ExecuteC() @@ -663,7 +753,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { // initialize help as the last point possible to allow for user // overriding - c.initHelpCmd() + c.InitDefaultHelpCmd() var args []string @@ -674,7 +764,12 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { args = c.args } - cmd, flags, err := c.Find(args) + var flags []string + if c.TraverseChildren { + cmd, flags, err = c.Traverse(args) + } else { + cmd, flags, err = c.Find(args) + } if err != nil { // If found parse to a subcommand and then failed, talk about the subcommand if cmd != nil { @@ -686,6 +781,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { } return c, err } + err = cmd.execute(flags) if err != nil { // Always show help if requested, even if SilenceErrors is in @@ -706,52 +802,92 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { if !cmd.SilenceUsage && !c.SilenceUsage { c.Println(cmd.UsageString()) } - return cmd, err } - return cmd, nil + return cmd, err } -func (c *Command) initHelpFlag() { - if c.Flags().Lookup("help") == nil { - c.Flags().BoolP("help", "h", false, "help for "+c.Name()) +func (c *Command) ValidateArgs(args []string) error { + if c.Args == nil { + return nil } + return c.Args(c, args) } -func (c *Command) initHelpCmd() { - if c.helpCommand == nil { - if !c.HasSubCommands() { +func (c *Command) validateRequiredFlags() error { + flags := c.Flags() + missingFlagNames := []string{} + flags.VisitAll(func(pflag *flag.Flag) { + requiredAnnotation, found := pflag.Annotations[BashCompOneRequiredFlag] + if !found { return } + if (requiredAnnotation[0] == "true") && !pflag.Changed { + missingFlagNames = append(missingFlagNames, pflag.Name) + } + }) + if len(missingFlagNames) > 0 { + return fmt.Errorf(`required flag(s) "%s" not set`, strings.Join(missingFlagNames, `", "`)) + } + return nil +} + +// InitDefaultHelpFlag adds default help flag to c. +// It is called automatically by executing the c or by calling help and usage. +// If c already has help flag, it will do nothing. +func (c *Command) InitDefaultHelpFlag() { + c.mergePersistentFlags() + if c.Flags().Lookup("help") == nil { + usage := "help for " + if c.Name() == "" { + usage += "this command" + } else { + usage += c.Name() + } + c.Flags().BoolP("help", "h", false, usage) + } +} + +// InitDefaultHelpCmd adds default help command to c. +// It is called automatically by executing the c or by calling help and usage. +// If c already has help command or c has no subcommands, it will do nothing. +func (c *Command) InitDefaultHelpCmd() { + if !c.HasSubCommands() { + return + } + + 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.`, - PersistentPreRun: func(cmd *Command, args []string) {}, - PersistentPostRun: func(cmd *Command, args []string) {}, +Simply type ` + c.Name() + ` help [path to command] for full details.`, Run: func(c *Command, args []string) { cmd, _, e := c.Root().Find(args) if cmd == nil || e != nil { - c.Printf("Unknown help topic %#q.", args) + c.Printf("Unknown help topic %#q\n", args) c.Root().Usage() } else { + cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown cmd.Help() } }, } } + c.RemoveCommand(c.helpCommand) c.AddCommand(c.helpCommand) } -// Used for testing +// ResetCommands delete parent, subcommand and help command from c. func (c *Command) ResetCommands() { + c.parent = nil c.commands = nil c.helpCommand = nil + c.parentsPflags = nil } -// Sorts commands by their names +// Sorts commands by their names. type commandSorterByName []*Command func (c commandSorterByName) Len() int { return len(c) } @@ -831,45 +967,48 @@ main: } } -// Print is a convenience method to Print to the defined output, fallback to Stderr if not set +// 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.OutOrStderr(), i...) } -// Println is a convenience method to Println to the defined output, fallback to Stderr if not set +// 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) + c.Print(fmt.Sprintln(i...)) } -// Printf is a convenience method to Printf to the defined output, fallback to Stderr if not set +// 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) + c.Print(fmt.Sprintf(format, i...)) } // CommandPath returns the full path to this command. func (c *Command) CommandPath() string { - str := c.Name() - x := c - for x.HasParent() { - str = x.parent.Name() + " " + str - x = x.parent - } - return str -} - -//The full usage for a given command (including parents) -func (c *Command) UseLine() string { - str := "" if c.HasParent() { - str = c.parent.CommandPath() + " " + return c.Parent().CommandPath() + " " + c.Name() } - return str + c.Use + return c.Name() } -// For use in determining which flags have been assigned to which commands -// and which persist +// UseLine puts out the full usage for a given command (including parents). +func (c *Command) UseLine() string { + var useline string + if c.HasParent() { + useline = c.parent.CommandPath() + " " + c.Use + } else { + useline = c.Use + } + if c.DisableFlagsInUseLine { + return useline + } + if c.HasAvailableFlags() && !strings.Contains(useline, "[flags]") { + useline += " [flags]" + } + return useline +} + +// DebugFlags used to determine which flags have been assigned to which commands +// and which persist. func (c *Command) DebugFlags() { c.Println("DebugFlags called on", c.Name()) var debugflags func(*Command) @@ -880,12 +1019,8 @@ func (c *Command) DebugFlags() { } if x.HasFlags() { x.flags.VisitAll(func(f *flag.Flag) { - if x.HasPersistentFlags() { - if x.persistentFlag(f.Name) == nil { - c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [L]") - } else { - c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [LP]") - } + if x.HasPersistentFlags() && x.persistentFlag(f.Name) != nil { + c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [LP]") } else { c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [L]") } @@ -915,9 +1050,6 @@ func (c *Command) DebugFlags() { // Name returns the command's name: the first word in the use line. func (c *Command) Name() string { - if c.name != "" { - return c.name - } name := c.Use i := strings.Index(name, " ") if i >= 0 { @@ -936,26 +1068,42 @@ func (c *Command) HasAlias(s string) bool { return false } +// hasNameOrAliasPrefix returns true if the Name or any of aliases start +// with prefix +func (c *Command) hasNameOrAliasPrefix(prefix string) bool { + if strings.HasPrefix(c.Name(), prefix) { + return true + } + for _, alias := range c.Aliases { + if strings.HasPrefix(alias, prefix) { + return true + } + } + return false +} + +// NameAndAliases returns a list of the command name and all aliases func (c *Command) NameAndAliases() string { return strings.Join(append([]string{c.Name()}, c.Aliases...), ", ") } +// HasExample determines if the command has example. func (c *Command) HasExample() bool { return len(c.Example) > 0 } -// Runnable determines 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 } -// HasSubCommands determines if the command has children commands +// HasSubCommands determines if the command has children commands. func (c *Command) HasSubCommands() bool { return len(c.commands) > 0 } // IsAvailableCommand determines if a command is available as a non-help command -// (this includes all non deprecated/hidden commands) +// (this includes all non deprecated/hidden commands). func (c *Command) IsAvailableCommand() bool { if len(c.Deprecated) != 0 || c.Hidden { return false @@ -972,11 +1120,12 @@ func (c *Command) IsAvailableCommand() bool { return false } -// IsHelpCommand determines if a command is a 'help' command; a help command is -// determined by the fact that it is NOT runnable/hidden/deprecated, and has no -// sub commands that are runnable/hidden/deprecated -func (c *Command) IsHelpCommand() bool { - +// IsAdditionalHelpTopicCommand determines if a command is an additional +// help topic command; additional help topic command is determined by the +// fact that it is NOT runnable/hidden/deprecated, and has no sub commands that +// are runnable/hidden/deprecated. +// Concrete example: https://github.com/spf13/cobra/issues/393#issuecomment-282741924. +func (c *Command) IsAdditionalHelpTopicCommand() bool { // if a command is runnable, deprecated, or hidden it is not a 'help' command if c.Runnable() || len(c.Deprecated) != 0 || c.Hidden { return false @@ -984,7 +1133,7 @@ func (c *Command) IsHelpCommand() bool { // if any non-help sub commands are found, the command is not a 'help' command for _, sub := range c.commands { - if !sub.IsHelpCommand() { + if !sub.IsAdditionalHelpTopicCommand() { return false } } @@ -993,14 +1142,13 @@ func (c *Command) IsHelpCommand() bool { return true } -// HasHelpSubCommands determines if a command has any avilable 'help' sub commands +// HasHelpSubCommands determines if a command has any available 'help' sub commands // that need to be shown in the usage/help default template under 'additional help -// topics' +// topics'. func (c *Command) HasHelpSubCommands() bool { - // return true on the first found available 'help' sub command for _, sub := range c.commands { - if sub.IsHelpCommand() { + if sub.IsAdditionalHelpTopicCommand() { return true } } @@ -1010,9 +1158,8 @@ func (c *Command) HasHelpSubCommands() bool { } // HasAvailableSubCommands determines if a command has available sub commands that -// need to be shown in the usage/help default template under 'available commands' +// need to be shown in the usage/help default template under 'available commands'. func (c *Command) HasAvailableSubCommands() bool { - // return true on the first found available (non deprecated/help/hidden) // sub command for _, sub := range c.commands { @@ -1021,22 +1168,23 @@ func (c *Command) HasAvailableSubCommands() bool { } } - // the command either has no sub comamnds, or no available (non deprecated/help/hidden) + // the command either has no sub commands, or no available (non deprecated/help/hidden) // sub commands return false } -// Determine if the command is a child command +// HasParent determines if the command is a child command. func (c *Command) HasParent() bool { return c.parent != nil } -// GlobalNormalizationFunc returns the global normalization function or nil if doesn't exists +// GlobalNormalizationFunc returns the global normalization function or nil if doesn't exists. func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) flag.NormalizedName { return c.globNormFunc } -// Get the complete FlagSet that applies to this command (local and persistent declared here and by all parents) +// Flags returns the complete FlagSet that applies +// to this command (local and persistent declared here and by all parents). func (c *Command) Flags() *flag.FlagSet { if c.flags == nil { c.flags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) @@ -1045,10 +1193,11 @@ func (c *Command) Flags() *flag.FlagSet { } c.flags.SetOutput(c.flagErrorBuf) } + return c.flags } -// LocalNonPersistentFlags are flags specific to this command which will NOT persist to subcommands +// LocalNonPersistentFlags are flags specific to this command which will NOT persist to subcommands. func (c *Command) LocalNonPersistentFlags() *flag.FlagSet { persistentFlags := c.PersistentFlags() @@ -1061,59 +1210,63 @@ func (c *Command) LocalNonPersistentFlags() *flag.FlagSet { return out } -// Get the local FlagSet specifically set in the current command +// LocalFlags returns the local FlagSet specifically set in the current command. func (c *Command) LocalFlags() *flag.FlagSet { c.mergePersistentFlags() - local := flag.NewFlagSet(c.Name(), flag.ContinueOnError) - c.lflags.VisitAll(func(f *flag.Flag) { - local.AddFlag(f) - }) - if !c.HasParent() { - flag.CommandLine.VisitAll(func(f *flag.Flag) { - if local.Lookup(f.Name) == nil { - local.AddFlag(f) - } - }) + if c.lflags == nil { + c.lflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + if c.flagErrorBuf == nil { + c.flagErrorBuf = new(bytes.Buffer) + } + c.lflags.SetOutput(c.flagErrorBuf) } - return local + c.lflags.SortFlags = c.Flags().SortFlags + if c.globNormFunc != nil { + c.lflags.SetNormalizeFunc(c.globNormFunc) + } + + addToLocal := func(f *flag.Flag) { + if c.lflags.Lookup(f.Name) == nil && c.parentsPflags.Lookup(f.Name) == nil { + c.lflags.AddFlag(f) + } + } + c.Flags().VisitAll(addToLocal) + c.PersistentFlags().VisitAll(addToLocal) + return c.lflags } -// All Flags which were inherited from parents commands +// InheritedFlags returns all flags which were inherited from parents commands. func (c *Command) InheritedFlags() *flag.FlagSet { c.mergePersistentFlags() - inherited := flag.NewFlagSet(c.Name(), flag.ContinueOnError) + if c.iflags == nil { + c.iflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + if c.flagErrorBuf == nil { + c.flagErrorBuf = new(bytes.Buffer) + } + c.iflags.SetOutput(c.flagErrorBuf) + } + local := c.LocalFlags() - - var rmerge func(x *Command) - - rmerge = func(x *Command) { - if x.HasPersistentFlags() { - x.PersistentFlags().VisitAll(func(f *flag.Flag) { - if inherited.Lookup(f.Name) == nil && local.Lookup(f.Name) == nil { - inherited.AddFlag(f) - } - }) - } - if x.HasParent() { - rmerge(x.parent) - } + if c.globNormFunc != nil { + c.iflags.SetNormalizeFunc(c.globNormFunc) } - if c.HasParent() { - rmerge(c.parent) - } - - return inherited + c.parentsPflags.VisitAll(func(f *flag.Flag) { + if c.iflags.Lookup(f.Name) == nil && local.Lookup(f.Name) == nil { + c.iflags.AddFlag(f) + } + }) + return c.iflags } -// All Flags which were not inherited from parent commands +// NonInheritedFlags returns all flags which were not inherited from parent commands. func (c *Command) NonInheritedFlags() *flag.FlagSet { return c.LocalFlags() } -// Get the Persistent FlagSet specifically set in the current command +// PersistentFlags returns the persistent FlagSet specifically set in the current command. func (c *Command) PersistentFlags() *flag.FlagSet { if c.pflags == nil { c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) @@ -1125,7 +1278,7 @@ func (c *Command) PersistentFlags() *flag.FlagSet { return c.pflags } -// For use in testing +// ResetFlags deletes all flags from command. func (c *Command) ResetFlags() { c.flagErrorBuf = new(bytes.Buffer) c.flagErrorBuf.Reset() @@ -1133,52 +1286,56 @@ func (c *Command) ResetFlags() { c.flags.SetOutput(c.flagErrorBuf) c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) c.pflags.SetOutput(c.flagErrorBuf) + + c.lflags = nil + c.iflags = nil + c.parentsPflags = nil } -// Does the command contain any flags (local plus persistent from the entire structure) +// HasFlags checks if the command contains any flags (local plus persistent from the entire structure). func (c *Command) HasFlags() bool { return c.Flags().HasFlags() } -// Does the command contain persistent flags +// HasPersistentFlags checks if the command contains persistent flags. func (c *Command) HasPersistentFlags() bool { return c.PersistentFlags().HasFlags() } -// Does the command has flags specifically declared locally +// HasLocalFlags checks if the command has flags specifically declared locally. func (c *Command) HasLocalFlags() bool { return c.LocalFlags().HasFlags() } -// Does the command have flags inherited from its parent command +// HasInheritedFlags checks if the command has flags inherited from its parent command. func (c *Command) HasInheritedFlags() bool { return c.InheritedFlags().HasFlags() } -// Does the command contain any flags (local plus persistent from the entire -// structure) which are not hidden or deprecated +// HasAvailableFlags checks if the command contains 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 +// HasAvailablePersistentFlags checks if the command contains 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 +// HasAvailableLocalFlags checks if 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 +// HasAvailableInheritedFlags checks if the command has 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 +// Flag climbs up the command tree looking for matching flag. func (c *Command) Flag(name string) (flag *flag.Flag) { flag = c.Flags().Lookup(name) @@ -1189,68 +1346,69 @@ func (c *Command) Flag(name string) (flag *flag.Flag) { return } -// recursively find matching persistent flag +// Recursively find matching persistent flag. func (c *Command) persistentFlag(name string) (flag *flag.Flag) { if c.HasPersistentFlags() { flag = c.PersistentFlags().Lookup(name) } - if flag == nil && c.HasParent() { - flag = c.parent.persistentFlag(name) + if flag == nil { + c.updateParentsPflags() + flag = c.parentsPflags.Lookup(name) } return } -// ParseFlags parses persistent flag tree & local flags -func (c *Command) ParseFlags(args []string) (err error) { +// ParseFlags parses persistent flag tree and local flags. +func (c *Command) ParseFlags(args []string) error { if c.DisableFlagParsing { return nil } + + if c.flagErrorBuf == nil { + c.flagErrorBuf = new(bytes.Buffer) + } + beforeErrorBufLen := c.flagErrorBuf.Len() c.mergePersistentFlags() - err = c.Flags().Parse(args) - return + err := c.Flags().Parse(args) + // Print warnings if they occurred (e.g. deprecated flag messages). + if c.flagErrorBuf.Len()-beforeErrorBufLen > 0 && err == nil { + c.Print(c.flagErrorBuf.String()) + } + + return err } -// Parent returns a commands parent command +// Parent returns a commands parent command. func (c *Command) Parent() *Command { return c.parent } +// mergePersistentFlags merges c.PersistentFlags() to c.Flags() +// and adds missing persistent flags of all parents. func (c *Command) mergePersistentFlags() { - var rmerge func(x *Command) - - // Save the set of local flags - if c.lflags == nil { - c.lflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) - if c.flagErrorBuf == nil { - c.flagErrorBuf = new(bytes.Buffer) - } - c.lflags.SetOutput(c.flagErrorBuf) - addtolocal := func(f *flag.Flag) { - c.lflags.AddFlag(f) - } - c.Flags().VisitAll(addtolocal) - c.PersistentFlags().VisitAll(addtolocal) - } - rmerge = func(x *Command) { - if !x.HasParent() { - flag.CommandLine.VisitAll(func(f *flag.Flag) { - if x.PersistentFlags().Lookup(f.Name) == nil { - x.PersistentFlags().AddFlag(f) - } - }) - } - if x.HasPersistentFlags() { - x.PersistentFlags().VisitAll(func(f *flag.Flag) { - if c.Flags().Lookup(f.Name) == nil { - c.Flags().AddFlag(f) - } - }) - } - if x.HasParent() { - rmerge(x.parent) - } - } - - rmerge(c) + c.updateParentsPflags() + c.Flags().AddFlagSet(c.PersistentFlags()) + c.Flags().AddFlagSet(c.parentsPflags) +} + +// updateParentsPflags updates c.parentsPflags by adding +// new persistent flags of all parents. +// If c.parentsPflags == nil, it makes new. +func (c *Command) updateParentsPflags() { + if c.parentsPflags == nil { + c.parentsPflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + c.parentsPflags.SetOutput(c.flagErrorBuf) + c.parentsPflags.SortFlags = false + } + + if c.globNormFunc != nil { + c.parentsPflags.SetNormalizeFunc(c.globNormFunc) + } + + c.Root().PersistentFlags().AddFlagSet(flag.CommandLine) + + c.VisitParents(func(parent *Command) { + c.parentsPflags.AddFlagSet(parent.PersistentFlags()) + }) } diff --git a/vendor/github.com/spf13/cobra/command_win.go b/vendor/github.com/spf13/cobra/command_win.go index 4b0eaa1b6bc..edec728e4f5 100644 --- a/vendor/github.com/spf13/cobra/command_win.go +++ b/vendor/github.com/spf13/cobra/command_win.go @@ -11,14 +11,8 @@ import ( 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() { + if MousetrapHelpText != "" && mousetrap.StartedByExplorer() { c.Print(MousetrapHelpText) time.Sleep(5 * time.Second) os.Exit(1) diff --git a/vendor/github.com/spf13/cobra/doc/BUILD b/vendor/github.com/spf13/cobra/doc/BUILD index 1820193cc00..52fbc08c1ef 100644 --- a/vendor/github.com/spf13/cobra/doc/BUILD +++ b/vendor/github.com/spf13/cobra/doc/BUILD @@ -5,7 +5,9 @@ go_library( srcs = [ "man_docs.go", "md_docs.go", + "rest_docs.go", "util.go", + "yaml_docs.go", ], importpath = "github.com/spf13/cobra/doc", visibility = ["//visibility:public"], @@ -13,6 +15,7 @@ go_library( "//vendor/github.com/cpuguy83/go-md2man/md2man:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library", "//vendor/github.com/spf13/pflag:go_default_library", + "//vendor/gopkg.in/yaml.v2:go_default_library", ], ) diff --git a/vendor/github.com/spf13/cobra/doc/man_docs.go b/vendor/github.com/spf13/cobra/doc/man_docs.go index b202029d1e0..ce92332dd17 100644 --- a/vendor/github.com/spf13/cobra/doc/man_docs.go +++ b/vendor/github.com/spf13/cobra/doc/man_docs.go @@ -23,21 +23,21 @@ import ( "strings" "time" - mangen "github.com/cpuguy83/go-md2man/md2man" + "github.com/cpuguy83/go-md2man/md2man" "github.com/spf13/cobra" "github.com/spf13/pflag" ) // GenManTree will generate a man page for this command and all descendants // in the directory given. The header may be nil. This function may not work -// 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` +// 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 GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error { return GenManTreeFromOpts(cmd, GenManTreeOptions{ Header: header, Path: dir, - CommandSeparator: "_", + CommandSeparator: "-", }) } @@ -49,7 +49,7 @@ func GenManTreeFromOpts(cmd *cobra.Command, opts GenManTreeOptions) error { header = &GenManHeader{} } for _, c := range cmd.Commands() { - if !c.IsAvailableCommand() || c.IsHelpCommand() { + if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { continue } if err := GenManTreeFromOpts(c, opts); err != nil { @@ -66,7 +66,7 @@ func GenManTreeFromOpts(cmd *cobra.Command, opts GenManTreeOptions) error { separator = opts.CommandSeparator } basename := strings.Replace(cmd.CommandPath(), " ", separator, -1) - filename := filepath.Join(opts.Path, basename + "." + section) + filename := filepath.Join(opts.Path, basename+"."+section) f, err := os.Create(filename) if err != nil { return err @@ -77,6 +77,8 @@ func GenManTreeFromOpts(cmd *cobra.Command, opts GenManTreeOptions) error { return GenMan(cmd, &headerCopy, f) } +// GenManTreeOptions is the options for generating the man pages. +// Used only in GenManTreeFromOpts. type GenManTreeOptions struct { Header *GenManHeader Path string @@ -105,7 +107,7 @@ func GenMan(cmd *cobra.Command, header *GenManHeader, w io.Writer) error { fillHeader(header, cmd.CommandPath()) b := genMan(cmd, header) - _, err := w.Write(mangen.Render(b)) + _, err := w.Write(md2man.Render(b)) return err } @@ -126,25 +128,25 @@ func fillHeader(header *GenManHeader, name string) { } } -func manPreamble(out io.Writer, header *GenManHeader, cmd *cobra.Command, dashedName string) { +func manPreamble(buf *bytes.Buffer, header *GenManHeader, cmd *cobra.Command, dashedName string) { description := cmd.Long if len(description) == 0 { description = cmd.Short } - fmt.Fprintf(out, `%% %s(%s)%s + buf.WriteString(fmt.Sprintf(`%% %s(%s)%s %% %s %% %s # NAME -`, header.Title, header.Section, header.date, header.Source, header.Manual) - fmt.Fprintf(out, "%s \\- %s\n\n", dashedName, cmd.Short) - fmt.Fprintf(out, "# SYNOPSIS\n") - fmt.Fprintf(out, "**%s**\n\n", cmd.UseLine()) - fmt.Fprintf(out, "# DESCRIPTION\n") - fmt.Fprintf(out, "%s\n\n", description) +`, header.Title, header.Section, header.date, header.Source, header.Manual)) + buf.WriteString(fmt.Sprintf("%s \\- %s\n\n", dashedName, cmd.Short)) + buf.WriteString("# SYNOPSIS\n") + buf.WriteString(fmt.Sprintf("**%s**\n\n", cmd.UseLine())) + buf.WriteString("# DESCRIPTION\n") + buf.WriteString(description + "\n\n") } -func manPrintFlags(out io.Writer, flags *pflag.FlagSet) { +func manPrintFlags(buf *bytes.Buffer, flags *pflag.FlagSet) { flags.VisitAll(func(flag *pflag.Flag) { if len(flag.Deprecated) > 0 || flag.Hidden { return @@ -156,38 +158,41 @@ func manPrintFlags(out io.Writer, flags *pflag.FlagSet) { format = fmt.Sprintf("**--%s**", flag.Name) } if len(flag.NoOptDefVal) > 0 { - format = format + "[" + format += "[" } if flag.Value.Type() == "string" { // put quotes on the value - format = format + "=%q" + format += "=%q" } else { - format = format + "=%s" + format += "=%s" } if len(flag.NoOptDefVal) > 0 { - format = format + "]" + format += "]" } - format = format + "\n\t%s\n\n" - fmt.Fprintf(out, format, flag.DefValue, flag.Usage) + format += "\n\t%s\n\n" + buf.WriteString(fmt.Sprintf(format, flag.DefValue, flag.Usage)) }) } -func manPrintOptions(out io.Writer, command *cobra.Command) { +func manPrintOptions(buf *bytes.Buffer, command *cobra.Command) { flags := command.NonInheritedFlags() if flags.HasFlags() { - fmt.Fprintf(out, "# OPTIONS\n") - manPrintFlags(out, flags) - fmt.Fprintf(out, "\n") + buf.WriteString("# OPTIONS\n") + manPrintFlags(buf, flags) + buf.WriteString("\n") } flags = command.InheritedFlags() if flags.HasFlags() { - fmt.Fprintf(out, "# OPTIONS INHERITED FROM PARENT COMMANDS\n") - manPrintFlags(out, flags) - fmt.Fprintf(out, "\n") + buf.WriteString("# OPTIONS INHERITED FROM PARENT COMMANDS\n") + manPrintFlags(buf, flags) + buf.WriteString("\n") } } func genMan(cmd *cobra.Command, header *GenManHeader) []byte { + cmd.InitDefaultHelpCmd() + cmd.InitDefaultHelpFlag() + // something like `rootcmd-subcmd1-subcmd2` dashCommandName := strings.Replace(cmd.CommandPath(), " ", "-", -1) @@ -196,11 +201,11 @@ func genMan(cmd *cobra.Command, header *GenManHeader) []byte { manPreamble(buf, header, cmd, dashCommandName) manPrintOptions(buf, cmd) if len(cmd.Example) > 0 { - fmt.Fprintf(buf, "# EXAMPLE\n") - fmt.Fprintf(buf, "```\n%s\n```\n", cmd.Example) + buf.WriteString("# EXAMPLE\n") + buf.WriteString(fmt.Sprintf("```\n%s\n```\n", cmd.Example)) } if hasSeeAlso(cmd) { - fmt.Fprintf(buf, "# SEE ALSO\n") + buf.WriteString("# SEE ALSO\n") seealsos := make([]string, 0) if cmd.HasParent() { parentPath := cmd.Parent().CommandPath() @@ -216,16 +221,16 @@ func genMan(cmd *cobra.Command, header *GenManHeader) []byte { children := cmd.Commands() sort.Sort(byName(children)) for _, c := range children { - if !c.IsAvailableCommand() || c.IsHelpCommand() { + if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { continue } seealso := fmt.Sprintf("**%s-%s(%s)**", dashCommandName, c.Name(), header.Section) seealsos = append(seealsos, seealso) } - fmt.Fprintf(buf, "%s\n", strings.Join(seealsos, ", ")) + buf.WriteString(strings.Join(seealsos, ", ") + "\n") } if !cmd.DisableAutoGenTag { - fmt.Fprintf(buf, "# HISTORY\n%s Auto generated by spf13/cobra\n", header.Date.Format("2-Jan-2006")) + buf.WriteString(fmt.Sprintf("# HISTORY\n%s Auto generated by spf13/cobra\n", header.Date.Format("2-Jan-2006"))) } return buf.Bytes() } diff --git a/vendor/github.com/spf13/cobra/doc/man_docs.md b/vendor/github.com/spf13/cobra/doc/man_docs.md index 5fe957a3558..3709160f34f 100644 --- a/vendor/github.com/spf13/cobra/doc/man_docs.md +++ b/vendor/github.com/spf13/cobra/doc/man_docs.md @@ -6,6 +6,8 @@ Generating man pages from a cobra command is incredibly easy. An example is as f package main import ( + "log" + "github.com/spf13/cobra" "github.com/spf13/cobra/doc" ) @@ -15,12 +17,15 @@ func main() { Use: "test", Short: "my test program", } - header := &cobra.GenManHeader{ + header := &doc.GenManHeader{ Title: "MINE", Section: "3", } - doc.GenManTree(cmd, header, "/tmp") + err := doc.GenManTree(cmd, header, "/tmp") + if err != nil { + log.Fatal(err) + } } ``` -That will get you a man page `/tmp/test.1` +That will get you a man page `/tmp/test.3` diff --git a/vendor/github.com/spf13/cobra/doc/md_docs.go b/vendor/github.com/spf13/cobra/doc/md_docs.go index fa136318049..68cf5bf6487 100644 --- a/vendor/github.com/spf13/cobra/doc/md_docs.go +++ b/vendor/github.com/spf13/cobra/doc/md_docs.go @@ -14,6 +14,7 @@ package doc import ( + "bytes" "fmt" "io" "os" @@ -25,38 +26,36 @@ import ( "github.com/spf13/cobra" ) -func printOptions(w io.Writer, cmd *cobra.Command, name string) error { +func printOptions(buf *bytes.Buffer, cmd *cobra.Command, name string) error { flags := cmd.NonInheritedFlags() - flags.SetOutput(w) + flags.SetOutput(buf) if flags.HasFlags() { - if _, err := fmt.Fprintf(w, "### Options\n\n```\n"); err != nil { - return err - } + buf.WriteString("### Options\n\n```\n") flags.PrintDefaults() - if _, err := fmt.Fprintf(w, "```\n\n"); err != nil { - return err - } + buf.WriteString("```\n\n") } parentFlags := cmd.InheritedFlags() - parentFlags.SetOutput(w) + parentFlags.SetOutput(buf) if parentFlags.HasFlags() { - if _, err := fmt.Fprintf(w, "### Options inherited from parent commands\n\n```\n"); err != nil { - return err - } + buf.WriteString("### Options inherited from parent commands\n\n```\n") parentFlags.PrintDefaults() - if _, err := fmt.Fprintf(w, "```\n\n"); err != nil { - return err - } + buf.WriteString("```\n\n") } return nil } +// GenMarkdown creates markdown output. func GenMarkdown(cmd *cobra.Command, w io.Writer) error { return GenMarkdownCustom(cmd, w, func(s string) string { return s }) } +// GenMarkdownCustom creates custom markdown output. func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) string) error { + cmd.InitDefaultHelpCmd() + cmd.InitDefaultHelpFlag() + + buf := new(bytes.Buffer) name := cmd.CommandPath() short := cmd.Short @@ -65,49 +64,31 @@ func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) long = short } - if _, err := fmt.Fprintf(w, "## %s\n\n", name); err != nil { - return err - } - if _, err := fmt.Fprintf(w, "%s\n\n", short); err != nil { - return err - } - if _, err := fmt.Fprintf(w, "### Synopsis\n\n"); err != nil { - return err - } - if _, err := fmt.Fprintf(w, "\n%s\n\n", long); err != nil { - return err - } + buf.WriteString("## " + name + "\n\n") + buf.WriteString(short + "\n\n") + buf.WriteString("### Synopsis\n\n") + buf.WriteString("\n" + long + "\n\n") if cmd.Runnable() { - if _, err := fmt.Fprintf(w, "```\n%s\n```\n\n", cmd.UseLine()); err != nil { - return err - } + buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.UseLine())) } if len(cmd.Example) > 0 { - if _, err := fmt.Fprintf(w, "### Examples\n\n"); err != nil { - return err - } - if _, err := fmt.Fprintf(w, "```\n%s\n```\n\n", cmd.Example); err != nil { - return err - } + buf.WriteString("### Examples\n\n") + buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.Example)) } - if err := printOptions(w, cmd, name); err != nil { + if err := printOptions(buf, cmd, name); err != nil { return err } if hasSeeAlso(cmd) { - if _, err := fmt.Fprintf(w, "### SEE ALSO\n"); err != nil { - return err - } + buf.WriteString("### SEE ALSO\n") if cmd.HasParent() { parent := cmd.Parent() pname := parent.CommandPath() link := pname + ".md" link = strings.Replace(link, " ", "_", -1) - if _, err := fmt.Fprintf(w, "* [%s](%s)\t - %s\n", pname, linkHandler(link), parent.Short); err != nil { - return err - } + buf.WriteString(fmt.Sprintf("* [%s](%s)\t - %s\n", pname, linkHandler(link), parent.Short)) cmd.VisitParents(func(c *cobra.Command) { if c.DisableAutoGenTag { cmd.DisableAutoGenTag = c.DisableAutoGenTag @@ -119,37 +100,40 @@ func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) sort.Sort(byName(children)) for _, child := range children { - if !child.IsAvailableCommand() || child.IsHelpCommand() { + if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() { continue } cname := name + " " + child.Name() link := cname + ".md" link = strings.Replace(link, " ", "_", -1) - if _, err := fmt.Fprintf(w, "* [%s](%s)\t - %s\n", cname, linkHandler(link), child.Short); err != nil { - return err - } - } - if _, err := fmt.Fprintf(w, "\n"); err != nil { - return err + buf.WriteString(fmt.Sprintf("* [%s](%s)\t - %s\n", cname, linkHandler(link), child.Short)) } + buf.WriteString("\n") } if !cmd.DisableAutoGenTag { - if _, err := fmt.Fprintf(w, "###### Auto generated by spf13/cobra on %s\n", time.Now().Format("2-Jan-2006")); err != nil { - return err - } + buf.WriteString("###### Auto generated by spf13/cobra on " + time.Now().Format("2-Jan-2006") + "\n") } - return nil + _, err := buf.WriteTo(w) + return err } +// GenMarkdownTree will generate a markdown page for this command and all +// descendants in the directory given. The header may be nil. +// This function may not work correctly if your command names have `-` in them. +// If you have `cmd` with two subcmds, `sub` and `sub-third`, +// and `sub` has a subcommand called `third`, it is undefined which +// help output will be in the file `cmd-sub-third.1`. func GenMarkdownTree(cmd *cobra.Command, dir string) error { identity := func(s string) string { return s } emptyStr := func(s string) string { return "" } return GenMarkdownTreeCustom(cmd, dir, emptyStr, identity) } +// GenMarkdownTreeCustom is the the same as GenMarkdownTree, but +// with custom filePrepender and linkHandler. func GenMarkdownTreeCustom(cmd *cobra.Command, dir string, filePrepender, linkHandler func(string) string) error { for _, c := range cmd.Commands() { - if !c.IsAvailableCommand() || c.IsHelpCommand() { + if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { continue } if err := GenMarkdownTreeCustom(c, dir, filePrepender, linkHandler); err != nil { diff --git a/vendor/github.com/spf13/cobra/doc/md_docs.md b/vendor/github.com/spf13/cobra/doc/md_docs.md index 0c3b96e2718..56ce9fe819e 100644 --- a/vendor/github.com/spf13/cobra/doc/md_docs.md +++ b/vendor/github.com/spf13/cobra/doc/md_docs.md @@ -6,6 +6,8 @@ Generating man pages from a cobra command is incredibly easy. An example is as f package main import ( + "log" + "github.com/spf13/cobra" "github.com/spf13/cobra/doc" ) @@ -15,7 +17,10 @@ func main() { Use: "test", Short: "my test program", } - doc.GenMarkdownTree(cmd, "/tmp") + err := doc.GenMarkdownTree(cmd, "/tmp") + if err != nil { + log.Fatal(err) + } } ``` @@ -29,18 +34,22 @@ This program can actually generate docs for the kubectl command in the kubernete package main import ( + "log" "io/ioutil" "os" - kubectlcmd "k8s.io/kubernetes/pkg/kubectl/cmd" + "k8s.io/kubernetes/pkg/kubectl/cmd" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "github.com/spf13/cobra/doc" ) func main() { - cmd := kubectlcmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard) - doc.GenMarkdownTree(cmd, "./") + kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard) + err := doc.GenMarkdownTree(kubectl, "./") + if err != nil { + log.Fatal(err) + } } ``` @@ -52,7 +61,10 @@ You may wish to have more control over the output, or only generate for a single ```go out := new(bytes.Buffer) - doc.GenMarkdown(cmd, out) + err := doc.GenMarkdown(cmd, out) + if err != nil { + log.Fatal(err) + } ``` This will write the markdown doc for ONLY "cmd" into the out, buffer. @@ -101,4 +113,3 @@ linkHandler := func(name string) string { return "/commands/" + strings.ToLower(base) + "/" } ``` - diff --git a/vendor/github.com/spf13/cobra/doc/rest_docs.go b/vendor/github.com/spf13/cobra/doc/rest_docs.go new file mode 100644 index 00000000000..4913e3ee2ea --- /dev/null +++ b/vendor/github.com/spf13/cobra/doc/rest_docs.go @@ -0,0 +1,185 @@ +//Copyright 2015 Red Hat Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package doc + +import ( + "bytes" + "fmt" + "io" + "os" + "path/filepath" + "sort" + "strings" + "time" + + "github.com/spf13/cobra" +) + +func printOptionsReST(buf *bytes.Buffer, cmd *cobra.Command, name string) error { + flags := cmd.NonInheritedFlags() + flags.SetOutput(buf) + if flags.HasFlags() { + buf.WriteString("Options\n") + buf.WriteString("~~~~~~~\n\n::\n\n") + flags.PrintDefaults() + buf.WriteString("\n") + } + + parentFlags := cmd.InheritedFlags() + parentFlags.SetOutput(buf) + if parentFlags.HasFlags() { + buf.WriteString("Options inherited from parent commands\n") + buf.WriteString("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n") + parentFlags.PrintDefaults() + buf.WriteString("\n") + } + return nil +} + +// linkHandler for default ReST hyperlink markup +func defaultLinkHandler(name, ref string) string { + return fmt.Sprintf("`%s <%s.rst>`_", name, ref) +} + +// GenReST creates reStructured Text output. +func GenReST(cmd *cobra.Command, w io.Writer) error { + return GenReSTCustom(cmd, w, defaultLinkHandler) +} + +// GenReSTCustom creates custom reStructured Text output. +func GenReSTCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string, string) string) error { + cmd.InitDefaultHelpCmd() + cmd.InitDefaultHelpFlag() + + buf := new(bytes.Buffer) + name := cmd.CommandPath() + + short := cmd.Short + long := cmd.Long + if len(long) == 0 { + long = short + } + ref := strings.Replace(name, " ", "_", -1) + + buf.WriteString(".. _" + ref + ":\n\n") + buf.WriteString(name + "\n") + buf.WriteString(strings.Repeat("-", len(name)) + "\n\n") + buf.WriteString(short + "\n\n") + buf.WriteString("Synopsis\n") + buf.WriteString("~~~~~~~~\n\n") + buf.WriteString("\n" + long + "\n\n") + + if cmd.Runnable() { + buf.WriteString(fmt.Sprintf("::\n\n %s\n\n", cmd.UseLine())) + } + + if len(cmd.Example) > 0 { + buf.WriteString("Examples\n") + buf.WriteString("~~~~~~~~\n\n") + buf.WriteString(fmt.Sprintf("::\n\n%s\n\n", indentString(cmd.Example, " "))) + } + + if err := printOptionsReST(buf, cmd, name); err != nil { + return err + } + if hasSeeAlso(cmd) { + buf.WriteString("SEE ALSO\n") + buf.WriteString("~~~~~~~~\n\n") + if cmd.HasParent() { + parent := cmd.Parent() + pname := parent.CommandPath() + ref = strings.Replace(pname, " ", "_", -1) + buf.WriteString(fmt.Sprintf("* %s \t - %s\n", linkHandler(pname, ref), parent.Short)) + cmd.VisitParents(func(c *cobra.Command) { + if c.DisableAutoGenTag { + cmd.DisableAutoGenTag = c.DisableAutoGenTag + } + }) + } + + children := cmd.Commands() + sort.Sort(byName(children)) + + for _, child := range children { + if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() { + continue + } + cname := name + " " + child.Name() + ref = strings.Replace(cname, " ", "_", -1) + buf.WriteString(fmt.Sprintf("* %s \t - %s\n", linkHandler(cname, ref), child.Short)) + } + buf.WriteString("\n") + } + if !cmd.DisableAutoGenTag { + buf.WriteString("*Auto generated by spf13/cobra on " + time.Now().Format("2-Jan-2006") + "*\n") + } + _, err := buf.WriteTo(w) + return err +} + +// GenReSTTree will generate a ReST page for this command and all +// descendants in the directory given. +// This function may not work correctly if your command names have `-` in them. +// If you have `cmd` with two subcmds, `sub` and `sub-third`, +// and `sub` has a subcommand called `third`, it is undefined which +// help output will be in the file `cmd-sub-third.1`. +func GenReSTTree(cmd *cobra.Command, dir string) error { + emptyStr := func(s string) string { return "" } + return GenReSTTreeCustom(cmd, dir, emptyStr, defaultLinkHandler) +} + +// GenReSTTreeCustom is the the same as GenReSTTree, but +// with custom filePrepender and linkHandler. +func GenReSTTreeCustom(cmd *cobra.Command, dir string, filePrepender func(string) string, linkHandler func(string, string) string) error { + for _, c := range cmd.Commands() { + if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { + continue + } + if err := GenReSTTreeCustom(c, dir, filePrepender, linkHandler); err != nil { + return err + } + } + + basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + ".rst" + filename := filepath.Join(dir, basename) + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + + if _, err := io.WriteString(f, filePrepender(filename)); err != nil { + return err + } + if err := GenReSTCustom(cmd, f, linkHandler); err != nil { + return err + } + return nil +} + +// adapted from: https://github.com/kr/text/blob/main/indent.go +func indentString(s, p string) string { + var res []byte + b := []byte(s) + prefix := []byte(p) + bol := true + for _, c := range b { + if bol && c != '\n' { + res = append(res, prefix...) + } + res = append(res, c) + bol = c == '\n' + } + return string(res) +} diff --git a/vendor/github.com/spf13/cobra/doc/rest_docs.md b/vendor/github.com/spf13/cobra/doc/rest_docs.md new file mode 100644 index 00000000000..6098430eff6 --- /dev/null +++ b/vendor/github.com/spf13/cobra/doc/rest_docs.md @@ -0,0 +1,114 @@ +# Generating ReStructured Text Docs For Your Own cobra.Command + +Generating ReST pages from a cobra command is incredibly easy. An example is as follows: + +```go +package main + +import ( + "log" + + "github.com/spf13/cobra" + "github.com/spf13/cobra/doc" +) + +func main() { + cmd := &cobra.Command{ + Use: "test", + Short: "my test program", + } + err := doc.GenReSTTree(cmd, "/tmp") + if err != nil { + log.Fatal(err) + } +} +``` + +That will get you a ReST document `/tmp/test.rst` + +## Generate ReST docs for the entire command tree + +This program can actually generate docs for the kubectl command in the kubernetes project + +```go +package main + +import ( + "log" + "io/ioutil" + "os" + + "k8s.io/kubernetes/pkg/kubectl/cmd" + cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" + + "github.com/spf13/cobra/doc" +) + +func main() { + kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard) + err := doc.GenReSTTree(kubectl, "./") + if err != nil { + log.Fatal(err) + } +} +``` + +This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case "./") + +## Generate ReST 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 `GenReST` instead of `GenReSTTree` + +```go + out := new(bytes.Buffer) + err := doc.GenReST(cmd, out) + if err != nil { + log.Fatal(err) + } +``` + +This will write the ReST doc for ONLY "cmd" into the out, buffer. + +## Customize the output + +Both `GenReST` and `GenReSTTree` have alternate versions with callbacks to get some control of the output: + +```go +func GenReSTTreeCustom(cmd *Command, dir string, filePrepender func(string) string, linkHandler func(string, string) string) error { + //... +} +``` + +```go +func GenReSTCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string, string) string) error { + //... +} +``` + +The `filePrepender` will prepend the return value given the full filepath to the rendered ReST 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 links to the commands, given a command name and reference. This is useful while converting rst to html or while generating documentation with tools like Sphinx where `:ref:` is used: + +```go +// Sphinx cross-referencing format +linkHandler := func(name, ref string) string { + return fmt.Sprintf(":ref:`%s <%s>`", name, ref) +} +``` diff --git a/vendor/github.com/spf13/cobra/doc/util.go b/vendor/github.com/spf13/cobra/doc/util.go index a1c6b89ba6c..8d3dbecec82 100644 --- a/vendor/github.com/spf13/cobra/doc/util.go +++ b/vendor/github.com/spf13/cobra/doc/util.go @@ -13,7 +13,11 @@ package doc -import "github.com/spf13/cobra" +import ( + "strings" + + "github.com/spf13/cobra" +) // Test to see if we have a reason to print See Also information in docs // Basically this is a test for a parent commend or a subcommand which is @@ -23,7 +27,7 @@ func hasSeeAlso(cmd *cobra.Command) bool { return true } for _, c := range cmd.Commands() { - if !c.IsAvailableCommand() || c.IsHelpCommand() { + if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { continue } return true @@ -31,6 +35,15 @@ func hasSeeAlso(cmd *cobra.Command) bool { return false } +// Temporary workaround for yaml lib generating incorrect yaml with long strings +// that do not contain \n. +func forceMultiLine(s string) string { + if len(s) > 60 && !strings.Contains(s, "\n") { + s = s + "\n" + } + return s +} + type byName []*cobra.Command func (s byName) Len() int { return len(s) } diff --git a/vendor/github.com/spf13/cobra/doc/yaml_docs.go b/vendor/github.com/spf13/cobra/doc/yaml_docs.go new file mode 100644 index 00000000000..ea00af07e81 --- /dev/null +++ b/vendor/github.com/spf13/cobra/doc/yaml_docs.go @@ -0,0 +1,169 @@ +// Copyright 2016 French Ben. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package doc + +import ( + "fmt" + "io" + "os" + "path/filepath" + "sort" + "strings" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "gopkg.in/yaml.v2" +) + +type cmdOption struct { + Name string + Shorthand string `yaml:",omitempty"` + DefaultValue string `yaml:"default_value,omitempty"` + Usage string `yaml:",omitempty"` +} + +type cmdDoc struct { + Name string + Synopsis string `yaml:",omitempty"` + Description string `yaml:",omitempty"` + Options []cmdOption `yaml:",omitempty"` + InheritedOptions []cmdOption `yaml:"inherited_options,omitempty"` + Example string `yaml:",omitempty"` + SeeAlso []string `yaml:"see_also,omitempty"` +} + +// GenYamlTree creates yaml structured ref files for this command and all descendants +// in the directory given. This function may not work +// correctly if your command names have `-` in them. If you have `cmd` with two +// subcmds, `sub` and `sub-third`, and `sub` has a subcommand called `third` +// it is undefined which help output will be in the file `cmd-sub-third.1`. +func GenYamlTree(cmd *cobra.Command, dir string) error { + identity := func(s string) string { return s } + emptyStr := func(s string) string { return "" } + return GenYamlTreeCustom(cmd, dir, emptyStr, identity) +} + +// GenYamlTreeCustom creates yaml structured ref files. +func GenYamlTreeCustom(cmd *cobra.Command, dir string, filePrepender, linkHandler func(string) string) error { + for _, c := range cmd.Commands() { + if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { + continue + } + if err := GenYamlTreeCustom(c, dir, filePrepender, linkHandler); err != nil { + return err + } + } + + basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + ".yaml" + filename := filepath.Join(dir, basename) + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + + if _, err := io.WriteString(f, filePrepender(filename)); err != nil { + return err + } + if err := GenYamlCustom(cmd, f, linkHandler); err != nil { + return err + } + return nil +} + +// GenYaml creates yaml output. +func GenYaml(cmd *cobra.Command, w io.Writer) error { + return GenYamlCustom(cmd, w, func(s string) string { return s }) +} + +// GenYamlCustom creates custom yaml output. +func GenYamlCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) string) error { + cmd.InitDefaultHelpCmd() + cmd.InitDefaultHelpFlag() + + yamlDoc := cmdDoc{} + yamlDoc.Name = cmd.CommandPath() + + yamlDoc.Synopsis = forceMultiLine(cmd.Short) + yamlDoc.Description = forceMultiLine(cmd.Long) + + if len(cmd.Example) > 0 { + yamlDoc.Example = cmd.Example + } + + flags := cmd.NonInheritedFlags() + if flags.HasFlags() { + yamlDoc.Options = genFlagResult(flags) + } + flags = cmd.InheritedFlags() + if flags.HasFlags() { + yamlDoc.InheritedOptions = genFlagResult(flags) + } + + if hasSeeAlso(cmd) { + result := []string{} + if cmd.HasParent() { + parent := cmd.Parent() + result = append(result, parent.CommandPath()+" - "+parent.Short) + } + children := cmd.Commands() + sort.Sort(byName(children)) + for _, child := range children { + if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() { + continue + } + result = append(result, child.Name()+" - "+child.Short) + } + yamlDoc.SeeAlso = result + } + + final, err := yaml.Marshal(&yamlDoc) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + if _, err := w.Write(final); err != nil { + return err + } + return nil +} + +func genFlagResult(flags *pflag.FlagSet) []cmdOption { + var result []cmdOption + + flags.VisitAll(func(flag *pflag.Flag) { + // Todo, when we mark a shorthand is deprecated, but specify an empty message. + // The flag.ShorthandDeprecated is empty as the shorthand is deprecated. + // Using len(flag.ShorthandDeprecated) > 0 can't handle this, others are ok. + if !(len(flag.ShorthandDeprecated) > 0) && len(flag.Shorthand) > 0 { + opt := cmdOption{ + flag.Name, + flag.Shorthand, + flag.DefValue, + forceMultiLine(flag.Usage), + } + result = append(result, opt) + } else { + opt := cmdOption{ + Name: flag.Name, + DefaultValue: forceMultiLine(flag.DefValue), + Usage: forceMultiLine(flag.Usage), + } + result = append(result, opt) + } + }) + + return result +} diff --git a/vendor/github.com/spf13/cobra/doc/yaml_docs.md b/vendor/github.com/spf13/cobra/doc/yaml_docs.md new file mode 100644 index 00000000000..1a9b7c6a3c9 --- /dev/null +++ b/vendor/github.com/spf13/cobra/doc/yaml_docs.md @@ -0,0 +1,112 @@ +# Generating Yaml Docs For Your Own cobra.Command + +Generating yaml files from a cobra command is incredibly easy. An example is as follows: + +```go +package main + +import ( + "log" + + "github.com/spf13/cobra" + "github.com/spf13/cobra/doc" +) + +func main() { + cmd := &cobra.Command{ + Use: "test", + Short: "my test program", + } + err := doc.GenYamlTree(cmd, "/tmp") + if err != nil { + log.Fatal(err) + } +} +``` + +That will get you a Yaml document `/tmp/test.yaml` + +## Generate yaml 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" + "log" + "os" + + "k8s.io/kubernetes/pkg/kubectl/cmd" + cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" + + "github.com/spf13/cobra/doc" +) + +func main() { + kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard) + err := doc.GenYamlTree(kubectl, "./") + if err != nil { + log.Fatal(err) + } +} +``` + +This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case "./") + +## Generate yaml 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 `GenYaml` instead of `GenYamlTree` + +```go + out := new(bytes.Buffer) + doc.GenYaml(cmd, out) +``` + +This will write the yaml doc for ONLY "cmd" into the out, buffer. + +## Customize the output + +Both `GenYaml` and `GenYamlTree` have alternate versions with callbacks to get some control of the output: + +```go +func GenYamlTreeCustom(cmd *Command, dir string, filePrepender, linkHandler func(string) string) error { + //... +} +``` + +```go +func GenYamlCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string) string) error { + //... +} +``` + +The `filePrepender` will prepend the return value given the full filepath to the rendered Yaml 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/cobra/zsh_completions.go b/vendor/github.com/spf13/cobra/zsh_completions.go new file mode 100644 index 00000000000..889c22e273c --- /dev/null +++ b/vendor/github.com/spf13/cobra/zsh_completions.go @@ -0,0 +1,126 @@ +package cobra + +import ( + "bytes" + "fmt" + "io" + "os" + "strings" +) + +// GenZshCompletionFile generates zsh completion file. +func (c *Command) GenZshCompletionFile(filename string) error { + outFile, err := os.Create(filename) + if err != nil { + return err + } + defer outFile.Close() + + return c.GenZshCompletion(outFile) +} + +// GenZshCompletion generates a zsh completion file and writes to the passed writer. +func (c *Command) GenZshCompletion(w io.Writer) error { + buf := new(bytes.Buffer) + + writeHeader(buf, c) + maxDepth := maxDepth(c) + writeLevelMapping(buf, maxDepth) + writeLevelCases(buf, maxDepth, c) + + _, err := buf.WriteTo(w) + return err +} + +func writeHeader(w io.Writer, cmd *Command) { + fmt.Fprintf(w, "#compdef %s\n\n", cmd.Name()) +} + +func maxDepth(c *Command) int { + if len(c.Commands()) == 0 { + return 0 + } + maxDepthSub := 0 + for _, s := range c.Commands() { + subDepth := maxDepth(s) + if subDepth > maxDepthSub { + maxDepthSub = subDepth + } + } + return 1 + maxDepthSub +} + +func writeLevelMapping(w io.Writer, numLevels int) { + fmt.Fprintln(w, `_arguments \`) + for i := 1; i <= numLevels; i++ { + fmt.Fprintf(w, ` '%d: :->level%d' \`, i, i) + fmt.Fprintln(w) + } + fmt.Fprintf(w, ` '%d: :%s'`, numLevels+1, "_files") + fmt.Fprintln(w) +} + +func writeLevelCases(w io.Writer, maxDepth int, root *Command) { + fmt.Fprintln(w, "case $state in") + defer fmt.Fprintln(w, "esac") + + for i := 1; i <= maxDepth; i++ { + fmt.Fprintf(w, " level%d)\n", i) + writeLevel(w, root, i) + fmt.Fprintln(w, " ;;") + } + fmt.Fprintln(w, " *)") + fmt.Fprintln(w, " _arguments '*: :_files'") + fmt.Fprintln(w, " ;;") +} + +func writeLevel(w io.Writer, root *Command, i int) { + fmt.Fprintf(w, " case $words[%d] in\n", i) + defer fmt.Fprintln(w, " esac") + + commands := filterByLevel(root, i) + byParent := groupByParent(commands) + + for p, c := range byParent { + names := names(c) + fmt.Fprintf(w, " %s)\n", p) + fmt.Fprintf(w, " _arguments '%d: :(%s)'\n", i, strings.Join(names, " ")) + fmt.Fprintln(w, " ;;") + } + fmt.Fprintln(w, " *)") + fmt.Fprintln(w, " _arguments '*: :_files'") + fmt.Fprintln(w, " ;;") + +} + +func filterByLevel(c *Command, l int) []*Command { + cs := make([]*Command, 0) + if l == 0 { + cs = append(cs, c) + return cs + } + for _, s := range c.Commands() { + cs = append(cs, filterByLevel(s, l-1)...) + } + return cs +} + +func groupByParent(commands []*Command) map[string][]*Command { + m := make(map[string][]*Command) + for _, c := range commands { + parent := c.Parent() + if parent == nil { + continue + } + m[parent.Name()] = append(m[parent.Name()], c) + } + return m +} + +func names(commands []*Command) []string { + ns := make([]string, len(commands)) + for i, c := range commands { + ns[i] = c.Name() + } + return ns +}