Merge pull request #294 from dnephin/fix_man_page_gen_bugs
Fix man page gen bugs
This commit is contained in:
		@ -34,6 +34,17 @@ import (
 | 
				
			|||||||
// subcmds, `sub` and `sub-third`. And `sub` has a subcommand called `third`
 | 
					// 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`.
 | 
					// 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 {
 | 
					func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error {
 | 
				
			||||||
 | 
						return GenManTreeFromOpts(cmd, GenManTreeOptions{
 | 
				
			||||||
 | 
							Header:           header,
 | 
				
			||||||
 | 
							Path:             dir,
 | 
				
			||||||
 | 
							CommandSeparator: "_",
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GenManTreeFromOpts generates a man page for the command and all descendants.
 | 
				
			||||||
 | 
					// The pages are written to the opts.Path directory.
 | 
				
			||||||
 | 
					func GenManTreeFromOpts(cmd *cobra.Command, opts GenManTreeOptions) error {
 | 
				
			||||||
 | 
						header := opts.Header
 | 
				
			||||||
	if header == nil {
 | 
						if header == nil {
 | 
				
			||||||
		header = &GenManHeader{}
 | 
							header = &GenManHeader{}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -41,28 +52,35 @@ func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error {
 | 
				
			|||||||
		if !c.IsAvailableCommand() || c.IsHelpCommand() {
 | 
							if !c.IsAvailableCommand() || c.IsHelpCommand() {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err := GenManTree(c, header, dir); err != nil {
 | 
							if err := GenManTreeFromOpts(c, opts); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	needToResetTitle := header.Title == ""
 | 
						section := "1"
 | 
				
			||||||
 | 
						if header.Section != "" {
 | 
				
			||||||
 | 
							section = header.Section
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + ".1"
 | 
						separator := "_"
 | 
				
			||||||
	filename := filepath.Join(dir, basename)
 | 
						if opts.CommandSeparator != "" {
 | 
				
			||||||
 | 
							separator = opts.CommandSeparator
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						basename := strings.Replace(cmd.CommandPath(), " ", separator, -1)
 | 
				
			||||||
 | 
						filename := filepath.Join(opts.Path, basename + "." + section)
 | 
				
			||||||
	f, err := os.Create(filename)
 | 
						f, err := os.Create(filename)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer f.Close()
 | 
						defer f.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := GenMan(cmd, header, f); err != nil {
 | 
						headerCopy := *header
 | 
				
			||||||
		return err
 | 
						return GenMan(cmd, &headerCopy, f)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if needToResetTitle {
 | 
					type GenManTreeOptions struct {
 | 
				
			||||||
		header.Title = ""
 | 
						Header           *GenManHeader
 | 
				
			||||||
	}
 | 
						Path             string
 | 
				
			||||||
	return nil
 | 
						CommandSeparator string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GenManHeader is a lot like the .TH header at the start of man pages. These
 | 
					// GenManHeader is a lot like the .TH header at the start of man pages. These
 | 
				
			||||||
@ -84,9 +102,10 @@ func GenMan(cmd *cobra.Command, header *GenManHeader, w io.Writer) error {
 | 
				
			|||||||
	if header == nil {
 | 
						if header == nil {
 | 
				
			||||||
		header = &GenManHeader{}
 | 
							header = &GenManHeader{}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						fillHeader(header, cmd.CommandPath())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	b := genMan(cmd, header)
 | 
						b := genMan(cmd, header)
 | 
				
			||||||
	final := mangen.Render(b)
 | 
						_, err := w.Write(mangen.Render(b))
 | 
				
			||||||
	_, err := w.Write(final)
 | 
					 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -107,18 +126,22 @@ func fillHeader(header *GenManHeader, name string) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func manPreamble(out io.Writer, header *GenManHeader, name, short, long string) {
 | 
					func manPreamble(out io.Writer, header *GenManHeader, cmd *cobra.Command, dashedName string) {
 | 
				
			||||||
	dashName := strings.Replace(name, " ", "-", -1)
 | 
						description := cmd.Long
 | 
				
			||||||
 | 
						if len(description) == 0 {
 | 
				
			||||||
 | 
							description = cmd.Short
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fmt.Fprintf(out, `%% %s(%s)%s
 | 
						fmt.Fprintf(out, `%% %s(%s)%s
 | 
				
			||||||
%% %s
 | 
					%% %s
 | 
				
			||||||
%% %s
 | 
					%% %s
 | 
				
			||||||
# NAME
 | 
					# NAME
 | 
				
			||||||
`, header.Title, header.Section, header.date, header.Source, header.Manual)
 | 
					`, header.Title, header.Section, header.date, header.Source, header.Manual)
 | 
				
			||||||
	fmt.Fprintf(out, "%s \\- %s\n\n", dashName, short)
 | 
						fmt.Fprintf(out, "%s \\- %s\n\n", dashedName, cmd.Short)
 | 
				
			||||||
	fmt.Fprintf(out, "# SYNOPSIS\n")
 | 
						fmt.Fprintf(out, "# SYNOPSIS\n")
 | 
				
			||||||
	fmt.Fprintf(out, "**%s** [OPTIONS]\n\n", name)
 | 
						fmt.Fprintf(out, "**%s**\n\n", cmd.UseLine())
 | 
				
			||||||
	fmt.Fprintf(out, "# DESCRIPTION\n")
 | 
						fmt.Fprintf(out, "# DESCRIPTION\n")
 | 
				
			||||||
	fmt.Fprintf(out, "%s\n\n", long)
 | 
						fmt.Fprintf(out, "%s\n\n", description)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func manPrintFlags(out io.Writer, flags *pflag.FlagSet) {
 | 
					func manPrintFlags(out io.Writer, flags *pflag.FlagSet) {
 | 
				
			||||||
@ -127,10 +150,10 @@ func manPrintFlags(out io.Writer, flags *pflag.FlagSet) {
 | 
				
			|||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		format := ""
 | 
							format := ""
 | 
				
			||||||
		if len(flag.Shorthand) > 0 {
 | 
							if len(flag.Shorthand) > 0 && len(flag.ShorthandDeprecated) == 0 {
 | 
				
			||||||
			format = "**-%s**, **--%s**"
 | 
								format = fmt.Sprintf("**-%s**, **--%s**", flag.Shorthand, flag.Name)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			format = "%s**--%s**"
 | 
								format = fmt.Sprintf("**--%s**", flag.Name)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if len(flag.NoOptDefVal) > 0 {
 | 
							if len(flag.NoOptDefVal) > 0 {
 | 
				
			||||||
			format = format + "["
 | 
								format = format + "["
 | 
				
			||||||
@ -145,7 +168,7 @@ func manPrintFlags(out io.Writer, flags *pflag.FlagSet) {
 | 
				
			|||||||
			format = format + "]"
 | 
								format = format + "]"
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		format = format + "\n\t%s\n\n"
 | 
							format = format + "\n\t%s\n\n"
 | 
				
			||||||
		fmt.Fprintf(out, format, flag.Shorthand, flag.Name, flag.DefValue, flag.Usage)
 | 
							fmt.Fprintf(out, format, flag.DefValue, flag.Usage)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -165,22 +188,12 @@ func manPrintOptions(out io.Writer, command *cobra.Command) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func genMan(cmd *cobra.Command, header *GenManHeader) []byte {
 | 
					func genMan(cmd *cobra.Command, header *GenManHeader) []byte {
 | 
				
			||||||
	// something like `rootcmd subcmd1 subcmd2`
 | 
					 | 
				
			||||||
	commandName := cmd.CommandPath()
 | 
					 | 
				
			||||||
	// something like `rootcmd-subcmd1-subcmd2`
 | 
						// something like `rootcmd-subcmd1-subcmd2`
 | 
				
			||||||
	dashCommandName := strings.Replace(commandName, " ", "-", -1)
 | 
						dashCommandName := strings.Replace(cmd.CommandPath(), " ", "-", -1)
 | 
				
			||||||
 | 
					 | 
				
			||||||
	fillHeader(header, commandName)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buf := new(bytes.Buffer)
 | 
						buf := new(bytes.Buffer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	short := cmd.Short
 | 
						manPreamble(buf, header, cmd, dashCommandName)
 | 
				
			||||||
	long := cmd.Long
 | 
					 | 
				
			||||||
	if len(long) == 0 {
 | 
					 | 
				
			||||||
		long = short
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	manPreamble(buf, header, commandName, short, long)
 | 
					 | 
				
			||||||
	manPrintOptions(buf, cmd)
 | 
						manPrintOptions(buf, cmd)
 | 
				
			||||||
	if len(cmd.Example) > 0 {
 | 
						if len(cmd.Example) > 0 {
 | 
				
			||||||
		fmt.Fprintf(buf, "# EXAMPLE\n")
 | 
							fmt.Fprintf(buf, "# EXAMPLE\n")
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,9 @@ import (
 | 
				
			|||||||
	"bufio"
 | 
						"bufio"
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -129,6 +131,45 @@ func TestGenManSeeAlso(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestManPrintFlagsHidesShortDeperecated(t *testing.T) {
 | 
				
			||||||
 | 
						cmd := &cobra.Command{}
 | 
				
			||||||
 | 
						flags := cmd.Flags()
 | 
				
			||||||
 | 
						flags.StringP("foo", "f", "default", "Foo flag")
 | 
				
			||||||
 | 
						flags.MarkShorthandDeprecated("foo", "don't use it no more")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						out := new(bytes.Buffer)
 | 
				
			||||||
 | 
						manPrintFlags(out, flags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						expected := "**--foo**=\"default\"\n\tFoo flag\n\n"
 | 
				
			||||||
 | 
						if out.String() != expected {
 | 
				
			||||||
 | 
							t.Fatalf("Expected %s, but got %s", expected, out.String())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestGenManTree(t *testing.T) {
 | 
				
			||||||
 | 
						cmd := &cobra.Command{
 | 
				
			||||||
 | 
							Use: "do [OPTIONS] arg1 arg2",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						header := &GenManHeader{Section: "2"}
 | 
				
			||||||
 | 
						tmpdir, err := ioutil.TempDir("", "test-gen-man-tree")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("Failed to create tempdir: %s", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer os.RemoveAll(tmpdir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := GenManTree(cmd, header, tmpdir); err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("GenManTree failed: %s", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err := os.Stat(filepath.Join(tmpdir, "do.2")); err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("Expected file 'do.2' to exist")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if header.Title != "" {
 | 
				
			||||||
 | 
							t.Fatalf("Expected header.Title to be unmodified")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func AssertLineFound(scanner *bufio.Scanner, expectedLine string) error {
 | 
					func AssertLineFound(scanner *bufio.Scanner, expectedLine string) error {
 | 
				
			||||||
	for scanner.Scan() {
 | 
						for scanner.Scan() {
 | 
				
			||||||
		line := scanner.Text()
 | 
							line := scanner.Text()
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user