...

Source file src/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/main.go

Documentation: github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway

     1  // Command protoc-gen-grpc-gateway is a plugin for Google protocol buffer
     2  // compiler to generate a reverse-proxy, which converts incoming RESTful
     3  // HTTP/1 requests gRPC invocation.
     4  // You rarely need to run this program directly. Instead, put this program
     5  // into your $PATH with a name "protoc-gen-grpc-gateway" and run
     6  //   protoc --grpc-gateway_out=output_directory path/to/input.proto
     7  //
     8  // See README.md for more details.
     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  // Variables set by goreleaser at build time
    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