autogenpb/protoParse.go

274 lines
7.6 KiB
Go
Raw Normal View History

package main
// auto run protoc with the correct args
import (
2025-01-09 15:03:05 -06:00
"bufio"
"fmt"
"os"
"strings"
"go.wit.com/log"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"github.com/google/uuid"
)
2025-01-08 20:30:33 -06:00
// this parses the .proto file and handles anything with `autogenpb: `
2025-01-09 15:03:05 -06:00
// does the fruit.proto file have "message Fruits"
func (pb *Files) hasPluralMessage(f *File) error {
file, err := os.Open(f.Filename)
if err != nil {
return err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
base := cases.Title(language.English, cases.NoLower).String(f.Filebase)
2025-01-09 15:29:27 -06:00
prefix := "message " + base + "s {" // to conform, it must have an added 's'
2025-01-09 15:03:05 -06:00
if !strings.HasPrefix(line, prefix) {
// log.Info("nope", prefix, "line", line)
// nope, not this line
continue
}
scanner.Scan()
2025-01-09 15:03:05 -06:00
line = scanner.Text()
fields := strings.Fields(line)
// log.Info("GOT LINE", line)
2025-01-09 15:03:05 -06:00
if fields[0] == "string" && fields[1] != "uuid" {
2025-01-12 06:13:42 -06:00
f.noUuid()
2025-01-09 15:03:05 -06:00
return fmt.Errorf("proto file does not have a UUID")
}
// ok, uuid is here
f.Uuid = line
log.Info("found UUID:", line)
scanner.Scan()
2025-01-09 15:03:05 -06:00
line = scanner.Text()
fields = strings.Fields(line)
// log.Info("GOT LINE", line)
2025-01-09 15:03:05 -06:00
if fields[0] == "string" && fields[1] != "version" {
2025-01-12 06:13:42 -06:00
f.noUuid()
2025-01-09 15:03:05 -06:00
return fmt.Errorf("proto file does not have a version")
}
// found "version", the .proto file conforms
f.Version = line
log.Info("found Version:", line)
return nil
}
2025-01-12 06:13:42 -06:00
f.noPluralMessage()
2025-01-09 15:03:05 -06:00
return fmt.Errorf("proto file error %s", f.Filename)
}
2025-01-12 06:13:42 -06:00
func (pf *File) noPluralMessage() {
base := cases.Title(language.English, cases.NoLower).String(pf.Filebase)
log.Info("")
log.Info("###########################################################################")
log.Info("Your proto file", pf.Filename, "does not contain the correct 'message' definitions")
log.Info("")
log.Info("For autogenpb to work on your file", pf.Filename, ", you must have both names exactly:")
log.Info("")
log.Printf("message %s {\n", base)
log.Info("}")
log.Printf("message %s {\n", base+"s")
log.Info("}")
log.Info("")
log.Info("###########################################################################")
badExit(fmt.Errorf("proto file error %s", pf.Filename))
}
// message Fruits { // `autogenpb:marshal` `autogenpb:mutex`
// string uuid = 1; // `autogenpb:uuid:be926ad9-f07f-484c-adf2-d96eeabf3079`
// string version = 2; // `autogenpb:version:v0.0.1`
// repeated Fruit Fruits = 3; // THIS MUST BE "Fruit" and then "Fruit" + "s"
// }
func (pf *File) noUuid() {
base := cases.Title(language.English, cases.NoLower).String(pf.Filebase)
id := uuid.New()
2025-01-12 06:13:42 -06:00
log.Info("")
log.Info("###########################################################################")
log.Info("Your proto file", pf.Filename, "is incorrect for 'message' ", base+"s")
log.Info("")
log.Info("For autogenpb to work on your file", pf.Filename, ",", base+"s must be exactly:")
log.Info("")
log.Info("message", base+"s", "{ // `autogenpb:marshal` `autogenpb:mutex`")
log.Info(" string uuid = 1; // `autogenpb:uuid:" + id.String() + "`")
2025-01-12 06:13:42 -06:00
log.Info(" string version = 2; // `autogenpb:version:v0.0.1`")
log.Info(" repeated", base, base+"s", " = 3; // THIS MUST BE ", base, " and then ", base+"s")
2025-01-12 06:13:42 -06:00
log.Info("}")
log.Info("")
log.Info("If you don't have a UUID, you can use the randomly generated one here")
log.Info("")
log.Info("###########################################################################")
badExit(fmt.Errorf("proto file error %s", pf.Filename))
}
func (pb *Files) protoParse(pf *File) error {
2025-01-09 15:03:05 -06:00
// does the file conform to the standard? (also reads in UUID & Version)
if err := pb.hasPluralMessage(pf); err != nil {
2025-01-09 15:03:05 -06:00
return err
}
log.Info(pf.Filename, "is valid so far")
2025-01-09 15:03:05 -06:00
// read in the .proto file
data, err := os.ReadFile(pf.Filename)
if err != nil {
return err
}
2025-01-08 20:58:29 -06:00
var curmsg *MsgName
// parse the proto file for message struct names
2025-01-08 20:52:47 -06:00
for _, line := range strings.Split(string(data), "\n") {
if strings.HasPrefix(line, "message ") {
curmsg = pf.parseForMessage(line)
2025-01-08 20:58:29 -06:00
}
// this logic isn't right. find end of message with more bravado
2025-01-08 20:58:29 -06:00
if strings.HasPrefix(line, "}") {
curmsg = nil
2025-01-08 20:52:47 -06:00
}
2025-01-09 15:03:05 -06:00
if curmsg == nil {
// log.Info("curmsg == nil", line)
2025-01-09 15:03:05 -06:00
// can't contiue on nil below here
continue
}
// log.Info("curmsg != nil", line)
2025-01-08 20:52:47 -06:00
parts := strings.Fields(line)
2025-01-10 11:22:08 -06:00
msgvar := parseMsgVar(line)
if msgvar == nil {
// log.Info("Junk in .proto file? line did not contain a message var:", line)
continue
}
if msgvar.IsRepeated {
log.Info("ADDING ITER MAP", curmsg.Name, msgvar.VarType)
pf.IterMap[curmsg.Name] = msgvar.VarType
}
2025-01-09 03:42:29 -06:00
if strings.Contains(line, "autogenpb:sort") {
newS := cases.Title(language.English, cases.NoLower).String(parts[1])
2025-01-09 15:03:05 -06:00
log.Info("Addded Sort:", newS, "in struct", curmsg.Name)
curmsg.Sort = append(curmsg.Sort, newS)
2025-01-10 11:22:08 -06:00
msgvar.HasSort = true
}
2025-01-09 04:22:11 -06:00
if strings.Contains(line, "autogenpb:unique") {
2025-01-09 15:03:05 -06:00
newU := parts[1]
newU = cases.Title(language.English, cases.NoLower).String(newU)
log.Info("Added Unique:", newU, "in struct", curmsg.Name)
curmsg.Unique = append(curmsg.Unique, newU)
2025-01-10 11:22:08 -06:00
msgvar.HasUnique = true
}
2025-01-10 11:22:08 -06:00
curmsg.Vars = append(curmsg.Vars, msgvar)
}
pf.makeSortTable()
// for i, s := range slices.Backward(pf.ToSort) {
return nil
}
2024-12-01 22:21:09 -06:00
func (pf *File) makeSortTable() {
pf.sortWhat(pf.Bases)
pf.sortWhat(pf.Base)
// everything else
for _, msg := range pf.MsgNames {
pf.sortWhat(msg)
}
}
func (pf *File) sortWhat(msg *MsgName) {
for _, v := range msg.Vars {
if !v.IsRepeated {
continue
}
if check := pf.findMsg(v.VarType); check == nil {
// the VarType must be a struct
continue
}
s := new(Sort)
s.MsgName = msg.Name
s.VarType = v.VarType
s.VarName = v.VarName
s.Lockname = msg.Lockname
pf.ToSort = append(pf.ToSort, s)
}
}
2025-01-10 11:22:08 -06:00
func parseMsgVar(line string) *MsgVar {
if strings.Contains(line, "//") {
parts := strings.Split(line, "//")
if len(parts) == 0 {
// log.Info("parseMsgVar() nothing line", line)
return nil
}
line = parts[0]
}
parts := strings.Fields(line)
if len(parts) < 3 {
// log.Info("parseMsgVar() len < 3", parts)
return nil
}
if parts[0] == "message" {
// this is the struct
return nil
}
v := new(MsgVar)
if parts[0] == "repeated" {
v.IsRepeated = true
v.VarType = parts[1]
2025-01-11 10:19:37 -06:00
v.VarName = cases.Title(language.English, cases.NoLower).String(parts[2])
2025-01-10 11:22:08 -06:00
return v
}
v.VarType = parts[0]
2025-01-11 10:19:37 -06:00
v.VarName = cases.Title(language.English, cases.NoLower).String(parts[1])
2025-01-10 11:22:08 -06:00
return v
}
2025-01-08 20:52:47 -06:00
// looks for mutex and marshal entries
func (pf *File) parseForMessage(line string) *MsgName {
2025-01-08 20:52:47 -06:00
fields := strings.Fields(line)
if len(fields) == 0 || fields[0] != "message" {
2025-01-08 20:58:29 -06:00
return nil
2025-01-08 20:52:47 -06:00
}
var msg *MsgName
msg = new(MsgName)
base := cases.Title(language.English, cases.NoLower).String(pf.Filebase)
prefix := "message " + base + "s {" // only look for this for now
if strings.HasPrefix(line, prefix) {
pf.Bases = msg
} else {
prefix := "message " + base + " {" // only look for this for now
if strings.HasPrefix(line, prefix) {
pf.Base = msg
} else {
pf.MsgNames = append(pf.MsgNames, msg)
}
}
2025-01-09 15:29:27 -06:00
msgName := cases.Title(language.English, cases.NoLower).String(fields[1])
2025-01-09 15:03:05 -06:00
log.Info("found messge:", msgName)
2025-01-08 20:52:47 -06:00
msg.Name = msgName
msg.Lockname = pf.Filebase + "Mu" // this should be lowercase. do not export the Mutex
msg.NeedIter = true
2025-01-08 20:52:47 -06:00
if strings.Contains(line, "`autogenpb:mutex`") {
msg.DoMutex = true
2025-01-09 04:03:30 -06:00
log.Info("Added Mutex=true:", msg.Name)
2025-01-08 20:52:47 -06:00
}
if strings.Contains(line, "`autogenpb:marshal`") {
msg.DoMarshal = true
2025-01-09 04:03:30 -06:00
log.Info("Added Marshal=true:", msg.Name)
2025-01-08 20:52:47 -06:00
}
2025-01-08 20:58:29 -06:00
return msg
2025-01-08 20:52:47 -06:00
}