Skip to content

Commit

Permalink
fix(clidoc): do not escape args
Browse files Browse the repository at this point in the history
Closes #477
  • Loading branch information
aeneasr committed Mar 24, 2022
1 parent 28892fd commit 6b8135e
Show file tree
Hide file tree
Showing 8 changed files with 259 additions and 9 deletions.
6 changes: 2 additions & 4 deletions clidoc/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package clidoc
import (
"bytes"
"fmt"
"html"
"io"
"os"
"path/filepath"
Expand All @@ -12,7 +11,6 @@ import (
"github.com/pkg/errors"

"github.com/spf13/cobra"
"github.com/spf13/cobra/doc"
)

// Generate generates markdown documentation for a cobra command and its children.
Expand Down Expand Up @@ -72,10 +70,10 @@ To improve this file please make your change against the appropriate "./cmd/*.go
}

var b bytes.Buffer
if err := doc.GenMarkdownCustom(cmd, &b, trimExt); err != nil {
if err := GenMarkdownCustom(cmd, &b, trimExt); err != nil {
return err
}

_, err = f.WriteString(html.EscapeString(b.String()))
_, err = f.WriteString(b.String())
return err
}
24 changes: 20 additions & 4 deletions clidoc/generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,26 @@ import (
func noopRun(_ *cobra.Command, _ []string) {}

var (
root = &cobra.Command{Use: "root", Run: noopRun}
child1 = &cobra.Command{Use: "child1", Run: noopRun}
child2 = &cobra.Command{Use: "child2", Run: noopRun}
subChild1 = &cobra.Command{Use: "subChild1", Run: noopRun}
root = &cobra.Command{Use: "root", Run: noopRun, Long: `A sample text
root
<[some argument]>
`}
child1 = &cobra.Command{Use: "child1", Run: noopRun, Long: `A sample text
child1
<[some argument]>
`}
child2 = &cobra.Command{Use: "child2", Run: noopRun, Long: `A sample text
child2
<[some argument]>
`}
subChild1 = &cobra.Command{Use: "subChild1 <args>", Run: noopRun, Long: `A sample text
subChild1
<[some argument]>
`}
)

func snapshotDir(t *testing.T, path ...string) (assertNoChange func(t *testing.T)) {
Expand Down
153 changes: 153 additions & 0 deletions clidoc/md_docs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
//Copyright 2015 Red Hat Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package clidoc

import (
"bytes"
"fmt"
"html"
"io"
"os"
"path/filepath"
"sort"
"strings"

"github.com/spf13/cobra"
)

func printOptions(buf *bytes.Buffer, cmd *cobra.Command, name string) error {
flags := cmd.NonInheritedFlags()
flags.SetOutput(buf)
if flags.HasAvailableFlags() {
buf.WriteString("### Options\n\n```\n")
flags.PrintDefaults()
buf.WriteString("```\n\n")
}

parentFlags := cmd.InheritedFlags()
parentFlags.SetOutput(buf)
if parentFlags.HasAvailableFlags() {
buf.WriteString("### Options inherited from parent commands\n\n```\n")
parentFlags.PrintDefaults()
buf.WriteString("```\n\n")
}
return nil
}

// GenMarkdown creates markdown output.
func GenMarkdown(cmd *cobra.Command, w io.Writer) error {
return GenMarkdownCustom(cmd, w, func(s string) string { return s })
}

// GenMarkdownCustom creates custom markdown output.
func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) string) error {
cmd.InitDefaultHelpCmd()
cmd.InitDefaultHelpFlag()

buf := new(bytes.Buffer)
name := cmd.CommandPath()

buf.WriteString("## " + html.EscapeString(name) + "\n\n")
buf.WriteString(cmd.Short + "\n\n")
if len(cmd.Long) > 0 {
buf.WriteString("### Synopsis\n\n")
buf.WriteString(html.EscapeString(cmd.Long) + "\n\n")
}

if cmd.Runnable() {
buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.UseLine()))
}

if len(cmd.Example) > 0 {
buf.WriteString("### Examples\n\n")
buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.Example))
}

