mStar
b9c95a0297
It now also generates a function for comparing two roles for equality. If an attribute is nil, that attribute is ignored (or rather counted as equal)
171 lines
4.6 KiB
Go
171 lines
4.6 KiB
Go
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{}
|
|
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())
|
|
}
|