Repository: spf13/cobra (go)

Issue:
GenManTree and GenMarkdownTree require the output directory to exists. No error shown.
I was trying `GenManTree` and `GenMarkdownTree` unsuccessfully but without any error, until I realized that the directory in which the results are to be saved must exist prior to executing the binary. I think it would be helpful to make cobra either:

- Display an error message if the target directory does not exist.
- Create the target directory.

Pull request description:
Fix #401
* doc: Add and edit docs
* doc: Add tests

Fixes #401

Patch:
diff --git a/README.md b/README.md
index 2de9840..0d5bbfb 100644
--- a/README.md
+++ b/README.md
@@ -168,7 +168,7 @@ import (
 func main() {
 	if err := cmd.RootCmd.Execute(); err != nil {
 		fmt.Println(err)
-		os.Exit(-1)
+		os.Exit(1)
 	}
 }
 ```
@@ -329,7 +329,7 @@ import (
 func main() {
 	if err := cmd.RootCmd.Execute(); err != nil {
 		fmt.Println(err)
-		os.Exit(-1)
+		os.Exit(1)
 	}
 }
 ```
diff --git a/bash_completions.go b/bash_completions.go
index 8820ba8..a0d0402 100644
--- a/bash_completions.go
+++ b/bash_completions.go
@@ -88,8 +88,8 @@ __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}]}
@@ -225,7 +225,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()
diff --git a/cobra.go b/cobra.go
index 9605b98..25473a7 100644
--- a/cobra.go
+++ b/cobra.go
@@ -52,7 +52,7 @@ func AddTemplateFunc(name string, tmplFunc interface{}) {
 	templateFuncs[name] = tmplFunc
 }
 
