Files
atomctl/cmd/new_event.go

162 lines
4.1 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 cmd
import (
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
"text/template"
"github.com/samber/lo"
"github.com/spf13/cobra"
"go.ipao.vip/atomctl/v2/pkg/utils/gomod"
"go.ipao.vip/atomctl/v2/templates"
)
// CommandNewProvider 注册 new_provider 命令
func CommandNewEvent(root *cobra.Command) {
cmd := &cobra.Command{
Use: "event",
Aliases: []string{"e"},
Short: "创建新的 event publish & subscriber",
Long: `生成事件的发布者与订阅者模板,并在 app/events/topics.go 中维护事件常量。
行为:
- 根据名称转换:驼峰 -> snake 作为 topicPascal 作为导出名
- 生成 publishers/<snake>.go 与 subscribers/<snake>.go可通过 --only 选择一侧)
- 若 topics.go 不存在会自动创建,并追加 const Topic{Name}="<snake>"(避免重复)
- --dry-run 仅打印渲染与写入动作;--dir 指定输出基目录(默认 .
示例:
atomctl new event UserCreated
atomctl new event UserCreated --only=publisher`,
Args: cobra.ExactArgs(1),
RunE: commandNewEventE,
}
cmd.Flags().String("only", "", "仅生成: publisher 或 subscriber")
root.AddCommand(cmd)
}
func commandNewEventE(cmd *cobra.Command, args []string) error {
snakeName := lo.SnakeCase(args[0])
camelName := lo.PascalCase(args[0])
// shared flags
dryRun, _ := cmd.Flags().GetBool("dry-run")
baseDir, _ := cmd.Flags().GetString("dir")
only, _ := cmd.Flags().GetString("only")
publisherPath := filepath.Join(baseDir, "app/events/publishers")
subscriberPath := filepath.Join(baseDir, "app/events/subscribers")
path, err := os.Getwd()
if err != nil {
return err
}
path, _ = filepath.Abs(path)
err = gomod.Parse(filepath.Join(path, "go.mod"))
if err != nil {
return err
}
if dryRun {
fmt.Printf("[dry-run] mkdir -p %s\n", publisherPath)
fmt.Printf("[dry-run] mkdir -p %s\n", subscriberPath)
} else {
if err := os.MkdirAll(publisherPath, os.ModePerm); err != nil {
return err
}
if err := os.MkdirAll(subscriberPath, os.ModePerm); err != nil {
return err
}
}
err = fs.WalkDir(templates.Events, "events", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
return nil
}
relPath, err := filepath.Rel("events", path)
if err != nil {
return err
}
var destPath string
if relPath == "publisher.go.tpl" {
if only == "subscriber" {
return nil
}
destPath = filepath.Join(publisherPath, snakeName+".go")
} else if relPath == "subscriber.go.tpl" {
if only == "publisher" {
return nil
}
destPath = filepath.Join(subscriberPath, snakeName+".go")
} else {
return nil
}
tmpl, err := template.ParseFS(templates.Events, path)
if err != nil {
return err
}
if dryRun {
fmt.Printf("[dry-run] render > %s\n", destPath)
return nil
}
destFile, err := os.Create(destPath)
if err != nil {
return err
}
defer destFile.Close()
return tmpl.Execute(destFile, map[string]string{
"Name": camelName,
"ModuleName": gomod.GetModuleName(),
})
})
// 写入或追加 topic 常量,避免重复。
topicsPath := filepath.Join(baseDir, "app/events/topics.go")
topicLine := fmt.Sprintf("const Topic%s = %q\n", camelName, snakeName)
if dryRun {
fmt.Printf("[dry-run] ensure topics file and add constant > %s\n", topicsPath)
} else {
// ensure file exists with basic header
if _, statErr := os.Stat(topicsPath); os.IsNotExist(statErr) {
if err := os.MkdirAll(filepath.Dir(topicsPath), os.ModePerm); err != nil {
return err
}
header := "package events\n\n// topics generated by atomctl\n\n"
if err := os.WriteFile(topicsPath, []byte(header), 0o644); err != nil {
return err
}
}
// check duplicate
content, _ := os.ReadFile(topicsPath)
if !strings.Contains(string(content), "Topic"+camelName+" ") && !strings.Contains(string(content), topicLine) {
f, err := os.OpenFile(topicsPath, os.O_APPEND|os.O_WRONLY, 0o644)
if err != nil {
return err
}
defer f.Close()
if _, err := f.WriteString(topicLine); err != nil {
return err
}
}
}
fmt.Printf("event 已创建: %s\n", snakeName)
return nil
}