Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple generators #45

Merged
merged 1 commit into from Oct 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
57 changes: 50 additions & 7 deletions config.go
Expand Up @@ -27,10 +27,19 @@ import (
const configVersion = "unstable"

type config struct {
Version string
Version string
Generators []string

// Generator is a code generator which is used from protoc.
// Deprecated: Use Generators instead.
Generator string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to keep compatibility with the previous syntax?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be. Let me check.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The latest revision should support both Generator and Generators. The former is converted to the latter internally.

Plugins []string
Includes struct {

// Plugins will be deprecated. It has to be per-Generator setting,
// but neither protoc-gen-go nor protoc-gen-go-grpc support plugins.
// So the refactoring is not worth to do.
Plugins []string

Includes struct {
Before []string
Vendored []string
Packages []string
Expand All @@ -40,9 +49,12 @@ type config struct {
Packages map[string]string

Overrides []struct {
Prefixes []string
Generator string
Plugins *[]string
Prefixes []string
// Generator is a code generator which is used from protoc.
// Deprecated: Use Generators instead.
Generator string
Generators []string
Plugins *[]string

// TODO(stevvooe): We could probably support overriding of includes and
// package maps, but they don't seem to be as useful. Likely,
Expand All @@ -59,7 +71,6 @@ type config struct {

func newDefaultConfig() config {
return config{
Generator: "go",
Includes: struct {
Before []string
Vendored []string
Expand All @@ -77,6 +88,10 @@ func readConfig(path string) (config, error) {
if err != nil {
log.Fatalln(err)
}
return readConfigFrom(p)
}

func readConfigFrom(p []byte) (config, error) {
c := newDefaultConfig()
if err := toml.Unmarshal(p, &c); err != nil {
log.Fatalln(err)
Expand All @@ -86,5 +101,33 @@ func readConfig(path string) (config, error) {
return config{}, fmt.Errorf("unknown file version %v; please upgrade to %v", c.Version, configVersion)
}

if c.Generator != "" {
if len(c.Generators) > 0 {
return config{}, fmt.Errorf(
`specify either "generators = %v" or "generator = %v", not both`,
c.Generators, c.Generator,
)
}
c.Generators = []string{c.Generator}
c.Generator = ""
}

for i, o := range c.Overrides {
if o.Generator != "" {
if len(o.Generators) > 0 {
return config{}, fmt.Errorf(
`specify either "overrides[%d].generators" or "overrides[%d].generator", not both`,
i, i,
)
}
c.Overrides[i].Generators = []string{o.Generator}
c.Overrides[i].Generator = ""
}
}

if len(c.Generators) == 0 {
c.Generators = []string{"go"}
}

return c, nil
}
60 changes: 60 additions & 0 deletions config_test.go
@@ -0,0 +1,60 @@
/*
Copyright The containerd Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import "testing"

func TestReadConfigFrom(t *testing.T) {
testcases := []struct {
name string
toml string
}{
{
name: "empty",
toml: `version="unstable"`,
},
{
name: "generator",
toml: `
version="unstable"
generator="go"
`,
},
{
name: "generators",
toml: `
version="unstable"
generators=["go"]
`,
},
}

for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
c, err := readConfigFrom([]byte(tc.toml))
if err != nil {
t.Fatalf("err must be nil, but got %v", err)
}
if c.Generator == "go" {
t.Fatalf("Generator must be cleared, but got %v", c.Generator)
}
if len(c.Generators) != 1 || c.Generators[0] != "go" {
t.Fatalf("Generators must be [go], but got %v", c.Generators)
}
})
}
}
13 changes: 7 additions & 6 deletions main.go
Expand Up @@ -77,9 +77,10 @@ func main() {

// Index overrides by target import path
overrides := map[string]struct {
Prefixes []string
Generator string
Plugins *[]string
Prefixes []string
Generator string
Generators []string
Plugins *[]string
}{}
for _, override := range c.Overrides {
for _, prefix := range override.Prefixes {
Expand Down Expand Up @@ -166,7 +167,7 @@ func main() {
includes = append(includes, c.Includes.After...)

protoc := protocCmd{
Name: c.Generator,
Names: c.Generators,
ImportPath: pkg.GoImportPath,
PackageMap: c.Packages,
Plugins: c.Plugins,
Expand All @@ -182,8 +183,8 @@ func main() {

if override, ok := overrides[importDirPath]; ok {
// selectively apply the overrides to the protoc structure.
if override.Generator != "" {
protoc.Name = override.Generator
if len(override.Generators) > 0 {
protoc.Names = override.Generators
}

if override.Plugins != nil {
Expand Down
16 changes: 10 additions & 6 deletions protoc.go
Expand Up @@ -30,12 +30,16 @@ var (
{{if $index}}` + string(filepath.ListSeparator) + `{{end -}}
{{.}}
{{- end -}}
{{- if .Descriptors}} --include_imports --descriptor_set_out={{.Descriptors}}{{- end }} --
{{- .Name -}}_out={{if .Plugins}}plugins={{- range $index, $plugin := .Plugins -}}
{{- if $index}}+{{end}}
{{- $plugin}}
{{- if .Descriptors}} --include_imports --descriptor_set_out={{.Descriptors}}{{- end -}}

{{- range $index, $name := .Names }} --{{- $name -}}_out=
{{- if $.Plugins}}plugins={{- range $index, $plugin := $.Plugins -}}
{{- if $index}}+{{end}}
{{- $plugin}}
{{- end -}},{{- end -}}
import_path={{$.ImportPath}}
{{- end -}}
,{{- end -}}import_path={{.ImportPath}}

{{- range $proto, $gopkg := .PackageMap -}},M
{{- $proto}}={{$gopkg -}}
{{- end -}}
Expand All @@ -46,7 +50,7 @@ var (

// protocParams defines inputs to a protoc command string.
type protocCmd struct {
Name string // backend name
Names []string
Includes []string
Plugins []string
Descriptors string
Expand Down
57 changes: 57 additions & 0 deletions protoc_test.go
@@ -0,0 +1,57 @@
/*
Copyright The containerd Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import "testing"

func TestMkcmd(t *testing.T) {
testcases := []struct {
name string
cmd protocCmd
expected string
}{
{
name: "basic",
cmd: protocCmd{Names: []string{"go"}},
expected: "protoc -I --go_out=import_path=:",
},
{
name: "plugin",
cmd: protocCmd{Names: []string{"go"}, Plugins: []string{"grpc"}},
expected: "protoc -I --go_out=plugins=grpc,import_path=:",
},
{
name: "use protoc-gen-go-grpc instead of plugins",
cmd: protocCmd{Names: []string{"go", "go-grpc"}},
expected: "protoc -I --go_out=import_path= --go-grpc_out=import_path=:",
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
cmd := &tc.cmd

s, err := cmd.mkcmd()
if err != nil {
t.Fatalf("err must be nil but %+v", err)
}

if s != tc.expected {
t.Fatalf(`s must be %q, but %q`, tc.expected, s)
}
})
}
}