-// AddTemplateFuncs adds multiple template functions availalble to Usage and
+// AddTemplateFuncs adds multiple template functions that are available to Usage and
 // Help template generation.
 func AddTemplateFuncs(tmplFuncs template.FuncMap) {
 	for k, v := range tmplFuncs {
diff --git a/command.go b/command.go
index 664bf5a..f4cd95c 100644
--- a/command.go
+++ b/command.go
@@ -113,7 +113,7 @@ type Command struct {
 	flagErrorBuf *bytes.Buffer
 
 	args          []string             // actual args parsed from flags
-	output        *io.Writer           // out writer if set in SetOutput(w)
+	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
 	flagErrorFunc func(*Command, error) error
@@ -141,7 +141,7 @@ 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
 }
 
 // SetUsageFunc sets usage function. Usage can be defined by application.
@@ -199,7 +199,7 @@ func (c *Command) OutOrStderr() io.Writer {
 
 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)
@@ -341,8 +341,7 @@ func (c *Command) UsageTemplate() string {
   {{ .CommandPath}} [command]{{end}}{{if gt .Aliases 0}}
 
 Aliases:
-  {{.NameAndAliases}}
-{{end}}{{if .HasExample}}
+  {{.NameAndAliases}}{{end}}{{if .HasExample}}
 
 Examples:
 {{ .Example }}{{end}}{{if .HasAvailableSubCommands}}
diff --git a/doc/man_docs.go b/doc/man_docs.go
index b9266c3..1f90c44 100644
--- a/doc/man_docs.go
+++ b/doc/man_docs.go
@@ -30,8 +30,8 @@ import (
 
 // 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{
diff --git a/doc/man_docs.md b/doc/man_docs.md
index d568d9a..3709160 100644
--- a/doc/man_docs.md
+++ b/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"
 )
@@ -19,7 +21,10 @@ func main() {
 		Title: "MINE",
 		Section: "3",
 	}
-	doc.GenManTree(cmd, header, "/tmp")
+	err := doc.GenManTree(cmd, header, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
 }
 ```
 
diff --git a/doc/md_docs.go b/doc/md_docs.go
index 8d159c1..408d2f7 100644
--- a/doc/md_docs.go
+++ b/doc/md_docs.go
@@ -52,10 +52,12 @@ func printOptions(w io.Writer, cmd *cobra.Command, name string) error {
 	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 {
 	name := cmd.CommandPath()
 
@@ -141,6 +143,12 @@ func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string)
 	return nil
 }
 
+// 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 "" }
diff --git a/doc/md_docs.md b/doc/md_docs.md
index beec3e0..56ce9fe 100644
--- a/doc/md_docs.md
+++ b/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,6 +34,7 @@ This program can actually generate docs for the kubectl command in the kubernete
 package main
 
 import (
+	"log"
 	"io/ioutil"
 	"os"
 
@@ -40,7 +46,10 @@ import (
 
 func main() {
 	kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
-	doc.GenMarkdownTree(kubectl, "./")
+	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.
diff --git a/doc/yaml_docs.go b/doc/yaml_docs.go
index ac8db89..f5cd5a3 100644
--- a/doc/yaml_docs.go
+++ b/doc/yaml_docs.go
@@ -45,8 +45,8 @@ type cmdDoc struct {
 
 // 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`
+// 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 }
@@ -54,7 +54,7 @@ func GenYamlTree(cmd *cobra.Command, dir string) error {
 	return GenYamlTreeCustom(cmd, dir, emptyStr, identity)
 }
 
-// GenYamlTreeCustom creates yaml structured ref files
+// 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() {
@@ -82,12 +82,12 @@ func GenYamlTreeCustom(cmd *cobra.Command, dir string, filePrepender, linkHandle
 	return nil
 }
 
-// GenYaml creates yaml output
+// 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
+// GenYamlCustom creates custom yaml output.
 func GenYamlCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) string) error {
 	yamlDoc := cmdDoc{}
 	yamlDoc.Name = cmd.CommandPath()
diff --git a/doc/yaml_docs.md b/doc/yaml_docs.md
index 4d0c75a..1a9b7c6 100644
--- a/doc/yaml_docs.md
+++ b/doc/yaml_docs.md
@@ -6,6 +6,8 @@ Generating yaml files from a cobra command is incredibly easy. An example is as
 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.GenYamlTree(cmd, "/tmp")
+	err := doc.GenYamlTree(cmd, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
 }
 ```
 
@@ -30,6 +35,7 @@ package main
 
 import (
 	"io/ioutil"
+	"log"
 	"os"
 
 	"k8s.io/kubernetes/pkg/kubectl/cmd"
@@ -40,7 +46,10 @@ import (
 
 func main() {
 	kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
-	doc.GenYamlTree(kubectl, "./")
+	err := doc.GenYamlTree(kubectl, "./")
+	if err != nil {
+		log.Fatal(err)
+	}
 }
 ```
 


Test patch:
diff --git a/command_test.go b/command_test.go
index 7947f6c..8b78ee3 100644
--- a/command_test.go
+++ b/command_test.go
@@ -191,6 +191,14 @@ func TestEnableCommandSortingIsDisabled(t *testing.T) {
 	EnableCommandSorting = true
 }
 
+func TestSetOutput(t *testing.T) {
+	cmd := &Command{}
+	cmd.SetOutput(nil)
+	if out := cmd.OutOrStdout(); out != os.Stdout {
+		t.Fatalf("expected setting output to nil to revert back to stdout, got %v", out)
+	}
+}
+
 func TestFlagErrorFunc(t *testing.T) {
 
 	cmd := &Command{
diff --git a/doc/man_docs_test.go b/doc/man_docs_test.go
index 26b8fcc..9b27291 100644
--- a/doc/man_docs_test.go
+++ b/doc/man_docs_test.go
@@ -13,9 +13,6 @@ import (
 	"github.com/spf13/cobra"
 )
 
-var _ = fmt.Println
-var _ = os.Stderr
-
 func translate(in string) string {
 	return strings.Replace(in, "-", "\\-", -1)
 }
@@ -153,7 +150,7 @@ func TestGenManTree(t *testing.T) {
 	header := &GenManHeader{Section: "2"}
 	tmpdir, err := ioutil.TempDir("", "test-gen-man-tree")
 	if err != nil {
-		t.Fatalf("Failed to create tempdir: %s", err.Error())
+		t.Fatalf("Failed to create tmpdir: %s", err.Error())
 	}
 	defer os.RemoveAll(tmpdir)
 
diff --git a/doc/man_examples_test.go b/doc/man_examples_test.go
index 3593853..db66042 100644
--- a/doc/man_examples_test.go
+++ b/doc/man_examples_test.go
@@ -8,7 +8,7 @@ import (
 	"github.com/spf13/cobra/doc"
 )
 
-func ExampleCommand_GenManTree() {
+func ExampleGenManTree() {
 	cmd := &cobra.Command{
 		Use:   "test",
 		Short: "my test program",
@@ -20,7 +20,7 @@ func ExampleCommand_GenManTree() {
 	doc.GenManTree(cmd, header, "/tmp")
 }
 
-func ExampleCommand_GenMan() {
+func ExampleGenMan() {
 	cmd := &cobra.Command{
 		Use:   "test",
 		Short: "my test program",
diff --git a/doc/md_docs_test.go b/doc/md_docs_test.go
index 86ee029..f4f3bc1 100644
--- a/doc/md_docs_test.go
+++ b/doc/md_docs_test.go
@@ -2,14 +2,14 @@ package doc
 
 import (
 	"bytes"
-	"fmt"
+	"io/ioutil"
 	"os"
+	"path/filepath"
 	"strings"
 	"testing"
-)
 
-var _ = fmt.Println
-var _ = os.Stderr
+	"github.com/spf13/cobra"
+)
 
 func TestGenMdDoc(t *testing.T) {
 	c := initializeWithRootCmd()
@@ -86,3 +86,22 @@ func TestGenMdNoTag(t *testing.T) {
 	checkStringOmits(t, found, unexpected)
 
 }
+
+func TestGenMdTree(t *testing.T) {
+	cmd := &cobra.Command{
+		Use: "do [OPTIONS] arg1 arg2",
+	}
+	tmpdir, err := ioutil.TempDir("", "test-gen-md-tree")
+	if err != nil {
+		t.Fatalf("Failed to create tmpdir: %s", err.Error())
+	}
+	defer os.RemoveAll(tmpdir)
+
+	if err := GenMarkdownTree(cmd, tmpdir); err != nil {
+		t.Fatalf("GenMarkdownTree failed: %s", err.Error())
+	}
+
+	if _, err := os.Stat(filepath.Join(tmpdir, "do.md")); err != nil {
+		t.Fatalf("Expected file 'do.md' to exist")
+	}
+}
diff --git a/doc/yaml_docs_test.go b/doc/yaml_docs_test.go
index a41499e..fb969da 100644
--- a/doc/yaml_docs_test.go
+++ b/doc/yaml_docs_test.go
@@ -2,14 +2,14 @@ package doc
 
 import (
 	"bytes"
-	"fmt"
+	"io/ioutil"
 	"os"
+	"path/filepath"
 	"strings"
 	"testing"
-)
 
-var _ = fmt.Println
-var _ = os.Stderr
+	"github.com/spf13/cobra"
+)
 
 func TestGenYamlDoc(t *testing.T) {
 	c := initializeWithRootCmd()
@@ -86,3 +86,23 @@ func TestGenYamlNoTag(t *testing.T) {
 	checkStringOmits(t, found, unexpected)
 
 }
+
+func TestGenYamlTree(t *testing.T) {
+	cmd := &cobra.Command{
+		Use: "do [OPTIONS] arg1 arg2",
+	}
+
+	tmpdir, err := ioutil.TempDir("", "test-gen-yaml-tree")
+	if err != nil {
+		t.Fatalf("Failed to create tmpdir: %s", err.Error())
+	}
+	defer os.RemoveAll(tmpdir)
+
+	if err := GenYamlTree(cmd, tmpdir); err != nil {
+		t.Fatalf("GenYamlTree failed: %s", err.Error())
+	}
+
+	if _, err := os.Stat(filepath.Join(tmpdir, "do.yaml")); err != nil {
+		t.Fatalf("Expected file 'do.yaml' to exist")
+	}
+}