package genaip import ( "fmt" "google.golang.org/genproto/googleapis/api/annotations" "google.golang.org/protobuf/compiler/protogen" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/reflect/protoregistry" ) // PluginName is the name of the AIP Go protobuf compiler plugin. const PluginName = "protoc-gen-go-aip" const generatedFilenameSuffix = "_aip.go" type Config struct { IncludeResourceDefinitions bool } // Run the AIP Go protobuf compiler plugin. func Run(gen *protogen.Plugin, config Config) error { var files protoregistry.Files for _, file := range gen.Files { if err := files.RegisterFile(file.Desc); err != nil { return err } } for _, file := range gen.Files { file := file if !file.Generate { continue } g := newGeneratedFile(gen, file) g.Skip() var rangeErr error rangeResourcesInFile( file.Desc, func(resource *annotations.ResourceDescriptor, extension protoreflect.ExtensionType) bool { if !config.IncludeResourceDefinitions && extension == annotations.E_ResourceDefinition { return true } g.Unskip() if err := (resourceNameCodeGenerator{ resource: resource, files: &files, file: file, }).GenerateCode(g); err != nil { rangeErr = err return false } return true }, ) if rangeErr != nil { return rangeErr } } return nil } func newGeneratedFile(gen *protogen.Plugin, file *protogen.File) *protogen.GeneratedFile { g := gen.NewGeneratedFile(file.GeneratedFilenamePrefix+generatedFilenameSuffix, file.GoImportPath) g.P("// Code generated by ", PluginName, ". DO NOT EDIT.") g.P("//") g.P("// versions:") g.P("// \t", PluginName, " ", PluginVersion) g.P("// \tprotoc ", getProtocVersion(gen)) g.P("// source: ", file.Desc.Path()) g.P() g.P("package ", file.GoPackageName) return g } func getProtocVersion(gen *protogen.Plugin) string { if v := gen.Request.GetCompilerVersion(); v != nil { return fmt.Sprintf("v%v.%v.%v", v.GetMajor(), v.GetMinor(), v.GetPatch()) } return "(unknown)" } func rangeResourcesInFile( file protoreflect.FileDescriptor, fn func(resource *annotations.ResourceDescriptor, extension protoreflect.ExtensionType) bool, ) { for _, resource := range proto.GetExtension( file.Options(), annotations.E_ResourceDefinition, ).([]*annotations.ResourceDescriptor) { if !fn(resource, annotations.E_ResourceDefinition) { return } } for i := 0; i < file.Messages().Len(); i++ { resource := proto.GetExtension( file.Messages().Get(i).Options(), annotations.E_Resource, ).(*annotations.ResourceDescriptor) if resource == nil { continue } if !fn(resource, annotations.E_Resource) { return } } }