Files
sundynix-go/service/codegen/codegen_register.go
T
2026-04-28 10:29:02 +08:00

212 lines
7.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package codegen
import (
"fmt"
"os"
"path/filepath"
"strings"
codegenModel "sundynix-go/model/codegen"
)
// autoRegister 在代码生成后自动修改项目的注册文件
// 包括:initialize/gorm.go, initialize/router.go, api/v1/enter.go, router/enter.go, service/enter.go
// 以及子模块的 enter.go 文件(增量追加新 feature
func (s *CodegenService) autoRegister(outputDir string, config codegenModel.GenConfig) error {
for _, module := range config.Modules {
if strings.TrimSpace(module.PackageName) == "" || strings.TrimSpace(module.Name) == "" {
continue
}
pkg := module.PackageName
pascalModule := module.Name
// 判断是否新模块:检查 router/{pkg}/enter.go 是否已存在
routerEnterPath := filepath.Join(outputDir, "router", pkg, "enter.go")
isNewModule := !fileExistsOnDisk(routerEnterPath)
if isNewModule {
// 新模块:注册到 5 个顶级文件
if err := s.registerGorm(outputDir, module); err != nil {
return fmt.Errorf("注册 gorm 迁移失败: %w", err)
}
if err := s.registerTopEnter(outputDir, pkg, pascalModule); err != nil {
return fmt.Errorf("注册顶级 enter 失败: %w", err)
}
if err := s.registerRouter(outputDir, pkg, pascalModule, module.Features); err != nil {
return fmt.Errorf("注册路由初始化失败: %w", err)
}
} else {
// 已有模块:增量注册新 feature
if err := s.registerGormIncremental(outputDir, module); err != nil {
return fmt.Errorf("增量注册 gorm 迁移失败: %w", err)
}
if err := s.registerRouterIncremental(outputDir, pkg, pascalModule, module.Features); err != nil {
return fmt.Errorf("增量注册路由失败: %w", err)
}
}
}
return nil
}
// registerGorm 向 initialize/gorm.go 的 AutoMigrate 中追加所有 feature
func (s *CodegenService) registerGorm(outputDir string, module codegenModel.Module) error {
gormPath := filepath.Join(outputDir, "initialize", "gorm.go")
content, err := os.ReadFile(gormPath)
if err != nil {
return fmt.Errorf("读取 %s 失败: %w", gormPath, err)
}
text := string(content)
pkg := module.PackageName
// 1. 添加 import
importLine := fmt.Sprintf("\t\"sundynix-go/model/%s\"", pkg)
if !strings.Contains(text, importLine) {
text = strings.Replace(text, "\"go.uber.org/zap\"", importLine+"\n\n\t\"go.uber.org/zap\"", 1)
}
// 2. 在 AutoMigrate 闭合 ) 前插入 model
for _, feature := range module.Features {
if strings.TrimSpace(feature.Name) == "" {
continue
}
modelEntry := fmt.Sprintf("\t\t%s.%s{},", pkg, feature.Name)
if !strings.Contains(text, modelEntry) {
// 找最后一个 ) 之前的位置(AutoMigrate 结束)
closeIdx := strings.LastIndex(text, "\t)")
if closeIdx > 0 {
text = text[:closeIdx] + "\n" + modelEntry + "\n" + text[closeIdx:]
}
}
}
return os.WriteFile(gormPath, []byte(text), 0644)
}
// registerGormIncremental 增量模式:只追加新 feature 到 AutoMigrate
func (s *CodegenService) registerGormIncremental(outputDir string, module codegenModel.Module) error {
return s.registerGorm(outputDir, module) // 逻辑相同,Contains 检查保证幂等
}
// registerTopEnter 向 api/v1/enter.go、router/enter.go、service/enter.go 追加新模块
func (s *CodegenService) registerTopEnter(outputDir string, pkg, pascalModule string) error {
// --- api/v1/enter.go ---
apiEnterPath := filepath.Join(outputDir, "api", "v1", "enter.go")
if err := appendToEnterFile(apiEnterPath,
fmt.Sprintf("\t\"sundynix-go/api/v1/%s\"", pkg),
fmt.Sprintf("\t%sApiGroup %s.ApiGroup", pascalModule, pkg),
); err != nil {
return err
}
// --- router/enter.go ---
routerEnterPath := filepath.Join(outputDir, "router", "enter.go")
if err := appendToEnterFile(routerEnterPath,
fmt.Sprintf("\t\"sundynix-go/router/%s\"", pkg),
fmt.Sprintf("\t%s %s.RouterGroup", pascalModule, pkg),
); err != nil {
return err
}
// --- service/enter.go ---
svcEnterPath := filepath.Join(outputDir, "service", "enter.go")
if err := appendToEnterFile(svcEnterPath,
fmt.Sprintf("\t\"sundynix-go/service/%s\"", pkg),
fmt.Sprintf("\t%sServiceGroup %s.ServiceGroup", pascalModule, pkg),
); err != nil {
return err
}
return nil
}
// appendToEnterFile 向 enter.go 文件追加 import 和 struct 字段
func appendToEnterFile(filePath, importLine, structField string) error {
content, err := os.ReadFile(filePath)
if err != nil {
return fmt.Errorf("读取 %s 失败: %w", filePath, err)
}
text := string(content)
// 添加 import(如果不存在)
if !strings.Contains(text, importLine) {
// 在最后一个 import 之前插入
lastImportIdx := strings.LastIndex(text, "\t\"")
if lastImportIdx > 0 {
// 找这行的换行符
nlIdx := strings.Index(text[lastImportIdx:], "\n")
if nlIdx > 0 {
insertPos := lastImportIdx + nlIdx + 1
text = text[:insertPos] + importLine + "\n" + text[insertPos:]
}
}
}
// 添加 struct 字段(如果不存在)
if !strings.Contains(text, structField) {
// 在 struct 的 } 之前插入
closeBrace := strings.Index(text, "\n}")
if closeBrace > 0 {
text = text[:closeBrace] + "\n" + structField + text[closeBrace:]
}
}
return os.WriteFile(filePath, []byte(text), 0644)
}
// registerRouter 向 initialize/router.go 追加路由注册代码
func (s *CodegenService) registerRouter(outputDir, pkg, pascalModule string, features []codegenModel.Feature) error {
routerPath := filepath.Join(outputDir, "initialize", "router.go")
content, err := os.ReadFile(routerPath)
if err != nil {
return fmt.Errorf("读取 %s 失败: %w", routerPath, err)
}
text := string(content)
// 1. 添加变量声明:xxxRouter := router.GroupApp.Xxx
varLine := fmt.Sprintf("\t%sRouter := router.GroupApp.%s", lowerFirst(pkg), pascalModule)
if !strings.Contains(text, varLine) {
// 在 NeedAuthGroup 行之前插入
needAuthIdx := strings.Index(text, "NeedAuthGroup := Router.Group")
if needAuthIdx > 0 {
text = text[:needAuthIdx] + varLine + "\n\n\t" + text[needAuthIdx:]
}
}
// 2. 添加路由注册:xxxRouter.InitXxxRouter(NeedAuthGroup)
for _, feature := range features {
if strings.TrimSpace(feature.Name) == "" {
continue
}
routerCall := fmt.Sprintf("\t\t%sRouter.Init%sRouter(NeedAuthGroup)", lowerFirst(pkg), feature.Name)
if !strings.Contains(text, routerCall) {
// 在最后一个 Init...Router 行之后插入
lastInitIdx := strings.LastIndex(text, "Router(NeedAuthGroup)")
if lastInitIdx > 0 {
nlIdx := strings.Index(text[lastInitIdx:], "\n")
if nlIdx > 0 {
insertPos := lastInitIdx + nlIdx
comment := fmt.Sprintf(" //%s", feature.Comment)
if feature.Comment == "" {
comment = ""
}
text = text[:insertPos] + "\n" + routerCall + comment + text[insertPos:]
}
}
}
}
return os.WriteFile(routerPath, []byte(text), 0644)
}
// registerRouterIncremental 增量模式:只追加新 feature 的路由注册
func (s *CodegenService) registerRouterIncremental(outputDir, pkg, pascalModule string, features []codegenModel.Feature) error {
return s.registerRouter(outputDir, pkg, pascalModule, features) // Contains 检查保证幂等
}
// fileExistsOnDisk 检查文件是否已存在
func fileExistsOnDisk(path string) bool {
_, err := os.Stat(path)
return err == nil
}