Skip to content

Commit e5e6ac7

Browse files
authored
Fixes #1 - use streamed_output to get around 2GB limitation (#10)
1 parent ea47461 commit e5e6ac7

7 files changed

Lines changed: 86 additions & 17 deletions

File tree

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ A couple reasons:
8080

8181
* Some of the short codes for the CLI are different (only supporting one character instead of two)
8282
* Due to some minor implementation differences, the actual hashes generated by the two programs are different
83-
* `bazel-differ` isn't using `streamed_proto` output from Bazel query (I'm not sure if there is a Go implemntation of this?). In some minimal testing against some large repositories, `bazel-differ` still seems to outperform `bazel-diff` by 2x.
8483

8584
3. What target types has this been tested against?
8685

internal/BUILD.bazel

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ go_library(
1111
"filesystem.go",
1212
"git_client.go",
1313
"io_utils.go",
14+
"proto_delimited.go",
1415
"target_hashing_client.go",
1516
],
1617
importpath = "github.com/ewhauser/bazel-differ/internal",
@@ -24,9 +25,15 @@ go_library(
2425

2526
go_test(
2627
name = "internal_test",
27-
srcs = ["target_hashing_client_test.go"],
28+
srcs = [
29+
"proto_delimited_test.go",
30+
"target_hashing_client_test.go",
31+
],
32+
data = [
33+
"query.protodelim", # keep
34+
],
35+
embed = [":internal"],
2836
deps = [
29-
":internal",
3037
"//mocks",
3138
"@com_github_golang_mock//gomock",
3239
],

internal/bazel.go

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ import (
1818
"bytes"
1919
"context"
2020
"errors"
21-
"fmt"
22-
"google.golang.org/protobuf/proto"
2321
"io"
2422
"log"
2523
"os"
@@ -122,7 +120,7 @@ type Bazel interface {
122120
WriteToStderr(v bool)
123121
WriteToStdout(v bool)
124122
Info() (map[string]string, error)
125-
Query(args ...string) (*QueryResult, error)
123+
Query(args ...string) ([]*Target, error)
126124
Build(args ...string) (*bytes.Buffer, error)
127125
Test(args ...string) (*bytes.Buffer, error)
128126
Run(args ...string) (*exec.Cmd, *bytes.Buffer, error)
@@ -286,8 +284,8 @@ func (b *bazel) processInfo(info string) (map[string]string, error) {
286284
// or to find a dependency path between //path/to/package:target and //dependency:
287285
//
288286
// res, err := b.Query('somepath(//path/to/package:target, //dependency)')
289-
func (b *bazel) Query(args ...string) (*QueryResult, error) {
290-
blazeArgs := append([]string(nil), "--output=proto", "--order_output=no", "--color=no")
287+
func (b *bazel) Query(args ...string) ([]*Target, error) {
288+
blazeArgs := append([]string(nil), "--output=streamed_proto", "--order_output=no", "--color=no")
291289
blazeArgs = append(blazeArgs, args...)
292290

293291
b.WriteToStderr(true)
@@ -302,14 +300,9 @@ func (b *bazel) Query(args ...string) (*QueryResult, error) {
302300
return b.processQuery(stdoutBuffer.Bytes())
303301
}
304302

305-
func (b *bazel) processQuery(out []byte) (*QueryResult, error) {
306-
var qr QueryResult
307-
if err := proto.Unmarshal(out, &qr); err != nil {
308-
fmt.Fprintf(os.Stderr, "Could not read blaze query response. Error: %s\nOutput: %s\n", err, out)
309-
return nil, err
310-
}
311-
312-
return &qr, nil
303+
func (b *bazel) processQuery(out []byte) ([]*Target, error) {
304+
reader := NewReader(bytes.NewReader(out))
305+
return reader.ReadTargets()
313306
}
314307

315308
func (b *bazel) Build(args ...string) (*bytes.Buffer, error) {

internal/bazel_client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,5 +146,5 @@ func (b bazelClient) performBazelQuery(query string) ([]*Target, error) {
146146
if err != nil {
147147
return nil, err
148148
}
149-
return result.Target, nil
149+
return result, nil
150150
}

internal/proto_delimited.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package internal
2+
3+
import (
4+
"bufio"
5+
"encoding/binary"
6+
"fmt"
7+
"google.golang.org/protobuf/proto"
8+
"io"
9+
)
10+
11+
type ProtoDelimitedReader struct {
12+
buf *bufio.Reader
13+
}
14+
15+
func NewReader(r io.Reader) *ProtoDelimitedReader {
16+
return &ProtoDelimitedReader{
17+
buf: bufio.NewReader(r),
18+
}
19+
}
20+
21+
func (r *ProtoDelimitedReader) Next() ([]byte, error) {
22+
size, err := binary.ReadUvarint(r.buf)
23+
if err != nil {
24+
return nil, err
25+
}
26+
data := make([]byte, size)
27+
if _, err := io.ReadFull(r.buf, data); err != nil {
28+
return nil, err
29+
}
30+
return data, nil
31+
}
32+
33+
func (r *ProtoDelimitedReader) ReadTargets() ([]*Target, error) {
34+
var targets []*Target
35+
var err error
36+
for buf, err := r.Next(); err == nil; buf, err = r.Next() {
37+
var target Target
38+
if err := proto.Unmarshal(buf, &target); err != nil {
39+
return nil, fmt.Errorf("failed to unmarshal Target message: %w", err)
40+
}
41+
targets = append(targets, &target)
42+
}
43+
if err != nil && err != io.EOF {
44+
return nil, fmt.Errorf("error while reading stdout from bazel command: %w", err)
45+
}
46+
return targets, nil
47+
}

internal/proto_delimited_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package internal
2+
3+
import (
4+
"bytes"
5+
"io/ioutil"
6+
"testing"
7+
)
8+
9+
func TestDelimitedReader(t *testing.T) {
10+
protoBytes, err := ioutil.ReadFile("query.protodelim")
11+
if err != nil {
12+
t.Errorf("Error reading file")
13+
}
14+
reader := NewReader(bytes.NewReader(protoBytes))
15+
targets, err := reader.ReadTargets()
16+
if err != nil {
17+
t.Errorf("error marshalling: %s", err)
18+
t.FailNow()
19+
}
20+
if len(targets) != 49 {
21+
t.Errorf("Expecting 49 targets but got %d", len(targets))
22+
}
23+
}

internal/query.protodelim

110 KB
Binary file not shown.

0 commit comments

Comments
 (0)