linstrom/cmd/RolesGenerator/main.go

172 lines
4.6 KiB
Go
Raw Normal View History

package main
import (
"flag"
"fmt"
"io"
"os"
"regexp"
"strings"
"gitlab.com/mstarongitlab/goutils/sliceutils"
)
var findRoleStructRegex = regexp.MustCompile(`type Role struct \{([\s\S]+)\}\n\n/\*`)
var (
flagInputFile = flag.String("input", "", "Specify the input file. If empty, read from stdin")
flagOutputFile = flag.String(
"output",
"",
"Specify the output file. If empty, writes to stdout",
)
)
func main() {
flag.Parse()
var input io.Reader
var output io.Writer
if *flagInputFile == "" {
input = os.Stdin
} else {
file, err := os.Open(*flagInputFile)
if err != nil {
panic(err)
}
defer file.Close()
input = file
}
if *flagOutputFile == "" {
output = os.Stdout
} else {
file, err := os.Create(*flagOutputFile)
if err != nil {
panic(err)
}
defer file.Close()
output = file
}
data, err := io.ReadAll(input)
if err != nil {
panic(err)
}
if !findRoleStructRegex.Match(data) {
panic("Input doesn't contain role struct")
}
content := findRoleStructRegex.FindStringSubmatch(string(data))[1]
lines := strings.Split(content, "\n")
lines = sliceutils.Map(lines, func(t string) string { return strings.TrimSpace(t) })
importantLines := sliceutils.Filter(lines, func(t string) bool {
if strings.HasPrefix(t, "//") {
return false
}
if strings.Contains(t, "gorm.Model") {
return false
}
data := sliceutils.Filter(strings.Split(t, " "), func(t string) bool { return t != "" })
if len(data) < 2 {
return false
}
if !strings.HasPrefix(data[1], "*") && !strings.HasPrefix(data[1], "[]") {
return false
}
return true
})
nameTypeMap := map[string]string{}
for _, line := range importantLines {
parts := sliceutils.Filter(strings.Split(line, " "), func(t string) bool { return t != "" })
nameTypeMap[parts[0]] = parts[1]
}
pkgString, _, _ := strings.Cut(string(data), "\n")
outBuilder := strings.Builder{}
2024-09-18 09:15:44 +00:00
outBuilder.WriteString(`// Code generated by cmd/RolesGenerator DO NOT EDIT.
// If you need to refresh the content, run go generate again
`)
outBuilder.WriteString(pkgString + "\n\n")
outBuilder.WriteString(
"import (\n \"slices\"\n \"gitlab.com/mstarongitlab/goutils/sliceutils\"\n)\n\n",
)
// Build role collapse function
outBuilder.WriteString(
`func CollapseRolesIntoOne(roles ...Role) Role {
startingRole := RoleDeepCopy(DefaultUserRole)
slices.SortFunc(roles, func(a, b Role) int { return int(int64(a.Priority)-int64(b.Priority)) })
for _, role := range roles {
`)
// Write all the stupid conditions here
for valName, valType := range nameTypeMap {
if strings.HasPrefix(valType, "[]") {
outBuilder.WriteString(fmt.Sprintf(` if role.%s != nil {
startingRole.%s = append(startingRole.%s, role.%s...)
}
`, valName, valName, valName, valName))
} else {
outBuilder.WriteString(fmt.Sprintf(` if role.%s != nil {
*startingRole.%s = *role.%s
}
`, valName, valName, valName))
}
}
// Then finish up with the end of the function
outBuilder.WriteString(
` }
return startingRole
}
`)
// Then build the deep copy function
outBuilder.WriteString("\nfunc RoleDeepCopy(o Role) Role {\n")
outBuilder.WriteString(` n := Role{}
n.Model = o.Model
n.Name = o.Name
n.Priority = o.Priority
n.IsUserRole = o.IsUserRole
n.IsBuiltIn = o.IsBuiltIn
`)
for valName, valType := range nameTypeMap {
if strings.HasPrefix(valType, "[]") {
outBuilder.WriteString(fmt.Sprintf(" n.%s = slices.Clone(o.%s)\n", valName, valName))
} else {
outBuilder.WriteString(fmt.Sprintf(` if o.%s == nil { n.%s = nil } else {
t := *o.%s
n.%s = &t
}
`, valName, valName, valName, valName))
}
}
outBuilder.WriteString(" return n\n}\n\n")
// Build compare function
outBuilder.WriteString("func CompareRoles(a, b *Role) bool {\n")
outBuilder.WriteString(" return ")
lastName, lastType := "", ""
for valName, valType := range nameTypeMap {
lastName = valName
lastType = valType
outBuilder.WriteString(fmt.Sprintf("(a.%s == nil || b.%s == nil || ", valName, valName))
if strings.HasPrefix(valType, "[]") {
outBuilder.WriteString(
fmt.Sprintf("sliceutils.CompareUnordered(a.%s,b.%s)) && ", valName, valName),
)
} else {
outBuilder.WriteString(fmt.Sprintf("a.%s == b.%s) && ", valName, valName))
}
}
outBuilder.WriteString("(a == nil || b == nil || ")
if strings.HasPrefix(lastType, "[]") {
outBuilder.WriteString(
fmt.Sprintf("sliceutils.CompareUnordered(a.%s,b.%s))", lastName, lastName),
)
} else {
outBuilder.WriteString(fmt.Sprintf("a.%s == b.%s)", lastName, lastName))
}
outBuilder.WriteString("\n}")
// And write the entire thing to the output
fmt.Fprint(output, outBuilder.String())
}