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`
 | 
			
		||||
// it is undefined which help output will be in the file `cmd-sub-third.1`.
 | 
			
		||||
func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error {
 | 
			
		||||
	return GenManTreeFromOpts(cmd, GenManTreeOptions{
 | 
			
		||||
		Header:           header,
 | 
			
		||||
		Path:             dir,
 | 
			
		||||
		CommandSeparator: "_",
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 {
 | 
			
		||||
		header = &GenManHeader{}
 | 
			
		||||
	}
 | 
			
		||||
@ -41,28 +52,35 @@ func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error {
 | 
			
		||||
		if !c.IsAvailableCommand() || c.IsHelpCommand() {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if err := GenManTree(c, header, dir); err != nil {
 | 
			
		||||
		if err := GenManTreeFromOpts(c, opts); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	needToResetTitle := header.Title == ""
 | 
			
		||||
	section := "1"
 | 
			
		||||
	if header.Section != "" {
 | 
			
		||||
		section = header.Section
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + ".1"
 | 
			
		||||
	filename := filepath.Join(dir, basename)
 | 
			
		||||
	separator := "_"
 | 
			
		||||
	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)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	if err := GenMan(cmd, header, f); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	headerCopy := *header
 | 
			
		||||
	return GenMan(cmd, &headerCopy, f)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	if needToResetTitle {
 | 
			
		||||
		header.Title = ""
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
type GenManTreeOptions struct {
 | 
			
		||||
	Header           *GenManHeader
 | 
			
		||||
	Path             string
 | 
			
		||||
	CommandSeparator string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 {
 | 
			
		||||
		header = &GenManHeader{}
 | 
			
		||||
	}
 | 
			
		||||
	fillHeader(header, cmd.CommandPath())
 | 
			
		||||
 | 
			
		||||
	b := genMan(cmd, header)
 | 
			
		||||
	final := mangen.Render(b)
 | 
			
		||||
	_, err := w.Write(final)
 | 
			
		||||
	_, err := w.Write(mangen.Render(b))
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -107,18 +126,22 @@ func fillHeader(header *GenManHeader, name string) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func manPreamble(out io.Writer, header *GenManHeader, name, short, long string) {
 | 
			
		||||
	dashName := strings.Replace(name, " ", "-", -1)
 | 
			
		||||
func manPreamble(out io.Writer, header *GenManHeader, cmd *cobra.Command, dashedName string) {
 | 
			
		||||
	description := cmd.Long
 | 
			
		||||
	if len(description) == 0 {
 | 
			
		||||
		description = cmd.Short
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Fprintf(out, `%% %s(%s)%s
 | 
			
		||||
%% %s
 | 
			
		||||
%% %s
 | 
			
		||||
# NAME
 | 
			
		||||
`, header.Title, header.Section, header.date, header.Source, header.Manual)
 | 
			
		||||
	fmt.Fprintf(out, "%s \\- %s\n\n", dashName, short)
 | 
			
		||||
	fmt.Fprintf(out, "%s \\- %s\n\n", dashedName, cmd.Short)
 | 
			
		||||
	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, "%s\n\n", long)
 | 
			
		||||
	fmt.Fprintf(out, "%s\n\n", description)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func manPrintFlags(out io.Writer, flags *pflag.FlagSet) {
 | 
			
		||||
@ -127,10 +150,10 @@ func manPrintFlags(out io.Writer, flags *pflag.FlagSet) {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		format := ""
 | 
			
		||||
		if len(flag.Shorthand) > 0 {
 | 
			
		||||
			format = "**-%s**, **--%s**"
 | 
			
		||||
		if len(flag.Shorthand) > 0 && len(flag.ShorthandDeprecated) == 0 {
 | 
			
		||||
			format = fmt.Sprintf("**-%s**, **--%s**", flag.Shorthand, flag.Name)
 | 
			
		||||
		} else {
 | 
			
		||||
			format = "%s**--%s**"
 | 
			
		||||
			format = fmt.Sprintf("**--%s**", flag.Name)
 | 
			
		||||
		}
 | 
			
		||||
		if len(flag.NoOptDefVal) > 0 {
 | 
			
		||||
			format = format + "["
 | 
			
		||||
@ -145,7 +168,7 @@ func manPrintFlags(out io.Writer, flags *pflag.FlagSet) {
 | 
			
		||||
			format = format + "]"
 | 
			
		||||
		}
 | 
			
		||||
		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 {
 | 
			
		||||
	// something like `rootcmd subcmd1 subcmd2`
 | 
			
		||||
	commandName := cmd.CommandPath()
 | 
			
		||||
	// something like `rootcmd-subcmd1-subcmd2`
 | 
			
		||||
	dashCommandName := strings.Replace(commandName, " ", "-", -1)
 | 
			
		||||
 | 
			
		||||
	fillHeader(header, commandName)
 | 
			
		||||
	dashCommandName := strings.Replace(cmd.CommandPath(), " ", "-", -1)
 | 
			
		||||
 | 
			
		||||
	buf := new(bytes.Buffer)
 | 
			
		||||
 | 
			
		||||
	short := cmd.Short
 | 
			
		||||
	long := cmd.Long
 | 
			
		||||
	if len(long) == 0 {
 | 
			
		||||
		long = short
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	manPreamble(buf, header, commandName, short, long)
 | 
			
		||||
	manPreamble(buf, header, cmd, dashCommandName)
 | 
			
		||||
	manPrintOptions(buf, cmd)
 | 
			
		||||
	if len(cmd.Example) > 0 {
 | 
			
		||||
		fmt.Fprintf(buf, "# EXAMPLE\n")
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,9 @@ import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"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 {
 | 
			
		||||
	for scanner.Scan() {
 | 
			
		||||
		line := scanner.Text()
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user