143 lines
2.6 KiB
Go
143 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"go/format"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"sort"
|
|
)
|
|
|
|
func main() {
|
|
controllerDir, err := findControllerDir()
|
|
if err != nil {
|
|
fatal(err)
|
|
}
|
|
|
|
ctors, err := findControllerCtors(controllerDir)
|
|
if err != nil {
|
|
fatal(err)
|
|
}
|
|
|
|
content, err := renderModule(ctors)
|
|
if err != nil {
|
|
fatal(err)
|
|
}
|
|
|
|
outPath := filepath.Join(controllerDir, "module.go")
|
|
if err := os.WriteFile(outPath, content, 0o644); err != nil {
|
|
fatal(err)
|
|
}
|
|
}
|
|
|
|
func findControllerDir() (string, error) {
|
|
wd, err := os.Getwd()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if exists(filepath.Join(wd, "module.go")) && exists(filepath.Join(wd, "routes.go")) {
|
|
return wd, nil
|
|
}
|
|
|
|
candidate := filepath.Join(wd, "internal", "controller")
|
|
if exists(filepath.Join(candidate, "module.go")) {
|
|
return candidate, nil
|
|
}
|
|
|
|
return "", fmt.Errorf("could not locate internal/controller")
|
|
}
|
|
|
|
func findControllerCtors(dir string) ([]string, error) {
|
|
entries, err := os.ReadDir(dir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ctorRe := regexp.MustCompile(`(?m)^func\s+(New[A-Za-z0-9_]*Controller)\s*\(`)
|
|
|
|
seen := make(map[string]struct{})
|
|
for _, entry := range entries {
|
|
if entry.IsDir() {
|
|
continue
|
|
}
|
|
name := entry.Name()
|
|
if !hasSuffix(name, "_controller.go") {
|
|
continue
|
|
}
|
|
if name == "module.go" {
|
|
continue
|
|
}
|
|
|
|
path := filepath.Join(dir, name)
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
matches := ctorRe.FindAllSubmatch(data, -1)
|
|
for _, m := range matches {
|
|
if len(m) < 2 {
|
|
continue
|
|
}
|
|
seen[string(m[1])] = struct{}{}
|
|
}
|
|
}
|
|
|
|
var ctors []string
|
|
for k := range seen {
|
|
ctors = append(ctors, k)
|
|
}
|
|
sort.Strings(ctors)
|
|
|
|
return ctors, nil
|
|
}
|
|
|
|
func renderModule(ctors []string) ([]byte, error) {
|
|
var buf bytes.Buffer
|
|
|
|
buf.WriteString("// Code generated by cmd/gen/controllers; DO NOT EDIT.\n")
|
|
buf.WriteString("package controller\n\n")
|
|
buf.WriteString("import \"go.uber.org/fx\"\n\n")
|
|
buf.WriteString("var Module = fx.Options(\n")
|
|
|
|
if len(ctors) > 0 {
|
|
buf.WriteString("\tfx.Provide(\n")
|
|
for _, ctor := range ctors {
|
|
buf.WriteString("\t\t")
|
|
buf.WriteString(ctor)
|
|
buf.WriteString(",\n")
|
|
}
|
|
buf.WriteString("\t),\n")
|
|
}
|
|
|
|
buf.WriteString("\tfx.Invoke(\n\t\tRegisterRoutes,\n\t),\n")
|
|
buf.WriteString(")\n")
|
|
|
|
formatted, err := format.Source(buf.Bytes())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return formatted, nil
|
|
}
|
|
|
|
func exists(path string) bool {
|
|
info, err := os.Stat(path)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return !info.IsDir()
|
|
}
|
|
|
|
func hasSuffix(s, suffix string) bool {
|
|
return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
|
|
}
|
|
|
|
func fatal(err error) {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|