/
parse.go
124 lines (107 loc) · 3.45 KB
/
parse.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Copyright (c) 2018 Parker Heindl. All rights reserved.
//
// Use of this source code is governed by the MIT License.
// Read LICENSE.md in the project root for information.
package cobra
import (
"encoding/json"
"fmt"
"io"
"os"
"reflect"
"strings"
"github.com/spf13/cobra"
)
// CommandData is the aggregated documentation data from a Cobra command.
// Must remain in the parse.go file to be transferred into the cobra directory.
// This file should only import from cobra and the standard library.
type CommandData struct {
// TODO: Eventually need to adjust the installation command based on multiple execution paths.
// ExecutionRemotePath string `json:""`
Name string `json:""`
Use string `json:""`
UseLine string `json:""`
Long string `json:""`
Short string `json:""`
Example string `json:""`
// HasExample determines if the command has example.
HasExample bool `json:""`
// Runnable determines if the command is itself runnable.
Runnable bool `json:""`
// HasSubCommands determines if the command has children commands.
HasSubCommands bool `json:""`
SubCommands []*CommandData `json:""`
// IsAvailableCommand determines if a command is available as a non-help command
// (this includes all non deprecated/hidden commands).
IsAvailableCommand bool `json:""`
PersistentFlags []string `json:""`
LocalFlags []string `json:""`
}
func (Ω *CommandData) formatFlagUsages(flags string) (res []string) {
for _, line := range strings.Split(flags, "\n") {
line = strings.TrimSpace(line)
if len(line) > 0 {
res = append(res, line)
}
}
return
}
func stripIndents(s string) string {
lines := strings.Split(s, "\n")
for i, s := range lines {
lines[i] = strings.TrimSpace(s)
}
return strings.Join(lines, "\n")
}
func (Ω *CommandData) update(cmd *cobra.Command) {
Ω.Name = cmd.Name()
Ω.Use = cmd.Use
Ω.UseLine = cmd.UseLine()
Ω.Short = stripIndents(cmd.Short)
Ω.Long = stripIndents(cmd.Long)
Ω.Example = stripIndents(cmd.Example)
Ω.HasExample = cmd.HasExample()
Ω.HasSubCommands = cmd.HasSubCommands()
Ω.Runnable = cmd.Runnable()
Ω.IsAvailableCommand = cmd.IsAvailableCommand()
Ω.PersistentFlags = Ω.formatFlagUsages(cmd.PersistentFlags().FlagUsages())
for _, localFlag := range Ω.formatFlagUsages(cmd.LocalFlags().FlagUsages()) {
ex := false
for _, persistentFlag := range Ω.PersistentFlags {
ex = ex || localFlag == persistentFlag
}
if !ex {
Ω.LocalFlags = append(Ω.LocalFlags, localFlag)
}
}
}
// Establish as variables to they can be mocked in tests.
var cobraReadmeErrorWriter io.Writer = os.Stderr
var cobraReadmeOutputWriter io.Writer = os.Stdout
// getCobraReadMeRootCommand is a hack to account for lack of pointers in root command variable.
func getCobraReadMeRootCommand(i interface{}) *cobra.Command {
if reflect.ValueOf(i).Kind() != reflect.Ptr {
cmd := i.(cobra.Command)
return &cmd
}
return i.(*cobra.Command)
}
func main() {
parentCmd := getCobraReadMeRootCommand(cobraReadmeRootCmd)
if parentCmd == nil {
fmt.Fprintf(cobraReadmeErrorWriter, "root command [cobraReadmeRootCmd] is nil")
return
}
parent := &CommandData{}
parent.update(parentCmd)
for i, childCmd := range parentCmd.Commands() {
parent.SubCommands = append(parent.SubCommands, &CommandData{})
parent.SubCommands[i].update(childCmd)
}
b, err := json.Marshal(parent)
if err != nil {
fmt.Fprintf(cobraReadmeErrorWriter, err.Error())
return
}
fmt.Fprint(cobraReadmeOutputWriter, string(b))
}