Skip to content

Commit b7bf165

Browse files
jbacodyoss
andauthored
chore(internal/protoveneer): add protoveneer tool (#9352)
Add the protoveneer tool, used to generate the vertexai/genai client. Add an entry to CODEOWNERS so the current maintainers, members of the Go team, can approve and merge PRs. --------- Co-authored-by: Cody Oss <[email protected]>
1 parent 5f8e21f commit b7bf165

File tree

15 files changed

+1851
-0
lines changed

15 files changed

+1851
-0
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
/logging/ @googleapis/api-logging @googleapis/api-logging-partners @googleapis/yoshi-go-admins
1818
/profiler/ @googleapis/api-profiler @googleapis/yoshi-go-admins
1919
/vertexai/ @googleapis/go-vertexai @googleapis/yoshi-go-admins
20+
/internal/protoveneer/ @googleapis/yoshi-go-admins @jba @eliben
2021

2122
# individual release versions manifest is unowned (to avoid notifying every team)
2223
.release-please-manifest-individual.json

go.work

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ use (
8787
./internal/generated/snippets
8888
./internal/godocfx
8989
./internal/postprocessor
90+
./internal/protoveneer
9091
./iot
9192
./kms
9293
./language

internal/protoveneer/README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# The protoveneer tool
2+
3+
Protoveneer is an experimental tool that generates idiomatic Go types that
4+
correspond to protocol buffer messages and enums -- a veneer on top of the proto
5+
layer.
6+
7+
## Usage
8+
9+
Call protoveneer with a config file and a directory containing *.pb.go files:
10+
11+
protoveneer config.yaml ../ai/generativelanguage/apiv1beta/generativelanguagepb
12+
13+
That will write Go source code to the current directory, or the one specified by -outdir.
14+
15+
To add a license to the generated code, pass the -license flag with a filename.
16+
17+
See testdata/basic/config.yaml for a sample config file.
18+
19+
The generated code requires the "support" package. Copy this package to your
20+
project and provide its import path as the value of `supportImportPath` in the
21+
config file.
22+
23+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package main
16+
17+
import (
18+
"errors"
19+
"fmt"
20+
"os"
21+
22+
"gopkg.in/yaml.v3"
23+
)
24+
25+
// config holds the configuration for a package.
26+
type config struct {
27+
Package string
28+
ProtoImportPath string `yaml:"protoImportPath"`
29+
// Import path for the support package needed by the generated code.
30+
SupportImportPath string `yaml:"supportImportPath"`
31+
32+
// The types to process. Only these types and the types they depend
33+
// on will be output.
34+
// The key is the name of the proto type.
35+
Types map[string]*typeConfig
36+
// Omit the types in this list, even if they would normally be output.
37+
// Elements can be globs.
38+
OmitTypes []string `yaml:"omitTypes"`
39+
// Converter functions for types not in the proto package.
40+
// Each value should be "tofunc, fromfunc"
41+
Converters map[string]string
42+
}
43+
44+
type typeConfig struct {
45+
// The name for the veneer type, if different.
46+
Name string
47+
// The prefix of the proto enum values. It will be removed.
48+
ProtoPrefix string `yaml:"protoPrefix"`
49+
// The prefix for the veneer enum values, if different from the type name.
50+
VeneerPrefix string `yaml:"veneerPrefix"`
51+
// Overrides for enum values.
52+
ValueNames map[string]string `yaml:"valueNames"`
53+
// Overrides for field types. Map key is proto field name.
54+
Fields map[string]fieldConfig
55+
// Custom conversion functions: "tofunc, fromfunc"
56+
ConvertToFrom string `yaml:"convertToFrom"`
57+
// Doc string for the type, omitting the initial type name.
58+
Doc string
59+
// Verb to place after type name in doc. Default: "is".
60+
// Ignored if Doc is non-empty.
61+
DocVerb string `yaml:"docVerb"`
62+
}
63+
64+
type fieldConfig struct {
65+
Name string // veneer name
66+
Type string // veneer type
67+
// Omit from output.
68+
Omit bool
69+
}
70+
71+
func (c *config) init() {
72+
for protoName, tc := range c.Types {
73+
if tc == nil {
74+
tc = &typeConfig{Name: protoName}
75+
c.Types[protoName] = tc
76+
}
77+
if tc.Name == "" {
78+
tc.Name = protoName
79+
}
80+
tc.init()
81+
}
82+
}
83+
84+
func (tc *typeConfig) init() {
85+
if tc.VeneerPrefix == "" {
86+
tc.VeneerPrefix = tc.Name
87+
}
88+
}
89+
90+
func readConfigFile(filename string) (*config, error) {
91+
if filename == "" {
92+
return nil, errors.New("missing config file")
93+
}
94+
f, err := os.Open(filename)
95+
if err != nil {
96+
return nil, err
97+
}
98+
defer f.Close()
99+
dec := yaml.NewDecoder(f)
100+
dec.KnownFields(true)
101+
102+
var c config
103+
if err := dec.Decode(&c); err != nil {
104+
return nil, fmt.Errorf("reading %s: %w", filename, err)
105+
}
106+
c.init()
107+
return &c, nil
108+
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package main
16+
17+
import "fmt"
18+
19+
// A converter generates code to convert between a proto type and a veneer type.
20+
type converter interface {
21+
// genFrom returns code to convert from proto to veneer.
22+
genFrom(string) string
23+
// genTo returns code to convert to proto from veneer.
24+
genTo(string) string
25+
// These return the function argument to Transform{Slice,MapValues}, or "" if we don't need it.
26+
genTransformFrom() string
27+
genTransformTo() string
28+
}
29+
30+
// An identityConverter does no conversion.
31+
type identityConverter struct{}
32+
33+
func (identityConverter) genFrom(arg string) string { return arg }
34+
func (identityConverter) genTo(arg string) string { return arg }
35+
func (identityConverter) genTransformFrom() string { return "" }
36+
func (identityConverter) genTransformTo() string { return "" }
37+
38+
// A derefConverter converts between T in the veneer and *T in the proto.
39+
type derefConverter struct{}
40+
41+
func (derefConverter) genFrom(arg string) string { return fmt.Sprintf("support.DerefOrZero(%s)", arg) }
42+
func (derefConverter) genTo(arg string) string { return fmt.Sprintf("support.AddrOrNil(%s)", arg) }
43+
func (derefConverter) genTransformFrom() string { panic("can't handle deref slices") }
44+
func (derefConverter) genTransformTo() string { panic("can't handle deref slices") }
45+
46+
type enumConverter struct {
47+
protoName, veneerName string
48+
}
49+
50+
func (c enumConverter) genFrom(arg string) string {
51+
return fmt.Sprintf("%s(%s)", c.veneerName, arg)
52+
}
53+
54+
func (c enumConverter) genTransformFrom() string {
55+
return fmt.Sprintf("func(p pb.%s) %s { return %s }", c.protoName, c.veneerName, c.genFrom("p"))
56+
}
57+
58+
func (c enumConverter) genTo(arg string) string {
59+
return fmt.Sprintf("pb.%s(%s)", c.protoName, arg)
60+
}
61+
62+
func (c enumConverter) genTransformTo() string {
63+
return fmt.Sprintf("func(v %s) pb.%s { return %s }", c.veneerName, c.protoName, c.genTo("v"))
64+
}
65+
66+
type protoConverter struct {
67+
veneerName string
68+
}
69+
70+
func (c protoConverter) genFrom(arg string) string {
71+
return fmt.Sprintf("(%s{}).fromProto(%s)", c.veneerName, arg)
72+
}
73+
74+
func (c protoConverter) genTransformFrom() string {
75+
return fmt.Sprintf("(%s{}).fromProto", c.veneerName)
76+
}
77+
78+
func (c protoConverter) genTo(arg string) string {
79+
return fmt.Sprintf("%s.toProto()", arg)
80+
}
81+
82+
func (c protoConverter) genTransformTo() string {
83+
return fmt.Sprintf("(*%s).toProto", c.veneerName)
84+
}
85+
86+
type customConverter struct {
87+
toFunc, fromFunc string
88+
}
89+
90+
func (c customConverter) genFrom(arg string) string {
91+
return fmt.Sprintf("%s(%s)", c.fromFunc, arg)
92+
}
93+
94+
func (c customConverter) genTransformFrom() string { return c.fromFunc }
95+
96+
func (c customConverter) genTo(arg string) string {
97+
return fmt.Sprintf("%s(%s)", c.toFunc, arg)
98+
}
99+
100+
func (c customConverter) genTransformTo() string { return c.toFunc }
101+
102+
type sliceConverter struct {
103+
eltConverter converter
104+
}
105+
106+
func (c sliceConverter) genFrom(arg string) string {
107+
if fn := c.eltConverter.genTransformFrom(); fn != "" {
108+
return fmt.Sprintf("support.TransformSlice(%s, %s)", arg, fn)
109+
}
110+
return c.eltConverter.genFrom(arg)
111+
}
112+
113+
func (c sliceConverter) genTo(arg string) string {
114+
if fn := c.eltConverter.genTransformTo(); fn != "" {
115+
return fmt.Sprintf("support.TransformSlice(%s, %s)", arg, fn)
116+
}
117+
return c.eltConverter.genTo(arg)
118+
}
119+
120+
func (c sliceConverter) genTransformTo() string {
121+
panic("sliceConverter.genToSlice called")
122+
}
123+
124+
func (c sliceConverter) genTransformFrom() string {
125+
panic("sliceConverter.genFromSlice called")
126+
}
127+
128+
// Only the values are converted.
129+
type mapConverter struct {
130+
valueConverter converter
131+
}
132+
133+
func (c mapConverter) genFrom(arg string) string {
134+
if fn := c.valueConverter.genTransformFrom(); fn != "" {
135+
return fmt.Sprintf("support.TransformMapValues(%s, %s)", arg, fn)
136+
}
137+
return c.valueConverter.genFrom(arg)
138+
}
139+
140+
func (c mapConverter) genTo(arg string) string {
141+
if fn := c.valueConverter.genTransformTo(); fn != "" {
142+
return fmt.Sprintf("support.TransformMapValues(%s, %s)", arg, fn)
143+
}
144+
return c.valueConverter.genTo(arg)
145+
}
146+
147+
func (c mapConverter) genTransformTo() string {
148+
panic("mapConverter.genToSlice called")
149+
}
150+
151+
func (c mapConverter) genTransformFrom() string {
152+
panic("mapConverter.genFromSlice called")
153+
}

0 commit comments

Comments
 (0)