Skip to content

Commit 1a5a661

Browse files
authored
feat: vsctl support both JSON and table as the output format (#105)
1 parent f77f2e7 commit 1a5a661

File tree

8 files changed

+286
-72
lines changed

8 files changed

+286
-72
lines changed

vsctl/command/event.go

Lines changed: 81 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import (
3030
"github.com/fatih/color"
3131
"github.com/golang/protobuf/ptypes/empty"
3232
"github.com/google/uuid"
33+
"github.com/jedib0t/go-pretty/v6/table"
34+
"github.com/jedib0t/go-pretty/v6/text"
3335
ctrlpb "github.com/linkall-labs/vanus/proto/pkg/controller"
3436
"github.com/spf13/cobra"
3537
)
@@ -66,11 +68,11 @@ func putEventCommand() *cobra.Command {
6668
endpoint := mustGetGatewayEndpoint(cmd)
6769
p, err := ce.NewHTTP()
6870
if err != nil {
69-
cmdFailedf("init ce protocol error: %s\n", err)
71+
cmdFailedf(cmd, "init ce protocol error: %s\n", err)
7072
}
7173
c, err := ce.NewClient(p, ce.WithTimeNow(), ce.WithUUIDs())
7274
if err != nil {
73-
cmdFailedf("create ce client error: %s\n", err)
75+
cmdFailedf(cmd, "create ce client error: %s\n", err)
7476
}
7577
var target string
7678
if strings.HasPrefix(endpoint, httpPrefix) {
@@ -82,9 +84,9 @@ func putEventCommand() *cobra.Command {
8284
ctx := ce.ContextWithTarget(context.Background(), target)
8385

8486
if dataFile == "" {
85-
sendOne(ctx, c)
87+
sendOne(cmd, ctx, c)
8688
} else {
87-
sendFile(ctx, c)
89+
sendFile(cmd, ctx, c)
8890
}
8991
},
9092
}
@@ -108,12 +110,12 @@ func mustGetGatewayEndpoint(cmd *cobra.Command) string {
108110
cli := ctrlpb.NewPingServerClient(grpcConn)
109111
res, err := cli.Ping(ctx, &empty.Empty{})
110112
if err != nil {
111-
cmdFailedf("get Gateway endpoint from controller failed: %s", err)
113+
cmdFailedf(cmd, "get Gateway endpoint from controller failed: %s", err)
112114
}
113115
return res.GatewayAddr
114116
}
115117

116-
func sendOne(ctx context.Context, ceClient ce.Client) {
118+
func sendOne(cmd *cobra.Command, ctx context.Context, ceClient ce.Client) {
117119
event := ce.NewEvent()
118120
if eventID == "" {
119121
eventID = uuid.NewString()
@@ -126,37 +128,50 @@ func sendOne(ctx context.Context, ceClient ce.Client) {
126128
m := make(map[string]interface{})
127129
if err := json.Unmarshal([]byte(eventBody), &m); err != nil {
128130
color.White(eventBody)
129-
cmdFailedf("invalid format of data body: %s, err: %s", eventBody, err.Error())
131+
cmdFailedf(cmd, "invalid format of data body: %s, err: %s", eventBody, err.Error())
130132
}
131133
err = event.SetData(ce.ApplicationJSON, m)
132134
} else {
133135
err = event.SetData(ce.TextPlain, eventBody)
134136
}
135137

136138
if err != nil {
137-
cmdFailedf("set data failed: %s\n", err)
139+
cmdFailedf(cmd, "set data failed: %s\n", err)
138140
}
139141
res := ceClient.Send(ctx, event)
140142
if ce.IsUndelivered(res) {
141-
cmdFailedf("failed to send: %s\n", res.Error())
143+
cmdFailedf(cmd, "failed to send: %s\n", res.Error())
142144
} else {
143145
var httpResult *cehttp.Result
144146
ce.ResultAs(res, &httpResult)
145147
if httpResult == nil {
146-
cmdFailedf("failed to send: %s\n", res.Error())
148+
cmdFailedf(cmd, "failed to send: %s\n", res.Error())
147149
} else {
148-
color.Green("sent %d \n", httpResult.StatusCode)
150+
if isOutputFormatJSON(cmd) {
151+
data, _ := json.Marshal(map[string]interface{}{"Result": httpResult.StatusCode})
152+
color.Green(string(data))
153+
} else {
154+
t := table.NewWriter()
155+
t.AppendHeader(table.Row{"Result"})
156+
t.AppendRow(table.Row{httpResult.StatusCode})
157+
t.SetColumnConfigs([]table.ColumnConfig{
158+
{Number: 1, Align: text.AlignCenter, AlignHeader: text.AlignCenter},
159+
{Number: 2, Align: text.AlignCenter, AlignHeader: text.AlignCenter},
160+
})
161+
t.SetOutputMirror(os.Stdout)
162+
t.Render()
163+
}
149164
}
150165
}
151166
}
152167

153-
func sendFile(ctx context.Context, ceClient ce.Client) {
168+
func sendFile(cmd *cobra.Command, ctx context.Context, ceClient ce.Client) {
154169
f, err := os.Open(dataFile)
155170
defer func() {
156171
_ = f.Close()
157172
}()
158173
if err != nil {
159-
cmdFailedf("open data file failed: %s\n", err)
174+
cmdFailedf(cmd, "open data file failed: %s\n", err)
160175
}
161176
events := make([][]string, 0)
162177
reader := bufio.NewReader(f)
@@ -166,38 +181,59 @@ func sendFile(ctx context.Context, ceClient ce.Client) {
166181
if _err == io.EOF {
167182
break
168183
}
169-
cmdFailedf("read data file failed: %s\n", _err)
184+
cmdFailedf(cmd, "read data file failed: %s\n", _err)
170185
}
171186
for isPrx {
172187
var _data []byte
173188
_data, isPrx, err = reader.ReadLine()
174189
if err != nil {
175-
cmdFailedf("read data file failed: %s\n", err)
190+
cmdFailedf(cmd, "read data file failed: %s\n", err)
176191
}
177192
data = append(data, _data...)
178193
}
179194
arr := strings.Split(string(data), ",")
180195
if len(arr) != cloudEventDataRowLength {
181-
cmdFailedf("invalid data file: %s, please see vsctl event put --print-template", string(data))
196+
cmdFailedf(cmd, "invalid data file: %s, please see vsctl event put --print-template", string(data))
182197
}
183198
events = append(events, arr)
184199
}
200+
t := table.NewWriter()
201+
t.AppendHeader(table.Row{"No.", "Result"})
202+
t.SetColumnConfigs([]table.ColumnConfig{
203+
{Number: 1, Align: text.AlignCenter, AlignHeader: text.AlignCenter},
204+
{Number: 2, Align: text.AlignCenter, AlignHeader: text.AlignCenter},
205+
})
206+
t.SetOutputMirror(os.Stdout)
185207
for idx, v := range events {
186208
event := ce.NewEvent()
187209
event.SetID(v[0])
188210
event.SetSource(v[1])
189211
event.SetType(v[2])
190212
err = event.SetData(ce.ApplicationJSON, v[3])
191213
if err != nil {
192-
cmdFailedf("set data failed: %s\n", err)
214+
cmdFailedf(cmd, "set data failed: %s\n", err)
193215
}
194216
res := ceClient.Send(ctx, event)
195217
if ce.IsUndelivered(res) {
196-
cmdFailedf("failed to send: %s\n", res.Error())
218+
cmdFailedf(cmd, "failed to send: %s\n", res.Error())
197219
} else {
198220
var httpResult *cehttp.Result
199221
ce.ResultAs(res, &httpResult)
200-
cmdFailedf("%dth sent %d \n", idx, httpResult.StatusCode)
222+
if httpResult == nil {
223+
cmdFailedf(cmd, "failed to send: %s\n", res.Error())
224+
} else {
225+
if isOutputFormatJSON(cmd) {
226+
data, _ := json.Marshal(map[string]interface{}{
227+
"No.": idx,
228+
"Result": httpResult.StatusCode,
229+
})
230+
color.Green(string(data))
231+
} else {
232+
t.AppendRow(table.Row{idx, httpResult.StatusCode})
233+
t.AppendSeparator()
234+
t.Render()
235+
}
236+
}
201237
}
202238
}
203239
}
@@ -217,26 +253,46 @@ func getEventCommand() *cobra.Command {
217253
idx := strings.LastIndex(endpoint, ":")
218254
port, err := strconv.Atoi(endpoint[idx+1:])
219255
if err != nil {
220-
cmdFailedf("parse gateway port failed: %s, endpoint: %s", err, endpoint)
256+
cmdFailedf(cmd, "parse gateway port failed: %s, endpoint: %s", err, endpoint)
221257
}
222258
endpoint = fmt.Sprintf("%s:%d", endpoint[:idx], port+1)
223259
res, err := newHTTPRequest().Get(fmt.Sprintf("%s/getEvents?eventbus=%s&offset=%d&number=%d",
224260
endpoint, args[0], offset, number))
225261
if err != nil {
226-
cmdFailedf("send request to gateway failed: %s", err)
262+
cmdFailedf(cmd, "send request to gateway failed: %s", err)
227263
}
228264
if res.StatusCode() != http.StatusOK {
229-
cmdFailedf("got response, but no 200 OK: %d", res.StatusCode())
265+
cmdFailedf(cmd, "got response, but no 200 OK: %d", res.StatusCode())
230266
}
231267
data := new(struct {
232268
Events []ce.Event
233269
})
234270
err = json.Unmarshal(res.Body(), data)
235271
if err != nil {
236-
cmdFailedf("unmarshal http response data failed: %s", err)
272+
cmdFailedf(cmd, "unmarshal http response data failed: %s", err)
237273
}
238-
for idx := range data.Events {
239-
color.Yellow("event: %d, %s\n", idx, data.Events[idx].String())
274+
if isOutputFormatJSON(cmd) {
275+
for idx := range data.Events {
276+
data, _ := json.Marshal(map[string]interface{}{
277+
"No.": idx,
278+
"Event": data.Events[idx].String(),
279+
})
280+
281+
color.Yellow(string(data))
282+
}
283+
} else {
284+
t := table.NewWriter()
285+
t.AppendHeader(table.Row{"No.", "Event"})
286+
for idx := range data.Events {
287+
t.AppendRow(table.Row{idx, data.Events[idx].String()})
288+
t.AppendSeparator()
289+
}
290+
t.SetColumnConfigs([]table.ColumnConfig{
291+
{Number: 1, VAlign: text.VAlignMiddle, Align: text.AlignCenter, AlignHeader: text.AlignCenter},
292+
{Number: 2, AlignHeader: text.AlignCenter},
293+
})
294+
t.SetOutputMirror(os.Stdout)
295+
t.Render()
240296
}
241297
},
242298
}

vsctl/command/eventbus.go

Lines changed: 67 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
package command
1616

1717
import (
18-
"bytes"
1918
"context"
2019
"encoding/json"
2120
"os"
@@ -49,7 +48,7 @@ func createEventbusCommand() *cobra.Command {
4948
Short: "create a eventbus",
5049
Run: func(cmd *cobra.Command, args []string) {
5150
if eventbus == "" {
52-
cmdFailedf("the --name flag MUST> be set")
51+
cmdFailedf(cmd, "the --name flag MUST be set")
5352
}
5453
ctx := context.Background()
5554
grpcConn := mustGetLeaderControllerGRPCConn(ctx, cmd)
@@ -62,9 +61,22 @@ func createEventbusCommand() *cobra.Command {
6261
Name: eventbus,
6362
})
6463
if err != nil {
65-
cmdFailedf("create eventbus failed: %s", err)
64+
cmdFailedf(cmd, "create eventbus failed: %s", err)
65+
}
66+
if isOutputFormatJSON(cmd) {
67+
data, _ := json.Marshal(map[string]interface{}{"Result": "Create Success", "Eventbus": eventbus})
68+
color.Green(string(data))
69+
} else {
70+
t := table.NewWriter()
71+
t.AppendHeader(table.Row{"Result", "Eventbus"})
72+
t.AppendRow(table.Row{"Create Success", eventbus})
73+
t.SetColumnConfigs([]table.ColumnConfig{
74+
{Number: 1, VAlign: text.VAlignMiddle, Align: text.AlignCenter, AlignHeader: text.AlignCenter},
75+
{Number: 2, AlignHeader: text.AlignCenter},
76+
})
77+
t.SetOutputMirror(os.Stdout)
78+
t.Render()
6679
}
67-
color.Green("create eventbus: %s success\n", eventbus)
6880
},
6981
}
7082
cmd.Flags().StringVar(&eventbus, "name", "", "eventbus name to deleting")
@@ -77,7 +89,7 @@ func deleteEventbusCommand() *cobra.Command {
7789
Short: "delete a eventbus",
7890
Run: func(cmd *cobra.Command, args []string) {
7991
if eventbus == "" {
80-
cmdFailedf("the --name flag MUST> be set")
92+
cmdFailedf(cmd, "the --name flag MUST be set")
8193
}
8294
ctx := context.Background()
8395
grpcConn := mustGetLeaderControllerGRPCConn(ctx, cmd)
@@ -88,9 +100,22 @@ func deleteEventbusCommand() *cobra.Command {
88100
cli := ctrlpb.NewEventBusControllerClient(grpcConn)
89101
_, err := cli.DeleteEventBus(ctx, &metapb.EventBus{Name: args[0]})
90102
if err != nil {
91-
cmdFailedf("delete eventbus failed: %s", err)
103+
cmdFailedf(cmd, "delete eventbus failed: %s", err)
104+
}
105+
if isOutputFormatJSON(cmd) {
106+
data, _ := json.Marshal(map[string]interface{}{"Result": "Delete Success", "Eventbus": eventbus})
107+
color.Green(string(data))
108+
} else {
109+
t := table.NewWriter()
110+
t.AppendHeader(table.Row{"Result", "Eventbus"})
111+
t.AppendRow(table.Row{"Delete Success", eventbus})
112+
t.SetColumnConfigs([]table.ColumnConfig{
113+
{Number: 1, VAlign: text.VAlignMiddle, Align: text.AlignCenter, AlignHeader: text.AlignCenter},
114+
{Number: 2, AlignHeader: text.AlignCenter},
115+
})
116+
t.SetOutputMirror(os.Stdout)
117+
t.Render()
92118
}
93-
color.Green("delete eventbus: %s success\n", args[0])
94119
},
95120
}
96121
cmd.Flags().StringVar(&eventbus, "name", "", "eventbus name to deleting")
@@ -103,7 +128,7 @@ func getEventbusInfoCommand() *cobra.Command {
103128
Short: "get the eventbus info",
104129
Run: func(cmd *cobra.Command, args []string) {
105130
if eventbus == "" && (len(args) == 0 || args[0] == "") {
106-
cmdFailedf("the eventbus must be set")
131+
cmdFailedf(cmd, "the eventbus must be set")
107132
}
108133
var buses []string
109134
if len(args) > 0 && args[0] != "" {
@@ -123,7 +148,7 @@ func getEventbusInfoCommand() *cobra.Command {
123148
for idx := range buses {
124149
res, err := cli.GetEventBus(ctx, &metapb.EventBus{Name: buses[idx]})
125150
if err != nil {
126-
cmdFailedf("get eventbus failed: %s", err)
151+
cmdFailedf(cmd, "get eventbus failed: %s", err)
127152
}
128153

129154
busMetas = append(busMetas, res)
@@ -136,15 +161,17 @@ func getEventbusInfoCommand() *cobra.Command {
136161
EventLogId: logs[idx].EventLogId,
137162
})
138163
if err != nil {
139-
cmdFailedf("get segments failed: %s", err)
164+
cmdFailedf(cmd, "get segments failed: %s", err)
140165
}
141166
segs[logs[idx].EventLogId] = segRes.Segments
142167
}
143168
}
144169
}
145170

146171
t := table.NewWriter()
147-
172+
if isOutputFormatJSON(cmd) {
173+
color.Yellow("WARN: this command doesn't support --output-format\n")
174+
}
148175
if !showSegment && !showBlock {
149176
t.AppendHeader(table.Row{"Eventbus", "Eventlog", "Segment Number"})
150177
for _, res := range busMetas {
@@ -287,12 +314,36 @@ func listEventbusInfoCommand() *cobra.Command {
287314
cli := ctrlpb.NewEventBusControllerClient(grpcConn)
288315
res, err := cli.ListEventBus(ctx, &empty.Empty{})
289316
if err != nil {
290-
cmdFailedf("list eventbus failed: %s", err)
317+
cmdFailedf(cmd, "list eventbus failed: %s", err)
318+
}
319+
if isOutputFormatJSON(cmd) {
320+
data, _ := json.Marshal(res)
321+
color.Green(string(data))
322+
} else {
323+
t := table.NewWriter()
324+
t.AppendHeader(table.Row{"Name", "ID", "Eventlog", "Segments"})
325+
for idx := range res.Eventbus {
326+
eb := res.Eventbus[idx]
327+
if len(eb.Logs) == 0 {
328+
t.AppendRow(table.Row{eb.Name, eb.Id})
329+
} else {
330+
t.AppendRow(table.Row{eb.Name, eb.Id, eb.Logs[0].EventLogId, eb.Logs[0].CurrentSegmentNumbers})
331+
for sIdx := 1; sIdx < len(eb.Logs); sIdx++ {
332+
t.AppendSeparator()
333+
t.AppendRow(table.Row{eb.Name, eb.Id, eb.Logs[idx].EventLogId, eb.Logs[idx].CurrentSegmentNumbers})
334+
}
335+
}
336+
t.AppendSeparator()
337+
}
338+
t.SetColumnConfigs([]table.ColumnConfig{
339+
{Number: 1, VAlign: text.VAlignMiddle, Align: text.AlignCenter, AlignHeader: text.AlignCenter},
340+
{Number: 2, VAlign: text.VAlignMiddle, Align: text.AlignCenter, AlignHeader: text.AlignCenter},
341+
{Number: 3, Align: text.AlignCenter, AlignHeader: text.AlignCenter},
342+
{Number: 4, Align: text.AlignCenter, AlignHeader: text.AlignCenter},
343+
})
344+
t.SetOutputMirror(os.Stdout)
345+
t.Render()
291346
}
292-
data, _ := json.Marshal(res)
293-
var out bytes.Buffer
294-
_ = json.Indent(&out, data, "", "\t")
295-
color.Green("%s", out.String())
296347
},
297348
}
298349
return cmd

0 commit comments

Comments
 (0)