package main // auto run protoc with the correct args import ( "bufio" "fmt" "os" "strings" "go.wit.com/log" "golang.org/x/text/cases" "golang.org/x/text/language" ) // this parses the .proto file and handles anything with `autogenpb: ` // 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) prefix := "message " + base + "s {" // to conform, it must have an added 's' if !strings.HasPrefix(line, prefix) { // log.Info("nope", prefix, "line", line) // nope, not this line continue } line = scanner.Text() fields := strings.Fields(line) if fields[0] == "string" && fields[1] != "uuid" { return fmt.Errorf("proto file does not have a UUID") } // ok, uuid is here f.Uuid = line log.Info("found UUID:", line) line = scanner.Text() fields = strings.Fields(line) if fields[0] == "string" && fields[1] != "version" { 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 } return fmt.Errorf("proto file error %s", f.Filename) } func (pb *Files) protoParse(f *File) error { // does the file conform to the standard? (also reads in UUID & Version) if err := pb.hasPluralMessage(f); err != nil { return err } log.Info(f.Filename, "is valid so far") // read in the .proto file data, err := os.ReadFile(f.Filename) if err != nil { return err } var curmsg *MsgName // parse the proto file for message struct names for _, line := range strings.Split(string(data), "\n") { if strings.HasPrefix(line, "message ") { curmsg = f.parseForMessage(line) } // this logic isn't right. find end of message with more bravado if strings.HasPrefix(line, "}") { curmsg = nil } if curmsg == nil { // log.Info("curmsg == nil", line) // can't contiue on nil below here continue } // log.Info("curmsg != nil", line) parts := strings.Fields(line) msgvar := parseMsgVar(line) if msgvar == nil { // log.Info("Junk in .proto file? line did not contain a message var:", line) continue } if strings.Contains(line, "autogenpb:sort") { newS := cases.Title(language.English, cases.NoLower).String(parts[1]) log.Info("Addded Sort:", newS, "in struct", curmsg.Name) curmsg.Sort = append(curmsg.Sort, newS) msgvar.HasSort = true } if strings.Contains(line, "autogenpb:unique") { 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) msgvar.HasUnique = true } curmsg.Vars = append(curmsg.Vars, msgvar) } return nil } 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] v.VarName = cases.Title(language.English, cases.NoLower).String(parts[2]) return v } v.VarType = parts[0] v.VarName = cases.Title(language.English, cases.NoLower).String(parts[1]) return v } // looks for mutex and marshal entries func (pf *File) parseForMessage(line string) *MsgName { fields := strings.Fields(line) if len(fields) == 0 || fields[0] != "message" { return nil } 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) } } msgName := cases.Title(language.English, cases.NoLower).String(fields[1]) log.Info("found messge:", msgName) msg.Name = msgName msg.Lockname = pf.Filebase + "Mu" // this should be lowercase. do not export the Mutex if strings.Contains(line, "`autogenpb:mutex`") { msg.DoMutex = true log.Info("Added Mutex=true:", msg.Name) } if strings.Contains(line, "`autogenpb:marshal`") { msg.DoMarshal = true log.Info("Added Marshal=true:", msg.Name) } return msg }