1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package doc
16
17 import (
18 "fmt"
19 "io"
20 "os"
21 "path/filepath"
22 "sort"
23 "strings"
24
25 "github.com/spf13/cobra"
26 "github.com/spf13/pflag"
27 "gopkg.in/yaml.v3"
28 )
29
30 type cmdOption struct {
31 Name string
32 Shorthand string `yaml:",omitempty"`
33 DefaultValue string `yaml:"default_value,omitempty"`
34 Usage string `yaml:",omitempty"`
35 }
36
37 type cmdDoc struct {
38 Name string
39 Synopsis string `yaml:",omitempty"`
40 Description string `yaml:",omitempty"`
41 Usage string `yaml:",omitempty"`
42 Options []cmdOption `yaml:",omitempty"`
43 InheritedOptions []cmdOption `yaml:"inherited_options,omitempty"`
44 Example string `yaml:",omitempty"`
45 SeeAlso []string `yaml:"see_also,omitempty"`
46 }
47
48
49
50
51
52
53 func GenYamlTree(cmd *cobra.Command, dir string) error {
54 identity := func(s string) string { return s }
55 emptyStr := func(s string) string { return "" }
56 return GenYamlTreeCustom(cmd, dir, emptyStr, identity)
57 }
58
59
60 func GenYamlTreeCustom(cmd *cobra.Command, dir string, filePrepender, linkHandler func(string) string) error {
61 for _, c := range cmd.Commands() {
62 if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
63 continue
64 }
65 if err := GenYamlTreeCustom(c, dir, filePrepender, linkHandler); err != nil {
66 return err
67 }
68 }
69
70 basename := strings.ReplaceAll(cmd.CommandPath(), " ", "_") + ".yaml"
71 filename := filepath.Join(dir, basename)
72 f, err := os.Create(filename)
73 if err != nil {
74 return err
75 }
76 defer f.Close()
77
78 if _, err := io.WriteString(f, filePrepender(filename)); err != nil {
79 return err
80 }
81 if err := GenYamlCustom(cmd, f, linkHandler); err != nil {
82 return err
83 }
84 return nil
85 }
86
87
88 func GenYaml(cmd *cobra.Command, w io.Writer) error {
89 return GenYamlCustom(cmd, w, func(s string) string { return s })
90 }
91
92
93 func GenYamlCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) string) error {
94 cmd.InitDefaultHelpCmd()
95 cmd.InitDefaultHelpFlag()
96
97 yamlDoc := cmdDoc{}
98 yamlDoc.Name = cmd.CommandPath()
99
100 yamlDoc.Synopsis = forceMultiLine(cmd.Short)
101 yamlDoc.Description = forceMultiLine(cmd.Long)
102
103 if cmd.Runnable() {
104 yamlDoc.Usage = cmd.UseLine()
105 }
106
107 if len(cmd.Example) > 0 {
108 yamlDoc.Example = cmd.Example
109 }
110
111 flags := cmd.NonInheritedFlags()
112 if flags.HasFlags() {
113 yamlDoc.Options = genFlagResult(flags)
114 }
115 flags = cmd.InheritedFlags()
116 if flags.HasFlags() {
117 yamlDoc.InheritedOptions = genFlagResult(flags)
118 }
119
120 if hasSeeAlso(cmd) {
121 result := []string{}
122 if cmd.HasParent() {
123 parent := cmd.Parent()
124 result = append(result, parent.CommandPath()+" - "+parent.Short)
125 }
126 children := cmd.Commands()
127 sort.Sort(byName(children))
128 for _, child := range children {
129 if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() {
130 continue
131 }
132 result = append(result, child.CommandPath()+" - "+child.Short)
133 }
134 yamlDoc.SeeAlso = result
135 }
136
137 final, err := yaml.Marshal(&yamlDoc)
138 if err != nil {
139 fmt.Println(err)
140 os.Exit(1)
141 }
142
143 if _, err := w.Write(final); err != nil {
144 return err
145 }
146 return nil
147 }
148
149 func genFlagResult(flags *pflag.FlagSet) []cmdOption {
150 var result []cmdOption
151
152 flags.VisitAll(func(flag *pflag.Flag) {
153
154
155
156 if !(len(flag.ShorthandDeprecated) > 0) && len(flag.Shorthand) > 0 {
157 opt := cmdOption{
158 flag.Name,
159 flag.Shorthand,
160 flag.DefValue,
161 forceMultiLine(flag.Usage),
162 }
163 result = append(result, opt)
164 } else {
165 opt := cmdOption{
166 Name: flag.Name,
167 DefaultValue: forceMultiLine(flag.DefValue),
168 Usage: forceMultiLine(flag.Usage),
169 }
170 result = append(result, opt)
171 }
172 })
173
174 return result
175 }
176
View as plain text