Skip to content

Commit 0a3ddf0

Browse files
authored
Allow printing SCIP index as JSON (#147)
- Add `--json` flag to `scip print` command to output as JSON - Manually update docs about CLI subcommands
1 parent 6c9b4a6 commit 0a3ddf0

File tree

4 files changed

+117
-11
lines changed

4 files changed

+117
-11
lines changed

cmd/convert.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func convertCommand() cli.Command {
2929
Name: "to",
3030
Usage: "Output path for LSIF index",
3131
Destination: &convertFlags.to,
32-
Value: "dump.lsif",
32+
Value: "dump.lsif",
3333
},
3434
},
3535
Action: func(c *cli.Context) error {

cmd/print.go

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,59 @@
11
package main
22

33
import (
4+
"io"
5+
"math"
6+
47
"github.com/k0kubun/pp/v3"
58
"github.com/urfave/cli/v2"
6-
"math"
9+
"google.golang.org/protobuf/encoding/protojson"
710

811
"github.com/sourcegraph/sourcegraph/lib/errors"
912
)
1013

1114
func printCommand() cli.Command {
15+
var json bool
1216
snapshot := cli.Command{
1317
Name: "print",
1418
Usage: "Print a SCIP index in a human-readable format for debugging",
1519
Description: `WARNING: The output may change over time.
1620
Do not rely on the output of this command in scripts`,
21+
Flags: []cli.Flag{
22+
&cli.BoolFlag{
23+
Name: "json",
24+
Usage: "Output in JSON format",
25+
Destination: &json,
26+
},
27+
},
1728
Action: func(c *cli.Context) error {
1829
indexPath := c.Args().Get(0)
1930
if indexPath == "" {
2031
return errors.New("missing argument for path to SCIP index")
2132
}
22-
return printMain(indexPath)
33+
return printMain(indexPath, json, c.App.Writer)
2334
},
2435
}
2536
return snapshot
2637
}
2738

28-
func printMain(indexPath string) error {
39+
func printMain(indexPath string, json bool, out io.Writer) error {
2940
index, err := readFromOption(indexPath)
3041
if err != nil {
3142
return err
3243
}
33-
pp.BufferFoldThreshold = math.MaxInt
34-
prettyPrinter := pp.New()
35-
prettyPrinter.SetExportedOnly(true)
36-
_, err = prettyPrinter.Print(index)
37-
return err
44+
if json {
45+
pp.BufferFoldThreshold = math.MaxInt
46+
47+
options := protojson.MarshalOptions{}
48+
49+
jsonBytes, err := options.Marshal(index)
50+
out.Write(jsonBytes)
51+
return err
52+
} else {
53+
prettyPrinter := pp.New()
54+
prettyPrinter.SetExportedOnly(true)
55+
prettyPrinter.SetOutput(out)
56+
_, err = prettyPrinter.Print(index)
57+
return err
58+
}
3859
}

cmd/print_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"io"
7+
"io/ioutil"
8+
"log"
9+
"os"
10+
"testing"
11+
12+
"github.com/sourcegraph/scip/bindings/go/scip"
13+
"github.com/stretchr/testify/require"
14+
"google.golang.org/protobuf/proto"
15+
)
16+
17+
func TestJSONPrinting(t *testing.T) {
18+
app := scipApp()
19+
// Redirect CLI writer to a buffer
20+
var buff bytes.Buffer
21+
app.Writer = io.Writer(&buff)
22+
idx := makeIndex([]string{"a"}, stringMap{"f": {"b"}}, stringMap{"f": {"a", "b"}})
23+
24+
idx.Metadata = &scip.Metadata{ProjectRoot: "howdy"}
25+
26+
// Serialise SCIP index
27+
indexBytes, err := proto.Marshal(idx)
28+
29+
// Write SCIP index to a temp file
30+
dir := os.TempDir()
31+
file, err := ioutil.TempFile(dir, "scip-cli-json-test*.scip")
32+
if err != nil {
33+
log.Fatal(err)
34+
}
35+
defer os.Remove(file.Name())
36+
37+
_, fErr := file.Write(indexBytes)
38+
if fErr != nil {
39+
log.Fatal(fErr)
40+
}
41+
42+
// Run the JSON command with the temporary file
43+
runErr := app.Run([]string{"scip", "print", "--json", file.Name()})
44+
if runErr != nil {
45+
log.Fatal(runErr)
46+
}
47+
48+
type JsonIndex struct {
49+
Metadata struct {
50+
ProjectRoot string `json:"projectRoot"`
51+
}
52+
Documents []struct {
53+
RelativePath string `json:"relativePath"`
54+
} `json:"documents"`
55+
}
56+
57+
var roundtripResult JsonIndex
58+
59+
bytes := buff.Bytes()
60+
61+
jsonErr := json.Unmarshal(bytes, &roundtripResult)
62+
if jsonErr != nil {
63+
log.Fatal(jsonErr)
64+
}
65+
66+
require.Equal(t, roundtripResult.Metadata.ProjectRoot, "howdy")
67+
require.Equal(t, len(roundtripResult.Documents), 1)
68+
require.Equal(t, roundtripResult.Documents[0].RelativePath, "f")
69+
}

docs/CLI.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# SCIP CLI Reference
22

3+
<!--toc:start-->
4+
5+
- [SCIP CLI Reference](#scip-cli-reference)
6+
- [`scip convert`](#scip-convert)
7+
- [`scip lint`](#scip-lint)
8+
- [`scip print`](#scip-print)
9+
- [`scip snapshot`](#scip-snapshot)
10+
- [`scip stats`](#scip-stats)
11+
<!--toc:end-->
12+
313
```
414
NAME:
515
scip - SCIP Code Intelligence Protocol CLI
@@ -26,6 +36,7 @@ COMMANDS:
2636
GLOBAL OPTIONS:
2737
--help, -h show help (default: false)
2838
--version, -v print the version (default: false)
39+
2940
```
3041

3142
## `scip convert`
@@ -78,6 +89,7 @@ DESCRIPTION:
7889
7990
OPTIONS:
8091
--help, -h show help (default: false)
92+
--json Output in JSON format (default: false)
8193
```
8294

8395
## `scip snapshot`
@@ -96,8 +108,12 @@ DESCRIPTION:
96108
and symbol information.
97109
98110
OPTIONS:
99-
--from value Path to SCIP index file (default: index.scip)
100-
--to value Path to output directory for snapshot files (default: scip-snapshot)
111+
--comment-syntax value Comment syntax to use for snapshot files (default: "//")
112+
--from value Path to SCIP index file (default: "index.scip")
113+
--help, -h show help (default: false)
114+
--project-root value Override project root in the SCIP file. For example, this can be helpful when the SCIP index was created inside a Docker image or created on another computer
115+
--strict If true, fail fast on errors (default: true)
116+
--to value Path to output directory for snapshot files (default: "scip-snapshot")
101117
```
102118

103119
## `scip stats`

0 commit comments

Comments
 (0)