diff --git a/README.md b/README.md index 4636a62d..2b971aa2 100644 --- a/README.md +++ b/README.md @@ -53,13 +53,14 @@ You can specify custom options, as follow: $> protoc --gotemplate_out=debug=true,template_dir=/path/to/template/directory:. input.proto ``` -| Option | Default Value | Accepted Values | Description -|-----------------------|---------------|---------------------------|----------------------- -| `template_dir`       | `./template` | absolute or relative path | path to look for templates -| `destination_dir`     | `.`           | absolute or relative path | base path to write output -| `single-package-mode` | *false* | `true` or `false` | if *true*, `protoc` won't accept multiple packages to be compiled at once (*!= from `all`*), but will support `Message` lookup across the imported protobuf dependencies -| `debug`               | *false*       | `true` or `false` | if *true*, `protoc` will generate a more verbose output -| `all`                 | *false*       | `true` or `false`         | if *true*, protobuf files without `Service` will also be parsed +| Option | Default Value | Accepted Values | Description +|-----------------------|---------------|-----------------------------------------|----------------------- +| `template_dir`       | `./template` | absolute or relative path | path to look for templates +| `destination_dir`     | `.`           | absolute or relative path | base path to write output +| `single-package-mode` | *false* | `true` or `false` | if *true*, `protoc` won't accept multiple packages to be compiled at once (*!= from `all`*), but will support `Message` lookup across the imported protobuf dependencies +| `debug`               | *false*       | `true` or `false` | if *true*, `protoc` will generate a more verbose output +| `type`                | `service`     | `none`, `service`, `file`, or `message` | Which type of definition to iterate over and generate templates for. +| `all`                 | *false*       | `true` or `false`         | if *true*, protobuf files without `Service` will also be parsed. Identical to type=file ##### Hints diff --git a/encoder.go b/encoder.go index f5d5fe79..cb4ccad3 100644 --- a/encoder.go +++ b/encoder.go @@ -18,7 +18,9 @@ import ( type GenericTemplateBasedEncoder struct { templateDir string service *descriptor.ServiceDescriptorProto + message *descriptor.DescriptorProto file *descriptor.FileDescriptorProto + files []*descriptor.FileDescriptorProto enum []*descriptor.EnumDescriptorProto debug bool destinationDir string @@ -32,16 +34,19 @@ type Ast struct { PWD string `json:"pwd"` Debug bool `json:"debug"` DestinationDir string `json:"destination-dir"` + Files []*descriptor.FileDescriptorProto `json:"file"` File *descriptor.FileDescriptorProto `json:"file"` RawFilename string `json:"raw-filename"` Filename string `json:"filename"` TemplateDir string `json:"template-dir"` Service *descriptor.ServiceDescriptorProto `json:"service"` + Message *descriptor.DescriptorProto `json:"message"` Enum []*descriptor.EnumDescriptorProto `json:"enum"` } func NewGenericServiceTemplateBasedEncoder(templateDir string, service *descriptor.ServiceDescriptorProto, file *descriptor.FileDescriptorProto, debug bool, destinationDir string) (e *GenericTemplateBasedEncoder) { e = &GenericTemplateBasedEncoder{ + message: nil, service: service, file: file, templateDir: templateDir, @@ -57,6 +62,40 @@ func NewGenericServiceTemplateBasedEncoder(templateDir string, service *descript return } +func NewGenericMessageTemplateBasedEncoder(templateDir string, message *descriptor.DescriptorProto, file *descriptor.FileDescriptorProto, debug bool, destinationDir string) (e *GenericTemplateBasedEncoder) { + e = &GenericTemplateBasedEncoder{ + message: message, + service: nil, + file: file, + templateDir: templateDir, + debug: debug, + destinationDir: destinationDir, + enum: file.GetEnumType(), + } + if debug { + log.Printf("new encoder: file=%q message=%q template-dir=%q", file.GetName(), message.GetName(), templateDir) + } + pgghelpers.InitPathMap(file) + + return +} + +func NewGenericAllTemplateBasedEncoder(templateDir string, files []*descriptor.FileDescriptorProto, debug bool, destinationDir string) (e *GenericTemplateBasedEncoder) { + e = &GenericTemplateBasedEncoder{ + service: nil, + files: files, + templateDir: templateDir, + debug: debug, + destinationDir: destinationDir, + } + if debug { + log.Printf("new encoder: all files template-dir=%q", templateDir) + } + pgghelpers.InitPathMaps(files) + + return +} + func NewGenericTemplateBasedEncoder(templateDir string, file *descriptor.FileDescriptorProto, debug bool, destinationDir string) (e *GenericTemplateBasedEncoder) { e = &GenericTemplateBasedEncoder{ service: nil, @@ -127,12 +166,14 @@ func (e *GenericTemplateBasedEncoder) genAst(templateFilename string) (*Ast, err PWD: pwd, GoPWD: goPwd, File: e.file, + Files: e.files, TemplateDir: e.templateDir, DestinationDir: e.destinationDir, RawFilename: templateFilename, Filename: "", Service: e.service, Enum: e.enum, + Message: e.message, } buffer := new(bytes.Buffer) tmpl, err := template.New("").Funcs(pgghelpers.ProtoHelpersFuncMap).Parse(templateFilename) diff --git a/main.go b/main.go index 3014869c..03abba34 100644 --- a/main.go +++ b/main.go @@ -46,7 +46,7 @@ func main() { templateDir = "./templates" destinationDir = "." debug = false - all = false + templateType = "service" singlePackageMode = false ) if parameter := g.Request.GetParameter(); parameter != "" { @@ -80,11 +80,13 @@ func main() { case "all": switch strings.ToLower(parts[1]) { case boolTrue, "t": - all = true + templateType = "file" case boolFalse, "f": default: - log.Printf("Err: invalid value for debug: %q", parts[1]) + log.Printf("Err: invalid value for all: %q", parts[1]) } + case "type": + templateType = parts[1] default: log.Printf("Err: unknown parameter: %q", param) } @@ -101,6 +103,14 @@ func main() { } } + appendOnce := func(file *plugin_go.CodeGeneratorResponse_File) { + if _, ok := tmplMap[file.GetName()]; ok { + return + } + tmplMap[file.GetName()] = file + g.Response.File = append(g.Response.File, file) + } + if singlePackageMode { registry = ggdescriptor.NewRegistry() pgghelpers.SetRegistry(registry) @@ -109,27 +119,50 @@ func main() { } } + files := g.Request.GetProtoFile() + // Generate the encoders - for _, file := range g.Request.GetProtoFile() { - if all { + for _, file := range files { + if !inStringSlice(file.GetName(), g.Request.FileToGenerate) { + continue + } + switch templateType { + case "none": if singlePackageMode { if _, err = registry.LookupFile(file.GetName()); err != nil { g.Error(err, "registry: failed to lookup file %q", file.GetName()) } } - encoder := NewGenericTemplateBasedEncoder(templateDir, file, debug, destinationDir) + encoder := NewGenericAllTemplateBasedEncoder(templateDir, files, debug, destinationDir) for _, tmpl := range encoder.Files() { - concatOrAppend(tmpl) + appendOnce(tmpl) } - - continue - } - - for _, service := range file.GetService() { - encoder := NewGenericServiceTemplateBasedEncoder(templateDir, service, file, debug, destinationDir) + case "file": + if singlePackageMode { + if _, err = registry.LookupFile(file.GetName()); err != nil { + g.Error(err, "registry: failed to lookup file %q", file.GetName()) + } + } + encoder := NewGenericTemplateBasedEncoder(templateDir, file, debug, destinationDir) for _, tmpl := range encoder.Files() { concatOrAppend(tmpl) } + case "message": + for _, message := range file.GetMessageType() { + encoder := NewGenericMessageTemplateBasedEncoder(templateDir, message, file, debug, destinationDir) + for _, tmpl := range encoder.Files() { + concatOrAppend(tmpl) + } + } + case "service": + for _, service := range file.GetService() { + encoder := NewGenericServiceTemplateBasedEncoder(templateDir, service, file, debug, destinationDir) + for _, tmpl := range encoder.Files() { + concatOrAppend(tmpl) + } + } + default: + log.Printf("Err: invalid value for type: %q", templateType) } } @@ -146,3 +179,12 @@ func main() { g.Error(err, "failed to write output proto") } } + +func inStringSlice(needle string, haystack []string) bool { + for _, value := range haystack { + if value == needle { + return true + } + } + return false +}