diff --git a/README.md b/README.md index 40c45399..dac40004 100644 --- a/README.md +++ b/README.md @@ -26,13 +26,22 @@ Alternatively, you can download a pre-built release for your platform from the [ The plugin is invoked by passing the `--doc_out`, and `--doc_opt` options to the `protoc` compiler. The option has the following format: - --doc_opt=|,[,default|source_relative] + --doc_opt=,[,default|source_relative][:,*[:[=],[=]*]] The format may be one of the built-in ones ( `docbook`, `html`, `markdown` or `json`) or the name of a file containing a custom [Go template][gotemplate]. If the `source_relative` flag is specified, the output file is written in the same relative directory as the input file. +The following key/value pairs are supported: + +| KEY | VALUE | +|------------|---------------| +| keep-order | true \| false | + +Omitting the value specifies "true". + + ### Using the Docker Image (Recommended) The docker image has two volumes: `/out` and `/protos` which are the directory to write the documentation to and the diff --git a/plugin.go b/plugin.go index bc769016..ddb4bb4c 100644 --- a/plugin.go +++ b/plugin.go @@ -21,6 +21,7 @@ type PluginOptions struct { OutputFile string ExcludePatterns []*regexp.Regexp SourceRelative bool + KeyValues map[string]string } // SupportedFeatures describes a flag setting for supported features. @@ -53,7 +54,7 @@ func (p *Plugin) Generate(r *plugin_go.CodeGeneratorRequest) (*plugin_go.CodeGen resp := new(plugin_go.CodeGeneratorResponse) fdsGroup := groupProtosByDirectory(result, options.SourceRelative) for dir, fds := range fdsGroup { - template := NewTemplate(fds) + template := NewTemplate(fds, options.KeyValues) output, err := RenderTemplate(options.Type, template, customTemplate) if err != nil { @@ -107,7 +108,7 @@ OUTER: // ParseOptions parses plugin options from a CodeGeneratorRequest. It does this by splitting the `Parameter` field from // the request object and parsing out the type of renderer to use and the name of the file to be generated. // -// The parameter (`--doc_opt`) must be of the format ,[,default|source_relative]:,*. +// The parameter (`--doc_opt`) must be of the format ,[,default|source_relative][:,*[:[=],[=]*]]. // The file will be written to the directory specified with the `--doc_out` argument to protoc. func ParseOptions(req *plugin_go.CodeGeneratorRequest) (*PluginOptions, error) { options := &PluginOptions{ @@ -115,6 +116,7 @@ func ParseOptions(req *plugin_go.CodeGeneratorRequest) (*PluginOptions, error) { TemplateFile: "", OutputFile: "index.html", SourceRelative: false, + KeyValues: map[string]string{}, } params := req.GetParameter() @@ -122,11 +124,25 @@ func ParseOptions(req *plugin_go.CodeGeneratorRequest) (*PluginOptions, error) { // Parse out exclude patterns if any parts := strings.Split(params, ":") for _, pattern := range strings.Split(parts[1], ",") { - r, err := regexp.Compile(pattern) - if err != nil { - return nil, err + pattern = strings.TrimSpace(pattern) + if pattern != "" { + r, err := regexp.Compile(pattern) + if err != nil { + return nil, err + } + options.ExcludePatterns = append(options.ExcludePatterns, r) + } + } + if len(parts) > 2 { + pairs := strings.Split(parts[2], ",") + for _, pair := range pairs { + if strings.Contains(pair, "=") { + pair := strings.Split(pair, "=") + options.KeyValues[pair[0]] = pair[1] + } else { + options.KeyValues[pair] = "true" + } } - options.ExcludePatterns = append(options.ExcludePatterns, r) } // The first part is parsed below params = parts[0] diff --git a/template.go b/template.go index 9edaac72..8957f4d2 100644 --- a/template.go +++ b/template.go @@ -21,7 +21,7 @@ type Template struct { } // NewTemplate creates a Template object from a set of descriptors. -func NewTemplate(descs []*protokit.FileDescriptor) *Template { +func NewTemplate(descs []*protokit.FileDescriptor, keyValues map[string]string) *Template { files := make([]*File, 0, len(descs)) for _, f := range descs { @@ -67,10 +67,12 @@ func NewTemplate(descs []*protokit.FileDescriptor) *Template { file.Services = append(file.Services, parseService(s)) } - sort.Sort(file.Enums) - sort.Sort(file.Extensions) - sort.Sort(file.Messages) - sort.Sort(file.Services) + if value, ok := keyValues["keep-order"]; !ok || value != "true" { + sort.Sort(file.Enums) + sort.Sort(file.Extensions) + sort.Sort(file.Messages) + sort.Sort(file.Services) + } files = append(files, file) }