if err := printOptions(buf, cmd, name); err != nil {
return err
}
if hasSeeAlso(cmd) {
buf.WriteString("### SEE ALSO\n\n")
if cmd.HasParent() {
parent := cmd.Parent()
pname := parent.CommandPath()
link := pname + ".md"
link = strings.Replace(link, " ", "_", -1)
buf.WriteString(fmt.Sprintf("* [%s](%s)\t - %s\n", pname, linkHandler(link), parent.Short))
cmd.VisitParents(func(c *cobra.Command) {
if c.DisableAutoGenTag {
cmd.DisableAutoGenTag = c.DisableAutoGenTag
}
})
}

children := cmd.Commands()
sort.Sort(byName(children))

for _, child := range children {
if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() {
continue
}
cname := name + " " + child.Name()
link := cname + ".md"
link = strings.Replace(link, " ", "_", -1)
buf.WriteString(fmt.Sprintf("* [%s](%s)\t - %s\n", cname, linkHandler(link), child.Short))
}
buf.WriteString("\n")
}

_, err := buf.WriteTo(w)
return err
}

// GenMarkdownTree will generate a markdown page for this command and all
// descendants 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 GenMarkdownTree(cmd *cobra.Command, dir string) error {
identity := func(s string) string { return s }
emptyStr := func(s string) string { return "" }
return GenMarkdownTreeCustom(cmd, dir, emptyStr, identity)
}

// GenMarkdownTreeCustom is the the same as GenMarkdownTree, but
// with custom filePrepender and linkHandler.
func GenMarkdownTreeCustom(cmd *cobra.Command, dir string, filePrepender, linkHandler func(string) string) error {
for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
continue
}
if err := GenMarkdownTreeCustom(c, dir, filePrepender, linkHandler); err != nil {
return err
}
}

basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + ".md"
filename := filepath.Join(dir, basename)
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()

if _, err := io.WriteString(f, filePrepender(filename)); err != nil {
return err
}
if err := GenMarkdownCustom(cmd, f, linkHandler); err != nil {
return err
}
return nil
}
10 changes: 9 additions & 1 deletion clidoc/testdata/root-child1-subChild1.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,16 @@ To improve this file please make your change against the appropriate "./cmd/*.go



### Synopsis

A sample text
subChild1

&lt;[some argument]&gt;


```
root child1 subChild1 [flags]
root child1 subChild1 <args> [flags]
```

### Options
Expand Down
8 changes: 8 additions & 0 deletions clidoc/testdata/root-child1.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ To improve this file please make your change against the appropriate "./cmd/*.go



### Synopsis

A sample text
child1

&lt;[some argument]&gt;


```
root child1 [flags]
```
Expand Down
8 changes: 8 additions & 0 deletions clidoc/testdata/root-child2.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ To improve this file please make your change against the appropriate "./cmd/*.go



### Synopsis

A sample text
child2

&lt;[some argument]&gt;


```
root child2 [flags]
```
Expand Down
8 changes: 8 additions & 0 deletions clidoc/testdata/root.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ To improve this file please make your change against the appropriate "./cmd/*.go



### Synopsis

A sample text
root

&lt;[some argument]&gt;


```
root [flags]
```
Expand Down
51 changes: 51 additions & 0 deletions clidoc/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2015 Red Hat Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package clidoc

import (
"strings"

"github.com/spf13/cobra"
)

// Test to see if we have a reason to print See Also information in docs
// Basically this is a test for a parent command or a subcommand which is
// both not deprecated and not the autogenerated help command.
func hasSeeAlso(cmd *cobra.Command) bool {
if cmd.HasParent() {
return true
}
for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
continue
}
return true
}
return false
}

// Temporary workaround for yaml lib generating incorrect yaml with long strings
// that do not contain \n.
func forceMultiLine(s string) string {
if len(s) > 60 && !strings.Contains(s, "\n") {
s = s + "\n"
}
return s
}

type byName []*cobra.Command

func (s byName) Len() int { return len(s) }
func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() }

0 comments on commit 6b8135e

Please sign in to comment.