diff --git a/cmd/cmd.go b/cmd/cmd.go new file mode 100644 index 0000000..2b2e242 --- /dev/null +++ b/cmd/cmd.go @@ -0,0 +1,34 @@ +package cmd + +import ( + "github.com/spf13/cobra" + "log" + "os" +) + +var ( + template = "git@golib-ssh.gaore.com:GaoreGo/hertz_demo.git" + project string + branch = "master" +) + +var rootCmd = &cobra.Command{ + Use: "hertz_scaffold", + Short: "hertz框架脚手架", + Long: `以golib.gaore.com/GaoreGo/hertz_demo为模板的脚手架`, + Run: func(cmd *cobra.Command, args []string) { + }, +} + +// Execute 执行命令 +func Execute() { + if err := rootCmd.Execute(); err != nil { + log.Panicln(err) + os.Exit(1) + } +} + +func init() { + rootCmd.AddCommand(createCmd) + rootCmd.AddCommand(updateCmd) +} diff --git a/cmd/create.go b/cmd/create.go new file mode 100644 index 0000000..d2763cc --- /dev/null +++ b/cmd/create.go @@ -0,0 +1,31 @@ +package cmd + +import ( + "fmt" + "github.com/spf13/cobra" + "log" + "os" +) + +var createCmd = &cobra.Command{ + Use: "create", + Short: "创建一个新项目", + Long: `通过hertz_demo为模板创建一个新项目`, + Run: func(cmd *cobra.Command, args []string) { + handleCreateCommand(args) + }, +} + +func init() { + createCmd.Flags().StringVarP(&project, "project", "p", "", "项目名称") +} + +func handleCreateCommand(args []string) { + err := handleRemoteTemplate(template, branch, project) + if err != nil { + log.Printf("Error creating project: %s\n", err) + os.Exit(1) + } + fmt.Printf("Project %s created successfully!\n", project) + return +} diff --git a/cmd/helpers.go b/cmd/helpers.go new file mode 100644 index 0000000..00da69b --- /dev/null +++ b/cmd/helpers.go @@ -0,0 +1,119 @@ +package cmd + +import ( + "fmt" + "io" + "io/fs" + "log" + "os" + "os/exec" + "path/filepath" + "strings" +) + +func getModuleName(goModPath string) (string, error) { + content, err := os.ReadFile(goModPath) + if err != nil { + return "", err + } + + lines := strings.Split(string(content), "\n") + for _, line := range lines { + if strings.HasPrefix(line, "module ") { + return strings.TrimSpace(strings.TrimPrefix(line, "module ")), nil + } + } + + return "", fmt.Errorf("module name not found in go.mod") +} + +func handleRemoteTemplate(templateRepo, branch, projectPath string) (err error) { + // 创建临时目录 + tempDir, err := os.MkdirTemp("", "template-*") + if err != nil { + return fmt.Errorf("error creating temporary directory: %s", err) + } + + // 清理临时目录 + defer os.RemoveAll(tempDir) + + // 克隆模板仓库 + cloneCmd := exec.Command("git", "clone", "-b", branch, templateRepo, tempDir) + cloneCmd.Stdout = io.Discard + cloneCmd.Stderr = os.Stderr + + if err = cloneCmd.Run(); err != nil { + return fmt.Errorf("error cloning template repository: %s", err) + } + + return copyTemplate(tempDir, projectPath) +} + +func copyTemplate(src, dist string) (err error) { + // 读取 go.mod 文件中的模块名称 + oldModuleName, err := getModuleName(filepath.Join(src, "go.mod")) + if err != nil { + log.Printf("error reading module name: %s", err) + os.Exit(1) + } + replacements := map[string]string{ + oldModuleName: filepath.Base(dist), + } + + return filepath.Walk(src, func(path string, info fs.FileInfo, err error) error { + if err != nil { + return err + } + + // 获取相对路径 + relPath, err := filepath.Rel(src, path) + if err != nil { + return err + } + + // 获取目标路径 + targetPath := filepath.Join(dist, relPath) + + if info.IsDir() && filepath.Base(path) == ".git" { + return filepath.SkipDir + } + + if info.IsDir() { + // 创建目录 + return os.MkdirAll(targetPath, info.Mode()) + } + + return copyAndReplaceFile(path, targetPath, info.Mode(), replacements) + }) +} + +func copyAndReplaceFile(src, dist string, mode os.FileMode, replacements map[string]string) (err error) { + + // 读取源文件 + sourceFile, err := os.Open(src) + if err != nil { + return err + } + defer sourceFile.Close() + + content, err := io.ReadAll(sourceFile) + if err != nil { + return err + } + + newContent := string(content) + for key, value := range replacements { + newContent = strings.ReplaceAll(newContent, key, value) + } + + // 读取目标文件 + targetFile, err := os.OpenFile(dist, os.O_CREATE|os.O_RDWR|os.O_TRUNC, mode) + if err != nil { + return err + } + + defer targetFile.Close() + + _, err = targetFile.WriteString(newContent) + return +} diff --git a/cmd/update.go b/cmd/update.go new file mode 100644 index 0000000..64d5567 --- /dev/null +++ b/cmd/update.go @@ -0,0 +1,15 @@ +package cmd + +import ( + "fmt" + "github.com/spf13/cobra" +) + +var updateCmd = &cobra.Command{ + Use: "update", + Short: "更新项目", + Long: `Update the current project`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("还没做") + }, +} diff --git a/go.mod b/go.mod index 8ee961b..3e81cfb 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,9 @@ module golib.gaore.com/xuy2/hertz_scaffold go 1.20 + +require ( + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/spf13/cobra v1.8.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..912390a --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index f2d4fae..babc576 100644 --- a/main.go +++ b/main.go @@ -2,167 +2,8 @@ package main -import ( - "flag" - "fmt" - "io" - "io/fs" - "log" - "os" - "os/exec" - "path/filepath" - "strings" -) +import "golib.gaore.com/xuy2/hertz_scaffold/cmd" func main() { - - if len(os.Args) < 2 { - fmt.Println("Usage: hertz_scaffold create -p ") - os.Exit(1) - } - - // 解析子命令 - subCommand := os.Args[1] - if subCommand != "create" && subCommand != "update" { - log.Printf("Unknown subcommand: %s\n", subCommand) - os.Exit(1) - } - - switch subCommand { - case "create": - handleCreateCommand(os.Args[2:]) - } - -} - -func handleCreateCommand(args []string) { - var ( - template = "git@golib-ssh.gaore.com:GaoreGo/hertz_demo.git" - branch = "master" - projectPath string - err error - ) - - flagSet := flag.NewFlagSet("create", flag.ExitOnError) - flagSet.StringVar(&projectPath, "p", "", "Path to the new project") - flagSet.Parse(args) - - if projectPath == "" { - log.Printf("Error: -p flag is required\n") - os.Exit(1) - } - - err = handleRemoteTemplate(template, branch, projectPath) - if err != nil { - log.Printf("Error creating project: %s\n", err) - os.Exit(1) - } - fmt.Printf("Project %s created successfully!\n", projectPath) -} - -func getModuleName(goModPath string) (string, error) { - content, err := os.ReadFile(goModPath) - if err != nil { - return "", err - } - - lines := strings.Split(string(content), "\n") - for _, line := range lines { - if strings.HasPrefix(line, "module ") { - return strings.TrimSpace(strings.TrimPrefix(line, "module ")), nil - } - } - - return "", fmt.Errorf("module name not found in go.mod") -} - -func handleRemoteTemplate(templateRepo, branch, projectPath string) (err error) { - // 创建临时目录 - tempDir, err := os.MkdirTemp("", "template-*") - if err != nil { - return fmt.Errorf("error creating temporary directory: %s", err) - } - - // 清理临时目录 - defer os.RemoveAll(tempDir) - - // 克隆模板仓库 - cloneCmd := exec.Command("git", "clone", "-b", branch, templateRepo, tempDir) - cloneCmd.Stdout = os.Stdout - cloneCmd.Stderr = os.Stderr - - if err = cloneCmd.Run(); err != nil { - return fmt.Errorf("error cloning template repository: %s", err) - } - - return copyTemplate(tempDir, projectPath) -} - -func copyTemplate(src, dist string) (err error) { - // 读取 go.mod 文件中的模块名称 - oldModuleName, err := getModuleName(filepath.Join(src, "go.mod")) - if err != nil { - log.Printf("error reading module name: %s", err) - os.Exit(1) - } - replacements := map[string]string{ - oldModuleName: filepath.Base(dist), - } - - return filepath.Walk(src, func(path string, info fs.FileInfo, err error) error { - if err != nil { - return err - } - - // 获取相对路径 - relPath, err := filepath.Rel(src, path) - if err != nil { - return err - } - - // 获取目标路径 - targetPath := filepath.Join(dist, relPath) - - if info.IsDir() && filepath.Base(path) == ".git" { - return filepath.SkipDir - } - - if info.IsDir() { - // 创建目录 - return os.MkdirAll(targetPath, info.Mode()) - } - - return copyAndReplaceFile(path, targetPath, info.Mode(), replacements) - }) -} - -func copyAndReplaceFile(src, dist string, mode os.FileMode, replacements map[string]string) (err error) { - - // 读取源文件 - sourceFile, err := os.Open(src) - if err != nil { - return err - } - defer sourceFile.Close() - - content, err := io.ReadAll(sourceFile) - if err != nil { - return err - } - - newContent := string(content) - for key, value := range replacements { - newContent = strings.ReplaceAll(newContent, key, value) - } - - // 读取目标文件 - targetFile, err := os.OpenFile(dist, os.O_CREATE|os.O_RDWR|os.O_TRUNC, mode) - if err != nil { - return err - } - - defer targetFile.Close() - - _, err = targetFile.WriteString(newContent) - return + cmd.Execute() }