Skip to content

Commit

Permalink
Add a protoc wrapper (bazel-contrib#1100)
Browse files Browse the repository at this point in the history
* Add a protoc wrapper

This version lets us add a much more informative message when the importpaths
are wrong for example:

```
2017/12/04 10:58:59 protoc failed to make all outputs
Got
[bazel-out/k8-fastbuild/bin/examples/proto/dep/useful_go_proto~/examples/proto/dep/useful.pb.go]
Expected
[bazel-out/k8-fastbuild/bin/examples/proto/dep/useful_go_proto~/github.com/bazelbuild/rules_go/examples/proto/dep/useful.pb.go]
Check the go package stanza is github.com/bazelbuild/rules_go/examples/proto/dep
```

* Review fixes
  • Loading branch information
ianthehat authored Dec 4, 2017
1 parent 3930b2c commit fd30212
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 1 deletion.
9 changes: 9 additions & 0 deletions go/tools/builders/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,12 @@ go_tool_binary(
],
visibility = ["//visibility:public"],
)

go_tool_binary(
name = "go-protoc",
srcs = [
"flags.go",
"protoc.go",
],
visibility = ["//visibility:public"],
)
84 changes: 84 additions & 0 deletions go/tools/builders/protoc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright 2017 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// protoc invokes the protobuf compiler and captures the resulting .pb.go file.
package main

import (
"flag"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
)

func run(args []string) error {
// process the args
expected := multiFlag{}
flags := flag.NewFlagSet("protoc", flag.ExitOnError)
protoc := flags.String("protoc", "", "The path to the real protoc.")
descriptor_set_in := flags.String("descriptor_set_in", "", "The descriptor set to read.")
go_out := flags.String("go_out", "", "The go plugin options.")
plugin := flags.String("plugin", "", "The go plugin to use.")
importpath := flags.String("importpath", "", "The importpath for the generated sources.")
flags.Var(&expected, "expected", "The expected output files.")
if err := flags.Parse(args); err != nil {
return err
}
protoc_args := []string{
"--go_out", *go_out,
"--plugin", *plugin,
"--descriptor_set_in", *descriptor_set_in,
}
protoc_args = append(protoc_args, flags.Args()...)
cmd := exec.Command(*protoc, protoc_args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return fmt.Errorf("error running protoc: %v", err)
}
notFound := []string{}
for _, src := range expected {
if _, err := os.Stat(src); os.IsNotExist(err) {
notFound = append(notFound, src)
}
}
if len(notFound) > 0 {
unexpected := []string{}
filepath.Walk(".", func(path string, f os.FileInfo, err error) error {
if strings.HasSuffix(path, ".pb.go") {
wasExpected := false
for _, s := range expected {
if s == path {
wasExpected = true
}
}
if !wasExpected {
unexpected = append(unexpected, path)
}
}
return nil
})
return fmt.Errorf("protoc failed to make all outputs\nGot %v\nExpected %v\nCheck that the go_package option is %q.", unexpected, notFound, *importpath)
}
return nil
}

func main() {
if err := run(os.Args[1:]); err != nil {
log.Fatal(err)
}
}
15 changes: 14 additions & 1 deletion proto/compiler.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,27 @@ def go_proto_compile(ctx, compiler, lib, importpath):
if plugin_base_name.startswith(_protoc_prefix):
plugin_base_name = plugin_base_name[len(_protoc_prefix):]
args = ctx.actions.args()
args.add(["-protoc", compiler.protoc.path])
args.add([
"--importpath", importpath,
"--{}_out={}:{}".format(plugin_base_name, ",".join(compiler.options), outpath),
"--plugin={}={}".format(compiler.plugin.basename, compiler.plugin.path),
"--descriptor_set_in", ":".join(
[s.path for s in lib.proto.transitive_descriptor_sets])
])
for out in go_srcs:
args.add(["--expected", out])
args.add(lib.proto.direct_sources, map_fn=_all_proto_paths)
ctx.actions.run(
inputs = sets.union([
compiler.go_protoc,
compiler.protoc,
compiler.plugin,
], lib.proto.transitive_descriptor_sets),
outputs = go_srcs,
progress_message = "Generating into %s" % go_srcs[0].dirname,
mnemonic = "GoProtocGen",
executable = compiler.protoc,
executable = compiler.go_protoc,
arguments = [args],
)
return go_srcs
Expand Down Expand Up @@ -80,6 +85,7 @@ def _go_proto_compiler_impl(ctx):
compile = go_proto_compile,
options = ctx.attr.options,
suffix = ctx.attr.suffix,
go_protoc = ctx.file._go_protoc,
protoc = ctx.file._protoc,
plugin = ctx.file.plugin,
)]
Expand All @@ -97,6 +103,13 @@ go_proto_compiler = rule(
cfg = "host",
default = Label("@com_github_golang_protobuf//protoc-gen-go"),
),
"_go_protoc": attr.label(
allow_files=True,
single_file=True,
executable = True,
cfg = "host",
default=Label("@io_bazel_rules_go//go/tools/builders:go-protoc"),
),
"_protoc": attr.label(
allow_files = True,
single_file = True,
Expand Down

0 comments on commit fd30212

Please sign in to comment.