Skip to content

Commit 05d3348

Browse files
authored
streaming: support JSON flag (#492)
This adds support for `-json` to streaming search. Events are split into individual results and written as JSON to stdout. Each line contains 1 result with possibly many matches.
1 parent 556ba8b commit 05d3348

File tree

5 files changed

+192
-104
lines changed

5 files changed

+192
-104
lines changed

cmd/src/search.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ Other tips:
5555
explainJSONFlag = flagSet.Bool("explain-json", false, "Explain the JSON output schema and exit.")
5656
apiFlags = api.NewFlags(flagSet)
5757
lessFlag = flagSet.Bool("less", true, "Pipe output to 'less -R' (only if stdout is terminal, and not json flag).")
58-
streamFlag = flagSet.Bool("stream", false, "Consume results as stream. Streaming search only supports a subset of flags and parameters: trace, insecure-skip-verify, display.")
58+
streamFlag = flagSet.Bool("stream", false, "Consume results as stream. Streaming search only supports a subset of flags and parameters: trace, insecure-skip-verify, display, json.")
5959
display = flagSet.Int("display", -1, "Limit the number of results that are displayed. Only supported together with stream flag. Statistics continue to report all results.")
6060
)
6161

@@ -68,6 +68,7 @@ Other tips:
6868
opts := streaming.Opts{
6969
Display: *display,
7070
Trace: apiFlags.Trace(),
71+
Json: *jsonFlag,
7172
}
7273
client := cfg.apiClient(apiFlags, flagSet.Output())
7374
return streamSearch(flagSet.Arg(0), opts, client, os.Stdout)

cmd/src/search_stream.go

Lines changed: 75 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ package main
22

33
import (
44
"bytes"
5+
"encoding/json"
56
"fmt"
67
"io"
78
"os"
89
"os/exec"
910
"regexp"
1011
"strconv"
1112
"strings"
13+
"text/template"
1214

1315
"github.com/sourcegraph/src-cli/internal/api"
1416
"github.com/sourcegraph/src-cli/internal/streaming"
@@ -21,20 +23,77 @@ func init() {
2123
}
2224

2325
func streamSearch(query string, opts streaming.Opts, client api.Client, w io.Writer) error {
24-
t, err := parseTemplate(streamingTemplate)
25-
if err != nil {
26-
panic(err)
26+
var d streaming.Decoder
27+
if opts.Json {
28+
d = jsonDecoder(w)
29+
} else {
30+
t, err := parseTemplate(streamingTemplate)
31+
if err != nil {
32+
return err
33+
}
34+
d = textDecoder(query, t, w)
35+
}
36+
return streaming.Search(query, opts, client, d)
37+
}
38+
39+
// jsonDecoder streams results as JSON to w.
40+
func jsonDecoder(w io.Writer) streaming.Decoder {
41+
// write json.Marshals data and writes it as one line to w plus a newline.
42+
write := func(data interface{}) error {
43+
b, err := json.Marshal(data)
44+
if err != nil {
45+
return err
46+
}
47+
_, err = w.Write(b)
48+
if err != nil {
49+
return err
50+
}
51+
_, err = w.Write([]byte("\n"))
52+
if err != nil {
53+
return err
54+
}
55+
return nil
2756
}
28-
logError := func(msg string) {
29-
_, _ = fmt.Fprintf(os.Stderr, msg)
57+
58+
return streaming.Decoder{
59+
OnProgress: func(progress *streaming.Progress) {
60+
if !progress.Done {
61+
return
62+
}
63+
err := write(progress)
64+
if err != nil {
65+
logError(err.Error())
66+
}
67+
},
68+
OnMatches: func(matches []streaming.EventMatch) {
69+
for _, match := range matches {
70+
err := write(match)
71+
if err != nil {
72+
logError(err.Error())
73+
}
74+
}
75+
},
76+
OnAlert: func(alert *streaming.EventAlert) {
77+
err := write(alert)
78+
if err != nil {
79+
logError(err.Error())
80+
}
81+
},
82+
OnError: func(eventError *streaming.EventError) {
83+
// Errors are just written to stderr.
84+
logError(eventError.Message)
85+
},
3086
}
31-
decoder := streaming.Decoder{
87+
}
88+
89+
func textDecoder(query string, t *template.Template, w io.Writer) streaming.Decoder {
90+
return streaming.Decoder{
3291
OnProgress: func(progress *streaming.Progress) {
3392
// We only show the final progress.
3493
if !progress.Done {
3594
return
3695
}
37-
err = t.ExecuteTemplate(w, "progress", progress)
96+
err := t.ExecuteTemplate(w, "progress", progress)
3897
if err != nil {
3998
logError(fmt.Sprintf("error when executing template: %s\n", err))
4099
}
@@ -52,7 +111,7 @@ func streamSearch(query string, opts streaming.Opts, client api.Client, w io.Wri
52111
})
53112
}
54113

55-
err = t.ExecuteTemplate(w, "alert", searchResultsAlert{
114+
err := t.ExecuteTemplate(w, "alert", searchResultsAlert{
56115
Title: alert.Title,
57116
Description: alert.Description,
58117
ProposedQueries: proposedQueries,
@@ -66,7 +125,7 @@ func streamSearch(query string, opts streaming.Opts, client api.Client, w io.Wri
66125
for _, match := range matches {
67126
switch match := match.(type) {
68127
case *streaming.EventFileMatch:
69-
err = t.ExecuteTemplate(w, "file", struct {
128+
err := t.ExecuteTemplate(w, "file", struct {
70129
Query string
71130
*streaming.EventFileMatch
72131
}{
@@ -79,7 +138,7 @@ func streamSearch(query string, opts streaming.Opts, client api.Client, w io.Wri
79138
return
80139
}
81140
case *streaming.EventRepoMatch:
82-
err = t.ExecuteTemplate(w, "repo", struct {
141+
err := t.ExecuteTemplate(w, "repo", struct {
83142
SourcegraphEndpoint string
84143
*streaming.EventRepoMatch
85144
}{
@@ -91,7 +150,7 @@ func streamSearch(query string, opts streaming.Opts, client api.Client, w io.Wri
91150
return
92151
}
93152
case *streaming.EventCommitMatch:
94-
err = t.ExecuteTemplate(w, "commit", struct {
153+
err := t.ExecuteTemplate(w, "commit", struct {
95154
SourcegraphEndpoint string
96155
*streaming.EventCommitMatch
97156
}{
@@ -103,7 +162,7 @@ func streamSearch(query string, opts streaming.Opts, client api.Client, w io.Wri
103162
return
104163
}
105164
case *streaming.EventSymbolMatch:
106-
err = t.ExecuteTemplate(w, "symbol", struct {
165+
err := t.ExecuteTemplate(w, "symbol", struct {
107166
SourcegraphEndpoint string
108167
*streaming.EventSymbolMatch
109168
}{
@@ -119,8 +178,6 @@ func streamSearch(query string, opts streaming.Opts, client api.Client, w io.Wri
119178
}
120179
},
121180
}
122-
123-
return streaming.Search(query, opts, client, decoder)
124181
}
125182

126183
const streamingTemplate = `
@@ -362,3 +419,7 @@ func streamConvertMatchToHighlights(m streaming.EventLineMatch, isPreview bool)
362419
}
363420
return highlights
364421
}
422+
423+
func logError(msg string) {
424+
_, _ = fmt.Fprintf(os.Stderr, msg)
425+
}

0 commit comments

Comments
 (0)