-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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]>
- Loading branch information
Showing
15 changed files
with
1,851 additions
and
0 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# The protoveneer tool | ||
|
||
Protoveneer is an experimental tool that generates idiomatic Go types that | ||
correspond to protocol buffer messages and enums -- a veneer on top of the proto | ||
layer. | ||
|
||
## Usage | ||
|
||
Call protoveneer with a config file and a directory containing *.pb.go files: | ||
|
||
protoveneer config.yaml ../ai/generativelanguage/apiv1beta/generativelanguagepb | ||
|
||
That will write Go source code to the current directory, or the one specified by -outdir. | ||
|
||
To add a license to the generated code, pass the -license flag with a filename. | ||
|
||
See testdata/basic/config.yaml for a sample config file. | ||
|
||
The generated code requires the "support" package. Copy this package to your | ||
project and provide its import path as the value of `supportImportPath` in the | ||
config file. | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// Copyright 2024 Google LLC | ||
// | ||
// 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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
// Copyright 2024 Google LLC | ||
// | ||
// 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 ( | ||
"errors" | ||
"fmt" | ||
"os" | ||
|
||
"gopkg.in/yaml.v3" | ||
) | ||
|
||
// config holds the configuration for a package. | ||
type config struct { | ||
Package string | ||
ProtoImportPath string `yaml:"protoImportPath"` | ||
// Import path for the support package needed by the generated code. | ||
SupportImportPath string `yaml:"supportImportPath"` | ||
|
||
// The types to process. Only these types and the types they depend | ||
// on will be output. | ||
// The key is the name of the proto type. | ||
Types map[string]*typeConfig | ||
// Omit the types in this list, even if they would normally be output. | ||
// Elements can be globs. | ||
OmitTypes []string `yaml:"omitTypes"` | ||
// Converter functions for types not in the proto package. | ||
// Each value should be "tofunc, fromfunc" | ||
Converters map[string]string | ||
} | ||
|
||
type typeConfig struct { | ||
// The name for the veneer type, if different. | ||
Name string | ||
// The prefix of the proto enum values. It will be removed. | ||
ProtoPrefix string `yaml:"protoPrefix"` | ||
// The prefix for the veneer enum values, if different from the type name. | ||
VeneerPrefix string `yaml:"veneerPrefix"` | ||
// Overrides for enum values. | ||
ValueNames map[string]string `yaml:"valueNames"` | ||
// Overrides for field types. Map key is proto field name. | ||
Fields map[string]fieldConfig | ||
// Custom conversion functions: "tofunc, fromfunc" | ||
ConvertToFrom string `yaml:"convertToFrom"` | ||
// Doc string for the type, omitting the initial type name. | ||
Doc string | ||
// Verb to place after type name in doc. Default: "is". | ||
// Ignored if Doc is non-empty. | ||
DocVerb string `yaml:"docVerb"` | ||
} | ||
|
||
type fieldConfig struct { | ||
Name string // veneer name | ||
Type string // veneer type | ||
// Omit from output. | ||
Omit bool | ||
} | ||
|
||
func (c *config) init() { | ||
for protoName, tc := range c.Types { | ||
if tc == nil { | ||
tc = &typeConfig{Name: protoName} | ||
c.Types[protoName] = tc | ||
} | ||
if tc.Name == "" { | ||
tc.Name = protoName | ||
} | ||
tc.init() | ||
} | ||
} | ||
|
||
func (tc *typeConfig) init() { | ||
if tc.VeneerPrefix == "" { | ||
tc.VeneerPrefix = tc.Name | ||
} | ||
} | ||
|
||
func readConfigFile(filename string) (*config, error) { | ||
if filename == "" { | ||
return nil, errors.New("missing config file") | ||
} | ||
f, err := os.Open(filename) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer f.Close() | ||
dec := yaml.NewDecoder(f) | ||
dec.KnownFields(true) | ||
|
||
var c config | ||
if err := dec.Decode(&c); err != nil { | ||
return nil, fmt.Errorf("reading %s: %w", filename, err) | ||
} | ||
c.init() | ||
return &c, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
// Copyright 2024 Google LLC | ||
// | ||
// 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 "fmt" | ||
|
||
// A converter generates code to convert between a proto type and a veneer type. | ||
type converter interface { | ||
// genFrom returns code to convert from proto to veneer. | ||
genFrom(string) string | ||
// genTo returns code to convert to proto from veneer. | ||
genTo(string) string | ||
// These return the function argument to Transform{Slice,MapValues}, or "" if we don't need it. | ||
genTransformFrom() string | ||
genTransformTo() string | ||
} | ||
|
||
// An identityConverter does no conversion. | ||
type identityConverter struct{} | ||
|
||
func (identityConverter) genFrom(arg string) string { return arg } | ||
func (identityConverter) genTo(arg string) string { return arg } | ||
func (identityConverter) genTransformFrom() string { return "" } | ||
func (identityConverter) genTransformTo() string { return "" } | ||
|
||
// A derefConverter converts between T in the veneer and *T in the proto. | ||
type derefConverter struct{} | ||
|
||
func (derefConverter) genFrom(arg string) string { return fmt.Sprintf("support.DerefOrZero(%s)", arg) } | ||
func (derefConverter) genTo(arg string) string { return fmt.Sprintf("support.AddrOrNil(%s)", arg) } | ||
func (derefConverter) genTransformFrom() string { panic("can't handle deref slices") } | ||
func (derefConverter) genTransformTo() string { panic("can't handle deref slices") } | ||
|
||
type enumConverter struct { | ||
protoName, veneerName string | ||
} | ||
|
||
func (c enumConverter) genFrom(arg string) string { | ||
return fmt.Sprintf("%s(%s)", c.veneerName, arg) | ||
} | ||
|
||
func (c enumConverter) genTransformFrom() string { | ||
return fmt.Sprintf("func(p pb.%s) %s { return %s }", c.protoName, c.veneerName, c.genFrom("p")) | ||
} | ||
|
||
func (c enumConverter) genTo(arg string) string { | ||
return fmt.Sprintf("pb.%s(%s)", c.protoName, arg) | ||
} | ||
|
||
func (c enumConverter) genTransformTo() string { | ||
return fmt.Sprintf("func(v %s) pb.%s { return %s }", c.veneerName, c.protoName, c.genTo("v")) | ||
} | ||
|
||
type protoConverter struct { | ||
veneerName string | ||
} | ||
|
||
func (c protoConverter) genFrom(arg string) string { | ||
return fmt.Sprintf("(%s{}).fromProto(%s)", c.veneerName, arg) | ||
} | ||
|
||
func (c protoConverter) genTransformFrom() string { | ||
return fmt.Sprintf("(%s{}).fromProto", c.veneerName) | ||
} | ||
|
||
func (c protoConverter) genTo(arg string) string { | ||
return fmt.Sprintf("%s.toProto()", arg) | ||
} | ||
|
||
func (c protoConverter) genTransformTo() string { | ||
return fmt.Sprintf("(*%s).toProto", c.veneerName) | ||
} | ||
|
||
type customConverter struct { | ||
toFunc, fromFunc string | ||
} | ||
|
||
func (c customConverter) genFrom(arg string) string { | ||
return fmt.Sprintf("%s(%s)", c.fromFunc, arg) | ||
} | ||
|
||
func (c customConverter) genTransformFrom() string { return c.fromFunc } | ||
|
||
func (c customConverter) genTo(arg string) string { | ||
return fmt.Sprintf("%s(%s)", c.toFunc, arg) | ||
} | ||
|
||
func (c customConverter) genTransformTo() string { return c.toFunc } | ||
|
||
type sliceConverter struct { | ||
eltConverter converter | ||
} | ||
|
||
func (c sliceConverter) genFrom(arg string) string { | ||
if fn := c.eltConverter.genTransformFrom(); fn != "" { | ||
return fmt.Sprintf("support.TransformSlice(%s, %s)", arg, fn) | ||
} | ||
return c.eltConverter.genFrom(arg) | ||
} | ||
|
||
func (c sliceConverter) genTo(arg string) string { | ||
if fn := c.eltConverter.genTransformTo(); fn != "" { | ||
return fmt.Sprintf("support.TransformSlice(%s, %s)", arg, fn) | ||
} | ||
return c.eltConverter.genTo(arg) | ||
} | ||
|
||
func (c sliceConverter) genTransformTo() string { | ||
panic("sliceConverter.genToSlice called") | ||
} | ||
|
||
func (c sliceConverter) genTransformFrom() string { | ||
panic("sliceConverter.genFromSlice called") | ||
} | ||
|
||
// Only the values are converted. | ||
type mapConverter struct { | ||
valueConverter converter | ||
} | ||
|
||
func (c mapConverter) genFrom(arg string) string { | ||
if fn := c.valueConverter.genTransformFrom(); fn != "" { | ||
return fmt.Sprintf("support.TransformMapValues(%s, %s)", arg, fn) | ||
} | ||
return c.valueConverter.genFrom(arg) | ||
} | ||
|
||
func (c mapConverter) genTo(arg string) string { | ||
if fn := c.valueConverter.genTransformTo(); fn != "" { | ||
return fmt.Sprintf("support.TransformMapValues(%s, %s)", arg, fn) | ||
} | ||
return c.valueConverter.genTo(arg) | ||
} | ||
|
||
func (c mapConverter) genTransformTo() string { | ||
panic("mapConverter.genToSlice called") | ||
} | ||
|
||
func (c mapConverter) genTransformFrom() string { | ||
panic("mapConverter.genFromSlice called") | ||
} |
Oops, something went wrong.