From 2775e36aa4e981a4a052b6f15148b61b0f13a2f7 Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Wed, 26 Mar 2025 03:03:22 -0500 Subject: [PATCH] try to autoformat the protobufs for the signal devs --- argv.go | 1 + file.proto | 10 +++++ file.proto.new | 103 ----------------------------------------------- main.go | 5 +++ protoParse.go | 3 ++ protoReformat.go | 80 ++++++++++++++++++++++++++++++++++-- 6 files changed, 96 insertions(+), 106 deletions(-) delete mode 100644 file.proto.new diff --git a/argv.go b/argv.go index 5220faf..76cef67 100644 --- a/argv.go +++ b/argv.go @@ -19,6 +19,7 @@ type args struct { Regret bool `arg:"--regret" help:"ignore needed UUID. You will eventually regret this."` Delete bool `arg:"--delete" help:"use delete with copy experiment"` DryRun bool `arg:"--dry-run" help:"check the .proto syntax, but don't do anything"` + Format bool `arg:"--format" help:"only reformat the .proto file"` GoSrc string `arg:"--go-src" help:"default is ~/go/src. could be set to your go.work path"` GoPath string `arg:"--gopath" help:"the gopath of this repo"` Identify string `arg:"--identify" help:"identify file"` diff --git a/file.proto b/file.proto index a947826..94e05dd 100644 --- a/file.proto +++ b/file.proto @@ -48,6 +48,7 @@ message MsgName { bool noMutex = 12; // only use the global mutex bool doGui = 13; // if a gui.pb.go file should be created string guiVarName = 14; // the name of the variable to use + MsgName localMsgs = 15; // messages can define other local only messages } message Sort { @@ -58,6 +59,15 @@ message Sort { bool needAll = 5; // } +// used to format protobuf files +message FormatMsg { + repeated string lines = 1; // keys to sort on + int64 maxVarname = 2; // max string length of var names + int64 maxVartype = 3; // max string length of var types + repeated FormatMsg inceptionMsgs = 4; // messages inside messages + repeated FormatMsg enums = 5; // locally defined enums +} + message Find { string parent = 1; // `autogenpb:unique` File string varType = 2; // `autogenpb:unique` MsgName diff --git a/file.proto.new b/file.proto.new deleted file mode 100644 index 1bba651..0000000 --- a/file.proto.new +++ /dev/null @@ -1,103 +0,0 @@ -syntax = "proto3"; - -// Look at "example/fruit.proto" not this file - -// this file is actually used by autogenpb - -// here are some docs, but probably it's just easier to run -// autogenpb on this file and see what gets autogenerated -// in this directory. All autogenerated files are named *.pb.go - -// the 'uuid' standard at the end is an experiment -// establish a way to identify arbitrary .pb files - -// You can generate Marshal & Unmarshal for any struct (message) you want -// You can generate SortBy and Append functions ONLY FOR 'repeated ' -// Also, those structs must be defined in the same file -// Additionally, you must use `autogenpb:mutex` on the parent struct. -// The autogenerated code requires a RW mutex and autogenpb will insert it into the struct - -package main; - -// -// below are the actual structs autogen uses -// autogen parses the .proto file and then store the information -// it needs in these protobuf files, then it processes the -// protobuf files to write out *.sort.pb.go and *.marshal.pb.go files -// -message MsgVar { - string varName = 1; // the variable name - string varType = 2; // the variable type - bool isRepeated = 3; // does the variable repeate - bool hasSort = 4; // marked with sort - bool hasUnique = 5; // marked with unique -} - -message MsgName { - string name = 1; // the name of the message aka struct. for this example: "Shelf" - string lockname = 2; // name of the lockfile. ends in Mu - bool doMarshal = 3; // if msg struct should have Marshal & Unmarshal functions - bool doMutex = 4; // true if a mutex is needed for the message struct - bool doProtocMutex = 5; // an experiment to insert a mutex into the protoc generated msg struct (bad idea?) - bool mutexFound = 6; // true if the mutex was added to the protoc pb.go file - repeated string sort = 7; // keys to sort on - repeated string unique = 8; // if the fields should have AppendUnique() functions - repeated MsgVar vars = 9; // store all the vars in the message - bool needIter = 10; // true if the sort iterator has not been generated yet - bool needAll = 11; // true if the sort iterator has not been generated yet - bool noMutex = 12; // only use the global mutex -} - -message Sort { - string msgName = 1; // `autogenpb:unique` File - string varType = 2; // `autogenpb:unique` MsgName - string varName = 3; // `autogenpb:unique` msgNames, sortNames - string lockname = 4; // - bool needAll = 5; // -} - -message Find { - string parent = 1; // `autogenpb:unique` File - string varType = 2; // `autogenpb:unique` MsgName - string varName = 3; // `autogenpb:unique` msgNames, sortNames - bool needAll = 4; // -} - -message File { - // `autogenpb:var:w io.Writer` - string Package = 1; // whatever the package name is at the top of the .go file - string filename = 2; // yellow.proto - string pbfilename = 3; // yellow.pb.go - string filebase = 4; // yellow - string uuid = 5; // the uuid to use in a func NewMsgName() - string version = 6; // the version to use in a func NewMsgName() - MsgName bases = 7; // the message in "plural" form - MsgName base = 8; // the primary repeated message for the master struct - - // every struct in this proto file, this file has: "Apple", "Apples", ... "File", etc... - repeated MsgName msgNames = 9; - repeated MsgName sortNames = 10; // variables that are repeated can have the standard functions generated (Sort(), etc) - map iterMap = 11; - repeated Sort toSort = 12; // variables that are repeated can have the standard functions generated (Sort(), etc) - string goPath = 13; // the version to use in a func NewMsgName() -} - -// I know, I know, the whole point of using protobuf -// is so you don't need a uuid or versions because it's -// inherently forward compatable. nonetheless, a simple stubbed out -// trivial and empty protobuf message can marshal and identify all the files -// also, this could be used to modify /usr/bin/file /usr/share/magic to identify the files -// maybe this is already been done and is pointless, but it seems like a good idea -message Files { // `autogenpb:marshal` - string uuid = 1; // `autogenpb:uuid:6c9ae4dd-648d-4b51-9738-bd59fb8fafd5` - string version = 2; // `autogenpb:version:v0.0.38` - repeated File Files = 3; // an array of each .proto file in the working directory -} - -// this generic message is used by autogen to identify and -// then dump the uuid and version from any arbitrary .pb file -message Identify { // `autogenpb:marshal` - string uuid = 1; // - string version = 2; // -} - diff --git a/main.go b/main.go index ac1ee1a..004ce5a 100644 --- a/main.go +++ b/main.go @@ -62,6 +62,11 @@ func main() { os.Exit(-1) } + if argv.Format { + protoReformat(argv.Proto) + okExit("") + } + if argv.Regret { // this will override the manditory Uuid checks os.Setenv("PROTOBUF_REGRET", "true") diff --git a/protoParse.go b/protoParse.go index 79f36df..8994cee 100644 --- a/protoParse.go +++ b/protoParse.go @@ -45,6 +45,9 @@ func (pf *File) protoParse() error { // parse the proto file for message struct names for _, line := range strings.Split(string(data), "\n") { if strings.HasPrefix(line, "message ") { + if curmsg != nil { + // message defined inside another message + } curmsg = pf.parseForMessage(line) } // this logic isn't right. find end of message with more bravado diff --git a/protoReformat.go b/protoReformat.go index e7b757b..1739288 100644 --- a/protoReformat.go +++ b/protoReformat.go @@ -5,6 +5,7 @@ package main import ( "fmt" + "iter" "os" "strings" @@ -15,6 +16,7 @@ import ( var maxVarname int var maxVartype int +var linesIter iter.Seq[string] func protoReformat(filename string) error { // read in the .proto file @@ -27,9 +29,13 @@ func protoReformat(filename string) error { var inMessage bool var curmsg []string var newfile string + var fmtmsg *FormatMsg + fmtmsg = new(FormatMsg) + + linesIter = makeLineIter(data) // gets the max vartype and varname - for _, line := range strings.Split(string(data), "\n") { + for line := range linesIter { if strings.HasPrefix(line, "message ") { inMessage = true continue @@ -39,7 +45,9 @@ func protoReformat(filename string) error { if strings.HasPrefix(line, "}") { inMessage = false formatMessage(curmsg) + formatMessage2(fmtmsg) curmsg = nil + fmtmsg = new(FormatMsg) continue } @@ -48,11 +56,15 @@ func protoReformat(filename string) error { continue } curmsg = append(curmsg, line) + fmtmsg.Lines = append(fmtmsg.Lines, line) } - // parse the proto file for message struct names - for _, line := range strings.Split(string(data), "\n") { + // gets the max vartype and varname + for line := range linesIter { if strings.HasPrefix(line, "message ") { + if inMessage { + // message inception. search for the architect. don't forget your totem + } inMessage = true parts := strings.Fields(line) if len(parts) > 3 { @@ -180,3 +192,65 @@ func slicesPop(parts []string) ([]string, string) { end := parts[x-1] return parts[0 : x-1], end } + +// 'for x := range' syntax using the awesome golang 1.24 'iter' +func makeLineIter(data []byte) iter.Seq[string] { + items := strings.Split(string(data), "\n") + // log.Println("Made All() Iter.Seq[] with length", len(items)) + return func(yield func(string) bool) { + for _, v := range items { + if !yield(v) { + return + } + } + } +} + +func formatMessage2(curmsg *FormatMsg) []string { + var newmsg []string + + // find the max length of varname and vartype + for _, line := range curmsg.Lines { + parts := strings.Split(line, ";") + if len(parts) < 2 { + // line is blank or just a comment + continue + } + + vartype, varname, _, _ := tokenMsgVar(line) + if len(vartype) > maxVartype { + maxVartype = len(vartype) + } + if len(varname) > maxVarname { + maxVarname = len(varname) + } + } + + for _, line := range curmsg.Lines { + line = strings.TrimSpace(line) + if line == "" { + newmsg = append(newmsg, line) + continue + } + if strings.HasPrefix(line, "//") { + pad := fmt.Sprintf("%d", maxVartype+maxVarname+21) + hmm := "%" + pad + "s %s" + line = fmt.Sprintf(hmm, " ", line) // todo: compute 50 + newmsg = append(newmsg, line) + continue + } + mt := fmt.Sprintf("%d", maxVartype) + mv := fmt.Sprintf("%d", maxVarname) + + hmm := " %-" + mt + "s %-" + mv + "s = %-3s %s" + + vartype, varname, id, end := tokenMsgVar(line) + end = strings.TrimSpace(end) + id = id + ";" + + newline := fmt.Sprintf(hmm, vartype, varname, id, end) + newline = strings.TrimRight(newline, " ") + newmsg = append(newmsg, newline) + } + return newmsg +}