diff --git a/doc/man_docs.go b/doc/man_docs.go index 5364326..b202029 100644 --- a/doc/man_docs.go +++ b/doc/man_docs.go @@ -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") diff --git a/doc/man_docs_test.go b/doc/man_docs_test.go index e6e6263..26b8fcc 100644 --- a/doc/man_docs_test.go +++ b/doc/man_docs_test.go @@ -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()