mirror of
https://github.com/spf13/cobra
synced 2024-11-24 14:47:12 +00:00
Merge pull request #145 from eparis/man-cleanups
Enhance Man Page Generation
This commit is contained in:
commit
75d96d75c3
6 changed files with 139 additions and 47 deletions
|
@ -265,16 +265,24 @@ func logErr(t *testing.T, found, expected string) {
|
||||||
t.Errorf(out.String())
|
t.Errorf(out.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkStringContains(t *testing.T, found, expected string) {
|
||||||
|
if !strings.Contains(found, expected) {
|
||||||
|
logErr(t, found, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func checkResultContains(t *testing.T, x resulter, check string) {
|
func checkResultContains(t *testing.T, x resulter, check string) {
|
||||||
if !strings.Contains(x.Output, check) {
|
checkStringContains(t, x.Output, check)
|
||||||
logErr(t, x.Output, check)
|
}
|
||||||
|
|
||||||
|
func checkStringOmits(t *testing.T, found, expected string) {
|
||||||
|
if strings.Contains(found, expected) {
|
||||||
|
logErr(t, found, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkResultOmits(t *testing.T, x resulter, check string) {
|
func checkResultOmits(t *testing.T, x resulter, check string) {
|
||||||
if strings.Contains(x.Output, check) {
|
checkStringOmits(t, x.Output, check)
|
||||||
logErr(t, x.Output, check)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkOutputContains(t *testing.T, c *Command, check string) {
|
func checkOutputContains(t *testing.T, c *Command, check string) {
|
||||||
|
|
34
examples_test.go
Normal file
34
examples_test.go
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package cobra_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleCommand_GenManTree() {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "test",
|
||||||
|
Short: "my test program",
|
||||||
|
}
|
||||||
|
header := &cobra.GenManHeader{
|
||||||
|
Title: "MINE",
|
||||||
|
Section: "3",
|
||||||
|
}
|
||||||
|
cmd.GenManTree(header, "/tmp")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleCommand_GenMan() {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "test",
|
||||||
|
Short: "my test program",
|
||||||
|
}
|
||||||
|
header := &cobra.GenManHeader{
|
||||||
|
Title: "MINE",
|
||||||
|
Section: "3",
|
||||||
|
}
|
||||||
|
out := new(bytes.Buffer)
|
||||||
|
cmd.GenMan(header, out)
|
||||||
|
fmt.Print(out.String())
|
||||||
|
}
|
83
man_docs.go
83
man_docs.go
|
@ -25,20 +25,29 @@ import (
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GenManTree(cmd *Command, projectName, dir string) {
|
// GenManTree will call cmd.GenManTree(header, dir)
|
||||||
cmd.GenManTree(projectName, dir)
|
func GenManTree(cmd *Command, header *GenManHeader, dir string) {
|
||||||
|
cmd.GenManTree(header, dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cmd *Command) GenManTree(projectName, dir string) {
|
// GenManTree will generate a man page for this command and all decendants
|
||||||
|
// 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 (cmd *Command) GenManTree(header *GenManHeader, dir string) {
|
||||||
|
if header == nil {
|
||||||
|
header = &GenManHeader{}
|
||||||
|
}
|
||||||
for _, c := range cmd.Commands() {
|
for _, c := range cmd.Commands() {
|
||||||
if len(c.Deprecated) != 0 || c == cmd.helpCommand {
|
if len(c.Deprecated) != 0 || c == cmd.helpCommand {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
GenManTree(c, projectName, dir)
|
GenManTree(c, header, dir)
|
||||||
}
|
}
|
||||||
out := new(bytes.Buffer)
|
out := new(bytes.Buffer)
|
||||||
|
|
||||||
cmd.GenMan(projectName, out)
|
cmd.GenMan(header, out)
|
||||||
|
|
||||||
filename := cmd.CommandPath()
|
filename := cmd.CommandPath()
|
||||||
filename = dir + strings.Replace(filename, " ", "-", -1) + ".1"
|
filename = dir + strings.Replace(filename, " ", "-", -1) + ".1"
|
||||||
|
@ -55,21 +64,58 @@ func (cmd *Command) GenManTree(projectName, dir string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenMan(cmd *Command, projectName string, out *bytes.Buffer) {
|
// GenManHeader is a lot like the .TH header at the start of man pages. These
|
||||||
cmd.GenMan(projectName, out)
|
// 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"
|
||||||
|
// if the Source is unset.
|
||||||
|
type GenManHeader struct {
|
||||||
|
Title string
|
||||||
|
Section string
|
||||||
|
Date *time.Time
|
||||||
|
date string
|
||||||
|
Source string
|
||||||
|
Manual string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cmd *Command) GenMan(projectName string, out *bytes.Buffer) {
|
// GenMan will call cmd.GenMan(header, out)
|
||||||
|
func GenMan(cmd *Command, header *GenManHeader, out *bytes.Buffer) {
|
||||||
|
cmd.GenMan(header, out)
|
||||||
|
}
|
||||||
|
|
||||||
buf := genMarkdown(cmd, projectName)
|
// GenMan will generate a man page for the given command in the out buffer.
|
||||||
|
// The header argument may be nil, however obviously out may not.
|
||||||
|
func (cmd *Command) GenMan(header *GenManHeader, out *bytes.Buffer) {
|
||||||
|
if header == nil {
|
||||||
|
header = &GenManHeader{}
|
||||||
|
}
|
||||||
|
buf := genMarkdown(cmd, header)
|
||||||
final := mangen.Render(buf)
|
final := mangen.Render(buf)
|
||||||
out.Write(final)
|
out.Write(final)
|
||||||
}
|
}
|
||||||
|
|
||||||
func manPreamble(out *bytes.Buffer, projectName, name, short, long string) {
|
func fillHeader(header *GenManHeader, name string) {
|
||||||
fmt.Fprintf(out, `%% %s(1)
|
if header.Title == "" {
|
||||||
|
header.Title = name
|
||||||
|
}
|
||||||
|
if header.Section == "" {
|
||||||
|
header.Section = "1"
|
||||||
|
}
|
||||||
|
if header.Date == nil {
|
||||||
|
now := time.Now()
|
||||||
|
header.Date = &now
|
||||||
|
}
|
||||||
|
header.date = (*header.Date).Format("Jan 2006")
|
||||||
|
if header.Source == "" {
|
||||||
|
header.Source = "Auto generated by spf13/cobra"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func manPreamble(out *bytes.Buffer, header *GenManHeader, name, short, long string) {
|
||||||
|
fmt.Fprintf(out, `%% %s(%s)%s
|
||||||
|
%% %s
|
||||||
|
%% %s
|
||||||
# NAME
|
# NAME
|
||||||
`, projectName)
|
`, header.Title, header.Section, header.date, header.Source, header.Manual)
|
||||||
fmt.Fprintf(out, "%s \\- %s\n\n", name, short)
|
fmt.Fprintf(out, "%s \\- %s\n\n", name, short)
|
||||||
fmt.Fprintf(out, "# SYNOPSIS\n")
|
fmt.Fprintf(out, "# SYNOPSIS\n")
|
||||||
fmt.Fprintf(out, "**%s** [OPTIONS]\n\n", name)
|
fmt.Fprintf(out, "**%s** [OPTIONS]\n\n", name)
|
||||||
|
@ -120,7 +166,8 @@ func manPrintOptions(out *bytes.Buffer, command *Command) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func genMarkdown(cmd *Command, projectName string) []byte {
|
func genMarkdown(cmd *Command, header *GenManHeader) []byte {
|
||||||
|
fillHeader(header, cmd.Name())
|
||||||
// something like `rootcmd subcmd1 subcmd2`
|
// something like `rootcmd subcmd1 subcmd2`
|
||||||
commandName := cmd.CommandPath()
|
commandName := cmd.CommandPath()
|
||||||
// something like `rootcmd-subcmd1-subcmd2`
|
// something like `rootcmd-subcmd1-subcmd2`
|
||||||
|
@ -134,7 +181,7 @@ func genMarkdown(cmd *Command, projectName string) []byte {
|
||||||
long = short
|
long = short
|
||||||
}
|
}
|
||||||
|
|
||||||
manPreamble(buf, projectName, commandName, short, long)
|
manPreamble(buf, header, commandName, short, long)
|
||||||
manPrintOptions(buf, cmd)
|
manPrintOptions(buf, cmd)
|
||||||
|
|
||||||
if len(cmd.Example) > 0 {
|
if len(cmd.Example) > 0 {
|
||||||
|
@ -145,7 +192,9 @@ func genMarkdown(cmd *Command, projectName string) []byte {
|
||||||
if cmd.hasSeeAlso() {
|
if cmd.hasSeeAlso() {
|
||||||
fmt.Fprintf(buf, "# SEE ALSO\n")
|
fmt.Fprintf(buf, "# SEE ALSO\n")
|
||||||
if cmd.HasParent() {
|
if cmd.HasParent() {
|
||||||
fmt.Fprintf(buf, "**%s(1)**, ", cmd.Parent().CommandPath())
|
parentPath := cmd.Parent().CommandPath()
|
||||||
|
dashParentPath := strings.Replace(parentPath, " ", "-", -1)
|
||||||
|
fmt.Fprintf(buf, "**%s(%s)**, ", dashParentPath, header.Section)
|
||||||
}
|
}
|
||||||
|
|
||||||
children := cmd.Commands()
|
children := cmd.Commands()
|
||||||
|
@ -154,11 +203,11 @@ func genMarkdown(cmd *Command, projectName string) []byte {
|
||||||
if len(c.Deprecated) != 0 || c == cmd.helpCommand {
|
if len(c.Deprecated) != 0 || c == cmd.helpCommand {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Fprintf(buf, "**%s-%s(1)**, ", dashCommandName, c.Name())
|
fmt.Fprintf(buf, "**%s-%s(%s)**, ", dashCommandName, c.Name(), header.Section)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(buf, "\n")
|
fmt.Fprintf(buf, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(buf, "# HISTORY\n%s Auto generated by spf13/cobra\n", time.Now().UTC())
|
fmt.Fprintf(buf, "# HISTORY\n%s Auto generated by spf13/cobra\n", header.Date.Format("2-Jan-2006"))
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,11 @@ func main() {
|
||||||
Use: "test",
|
Use: "test",
|
||||||
Short: "my test program",
|
Short: "my test program",
|
||||||
}
|
}
|
||||||
cmd.GenManTree("/tmp")
|
header := &cobra.GenManHeader{
|
||||||
|
Title: "MINE",
|
||||||
|
Section: "3",
|
||||||
|
}
|
||||||
|
cmd.GenManTree(header, "/tmp")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -24,48 +24,45 @@ func TestGenManDoc(t *testing.T) {
|
||||||
|
|
||||||
out := new(bytes.Buffer)
|
out := new(bytes.Buffer)
|
||||||
|
|
||||||
|
header := &GenManHeader{
|
||||||
|
Title: "Project",
|
||||||
|
Section: "2",
|
||||||
|
}
|
||||||
// We generate on a subcommand so we have both subcommands and parents
|
// We generate on a subcommand so we have both subcommands and parents
|
||||||
cmdEcho.GenMan("PROJECT", out)
|
cmdEcho.GenMan(header, out)
|
||||||
found := out.String()
|
found := out.String()
|
||||||
|
|
||||||
|
// Make sure parent has - in CommandPath() in SEE ALSO:
|
||||||
|
parentPath := cmdEcho.Parent().CommandPath()
|
||||||
|
dashParentPath := strings.Replace(parentPath, " ", "-", -1)
|
||||||
|
expected := translate(dashParentPath)
|
||||||
|
expected = expected + "(" + header.Section + ")"
|
||||||
|
checkStringContains(t, found, expected)
|
||||||
|
|
||||||
// Our description
|
// Our description
|
||||||
expected := translate(cmdEcho.Name())
|
expected = translate(cmdEcho.Name())
|
||||||
if !strings.Contains(found, expected) {
|
checkStringContains(t, found, expected)
|
||||||
t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Better have our example
|
// Better have our example
|
||||||
expected = translate(cmdEcho.Name())
|
expected = translate(cmdEcho.Name())
|
||||||
if !strings.Contains(found, expected) {
|
checkStringContains(t, found, expected)
|
||||||
t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A local flag
|
// A local flag
|
||||||
expected = "boolone"
|
expected = "boolone"
|
||||||
if !strings.Contains(found, expected) {
|
checkStringContains(t, found, expected)
|
||||||
t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
|
|
||||||
}
|
|
||||||
|
|
||||||
// persistent flag on parent
|
// persistent flag on parent
|
||||||
expected = "rootflag"
|
expected = "rootflag"
|
||||||
if !strings.Contains(found, expected) {
|
checkStringContains(t, found, expected)
|
||||||
t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We better output info about our parent
|
// We better output info about our parent
|
||||||
expected = translate(cmdRootWithRun.Name())
|
expected = translate(cmdRootWithRun.Name())
|
||||||
if !strings.Contains(found, expected) {
|
checkStringContains(t, found, expected)
|
||||||
t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
|
|
||||||
}
|
|
||||||
|
|
||||||
// And about subcommands
|
// And about subcommands
|
||||||
expected = translate(cmdEchoSub.Name())
|
expected = translate(cmdEchoSub.Name())
|
||||||
if !strings.Contains(found, expected) {
|
checkStringContains(t, found, expected)
|
||||||
t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
|
|
||||||
}
|
|
||||||
|
|
||||||
unexpected := translate(cmdDeprecated.Name())
|
unexpected := translate(cmdDeprecated.Name())
|
||||||
if strings.Contains(found, unexpected) {
|
checkStringOmits(t, found, unexpected)
|
||||||
t.Errorf("Unexpected response.\nFound: %v\nBut should not have!!\n", unexpected)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ func (cmd *Command) GenMarkdownCustom(out *bytes.Buffer, linkHandler func(string
|
||||||
fmt.Fprintf(out, "\n")
|
fmt.Fprintf(out, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(out, "###### Auto generated by spf13/cobra at %s\n", time.Now().UTC())
|
fmt.Fprintf(out, "###### Auto generated by spf13/cobra on %s\n", time.Now().Format("2-Jan-2006"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenMarkdownTree(cmd *Command, dir string) {
|
func GenMarkdownTree(cmd *Command, dir string) {
|
||||||
|
|
Loading…
Reference in a new issue