Skip to content

Commit

Permalink
Add module generator option (#1400)
Browse files Browse the repository at this point in the history
* Add module generator option

* Feedback from code review
  • Loading branch information
Humpheh authored May 26, 2020
1 parent e4d31aa commit 29efd26
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 9 deletions.
32 changes: 28 additions & 4 deletions protoc-gen-grpc-gateway/internal/gengateway/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ type generator struct {
useRequestContext bool
registerFuncSuffix string
pathType pathType
modulePath string
allowPatchFeature bool
}

// New returns a new generator which generates grpc gateway files.
func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix, pathTypeString string, allowPatchFeature bool) gen.Generator {
func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix, pathTypeString, modulePathString string, allowPatchFeature bool) gen.Generator {
var imports []descriptor.GoPackage
for _, pkgpath := range []string{
"context",
Expand Down Expand Up @@ -84,6 +85,7 @@ func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix, p
useRequestContext: useRequestContext,
registerFuncSuffix: registerFuncSuffix,
pathType: pathType,
modulePath: modulePathString,
allowPatchFeature: allowPatchFeature,
}
}
Expand All @@ -105,9 +107,10 @@ func (g *generator) Generate(targets []*descriptor.File) ([]*plugin.CodeGenerato
glog.Errorf("%v: %s", err, code)
return nil, err
}
name := file.GetName()
if g.pathType == pathTypeImport && file.GoPkg.Path != "" {
name = fmt.Sprintf("%s/%s", file.GoPkg.Path, filepath.Base(name))
name, err := g.getFilePath(file)
if err != nil {
glog.Errorf("%v: %s", err, code)
return nil, err
}
ext := filepath.Ext(name)
base := strings.TrimSuffix(name, ext)
Expand All @@ -121,6 +124,27 @@ func (g *generator) Generate(targets []*descriptor.File) ([]*plugin.CodeGenerato
return files, nil
}

func (g *generator) getFilePath(file *descriptor.File) (string, error) {
name := file.GetName()
switch {
case g.modulePath != "" && g.pathType != pathTypeImport:
return "", errors.New("cannot use module= with paths=")

case g.modulePath != "":
trimPath, pkgPath := g.modulePath+"/", file.GoPkg.Path+"/"
if !strings.HasPrefix(pkgPath, trimPath) {
return "", fmt.Errorf("%v: file go path does not match module prefix: %v", file.GoPkg.Path, trimPath)
}
return filepath.Join(strings.TrimPrefix(pkgPath, trimPath), filepath.Base(name)), nil

case g.pathType == pathTypeImport && file.GoPkg.Path != "":
return fmt.Sprintf("%s/%s", file.GoPkg.Path, filepath.Base(name)), nil

default:
return name, nil
}
}

func (g *generator) generate(file *descriptor.File) (string, error) {
pkgSeen := make(map[string]bool)
var imports []descriptor.GoPackage
Expand Down
77 changes: 73 additions & 4 deletions protoc-gen-grpc-gateway/internal/gengateway/generator_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package gengateway

import (
"errors"
"path/filepath"
"strings"
"testing"
Expand Down Expand Up @@ -100,9 +101,11 @@ func TestGenerateServiceWithoutBindings(t *testing.T) {

func TestGenerateOutputPath(t *testing.T) {
cases := []struct {
file *descriptor.File
pathType pathType
expected string
file *descriptor.File
pathType pathType
modulePath string
expected string
expectedError error
}{
{
file: newExampleFileDescriptorWithGoPkg(
Expand Down Expand Up @@ -142,13 +145,79 @@ func TestGenerateOutputPath(t *testing.T) {
pathType: pathTypeSourceRelative,
expected: ".",
},
{
file: newExampleFileDescriptorWithGoPkg(
&descriptor.GoPackage{
Path: "example.com/path/root",
Name: "example_pb",
},
),
modulePath: "example.com/path/root",
expected: ".",
},
{
file: newExampleFileDescriptorWithGoPkg(
&descriptor.GoPackage{
Path: "example.com/path/to/example",
Name: "example_pb",
},
),
modulePath: "example.com/path/to",
expected: "example",
},
{
file: newExampleFileDescriptorWithGoPkg(
&descriptor.GoPackage{
Path: "example.com/path/to/example/with/many/nested/paths",
Name: "example_pb",
},
),
modulePath: "example.com/path/to",
expected: "example/with/many/nested/paths",
},

// Error cases
{
file: newExampleFileDescriptorWithGoPkg(
&descriptor.GoPackage{
Path: "example.com/path/root",
Name: "example_pb",
},
),
modulePath: "example.com/path/root",
pathType: pathTypeSourceRelative, // Not allowed
expectedError: errors.New("cannot use module= with paths="),
},
{
file: newExampleFileDescriptorWithGoPkg(
&descriptor.GoPackage{
Path: "example.com/path/rootextra",
Name: "example_pb",
},
),
modulePath: "example.com/path/root",
expectedError: errors.New("example.com/path/rootextra: file go path does not match module prefix: example.com/path/root/"),
},
}

for _, c := range cases {
g := &generator{pathType: c.pathType}
g := &generator{
pathType: c.pathType,
modulePath: c.modulePath,
}

file := c.file
gots, err := g.Generate([]*descriptor.File{crossLinkFixture(file)})

// If we expect an error response, check it matches what we want
if c.expectedError != nil {
if err == nil || err.Error() != c.expectedError.Error() {
t.Errorf("Generate(%#v) failed with %v; wants error of: %v", file, err, c.expectedError)
}
return
}

// Handle case where we don't expect an error
if err != nil {
t.Errorf("Generate(%#v) failed with %v; wants success", file, err)
return
Expand Down
3 changes: 2 additions & 1 deletion protoc-gen-grpc-gateway/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ var (
allowDeleteBody = flag.Bool("allow_delete_body", false, "unless set, HTTP DELETE methods may not have a body")
grpcAPIConfiguration = flag.String("grpc_api_configuration", "", "path to gRPC API Configuration in YAML format")
pathType = flag.String("paths", "", "specifies how the paths of generated files are structured")
modulePath = flag.String("module", "", "specifies a module prefix that will be stripped from the go package to determine the output directory")
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")
repeatedPathParamSeparator = flag.String("repeated_path_param_separator", "csv", "configures how repeated fields should be split. Allowed values are `csv`, `pipes`, `ssv` and `tsv`.")
allowPatchFeature = flag.Bool("allow_patch_feature", true, "determines whether to use PATCH feature involving update masks (using google.protobuf.FieldMask).")
Expand Down Expand Up @@ -81,7 +82,7 @@ func main() {
}
}

g := gengateway.New(reg, *useRequestContext, *registerFuncSuffix, *pathType, *allowPatchFeature)
g := gengateway.New(reg, *useRequestContext, *registerFuncSuffix, *pathType, *modulePath, *allowPatchFeature)

if *grpcAPIConfiguration != "" {
if err := reg.LoadGrpcAPIServiceFromYAML(*grpcAPIConfiguration); err != nil {
Expand Down

0 comments on commit 29efd26

Please sign in to comment.