1
2
3
4
5
6
7
8
9 package main
10
11 import (
12 "flag"
13 "fmt"
14 "os"
15 "strings"
16
17 "github.com/golang/glog"
18 "github.com/golang/protobuf/proto"
19 plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
20 "github.com/grpc-ecosystem/grpc-gateway/codegenerator"
21 "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor"
22 "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/internal/gengateway"
23 )
24
25 var (
26 importPrefix = flag.String("import_prefix", "", "prefix to be added to go package paths for imported proto files")
27 importPath = flag.String("import_path", "", "used as the package if no input files declare go_package. If it contains slashes, everything up to the rightmost slash is ignored.")
28 registerFuncSuffix = flag.String("register_func_suffix", "Handler", "used to construct names of generated Register*<Suffix> methods.")
29 useRequestContext = flag.Bool("request_context", true, "determine whether to use http.Request's context or not")
30 allowDeleteBody = flag.Bool("allow_delete_body", false, "unless set, HTTP DELETE methods may not have a body")
31 grpcAPIConfiguration = flag.String("grpc_api_configuration", "", "path to gRPC API Configuration in YAML format")
32 pathType = flag.String("paths", "", "specifies how the paths of generated files are structured")
33 modulePath = flag.String("module", "", "specifies a module prefix that will be stripped from the go package to determine the output directory")
34 allowRepeatedFieldsInBody = flag.Bool("allow_repeated_fields_in_body", false, "allows to use repeated field in `body` and `response_body` field of `google.api.http` annotation option")
35 repeatedPathParamSeparator = flag.String("repeated_path_param_separator", "csv", "configures how repeated fields should be split. Allowed values are `csv`, `pipes`, `ssv` and `tsv`.")
36 allowPatchFeature = flag.Bool("allow_patch_feature", true, "determines whether to use PATCH feature involving update masks (using google.protobuf.FieldMask).")
37 allowColonFinalSegments = flag.Bool("allow_colon_final_segments", false, "determines whether colons are permitted in the final segment of a path")
38 omitPackageDoc = flag.Bool("omit_package_doc", false, "if true, no package comment will be included in the generated code")
39 versionFlag = flag.Bool("version", false, "print the current version")
40 warnOnUnboundMethods = flag.Bool("warn_on_unbound_methods", false, "emit a warning message if an RPC method has no HttpRule annotation")
41 generateUnboundMethods = flag.Bool("generate_unbound_methods", false, "generate proxy methods even for RPC methods that have no HttpRule annotation")
42 )
43
44
45 var (
46 version = "dev"
47 commit = "unknown"
48 date = "unknown"
49 )
50
51 func main() {
52 flag.Parse()
53 defer glog.Flush()
54
55 if *versionFlag {
56 fmt.Printf("Version %v, commit %v, built at %v\n", version, commit, date)
57 os.Exit(0)
58 }
59
60 reg := descriptor.NewRegistry()
61
62 glog.V(1).Info("Parsing code generator request")
63 req, err := codegenerator.ParseRequest(os.Stdin)
64 if err != nil {
65 glog.Fatal(err)
66 }
67 glog.V(1).Info("Parsed code generator request")
68 if req.Parameter != nil {
69 for _, p := range strings.Split(req.GetParameter(), ",") {
70 spec := strings.SplitN(p, "=", 2)
71 if len(spec) == 1 {
72 if err := flag.CommandLine.Set(spec[0], ""); err != nil {
73 glog.Fatalf("Cannot set flag %s", p)
74 }
75 continue
76 }
77 name, value := spec[0], spec[1]
78 if strings.HasPrefix(name, "M") {
79 reg.AddPkgMap(name[1:], value)
80 continue
81 }
82 if err := flag.CommandLine.Set(name, value); err != nil {
83 glog.Fatalf("Cannot set flag %s", p)
84 }
85 }
86 }
87
88 g := gengateway.New(reg, *useRequestContext, *registerFuncSuffix, *pathType, *modulePath, *allowPatchFeature)
89
90 if *grpcAPIConfiguration != "" {
91 if err := reg.LoadGrpcAPIServiceFromYAML(*grpcAPIConfiguration); err != nil {
92 emitError(err)
93 return
94 }
95 }
96
97 reg.SetPrefix(*importPrefix)
98 reg.SetImportPath(*importPath)
99 reg.SetAllowDeleteBody(*allowDeleteBody)
100 reg.SetAllowRepeatedFieldsInBody(*allowRepeatedFieldsInBody)
101 reg.SetAllowColonFinalSegments(*allowColonFinalSegments)
102 reg.SetOmitPackageDoc(*omitPackageDoc)
103
104 if *warnOnUnboundMethods && *generateUnboundMethods {
105 glog.Warningf("Option warn_on_unbound_methods has no effect when generate_unbound_methods is used.")
106 }
107
108 reg.SetWarnOnUnboundMethods(*warnOnUnboundMethods)
109 reg.SetGenerateUnboundMethods(*generateUnboundMethods)
110 if err := reg.SetRepeatedPathParamSeparator(*repeatedPathParamSeparator); err != nil {
111 emitError(err)
112 return
113 }
114 if err := reg.Load(req); err != nil {
115 emitError(err)
116 return
117 }
118 unboundHTTPRules := reg.UnboundExternalHTTPRules()
119 if len(unboundHTTPRules) != 0 {
120 emitError(fmt.Errorf("HTTP rules without a matching selector: %s", strings.Join(unboundHTTPRules, ", ")))
121 return
122 }
123
124 var targets []*descriptor.File
125 for _, target := range req.FileToGenerate {
126 f, err := reg.LookupFile(target)
127 if err != nil {
128 glog.Fatal(err)
129 }
130 targets = append(targets, f)
131 }
132
133 out, err := g.Generate(targets)
134 glog.V(1).Info("Processed code generator request")
135 if err != nil {
136 emitError(err)
137 return
138 }
139 emitFiles(out)
140 }
141
142 func emitFiles(out []*plugin.CodeGeneratorResponse_File) {
143 emitResp(&plugin.CodeGeneratorResponse{File: out})
144 }
145
146 func emitError(err error) {
147 emitResp(&plugin.CodeGeneratorResponse{Error: proto.String(err.Error())})
148 }
149
150 func emitResp(resp *plugin.CodeGeneratorResponse) {
151 buf, err := proto.Marshal(resp)
152 if err != nil {
153 glog.Fatal(err)
154 }
155 if _, err := os.Stdout.Write(buf); err != nil {
156 glog.Fatal(err)
157 }
158 }
159
View as plain text