forked from cli/cli
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathjson_flags.go
More file actions
123 lines (109 loc) · 3.05 KB
/
json_flags.go
File metadata and controls
123 lines (109 loc) · 3.05 KB
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
package cmdutil
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"sort"
"strings"
"github.com/cli/cli/pkg/export"
"github.com/cli/cli/pkg/jsoncolor"
"github.com/cli/cli/pkg/set"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
type JSONFlagError struct {
error
}
func AddJSONFlags(cmd *cobra.Command, exportTarget *Exporter, fields []string) {
f := cmd.Flags()
f.StringSlice("json", nil, "Output JSON with the specified `fields`")
f.StringP("jq", "q", "", "Filter JSON output using a jq `expression`")
f.StringP("template", "t", "", "Format JSON output using a Go template")
oldPreRun := cmd.PreRunE
cmd.PreRunE = func(c *cobra.Command, args []string) error {
if oldPreRun != nil {
if err := oldPreRun(c, args); err != nil {
return err
}
}
if export, err := checkJSONFlags(c); err == nil {
if export == nil {
*exportTarget = nil
} else {
allowedFields := set.NewStringSet()
allowedFields.AddValues(fields)
for _, f := range export.fields {
if !allowedFields.Contains(f) {
sort.Strings(fields)
return JSONFlagError{fmt.Errorf("Unknown JSON field: %q\nAvailable fields:\n %s", f, strings.Join(fields, "\n "))}
}
}
*exportTarget = export
}
} else {
return err
}
return nil
}
cmd.SetFlagErrorFunc(func(c *cobra.Command, e error) error {
if e.Error() == "flag needs an argument: --json" {
sort.Strings(fields)
return JSONFlagError{fmt.Errorf("Specify one or more comma-separated fields for `--json`:\n %s", strings.Join(fields, "\n "))}
}
return c.Parent().FlagErrorFunc()(c, e)
})
}
func checkJSONFlags(cmd *cobra.Command) (*exportFormat, error) {
f := cmd.Flags()
jsonFlag := f.Lookup("json")
jqFlag := f.Lookup("jq")
tplFlag := f.Lookup("template")
webFlag := f.Lookup("web")
if jsonFlag.Changed {
if webFlag != nil && webFlag.Changed {
return nil, errors.New("cannot use `--web` with `--json`")
}
jv := jsonFlag.Value.(pflag.SliceValue)
return &exportFormat{
fields: jv.GetSlice(),
filter: jqFlag.Value.String(),
template: tplFlag.Value.String(),
}, nil
} else if jqFlag.Changed {
return nil, errors.New("cannot use `--jq` without specifying `--json`")
} else if tplFlag.Changed {
return nil, errors.New("cannot use `--template` without specifying `--json`")
}
return nil, nil
}
type Exporter interface {
Fields() []string
Write(w io.Writer, data interface{}, colorEnabled bool) error
}
type exportFormat struct {
fields []string
filter string
template string
}
func (e *exportFormat) Fields() []string {
return e.fields
}
func (e *exportFormat) Write(w io.Writer, data interface{}, colorEnabled bool) error {
buf := bytes.Buffer{}
encoder := json.NewEncoder(&buf)
encoder.SetEscapeHTML(false)
if err := encoder.Encode(data); err != nil {
return err
}
if e.filter != "" {
return export.FilterJSON(w, &buf, e.filter)
} else if e.template != "" {
return export.ExecuteTemplate(w, &buf, e.template, colorEnabled)
} else if colorEnabled {
return jsoncolor.Write(w, &buf, " ")
}
_, err := io.Copy(w, &buf)
return err
}