Setting GH_COBRA allows access to Cobra's built-in implementation of generating man pages and markdown trees. This is useful for testing and comparing our overrides against Cobra's own logic.
166 lines
3.9 KiB
Go
166 lines
3.9 KiB
Go
package docs
|
|
|
|
import (
|
|
"fmt"
|
|
"html/template"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/cli/cli/v2/pkg/cmd/root"
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/cobra/doc"
|
|
"github.com/spf13/pflag"
|
|
)
|
|
|
|
func printOptions(w io.Writer, cmd *cobra.Command) error {
|
|
flags := cmd.NonInheritedFlags()
|
|
flags.SetOutput(w)
|
|
if flags.HasAvailableFlags() {
|
|
fmt.Fprint(w, "### Options\n\n")
|
|
if err := printFlagsHTML(w, flags); err != nil {
|
|
return err
|
|
}
|
|
fmt.Fprint(w, "\n\n")
|
|
}
|
|
|
|
parentFlags := cmd.InheritedFlags()
|
|
parentFlags.SetOutput(w)
|
|
if hasNonHelpFlags(parentFlags) {
|
|
fmt.Fprint(w, "### Options inherited from parent commands\n\n")
|
|
if err := printFlagsHTML(w, parentFlags); err != nil {
|
|
return err
|
|
}
|
|
fmt.Fprint(w, "\n\n")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func hasNonHelpFlags(fs *pflag.FlagSet) (found bool) {
|
|
fs.VisitAll(func(f *pflag.Flag) {
|
|
if !f.Hidden && f.Name != "help" {
|
|
found = true
|
|
}
|
|
})
|
|
return
|
|
}
|
|
|
|
type flagView struct {
|
|
Name string
|
|
Varname string
|
|
Shorthand string
|
|
Usage string
|
|
}
|
|
|
|
var flagsTemplate = `
|
|
<dl class="flags">{{ range . }}
|
|
<dt>{{ if .Shorthand }}<code>-{{.Shorthand}}</code>, {{ end -}}
|
|
<code>--{{.Name}}{{ if .Varname }} <{{.Varname}}>{{ end }}</code></dt>
|
|
<dd>{{.Usage}}</dd>
|
|
{{ end }}</dl>
|
|
`
|
|
|
|
var tpl = template.Must(template.New("flags").Parse(flagsTemplate))
|
|
|
|
func printFlagsHTML(w io.Writer, fs *pflag.FlagSet) error {
|
|
var flags []flagView
|
|
fs.VisitAll(func(f *pflag.Flag) {
|
|
if f.Hidden || f.Name == "help" {
|
|
return
|
|
}
|
|
varname, usage := pflag.UnquoteUsage(f)
|
|
flags = append(flags, flagView{
|
|
Name: f.Name,
|
|
Varname: varname,
|
|
Shorthand: f.Shorthand,
|
|
Usage: usage,
|
|
})
|
|
})
|
|
return tpl.Execute(w, flags)
|
|
}
|
|
|
|
// genMarkdownCustom creates custom markdown output.
|
|
func genMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) string) error {
|
|
fmt.Fprint(w, "{% raw %}")
|
|
fmt.Fprintf(w, "## %s\n\n", cmd.CommandPath())
|
|
|
|
hasLong := cmd.Long != ""
|
|
if !hasLong {
|
|
fmt.Fprintf(w, "%s\n\n", cmd.Short)
|
|
}
|
|
if cmd.Runnable() {
|
|
fmt.Fprintf(w, "```\n%s\n```\n\n", cmd.UseLine())
|
|
}
|
|
if hasLong {
|
|
fmt.Fprintf(w, "%s\n\n", cmd.Long)
|
|
}
|
|
|
|
for _, g := range root.GroupedCommands(cmd) {
|
|
fmt.Fprintf(w, "### %s\n\n", g.Title)
|
|
for _, subcmd := range g.Commands {
|
|
fmt.Fprintf(w, "* [%s](%s)\n", subcmd.CommandPath(), linkHandler(cmdManualPath(subcmd)))
|
|
}
|
|
fmt.Fprint(w, "\n\n")
|
|
}
|
|
|
|
if err := printOptions(w, cmd); err != nil {
|
|
return err
|
|
}
|
|
fmt.Fprint(w, "{% endraw %}\n")
|
|
|
|
if len(cmd.Example) > 0 {
|
|
fmt.Fprint(w, "### Examples\n\n{% highlight bash %}{% raw %}\n")
|
|
fmt.Fprint(w, cmd.Example)
|
|
fmt.Fprint(w, "{% endraw %}{% endhighlight %}\n\n")
|
|
}
|
|
|
|
if cmd.HasParent() {
|
|
p := cmd.Parent()
|
|
fmt.Fprint(w, "### See also\n\n")
|
|
fmt.Fprintf(w, "* [%s](%s)\n", p.CommandPath(), linkHandler(cmdManualPath(p)))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GenMarkdownTreeCustom is the same as GenMarkdownTree, but
|
|
// with custom filePrepender and linkHandler.
|
|
func GenMarkdownTreeCustom(cmd *cobra.Command, dir string, filePrepender, linkHandler func(string) string) error {
|
|
if os.Getenv("GH_COBRA") != "" {
|
|
return doc.GenMarkdownTreeCustom(cmd, dir, filePrepender, linkHandler)
|
|
}
|
|
|
|
for _, c := range cmd.Commands() {
|
|
_, forceGeneration := c.Annotations["markdown:generate"]
|
|
if c.Hidden && !forceGeneration {
|
|
continue
|
|
}
|
|
|
|
if err := GenMarkdownTreeCustom(c, dir, filePrepender, linkHandler); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
filename := filepath.Join(dir, cmdManualPath(cmd))
|
|
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
|
|
}
|
|
|
|
func cmdManualPath(c *cobra.Command) string {
|
|
if basenameOverride, found := c.Annotations["markdown:basename"]; found {
|
|
return basenameOverride + ".md"
|
|
}
|
|
return strings.ReplaceAll(c.CommandPath(), " ", "_") + ".md"
|
|
}
|