From ff1721c250420fb4f1ce24f13d2e20721e40a07b Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Thu, 9 Jan 2025 15:03:05 -0600 Subject: [PATCH] compiles again --- Makefile | 4 +- auto.proto | 61 +++----------- example/{auto.proto => file.proto} | 0 example/fruit.New.go | 1 + file.proto | 70 +++++++++++++++ main.go | 8 +- marshal.go | 2 +- protoParse.go | 131 ++++++++++++++++------------- 8 files changed, 159 insertions(+), 118 deletions(-) rename example/{auto.proto => file.proto} (100%) create mode 100644 file.proto diff --git a/Makefile b/Makefile index 9290772..97ef344 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ install: auto: rm -f auto.pb.go - ./autogenpb --proto auto.proto --package main + ./autogenpb --proto file.proto --package main rm -f auto.sort.pb.go auto.newsort.pb.go # auto.marshal.pb.go test: @@ -33,7 +33,7 @@ test: junk: cd example; rm -f go.* *.pb.go - cd example; ../autogenpb --proto auto.proto --package yellow + cd example; ../autogenpb --proto file.proto --package yellow cd example; GO111MODULE=off go vet goimports: diff --git a/auto.proto b/auto.proto index a19afa6..87e6836 100644 --- a/auto.proto +++ b/auto.proto @@ -1,5 +1,9 @@ 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 @@ -15,26 +19,6 @@ syntax = "proto3"; package main; -message Apple { // `autogenpb:marshal` - string name = 1; // `autogenpb:unique` // generates SortByxxx() and AppendUnique() functions - string genus = 2; // `autogenpb:unique` // generates same thing here but SortByGenus() -} - -message Apples { // `autogenpb:marshal` `autogenpb:mutex` - string uuid = 1; // `autogenpb:default:b2a2de35-07b6-443b-8188-709e27bee8a7` - string version = 2; // `autogenpb:default:2` - repeated Apple Apples = 3; // `autogenpb:sort` - repeated Pears More = 4; // `autogenpb:sort` - repeated string Color = 5; // `autogenpb:sort` `autogenpb:unique` -} - -message Pears { - string name = 1; // - string favorite = 2; // `autogenpb:sort` -} - -// above is an example - // // below are the actual structs autogen uses // autogen parses the .proto file and then store the information @@ -42,34 +26,13 @@ message Pears { // protobuf files to write out *.sort.pb.go and *.marshal.pb.go files // message MsgName { - // If you have: - // - // "Shelf" for msgname - // "Books" for name - // - // Then in the proto file, that would mean it would look like: - // - // message Shelf { - // and then - // repeated string Books = 42; - // - // autogenpb will then generate sort functions for each 'name' - // things like: - // - // for _, b := range all.Book { - // - // and sort functions like: - // - // func (a ShelfBook) Less(i, j int) bool { return a[i].Book < a[j].Book } - // - string name = 1; // the name of the message aka struct. for this example: "Shelf" - string lockname = 2; // ShelfMU - bool doMarshal = 3; // if "Shelf" should have Marshal & Unmarshal functions + 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; // "Book", "Picture", etc + repeated string sort = 7; // keys to sort on repeated string unique = 8; // if the fields should have AppendUnique() functions } @@ -79,10 +42,12 @@ message File { // `autogenpb:nomarshal` string pbfilename = 3; // yellow.pb.go string filebase = 4; // yellow string uuid = 5; // the uuid to use in a func NewMsgName() - int64 version = 6; // the version 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 = 7; // `autogenpb:unique` // in this file + repeated MsgName msgNames = 9; // `autogenpb:unique` // in this file } // I know, I know, the whole point of using protobuf @@ -92,8 +57,8 @@ message File { // `autogenpb:nomarshal` // 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; // if you use this scheme, autogen will be able to identify your - int64 version = 2; // protobuf files from the command line. + 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 } diff --git a/example/auto.proto b/example/file.proto similarity index 100% rename from example/auto.proto rename to example/file.proto diff --git a/example/fruit.New.go b/example/fruit.New.go index c00f981..6d32ded 100644 --- a/example/fruit.New.go +++ b/example/fruit.New.go @@ -3,5 +3,6 @@ package main func NewFruits() *Fruits { x := new(Fruits) x.Uuid = "test" + x.Version = "v0.0.2" return x } diff --git a/file.proto b/file.proto new file mode 100644 index 0000000..87e6836 --- /dev/null +++ b/file.proto @@ -0,0 +1,70 @@ +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 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 +} + +message File { // `autogenpb:nomarshal` + 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; // `autogenpb:unique` // in this file +} + +// 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; // + int64 version = 2; // +} diff --git a/main.go b/main.go index 6e85d5b..f9f62da 100644 --- a/main.go +++ b/main.go @@ -108,16 +108,10 @@ func main() { protobase := strings.TrimSuffix(argv.Proto, ".proto") f.Filebase = protobase - // parse the .proto file - if err := pb.protoParse(f); err != nil { - log.Info("autogenpb parse error:", err) - os.Exit(-1) - } - // parse sort & marshal options from the .proto file // this goes through the .proto files and looks // for `autogenpb: ` lines - if err := pb.protoParseNew(f); err != nil { + if err := pb.protoParse(f); err != nil { log.Info("autogenpb parse error:", err) os.Exit(-1) } diff --git a/marshal.go b/marshal.go index 43d8c14..9709d5a 100644 --- a/marshal.go +++ b/marshal.go @@ -52,7 +52,7 @@ func marshalThing(w io.Writer, thing string) { fmt.Fprintln(w, "") fmt.Fprintln(w, "// apparently this isn't stable, but it's awesomely better") fmt.Fprintln(w, "// https://protobuf.dev/reference/go/faq/#unstable-text") - fmt.Fprintln(w, "// it's so great for config files, I'm using it by default to try to fix the problems with it") + fmt.Fprintln(w, "// it's brilliant for config files!") fmt.Fprintln(w, "func (v *"+thing+") FormatTEXT() string {") fmt.Fprintln(w, " return prototext.Format(v)") fmt.Fprintln(w, "}") diff --git a/protoParse.go b/protoParse.go index 31e2f6d..bd7db81 100644 --- a/protoParse.go +++ b/protoParse.go @@ -3,6 +3,8 @@ package main // auto run protoc with the correct args import ( + "bufio" + "fmt" "os" "strings" @@ -13,15 +15,59 @@ import ( // this parses the .proto file and handles anything with `autogenpb: ` -// finds autogenpb:marshal and autogenpb:unique in the .proto file -// -// adds fields to []marshal and []unique -func (pb *Files) protoParseNew(f *File) error { - // log.Info("starting findAutogenpb() on", names["protofile"]) +// 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 + } + // found the matching message + // f.Bases = f.parseForMessage(line) + + 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 { - // log.Info("open config file :", err) return err } @@ -29,45 +75,38 @@ func (pb *Files) protoParseNew(f *File) error { // parse the proto file for message struct names for _, line := range strings.Split(string(data), "\n") { + base := cases.Title(language.English, cases.NoLower).String(f.Filebase) if strings.HasPrefix(line, "message ") { curmsg = f.parseForMessage(line) + prefix := "message " + base // only look for this for now + if strings.HasPrefix(line, prefix) { + // f.Base = curmsg + } else { + f.MsgNames = append(f.MsgNames, curmsg) + } } if strings.HasPrefix(line, "}") { curmsg = nil } + if curmsg == nil { + // can't contiue on nil below here + continue + } // log.Info("line:", line) parts := strings.Fields(line) if strings.Contains(line, "autogenpb:sort") { - if parts[0] == "repeated" { - newS := parts[1] - if curmsg == nil { - log.Info("Error: Found Sort for:", newS, "however, this struct can't be used") - } else { - log.Info("Addded Sort:", newS, "in struct", curmsg.Name) - curmsg.Sort = append(curmsg.Sort, newS) - } - } else { - log.Info("Error:", line) - log.Info("Error: can not sort on non repeated fields") - } + newS := parts[1] + log.Info("Addded Sort:", newS, "in struct", curmsg.Name) + curmsg.Sort = append(curmsg.Sort, newS) } if strings.Contains(line, "autogenpb:unique") { - if parts[0] == "repeated" { - newU := parts[1] - newU = cases.Title(language.English, cases.NoLower).String(newU) - if curmsg == nil { - log.Info("Error: Found Unique for:", newU, "however, this struct can't be used") - } else { - log.Info("Added Unique:", newU, "in struct", curmsg.Name) - curmsg.Unique = append(curmsg.Unique, newU) - } - } else { - log.Info("Error:", line) - log.Info("Error: can not append on non repeated fields") - } + 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) } } return nil @@ -80,8 +119,8 @@ func (f *File) parseForMessage(line string) *MsgName { return nil } msgName := fields[1] + log.Info("found messge:", msgName) msg := new(MsgName) - f.MsgNames = append(f.MsgNames, msg) msg.Name = msgName msg.Lockname = msgName + "Mu" @@ -95,31 +134,3 @@ func (f *File) parseForMessage(line string) *MsgName { } return msg } - -// this doesn't do anything anymore (?) -func (pb *Files) protoParse(f *File) error { - // log.Info("starting findAutogenpb() on", filename) - // read in the .proto file - data, err := os.ReadFile(f.Filename) - if err != nil { - // log.Info("open config file :", err) - return err - } - - lines := strings.Split(string(data), "\n") - for _, line := range lines { - if strings.Contains(line, "autogenpb:ignoreproto") { - // ignore this protofile completely (don't make foo.pb.go) - os.Exit(0) - } - if strings.Contains(line, "autogenpb:no-marshal") { - // don't marshal anything (don't make foo.marshal.pb.go) - argv.NoMarshal = true - } - if strings.Contains(line, "autogenpb:no-sort") { - // don't sort anything (don't make foo.sort.pb.go) - argv.NoSort = true - } - } - return nil -}