2024-12-13 16:09:02 +08:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"archive/tar"
|
|
|
|
"bytes"
|
|
|
|
"compress/gzip"
|
|
|
|
"errors"
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
2024-12-13 16:24:43 +08:00
|
|
|
"git.nobla.cn/golang/kos/util/env"
|
2024-12-13 16:09:02 +08:00
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
"path"
|
|
|
|
"runtime"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2024-12-13 16:24:43 +08:00
|
|
|
packageNameFlag = flag.String("package-name", "", "应用程序包名称")
|
|
|
|
versionFlag = flag.String("version", env.Get("MOTO_VERSION", "v0.0.1"), "模板版本号,可以使用环境变量 MOTO_VERSION")
|
2024-12-13 16:09:02 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
oldPackageName = "git.nobla.cn/golang/moto"
|
|
|
|
)
|
|
|
|
|
|
|
|
func writeFile(dstFile string, r io.Reader) (err error) {
|
|
|
|
var (
|
|
|
|
fp *os.File
|
|
|
|
)
|
|
|
|
if fp, err = os.Create(dstFile); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer fp.Close()
|
|
|
|
_, err = io.Copy(fp, r)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func extractFile(file string, dirname string) (err error) {
|
|
|
|
var (
|
|
|
|
prefix string
|
|
|
|
fp *os.File
|
|
|
|
gzipReader *gzip.Reader
|
|
|
|
)
|
|
|
|
// 清理路径字符串
|
|
|
|
dirname = path.Clean(dirname)
|
|
|
|
|
|
|
|
// 打开压缩文件
|
|
|
|
if fp, err = os.Open(file); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer fp.Close()
|
|
|
|
// 执行解压操作
|
|
|
|
if gzipReader, err = gzip.NewReader(fp); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer gzipReader.Close()
|
|
|
|
tarReader := tar.NewReader(gzipReader)
|
|
|
|
for {
|
|
|
|
header, errRead := tarReader.Next()
|
|
|
|
if errRead != nil {
|
|
|
|
if errors.Is(errRead, io.EOF) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
err = errRead
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if header.Typeflag == tar.TypeXGlobalHeader {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if prefix == "" && header.Typeflag == tar.TypeDir {
|
|
|
|
prefix = header.Name
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
filename := path.Join(dirname, strings.TrimPrefix(header.Name, prefix))
|
|
|
|
if header.Typeflag == tar.TypeDir {
|
2024-12-13 16:24:43 +08:00
|
|
|
if err = os.MkdirAll(filename, 0755); err != nil {
|
2024-12-13 16:09:02 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if err = writeFile(filename, tarReader); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if runtime.GOOS != "windows" {
|
2024-12-13 16:24:43 +08:00
|
|
|
os.Chmod(filename, 0644)
|
2024-12-13 16:09:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func downloadPackage(version string, dirname string) (err error) {
|
|
|
|
var (
|
|
|
|
uri string
|
|
|
|
res *http.Response
|
|
|
|
)
|
|
|
|
uri = "https://git.nobla.cn/golang/moto/archive/" + version + ".tar.gz"
|
|
|
|
if res, err = http.Get(uri); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
res.Body.Close()
|
|
|
|
}()
|
|
|
|
if res.StatusCode != http.StatusOK {
|
|
|
|
err = errors.New(res.Status)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
filename := path.Join(os.TempDir(), strconv.FormatInt(time.Now().UnixMilli(), 10)+".tar.gz")
|
|
|
|
if err = writeFile(filename, res.Body); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
err = extractFile(filename, dirname)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func replaceFiles(dirname string, source, replace string) (err error) {
|
|
|
|
var (
|
|
|
|
buf []byte
|
|
|
|
files []os.DirEntry
|
|
|
|
)
|
|
|
|
if files, err = os.ReadDir(dirname); err != nil {
|
|
|
|
if errors.Is(err, io.EOF) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
sb := []byte(source)
|
|
|
|
rb := []byte(replace)
|
|
|
|
for _, file := range files {
|
|
|
|
if file.Name() == "." || file.Name() == ".." {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
filename := path.Join(dirname, file.Name())
|
|
|
|
if file.IsDir() {
|
|
|
|
err = replaceFiles(filename, source, replace)
|
|
|
|
} else {
|
|
|
|
if buf, err = os.ReadFile(filename); err == nil {
|
|
|
|
buf = bytes.ReplaceAll(buf, sb, rb)
|
|
|
|
os.WriteFile(filename, buf, 064)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
var (
|
|
|
|
pos int
|
|
|
|
err error
|
|
|
|
dirname string
|
|
|
|
appname string
|
|
|
|
packageName string
|
|
|
|
)
|
|
|
|
flag.Parse()
|
|
|
|
packageName = *packageNameFlag
|
2024-12-13 16:24:43 +08:00
|
|
|
if packageName == "" {
|
|
|
|
if len(os.Args) > 1 {
|
|
|
|
packageName = os.Args[1]
|
|
|
|
}
|
|
|
|
}
|
2024-12-13 16:09:02 +08:00
|
|
|
pos = strings.LastIndexByte(packageName, '/')
|
|
|
|
if pos == -1 {
|
2024-12-13 16:24:43 +08:00
|
|
|
fmt.Println("应用包名称是无效的")
|
2024-12-13 16:09:02 +08:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
appname = packageName[pos:]
|
|
|
|
if dirname, err = os.Getwd(); err != nil {
|
2024-12-13 16:24:43 +08:00
|
|
|
fmt.Println("获取应用目录失败:" + err.Error())
|
2024-12-13 16:09:02 +08:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
dirname = path.Join(dirname, appname)
|
|
|
|
if err = os.MkdirAll(dirname, 0755); err != nil {
|
2024-12-13 16:24:43 +08:00
|
|
|
fmt.Println("创建应用目录失败:" + err.Error())
|
2024-12-13 16:09:02 +08:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
if err = downloadPackage(*versionFlag, dirname); err != nil {
|
2024-12-13 16:24:43 +08:00
|
|
|
fmt.Println("下载模板文件失败:" + err.Error())
|
2024-12-13 16:09:02 +08:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
if err = replaceFiles(dirname, oldPackageName, packageName); err != nil {
|
2024-12-13 16:24:43 +08:00
|
|
|
fmt.Println("生产应用文件失败:" + err.Error())
|
2024-12-13 16:09:02 +08:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
2024-12-13 16:24:43 +08:00
|
|
|
fmt.Println("创建项目成功")
|
2024-12-13 16:09:02 +08:00
|
|
|
}
|