try to autoformat the protobufs for the signal devs

This commit is contained in:
Jeff Carr 2025-03-26 03:03:22 -05:00
parent 96fe1d8f14
commit 2775e36aa4
6 changed files with 96 additions and 106 deletions

View File

@ -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"`

View File

@ -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

View File

@ -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 <message>'
// 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<string, string> 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; //
}

View File

@ -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")

View File

@ -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

View File

@ -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
}