// protoc-gen-tarantool is a protoc plugin that generates Lua code targeting
// Tarantool's LuaJIT runtime, paired with the runtime/protobuf Lua package.
//
// Usage:
// protoc --tarantool_out=./out --plugin=./protoc-gen-tarantool foo.proto
//
// File option (in your .proto):
// import "tarantool/tarantool.proto";
// option (tarantool.lua_package) = "myapp.proto.foo";
package main
import (
"flag"
"fmt"
"io"
"os"
"strings"
"google.golang.org/protobuf/compiler/protogen"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/descriptorpb"
"google.golang.org/protobuf/types/pluginpb"
"sourcecraft.dev/bigbes/tarantool-protobuf/cmd/protoc-gen-tarantool/internal/gen"
)
func main() {
in, err := io.ReadAll(os.Stdin)
if err != nil {
fail("read stdin: %v", err)
}
req := &pluginpb.CodeGeneratorRequest{}
if err := proto.Unmarshal(in, req); err != nil {
fail("parse CodeGeneratorRequest: %v", err)
}
// protogen requires a go_package on every input file even when we are not
// generating Go. Inject a synthetic value when it's missing — it's never
// surfaced to the generated Lua.
for _, f := range req.ProtoFile {
if f.Options == nil {
f.Options = &descriptorpb.FileOptions{}
}
if f.Options.GoPackage == nil {
stub := "tarantoolpb_synthetic/" + strings.TrimSuffix(f.GetName(), ".proto")
f.Options.GoPackage = proto.String(stub)
}
}
var flags flag.FlagSet
modeFlag := flags.String("mode", "full", "codegen mode: full | runtime")
prefixFlag := flags.String("prefix", "",
"prefix prepended to every generated module's Lua require path "+
"(useful for side-by-side generation in tests)")
plugin, err := protogen.Options{ParamFunc: flags.Set}.New(req)
if err != nil {
fail("init protogen: %v", err)
}
mode, err := gen.ParseMode(*modeFlag)
if err != nil {
fail("%v", err)
}
cfg := gen.Config{Mode: mode, Prefix: *prefixFlag}
// Advertise proto3 optional support so protoc lets us see those fields.
plugin.SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)
for _, file := range plugin.Files {
if !file.Generate {
continue
}
if err := gen.GenerateFile(plugin, file, cfg); err != nil {
plugin.Error(err)
}
}
out, err := proto.Marshal(plugin.Response())
if err != nil {
fail("marshal CodeGeneratorResponse: %v", err)
}
if _, err := os.Stdout.Write(out); err != nil {
fail("write stdout: %v", err)
}
}
func fail(format string, args ...any) {
fmt.Fprintf(os.Stderr, "protoc-gen-tarantool: "+format+"\n", args...)
os.Exit(1)
}