From 29c0a1f42ef799b2d335162003a76711fa966fce Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Mon, 20 Jun 2016 17:27:41 -0400 Subject: [PATCH 1/4] Use the correct UseLine for the man page synposis. Signed-off-by: Daniel Nephin --- doc/man_docs.go | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/doc/man_docs.go b/doc/man_docs.go index 5364326..833adc0 100644 --- a/doc/man_docs.go +++ b/doc/man_docs.go @@ -107,18 +107,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) { @@ -174,13 +178,7 @@ func genMan(cmd *cobra.Command, header *GenManHeader) []byte { 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") From 112c7dca3abb01000dd25be3311b2fba3830b236 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Mon, 20 Jun 2016 17:29:54 -0400 Subject: [PATCH 2/4] Hide deprecated shorthand flags in man page generation. --- doc/man_docs.go | 8 ++++---- doc/man_docs_test.go | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/doc/man_docs.go b/doc/man_docs.go index 833adc0..e990b3f 100644 --- a/doc/man_docs.go +++ b/doc/man_docs.go @@ -131,10 +131,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 + "[" @@ -149,7 +149,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) }) } diff --git a/doc/man_docs_test.go b/doc/man_docs_test.go index e6e6263..3fd195f 100644 --- a/doc/man_docs_test.go +++ b/doc/man_docs_test.go @@ -129,6 +129,21 @@ 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 AssertLineFound(scanner *bufio.Scanner, expectedLine string) error { for scanner.Scan() { line := scanner.Text() From 97206b3170fb7e2e5c28333eab815dcd6d47d369 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Tue, 21 Jun 2016 12:25:26 -0400 Subject: [PATCH 3/4] Use the correct man page section for the filename Also make header mutation cleaner. Signed-off-by: Daniel Nephin --- doc/man_docs.go | 24 ++++++++++-------------- doc/man_docs_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/doc/man_docs.go b/doc/man_docs.go index e990b3f..ce4404d 100644 --- a/doc/man_docs.go +++ b/doc/man_docs.go @@ -45,9 +45,12 @@ func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error { return err } } - needToResetTitle := header.Title == "" + section := "1" + if header.Section != "" { + section = header.Section + } - basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + ".1" + basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + "." + section filename := filepath.Join(dir, basename) f, err := os.Create(filename) if err != nil { @@ -55,14 +58,8 @@ func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error { } defer f.Close() - if err := GenMan(cmd, header, f); err != nil { - return err - } - - if needToResetTitle { - header.Title = "" - } - return nil + headerCopy := *header + return GenMan(cmd, &headerCopy, f) } // GenManHeader is a lot like the .TH header at the start of man pages. These @@ -84,9 +81,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 } @@ -174,8 +172,6 @@ func genMan(cmd *cobra.Command, header *GenManHeader) []byte { // something like `rootcmd-subcmd1-subcmd2` dashCommandName := strings.Replace(commandName, " ", "-", -1) - fillHeader(header, commandName) - buf := new(bytes.Buffer) manPreamble(buf, header, cmd, dashCommandName) diff --git a/doc/man_docs_test.go b/doc/man_docs_test.go index 3fd195f..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" @@ -144,6 +146,30 @@ func TestManPrintFlagsHidesShortDeperecated(t *testing.T) { } } +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() From e291587027b16ffd7fb0e5bdd6bf203e8ed2620f Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Tue, 21 Jun 2016 12:34:20 -0400 Subject: [PATCH 4/4] Cretea a new GenManTree function that takes an options struct. Signed-off-by: Daniel Nephin --- doc/man_docs.go | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/doc/man_docs.go b/doc/man_docs.go index ce4404d..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,7 +52,7 @@ 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 } } @@ -50,8 +61,12 @@ func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error { section = header.Section } - basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + "." + section - 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 @@ -62,6 +77,12 @@ func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error { return GenMan(cmd, &headerCopy, f) } +type GenManTreeOptions struct { + Header *GenManHeader + Path string + CommandSeparator string +} + // GenManHeader is a lot like the .TH header at the start of man pages. These // include the title, section, date, source, and manual. We will use the // current time if Date if unset and will use "Auto generated by spf13/cobra" @@ -167,10 +188,8 @@ 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) + dashCommandName := strings.Replace(cmd.CommandPath(), " ", "-", -1) buf := new(bytes.Buffer)