1 // Copyright 2016 Google Inc.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
17 // Regen.go regenerates the genproto repository.
19 // Regen.go recursively walks through each directory named by given arguments,
20 // looking for all .proto files. (Symlinks are not followed.)
21 // If the pkg_prefix flag is not an empty string,
22 // any proto file without `go_package` option
23 // or whose option does not begin with the prefix is ignored.
24 // Protoc is executed on remaining files,
25 // one invocation per set of files declaring the same Go package.
41 var goPkgOptRe = regexp.MustCompile(`(?m)^option go_package = (.*);`)
44 fmt.Fprintln(os.Stderr, `usage: go run regen.go -go_out=path/to/output [-pkg_prefix=pkg/prefix] roots...
46 Most users will not need to run this file directly.
47 To regenerate this repository, run regen.sh instead.`)
52 goOutDir := flag.String("go_out", "", "go_out argument to pass to protoc-gen-go")
53 pkgPrefix := flag.String("pkg_prefix", "", "only include proto files with go_package starting with this prefix")
58 log.Fatal("need go_out flag")
61 pkgFiles := make(map[string][]string)
62 walkFn := func(path string, info os.FileInfo, err error) error {
66 if !info.Mode().IsRegular() || !strings.HasSuffix(path, ".proto") {
69 pkg, err := goPkg(path)
73 pkgFiles[pkg] = append(pkgFiles[pkg], path)
76 for _, root := range flag.Args() {
77 if err := filepath.Walk(root, walkFn); err != nil {
81 for pkg, fnames := range pkgFiles {
82 if !strings.HasPrefix(pkg, *pkgPrefix) {
85 if out, err := protoc(*goOutDir, flag.Args(), fnames); err != nil {
86 log.Fatalf("error executing protoc: %s\n%s", err, out)
91 // goPkg reports the import path declared in the given file's
92 // `go_package` option. If the option is missing, goPkg returns empty string.
93 func goPkg(fname string) (string, error) {
94 content, err := ioutil.ReadFile(fname)
100 if match := goPkgOptRe.FindSubmatch(content); len(match) > 0 {
101 pn, err := strconv.Unquote(string(match[1]))
107 if p := strings.IndexRune(pkgName, ';'); p > 0 {
108 pkgName = pkgName[:p]
113 // protoc executes the "protoc" command on files named in fnames,
114 // passing go_out and include flags specified in goOut and includes respectively.
115 // protoc returns combined output from stdout and stderr.
116 func protoc(goOut string, includes, fnames []string) ([]byte, error) {
117 args := []string{"--go_out=plugins=grpc:" + goOut}
118 for _, inc := range includes {
119 args = append(args, "-I", inc)
121 args = append(args, fnames...)
122 return exec.Command("protoc", args...).CombinedOutput()