From cdf2a6e76b479203ca37fcd01ceaf876bf6941b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Schw=C3=B6rer?= Date: Mon, 18 Sep 2023 10:38:25 +0200 Subject: [PATCH] v0.0.261 added id-generate.go --- TODO.md | 12 +- bfcodegen/enum-generate.go | 22 ++-- bfcodegen/id-generate.go | 228 +++++++++++++++++++++++++++++++++++++ exerr/data.go | 2 + go.mod | 2 +- go.sum | 2 + goextVersion.go | 4 +- 7 files changed, 249 insertions(+), 23 deletions(-) create mode 100644 bfcodegen/id-generate.go diff --git a/TODO.md b/TODO.md index 399b5f7..9da2f45 100644 --- a/TODO.md +++ b/TODO.md @@ -2,12 +2,6 @@ - cronext - - cursortoken - - - typed/geenric mongo wrapper - - - error package - -- rfctime.DateOnly -- rfctime.HMSTimeOnly -- rfctime.NanoTimeOnly \ No newline at end of file + - rfctime.DateOnly + - rfctime.HMSTimeOnly + - rfctime.NanoTimeOnly \ No newline at end of file diff --git a/bfcodegen/enum-generate.go b/bfcodegen/enum-generate.go index e9b658a..df7f4c2 100644 --- a/bfcodegen/enum-generate.go +++ b/bfcodegen/enum-generate.go @@ -31,13 +31,13 @@ type EnumDef struct { Values []EnumDefVal } -var rexPackage = rext.W(regexp.MustCompile(`^package\s+(?P[A-Za-z0-9_]+)\s*$`)) +var rexEnumPackage = rext.W(regexp.MustCompile(`^package\s+(?P[A-Za-z0-9_]+)\s*$`)) var rexEnumDef = rext.W(regexp.MustCompile(`^\s*type\s+(?P[A-Za-z0-9_]+)\s+(?P[A-Za-z0-9_]+)\s*//\s*(@enum:type).*$`)) -var rexValueDef = rext.W(regexp.MustCompile(`^\s*(?P[A-Za-z0-9_]+)\s+(?P[A-Za-z0-9_]+)\s*=\s*(?P("[A-Za-z0-9_:]+"|[0-9]+))\s*(//(?P.*))?.*$`)) +var rexEnumValueDef = rext.W(regexp.MustCompile(`^\s*(?P[A-Za-z0-9_]+)\s+(?P[A-Za-z0-9_]+)\s*=\s*(?P("[A-Za-z0-9_:]+"|[0-9]+))\s*(//(?P.*))?.*$`)) -var rexChecksumConst = rext.W(regexp.MustCompile(`const ChecksumGenerator = "(?P[A-Za-z0-9_]*)"`)) +var rexEnumChecksumConst = rext.W(regexp.MustCompile(`const ChecksumEnumGenerator = "(?P[A-Za-z0-9_]*)"`)) func GenerateEnumSpecs(sourceDir string, destFile string) error { @@ -52,7 +52,7 @@ func GenerateEnumSpecs(sourceDir string, destFile string) error { if err != nil { return err } - if m, ok := rexChecksumConst.MatchFirst(string(content)); ok { + if m, ok := rexEnumChecksumConst.MatchFirst(string(content)); ok { oldChecksum = m.GroupByName("cs").Value() } } @@ -85,7 +85,7 @@ func GenerateEnumSpecs(sourceDir string, destFile string) error { for _, f := range files { fmt.Printf("========= %s =========\n\n", f.Name()) - fileEnums, pn, err := processFile(sourceDir, path.Join(sourceDir, f.Name())) + fileEnums, pn, err := processEnumFile(sourceDir, path.Join(sourceDir, f.Name())) if err != nil { return err } @@ -103,7 +103,7 @@ func GenerateEnumSpecs(sourceDir string, destFile string) error { return errors.New("no package name found in any file") } - err = os.WriteFile(destFile, []byte(fmtOutput(newChecksum, allEnums, pkgname)), 0o755) + err = os.WriteFile(destFile, []byte(fmtEnumOutput(newChecksum, allEnums, pkgname)), 0o755) if err != nil { return err } @@ -125,7 +125,7 @@ func GenerateEnumSpecs(sourceDir string, destFile string) error { return nil } -func processFile(basedir string, fn string) ([]EnumDef, string, error) { +func processEnumFile(basedir string, fn string) ([]EnumDef, string, error) { file, err := os.Open(fn) if err != nil { return nil, "", err @@ -149,7 +149,7 @@ func processFile(basedir string, fn string) ([]EnumDef, string, error) { break } - if match, ok := rexPackage.MatchFirst(line); i == 0 && ok { + if match, ok := rexEnumPackage.MatchFirst(line); i == 0 && ok { pkgname = match.GroupByName("name").Value() continue } @@ -172,7 +172,7 @@ func processFile(basedir string, fn string) ([]EnumDef, string, error) { fmt.Printf("Found enum definition { '%s' -> '%s' }\n", def.EnumTypeName, def.Type) } - if match, ok := rexValueDef.MatchFirst(line); ok { + if match, ok := rexEnumValueDef.MatchFirst(line); ok { typename := match.GroupByName("type").Value() def := EnumDefVal{ VarName: match.GroupByName("name").Value(), @@ -202,7 +202,7 @@ func processFile(basedir string, fn string) ([]EnumDef, string, error) { return enums, pkgname, nil } -func fmtOutput(cs string, enums []EnumDef, pkgname string) string { +func fmtEnumOutput(cs string, enums []EnumDef, pkgname string) string { str := "// Code generated by enum-generate.go DO NOT EDIT.\n" str += "\n" str += "package " + pkgname + "\n" @@ -212,7 +212,7 @@ func fmtOutput(cs string, enums []EnumDef, pkgname string) string { str += "import \"gogs.mikescher.com/BlackForestBytes/goext/enums\"" + "\n" str += "\n" - str += "const ChecksumGenerator = \"" + cs + "\" // GoExtVersion: " + goext.GoextVersion + "\n" + str += "const ChecksumEnumGenerator = \"" + cs + "\" // GoExtVersion: " + goext.GoextVersion + "\n" str += "\n" for _, enumdef := range enums { diff --git a/bfcodegen/id-generate.go b/bfcodegen/id-generate.go new file mode 100644 index 0000000..6fbcd25 --- /dev/null +++ b/bfcodegen/id-generate.go @@ -0,0 +1,228 @@ +package bfcodegen + +import ( + "errors" + "fmt" + "gogs.mikescher.com/BlackForestBytes/goext" + "gogs.mikescher.com/BlackForestBytes/goext/cmdext" + "gogs.mikescher.com/BlackForestBytes/goext/cryptext" + "gogs.mikescher.com/BlackForestBytes/goext/langext" + "gogs.mikescher.com/BlackForestBytes/goext/rext" + "io" + "os" + "path" + "path/filepath" + "regexp" + "strings" + "time" +) + +type IDDef struct { + File string + FileRelative string + Name string +} + +var rexIDPackage = rext.W(regexp.MustCompile(`^package\s+(?P[A-Za-z0-9_]+)\s*$`)) + +var rexIDDef = rext.W(regexp.MustCompile(`^\s*type\s+(?P[A-Za-z0-9_]+)\s+string\s*//\s*(@id:type).*$`)) + +var rexIDChecksumConst = rext.W(regexp.MustCompile(`const ChecksumIDGenerator = "(?P[A-Za-z0-9_]*)"`)) + +func GenerateIDSpecs(sourceDir string, destFile string) error { + + files, err := os.ReadDir(sourceDir) + if err != nil { + return err + } + + oldChecksum := "N/A" + if _, err := os.Stat(destFile); !os.IsNotExist(err) { + content, err := os.ReadFile(destFile) + if err != nil { + return err + } + if m, ok := rexIDChecksumConst.MatchFirst(string(content)); ok { + oldChecksum = m.GroupByName("cs").Value() + } + } + + files = langext.ArrFilter(files, func(v os.DirEntry) bool { return v.Name() != path.Base(destFile) }) + files = langext.ArrFilter(files, func(v os.DirEntry) bool { return strings.HasSuffix(v.Name(), ".go") }) + langext.SortBy(files, func(v os.DirEntry) string { return v.Name() }) + + newChecksumStr := goext.GoextVersion + for _, f := range files { + content, err := os.ReadFile(path.Join(sourceDir, f.Name())) + if err != nil { + return err + } + newChecksumStr += "\n" + f.Name() + "\t" + cryptext.BytesSha256(content) + } + + newChecksum := cryptext.BytesSha256([]byte(newChecksumStr)) + + if newChecksum != oldChecksum { + fmt.Printf("[IDGenerate] Checksum has changed ( %s -> %s ), will generate new file\n\n", oldChecksum, newChecksum) + } else { + fmt.Printf("[IDGenerate] Checksum unchanged ( %s ), nothing to do\n", oldChecksum) + //TODO return nil + } + + allIDs := make([]IDDef, 0) + + pkgname := "" + + for _, f := range files { + fmt.Printf("========= %s =========\n\n", f.Name()) + fileIDs, pn, err := processIDFile(sourceDir, path.Join(sourceDir, f.Name())) + if err != nil { + return err + } + + fmt.Printf("\n") + + allIDs = append(allIDs, fileIDs...) + + if pn != "" { + pkgname = pn + } + } + + if pkgname == "" { + return errors.New("no package name found in any file") + } + + err = os.WriteFile(destFile, []byte(fmtIDOutput(newChecksum, allIDs, pkgname)), 0o755) + if err != nil { + return err + } + + res, err := cmdext.RunCommand("go", []string{"fmt", destFile}, langext.Ptr(2*time.Second)) + if err != nil { + return err + } + + if res.CommandTimedOut { + fmt.Println(res.StdCombined) + return errors.New("go fmt timed out") + } + if res.ExitCode != 0 { + fmt.Println(res.StdCombined) + return errors.New("go fmt did not succeed") + } + + return nil +} + +func processIDFile(basedir string, fn string) ([]IDDef, string, error) { + file, err := os.Open(fn) + if err != nil { + return nil, "", err + } + + defer func() { _ = file.Close() }() + + bin, err := io.ReadAll(file) + if err != nil { + return nil, "", err + } + + lines := strings.Split(string(bin), "\n") + + ids := make([]IDDef, 0) + + pkgname := "" + + for i, line := range lines { + if i == 0 && strings.HasPrefix(line, "// Code generated by") { + break + } + + if match, ok := rexIDPackage.MatchFirst(line); i == 0 && ok { + pkgname = match.GroupByName("name").Value() + continue + } + + if match, ok := rexIDDef.MatchFirst(line); ok { + + rfp, err := filepath.Rel(basedir, fn) + if err != nil { + return nil, "", err + } + + def := IDDef{ + File: fn, + FileRelative: rfp, + Name: match.GroupByName("name").Value(), + } + fmt.Printf("Found ID definition { '%s' }\n", def.Name) + ids = append(ids, def) + } + } + + return ids, pkgname, nil +} + +func fmtIDOutput(cs string, ids []IDDef, pkgname string) string { + str := "// Code generated by id-generate.go DO NOT EDIT.\n" + str += "\n" + str += "package " + pkgname + "\n" + str += "\n" + + str += "import \"go.mongodb.org/mongo-driver/bson\"" + "\n" + str += "import \"go.mongodb.org/mongo-driver/bson/bsontype\"" + "\n" + str += "import \"go.mongodb.org/mongo-driver/bson/primitive\"" + "\n" + str += "import \"gogs.mikescher.com/BlackForestBytes/goext/exerr\"" + "\n" + str += "\n" + + str += "const ChecksumIDGenerator = \"" + cs + "\" // GoExtVersion: " + goext.GoextVersion + "\n" + str += "\n" + + anyDef := langext.ArrFirstOrNil(ids, func(def IDDef) bool { return def.Name == "AnyID" || def.Name == "AnyId" }) + + for _, iddef := range ids { + + str += "// ================================ " + iddef.Name + " (" + iddef.FileRelative + ") ================================" + "\n" + str += "" + "\n" + + str += "func (i " + iddef.Name + ") MarshalBSONValue() (bsontype.Type, []byte, error) {" + "\n" + str += " if objId, err := primitive.ObjectIDFromHex(string(i)); err == nil {" + "\n" + str += " return bson.MarshalValue(objId)" + "\n" + str += " } else {" + "\n" + str += " return 0, nil, exerr.New(exerr.TypeMarshalEntityID, \"Failed to marshal " + iddef.Name + "(\"+i.String()+\") to ObjectId\").Str(\"value\", string(i)).Type(\"type\", i).Build()" + "\n" + str += " }" + "\n" + str += "}" + "\n" + + str += "" + "\n" + + str += "func (i " + iddef.Name + ") String() string {" + "\n" + str += " return string(i)" + "\n" + str += "}" + "\n" + + str += "" + "\n" + + str += "func (i " + iddef.Name + ") ObjID() (primitive.ObjectID, error) {" + "\n" + str += " return primitive.ObjectIDFromHex(string(i))" + "\n" + str += "}" + "\n" + + str += "" + "\n" + + if anyDef != nil { + str += "func (i " + iddef.Name + ") AsAny() " + anyDef.Name + " {" + "\n" + str += " return " + anyDef.Name + "(i)" + "\n" + str += "}" + "\n" + + str += "" + "\n" + } + + str += "func New" + iddef.Name + "() " + iddef.Name + " {" + "\n" + str += " return " + iddef.Name + "(primitive.NewObjectID().Hex())" + "\n" + str += "}" + "\n" + + str += "" + "\n" + + } + + return str +} diff --git a/exerr/data.go b/exerr/data.go index 7229f4e..dedd4cd 100644 --- a/exerr/data.go +++ b/exerr/data.go @@ -55,6 +55,8 @@ var ( TypeBindFailFormData = NewType("BINDFAIL_FORMDATA", langext.Ptr(400)) TypeBindFailHeader = NewType("BINDFAIL_HEADER", langext.Ptr(400)) + TypeMarshalEntityID = NewType("MARSHAL_ENTITY_ID", langext.Ptr(400)) + TypeUnauthorized = NewType("UNAUTHORIZED", langext.Ptr(401)) TypeAuthFailed = NewType("AUTH_FAILED", langext.Ptr(401)) diff --git a/go.mod b/go.mod index 25dec46..097b193 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.15.3 // indirect + github.com/go-playground/validator/v10 v10.15.4 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/json-iterator/go v1.1.12 // indirect diff --git a/go.sum b/go.sum index ea4a040..7a2512d 100644 --- a/go.sum +++ b/go.sum @@ -36,6 +36,8 @@ github.com/go-playground/validator/v10 v10.15.1 h1:BSe8uhN+xQ4r5guV/ywQI4gO59C2r github.com/go-playground/validator/v10 v10.15.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-playground/validator/v10 v10.15.3 h1:S+sSpunYjNPDuXkWbK+x+bA7iXiW296KG4dL3X7xUZo= github.com/go-playground/validator/v10 v10.15.3/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.15.4 h1:zMXza4EpOdooxPel5xDqXEdXG5r+WggpvnAKMsalBjs= +github.com/go-playground/validator/v10 v10.15.4/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= diff --git a/goextVersion.go b/goextVersion.go index c6b3416..b39ada5 100644 --- a/goextVersion.go +++ b/goextVersion.go @@ -1,5 +1,5 @@ package goext -const GoextVersion = "0.0.260" +const GoextVersion = "0.0.261" -const GoextVersionTimestamp = "2023-09-12T11:40:39+0200" +const GoextVersionTimestamp = "2023-09-18T10:38:25+0200"