Jonathan A. Sternberg 64c5139ab6
hack: generate vtproto files for buildx
Integrates vtproto into buildx. The generated files dockerfile has been
modified to copy the buildkit equivalent file to ensure files are laid
out in the appropriate way for imports.

An import has also been included to change the grpc codec to the version
in buildkit that supports vtproto. This will allow buildx to utilize the
speed and memory improvements from that.

Also updates the gc control options for prune.

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2024-10-08 13:35:06 -05:00

166 lines
4.0 KiB
Go

// Copyright (c) 2021 PlanetScale Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package generator
import (
"fmt"
"runtime/debug"
"google.golang.org/protobuf/compiler/protogen"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/runtime/protoimpl"
"google.golang.org/protobuf/types/pluginpb"
"github.com/planetscale/vtprotobuf/generator/pattern"
)
type ObjectSet struct {
mp map[string]bool
}
func NewObjectSet() ObjectSet {
return ObjectSet{
mp: map[string]bool{},
}
}
func (o ObjectSet) String() string {
return fmt.Sprintf("%#v", o)
}
func (o ObjectSet) Contains(g protogen.GoIdent) bool {
objectPath := fmt.Sprintf("%s.%s", string(g.GoImportPath), g.GoName)
for wildcard := range o.mp {
// Ignore malformed pattern error because pattern already checked in Set
if ok, _ := pattern.Match(wildcard, objectPath); ok {
return true
}
}
return false
}
func (o ObjectSet) Set(s string) error {
if !pattern.ValidatePattern(s) {
return pattern.ErrBadPattern
}
o.mp[s] = true
return nil
}
type Config struct {
// Poolable rules determines if pool feature generate for particular message
Poolable ObjectSet
// PoolableExclude rules determines if pool feature disabled for particular message
PoolableExclude ObjectSet
Wrap bool
WellKnownTypes bool
AllowEmpty bool
BuildTag string
}
type Generator struct {
plugin *protogen.Plugin
cfg *Config
features []Feature
local map[protoreflect.FullName]bool
}
const SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)
func NewGenerator(plugin *protogen.Plugin, featureNames []string, cfg *Config) (*Generator, error) {
plugin.SupportedFeatures = SupportedFeatures
features, err := findFeatures(featureNames)
if err != nil {
return nil, err
}
local := make(map[protoreflect.FullName]bool)
for _, f := range plugin.Files {
if f.Generate {
local[f.Desc.Package()] = true
}
}
return &Generator{
plugin: plugin,
cfg: cfg,
features: features,
local: local,
}, nil
}
func (gen *Generator) Generate() {
for _, file := range gen.plugin.Files {
if !file.Generate {
continue
}
var importPath protogen.GoImportPath
if !gen.cfg.Wrap {
importPath = file.GoImportPath
}
gf := gen.plugin.NewGeneratedFile(file.GeneratedFilenamePrefix+"_vtproto.pb.go", importPath)
gen.generateFile(gf, file)
}
}
func (gen *Generator) generateFile(gf *protogen.GeneratedFile, file *protogen.File) {
p := &GeneratedFile{
GeneratedFile: gf,
Config: gen.cfg,
LocalPackages: gen.local,
}
if p.Config.BuildTag != "" {
// Support both forms of tags for maximum compatibility
p.P("//go:build ", p.Config.BuildTag)
p.P("// +build ", p.Config.BuildTag)
}
p.P("// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.")
if bi, ok := debug.ReadBuildInfo(); ok {
p.P("// protoc-gen-go-vtproto version: ", bi.Main.Version)
}
p.P("// source: ", file.Desc.Path())
p.P()
p.P("package ", file.GoPackageName)
p.P()
protoimplPackage := protogen.GoImportPath("google.golang.org/protobuf/runtime/protoimpl")
p.P("const (")
p.P("// Verify that this generated code is sufficiently up-to-date.")
p.P("_ = ", protoimplPackage.Ident("EnforceVersion"), "(", protoimpl.GenVersion, " - ", protoimplPackage.Ident("MinVersion"), ")")
p.P("// Verify that runtime/protoimpl is sufficiently up-to-date.")
p.P("_ = ", protoimplPackage.Ident("EnforceVersion"), "(", protoimplPackage.Ident("MaxVersion"), " - ", protoimpl.GenVersion, ")")
p.P(")")
p.P()
if p.Wrapper() {
for _, msg := range file.Messages {
p.P(`type `, msg.GoIdent.GoName, ` `, msg.GoIdent)
for _, one := range msg.Oneofs {
for _, field := range one.Fields {
p.P(`type `, field.GoIdent.GoName, ` `, field.GoIdent)
}
}
}
}
var generated bool
for _, feat := range gen.features {
featGenerator := feat(p)
if featGenerator.GenerateFile(file) {
generated = true
}
}
if !generated && !gen.cfg.AllowEmpty {
gf.Skip()
}
}