diff --git a/protoc-gen-twirp/command_line.go b/protoc-gen-twirp/command_line.go index 54876df6..c7fb632c 100644 --- a/protoc-gen-twirp/command_line.go +++ b/protoc-gen-twirp/command_line.go @@ -21,6 +21,7 @@ import ( type commandLineParams struct { importPrefix string // String to prefix to imported package file names. importMap map[string]string // Mapping from .proto file name to import path. + paths string // Paths value, used to control file output directory } // parseCommandLineParams breaks the comma-separated list of key=value pairs @@ -56,6 +57,11 @@ func parseCommandLineParams(parameter string) (*commandLineParams, error) { clp.importMap[k[1:]] = v // 1 is the length of 'M'. case len(k) > 0 && strings.HasPrefix(k, "go_import_mapping@"): clp.importMap[k[18:]] = v // 18 is the length of 'go_import_mapping@'. + case k == "paths": + if v != "source_relative" { + return nil, fmt.Errorf("paths does not support %q", v) + } + clp.paths = v default: return nil, fmt.Errorf("unknown parameter %q", k) } diff --git a/protoc-gen-twirp/generator.go b/protoc-gen-twirp/generator.go index 8df1058c..adcb5598 100644 --- a/protoc-gen-twirp/generator.go +++ b/protoc-gen-twirp/generator.go @@ -47,6 +47,9 @@ type twirp struct { importPrefix string // String to prefix to imported package file names. importMap map[string]string // Mapping from .proto file name to import path. + // Package output: + sourceRelativePaths bool // instruction on where to write output files + // Package naming: genPkgName string // Name of the package that we're generating fileToGoPackageName map[*descriptor.FileDescriptorProto]string @@ -82,6 +85,8 @@ func (t *twirp) Generate(in *plugin.CodeGeneratorRequest) *plugin.CodeGeneratorR t.genFiles = gen.FilesToGenerate(in) + t.sourceRelativePaths = params.paths == "source_relative" + // Collect information on types. t.reg = typemap.New(in.ProtoFile) @@ -125,7 +130,6 @@ func (t *twirp) Generate(in *plugin.CodeGeneratorRequest) *plugin.CodeGeneratorR t.fileToGoPackageName[f] = alias } } - // Showtime! Generate the response. resp := new(plugin.CodeGeneratorResponse) for _, f := range t.genFiles { @@ -211,7 +215,7 @@ func (t *twirp) generate(file *descriptor.FileDescriptorProto) *plugin.CodeGener t.generateFileDescriptor(file) - resp.Name = proto.String(goFileName(file)) + resp.Name = proto.String(t.goFileName(file)) resp.Content = proto.String(t.formattedOutput()) t.output.Reset() @@ -269,7 +273,7 @@ func (t *twirp) generateImports(file *descriptor.FileDescriptorProto) { // method. Make sure to import the package of any such message. First, dedupe // them. deps := make(map[string]string) // Map of package name to quoted import path. - ourImportPath := path.Dir(goFileName(file)) + ourImportPath := path.Dir(t.goFileName(file)) for _, s := range file.Service { for _, m := range s.Method { defs := []*typemap.MessageDefinition{ @@ -278,16 +282,20 @@ func (t *twirp) generateImports(file *descriptor.FileDescriptorProto) { } for _, def := range defs { // By default, import path is the dirname of the Go filename. - importPath := path.Dir(goFileName(def.File)) + importPath := path.Dir(t.goFileName(def.File)) if importPath == ourImportPath { continue } + if def.File.GetOptions().GetGoPackage() != "" { + importPath = def.File.GetOptions().GetGoPackage() + } if substitution, ok := t.importMap[def.File.GetName()]; ok { importPath = substitution } importPath = t.importPrefix + importPath pkg := t.goPackageName(def.File) deps[pkg] = strconv.Quote(importPath) + } } } @@ -1015,7 +1023,7 @@ func (t *twirp) generateServerJSONMethod(service *descriptor.ServiceDescriptorPr t.P(` panic(r)`) t.P(` }`) t.P(` }()`) - t.P(` respContent, err = s.`, servName,`.`,methName, `(ctx, reqContent)`) + t.P(` respContent, err = s.`, servName, `.`, methName, `(ctx, reqContent)`) t.P(` }()`) t.P() t.P(` if err != nil {`) @@ -1088,7 +1096,7 @@ func (t *twirp) generateServerProtobufMethod(service *descriptor.ServiceDescript t.P(` panic(r)`) t.P(` }`) t.P(` }()`) - t.P(` respContent, err = s.`, servName,`.`,methName, `(ctx, reqContent)`) + t.P(` respContent, err = s.`, servName, `.`, methName, `(ctx, reqContent)`) t.P(` }()`) t.P() t.P(` if err != nil {`) diff --git a/protoc-gen-twirp/go_naming.go b/protoc-gen-twirp/go_naming.go index 97fe9168..30f946c8 100644 --- a/protoc-gen-twirp/go_naming.go +++ b/protoc-gen-twirp/go_naming.go @@ -65,13 +65,15 @@ func goPackageName(f *descriptor.FileDescriptorProto) (name string, explicit boo } // goFileName returns the output name for the generated Go file. -func goFileName(f *descriptor.FileDescriptorProto) string { +func (t *twirp) goFileName(f *descriptor.FileDescriptorProto) string { name := *f.Name if ext := path.Ext(name); ext == ".proto" || ext == ".protodevel" { name = name[:len(name)-len(ext)] } name += ".twirp.go" - + if t.sourceRelativePaths { + return name + } // Does the file have a "go_package" option? If it does, it may override the // filename. if impPath, _, ok := goPackageOption(f); ok && impPath != "" {