protools插件设置不能被储存(Protobuf Options 自定义插件使用)
导读:ProtoOptions 简介...
ProtoOptions
简介
使用protobuf的options ,我们可以添加我们自己的option ,然后根据option生成代码添对proto中的参数进行处理,例如添加message的校验 。
extension
能够对已经存在的消息进行扩展 ,这种扩展只是动态增加字段 ,而没有增加接口 。
例子:扩展protobuf的FieldOptions message MyFileOptions { optional bool ok = 1; } // 扩展protobuf的MessageOptions extend google.protobuf.FileOptions { optional MyFileOptions my_file_option = 51234; // 取一个自定义不重复值 }protobuf options
google.protobuf.FileOptions google.protobuf.ServiceOptions google.protobuf.MethodOptions google.protobuf.MessageOptions google.protobuf.FieldOptions google.protobuf.EnumOptions google.protobuf.EnumValueOptions google.protobuf.OneofOptions google.protobuf.ExtensionRangeOptions实现自定义option
扩展实现
mkdir protoc-gen-my-option cd protoc-gen-my-option实现一个FileOptions
mkdir proto # 在proto中实现自己的option,可以将EOF的内容拷贝到proto/my_option.proto中 echo > proto/my_option.proto <<EOF syntax = "proto3"; package my_option; option go_package="protoc-gen-my-option/proto"; import "google/protobuf/descriptor.proto"; message MyFileOptions { optional bool ok = 1; } // 扩展protobuf的MessageOptions extend google.protobuf.FileOptions { optional MyFileOptions my_file_option = 51234; // 取一个自定义不重复值 } EOF生成后proto/my_option.proto中的内容
syntax = "proto3"; package my_option; option go_package="protoc-gen-my-option/proto"; import "google/protobuf/descriptor.proto"; message MyFileOptions { optional bool ok = 1; } // 扩展protobuf的MessageOptions extend google.protobuf.FileOptions { optional MyFileOptions my_file_option = 51234; // 取一个自定义不重复值 }生成扩展的pb文件
protoc --go_out=../ proto/my_option.proto解析扩展插件
创建工程文件目录扩展插件的开头必须以protoc-gen开头 ,在创建的protoc-gen-my-option目录下编写插件 ,并初始化项目。
go mod init protoc-gen-my-option 解析demo package main import ( "google.golang.org/protobuf/compiler/protogen" "google.golang.org/protobuf/proto" "log" my_proto "protoc-gen-my-option/proto" ) func getFileOptions(f *protogen.File) *my_proto.MyFileOptions { log.Println("getFileOptions") // 解析my_options if myOptions, ok := proto.GetExtension(f.Proto.Options, my_proto.E_MyFileOption).(*my_proto.MyFileOptions); ok { log.Println("my_options:", myOptions) return myOptions } else { log.Println("get my_options failed.") } return nil } func main() { protogen.Options{}.Run(func(plugin *protogen.Plugin) error { log.Println("protogen plugin") // protc时会把proto文件传入 ,解析所有文件 for _, f := range plugin.Files { // 只处理我们处理的文件 if !f.Generate { continue } // 处理getFiledOptions getFileOptions(f) } return nil }) }安装插件
go install . 使用MyFileOptions mkdir protoc-gen-my-option/test_proto # 使用my-option echo > test_proto/test_proto.proto <<EOF syntax = "proto3"; package my_option; option go_package="protoc-gen-my-option/test_proto"; import "my_option.proto"; // 使用FiledOptions option (my_option.my_file_option).ok = true; EOF生成的test_proto/test_proto.proto内容如下:
syntax = "proto3"; package my_option; option go_package="protoc-gen-my-option/test_proto"; import "my_option.proto"; // 使用FiledOptions option (my_option.my_file_option).ok = true; 验证插件解析MyFileOptions protoc -I=./proto --go_out=../ --my-option_out=../ --proto_path=test_proto test_option.proto成功后会输出以下内容,能够看到my_options中的ok被成功解析 。
2023/02/18 20:12:16 protogen plugin 2023/02/18 20:12:16 getFileOptions 2023/02/18 20:12:16 my_options: ok:true解析扩展插件后生成我们自己的代码
在上面的demo中添加代码生成逻辑
package main import ( "fmt" "google.golang.org/protobuf/compiler/protogen" "google.golang.org/protobuf/proto" "log" my_proto "protoc-gen-my-option/proto" ) func getFileOptions(f *protogen.File) *my_proto.MyFileOptions { log.Println("getFileOptions") // 解析my_options if myOptions, ok := proto.GetExtension(f.Proto.Options, my_proto.E_MyFileOption).(*my_proto.MyFileOptions); ok { log.Println("my_options:", myOptions) return myOptions } else { log.Println("get my_options failed.") } return nil } func genCode(myOptions *my_proto.MyFileOptions) string { if myOptions.Ok != nil && myOptions.GetOk() { return ` func HelloMyOptions() { fmt.Println("Hello MyOptions, MyOptions is ok!") } ` } return ` func HelloMyOptions() { fmt.Println("Hello MyOptions, MyOptions is not ok...") } ` } func main() { protogen.Options{}.Run(func(plugin *protogen.Plugin) error { log.Println("protogen plugin") // protc时会把proto文件传入 ,解析所有文件 for _, f := range plugin.Files { // 只处理我们处理的文件 if !f.Generate { continue } // 处理getFiledOptions myOptions := getFileOptions(f) head := fmt.Sprintf(` package %s import "fmt" `, f.GoPackageName) // go文件, package名是必须的 ,import生成后一般IDE会自动import,可以不用写 ,除非某些场景需要提前加好import outFile := plugin.NewGeneratedFile(fmt.Sprintf("%s.my.go", f.GeneratedFilenamePrefix), f.GoImportPath) outFile.Write([]byte(head)) outFile.Write([]byte(genCode(myOptions))) } return nil }) }重新安装插件 ,并生成我们的代码
go install . protoc -I=./proto --go_out=../ --my-option_out=../ --proto_path=test_proto test_option.proto在test_proto目录中会生成test_option.my.go,内容如下
package test_proto import "fmt" func HelloMyOptions() { fmt.Println("Hello MyOptions, MyOptions is ok!") }以上代码地址
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!