diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 59e62915e5b..866031536e6 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -307,6 +307,10 @@ "Comment": "0.1.3-8-g6633656", "Rev": "6633656539c1639d9d78127b7d47c622b5d7b6dc" }, + { + "ImportPath": "github.com/inconshreveable/mousetrap", + "Rev": "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" + }, { "ImportPath": "github.com/influxdb/influxdb/client", "Comment": "v0.8.8", @@ -392,11 +396,11 @@ }, { "ImportPath": "github.com/spf13/cobra", - "Rev": "79bd93d369fb73d640179208d4e2b1a748915567" + "Rev": "c0da825198c75814463e1b3018e42e438b771a5b" }, { "ImportPath": "github.com/spf13/pflag", - "Rev": "11b7cf8387a31f278486eaad758162830eca8c73" + "Rev": "18d831e92d67eafd1b0db8af9ffddbd04f7ae1f4" }, { "ImportPath": "github.com/stretchr/objx", diff --git a/Godeps/_workspace/src/github.com/inconshreveable/mousetrap/LICENSE b/Godeps/_workspace/src/github.com/inconshreveable/mousetrap/LICENSE new file mode 100644 index 00000000000..5f0d1fb6a7b --- /dev/null +++ b/Godeps/_workspace/src/github.com/inconshreveable/mousetrap/LICENSE @@ -0,0 +1,13 @@ +Copyright 2014 Alan Shreve + +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. diff --git a/Godeps/_workspace/src/github.com/inconshreveable/mousetrap/README.md b/Godeps/_workspace/src/github.com/inconshreveable/mousetrap/README.md new file mode 100644 index 00000000000..7a950d1774f --- /dev/null +++ b/Godeps/_workspace/src/github.com/inconshreveable/mousetrap/README.md @@ -0,0 +1,23 @@ +# mousetrap + +mousetrap is a tiny library that answers a single question. + +On a Windows machine, was the process invoked by someone double clicking on +the executable file while browsing in explorer? + +### Motivation + +Windows developers unfamiliar with command line tools will often "double-click" +the executable for a tool. Because most CLI tools print the help and then exit +when invoked without arguments, this is often very frustrating for those users. + +mousetrap provides a way to detect these invocations so that you can provide +more helpful behavior and instructions on how to run the CLI tool. To see what +this looks like, both from an organizational and a technical perspective, see +https://inconshreveable.com/09-09-2014/sweat-the-small-stuff/ + +### The interface + +The library exposes a single interface: + + func StartedByExplorer() (bool) diff --git a/Godeps/_workspace/src/github.com/inconshreveable/mousetrap/trap_others.go b/Godeps/_workspace/src/github.com/inconshreveable/mousetrap/trap_others.go new file mode 100644 index 00000000000..9d2d8a4bab9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/inconshreveable/mousetrap/trap_others.go @@ -0,0 +1,15 @@ +// +build !windows + +package mousetrap + +// StartedByExplorer returns true if the program was invoked by the user +// double-clicking on the executable from explorer.exe +// +// It is conservative and returns false if any of the internal calls fail. +// It does not guarantee that the program was run from a terminal. It only can tell you +// whether it was launched from explorer.exe +// +// On non-Windows platforms, it always returns false. +func StartedByExplorer() bool { + return false +} diff --git a/Godeps/_workspace/src/github.com/inconshreveable/mousetrap/trap_windows.go b/Godeps/_workspace/src/github.com/inconshreveable/mousetrap/trap_windows.go new file mode 100644 index 00000000000..336142a5e3e --- /dev/null +++ b/Godeps/_workspace/src/github.com/inconshreveable/mousetrap/trap_windows.go @@ -0,0 +1,98 @@ +// +build windows +// +build !go1.4 + +package mousetrap + +import ( + "fmt" + "os" + "syscall" + "unsafe" +) + +const ( + // defined by the Win32 API + th32cs_snapprocess uintptr = 0x2 +) + +var ( + kernel = syscall.MustLoadDLL("kernel32.dll") + CreateToolhelp32Snapshot = kernel.MustFindProc("CreateToolhelp32Snapshot") + Process32First = kernel.MustFindProc("Process32FirstW") + Process32Next = kernel.MustFindProc("Process32NextW") +) + +// ProcessEntry32 structure defined by the Win32 API +type processEntry32 struct { + dwSize uint32 + cntUsage uint32 + th32ProcessID uint32 + th32DefaultHeapID int + th32ModuleID uint32 + cntThreads uint32 + th32ParentProcessID uint32 + pcPriClassBase int32 + dwFlags uint32 + szExeFile [syscall.MAX_PATH]uint16 +} + +func getProcessEntry(pid int) (pe *processEntry32, err error) { + snapshot, _, e1 := CreateToolhelp32Snapshot.Call(th32cs_snapprocess, uintptr(0)) + if snapshot == uintptr(syscall.InvalidHandle) { + err = fmt.Errorf("CreateToolhelp32Snapshot: %v", e1) + return + } + defer syscall.CloseHandle(syscall.Handle(snapshot)) + + var processEntry processEntry32 + processEntry.dwSize = uint32(unsafe.Sizeof(processEntry)) + ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) + if ok == 0 { + err = fmt.Errorf("Process32First: %v", e1) + return + } + + for { + if processEntry.th32ProcessID == uint32(pid) { + pe = &processEntry + return + } + + ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) + if ok == 0 { + err = fmt.Errorf("Process32Next: %v", e1) + return + } + } +} + +func getppid() (pid int, err error) { + pe, err := getProcessEntry(os.Getpid()) + if err != nil { + return + } + + pid = int(pe.th32ParentProcessID) + return +} + +// StartedByExplorer returns true if the program was invoked by the user double-clicking +// on the executable from explorer.exe +// +// It is conservative and returns false if any of the internal calls fail. +// It does not guarantee that the program was run from a terminal. It only can tell you +// whether it was launched from explorer.exe +func StartedByExplorer() bool { + ppid, err := getppid() + if err != nil { + return false + } + + pe, err := getProcessEntry(ppid) + if err != nil { + return false + } + + name := syscall.UTF16ToString(pe.szExeFile[:]) + return name == "explorer.exe" +} diff --git a/Godeps/_workspace/src/github.com/inconshreveable/mousetrap/trap_windows_1.4.go b/Godeps/_workspace/src/github.com/inconshreveable/mousetrap/trap_windows_1.4.go new file mode 100644 index 00000000000..9a28e57c3c3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/inconshreveable/mousetrap/trap_windows_1.4.go @@ -0,0 +1,46 @@ +// +build windows +// +build go1.4 + +package mousetrap + +import ( + "os" + "syscall" + "unsafe" +) + +func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) { + snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0) + if err != nil { + return nil, err + } + defer syscall.CloseHandle(snapshot) + var procEntry syscall.ProcessEntry32 + procEntry.Size = uint32(unsafe.Sizeof(procEntry)) + if err = syscall.Process32First(snapshot, &procEntry); err != nil { + return nil, err + } + for { + if procEntry.ProcessID == uint32(pid) { + return &procEntry, nil + } + err = syscall.Process32Next(snapshot, &procEntry) + if err != nil { + return nil, err + } + } +} + +// StartedByExplorer returns true if the program was invoked by the user double-clicking +// on the executable from explorer.exe +// +// It is conservative and returns false if any of the internal calls fail. +// It does not guarantee that the program was run from a terminal. It only can tell you +// whether it was launched from explorer.exe +func StartedByExplorer() bool { + pe, err := getProcessEntry(os.Getppid()) + if err != nil { + return false + } + return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:]) +} diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/.travis.yml b/Godeps/_workspace/src/github.com/spf13/cobra/.travis.yml index 6de9ac2318f..dc43afd61b9 100644 --- a/Godeps/_workspace/src/github.com/spf13/cobra/.travis.yml +++ b/Godeps/_workspace/src/github.com/spf13/cobra/.travis.yml @@ -1,6 +1,8 @@ language: go go: - - 1.1 + - 1.3 + - 1.4.2 + - tip script: - go test ./... - go build diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/README.md b/Godeps/_workspace/src/github.com/spf13/cobra/README.md index 64c29ef1899..1b29a86e528 100644 --- a/Godeps/_workspace/src/github.com/spf13/cobra/README.md +++ b/Godeps/_workspace/src/github.com/spf13/cobra/README.md @@ -2,7 +2,7 @@ A Commander for modern go CLI interactions -[![Build Status](https://travis-ci.org/spf13/cobra.png)](https://travis-ci.org/spf13/cobra) +[![Build Status](https://travis-ci.org/spf13/cobra.svg)](https://travis-ci.org/spf13/cobra) ## Overview @@ -143,6 +143,15 @@ A flag can also be assigned locally which will only apply to that specific comma HugoCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") +### Remove a command from its parent + +Removing a command is not a common action is simple program but it allows 3rd parties to customize an existing command tree. + +In this exemple, we remove the existing `VersionCmd` command of an existing root command, and we replace it by our own version. + + mainlib.RootCmd.RemoveCommand(mainlib.VersionCmd) + mainlib.RootCmd.AddCommand(versionCmd) + ### Once all commands and flags are defined, Execute the commands Execute should be run on the root for clarity, though it can be called on any command. @@ -339,6 +348,13 @@ Like help the function and template are over ridable through public methods. command.SetUsageTemplate(s string) +## Generating markdown formatted documentation for your command + +Cobra can generate a markdown formatted document based on the subcommands, flags, etc. A simple example of how to do this for your command can be found in [Markdown Docs](md_docs.md) + +## Generating bash completions for your command + +Cobra can generate a bash completions file. If you add more information to your command these completions can be amazingly powerful and flexible. Read more about [Bash Completions](bash_completions.md) ## Debugging diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions.go b/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions.go new file mode 100644 index 00000000000..1c5640745f1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions.go @@ -0,0 +1,343 @@ +package cobra + +import ( + "bytes" + "fmt" + "os" + "strings" + + "github.com/spf13/pflag" +) + +const ( + BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extentions" + BashCompOneRequiredFlag = "cobra_annotation_bash_completion_one_required_flag" +) + +func preamble(out *bytes.Buffer) { + fmt.Fprintf(out, `#!/bin/bash + + +__debug() +{ + if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then + echo "$*" >> ${BASH_COMP_DEBUG_FILE} + fi +} + +__index_of_word() +{ + local w word=$1 + shift + index=0 + for w in "$@"; do + [[ $w = "$word" ]] && return + index=$((index+1)) + done + index=-1 +} + +__contains_word() +{ + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done + return 1 +} + +__handle_reply() +{ + __debug "${FUNCNAME}" + case $cur in + -*) + compopt -o nospace + local allflags + if [ ${#must_have_one_flag[@]} -ne 0 ]; then + allflags=("${must_have_one_flag[@]}") + else + allflags=("${flags[*]} ${two_word_flags[*]}") + fi + COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") ) + [[ $COMPREPLY == *= ]] || compopt +o nospace + return 0; + ;; + esac + + # check if we are handling a flag with special work handling + local index + __index_of_word "${prev}" "${flags_with_completion[@]}" + if [[ ${index} -ge 0 ]]; then + ${flags_completion[${index}]} + return + fi + + # we are parsing a flag and don't have a special handler, no completion + if [[ ${cur} != "${words[cword]}" ]]; then + return + fi + + local completions + if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then + completions=("${must_have_one_flag[@]}") + elif [[ ${#must_have_one_noun[@]} -ne 0 ]]; then + completions=("${must_have_one_noun[@]}") + else + completions=("${commands[@]}") + fi + COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") ) + + if [[ ${#COMPREPLY[@]} -eq 0 ]]; then + declare -F __custom_func >/dev/null && __custom_func + fi +} + +__handle_flag() +{ + __debug "${FUNCNAME}: c is $c words[c] is ${words[c]}" + + # if a command required a flag, and we found it, unset must_have_one_flag() + local flagname=${words[c]} + # if the word contained an = + if [[ ${words[c]} == *"="* ]]; then + flagname=${flagname%%=*} # strip everything after the = + flagname="${flagname}=" # but put the = back + fi + __debug "${FUNCNAME}: looking for ${flagname}" + if __contains_word "${flagname}" "${must_have_one_flag[@]}"; then + must_have_one_flag=() + fi + + # skip the argument to a two word flag + if __contains_word "${words[c]}" "${two_word_flags[@]}"; then + c=$((c+1)) + # if we are looking for a flags value, don't show commands + if [[ $c -eq $cword ]]; then + commands=() + fi + fi + + # skip the flag itself + c=$((c+1)) + +} + +__handle_noun() +{ + __debug "${FUNCNAME}: c is $c words[c] is ${words[c]}" + + if __contains_word "${words[c]}" "${must_have_one_noun[@]}"; then + must_have_one_noun=() + fi + + nouns+=("${words[c]}") + c=$((c+1)) +} + +__handle_command() +{ + __debug "${FUNCNAME}: c is $c words[c] is ${words[c]}" + + local next_command + if [[ -n ${last_command} ]]; then + next_command="_${last_command}_${words[c]}" + else + next_command="_${words[c]}" + fi + c=$((c+1)) + __debug "${FUNCNAME}: looking for ${next_command}" + declare -F $next_command >/dev/null && $next_command +} + +__handle_word() +{ + if [[ $c -ge $cword ]]; then + __handle_reply + return + fi + __debug "${FUNCNAME}: c is $c words[c] is ${words[c]}" + if [[ "${words[c]}" == -* ]]; then + __handle_flag + elif __contains_word "${words[c]}" "${commands[@]}"; then + __handle_command + else + __handle_noun + fi + __handle_word +} + +`) +} + +func postscript(out *bytes.Buffer, name string) { + fmt.Fprintf(out, "__start_%s()\n", name) + fmt.Fprintf(out, `{ + local cur prev words cword split + _init_completion -s || return + + local completions_func + local c=0 + local flags=() + local two_word_flags=() + local flags_with_completion=() + local flags_completion=() + local commands=("%s") + local must_have_one_flag=() + local must_have_one_noun=() + local last_command + local nouns=() + + __handle_word +} + +`, name) + fmt.Fprintf(out, "complete -F __start_%s %s\n", name, name) + fmt.Fprintf(out, "# ex: ts=4 sw=4 et filetype=sh\n") +} + +func writeCommands(cmd *Command, out *bytes.Buffer) { + fmt.Fprintf(out, " commands=()\n") + for _, c := range cmd.Commands() { + fmt.Fprintf(out, " commands+=(%q)\n", c.Name()) + } + fmt.Fprintf(out, "\n") +} + +func writeFlagHandler(name string, annotations map[string][]string, out *bytes.Buffer) { + for key, value := range annotations { + switch key { + case BashCompFilenameExt: + fmt.Fprintf(out, " flags_with_completion+=(%q)\n", name) + + ext := strings.Join(value, "|") + ext = "_filedir '@(" + ext + ")'" + fmt.Fprintf(out, " flags_completion+=(%q)\n", ext) + } + } +} + +func writeShortFlag(flag *pflag.Flag, out *bytes.Buffer) { + b := (flag.Value.Type() == "bool") + name := flag.Shorthand + format := " " + if !b { + format += "two_word_" + } + format += "flags+=(\"-%s\")\n" + fmt.Fprintf(out, format, name) + writeFlagHandler("-"+name, flag.Annotations, out) +} + +func writeFlag(flag *pflag.Flag, out *bytes.Buffer) { + b := (flag.Value.Type() == "bool") + name := flag.Name + format := " flags+=(\"--%s" + if !b { + format += "=" + } + format += "\")\n" + fmt.Fprintf(out, format, name) + writeFlagHandler("--"+name, flag.Annotations, out) +} + +func writeFlags(cmd *Command, out *bytes.Buffer) { + fmt.Fprintf(out, ` flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + +`) + cmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) { + writeFlag(flag, out) + if len(flag.Shorthand) > 0 { + writeShortFlag(flag, out) + } + }) + + fmt.Fprintf(out, "\n") +} + +func writeRequiredFlag(cmd *Command, out *bytes.Buffer) { + fmt.Fprintf(out, " must_have_one_flag=()\n") + flags := cmd.NonInheritedFlags() + flags.VisitAll(func(flag *pflag.Flag) { + for key, _ := range flag.Annotations { + switch key { + case BashCompOneRequiredFlag: + format := " must_have_one_flag+=(\"--%s" + b := (flag.Value.Type() == "bool") + if !b { + format += "=" + } + format += "\")\n" + fmt.Fprintf(out, format, flag.Name) + + if len(flag.Shorthand) > 0 { + fmt.Fprintf(out, " must_have_one_flag+=(\"-%s\")\n", flag.Shorthand) + } + } + } + }) +} + +func writeRequiredNoun(cmd *Command, out *bytes.Buffer) { + fmt.Fprintf(out, " must_have_one_noun=()\n") + for _, value := range cmd.ValidArgs { + fmt.Fprintf(out, " must_have_one_noun+=(%q)\n", value) + } +} + +func gen(cmd *Command, out *bytes.Buffer) { + for _, c := range cmd.Commands() { + gen(c, out) + } + commandName := cmd.CommandPath() + commandName = strings.Replace(commandName, " ", "_", -1) + fmt.Fprintf(out, "_%s()\n{\n", commandName) + fmt.Fprintf(out, " last_command=%q\n", commandName) + writeCommands(cmd, out) + writeFlags(cmd, out) + writeRequiredFlag(cmd, out) + writeRequiredNoun(cmd, out) + fmt.Fprintf(out, "}\n\n") +} + +func (cmd *Command) GenBashCompletion(out *bytes.Buffer) { + preamble(out) + if len(cmd.BashCompletionFunction) > 0 { + fmt.Fprintf(out, "%s\n", cmd.BashCompletionFunction) + } + gen(cmd, out) + postscript(out, cmd.Name()) +} + +func (cmd *Command) GenBashCompletionFile(filename string) error { + out := new(bytes.Buffer) + + cmd.GenBashCompletion(out) + + outFile, err := os.Create(filename) + if err != nil { + return err + } + defer outFile.Close() + + _, err = outFile.Write(out.Bytes()) + if err != nil { + return err + } + return nil +} + +func (cmd *Command) MarkFlagRequired(name string) { + flag := cmd.Flags().Lookup(name) + if flag == nil { + return + } + if flag.Annotations == nil { + flag.Annotations = make(map[string][]string) + } + annotation := make([]string, 1) + annotation[0] = "true" + flag.Annotations[BashCompOneRequiredFlag] = annotation +} diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions.md b/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions.md new file mode 100644 index 00000000000..e1a5d56d00b --- /dev/null +++ b/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions.md @@ -0,0 +1,146 @@ +# Generating Bash Completions For Your Own cobra.Command + +Generating bash completions from a cobra command is incredibly easy. An actual program which does so for the kubernetes kubectl binary is as follows: + +```go +package main + +import ( + "io/ioutil" + "os" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd" +) + +func main() { + kubectl := cmd.NewFactory(nil).NewKubectlCommand(os.Stdin, ioutil.Discard, ioutil.Discard) + kubectl.GenBashCompletionFile("out.sh") +} +``` + +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. + +## Creating your own custom functions + +Some more actual code that works in kubernetes: + +```bash +const ( + bash_completion_func = `__kubectl_parse_get() +{ + local kubectl_output out + if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then + out=($(echo "${kubectl_output}" | awk '{print $1}')) + COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) ) + fi +} + +__kubectl_get_resource() +{ + if [[ ${#nouns[@]} -eq 0 ]]; then + return 1 + fi + __kubectl_parse_get ${nouns[${#nouns[@]} -1]} + if [[ $? -eq 0 ]]; then + return 0 + fi +} + +__custom_func() { + case ${last_command} in + kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop) + __kubectl_get_resource + return + ;; + *) + ;; + esac +} +`) +``` + +And then I set that in my command definition: + +```go +cmds := &cobra.Command{ + Use: "kubectl", + Short: "kubectl controls the Kubernetes cluster manager", + Long: `kubectl controls the Kubernetes cluster manager. + +Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`, + Run: runHelp, + BashCompletionFunction: bash_completion_func, +} +``` + +The `BashCompletionFunction` option is really only valid/useful on the root command. Doing the above will cause `__custom_func()` to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like `kubectl get pod [mypod]`. If you type `kubectl get pod [tab][tab]` the `__customc_func()` will run because the cobra.Command only understood "kubectl" and "get." `__custom_func()` will see that the cobra.Command is "kubectl_get" and will thus call another helper `__kubectl_get_resource()`. `__kubectl_get_resource` will look at the 'nouns' collected. In our example the only noun will be `pod`. So it will call `__kubectl_parse_get pod`. `__kubectl_parse_get` will actually call out to kubernetes and get any pods. It will then set `COMPREPLY` to valid pods! + +## Have the completions code complete your 'nouns' + +In the above example "pod" was assumed to already be typed. But if you want `kubectl get [tab][tab]` to show a list of valid "nouns" you have to set them. Simplified code from `kubectl get` looks like: + +```go +validArgs []string = { "pods", "nodes", "services", "replicationControllers" } + +cmd := &cobra.Command{ + Use: "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)", + Short: "Display one or many resources", + Long: get_long, + Example: get_example, + Run: func(cmd *cobra.Command, args []string) { + err := RunGet(f, out, cmd, args) + util.CheckErr(err) + }, + ValidArgs: validArgs, +} +``` + +Notice we put the "ValidArgs" on the "get" subcommand. Doing so will give results like + +```bash +# kubectl get [tab][tab] +nodes pods replicationControllers services +``` + +## Mark flags as required + +Most of the time completions will only show subcommands. But if a flag is required to make a subcommand work, you probably want it to show up when the user types [tab][tab]. Marking a flag as 'Required' is incredibly easy. + +```go +cmd.MarkFlagRequired("pod") +cmd.MarkFlagRequired("container") +``` + +and you'll get something like + +```bash +# kubectl exec [tab][tab][tab] +-c --container= -p --pod= +``` + +# Specify valid filename extentions for flags that take a filename + +In this example we use --filename= and expect to get a json or yaml file as the argument. To make this easier we annotate the --filename flag with valid filename extensions. + +```go + annotations := make([]string, 3) + annotations[0] = "json" + annotations[1] = "yaml" + annotations[2] = "yml" + + annotation := make(map[string][]string) + annotation[cobra.BashCompFilenameExt] = annotations + + flag := &pflag.Flag{"filename", "f", usage, value, value.String(), false, annotation} + cmd.Flags().AddFlag(flag) +``` + +Now when you run a command with this filename flag you'll get something like + +```bash +# kubectl create -f +test/ example/ rpmbuild/ +hello.yml test.json +``` + +So while there are many other files in the CWD it only shows me subdirs and those with valid extensions. diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions_test.go b/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions_test.go new file mode 100644 index 00000000000..12dc96049cd --- /dev/null +++ b/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions_test.go @@ -0,0 +1,74 @@ +package cobra + +import ( + "bytes" + "fmt" + "os" + "strings" + "testing" +) + +var _ = fmt.Println +var _ = os.Stderr + +func check(t *testing.T, found, expected string) { + if !strings.Contains(found, expected) { + t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) + } +} + +// World worst custom function, just keep telling you to enter hello! +const ( + bash_completion_func = `__custom_func() { +COMPREPLY=( "hello" ) +} +` +) + +func TestBashCompletions(t *testing.T) { + c := initializeWithRootCmd() + cmdEcho.AddCommand(cmdTimes) + c.AddCommand(cmdEcho, cmdPrint) + + // custom completion function + c.BashCompletionFunction = bash_completion_func + + // required flag + c.MarkFlagRequired("introot") + + // valid nounds + validArgs := []string{"pods", "nodes", "services", "replicationControllers"} + c.ValidArgs = validArgs + + // filename extentions + annotations := make([]string, 3) + annotations[0] = "json" + annotations[1] = "yaml" + annotations[2] = "yml" + + annotation := make(map[string][]string) + annotation[BashCompFilenameExt] = annotations + + var flagval string + c.Flags().StringVar(&flagval, "filename", "", "Enter a filename") + flag := c.Flags().Lookup("filename") + flag.Annotations = annotation + + out := new(bytes.Buffer) + c.GenBashCompletion(out) + str := out.String() + + check(t, str, "_cobra-test") + check(t, str, "_cobra-test_echo") + check(t, str, "_cobra-test_echo_times") + check(t, str, "_cobra-test_print") + + // check for required flags + check(t, str, `must_have_one_flag+=("--introot=")`) + // check for custom completion function + check(t, str, `COMPREPLY=( "hello" )`) + // check for required nouns + check(t, str, `must_have_one_noun+=("pods")`) + // check for filename extention flags + check(t, str, `flags_completion+=("_filedir '@(json|yaml|yml)'")`) +} diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/cobra.go b/Godeps/_workspace/src/github.com/spf13/cobra/cobra.go index 1b5ca36024a..78b92b0af3b 100644 --- a/Godeps/_workspace/src/github.com/spf13/cobra/cobra.go +++ b/Godeps/_workspace/src/github.com/spf13/cobra/cobra.go @@ -31,6 +31,14 @@ var initializers []func() // Set this to true to enable it var EnablePrefixMatching bool = false +// enables an information splash screen on Windows if the CLI is started from explorer.exe. +var EnableWindowsMouseTrap bool = true + +var MousetrapHelpText string = `This is a command line tool + +You need to open cmd.exe and run it from there. +` + //OnInitialize takes a series of func() arguments and appends them to a slice of func(). func OnInitialize(y ...func()) { for _, x := range y { diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/cobra_test.go b/Godeps/_workspace/src/github.com/spf13/cobra/cobra_test.go index 120bc5c7ffb..a258508947f 100644 --- a/Godeps/_workspace/src/github.com/spf13/cobra/cobra_test.go +++ b/Godeps/_workspace/src/github.com/spf13/cobra/cobra_test.go @@ -3,11 +3,14 @@ package cobra import ( "bytes" "fmt" + "os" + "runtime" "strings" "testing" ) var _ = fmt.Println +var _ = os.Stderr var tp, te, tt, t1 []string var flagb1, flagb2, flagb3, flagbr, flagbp bool @@ -15,6 +18,7 @@ var flags1, flags2a, flags2b, flags3 string var flagi1, flagi2, flagi3, flagir int var globalFlag1 bool var flagEcho, rootcalled bool +var versionUsed int const strtwoParentHelp = "help message for parent flag strtwo" const strtwoChildHelp = "help message for child flag strtwo" @@ -22,7 +26,7 @@ const strtwoChildHelp = "help message for child flag strtwo" var cmdPrint = &Command{ Use: "print [string to print]", Short: "Print anything to the screen", - Long: `an utterly useless command for testing.`, + Long: `an absolutely utterly useless command for testing.`, Run: func(cmd *Command, args []string) { tp = args }, @@ -33,15 +37,24 @@ var cmdEcho = &Command{ Aliases: []string{"say"}, Short: "Echo anything to the screen", Long: `an utterly useless command for testing.`, + Example: "Just run cobra-test echo", Run: func(cmd *Command, args []string) { te = args }, } +var cmdEchoSub = &Command{ + Use: "echosub [string to print]", + Short: "second sub command for echo", + Long: `an absolutely utterly useless command for testing gendocs!.`, + Run: func(cmd *Command, args []string) { + }, +} + var cmdTimes = &Command{ Use: "times [# times] [string to echo]", Short: "Echo anything to the screen more times", - Long: `an slightly useless command for testing.`, + Long: `a slightly useless command for testing.`, Run: func(cmd *Command, args []string) { tt = args }, @@ -68,6 +81,30 @@ var cmdRootWithRun = &Command{ }, } +var cmdSubNoRun = &Command{ + Use: "subnorun", + Short: "A subcommand without a Run function", + Long: "A long output about a subcommand without a Run function", +} + +var cmdVersion1 = &Command{ + Use: "version", + Short: "Print the version number", + Long: `First version of the version command`, + Run: func(cmd *Command, args []string) { + versionUsed = 1 + }, +} + +var cmdVersion2 = &Command{ + Use: "version", + Short: "Print the version number", + Long: `Second version of the version command`, + Run: func(cmd *Command, args []string) { + versionUsed = 2 + }, +} + func flagInit() { cmdEcho.ResetFlags() cmdPrint.ResetFlags() @@ -75,6 +112,7 @@ func flagInit() { cmdRootNoRun.ResetFlags() cmdRootSameName.ResetFlags() cmdRootWithRun.ResetFlags() + cmdSubNoRun.ResetFlags() cmdRootNoRun.PersistentFlags().StringVarP(&flags2a, "strtwo", "t", "two", strtwoParentHelp) cmdEcho.Flags().IntVarP(&flagi1, "intone", "i", 123, "help message for flag intone") cmdTimes.Flags().IntVarP(&flagi2, "inttwo", "j", 234, "help message for flag inttwo") @@ -86,6 +124,8 @@ func flagInit() { cmdEcho.Flags().BoolVarP(&flagb1, "boolone", "b", true, "help message for flag boolone") cmdTimes.Flags().BoolVarP(&flagb2, "booltwo", "c", false, "help message for flag booltwo") cmdPrint.Flags().BoolVarP(&flagb3, "boolthree", "b", true, "help message for flag boolthree") + cmdVersion1.ResetFlags() + cmdVersion2.ResetFlags() } func commandInit() { @@ -95,6 +135,7 @@ func commandInit() { cmdRootNoRun.ResetCommands() cmdRootSameName.ResetCommands() cmdRootWithRun.ResetCommands() + cmdSubNoRun.ResetCommands() } func initialize() *Command { @@ -164,7 +205,7 @@ func fullTester(c *Command, input string) resulter { // Testing flag with invalid input c.SetOutput(buf) cmdEcho.AddCommand(cmdTimes) - c.AddCommand(cmdPrint, cmdEcho) + c.AddCommand(cmdPrint, cmdEcho, cmdSubNoRun) c.SetArgs(strings.Split(input, " ")) err := c.Execute() @@ -173,15 +214,26 @@ func fullTester(c *Command, input string) resulter { return resulter{err, output, c} } +func logErr(t *testing.T, found, expected string) { + out := new(bytes.Buffer) + + _, _, line, ok := runtime.Caller(2) + if ok { + fmt.Fprintf(out, "Line: %d ", line) + } + fmt.Fprintf(out, "Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) + t.Errorf(out.String()) +} + func checkResultContains(t *testing.T, x resulter, check string) { if !strings.Contains(x.Output, check) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", check, x.Output) + logErr(t, x.Output, check) } } func checkResultOmits(t *testing.T, x resulter, check string) { if strings.Contains(x.Output, check) { - t.Errorf("Unexpected response.\nExpecting to omit: \n %q\nGot:\n %q\n", check, x.Output) + logErr(t, x.Output, check) } } @@ -191,7 +243,7 @@ func checkOutputContains(t *testing.T, c *Command, check string) { c.Execute() if !strings.Contains(buf.String(), check) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", check, buf.String()) + logErr(t, buf.String(), check) } } @@ -417,6 +469,20 @@ func TestTrailingCommandFlags(t *testing.T) { } } +func TestInvalidSubCommandFlags(t *testing.T) { + cmd := initializeWithRootCmd() + cmd.AddCommand(cmdTimes) + + result := simpleTester(cmd, "times --inttwo=2 --badflag=bar") + + checkResultContains(t, result, "unknown flag: --badflag") + + if strings.Contains(result.Output, "unknown flag: --inttwo") { + t.Errorf("invalid --badflag flag shouldn't fail on 'unknown' --inttwo flag") + } + +} + func TestPersistentFlags(t *testing.T) { fullSetupTest("echo -s something -p more here") @@ -451,11 +517,14 @@ func TestPersistentFlags(t *testing.T) { } func TestHelpCommand(t *testing.T) { - c := fullSetupTest("help echo") - checkResultContains(t, c, cmdEcho.Long) + x := fullSetupTest("help") + checkResultContains(t, x, cmdRootWithRun.Long) - r := fullSetupTest("help echo times") - checkResultContains(t, r, cmdTimes.Long) + x = fullSetupTest("help echo") + checkResultContains(t, x, cmdEcho.Long) + + x = fullSetupTest("help echo times") + checkResultContains(t, x, cmdTimes.Long) } func TestChildCommandHelp(t *testing.T) { @@ -465,6 +534,11 @@ func TestChildCommandHelp(t *testing.T) { checkResultContains(t, r, strtwoChildHelp) } +func TestNonRunChildHelp(t *testing.T) { + x := noRRSetupTest("subnorun") + checkResultContains(t, x, cmdSubNoRun.Long) +} + func TestRunnableRootCommand(t *testing.T) { fullSetupTest("") @@ -473,6 +547,53 @@ func TestRunnableRootCommand(t *testing.T) { } } +func TestRunnableRootCommandNilInput(t *testing.T) { + empty_arg := make([]string, 0) + c := initializeWithRootCmd() + + buf := new(bytes.Buffer) + // Testing flag with invalid input + c.SetOutput(buf) + cmdEcho.AddCommand(cmdTimes) + c.AddCommand(cmdPrint, cmdEcho) + c.SetArgs(empty_arg) + + c.Execute() + + if rootcalled != true { + t.Errorf("Root Function was not called") + } +} + +func TestRunnableRootCommandEmptyInput(t *testing.T) { + args := make([]string, 3) + args[0] = "" + args[1] = "--introot=12" + args[2] = "" + c := initializeWithRootCmd() + + buf := new(bytes.Buffer) + // Testing flag with invalid input + c.SetOutput(buf) + cmdEcho.AddCommand(cmdTimes) + c.AddCommand(cmdPrint, cmdEcho) + c.SetArgs(args) + + c.Execute() + + if rootcalled != true { + t.Errorf("Root Function was not called.\n\nOutput was:\n\n%s\n", buf) + } +} + +func TestInvalidSubcommandWhenArgsAllowed(t *testing.T) { + fullSetupTest("echo invalid-sub") + + if te[0] != "invalid-sub" { + t.Errorf("Subcommand didn't work...") + } +} + func TestRootFlags(t *testing.T) { fullSetupTest("-i 17 -b") @@ -534,6 +655,24 @@ func TestFlagAccess(t *testing.T) { } } +func TestNoNRunnableRootCommandNilInput(t *testing.T) { + args := make([]string, 0) + c := initialize() + + buf := new(bytes.Buffer) + // Testing flag with invalid input + c.SetOutput(buf) + cmdEcho.AddCommand(cmdTimes) + c.AddCommand(cmdPrint, cmdEcho) + c.SetArgs(args) + + c.Execute() + + if !strings.Contains(buf.String(), cmdRootNoRun.Long) { + t.Errorf("Expected to get help output, Got: \n %s", buf) + } +} + func TestRootNoCommandHelp(t *testing.T) { x := rootOnlySetupTest("--help") @@ -554,6 +693,15 @@ func TestRootNoCommandHelp(t *testing.T) { } } +func TestRootUnknownCommand(t *testing.T) { + r := noRRSetupTest("bogus") + s := "Error: unknown command \"bogus\"\nRun 'cobra-test help' for usage.\n" + + if r.Output != s { + t.Errorf("Unexpected response.\nExpecting to be:\n %q\nGot:\n %q\n", s, r.Output) + } +} + func TestFlagsBeforeCommand(t *testing.T) { // short without space x := fullSetupTest("-i10 echo") @@ -607,3 +755,34 @@ func TestFlagsBeforeCommand(t *testing.T) { } } + +func TestRemoveCommand(t *testing.T) { + versionUsed = 0 + c := initializeWithRootCmd() + c.AddCommand(cmdVersion1) + c.RemoveCommand(cmdVersion1) + x := fullTester(c, "version") + if x.Error == nil { + t.Errorf("Removed command should not have been called\n") + return + } +} + +func TestReplaceCommandWithRemove(t *testing.T) { + versionUsed = 0 + c := initializeWithRootCmd() + c.AddCommand(cmdVersion1) + c.RemoveCommand(cmdVersion1) + c.AddCommand(cmdVersion2) + x := fullTester(c, "version") + if x.Error != nil { + t.Errorf("Valid Input shouldn't have errors, got:\n %q", x.Error) + return + } + if versionUsed == 1 { + t.Errorf("Removed command shouldn't be called\n") + } + if versionUsed != 2 { + t.Errorf("Replacing command should have been called but didn't\n") + } +} diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/command.go b/Godeps/_workspace/src/github.com/spf13/cobra/command.go index a7d90886c3f..59654c25cb4 100644 --- a/Godeps/_workspace/src/github.com/spf13/cobra/command.go +++ b/Godeps/_workspace/src/github.com/spf13/cobra/command.go @@ -18,11 +18,13 @@ package cobra import ( "bytes" "fmt" + "github.com/inconshreveable/mousetrap" + flag "github.com/spf13/pflag" "io" "os" + "runtime" "strings" - - flag "github.com/spf13/pflag" + "time" ) // Command is just that, a command for your application. @@ -42,6 +44,10 @@ type Command struct { Long string // Examples of how to use the command Example string + // List of all valid non-flag arguments, used for bash completions *TODO* actually validate these + ValidArgs []string + // Custom functions used by the bash autocompletion generator + BashCompletionFunction string // Full set of flags flags *flag.FlagSet // Set of flags childrens of this command will inherit @@ -223,7 +229,7 @@ Aliases: Examples: {{ .Example }} -{{end}}{{ if .HasSubCommands}} +{{end}}{{ if .HasRunnableSubCommands}} Available Commands: {{range .Commands}}{{if .Runnable}} {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}} @@ -231,8 +237,9 @@ Available Commands: {{range .Commands}}{{if .Runnable}} {{ if .HasLocalFlags}}Flags: {{.LocalFlags.FlagUsages}}{{end}} {{ if .HasInheritedFlags}}Global Flags: -{{.InheritedFlags.FlagUsages}}{{end}}{{if .HasParent}}{{if and (gt .Commands 0) (gt .Parent.Commands 1) }} -Additional help topics: {{if gt .Commands 0 }}{{range .Commands}}{{if not .Runnable}} {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if gt .Parent.Commands 1 }}{{range .Parent.Commands}}{{if .Runnable}}{{if not (eq .Name $cmd.Name) }}{{end}} +{{.InheritedFlags.FlagUsages}}{{end}}{{if or (.HasHelpSubCommands) (.HasRunnableSiblings)}} +Additional help topics: +{{if .HasHelpSubCommands}}{{range .Commands}}{{if not .Runnable}} {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasRunnableSiblings }}{{range .Parent.Commands}}{{if .Runnable}}{{if not (eq .Name $cmd.Name) }} {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{end}} {{end}}{{ if .HasSubCommands }} Use "{{.Root.Name}} help [command]" for more information about a command. @@ -305,6 +312,8 @@ func stripFlags(args []string, c *Command) []string { 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 @@ -375,10 +384,9 @@ func (c *Command) Find(arrs []string) (*Command, []string, error) { commandFound, a := innerfind(c, arrs) - // if commander returned and the first argument (if it exists) doesn't - // match the command name, return nil & error - if commandFound.Name() == c.Name() && len(arrs[0]) > 0 && commandFound.Name() != arrs[0] { - return nil, a, fmt.Errorf("unknown command %q\nRun 'help' for usage.\n", a[0]) + // If we matched on the root, but we asked for a subcommand, return an error + if commandFound.Name() == c.Name() && len(stripFlags(arrs, c)) > 0 && commandFound.Name() != arrs[0] { + return nil, a, fmt.Errorf("unknown command %q", a[0]) } return commandFound, a, nil @@ -398,16 +406,6 @@ func (c *Command) Root() *Command { return findRoot(c) } -// execute the command determined by args and the command tree -func (c *Command) findAndExecute(args []string) (err error) { - - cmd, a, e := c.Find(args) - if e != nil { - return e - } - return cmd.execute(a) -} - func (c *Command) execute(a []string) (err error) { if c == nil { return fmt.Errorf("Called Execute() on a nil Command") @@ -474,6 +472,14 @@ func (c *Command) Execute() (err error) { return c.Root().Execute() } + if EnableWindowsMouseTrap && runtime.GOOS == "windows" { + if mousetrap.StartedByExplorer() { + c.Print(MousetrapHelpText) + time.Sleep(5 * time.Second) + os.Exit(1) + } + } + // initialize help as the last point possible to allow for user // overriding c.initHelp() @@ -494,55 +500,21 @@ func (c *Command) Execute() (err error) { c.Help() } } else { - err = c.findAndExecute(args) - } - - // Now handle the case where the root is runnable and only flags are provided - if err != nil && c.Runnable() { - // This is pretty much a custom version of the *Command.execute method - // with a few differences because it's the final command (no fall back) - e := c.ParseFlags(args) + cmd, flags, e := c.Find(args) if e != nil { - // Flags parsing had an error. - // If an error happens here, we have to report it to the user - c.Println(e.Error()) - // If an error happens search also for subcommand info about that - if c.cmdErrorBuf != nil && c.cmdErrorBuf.Len() > 0 { - c.Println(c.cmdErrorBuf.String()) - } else { - c.Usage() - } err = e - return } else { - // If help is called, regardless of other flags, we print that - if c.helpFlagVal { - c.Help() - return nil - } - - argWoFlags := c.Flags().Args() - if len(argWoFlags) > 0 { - // If there are arguments (not flags) one of the earlier - // cases should have caught it.. It means invalid usage - // print the usage - c.Usage() - } else { - // Only flags left... Call root.Run - c.preRun() - c.Run(c, argWoFlags) - err = nil - } + err = cmd.execute(flags) } } if err != nil { if err == flag.ErrHelp { c.Help() + } else { c.Println("Error:", err.Error()) - c.Printf("%v: invalid command %#q\n", c.Root().Name(), os.Args[1:]) - c.Printf("Run '%v help' for usage\n", c.Root().Name()) + c.Printf("Run '%v help' for usage.\n", c.Root().Name()) } } @@ -787,6 +759,37 @@ func (c *Command) HasSubCommands() bool { return len(c.commands) > 0 } +func (c *Command) HasRunnableSiblings() bool { + if !c.HasParent() { + return false + } + for _, sub := range c.parent.commands { + if sub.Runnable() { + return true + } + } + return false +} + +func (c *Command) HasHelpSubCommands() bool { + for _, sub := range c.commands { + if !sub.Runnable() { + return true + } + } + return false +} + +// Determine if the command has runnable children commands +func (c *Command) HasRunnableSubCommands() bool { + for _, sub := range c.commands { + if sub.Runnable() { + return true + } + } + return false +} + // Determine if the command is a child command func (c *Command) HasParent() bool { return c.parent != nil diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/command_test.go b/Godeps/_workspace/src/github.com/spf13/cobra/command_test.go new file mode 100644 index 00000000000..477d84e7c8b --- /dev/null +++ b/Godeps/_workspace/src/github.com/spf13/cobra/command_test.go @@ -0,0 +1,90 @@ +package cobra + +import ( + "reflect" + "testing" +) + +func TestStripFlags(t *testing.T) { + tests := []struct { + input []string + output []string + }{ + { + []string{"foo", "bar"}, + []string{"foo", "bar"}, + }, + { + []string{"foo", "--bar", "-b"}, + []string{"foo"}, + }, + { + []string{"-b", "foo", "--bar", "bar"}, + []string{}, + }, + { + []string{"-i10", "echo"}, + []string{"echo"}, + }, + { + []string{"-i=10", "echo"}, + []string{"echo"}, + }, + { + []string{"--int=100", "echo"}, + []string{"echo"}, + }, + { + []string{"-ib", "echo", "-bfoo", "baz"}, + []string{"echo", "baz"}, + }, + { + []string{"-i=baz", "bar", "-i", "foo", "blah"}, + []string{"bar", "blah"}, + }, + { + []string{"--int=baz", "-bbar", "-i", "foo", "blah"}, + []string{"blah"}, + }, + { + []string{"--cat", "bar", "-i", "foo", "blah"}, + []string{"bar", "blah"}, + }, + { + []string{"-c", "bar", "-i", "foo", "blah"}, + []string{"bar", "blah"}, + }, + { + []string{"--persist", "bar"}, + []string{"bar"}, + }, + { + []string{"-p", "bar"}, + []string{"bar"}, + }, + } + + cmdPrint := &Command{ + Use: "print [string to print]", + Short: "Print anything to the screen", + Long: `an utterly useless command for testing.`, + Run: func(cmd *Command, args []string) { + tp = args + }, + } + + var flagi int + var flagstr string + var flagbool bool + cmdPrint.PersistentFlags().BoolVarP(&flagbool, "persist", "p", false, "help for persistent one") + cmdPrint.Flags().IntVarP(&flagi, "int", "i", 345, "help message for flag int") + cmdPrint.Flags().StringVarP(&flagstr, "bar", "b", "bar", "help message for flag string") + cmdPrint.Flags().BoolVarP(&flagbool, "cat", "c", false, "help message for flag bool") + + for _, test := range tests { + output := stripFlags(test.input, cmdPrint) + if !reflect.DeepEqual(test.output, output) { + t.Errorf("expected: %v, got: %v", test.output, output) + } + } +} diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/md_docs.go b/Godeps/_workspace/src/github.com/spf13/cobra/md_docs.go new file mode 100644 index 00000000000..71bc8d5bd96 --- /dev/null +++ b/Godeps/_workspace/src/github.com/spf13/cobra/md_docs.go @@ -0,0 +1,121 @@ +//Copyright 2015 Red Hat Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cobra + +import ( + "bytes" + "fmt" + "os" + "sort" + "strings" + "time" +) + +func printOptions(out *bytes.Buffer, cmd *Command, name string) { + flags := cmd.NonInheritedFlags() + flags.SetOutput(out) + if flags.HasFlags() { + fmt.Fprintf(out, "### Options\n\n```\n") + flags.PrintDefaults() + fmt.Fprintf(out, "```\n\n") + } + + parentFlags := cmd.InheritedFlags() + parentFlags.SetOutput(out) + if parentFlags.HasFlags() { + fmt.Fprintf(out, "### Options inherrited from parent commands\n\n```\n") + parentFlags.PrintDefaults() + fmt.Fprintf(out, "```\n\n") + } +} + +type byName []*Command + +func (s byName) Len() int { return len(s) } +func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() } + +func GenMarkdown(cmd *Command, out *bytes.Buffer) { + name := cmd.CommandPath() + + short := cmd.Short + long := cmd.Long + if len(long) == 0 { + long = short + } + + fmt.Fprintf(out, "## %s\n\n", name) + fmt.Fprintf(out, "%s\n\n", short) + fmt.Fprintf(out, "### Synopsis\n\n") + fmt.Fprintf(out, "\n%s\n\n", long) + + if cmd.Runnable() { + fmt.Fprintf(out, "```\n%s\n```\n\n", cmd.UseLine()) + } + + if len(cmd.Example) > 0 { + fmt.Fprintf(out, "### Examples\n\n") + fmt.Fprintf(out, "```\n%s\n```\n\n", cmd.Example) + } + + printOptions(out, cmd, name) + + if len(cmd.Commands()) > 0 || cmd.HasParent() { + fmt.Fprintf(out, "### SEE ALSO\n") + if cmd.HasParent() { + parent := cmd.Parent() + pname := parent.CommandPath() + link := pname + ".md" + link = strings.Replace(link, " ", "_", -1) + fmt.Fprintf(out, "* [%s](%s)\t - %s\n", pname, link, parent.Short) + } + + children := cmd.Commands() + sort.Sort(byName(children)) + + for _, child := range children { + cname := name + " " + child.Name() + link := cname + ".md" + link = strings.Replace(link, " ", "_", -1) + fmt.Fprintf(out, "* [%s](%s)\t - %s\n", cname, link, child.Short) + } + fmt.Fprintf(out, "\n") + } + + fmt.Fprintf(out, "###### Auto generated by spf13/cobra at %s\n", time.Now().UTC()) +} + +func GenMarkdownTree(cmd *Command, dir string) { + for _, c := range cmd.Commands() { + GenMarkdownTree(c, dir) + } + + out := new(bytes.Buffer) + + GenMarkdown(cmd, out) + + filename := cmd.CommandPath() + filename = dir + strings.Replace(filename, " ", "_", -1) + ".md" + outFile, err := os.Create(filename) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + defer outFile.Close() + _, err = outFile.Write(out.Bytes()) + if err != nil { + fmt.Println(err) + os.Exit(1) + } +} diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/md_docs.md b/Godeps/_workspace/src/github.com/spf13/cobra/md_docs.md new file mode 100644 index 00000000000..43b6c994713 --- /dev/null +++ b/Godeps/_workspace/src/github.com/spf13/cobra/md_docs.md @@ -0,0 +1,35 @@ +# Generating Markdown Docs For Your Own cobra.Command + +## Generate markdown docs for the entire command tree + +This program can actually generate docs for the kubectl command in the kubernetes project + +```go +package main + +import ( + "io/ioutil" + "os" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd" + "github.com/spf13/cobra" +) + +func main() { + kubectl := cmd.NewFactory(nil).NewKubectlCommand(os.Stdin, ioutil.Discard, ioutil.Discard) + cobra.GenMarkdownTree(kubectl, "./") +} +``` + +This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case "./") + +## Generate markdown docs for a single command + +You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to `GenMarkdown()` instead of `GenMarkdownTree` + +```go + out := new(bytes.Buffer) + cobra.GenMarkdown(cmd, out) +``` + +This will write the markdown doc for ONLY "cmd" into the out, buffer. diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/md_docs_test.go b/Godeps/_workspace/src/github.com/spf13/cobra/md_docs_test.go new file mode 100644 index 00000000000..33613af3a2b --- /dev/null +++ b/Godeps/_workspace/src/github.com/spf13/cobra/md_docs_test.go @@ -0,0 +1,64 @@ +package cobra + +import ( + "bytes" + "fmt" + "os" + "strings" + "testing" +) + +var _ = fmt.Println +var _ = os.Stderr + +func TestGenMdDoc(t *testing.T) { + c := initializeWithRootCmd() + // Need two commands to run the command alphabetical sort + cmdEcho.AddCommand(cmdTimes, cmdEchoSub) + c.AddCommand(cmdPrint, cmdEcho) + cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp) + + out := new(bytes.Buffer) + + // We generate on s subcommand so we have both subcommands and parents + GenMarkdown(cmdEcho, out) + found := out.String() + + // Our description + expected := cmdEcho.Long + if !strings.Contains(found, expected) { + t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) + } + + // Better have our example + expected = cmdEcho.Example + if !strings.Contains(found, expected) { + t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) + } + + // A local flag + expected = "boolone" + if !strings.Contains(found, expected) { + t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) + } + + // persistent flag on parent + expected = "rootflag" + if !strings.Contains(found, expected) { + t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) + } + + // We better output info about our parent + expected = cmdRootWithRun.Short + if !strings.Contains(found, expected) { + t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) + } + + // And about subcommands + expected = cmdEchoSub.Short + if !strings.Contains(found, expected) { + t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) + } + + fmt.Fprintf(os.Stdout, "%s\n", found) +} diff --git a/Godeps/_workspace/src/github.com/spf13/pflag/flag.go b/Godeps/_workspace/src/github.com/spf13/pflag/flag.go index 72165f6c8a7..5dc53732b42 100644 --- a/Godeps/_workspace/src/github.com/spf13/pflag/flag.go +++ b/Godeps/_workspace/src/github.com/spf13/pflag/flag.go @@ -147,6 +147,7 @@ type Flag struct { Value Value // value as set DefValue string // default value (as text); for usage message Changed bool // If the user set the value (or if left to default) + Annotations map[string][]string // used by cobra.Command bash autocomple code } // Value is the interface to the dynamic value stored in a flag. @@ -358,7 +359,7 @@ func (f *FlagSet) Var(value Value, name string, usage string) { // Like Var, but accepts a shorthand letter that can be used after a single dash. func (f *FlagSet) VarP(value Value, name, shorthand, usage string) { // Remember the default value as a string; it won't change. - flag := &Flag{name, shorthand, usage, value, value.String(), false} + flag := &Flag{name, shorthand, usage, value, value.String(), false, make(map[string][]string)} f.AddFlag(flag) } diff --git a/cmd/gendocs/gen_kubectl_docs.go b/cmd/gendocs/gen_kubectl_docs.go index 64b3e545db6..d345d550c56 100644 --- a/cmd/gendocs/gen_kubectl_docs.go +++ b/cmd/gendocs/gen_kubectl_docs.go @@ -17,97 +17,16 @@ limitations under the License. package main import ( - "bytes" "fmt" "io/ioutil" "os" "path/filepath" - "strings" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd" cmdutil "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util" "github.com/spf13/cobra" ) -func printOptions(out *bytes.Buffer, command *cobra.Command, name string) { - flags := command.NonInheritedFlags() - flags.SetOutput(out) - if flags.HasFlags() { - fmt.Fprintf(out, "### Options\n\n```\n") - flags.PrintDefaults() - fmt.Fprintf(out, "```\n\n") - } - - parentFlags := command.InheritedFlags() - parentFlags.SetOutput(out) - if parentFlags.HasFlags() { - fmt.Fprintf(out, "### Options inherrited from parent commands\n\n```\n") - parentFlags.PrintDefaults() - fmt.Fprintf(out, "```\n\n") - } -} - -func genMarkdown(command *cobra.Command, parent, docsDir string) { - dparent := strings.Replace(parent, " ", "-", -1) - name := command.Name() - dname := name - if len(parent) > 0 { - dname = dparent + "-" + name - name = parent + " " + name - } - - out := new(bytes.Buffer) - short := command.Short - long := command.Long - if len(long) == 0 { - long = short - } - - fmt.Fprintf(out, "## %s\n\n", name) - fmt.Fprintf(out, "%s\n\n", short) - fmt.Fprintf(out, "### Synopsis\n\n") - fmt.Fprintf(out, "\n%s\n\n", long) - - if command.Runnable() { - fmt.Fprintf(out, "```\n%s\n```\n\n", command.UseLine()) - } - - if len(command.Example) > 0 { - fmt.Fprintf(out, "### Examples\n\n") - fmt.Fprintf(out, "```\n%s\n```\n\n", command.Example) - } - - printOptions(out, command, name) - - if len(command.Commands()) > 0 || len(parent) > 0 { - fmt.Fprintf(out, "### SEE ALSO\n") - if len(parent) > 0 { - link := dparent + ".md" - fmt.Fprintf(out, "* [%s](%s)\n", dparent, link) - } - for _, c := range command.Commands() { - child := dname + "-" + c.Name() - link := child + ".md" - fmt.Fprintf(out, "* [%s](%s)\n", child, link) - genMarkdown(c, name, docsDir) - } - fmt.Fprintf(out, "\n") - } - - filename := docsDir + dname + ".md" - outFile, err := os.Create(filename) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - defer outFile.Close() - _, err = outFile.Write(out.Bytes()) - if err != nil { - fmt.Println(err) - os.Exit(1) - } -} - func main() { // use os.Args instead of "flags" because "flags" will mess up the man pages! docsDir := "docs/man/man1/" @@ -141,8 +60,5 @@ func main() { os.Setenv("HOME", "/home/username") //TODO os.Stdin should really be something like ioutil.Discard, but a Reader kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard) - genMarkdown(kubectl, "", docsDir) - for _, c := range kubectl.Commands() { - genMarkdown(c, "kubectl", docsDir) - } + cobra.GenMarkdownTree(kubectl, docsDir) } diff --git a/docs/kubectl-apiversions.md b/docs/kubectl-apiversions.md deleted file mode 100644 index df88ca2083b..00000000000 --- a/docs/kubectl-apiversions.md +++ /dev/null @@ -1,52 +0,0 @@ -## kubectl api-versions - -Print available API versions. - -### Synopsis - - -Print available API versions. - -``` -kubectl api-versions -``` - -### Options - -``` - -h, --help=false: help for api-versions -``` - -### Options inherrited from parent commands - -``` - --alsologtostderr=false: log to standard error as well as files - --api-version="": The API version to use when talking to the server - -a, --auth-path="": Path to the auth info file. If missing, prompt the user. Only used if using https. - --certificate-authority="": Path to a cert. file for the certificate authority. - --client-certificate="": Path to a client key file for TLS. - --client-key="": Path to a client key file for TLS. - --cluster="": The name of the kubeconfig cluster to use - --context="": The name of the kubeconfig context to use - --insecure-skip-tls-verify=false: If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure. - --kubeconfig="": Path to the kubeconfig file to use for CLI requests. - --log_backtrace_at=:0: when logging hits line file:N, emit a stack trace - --log_dir=: If non-empty, write log files in this directory - --log_flush_frequency=5s: Maximum number of seconds between log flushes - --logtostderr=true: log to standard error instead of files - --match-server-version=false: Require server version to match client version - --namespace="": If present, the namespace scope for this CLI request. - --password="": Password for basic authentication to the API server. - -s, --server="": The address and port of the Kubernetes API server - --stderrthreshold=2: logs at or above this threshold go to stderr - --token="": Bearer token for authentication to the API server. - --user="": The name of the kubeconfig user to use - --username="": Username for basic authentication to the API server. - --v=0: log level for V logs - --validate=false: If true, use a schema to validate the input before sending it - --vmodule=: comma-separated list of pattern=N settings for file-filtered logging -``` - -### SEE ALSO -* [kubectl](kubectl.md) - diff --git a/docs/kubectl-clusterinfo.md b/docs/kubectl-clusterinfo.md deleted file mode 100644 index e2765aba5ec..00000000000 --- a/docs/kubectl-clusterinfo.md +++ /dev/null @@ -1,52 +0,0 @@ -## kubectl cluster-info - -Display cluster info - -### Synopsis - - -Display addresses of the master and services with label kubernetes.io/cluster-service=true - -``` -kubectl cluster-info -``` - -### Options - -``` - -h, --help=false: help for cluster-info -``` - -### Options inherrited from parent commands - -``` - --alsologtostderr=false: log to standard error as well as files - --api-version="": The API version to use when talking to the server - -a, --auth-path="": Path to the auth info file. If missing, prompt the user. Only used if using https. - --certificate-authority="": Path to a cert. file for the certificate authority. - --client-certificate="": Path to a client key file for TLS. - --client-key="": Path to a client key file for TLS. - --cluster="": The name of the kubeconfig cluster to use - --context="": The name of the kubeconfig context to use - --insecure-skip-tls-verify=false: If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure. - --kubeconfig="": Path to the kubeconfig file to use for CLI requests. - --log_backtrace_at=:0: when logging hits line file:N, emit a stack trace - --log_dir=: If non-empty, write log files in this directory - --log_flush_frequency=5s: Maximum number of seconds between log flushes - --logtostderr=true: log to standard error instead of files - --match-server-version=false: Require server version to match client version - --namespace="": If present, the namespace scope for this CLI request. - --password="": Password for basic authentication to the API server. - -s, --server="": The address and port of the Kubernetes API server - --stderrthreshold=2: logs at or above this threshold go to stderr - --token="": Bearer token for authentication to the API server. - --user="": The name of the kubeconfig user to use - --username="": Username for basic authentication to the API server. - --v=0: log level for V logs - --validate=false: If true, use a schema to validate the input before sending it - --vmodule=: comma-separated list of pattern=N settings for file-filtered logging -``` - -### SEE ALSO -* [kubectl](kubectl.md) - diff --git a/docs/kubectl.md b/docs/kubectl.md index cfc3dfd84bb..91fbafab545 100644 --- a/docs/kubectl.md +++ b/docs/kubectl.md @@ -45,24 +45,25 @@ kubectl ``` ### SEE ALSO -* [kubectl-get](kubectl-get.md) -* [kubectl-describe](kubectl-describe.md) -* [kubectl-create](kubectl-create.md) -* [kubectl-update](kubectl-update.md) -* [kubectl-delete](kubectl-delete.md) -* [kubectl-namespace](kubectl-namespace.md) -* [kubectl-log](kubectl-log.md) -* [kubectl-rolling-update](kubectl-rolling-update.md) -* [kubectl-resize](kubectl-resize.md) -* [kubectl-exec](kubectl-exec.md) -* [kubectl-port-forward](kubectl-port-forward.md) -* [kubectl-proxy](kubectl-proxy.md) -* [kubectl-run-container](kubectl-run-container.md) -* [kubectl-stop](kubectl-stop.md) -* [kubectl-expose](kubectl-expose.md) -* [kubectl-label](kubectl-label.md) -* [kubectl-config](kubectl-config.md) -* [kubectl-cluster-info](kubectl-cluster-info.md) -* [kubectl-api-versions](kubectl-api-versions.md) -* [kubectl-version](kubectl-version.md) +* [kubectl api-versions](kubectl_api-versions.md) - Print available API versions. +* [kubectl cluster-info](kubectl_cluster-info.md) - Display cluster info +* [kubectl config](kubectl_config.md) - config modifies kubeconfig files +* [kubectl create](kubectl_create.md) - Create a resource by filename or stdin +* [kubectl delete](kubectl_delete.md) - Delete a resource by filename, stdin, resource and ID, or by resources and label selector. +* [kubectl describe](kubectl_describe.md) - Show details of a specific resource +* [kubectl exec](kubectl_exec.md) - Execute a command in a container. +* [kubectl expose](kubectl_expose.md) - Take a replicated application and expose it as Kubernetes Service +* [kubectl get](kubectl_get.md) - Display one or many resources +* [kubectl label](kubectl_label.md) - Update the labels on a resource +* [kubectl log](kubectl_log.md) - Print the logs for a container in a pod. +* [kubectl namespace](kubectl_namespace.md) - SUPERCEDED: Set and view the current Kubernetes namespace +* [kubectl port-forward](kubectl_port-forward.md) - Forward one or more local ports to a pod. +* [kubectl proxy](kubectl_proxy.md) - Run a proxy to the Kubernetes API server +* [kubectl resize](kubectl_resize.md) - Set a new size for a Replication Controller. +* [kubectl rolling-update](kubectl_rolling-update.md) - Perform a rolling update of the given ReplicationController. +* [kubectl run-container](kubectl_run-container.md) - Run a particular image on the cluster. +* [kubectl stop](kubectl_stop.md) - Gracefully shut down a resource by id or filename. +* [kubectl update](kubectl_update.md) - Update a resource by filename or stdin. +* [kubectl version](kubectl_version.md) - Print the client and server version information. +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.865844658 +0000 UTC diff --git a/docs/kubectl-api-versions.md b/docs/kubectl_api-versions.md similarity index 93% rename from docs/kubectl-api-versions.md rename to docs/kubectl_api-versions.md index df88ca2083b..410331ae665 100644 --- a/docs/kubectl-api-versions.md +++ b/docs/kubectl_api-versions.md @@ -48,5 +48,6 @@ kubectl api-versions ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.865438603 +0000 UTC diff --git a/docs/kubectl-cluster-info.md b/docs/kubectl_cluster-info.md similarity index 93% rename from docs/kubectl-cluster-info.md rename to docs/kubectl_cluster-info.md index e2765aba5ec..7fd935536ce 100644 --- a/docs/kubectl-cluster-info.md +++ b/docs/kubectl_cluster-info.md @@ -48,5 +48,6 @@ kubectl cluster-info ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.865291243 +0000 UTC diff --git a/docs/kubectl-config.md b/docs/kubectl_config.md similarity index 73% rename from docs/kubectl-config.md rename to docs/kubectl_config.md index 3df9970f13d..7fc7133c13e 100644 --- a/docs/kubectl-config.md +++ b/docs/kubectl_config.md @@ -51,12 +51,13 @@ kubectl config SUBCOMMAND ``` ### SEE ALSO -* [kubectl](kubectl.md) -* [kubectl-config-view](kubectl-config-view.md) -* [kubectl-config-set-cluster](kubectl-config-set-cluster.md) -* [kubectl-config-set-credentials](kubectl-config-set-credentials.md) -* [kubectl-config-set-context](kubectl-config-set-context.md) -* [kubectl-config-set](kubectl-config-set.md) -* [kubectl-config-unset](kubectl-config-unset.md) -* [kubectl-config-use-context](kubectl-config-use-context.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +* [kubectl config set](kubectl_config_set.md) - Sets an individual value in a kubeconfig file +* [kubectl config set-cluster](kubectl_config_set-cluster.md) - Sets a cluster entry in kubeconfig +* [kubectl config set-context](kubectl_config_set-context.md) - Sets a context entry in kubeconfig +* [kubectl config set-credentials](kubectl_config_set-credentials.md) - Sets a user entry in kubeconfig +* [kubectl config unset](kubectl_config_unset.md) - Unsets an individual value in a kubeconfig file +* [kubectl config use-context](kubectl_config_use-context.md) - Sets the current-context in a kubeconfig file +* [kubectl config view](kubectl_config_view.md) - displays merged kubeconfig settings or a specified kubeconfig file. +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.86513156 +0000 UTC diff --git a/docs/kubectl-config-set-cluster.md b/docs/kubectl_config_set-cluster.md similarity index 95% rename from docs/kubectl-config-set-cluster.md rename to docs/kubectl_config_set-cluster.md index a13b4f01063..74786a4c3d7 100644 --- a/docs/kubectl-config-set-cluster.md +++ b/docs/kubectl_config_set-cluster.md @@ -66,5 +66,6 @@ $ kubectl config set-cluster e2e --insecure-skip-tls-verify=true ``` ### SEE ALSO -* [kubectl-config](kubectl-config.md) +* [kubectl config](kubectl_config.md) - config modifies kubeconfig files +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.864096021 +0000 UTC diff --git a/docs/kubectl-config-set-context.md b/docs/kubectl_config_set-context.md similarity index 94% rename from docs/kubectl-config-set-context.md rename to docs/kubectl_config_set-context.md index b68df1e8c8a..d9eec2d6c1b 100644 --- a/docs/kubectl-config-set-context.md +++ b/docs/kubectl_config_set-context.md @@ -59,5 +59,6 @@ $ kubectl config set-context gce --user=cluster-admin ``` ### SEE ALSO -* [kubectl-config](kubectl-config.md) +* [kubectl config](kubectl_config.md) - config modifies kubeconfig files +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.86442717 +0000 UTC diff --git a/docs/kubectl-config-set-credentials.md b/docs/kubectl_config_set-credentials.md similarity index 95% rename from docs/kubectl-config-set-credentials.md rename to docs/kubectl_config_set-credentials.md index 69aa859557d..e31879543b6 100644 --- a/docs/kubectl-config-set-credentials.md +++ b/docs/kubectl_config_set-credentials.md @@ -79,5 +79,6 @@ $ kubectl set-credentials cluster-admin --client-certificate=~/.kube/admin.crt - ``` ### SEE ALSO -* [kubectl-config](kubectl-config.md) +* [kubectl config](kubectl_config.md) - config modifies kubeconfig files +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.864263862 +0000 UTC diff --git a/docs/kubectl-config-set.md b/docs/kubectl_config_set.md similarity index 94% rename from docs/kubectl-config-set.md rename to docs/kubectl_config_set.md index 9480ca9c35d..78b1f0e85de 100644 --- a/docs/kubectl-config-set.md +++ b/docs/kubectl_config_set.md @@ -53,5 +53,6 @@ kubectl config set PROPERTY_NAME PROPERTY_VALUE ``` ### SEE ALSO -* [kubectl-config](kubectl-config.md) +* [kubectl config](kubectl_config.md) - config modifies kubeconfig files +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.864594301 +0000 UTC diff --git a/docs/kubectl-config-unset.md b/docs/kubectl_config_unset.md similarity index 94% rename from docs/kubectl-config-unset.md rename to docs/kubectl_config_unset.md index cbf5bddae8e..be412e68019 100644 --- a/docs/kubectl-config-unset.md +++ b/docs/kubectl_config_unset.md @@ -52,5 +52,6 @@ kubectl config unset PROPERTY_NAME ``` ### SEE ALSO -* [kubectl-config](kubectl-config.md) +* [kubectl config](kubectl_config.md) - config modifies kubeconfig files +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.864788809 +0000 UTC diff --git a/docs/kubectl-config-use-context.md b/docs/kubectl_config_use-context.md similarity index 93% rename from docs/kubectl-config-use-context.md rename to docs/kubectl_config_use-context.md index af49950653c..e7e45733545 100644 --- a/docs/kubectl-config-use-context.md +++ b/docs/kubectl_config_use-context.md @@ -51,5 +51,6 @@ kubectl config use-context CONTEXT_NAME ``` ### SEE ALSO -* [kubectl-config](kubectl-config.md) +* [kubectl config](kubectl_config.md) - config modifies kubeconfig files +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.864953658 +0000 UTC diff --git a/docs/kubectl-config-view.md b/docs/kubectl_config_view.md similarity index 95% rename from docs/kubectl-config-view.md rename to docs/kubectl_config_view.md index 1db8654ec34..56378b12575 100644 --- a/docs/kubectl-config-view.md +++ b/docs/kubectl_config_view.md @@ -71,5 +71,6 @@ $ kubectl config view -o template --template='{{range .users}}{{ if eq .name "e2 ``` ### SEE ALSO -* [kubectl-config](kubectl-config.md) +* [kubectl config](kubectl_config.md) - config modifies kubeconfig files +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.863759642 +0000 UTC diff --git a/docs/kubectl-create.md b/docs/kubectl_create.md similarity index 94% rename from docs/kubectl-create.md rename to docs/kubectl_create.md index 5499da03e6e..ee2b5568b57 100644 --- a/docs/kubectl-create.md +++ b/docs/kubectl_create.md @@ -61,5 +61,6 @@ $ cat pod.json | kubectl create -f - ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.858089037 +0000 UTC diff --git a/docs/kubectl-delete.md b/docs/kubectl_delete.md similarity index 95% rename from docs/kubectl-delete.md rename to docs/kubectl_delete.md index 5c1ceb70000..ca044bbf5df 100644 --- a/docs/kubectl-delete.md +++ b/docs/kubectl_delete.md @@ -79,5 +79,6 @@ $ kubectl delete pods --all ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.858739718 +0000 UTC diff --git a/docs/kubectl-describe.md b/docs/kubectl_describe.md similarity index 93% rename from docs/kubectl-describe.md rename to docs/kubectl_describe.md index e79c4526fd8..8115b45265e 100644 --- a/docs/kubectl-describe.md +++ b/docs/kubectl_describe.md @@ -51,5 +51,6 @@ kubectl describe RESOURCE ID ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.857744518 +0000 UTC diff --git a/docs/kubectl-exec.md b/docs/kubectl_exec.md similarity index 94% rename from docs/kubectl-exec.md rename to docs/kubectl_exec.md index e2b75f10871..3df8ac7b730 100644 --- a/docs/kubectl-exec.md +++ b/docs/kubectl_exec.md @@ -62,5 +62,6 @@ $ kubectl exec -p 123456-7890 -c ruby-container -i -t -- bash -il ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.860311374 +0000 UTC diff --git a/docs/kubectl-expose.md b/docs/kubectl_expose.md similarity index 96% rename from docs/kubectl-expose.md rename to docs/kubectl_expose.md index 377f64d8662..689889d2308 100644 --- a/docs/kubectl-expose.md +++ b/docs/kubectl_expose.md @@ -80,5 +80,6 @@ $ kubectl expose streamer --port=4100 --protocol=udp --service-name=video-stream ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.863051668 +0000 UTC diff --git a/docs/kubectl-get.md b/docs/kubectl_get.md similarity index 96% rename from docs/kubectl-get.md rename to docs/kubectl_get.md index 34062025a7a..3bb1f16f101 100644 --- a/docs/kubectl-get.md +++ b/docs/kubectl_get.md @@ -83,5 +83,6 @@ $ kubectl get rc/web service/frontend pods/web-pod-13je7 ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.836684094 +0000 UTC diff --git a/docs/kubectl-label.md b/docs/kubectl_label.md similarity index 96% rename from docs/kubectl-label.md rename to docs/kubectl_label.md index 0c7824aedf9..185689834ea 100644 --- a/docs/kubectl-label.md +++ b/docs/kubectl_label.md @@ -79,5 +79,6 @@ $ kubectl label pods foo bar- ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.863412074 +0000 UTC diff --git a/docs/kubectl-log.md b/docs/kubectl_log.md similarity index 94% rename from docs/kubectl-log.md rename to docs/kubectl_log.md index 1e3510ad934..c9175c744ec 100644 --- a/docs/kubectl-log.md +++ b/docs/kubectl_log.md @@ -60,5 +60,6 @@ $ kubectl log -f 123456-7890 ruby-container ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.859351191 +0000 UTC diff --git a/docs/kubectl-namespace.md b/docs/kubectl_namespace.md similarity index 93% rename from docs/kubectl-namespace.md rename to docs/kubectl_namespace.md index 7f7c68961b0..ca006c270fa 100644 --- a/docs/kubectl-namespace.md +++ b/docs/kubectl_namespace.md @@ -51,5 +51,6 @@ kubectl namespace [namespace] ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.859053402 +0000 UTC diff --git a/docs/kubectl-port-forward.md b/docs/kubectl_port-forward.md similarity index 94% rename from docs/kubectl-port-forward.md rename to docs/kubectl_port-forward.md index 425e6ec0451..2a93e7848fa 100644 --- a/docs/kubectl-port-forward.md +++ b/docs/kubectl_port-forward.md @@ -66,5 +66,6 @@ $ kubectl port-forward -p mypod 0:5000 ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.860596821 +0000 UTC diff --git a/docs/kubectl-proxy.md b/docs/kubectl_proxy.md similarity index 94% rename from docs/kubectl-proxy.md rename to docs/kubectl_proxy.md index 48f37e41b7e..f11bfaed6a0 100644 --- a/docs/kubectl-proxy.md +++ b/docs/kubectl_proxy.md @@ -63,5 +63,6 @@ $ kubectl proxy --api-prefix=k8s-api ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.860912037 +0000 UTC diff --git a/docs/kubectl-resize.md b/docs/kubectl_resize.md similarity index 95% rename from docs/kubectl-resize.md rename to docs/kubectl_resize.md index 42a44a066ad..6482643d1b6 100644 --- a/docs/kubectl-resize.md +++ b/docs/kubectl_resize.md @@ -66,5 +66,6 @@ $ kubectl resize --current-replicas=2 --replicas=3 replicationcontrollers foo ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.859972905 +0000 UTC diff --git a/docs/kubectl-rolling-update.md b/docs/kubectl_rolling-update.md similarity index 95% rename from docs/kubectl-rolling-update.md rename to docs/kubectl_rolling-update.md index b4d188312f5..8501878d3a0 100644 --- a/docs/kubectl-rolling-update.md +++ b/docs/kubectl_rolling-update.md @@ -66,5 +66,6 @@ $ cat frontend-v2.json | kubectl rolling-update frontend-v1 -f - ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.859654934 +0000 UTC diff --git a/docs/kubectl-run-container.md b/docs/kubectl_run-container.md similarity index 96% rename from docs/kubectl-run-container.md rename to docs/kubectl_run-container.md index dfbde8a8d1b..b9c1c290b51 100644 --- a/docs/kubectl-run-container.md +++ b/docs/kubectl_run-container.md @@ -76,5 +76,6 @@ $ kubectl run-container nginx --image=dockerfile/nginx --overrides='{ "apiVersio ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.861280128 +0000 UTC diff --git a/docs/kubectl-stop.md b/docs/kubectl_stop.md similarity index 94% rename from docs/kubectl-stop.md rename to docs/kubectl_stop.md index 4da057ad766..c1fa7858133 100644 --- a/docs/kubectl-stop.md +++ b/docs/kubectl_stop.md @@ -70,5 +70,6 @@ $ kubectl stop -f path/to/resources ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.862654585 +0000 UTC diff --git a/docs/kubectl-update.md b/docs/kubectl_update.md similarity index 94% rename from docs/kubectl-update.md rename to docs/kubectl_update.md index 52af1e12a52..02600a4b74c 100644 --- a/docs/kubectl-update.md +++ b/docs/kubectl_update.md @@ -65,5 +65,6 @@ $ kubectl update pods my-pod --patch='{ "apiVersion": "v1beta1", "desiredState": ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.858390462 +0000 UTC diff --git a/docs/kubectl-version.md b/docs/kubectl_version.md similarity index 93% rename from docs/kubectl-version.md rename to docs/kubectl_version.md index a2c3f1ab298..eaf76fd9a81 100644 --- a/docs/kubectl-version.md +++ b/docs/kubectl_version.md @@ -49,5 +49,6 @@ kubectl version ``` ### SEE ALSO -* [kubectl](kubectl.md) +* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.865600008 +0000 UTC diff --git a/hack/verify-gendocs.sh b/hack/verify-gendocs.sh index a11e8a458c8..33ba6babf60 100755 --- a/hack/verify-gendocs.sh +++ b/hack/verify-gendocs.sh @@ -98,7 +98,7 @@ echo "diffing ${DOCROOT} against generated output from ${genman}" ${genman} "${TMP_DOCROOT}/man/man1/" ${gendocs} "${TMP_DOCROOT}" set +e -diff -Naupr "${DOCROOT}" "${TMP_DOCROOT}" +diff -Naupr -I 'Auto generated by' "${DOCROOT}" "${TMP_DOCROOT}" ret=$? set -e rm -rf "${TMP_DOCROOT}"