171 lines
3.7 KiB
Go
171 lines
3.7 KiB
Go
|
package main
|
|||
|
|
|||
|
import (
|
|||
|
"bufio"
|
|||
|
"flag"
|
|||
|
"fmt"
|
|||
|
"io"
|
|||
|
"io/fs"
|
|||
|
"log"
|
|||
|
"os"
|
|||
|
"os/exec"
|
|||
|
"path/filepath"
|
|||
|
"strings"
|
|||
|
)
|
|||
|
|
|||
|
func main() {
|
|||
|
|
|||
|
var (
|
|||
|
localTemplatePath string
|
|||
|
remoteTemplatePath string
|
|||
|
projectName string
|
|||
|
branch string
|
|||
|
)
|
|||
|
|
|||
|
flag.StringVar(&localTemplatePath, "local", "", "本地模板路径")
|
|||
|
flag.StringVar(&remoteTemplatePath, "remote", "", "远程仓库url")
|
|||
|
flag.StringVar(&projectName, "name", "", "项目名称")
|
|||
|
flag.StringVar(&branch, "branch", "main", "要使用的分支(仅当模板是远程仓库时)")
|
|||
|
|
|||
|
flag.Parse()
|
|||
|
if localTemplatePath == "" && remoteTemplatePath == "" {
|
|||
|
log.Println("请指定本地模板路径或远程仓库url")
|
|||
|
os.Exit(1)
|
|||
|
}
|
|||
|
|
|||
|
if projectName == "" {
|
|||
|
log.Println("请指定项目名称")
|
|||
|
os.Exit(1)
|
|||
|
}
|
|||
|
|
|||
|
templatePath := ""
|
|||
|
if localTemplatePath != "" {
|
|||
|
templatePath = localTemplatePath
|
|||
|
}
|
|||
|
|
|||
|
if remoteTemplatePath != "" {
|
|||
|
templatePath = remoteTemplatePath
|
|||
|
}
|
|||
|
|
|||
|
replacements := getReplacements()
|
|||
|
if _, ok := replacements["{{PROJECT_NAME}}"]; !ok {
|
|||
|
replacements["{{PROJECT_NAME}}"] = projectName
|
|||
|
}
|
|||
|
|
|||
|
var err error
|
|||
|
|
|||
|
if remoteTemplatePath != "" {
|
|||
|
err = handleRemoteTemplate(templatePath, branch, projectName, replacements)
|
|||
|
} else {
|
|||
|
err = copyTemplate(templatePath, projectName, replacements)
|
|||
|
}
|
|||
|
|
|||
|
if err != nil {
|
|||
|
log.Printf("Error creating project: %s\n", err)
|
|||
|
os.Exit(1)
|
|||
|
}
|
|||
|
|
|||
|
fmt.Printf("Project %s created successfully!\n", projectName)
|
|||
|
}
|
|||
|
|
|||
|
func handleRemoteTemplate(templateRepo, branch, projectName string, replacements map[string]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, projectName, replacements)
|
|||
|
}
|
|||
|
|
|||
|
func getReplacements() map[string]string {
|
|||
|
scanner := bufio.NewScanner(os.Stdin)
|
|||
|
replacements := make(map[string]string)
|
|||
|
fmt.Println("输入替换值(key=value),空行结束: ")
|
|||
|
for {
|
|||
|
fmt.Print("> ")
|
|||
|
scanner.Scan()
|
|||
|
line := scanner.Text()
|
|||
|
if line == "" {
|
|||
|
break
|
|||
|
}
|
|||
|
|
|||
|
splits := strings.Split(line, "=")
|
|||
|
if len(splits) != 2 {
|
|||
|
fmt.Println("无效输入,请以key=value格式输入")
|
|||
|
continue
|
|||
|
}
|
|||
|
|
|||
|
replacements[splits[0]] = splits[1]
|
|||
|
}
|
|||
|
|
|||
|
return replacements
|
|||
|
}
|
|||
|
|
|||
|
func copyTemplate(src, dist string, replacements map[string]string) (err error) {
|
|||
|
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() {
|
|||
|
// 创建目录
|
|||
|
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
|
|||
|
}
|