diff --git a/argv.go b/argv.go index 4ae5570..603e37c 100644 --- a/argv.go +++ b/argv.go @@ -13,6 +13,7 @@ type args struct { Proto string `arg:"--proto" help:"the .proto filename"` Mutex bool `arg:"--mutex" default:"true" help:"insert a mutex into protoc .pb.go file"` MutexName string `arg:"--mutex-name" help:"use a var name for the mutex"` + 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"` GoSrc string `arg:"--go-src" help:"default is ~/go/src. could be set to your go.work path"` diff --git a/example/fruit.New.go b/example/fruit.New.go index 0be9b07..bc192c0 100644 --- a/example/fruit.New.go +++ b/example/fruit.New.go @@ -1,6 +1,6 @@ package main -func NewFruits() *Fruits { +func oldNewFruits() *Fruits { x := new(Fruits) x.Uuid = "test" x.Version = "v0.0.2" diff --git a/file.proto b/file.proto index 591e15f..fb42046 100644 --- a/file.proto +++ b/file.proto @@ -75,10 +75,11 @@ message File { 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) + 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) + 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 diff --git a/generate.go b/generate.go index 5c7b92a..2ef7c6c 100644 --- a/generate.go +++ b/generate.go @@ -18,6 +18,9 @@ func (pb *Files) makeNewSortfile(pf *File) error { header(wSort, pf) pf.syncLock(wSort) + if os.Getenv("PROTOBUF_REGRET") != "true" { + pf.addNewFunc(wSort) + } fmt.Fprintf(wSort, "// START SORT\n") fmt.Fprintf(wSort, "\n") diff --git a/generateHeader.go b/generateHeader.go index 99040d2..1660689 100644 --- a/generateHeader.go +++ b/generateHeader.go @@ -3,6 +3,9 @@ package main import ( "fmt" "io" + "os" + + "go.wit.com/log" ) func pbHeaderComment(w io.Writer) { @@ -43,3 +46,34 @@ func header(w io.Writer, pf *File) { fmt.Fprintln(w, ")") fmt.Fprintln(w, "") } + +func (pf *File) addNewFunc(w io.Writer) { + var STRUCT string = pf.Bases.Name + var UUID string = pf.Uuid + var VERSION string = pf.Version + if UUID == "" { + log.Info("error: UUID == ''") + os.Exit(-1) + } + if VERSION == "" { + log.Info("error: Version == ''") + os.Exit(-1) + } + fmt.Fprintln(w, "func (x *"+STRUCT+") fixUuid() {") + fmt.Fprintln(w, " if x == nil {") + fmt.Fprintln(w, " return") + fmt.Fprintln(w, " }") + fmt.Fprintln(w, " if x.Uuid == \""+UUID+"\" {") + fmt.Fprintln(w, " return") + fmt.Fprintln(w, " }") + fmt.Fprintln(w, " x.Uuid = \""+UUID+"\"") + fmt.Fprintln(w, " x.Version = \""+VERSION+" "+pf.GoPath+"\"") + fmt.Fprintln(w, "}") + fmt.Fprintln(w, "") + fmt.Fprintln(w, "func New"+STRUCT+"() *"+STRUCT+"{") + fmt.Fprintln(w, " x := new("+STRUCT+")") + fmt.Fprintln(w, " x.Uuid = \""+UUID+"\"") + fmt.Fprintln(w, " x.Version = \""+VERSION+" "+pf.GoPath+"\"") + fmt.Fprintln(w, " return x") + fmt.Fprintln(w, "}") +} diff --git a/generateMarshal.go b/generateMarshal.go index 18758bb..8474efe 100644 --- a/generateMarshal.go +++ b/generateMarshal.go @@ -24,23 +24,28 @@ func (pb *Files) marshal(f *File) { fmt.Fprintln(w, "") if f.Bases.DoMarshal { - marshalThing(w, f.Bases.Name) + if f.Uuid == "" { + marshalThing(w, f.Bases.Name, false) + } else { + // if the Uuid is set, run fixUuid() in Marshal() + marshalThing(w, f.Bases.Name, true) + } } if f.Base.DoMarshal { - marshalThing(w, f.Base.Name) + marshalThing(w, f.Base.Name, false) } for _, msg := range f.MsgNames { if msg.DoMarshal { - marshalThing(w, msg.Name) + marshalThing(w, msg.Name, false) } else { // log.Info("Skipping. DoMarshal = false for", msg.Name) } } } -func marshalThing(w io.Writer, thing string) { +func marshalThing(w io.Writer, thing string, fix bool) { fmt.Fprintln(w, "// human readable JSON") fmt.Fprintln(w, "func (v *"+thing+") FormatJSON() string {") fmt.Fprintln(w, " return protojson.Format(v)") @@ -60,6 +65,9 @@ func marshalThing(w io.Writer, thing string) { fmt.Fprintln(w, "// https://protobuf.dev/reference/go/faq/#unstable-text") fmt.Fprintln(w, "// it's brilliant for config files!") fmt.Fprintln(w, "func (v *"+thing+") FormatTEXT() string {") + if fix { + fmt.Fprintln(w, " v.fixUuid()") + } fmt.Fprintln(w, " return prototext.Format(v)") fmt.Fprintln(w, "}") fmt.Fprintln(w, "") @@ -70,6 +78,9 @@ func marshalThing(w io.Writer, thing string) { fmt.Fprintln(w, "") fmt.Fprintln(w, "// marshal to wire. This is called winning.") fmt.Fprintln(w, "func (v *"+thing+") Marshal() ([]byte, error) {") + if fix { + fmt.Fprintln(w, " v.fixUuid()") + } fmt.Fprintln(w, " return proto.Marshal(v)") fmt.Fprintln(w, "}") fmt.Fprintln(w, "") diff --git a/main.go b/main.go index 75f82ba..381b2fd 100644 --- a/main.go +++ b/main.go @@ -51,6 +51,11 @@ func main() { os.Exit(-1) } + if argv.Regret { + // this will override the manditory Uuid checks + os.Setenv("PROTOBUF_REGRET", "true") + } + pf := new(File) pb.Files = append(pb.Files, pf) pf.Filename = argv.Proto @@ -61,7 +66,7 @@ func main() { // parse sort & marshal options from the .proto file // this goes through the .proto files and looks // for `autogenpb: ` lines - if err := pb.protoParse(pf); err != nil { + if err := pf.protoParse(); err != nil { log.Info("autogenpb parse error:", err) badExit(err) } diff --git a/protoParse.go b/protoParse.go index 9efe2fd..72c7e17 100644 --- a/protoParse.go +++ b/protoParse.go @@ -3,68 +3,17 @@ package main // auto run protoc with the correct args import ( - "bufio" - "fmt" "os" "strings" "go.wit.com/lib/fhelp" - "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 - } - - scanner.Scan() - line = scanner.Text() - fields := strings.Fields(line) - // log.Info("GOT LINE", line) - if fields[0] == "string" && fields[1] != "uuid" { - f.noUuid() - return fmt.Errorf("proto file does not have a UUID") - } - // ok, uuid is here - f.Uuid = line - log.Info("found UUID:", line) - - scanner.Scan() - line = scanner.Text() - fields = strings.Fields(line) - // log.Info("GOT LINE", line) - if fields[0] == "string" && fields[1] != "version" { - f.noUuid() - 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 - } - f.noPluralMessage() - return fmt.Errorf("proto file error %s", f.Filename) -} - -func (pb *Files) protoParse(pf *File) error { +func (pf *File) protoParse() error { // does the file conform to the standard? (also reads in UUID & Version) // if err := pb.hasPluralMessage(pf); err != nil { // return err @@ -73,10 +22,13 @@ func (pb *Files) protoParse(pf *File) error { uuid, version, err := fhelp.ValidProtobuf(pf.Filename) if err != nil { - return err + // the user can bypass this, but it's probably not worth allowing this + if os.Getenv("PROTOBUF_REGRET") != "true" { + return err + } } - pb.Uuid = uuid - pb.Version = version + pf.Uuid = uuid + pf.Version = version // read in the .proto file data, err := os.ReadFile(pf.Filename) diff --git a/protoc.go b/protoc.go index 5f17a19..e0c128e 100644 --- a/protoc.go +++ b/protoc.go @@ -33,19 +33,19 @@ import ( // --go_opt=MforgeConfig.proto=go.wit.com/apps/autogenpb/testautogen \ // forgeConfig.proto -func (pb *Files) protocBuild(f *File) error { +func (pb *Files) protocBuild(pf *File) error { // read in the .proto file - data, err := os.ReadFile(f.Filename) + data, err := os.ReadFile(pf.Filename) if err != nil { // log.Info("open config file :", err) return err } - if shell.Exists(f.Pbfilename) { - log.Info("protoc file already created", f.Pbfilename) + if shell.Exists(pf.Pbfilename) { + log.Info("protoc file already created", pf.Pbfilename) return nil } - log.Info("Attempt to generate the protoc file:", f.Pbfilename) + log.Info("Attempt to generate the protoc file:", pf.Pbfilename) // log.Info("go src", forge.GetGoSrc()) pwd, _ := os.Getwd() log.Info("go.Getwd()", pwd) @@ -60,9 +60,10 @@ func (pb *Files) protocBuild(f *File) error { gopath := strings.TrimPrefix(pwd, argv.GoSrc) gopath = strings.Trim(gopath, "/") log.Info("gopath", gopath) + pf.GoPath = gopath cmd := []string{"protoc", "--go_out=."} cmd = append(cmd, "--proto_path="+gopath) - cmd = append(cmd, "--go_opt=M"+f.Filename+"="+gopath) + cmd = append(cmd, "--go_opt=M"+pf.Filename+"="+gopath) // cmd = append(cmd, "--print_free_field_numbers") // look for included proto files @@ -87,7 +88,7 @@ func (pb *Files) protocBuild(f *File) error { } } - cmd = append(cmd, f.Filename) + cmd = append(cmd, pf.Filename) log.Info("\tpwd", argv.GoSrc) for i, s := range cmd { log.Info("\t", i, s) diff --git a/small/fruit.New.go b/small/fruit.New.go deleted file mode 100644 index 0be9b07..0000000 --- a/small/fruit.New.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -func NewFruits() *Fruits { - x := new(Fruits) - x.Uuid = "test" - x.Version = "v0.0.2" - // x.Fruits = - return x -}