many updates
This commit is contained in:
parent
c5bd8e0bf8
commit
58b75b48d9
10
go.mod
10
go.mod
@ -1,6 +1,8 @@
|
|||||||
module ag
|
module ag
|
||||||
|
|
||||||
go 1.18
|
go 1.21
|
||||||
|
|
||||||
|
toolchain go1.22.5
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/ssgo/httpclient v1.7.7
|
github.com/ssgo/httpclient v1.7.7
|
||||||
@ -8,9 +10,15 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/klauspost/compress v1.17.11 // indirect
|
||||||
|
github.com/nirhaas/gopacker v0.0.0-20190706195627-f33ba265006a // indirect
|
||||||
|
github.com/pkg/errors v0.8.1 // indirect
|
||||||
github.com/ssgo/config v1.7.7 // indirect
|
github.com/ssgo/config v1.7.7 // indirect
|
||||||
github.com/ssgo/log v1.7.7 // indirect
|
github.com/ssgo/log v1.7.7 // indirect
|
||||||
github.com/ssgo/standard v1.7.7 // indirect
|
github.com/ssgo/standard v1.7.7 // indirect
|
||||||
|
github.com/ssgo/tool v0.4.27
|
||||||
|
github.com/ulikunitz/xz v0.5.6 // indirect
|
||||||
|
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||||
golang.org/x/net v0.30.0 // indirect
|
golang.org/x/net v0.30.0 // indirect
|
||||||
golang.org/x/text v0.19.0 // indirect
|
golang.org/x/text v0.19.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
16
go.sum
16
go.sum
@ -1,3 +1,13 @@
|
|||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/klauspost/compress v1.7.1 h1:VRD0WLa8rweLB7alA5WMSVkoAtrI8xou5RrNd4JUlR0=
|
||||||
|
github.com/klauspost/compress v1.7.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||||
|
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||||
|
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||||
|
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
|
github.com/nirhaas/gopacker v0.0.0-20190706195627-f33ba265006a h1:sJwCHMhWaEkZF9kM3pJ3jsucYtV1bMOm5lBCj25JH14=
|
||||||
|
github.com/nirhaas/gopacker v0.0.0-20190706195627-f33ba265006a/go.mod h1:Q5pT9vDBdamRfhFef15uVGELy2xdrxThCQkqlSf3qYg=
|
||||||
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/ssgo/config v1.7.7 h1:gYYDuEEdesH41oNtvKHuwaua9quU655O8TRd3pBcuK8=
|
github.com/ssgo/config v1.7.7 h1:gYYDuEEdesH41oNtvKHuwaua9quU655O8TRd3pBcuK8=
|
||||||
github.com/ssgo/config v1.7.7/go.mod h1:4mnR3YLGkmK+YnVT0NAbfUpvxqGyjyEElag+bH4zb0c=
|
github.com/ssgo/config v1.7.7/go.mod h1:4mnR3YLGkmK+YnVT0NAbfUpvxqGyjyEElag+bH4zb0c=
|
||||||
github.com/ssgo/httpclient v1.7.7 h1:ex7pEwEpDaNtm334b04F0EQ62rPCNNxjOMi9tosXvGA=
|
github.com/ssgo/httpclient v1.7.7 h1:ex7pEwEpDaNtm334b04F0EQ62rPCNNxjOMi9tosXvGA=
|
||||||
@ -6,8 +16,14 @@ github.com/ssgo/log v1.7.7 h1:EjgPGDTAEz+ApNyluLpof9QlftxBiqh1Jt3e3E0h/m4=
|
|||||||
github.com/ssgo/log v1.7.7/go.mod h1:5E2Mkk+np9SCU84bX+lxBOG8QBD3XVkvFCbFi0RiKyk=
|
github.com/ssgo/log v1.7.7/go.mod h1:5E2Mkk+np9SCU84bX+lxBOG8QBD3XVkvFCbFi0RiKyk=
|
||||||
github.com/ssgo/standard v1.7.7 h1:5tnlcr9Nmftp7JI3jszYCEbW7VgS5HHsGueD+yWxbh0=
|
github.com/ssgo/standard v1.7.7 h1:5tnlcr9Nmftp7JI3jszYCEbW7VgS5HHsGueD+yWxbh0=
|
||||||
github.com/ssgo/standard v1.7.7/go.mod h1:LZcn56DzHu8OlDXrUPLI6h+RZbZRXhkmiKh6PSE8eDs=
|
github.com/ssgo/standard v1.7.7/go.mod h1:LZcn56DzHu8OlDXrUPLI6h+RZbZRXhkmiKh6PSE8eDs=
|
||||||
|
github.com/ssgo/tool v0.4.27 h1:tB2VvEWt0jSazel2/G+/JmhsYesJWCeRLEdyV2r5QeM=
|
||||||
|
github.com/ssgo/tool v0.4.27/go.mod h1:qIQYzXya36WWVypWP5T/AgKwKBwZkEvMRfjACkAeUuw=
|
||||||
github.com/ssgo/u v1.7.9 h1:m1wcJWQg13+NbqpG+c2z3yWO+PC7qE3PIwKfXhQqdPg=
|
github.com/ssgo/u v1.7.9 h1:m1wcJWQg13+NbqpG+c2z3yWO+PC7qE3PIwKfXhQqdPg=
|
||||||
github.com/ssgo/u v1.7.9/go.mod h1:dUG/PBG5k9fSM7SOp8RZLsK0KytNxhtenpoLgjhfxpY=
|
github.com/ssgo/u v1.7.9/go.mod h1:dUG/PBG5k9fSM7SOp8RZLsK0KytNxhtenpoLgjhfxpY=
|
||||||
|
github.com/ulikunitz/xz v0.5.6 h1:jGHAfXawEGZQ3blwU5wnWKQJvAraT7Ftq9EXjnXYgt8=
|
||||||
|
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||||
|
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
|
||||||
|
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
||||||
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||||
|
700
main.go
700
main.go
@ -9,7 +9,6 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -17,6 +16,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ssgo/httpclient"
|
"github.com/ssgo/httpclient"
|
||||||
|
"github.com/ssgo/tool/sskey/sskeylib"
|
||||||
"github.com/ssgo/u"
|
"github.com/ssgo/u"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -25,6 +25,9 @@ var version = "v0.0.1"
|
|||||||
//go:embed templates/_main.go
|
//go:embed templates/_main.go
|
||||||
var mainCodeTPL string
|
var mainCodeTPL string
|
||||||
|
|
||||||
|
//go:embed templates/_cacheFiles.go
|
||||||
|
var cacheFilesTPL string
|
||||||
|
|
||||||
//go:embed templates/_gitignore
|
//go:embed templates/_gitignore
|
||||||
var gitignoreTPL string
|
var gitignoreTPL string
|
||||||
|
|
||||||
@ -39,30 +42,38 @@ type Command struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Name string
|
Name string
|
||||||
Version string
|
Version string
|
||||||
Main string
|
Main string
|
||||||
Target map[string]string
|
Target map[string]string
|
||||||
Module map[string]string
|
Module map[string]string
|
||||||
ModuleAlias map[string]string
|
ModuleAlias map[string]string
|
||||||
ExtraImport map[string]string
|
ExtraImport map[string]string
|
||||||
CacheFile []string
|
CacheFile []string
|
||||||
|
SSKey string
|
||||||
|
CgoEnable bool
|
||||||
|
BuildFrom string
|
||||||
|
BuildEnv map[string][]string
|
||||||
|
BuildLdFlags map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
var commands = []Command{
|
var commands = []Command{
|
||||||
{"init", "i", "", "init a new project for empty dir", initProject},
|
{"init", "i", "[service|client]", "init a new project for empty dir", initProject},
|
||||||
{"build", "b", "", "build project for current os", buildProject},
|
{"build", "b", "[all|os arch]", "build project", buildProject},
|
||||||
// {"init plugin", "i p", "", "init a new plugin project for empty dir", initPluginProject},
|
{"pack", "p", "[all|os arch]", "pack project", packageProject},
|
||||||
// {"run", "r", "", "will exec `go run .`", runProject},
|
// {"login", "l", "", "login to apigo.cloud", login},
|
||||||
// {"watch run", "rr", "[...]", "run project use sskey, if project files changed will restart auto, ... args see sskey help https://github.com/ssgo/tool", devProject},
|
// {"deploy", "dp", "", "deploy project to apigo.cloud", depolyProject},
|
||||||
// {"test", "t", "", "will exec `go test -v .`, will exec into tests if exists tests dir", testProject},
|
{"run", "r", "[args...]", "run project", runProject},
|
||||||
// {"watch test", "tt", "[...]", "test project use sskey, if project files changed will restart auto, ... args see sskey help https://github.com/ssgo/tool", devTestProject},
|
{"buildrun", "rr", "[args...]", "build and run project", buildRunProject},
|
||||||
// {"tidy", "td", "", "tidy project, find imported plugins from .js files add import code to jsImports.go, export typescript code for used plugins into \"plugins/\"", tidy},
|
{"watch", "w", "[args...]", "run and watch project", watchProject},
|
||||||
// {"tags", "", "", "show git tags", showGitTags},
|
{"buildwatch", "ww", "[args...]", "build and run and watch project", buildWatchProject},
|
||||||
// {"commit", "co", "comment", "commit git repo and push, comment is need", commitGitRepo},
|
{"test", "t", "[args...]", "test project", testProject},
|
||||||
// {"commit and +tag", "co+", "comment", "commit git repo and push, than update tag, comment is need", commitAndTagGitRepo},
|
{"buildtest", "tt", "[args...]", "build and test project", buildTestProject},
|
||||||
// {"update tag", "t+", "[version]", "add git tag push, if no new tag specified will use last tag +1", addGitTag},
|
{"tidy", "td", "", "tidy project, run go mod tidy", tidyProject},
|
||||||
|
{"export", "e", "", "export typescript code for dev", exportForDev},
|
||||||
|
{"tags", "", "", "show git tags", showGitTags},
|
||||||
|
{"add tag", "t+", "[version]", "add git tag and push, if no new tag specified will use last tag +1", addGitTag},
|
||||||
|
{"commit", "c+", "comment", "commit git repo and push, comment is need", commitGitRepo},
|
||||||
}
|
}
|
||||||
|
|
||||||
var hc = httpclient.GetClient(30 * time.Second)
|
var hc = httpclient.GetClient(30 * time.Second)
|
||||||
@ -293,6 +304,7 @@ func getConfig() *Config {
|
|||||||
ModuleAlias: map[string]string{},
|
ModuleAlias: map[string]string{},
|
||||||
ExtraImport: map[string]string{},
|
ExtraImport: map[string]string{},
|
||||||
CacheFile: []string{},
|
CacheFile: []string{},
|
||||||
|
BuildFrom: "golang",
|
||||||
}
|
}
|
||||||
u.LoadYaml("apigo.yml", conf)
|
u.LoadYaml("apigo.yml", conf)
|
||||||
|
|
||||||
@ -353,19 +365,11 @@ func getConfig() *Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initProject(args []string) bool {
|
func initProject(args []string) bool {
|
||||||
// if u.FileExists("go.mod") {
|
|
||||||
// fmt.Println(u.Red("go.mod exists, are you sure to init this project?"))
|
|
||||||
// sure := 'n'
|
|
||||||
// _, _ = fmt.Scan(&sure)
|
|
||||||
// if sure != 'y' && sure != 'Y' {
|
|
||||||
// return false
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
if u.FileExists("main.go") || u.FileExists("go.mod") {
|
if u.FileExists("main.go") || u.FileExists("go.mod") {
|
||||||
fmt.Println(u.Red("main.go or go.mod is exists, are you sure to overwrite it? (y/n)"))
|
fmt.Println("main.go or go.mod is exists, are you sure to overwrite it? (y/n)")
|
||||||
sure := 'n'
|
sure := ""
|
||||||
_, _ = fmt.Scan(&sure)
|
_, _ = fmt.Scanln(&sure)
|
||||||
if sure != 'y' && sure != 'Y' {
|
if sure != "y" && sure != "Y" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -375,10 +379,9 @@ func initProject(args []string) bool {
|
|||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
refProjName = args[0]
|
refProjName = args[0]
|
||||||
}
|
}
|
||||||
// TODO check name is path
|
|
||||||
repoPath := fetchRepo(refProjName)
|
repoPath := fetchRepo(refProjName)
|
||||||
if u.FileExists(repoPath) {
|
if u.FileExists(repoPath) {
|
||||||
if err := CopyFile(repoPath, "."); err == nil {
|
if err := u.CopyFile(repoPath, "."); err == nil {
|
||||||
fmt.Println(u.Green("copy project files success"), repoPath)
|
fmt.Println(u.Green("copy project files success"), repoPath)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(u.BRed("copy project files failed"), repoPath, err.Error())
|
fmt.Println(u.BRed("copy project files failed"), repoPath, err.Error())
|
||||||
@ -393,8 +396,10 @@ func initProject(args []string) bool {
|
|||||||
conf := getConfig()
|
conf := getConfig()
|
||||||
writeFile("main.go", mainCodeTPL, conf)
|
writeFile("main.go", mainCodeTPL, conf)
|
||||||
|
|
||||||
_ = runCommand(goPath, "mod", "init", conf.Name)
|
if !u.FileExists("go.mod") {
|
||||||
_ = runCommand(goPath, "mod", "edit", "-go=1.18")
|
_ = runCommand(goPath, "mod", "init", conf.Name)
|
||||||
|
_ = runCommand(goPath, "mod", "edit", "-go=1.18")
|
||||||
|
}
|
||||||
|
|
||||||
for pkgName, pkgVersion := range conf.Module {
|
for pkgName, pkgVersion := range conf.Module {
|
||||||
_ = runCommand(goPath, "get", pkgName+"@"+pkgVersion)
|
_ = runCommand(goPath, "get", pkgName+"@"+pkgVersion)
|
||||||
@ -446,10 +451,38 @@ func buildProjectWithOption(args []string, isPack bool) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
output := "build"
|
output := "build"
|
||||||
|
action := "build"
|
||||||
if isPack {
|
if isPack {
|
||||||
output = "release"
|
output = "release"
|
||||||
// TODO 生成静态文件和入口文件嵌入代码
|
action = "pack"
|
||||||
// TODO 生成SSKey嵌入代码
|
cacheFiles := conf.CacheFile
|
||||||
|
cachedFiles := make([]string, 0)
|
||||||
|
if conf.Main != "" {
|
||||||
|
cacheFiles = append([]string{conf.Main}, cacheFiles...)
|
||||||
|
}
|
||||||
|
for _, file := range cacheFiles {
|
||||||
|
if cache := u.LoadFileToB64(file); cache != nil {
|
||||||
|
cachedFiles = append(cachedFiles, strings.ReplaceAll(u.Json(cache), `"`, `\"`))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(cachedFiles) > 0 {
|
||||||
|
writeFile("cacheFiles.go", cacheFilesTPL, map[string]any{
|
||||||
|
"Files": cachedFiles,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if conf.SSKey != "" {
|
||||||
|
homeDir, _ := os.UserHomeDir()
|
||||||
|
keyBuf := u.UnBase64(u.ReadFileN(filepath.Join(homeDir, "sskeys", conf.SSKey)))
|
||||||
|
if len(keyBuf) == 81 && keyBuf[80] == 217 {
|
||||||
|
if sskeyCode, err := sskeylib.MakeCode("go", keyBuf[0:40], keyBuf[40:80]); err == nil {
|
||||||
|
u.WriteFile("setSSKey.go", sskeyCode)
|
||||||
|
} else {
|
||||||
|
fmt.Println(u.Red("failed to make sskey file"), conf.SSKey, err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println(u.Red("no sskey ["+conf.SSKey+"] config found, please run [sskey -c "+conf.SSKey+"] to make"), filepath.Join(homeDir, "sskeys", conf.SSKey))
|
||||||
|
}
|
||||||
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
os.Remove("cacheFiles.go")
|
os.Remove("cacheFiles.go")
|
||||||
os.Remove("setSSKey.go")
|
os.Remove("setSSKey.go")
|
||||||
@ -458,75 +491,282 @@ func buildProjectWithOption(args []string, isPack bool) bool {
|
|||||||
|
|
||||||
_ = runCommand(goPath, "mod", "tidy")
|
_ = runCommand(goPath, "mod", "tidy")
|
||||||
|
|
||||||
|
cgoEnable := conf.CgoEnable
|
||||||
|
// 未指定时检测是否需要启用CGO
|
||||||
|
if !cgoEnable {
|
||||||
|
if lines, err := u.RunCommand(goPath, "list", "-f", "{{.ImportPath}}: {{.CgoFiles}}", "all"); err == nil {
|
||||||
|
for _, line := range lines {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if line == "" || strings.HasSuffix(line, ": []") || strings.HasPrefix(line, "github.com/shirou/gopsutil/") || strings.HasPrefix(line, "net:") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cgoEnable = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测是否有docker环境
|
||||||
|
upxBin := ""
|
||||||
|
_upxArgs := []string{}
|
||||||
|
dockerBin := ""
|
||||||
|
if dockerBinPath, err := exec.LookPath("docker"); err == nil {
|
||||||
|
dockerBin = dockerBinPath
|
||||||
|
}
|
||||||
|
|
||||||
|
if isPack {
|
||||||
|
if upxBinPath, err := exec.LookPath("upx"); err == nil {
|
||||||
|
upxBin = upxBinPath
|
||||||
|
} else if dockerBin != "" {
|
||||||
|
upxBin = dockerBin
|
||||||
|
_upxArgs = append(_upxArgs, "run", "--rm", "-v", ".:/build", "-w", "/build", "apigocc/upx")
|
||||||
|
}
|
||||||
|
|
||||||
|
if upxBin == "" {
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
fmt.Println(u.Red("upx not found, skip compress"))
|
||||||
|
fmt.Println(u.Red("you can install upx by \"brew install upx\""))
|
||||||
|
} else if runtime.GOOS == "linux" {
|
||||||
|
fmt.Println(u.Red("upx not found, skip compress"))
|
||||||
|
fmt.Println(u.Red("you can install upx by \"apt install upx\" or \"yum install upx\" or https://upx.github.io/"))
|
||||||
|
} else {
|
||||||
|
fmt.Println(u.Red("upx not found, skip compress"))
|
||||||
|
fmt.Println(u.Red("you can install upx https://upx.github.io/"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, target := range targets {
|
for _, target := range targets {
|
||||||
buildOS := target[0]
|
buildOS := target[0]
|
||||||
buildArch := target[1]
|
buildArch := target[1]
|
||||||
name := path.Base(conf.Name)
|
name := path.Base(conf.Name)
|
||||||
ext := ""
|
ext := ""
|
||||||
|
if buildOS == "mac" {
|
||||||
|
buildOS = "darwin"
|
||||||
|
}
|
||||||
if buildOS == "windows" {
|
if buildOS == "windows" {
|
||||||
ext = ".exe"
|
ext = ".exe"
|
||||||
}
|
}
|
||||||
buildPath := filepath.Join(output, fmt.Sprintf("%s_%s_%s%s", name, buildOS, buildArch, ext))
|
buildPath := filepath.Join(output, fmt.Sprintf("%s_%s_%s%s", name, buildOS, buildArch, ext))
|
||||||
env := append(make([]string, 0), "GOOS="+buildOS, "GOARCH="+buildArch)
|
|
||||||
err := runCommandWithEnv("go", env, "build", "-o", buildPath, "-ldflags", "-s -w", ".")
|
ldFlags := "-s -w"
|
||||||
if err != nil {
|
if conf.BuildLdFlags != nil && conf.BuildLdFlags[buildOS] != "" {
|
||||||
fmt.Println(u.BRed("build failed"), buildOS, buildArch, err.Error())
|
ldFlags = conf.BuildLdFlags[buildOS]
|
||||||
|
}
|
||||||
|
|
||||||
|
env := append(conf.BuildEnv[buildOS], "GOOS="+buildOS, "GOARCH="+buildArch)
|
||||||
|
buildArgs := []string{}
|
||||||
|
buildBin := goPath
|
||||||
|
workOS := runtime.GOOS
|
||||||
|
useDocker := false
|
||||||
|
if cgoEnable {
|
||||||
|
env = append(env, "CGO_ENABLED=1")
|
||||||
|
|
||||||
|
if cgoEnable && dockerBin != "" && workOS != buildOS {
|
||||||
|
buildBin = dockerBin
|
||||||
|
workOS = "linux"
|
||||||
|
homePath, _ := os.UserHomeDir()
|
||||||
|
buildArgs = append(buildArgs, "run", "--rm", "-v", filepath.Join(homePath, "go")+":/go", "-v", ".:/build", "-w", "/build")
|
||||||
|
useDocker = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查 CC 工具
|
||||||
|
ccBin := ""
|
||||||
|
cxxBin := ""
|
||||||
|
installCmd := ""
|
||||||
|
switch buildOS {
|
||||||
|
case "windows":
|
||||||
|
ldFlags += " -H windowsgui"
|
||||||
|
case "linux":
|
||||||
|
// env = append(env, "CGO_LDFLAGS=-static")
|
||||||
|
}
|
||||||
|
if workOS != buildOS {
|
||||||
|
switch workOS + buildOS {
|
||||||
|
case "darwinlinux":
|
||||||
|
ccBin = "x86_64-linux-musl-gcc"
|
||||||
|
cxxBin = "x86_64-linux-musl-g++"
|
||||||
|
installCmd = "brew install FiloSottile/musl-cross/musl-cross"
|
||||||
|
case "darwinwindows":
|
||||||
|
ccBin = "x86_64-w64-mingw32-gcc"
|
||||||
|
cxxBin = "x86_64-w64-mingw32-g++"
|
||||||
|
installCmd = "brew install mingw-w64"
|
||||||
|
case "linuxdarwin":
|
||||||
|
ccBin = "o64-clang"
|
||||||
|
cxxBin = "o64-clang++"
|
||||||
|
installCmd = "apt-get install -y cmake clang bison flex"
|
||||||
|
case "linuxwindows":
|
||||||
|
ccBin = "x86_64-w64-mingw32-gcc"
|
||||||
|
cxxBin = "x86_64-w64-mingw32-g++"
|
||||||
|
installCmd = "apt-get install -y gcc-mingw-w64"
|
||||||
|
case "windowswindows":
|
||||||
|
ccBin = "gcc.exe"
|
||||||
|
cxxBin = "g++.exe"
|
||||||
|
installCmd = "https://jmeubank.github.io/tdm-gcc/"
|
||||||
|
case "windowslinux", "windowsdarwin":
|
||||||
|
fmt.Println(u.Red("not support cross compile on windws when CGO_ENABLED=1, you can use WSL"))
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
fmt.Println(u.Red("not support cross compile on " + buildOS + " " + buildArch + " when CGO_ENABLED=1"))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if buildOS == "linux" && buildArch == "arm64" {
|
||||||
|
ccBin = "aarch64-linux-gnu-gcc"
|
||||||
|
cxxBin = "aarch64-linux-gnu-g++"
|
||||||
|
installCmd = "apt-get install -y gcc-aarch64-linux-gnu"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ccBin != "" && cxxBin != "" {
|
||||||
|
if !useDocker {
|
||||||
|
ccBinPath, err1 := exec.LookPath(ccBin)
|
||||||
|
cxxBinPath, err2 := exec.LookPath(cxxBin)
|
||||||
|
if err1 == nil && err2 == nil {
|
||||||
|
env = append(env, "CC="+ccBinPath, "CXX="+cxxBinPath)
|
||||||
|
} else {
|
||||||
|
fmt.Println(u.Red("not found " + ccBin + " or " + cxxBin))
|
||||||
|
fmt.Println("you can install by", u.BCyan(installCmd))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
env = append(env, "CC="+ccBin, "CXX="+cxxBin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if useDocker {
|
||||||
|
for _, v := range env {
|
||||||
|
if strings.Contains(v, "%cd%") {
|
||||||
|
v = strings.ReplaceAll(v, "%cd%", "/build/")
|
||||||
|
}
|
||||||
|
buildArgs = append(buildArgs, "-e", v)
|
||||||
|
}
|
||||||
|
env = nil
|
||||||
|
// buildArgs = append(buildArgs, "apigocc/gobuild", "go")
|
||||||
|
// buildArgs = append(buildArgs, "gob:v1", "bash", "-c")
|
||||||
|
buildArgs = append(buildArgs, conf.BuildFrom, "bash", "-c")
|
||||||
|
buildArgs = append(buildArgs, fmt.Sprintln("go", "build", "-o", buildPath, "-ldflags", "'"+ldFlags+"'", "."))
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(u.Green("build for"), buildOS, buildArch, "to", buildPath)
|
curPath, _ := os.Getwd()
|
||||||
|
for i, v := range env {
|
||||||
|
if strings.Contains(v, "%cd%") {
|
||||||
|
env[i] = strings.ReplaceAll(v, "%cd%", filepath.Join(curPath, ""))
|
||||||
|
}
|
||||||
|
buildArgs = append(buildArgs, "-e", v)
|
||||||
|
}
|
||||||
|
buildArgs = append(buildArgs, "build", "-o", buildPath, "-ldflags", ldFlags, ".")
|
||||||
|
}
|
||||||
|
// err := runCommandWithEnv("go", env, "build", "-o", buildPath, "-ldflags", ldFlags, ".")
|
||||||
|
err := runCommandWithEnv(buildBin, env, buildArgs...)
|
||||||
|
if isPack && upxBin != "" && buildOS != "darwin" {
|
||||||
|
upxArgs := append(_upxArgs, buildPath)
|
||||||
|
err = runCommand(upxBin, upxArgs...)
|
||||||
|
// if upxBin, err := exec.LookPath("upx"); err == nil {
|
||||||
|
// if buildOS == "darwin" {
|
||||||
|
// fmt.Println(u.Yellow("upx not support macos, skip compress"))
|
||||||
|
// } else {
|
||||||
|
// if err = runCommand(upxBin, buildPath); err == nil {
|
||||||
|
// fmt.Println(u.Green("compress file success"), buildPath)
|
||||||
|
// } else {
|
||||||
|
// fmt.Println(u.BRed("compress file failed"), buildPath, err.Error())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// if workOS == "darwin" {
|
||||||
|
// fmt.Println(u.Red("upx not found, skip compress"))
|
||||||
|
// fmt.Println(u.Red("you can install upx by \"brew install upx\""))
|
||||||
|
// } else if workOS == "linux" {
|
||||||
|
// fmt.Println(u.Red("upx not found, skip compress"))
|
||||||
|
// fmt.Println(u.Red("you can install upx by \"apt install upx\" or \"yum install upx\" or https://upx.github.io/"))
|
||||||
|
// } else {
|
||||||
|
// fmt.Println(u.Red("upx not found, skip compress"))
|
||||||
|
// fmt.Println(u.Red("you can install upx https://upx.github.io/"))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(u.BRed(action+" failed"), buildOS, buildArch, err.Error())
|
||||||
|
} else {
|
||||||
|
fmt.Println(u.Green(action+" for"), buildOS, buildArch, "to", buildPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func CopyFile(from, to string) error {
|
// func CopyFile(from, to string) error {
|
||||||
fromStat, _ := os.Stat(from)
|
// fromStat, _ := os.Stat(from)
|
||||||
if fromStat.IsDir() {
|
// if fromStat.IsDir() {
|
||||||
// copy dir
|
// // copy dir
|
||||||
for _, f := range u.ReadDirN(from) {
|
// for _, f := range u.ReadDirN(from) {
|
||||||
err := CopyFile(filepath.Join(from, f.Name), filepath.Join(to, f.Name))
|
// err := CopyFile(filepath.Join(from, f.Name), filepath.Join(to, f.Name))
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return nil
|
// return nil
|
||||||
} else {
|
// } else {
|
||||||
// copy file
|
// // copy file
|
||||||
toStat, err := os.Stat(to)
|
// toStat, err := os.Stat(to)
|
||||||
if err == nil && toStat.IsDir() {
|
// if err == nil && toStat.IsDir() {
|
||||||
to = filepath.Join(to, filepath.Base(from))
|
// to = filepath.Join(to, filepath.Base(from))
|
||||||
}
|
// }
|
||||||
u.CheckPath(to)
|
// u.CheckPath(to)
|
||||||
if writer, err := os.OpenFile(to, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644); err == nil {
|
// if writer, err := os.OpenFile(to, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644); err == nil {
|
||||||
defer writer.Close()
|
// defer writer.Close()
|
||||||
if reader, err := os.OpenFile(from, os.O_RDONLY, 0644); err == nil {
|
// if reader, err := os.OpenFile(from, os.O_RDONLY, 0644); err == nil {
|
||||||
defer reader.Close()
|
// defer reader.Close()
|
||||||
_, err = io.Copy(writer, reader)
|
// _, err = io.Copy(writer, reader)
|
||||||
return err
|
// return err
|
||||||
} else {
|
// } else {
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
func runProject(args []string) bool {
|
||||||
|
_, logVPath := findTool()
|
||||||
|
cmdArgs := append([]string{}, args...)
|
||||||
|
conf := getConfig()
|
||||||
|
name := path.Base(conf.Name)
|
||||||
|
binPath := filepath.Join("build", fmt.Sprintf("%s_%s_%s", name, runtime.GOOS, runtime.GOARCH))
|
||||||
|
if !u.FileExists(binPath) {
|
||||||
|
buildProject([]string{})
|
||||||
}
|
}
|
||||||
|
return nil == runCommandPipe(logVPath, binPath, cmdArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// func _runProject(args []string, isWatch bool) bool {
|
func buildRunProject(args []string) bool {
|
||||||
// _ = runCommand(goPath, "mod", "tidy")
|
buildProject(args)
|
||||||
// goBinPath, logVPath := findTool()
|
return runProject(args)
|
||||||
// if isWatch {
|
}
|
||||||
// args = append(args, "-pt", ".go,.js,.yml", "run", ".")
|
|
||||||
// } else {
|
|
||||||
// goBinPath = goPath
|
|
||||||
// args = append(args, "run", ".")
|
|
||||||
// }
|
|
||||||
// return nil == runCommandPipe (logVPath, goBinPath, goRunEnv, args...)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func runProject(args []string) bool {
|
func testProject(args []string) bool {
|
||||||
// return _runProject(args, false)
|
args = append([]string{"test"}, args...)
|
||||||
// }
|
return runProject(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildTestProject(args []string) bool {
|
||||||
|
buildProject(args)
|
||||||
|
args = append([]string{"test"}, args...)
|
||||||
|
return runProject(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func watchProject(args []string) bool {
|
||||||
|
args = append([]string{"-w"}, args...)
|
||||||
|
return runProject(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildWatchProject(args []string) bool {
|
||||||
|
buildProject(args)
|
||||||
|
args = append([]string{"-w"}, args...)
|
||||||
|
return runProject(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func exportForDev(args []string) bool {
|
||||||
|
return runProject([]string{"-export"})
|
||||||
|
}
|
||||||
|
|
||||||
// func devProject(args []string) bool {
|
// func devProject(args []string) bool {
|
||||||
// return _runProject(args, true)
|
// return _runProject(args, true)
|
||||||
@ -579,97 +819,97 @@ func CopyFile(from, to string) error {
|
|||||||
// return true
|
// return true
|
||||||
// }
|
// }
|
||||||
|
|
||||||
var pkgMatcher = regexp.MustCompile(`(?im)^\s*(import)?\s*_\s+"([\w-_/.]+)"`)
|
// var pkgMatcher = regexp.MustCompile(`(?im)^\s*(import)?\s*_\s+"([\w-_/.]+)"`)
|
||||||
var importMatcher = regexp.MustCompile(`(?im)^\s*import\s+([\w{}, ]+)\s+from\s+['"]([\w./\\\- ]+)['"]`)
|
// var importMatcher = regexp.MustCompile(`(?im)^\s*import\s+([\w{}, ]+)\s+from\s+['"]([\w./\\\- ]+)['"]`)
|
||||||
|
|
||||||
func makeJsImports(path string, jsImports *[]string, pkgName string) {
|
// func makeJsImports(path string, jsImports *[]string, pkgName string) {
|
||||||
if u.FileExists(filepath.Join(path, "go.mod")) {
|
// if u.FileExists(filepath.Join(path, "go.mod")) {
|
||||||
if m := modNameMatcher.FindStringSubmatch(u.ReadFileN(filepath.Join(path, "go.mod"))); m != nil {
|
// if m := modNameMatcher.FindStringSubmatch(u.ReadFileN(filepath.Join(path, "go.mod"))); m != nil {
|
||||||
if pkgName != m[1] {
|
// if pkgName != m[1] {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
for _, f := range u.ReadDirN(path) {
|
// for _, f := range u.ReadDirN(path) {
|
||||||
filename := f.Name
|
// filename := f.Name
|
||||||
fullName := filepath.Join(path, filename)
|
// fullName := filepath.Join(path, filename)
|
||||||
if !strings.HasPrefix(filename, ".") && !strings.HasPrefix(filename, "_") && filename != "_makePluginCode" && filename != "node_modules" && filename != "www" && filename != "src" {
|
// if !strings.HasPrefix(filename, ".") && !strings.HasPrefix(filename, "_") && filename != "_makePluginCode" && filename != "node_modules" && filename != "www" && filename != "src" {
|
||||||
if f.IsDir {
|
// if f.IsDir {
|
||||||
makeJsImports(fullName, jsImports, pkgName)
|
// makeJsImports(fullName, jsImports, pkgName)
|
||||||
} else if strings.HasSuffix(filename, ".js") {
|
// } else if strings.HasSuffix(filename, ".js") {
|
||||||
if code, err := u.ReadFile(fullName); err == nil {
|
// if code, err := u.ReadFile(fullName); err == nil {
|
||||||
for _, m := range importMatcher.FindAllStringSubmatch(code, 1024) {
|
// for _, m := range importMatcher.FindAllStringSubmatch(code, 1024) {
|
||||||
if !strings.HasPrefix(m[2], ".") && !strings.HasPrefix(m[2], "_") && m[2] != "current-plugin" && m[2] != "console" && m[2] != "logger" {
|
// if !strings.HasPrefix(m[2], ".") && !strings.HasPrefix(m[2], "_") && m[2] != "current-plugin" && m[2] != "console" && m[2] != "logger" {
|
||||||
checkFile := filepath.Join(path, m[2])
|
// checkFile := filepath.Join(path, m[2])
|
||||||
checkFileInfo := u.GetFileInfo(checkFile)
|
// checkFileInfo := u.GetFileInfo(checkFile)
|
||||||
if checkFileInfo != nil && checkFileInfo.IsDir {
|
// if checkFileInfo != nil && checkFileInfo.IsDir {
|
||||||
checkFile = filepath.Join(checkFile, "index.js")
|
// checkFile = filepath.Join(checkFile, "index.js")
|
||||||
} else if !strings.HasSuffix(checkFile, ".js") {
|
// } else if !strings.HasSuffix(checkFile, ".js") {
|
||||||
checkFile += ".js"
|
// checkFile += ".js"
|
||||||
}
|
// }
|
||||||
//fmt.Println(u.BMagenta(checkFile), u.FileExists(checkFile))
|
// //fmt.Println(u.BMagenta(checkFile), u.FileExists(checkFile))
|
||||||
if !u.FileExists(checkFile) {
|
// if !u.FileExists(checkFile) {
|
||||||
*jsImports = u.AppendUniqueString(*jsImports, m[2])
|
// *jsImports = u.AppendUniqueString(*jsImports, m[2])
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
func makePluginCodeImports(from string, imports *[]string, parentModuleName string) {
|
// func makePluginCodeImports(from string, imports *[]string, parentModuleName string) {
|
||||||
jsImports := make([]string, 0)
|
// jsImports := make([]string, 0)
|
||||||
currentParentModuleName := parentModuleName
|
// currentParentModuleName := parentModuleName
|
||||||
if u.FileExists(filepath.Join(from, "go.mod")) {
|
// if u.FileExists(filepath.Join(from, "go.mod")) {
|
||||||
pkgName := ""
|
// pkgName := ""
|
||||||
if m := modNameMatcher.FindStringSubmatch(u.ReadFileN(filepath.Join(from, "go.mod"))); m != nil {
|
// if m := modNameMatcher.FindStringSubmatch(u.ReadFileN(filepath.Join(from, "go.mod"))); m != nil {
|
||||||
pkgName = m[1]
|
// pkgName = m[1]
|
||||||
}
|
// }
|
||||||
makeJsImports(from, &jsImports, pkgName)
|
// makeJsImports(from, &jsImports, pkgName)
|
||||||
parentModuleName = pkgName
|
// parentModuleName = pkgName
|
||||||
}
|
// }
|
||||||
|
|
||||||
currentPkgName := ""
|
// currentPkgName := ""
|
||||||
for _, f := range u.ReadDirN(from) {
|
// for _, f := range u.ReadDirN(from) {
|
||||||
if f.IsDir {
|
// if f.IsDir {
|
||||||
if !strings.HasPrefix(f.Name, ".") {
|
// if !strings.HasPrefix(f.Name, ".") {
|
||||||
makePluginCodeImports(filepath.Join(from, f.Name), imports, parentModuleName)
|
// makePluginCodeImports(filepath.Join(from, f.Name), imports, parentModuleName)
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
if strings.HasSuffix(f.Name, ".go") && !strings.HasPrefix(f.Name, ".") && f.Name != "makePluginCode.go" {
|
// if strings.HasSuffix(f.Name, ".go") && !strings.HasPrefix(f.Name, ".") && f.Name != "makePluginCode.go" {
|
||||||
if code, err := u.ReadFile(filepath.Join(from, f.Name)); err == nil {
|
// if code, err := u.ReadFile(filepath.Join(from, f.Name)); err == nil {
|
||||||
if m := pkgNameMatcher.FindStringSubmatch(code); m != nil {
|
// if m := pkgNameMatcher.FindStringSubmatch(code); m != nil {
|
||||||
if currentPkgName+"_test" != m[1] {
|
// if currentPkgName+"_test" != m[1] {
|
||||||
currentPkgName = m[1]
|
// currentPkgName = m[1]
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
for _, m := range pkgMatcher.FindAllStringSubmatch(code, 1024) {
|
// for _, m := range pkgMatcher.FindAllStringSubmatch(code, 1024) {
|
||||||
if m[2] != "current-plugin" && !strings.HasPrefix(f.Name, "jsImports") {
|
// if m[2] != "current-plugin" && !strings.HasPrefix(f.Name, "jsImports") {
|
||||||
*imports = u.AppendUniqueString(*imports, m[2])
|
// *imports = u.AppendUniqueString(*imports, m[2])
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if currentPkgName != "" && u.FileExists(filepath.Join(from, "go.mod")) {
|
// if currentPkgName != "" && u.FileExists(filepath.Join(from, "go.mod")) {
|
||||||
pkgList := make([]string, 0)
|
// pkgList := make([]string, 0)
|
||||||
for _, plgPkg := range jsImports {
|
// for _, plgPkg := range jsImports {
|
||||||
if plgPkg != currentParentModuleName && !u.StringIn(*imports, plgPkg) {
|
// if plgPkg != currentParentModuleName && !u.StringIn(*imports, plgPkg) {
|
||||||
pkgList = append(pkgList, plgPkg)
|
// pkgList = append(pkgList, plgPkg)
|
||||||
*imports = u.AppendUniqueString(*imports, plgPkg)
|
// *imports = u.AppendUniqueString(*imports, plgPkg)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if len(pkgList) > 0 {
|
// if len(pkgList) > 0 {
|
||||||
_ = u.WriteFile(filepath.Join(from, u.StringIf(strings.HasSuffix(currentPkgName, "_test"), "jsImports_test.go", "jsImports.go")), `package `+currentPkgName+`
|
// _ = u.WriteFile(filepath.Join(from, u.StringIf(strings.HasSuffix(currentPkgName, "_test"), "jsImports_test.go", "jsImports.go")), `package `+currentPkgName+`
|
||||||
import _ "`+strings.Join(pkgList, "\"\nimport _ \"")+`"
|
// import _ "`+strings.Join(pkgList, "\"\nimport _ \"")+`"
|
||||||
`)
|
// `)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
func writeFile(filename string, fileContent string, data any) {
|
func writeFile(filename string, fileContent string, data any) {
|
||||||
if fp, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600); err == nil {
|
if fp, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600); err == nil {
|
||||||
@ -683,75 +923,34 @@ func writeFile(filename string, fileContent string, data any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var replaceMatcher = regexp.MustCompile(`([a-zA-Z0-9._\-/]+)\s+(v[0-9.]+)\s+=>\s+([a-zA-Z0-9._\-/\\]+)`)
|
// var replaceMatcher = regexp.MustCompile(`([a-zA-Z0-9._\-/]+)\s+(v[0-9.]+)\s+=>\s+([a-zA-Z0-9._\-/\\]+)`)
|
||||||
var modNameMatcher = regexp.MustCompile(`(?m)^module\s+([a-zA-Z0-9._\-/]+)$`)
|
// var modNameMatcher = regexp.MustCompile(`(?m)^module\s+([a-zA-Z0-9._\-/]+)$`)
|
||||||
var pkgNameMatcher = regexp.MustCompile(`(?m)^package\s+([a-zA-Z0-9._\-/]+)$`)
|
// var pkgNameMatcher = regexp.MustCompile(`(?m)^package\s+([a-zA-Z0-9._\-/]+)$`)
|
||||||
|
|
||||||
// func tidy(args []string) bool {
|
func tidyProject(args []string) bool {
|
||||||
// // 判断是否可执行项目(不创建指向项目本身的 import _)
|
_ = runCommand(goPath, "mod", "tidy")
|
||||||
// isMainProject := false
|
return true
|
||||||
// isEmptyProject := true
|
}
|
||||||
// if files, err := os.ReadDir("."); err == nil {
|
|
||||||
// for _, f := range files {
|
|
||||||
// if !f.IsDir() && strings.HasSuffix(f.Name(), ".go") {
|
|
||||||
// isEmptyProject = false
|
|
||||||
// code, _ := u.ReadFile(f.Name())
|
|
||||||
// if strings.Contains(code, "package main") || strings.Contains(code, "func main(") {
|
|
||||||
// isMainProject = true
|
|
||||||
// break
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 扫描用到的插件(import _)
|
|
||||||
// imports := make([]string, 0)
|
|
||||||
// makePluginCodeImports(".", &imports, "")
|
|
||||||
|
|
||||||
// findGoModCode, _ := u.ReadFile("go.mod")
|
|
||||||
// goModCode := "module main\ngo 1.18\n"
|
|
||||||
// currentModuleName := "current-project"
|
|
||||||
// if !isMainProject {
|
|
||||||
// if m := modNameMatcher.FindStringSubmatch(findGoModCode); m != nil {
|
|
||||||
// currentModuleName = m[1]
|
|
||||||
// }
|
|
||||||
// goModCode += "require " + currentModuleName + " v0.0.0 // indirect\nreplace " + currentModuleName + " v0.0.0 => ../\n"
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 扫描 replace,处理路径后加入到 _makePluginCode/go.mod
|
|
||||||
// for _, m := range replaceMatcher.FindAllStringSubmatch(findGoModCode, 100) {
|
|
||||||
// replacePath := m[3]
|
|
||||||
// if absPath, err := filepath.Abs(m[3]); err == nil {
|
|
||||||
// replacePath = absPath
|
|
||||||
// }
|
|
||||||
// goModCode += fmt.Sprintln("replace", m[1], m[2], "=>", replacePath)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if !isMainProject && !isEmptyProject {
|
|
||||||
// imports = append(imports, currentModuleName)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// _ = u.WriteFile(filepath.Join("_makePluginCode", "go.mod"), goModCode)
|
|
||||||
// writeFile(filepath.Join("_makePluginCode", "main.go"), makePluginCodeTPL, map[string]any{"imports": imports})
|
|
||||||
// _ = os.Chdir("_makePluginCode")
|
|
||||||
// defer func() {
|
|
||||||
// _ = os.Chdir("..")
|
|
||||||
// //_ = os.RemoveAll("_makePluginCode")
|
|
||||||
// }()
|
|
||||||
// _ = runCommand(goPath, "mod", "tidy")
|
|
||||||
// if err := runCommandWithEnv(goPath, goRunEnv, "run", "."); err != nil {
|
|
||||||
// fmt.Println(u.Red(err.Error()))
|
|
||||||
// }
|
|
||||||
// return true
|
|
||||||
// }
|
|
||||||
|
|
||||||
func runCommand(name string, args ...string) error {
|
func runCommand(name string, args ...string) error {
|
||||||
return runCommandWithEnv(name, nil, args...)
|
return runCommandWithEnv(name, nil, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printCmd(name string, env []string, args []string) {
|
||||||
|
fmt.Print(u.BMagenta(name))
|
||||||
|
for _, arg := range args {
|
||||||
|
fmt.Print(" ", u.BCyan(arg))
|
||||||
|
}
|
||||||
|
for _, v := range env {
|
||||||
|
fmt.Print(" ", u.BYellow(v))
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
func runCommandWithEnv(name string, env []string, args ...string) error {
|
func runCommandWithEnv(name string, env []string, args ...string) error {
|
||||||
// pathname, _ := os.Getwd()
|
// pathname, _ := os.Getwd()
|
||||||
// fmt.Println(u.BMagenta(pathname), u.BCyan(name), u.Cyan(strings.Join(args, " ")))
|
// fmt.Println(u.BMagenta(pathname), u.BCyan(name), u.Cyan(strings.Join(args, " ")))
|
||||||
|
printCmd(name, env, args)
|
||||||
cmd := exec.Command(name, args...)
|
cmd := exec.Command(name, args...)
|
||||||
if env != nil {
|
if env != nil {
|
||||||
// if runtime.GOOS == "windows" {
|
// if runtime.GOOS == "windows" {
|
||||||
@ -775,17 +974,16 @@ func runCommandPipe(pipeCommandName, commandName string, args ...string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runCommandPipeWithEnv(pipeCommandName, commandName string, env []string, args ...string) error {
|
func runCommandPipeWithEnv(pipeCommandName, commandName string, env []string, args ...string) error {
|
||||||
pathname, _ := os.Getwd()
|
printCmd(commandName, env, args)
|
||||||
fmt.Println(u.BMagenta(pathname), u.BCyan(commandName), u.Cyan(strings.Join(args, " ")), u.BMagenta(pipeCommandName))
|
|
||||||
cmd1 := exec.Command(commandName, args...)
|
cmd1 := exec.Command(commandName, args...)
|
||||||
cmd2 := exec.Command(pipeCommandName)
|
cmd2 := exec.Command(pipeCommandName)
|
||||||
// if env != nil {
|
if env != nil {
|
||||||
// if runtime.GOOS == "windows" {
|
// if runtime.GOOS == "windows" {
|
||||||
// env = append(env, "GOTMPDIR="+pathname, "GOWORK="+pathname)
|
// env = append(env, "GOTMPDIR="+pathname, "GOWORK="+pathname)
|
||||||
// }
|
// }
|
||||||
// cmd1.Env = append(cmd1.Env, env...)
|
cmd1.Env = append(os.Environ(), env...)
|
||||||
// cmd2.Env = append(cmd2.Env, env...)
|
cmd2.Env = append(os.Environ(), env...)
|
||||||
// }
|
}
|
||||||
|
|
||||||
r, w := io.Pipe()
|
r, w := io.Pipe()
|
||||||
wClosed := false
|
wClosed := false
|
||||||
@ -843,7 +1041,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("tools for apigo.cloud", version)
|
fmt.Println("tools for apigo.cc/apigo", version)
|
||||||
fmt.Println("go sdk", goPath)
|
fmt.Println("go sdk", goPath)
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println("Usage:")
|
fmt.Println("Usage:")
|
||||||
@ -861,7 +1059,13 @@ func main() {
|
|||||||
}
|
}
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println("Examples:")
|
fmt.Println("Examples:")
|
||||||
fmt.Println(" ", u.Magenta("ag +"), " create a new simple project with Hello World")
|
fmt.Println(" ", u.Magenta("ag init"), " init a new default project")
|
||||||
fmt.Println(" ", u.Magenta("ag +p ali"), " create a new plugin project named ali for use aliyun services")
|
fmt.Println(" ", u.Magenta("ag init service"), " init a new service project")
|
||||||
|
fmt.Println(" ", u.Magenta("ag init client"), " init a new client project")
|
||||||
|
fmt.Println(" ", u.Magenta("ag init all"), " init a new project use all modules by apigo included")
|
||||||
|
fmt.Println(" ", u.Magenta("ag build"), " build project")
|
||||||
|
fmt.Println(" ", u.Magenta("ag build all"), " build project for all platforms")
|
||||||
|
fmt.Println(" ", u.Magenta("ag run"), " run project")
|
||||||
|
fmt.Println(" ", u.Magenta("ag test"), " test project")
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
}
|
}
|
||||||
|
9
templates/_cacheFiles.go
Normal file
9
templates/_cacheFiles.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/ssgo/u"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
{{- range .Files}}
|
||||||
|
u.LoadFilesToMemoryFromJson("{{.}}")
|
||||||
|
{{- end}}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
.*
|
.*
|
||||||
!.gitignore
|
!.gitignore
|
||||||
go.sum
|
go.sum
|
||||||
/build
|
build
|
||||||
/release
|
release
|
||||||
node_modules
|
node_modules
|
||||||
package.json
|
package.json
|
@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/ssgo/u"
|
"github.com/ssgo/u"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _mainFile = "{{.Main}}"
|
||||||
var appName = "{{.Name}}"
|
var appName = "{{.Name}}"
|
||||||
var appVersion = "{{.Version}}"
|
var appVersion = "{{.Version}}"
|
||||||
var idFixMatcher = regexp.MustCompile(`[^a-zA-Z0-9_]`)
|
var idFixMatcher = regexp.MustCompile(`[^a-zA-Z0-9_]`)
|
||||||
@ -33,6 +34,10 @@ func init() {
|
|||||||
{{- end}}
|
{{- end}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setSSKey(key, iv []byte) {
|
||||||
|
gojs.SetSSKey(key, iv)
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if appName == "" {
|
if appName == "" {
|
||||||
appName = filepath.Base(os.Args[0])
|
appName = filepath.Base(os.Args[0])
|
||||||
@ -43,111 +48,127 @@ func main() {
|
|||||||
appVersion = "0.0.1"
|
appVersion = "0.0.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
args := os.Args[1:]
|
cmd := ""
|
||||||
if len(args) > 0 {
|
id := ""
|
||||||
if args[0] == "help" || args[0] == "--help" || args[0] == "-h" {
|
mainFile := _mainFile
|
||||||
|
isWatch := false
|
||||||
|
startArgs := make([]string, 0)
|
||||||
|
mainArgs := make([]any, 0)
|
||||||
|
for i := 1; i < len(os.Args); i++ {
|
||||||
|
arg := os.Args[i]
|
||||||
|
switch arg {
|
||||||
|
case "--help", "-help", "-h":
|
||||||
printUsage()
|
printUsage()
|
||||||
return
|
return
|
||||||
}
|
case "--version", "-version", "-v":
|
||||||
|
|
||||||
if args[0] == "version" || args[0] == "--version" || args[0] == "-v" {
|
|
||||||
fmt.Println(appName, appVersion)
|
fmt.Println(appName, appVersion)
|
||||||
return
|
return
|
||||||
|
case "--export", "-export":
|
||||||
|
fmt.Println(u.Cyan(gojs.ExportForDev()))
|
||||||
|
return
|
||||||
|
case "start", "stop", "restart", "reload", "test":
|
||||||
|
if len(mainArgs) == 0 && cmd == "" {
|
||||||
|
cmd = arg
|
||||||
|
} else {
|
||||||
|
mainArgs = append(mainArgs, arg)
|
||||||
|
}
|
||||||
|
case "--env", "-env", "-e":
|
||||||
|
i++
|
||||||
|
a := strings.SplitN(os.Args[i], "=", 2)
|
||||||
|
os.Setenv(a[0], a[1])
|
||||||
|
case "-id":
|
||||||
|
i++
|
||||||
|
id = strings.TrimSpace(os.Args[i])
|
||||||
|
case "-main":
|
||||||
|
i++
|
||||||
|
mainFile = strings.TrimSpace(os.Args[i])
|
||||||
|
startArgs = append(startArgs, "-main", mainFile)
|
||||||
|
case "-watch", "-w":
|
||||||
|
isWatch = true
|
||||||
|
startArgs = append(startArgs, arg)
|
||||||
|
default:
|
||||||
|
mainArgs = append(mainArgs, arg)
|
||||||
|
startArgs = append(startArgs, arg)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if args[0] == "export" || args[0] == "-e" {
|
if cmd != "test" {
|
||||||
gojs.ExportForDev()
|
if !u.FileExists(mainFile) {
|
||||||
|
log.DefaultLogger.Error("main file not found", "mainFile", mainFile)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
if id == "" {
|
||||||
|
id = fmt.Sprintf("%s_%s_%s", appName, mainFile, appVersion)
|
||||||
cmd := ""
|
|
||||||
if len(args) > 0 && (args[0] == "start" || args[0] == "stop" || args[0] == "restart" || args[0] == "test") {
|
|
||||||
cmd = args[0]
|
|
||||||
args = args[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
id := ""
|
|
||||||
mainFile := "{{.Main}}"
|
|
||||||
isWatch := false
|
|
||||||
mainArgs := make([]any, 0)
|
|
||||||
for i := 0; i < len(args); i++ {
|
|
||||||
arg := args[i]
|
|
||||||
if strings.HasPrefix(arg, "-") {
|
|
||||||
switch arg[1:] {
|
|
||||||
case "id":
|
|
||||||
i++
|
|
||||||
strings.TrimSpace(args[i])
|
|
||||||
case "main":
|
|
||||||
i++
|
|
||||||
strings.TrimSpace(args[i])
|
|
||||||
case "w":
|
|
||||||
isWatch = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mainArgs = append(mainArgs, arg)
|
|
||||||
}
|
}
|
||||||
|
id = idFixMatcher.ReplaceAllString(id, "_")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !u.FileExists(mainFile) {
|
|
||||||
log.DefaultLogger.Error("main file not found", "mainFile", mainFile)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if id == "" {
|
|
||||||
id = fmt.Sprintf("%s_%s_%s", appName, mainFile, appVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
id = idFixMatcher.ReplaceAllString(id, "_")
|
|
||||||
homeDir, _ := os.UserHomeDir()
|
homeDir, _ := os.UserHomeDir()
|
||||||
pidFile := filepath.Join(homeDir, ".pids", id+".pid")
|
pidFile := filepath.Join(homeDir, ".pids", id+".pid")
|
||||||
pid := u.Int(u.ReadFileN(pidFile))
|
pid := u.Int(u.ReadFileN(pidFile))
|
||||||
fmt.Println(appName, appVersion, mainFile, id, pidFile, pid)
|
|
||||||
switch cmd {
|
switch cmd {
|
||||||
case "start":
|
case "start":
|
||||||
if pid > 0 && checkProcess(pid) {
|
if pid > 0 && processIsExists(pid) {
|
||||||
log.DefaultLogger.Info("process already started", "pid", pid)
|
log.DefaultLogger.Info("process already started", "pid", pid)
|
||||||
} else {
|
} else {
|
||||||
startProcess(pidFile, mainFile)
|
startProcess(pidFile, startArgs)
|
||||||
}
|
}
|
||||||
case "stop":
|
case "stop":
|
||||||
if pid > 0 {
|
if pid > 0 {
|
||||||
killProcess(pid, mainFile)
|
killProcess(pid, mainFile)
|
||||||
_ = os.Remove(pidFile)
|
_ = os.Remove(pidFile)
|
||||||
}
|
}
|
||||||
|
case "reload":
|
||||||
|
if pid > 0 {
|
||||||
|
kill(pid, syscall.Signal(0x1e))
|
||||||
|
}
|
||||||
case "restart":
|
case "restart":
|
||||||
if pid > 0 {
|
if pid > 0 {
|
||||||
killProcess(pid, mainFile)
|
killProcess(pid, mainFile)
|
||||||
_ = os.Remove(pidFile)
|
_ = os.Remove(pidFile)
|
||||||
}
|
}
|
||||||
startProcess(pidFile, mainFile)
|
startProcess(pidFile, startArgs)
|
||||||
case "test":
|
case "test":
|
||||||
if pid > 0 {
|
testPath := "."
|
||||||
killProcess(pid, mainFile)
|
if u.FileExists("tests") {
|
||||||
_ = os.Remove(pidFile)
|
testPath = "tests"
|
||||||
|
}
|
||||||
|
for _, f := range u.ReadDirN(testPath) {
|
||||||
|
if !f.IsDir && strings.HasSuffix(f.Name, "_test.js") {
|
||||||
|
if r, err := gojs.RunFile(f.FullName, mainArgs...); err != nil {
|
||||||
|
fmt.Println(u.BRed("test failed for "+f.FullName), err.Error())
|
||||||
|
} else {
|
||||||
|
fmt.Println(u.Green("test passed for "+f.FullName), r)
|
||||||
|
}
|
||||||
|
gojs.WaitAll()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
startProcess(pidFile, mainFile)
|
|
||||||
default:
|
default:
|
||||||
|
defer os.Remove(pidFile)
|
||||||
if isWatch {
|
if isWatch {
|
||||||
gojs.WatchRun(mainFile, mainArgs...)
|
gojs.WatchRun(mainFile, nil, nil, mainArgs...)
|
||||||
} else {
|
} else {
|
||||||
gojs.RunFile(mainFile, mainArgs...)
|
if r, err := gojs.RunFile(mainFile, mainArgs...); err != nil {
|
||||||
|
log.DefaultLogger.Error("run failed for "+mainFile, "err", err.Error())
|
||||||
|
} else if r != nil {
|
||||||
|
log.DefaultLogger.Error("run "+mainFile, "result", r)
|
||||||
|
}
|
||||||
gojs.WaitAll()
|
gojs.WaitAll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func startProcess(pidFile string, mainFile string) {
|
func startProcess(pidFile string, startArgs []string) {
|
||||||
var cmd *exec.Cmd
|
cmd := exec.Command(os.Args[0], startArgs...)
|
||||||
cmd = exec.Command(os.Args[0], "-main", mainFile)
|
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
if err := cmd.Start(); err == nil {
|
if err := cmd.Start(); err == nil {
|
||||||
u.WriteFile(pidFile, u.String(cmd.Process.Pid))
|
u.WriteFile(pidFile, u.String(cmd.Process.Pid))
|
||||||
log.DefaultLogger.Info("started", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", cmd.Process.Pid)
|
log.DefaultLogger.Info("started", "appName", appName, "appVersion", appVersion, "startArgs", startArgs, "pid", cmd.Process.Pid)
|
||||||
} else {
|
} else {
|
||||||
log.DefaultLogger.Error("start failed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "err", err)
|
log.DefaultLogger.Error("start failed", "appName", appName, "appVersion", appVersion, "startArgs", startArgs, "err", err)
|
||||||
}
|
}
|
||||||
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func kill(pid int, sig os.Signal) error {
|
func kill(pid int, sig os.Signal) error {
|
||||||
@ -163,14 +184,14 @@ func killProcess(pid int, mainFile string) {
|
|||||||
log.DefaultLogger.Info("killing", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid)
|
log.DefaultLogger.Info("killing", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid)
|
||||||
t1 := time.Now().UnixMilli()
|
t1 := time.Now().UnixMilli()
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
if !checkProcess(pid) {
|
if !processIsExists(pid) {
|
||||||
log.DefaultLogger.Info("killed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid, "usedTime", (time.Duration(time.Now().UnixMilli()-t1) * time.Millisecond).String())
|
log.DefaultLogger.Info("killed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid, "usedTime", (time.Duration(time.Now().UnixMilli()-t1) * time.Millisecond).String())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
}
|
}
|
||||||
err := kill(pid, syscall.SIGKILL)
|
err := kill(pid, syscall.SIGKILL)
|
||||||
if checkProcess(pid) {
|
if processIsExists(pid) {
|
||||||
log.DefaultLogger.Error("fource kill failed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid, "err", err)
|
log.DefaultLogger.Error("fource kill failed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid, "err", err)
|
||||||
} else {
|
} else {
|
||||||
log.DefaultLogger.Info("fource killed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid)
|
log.DefaultLogger.Info("fource killed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid)
|
||||||
@ -178,20 +199,26 @@ func killProcess(pid int, mainFile string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkProcess(pid int) bool {
|
func processIsExists(pid int) bool {
|
||||||
// return kill(pid, 0) == nil
|
if proc, err := os.FindProcess(pid); err == nil {
|
||||||
_, err := os.FindProcess(pid)
|
if err2 := proc.Signal(syscall.Signal(0)); err2 == nil {
|
||||||
return err == nil
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func printUsage() {
|
func printUsage() {
|
||||||
fmt.Println(appName, appVersion)
|
fmt.Println(appName, appVersion)
|
||||||
fmt.Println("Usage:")
|
fmt.Println("Usage:")
|
||||||
fmt.Println(" ", appName, "[-main mainFile] ...", "run script")
|
fmt.Println(" ", appName, "[-main mainFile] ...", "run script")
|
||||||
fmt.Println(" ", appName, "version", "- show version")
|
fmt.Println(" ", appName, "-version|-v", "show version")
|
||||||
fmt.Println(" ", appName, "export", "- export for development")
|
fmt.Println(" ", appName, "-export", "export for development")
|
||||||
|
fmt.Println(" ", appName, "-env|-e", "set env")
|
||||||
fmt.Println(" ", appName, "start [-id id] [-main mainFile]", "start server")
|
fmt.Println(" ", appName, "start [-id id] [-main mainFile]", "start server")
|
||||||
fmt.Println(" ", appName, "stop [-id id]", "stop server")
|
fmt.Println(" ", appName, "stop [-id id]", "stop server")
|
||||||
fmt.Println(" ", appName, "restart [-id id] [-main mainFile]", "restart server")
|
fmt.Println(" ", appName, "restart [-id id] [-main mainFile]", "restart server")
|
||||||
|
fmt.Println(" ", appName, "reload [-id id] [-main mainFile]", "reload config")
|
||||||
|
fmt.Println(" ", appName, "test", "test *_test.js")
|
||||||
fmt.Println(" ", appName, "help", "- show help")
|
fmt.Println(" ", appName, "help", "- show help")
|
||||||
}
|
}
|
||||||
|
4
tests/.gitignore
vendored
4
tests/.gitignore
vendored
@ -1,7 +1,7 @@
|
|||||||
.*
|
.*
|
||||||
!.gitignore
|
!.gitignore
|
||||||
go.sum
|
go.sum
|
||||||
/dist
|
build
|
||||||
/build*
|
release
|
||||||
node_modules
|
node_modules
|
||||||
package.json
|
package.json
|
@ -21,4 +21,15 @@ extraimport:
|
|||||||
apigo.cc/ai/llm/zhipu: latest
|
apigo.cc/ai/llm/zhipu: latest
|
||||||
modernc.org/sqlite: latest
|
modernc.org/sqlite: latest
|
||||||
cachefile:
|
cachefile:
|
||||||
- main.js
|
sskey: test
|
||||||
|
cgoenable: false
|
||||||
|
buildfrom: apigocc/gobuild
|
||||||
|
buildenv:
|
||||||
|
linux:
|
||||||
|
darwin:
|
||||||
|
windows:
|
||||||
|
- CGO_CPPFLAGS="-I%cd%include"
|
||||||
|
buildldflags:
|
||||||
|
linux:
|
||||||
|
darwin:
|
||||||
|
windows:
|
||||||
|
1
tests/cctools-port
Submodule
1
tests/cctools-port
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit a2724f04cafe3590fbc3d0beacc37293d83a2177
|
@ -0,0 +1,8 @@
|
|||||||
|
import cli from 'client'
|
||||||
|
|
||||||
|
let w = cli.open({
|
||||||
|
title: 'Hello',
|
||||||
|
html: '<div>Hello999</div>',
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
})
|
11
tests/go.mod
11
tests/go.mod
@ -3,9 +3,9 @@ module tests
|
|||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
apigo.cc/ai/llm v0.0.1
|
apigo.cc/ai/llm v0.0.2
|
||||||
apigo.cc/gojs v0.0.2
|
apigo.cc/gojs v0.0.3
|
||||||
apigo.cc/gojs/client v0.0.0-20241013151255-35c2a0f3cf99
|
apigo.cc/gojs/client v0.0.1
|
||||||
apigo.cc/gojs/console v0.0.1
|
apigo.cc/gojs/console v0.0.1
|
||||||
apigo.cc/gojs/db v0.0.1
|
apigo.cc/gojs/db v0.0.1
|
||||||
apigo.cc/gojs/file v0.0.1
|
apigo.cc/gojs/file v0.0.1
|
||||||
@ -14,13 +14,11 @@ require (
|
|||||||
apigo.cc/gojs/service v0.0.1
|
apigo.cc/gojs/service v0.0.1
|
||||||
apigo.cc/gojs/util v0.0.2
|
apigo.cc/gojs/util v0.0.2
|
||||||
github.com/ssgo/log v1.7.7
|
github.com/ssgo/log v1.7.7
|
||||||
github.com/ssgo/s v1.7.17
|
|
||||||
github.com/ssgo/u v1.7.9
|
github.com/ssgo/u v1.7.9
|
||||||
modernc.org/sqlite v1.33.1
|
modernc.org/sqlite v1.33.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
apigo.cc/apigo/gojs v0.1.1 // indirect
|
|
||||||
filippo.io/edwards25519 v1.1.0 // indirect
|
filippo.io/edwards25519 v1.1.0 // indirect
|
||||||
github.com/dlclark/regexp2 v1.11.4 // indirect
|
github.com/dlclark/regexp2 v1.11.4 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
@ -50,6 +48,7 @@ require (
|
|||||||
github.com/ssgo/discover v1.7.9 // indirect
|
github.com/ssgo/discover v1.7.9 // indirect
|
||||||
github.com/ssgo/httpclient v1.7.8 // indirect
|
github.com/ssgo/httpclient v1.7.8 // indirect
|
||||||
github.com/ssgo/redis v1.7.7 // indirect
|
github.com/ssgo/redis v1.7.7 // indirect
|
||||||
|
github.com/ssgo/s v1.7.17 // indirect
|
||||||
github.com/ssgo/standard v1.7.7 // indirect
|
github.com/ssgo/standard v1.7.7 // indirect
|
||||||
github.com/ssgo/tool v0.4.27 // indirect
|
github.com/ssgo/tool v0.4.27 // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
||||||
@ -68,5 +67,3 @@ require (
|
|||||||
modernc.org/strutil v1.2.0 // indirect
|
modernc.org/strutil v1.2.0 // indirect
|
||||||
modernc.org/token v1.1.0 // indirect
|
modernc.org/token v1.1.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace apigo.cc/gojs v0.0.2 => ../../../gojs/gojs
|
|
||||||
|
25
tests/include/EventToken.h
Normal file
25
tests/include/EventToken.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef WEBVIEW_COMPAT_EVENTTOKEN_H
|
||||||
|
#define WEBVIEW_COMPAT_EVENTTOKEN_H
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
// This compatibility header provides types used by MS WebView2. This header can
|
||||||
|
// be used as an alternative to the "EventToken.h" header normally provided by
|
||||||
|
// the Windows SDK. Depending on the MinGW distribution, this header may not be
|
||||||
|
// present, or it may be present with the name "eventtoken.h". The letter casing
|
||||||
|
// matters when cross-compiling on a system with case-sensitive file names.
|
||||||
|
|
||||||
|
#ifndef __eventtoken_h__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include <cstdint>
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct EventRegistrationToken {
|
||||||
|
int64_t value;
|
||||||
|
} EventRegistrationToken;
|
||||||
|
#endif // __eventtoken_h__
|
||||||
|
|
||||||
|
#endif // _WIN32
|
||||||
|
#endif // WEBVIEW_COMPAT_EVENTTOKEN_H
|
174
tests/main.go
174
tests/main.go
@ -24,18 +24,17 @@ import (
|
|||||||
|
|
||||||
_ "apigo.cc/ai/llm/openai"
|
_ "apigo.cc/ai/llm/openai"
|
||||||
_ "apigo.cc/ai/llm/zhipu"
|
_ "apigo.cc/ai/llm/zhipu"
|
||||||
|
|
||||||
"github.com/ssgo/log"
|
"github.com/ssgo/log"
|
||||||
_ "github.com/ssgo/s"
|
|
||||||
"github.com/ssgo/u"
|
"github.com/ssgo/u"
|
||||||
_ "modernc.org/sqlite"
|
_ "modernc.org/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _mainFile = "main.js"
|
||||||
var appName = "tests"
|
var appName = "tests"
|
||||||
var appVersion = "v0.0.1"
|
var appVersion = "v0.0.1"
|
||||||
var idFixMatcher = regexp.MustCompile(`[^a-zA-Z0-9_]`)
|
var idFixMatcher = regexp.MustCompile(`[^a-zA-Z0-9_]`)
|
||||||
|
|
||||||
// TODO embed .CacheFiles
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
gojs.Alias("ai/llm", "apigo.cc/ai/llm")
|
gojs.Alias("ai/llm", "apigo.cc/ai/llm")
|
||||||
gojs.Alias("client", "apigo.cc/gojs/client")
|
gojs.Alias("client", "apigo.cc/gojs/client")
|
||||||
@ -48,6 +47,10 @@ func init() {
|
|||||||
gojs.Alias("util", "apigo.cc/gojs/util")
|
gojs.Alias("util", "apigo.cc/gojs/util")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setSSKey(key, iv []byte) {
|
||||||
|
gojs.SetSSKey(key, iv)
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if appName == "" {
|
if appName == "" {
|
||||||
appName = filepath.Base(os.Args[0])
|
appName = filepath.Base(os.Args[0])
|
||||||
@ -58,106 +61,129 @@ func main() {
|
|||||||
appVersion = "0.0.1"
|
appVersion = "0.0.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
args := os.Args[1:]
|
cmd := ""
|
||||||
if len(args) > 0 {
|
id := ""
|
||||||
if args[0] == "help" || args[0] == "--help" || args[0] == "-h" {
|
mainFile := _mainFile
|
||||||
|
isWatch := false
|
||||||
|
startArgs := make([]string, 0)
|
||||||
|
mainArgs := make([]any, 0)
|
||||||
|
for i := 1; i < len(os.Args); i++ {
|
||||||
|
arg := os.Args[i]
|
||||||
|
switch arg {
|
||||||
|
case "--help", "-help", "-h":
|
||||||
printUsage()
|
printUsage()
|
||||||
return
|
return
|
||||||
}
|
case "--version", "-version", "-v":
|
||||||
|
|
||||||
if args[0] == "version" || args[0] == "--version" || args[0] == "-v" {
|
|
||||||
fmt.Println(appName, appVersion)
|
fmt.Println(appName, appVersion)
|
||||||
return
|
return
|
||||||
|
case "--export", "-export":
|
||||||
|
fmt.Println(u.Cyan(gojs.ExportForDev()))
|
||||||
|
return
|
||||||
|
case "start", "stop", "restart", "reload", "test":
|
||||||
|
if len(mainArgs) == 0 && cmd == "" {
|
||||||
|
cmd = arg
|
||||||
|
} else {
|
||||||
|
mainArgs = append(mainArgs, arg)
|
||||||
|
}
|
||||||
|
case "--env", "-env", "-e":
|
||||||
|
i++
|
||||||
|
a := strings.SplitN(os.Args[i], "=", 2)
|
||||||
|
os.Setenv(a[0], a[1])
|
||||||
|
case "-id":
|
||||||
|
i++
|
||||||
|
id = strings.TrimSpace(os.Args[i])
|
||||||
|
case "-main":
|
||||||
|
i++
|
||||||
|
mainFile = strings.TrimSpace(os.Args[i])
|
||||||
|
startArgs = append(startArgs, "-main", mainFile)
|
||||||
|
case "-watch", "-w":
|
||||||
|
isWatch = true
|
||||||
|
startArgs = append(startArgs, arg)
|
||||||
|
default:
|
||||||
|
mainArgs = append(mainArgs, arg)
|
||||||
|
startArgs = append(startArgs, arg)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if args[0] == "export" || args[0] == "-e" {
|
if cmd != "test" {
|
||||||
gojs.ExportForDev()
|
if !u.FileExists(mainFile) {
|
||||||
|
log.DefaultLogger.Error("main file not found", "mainFile", mainFile)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if id == "" {
|
||||||
|
id = fmt.Sprintf("%s_%s_%s", appName, mainFile, appVersion)
|
||||||
|
}
|
||||||
|
id = idFixMatcher.ReplaceAllString(id, "_")
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := ""
|
|
||||||
if len(args) > 0 && (args[0] == "start" || args[0] == "stop" || args[0] == "restart") {
|
|
||||||
cmd = args[0]
|
|
||||||
args = args[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
id := ""
|
|
||||||
if len(args) > 1 && args[0] == "-id" {
|
|
||||||
id = strings.TrimSpace(args[1])
|
|
||||||
args = args[2:]
|
|
||||||
}
|
|
||||||
|
|
||||||
mainFile := "main.js"
|
|
||||||
if len(args) > 1 && args[0] == "-main" {
|
|
||||||
mainFile = strings.TrimSpace(args[1])
|
|
||||||
args = args[2:]
|
|
||||||
}
|
|
||||||
if !u.FileExists(mainFile) {
|
|
||||||
log.DefaultLogger.Error("main file not found", "mainFile", mainFile)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if id == "" {
|
|
||||||
id = fmt.Sprintf("%s_%s_%s", appName, mainFile, appVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
id = idFixMatcher.ReplaceAllString(id, "_")
|
|
||||||
homeDir, _ := os.UserHomeDir()
|
homeDir, _ := os.UserHomeDir()
|
||||||
pidFile := filepath.Join(homeDir, ".pids", id+".pid")
|
pidFile := filepath.Join(homeDir, ".pids", id+".pid")
|
||||||
pid := u.Int(u.ReadFileN(pidFile))
|
pid := u.Int(u.ReadFileN(pidFile))
|
||||||
fmt.Println(appName, appVersion, mainFile, id, pidFile, pid)
|
|
||||||
switch cmd {
|
switch cmd {
|
||||||
case "start":
|
case "start":
|
||||||
if pid > 0 && checkProcess(pid) {
|
if pid > 0 && processIsExists(pid) {
|
||||||
log.DefaultLogger.Info("process already started", "pid", pid)
|
log.DefaultLogger.Info("process already started", "pid", pid)
|
||||||
} else {
|
} else {
|
||||||
startProcess(pidFile, mainFile)
|
startProcess(pidFile, startArgs)
|
||||||
}
|
}
|
||||||
case "stop":
|
case "stop":
|
||||||
if pid > 0 {
|
if pid > 0 {
|
||||||
killProcess(pid, mainFile)
|
killProcess(pid, mainFile)
|
||||||
_ = os.Remove(pidFile)
|
_ = os.Remove(pidFile)
|
||||||
}
|
}
|
||||||
|
case "reload":
|
||||||
|
if pid > 0 {
|
||||||
|
kill(pid, syscall.Signal(0x1e))
|
||||||
|
}
|
||||||
case "restart":
|
case "restart":
|
||||||
if pid > 0 {
|
if pid > 0 {
|
||||||
killProcess(pid, mainFile)
|
killProcess(pid, mainFile)
|
||||||
_ = os.Remove(pidFile)
|
_ = os.Remove(pidFile)
|
||||||
}
|
}
|
||||||
startProcess(pidFile, mainFile)
|
startProcess(pidFile, startArgs)
|
||||||
|
case "test":
|
||||||
|
testPath := "."
|
||||||
|
if u.FileExists("tests") {
|
||||||
|
testPath = "tests"
|
||||||
|
}
|
||||||
|
for _, f := range u.ReadDirN(testPath) {
|
||||||
|
if !f.IsDir && strings.HasSuffix(f.Name, "_test.js") {
|
||||||
|
if r, err := gojs.RunFile(f.FullName, mainArgs...); err != nil {
|
||||||
|
fmt.Println(u.BRed("test failed for "+f.FullName), err.Error())
|
||||||
|
} else {
|
||||||
|
fmt.Println(u.Green("test passed for "+f.FullName), r)
|
||||||
|
}
|
||||||
|
gojs.WaitAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
gojs.RunFile(mainFile, u.ToInterfaceArray(args)...)
|
defer os.Remove(pidFile)
|
||||||
gojs.WaitAll()
|
if isWatch {
|
||||||
|
gojs.WatchRun(mainFile, nil, nil, mainArgs...)
|
||||||
|
} else {
|
||||||
|
if r, err := gojs.RunFile(mainFile, mainArgs...); err != nil {
|
||||||
|
log.DefaultLogger.Error("run failed for "+mainFile, "err", err.Error())
|
||||||
|
} else if r != nil {
|
||||||
|
log.DefaultLogger.Error("run "+mainFile, "result", r)
|
||||||
|
}
|
||||||
|
gojs.WaitAll()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func startProcess(pidFile string, mainFile string) {
|
func startProcess(pidFile string, startArgs []string) {
|
||||||
var cmd *exec.Cmd
|
cmd := exec.Command(os.Args[0], startArgs...)
|
||||||
cmd = exec.Command(os.Args[0], "-main", mainFile)
|
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
if err := cmd.Start(); err == nil {
|
if err := cmd.Start(); err == nil {
|
||||||
u.WriteFile(pidFile, u.String(cmd.Process.Pid))
|
u.WriteFile(pidFile, u.String(cmd.Process.Pid))
|
||||||
log.DefaultLogger.Info("started", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", cmd.Process.Pid)
|
log.DefaultLogger.Info("started", "appName", appName, "appVersion", appVersion, "startArgs", startArgs, "pid", cmd.Process.Pid)
|
||||||
} else {
|
} else {
|
||||||
log.DefaultLogger.Error("start failed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "err", err)
|
log.DefaultLogger.Error("start failed", "appName", appName, "appVersion", appVersion, "startArgs", startArgs, "err", err)
|
||||||
}
|
}
|
||||||
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// func killProcess1(pid int) error {
|
|
||||||
// switch runtime.GOOS {
|
|
||||||
// case "windows":
|
|
||||||
// // Windows 系统使用 taskkill 命令
|
|
||||||
// cmd := exec.Command("taskkill", "/F", "/PID", fmt.Sprintf("%d", pid))
|
|
||||||
// return cmd.Run()
|
|
||||||
// case "linux", "darwin":
|
|
||||||
// // Linux 和 macOS 系统使用 syscall.Kill
|
|
||||||
// return syscall.Kill(pid, syscall.SIGKILL)
|
|
||||||
// default:
|
|
||||||
// return fmt.Errorf("unsupported platform")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
func kill(pid int, sig os.Signal) error {
|
func kill(pid int, sig os.Signal) error {
|
||||||
if proc, err := os.FindProcess(pid); err == nil {
|
if proc, err := os.FindProcess(pid); err == nil {
|
||||||
return proc.Signal(sig)
|
return proc.Signal(sig)
|
||||||
@ -171,14 +197,14 @@ func killProcess(pid int, mainFile string) {
|
|||||||
log.DefaultLogger.Info("killing", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid)
|
log.DefaultLogger.Info("killing", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid)
|
||||||
t1 := time.Now().UnixMilli()
|
t1 := time.Now().UnixMilli()
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
if !checkProcess(pid) {
|
if !processIsExists(pid) {
|
||||||
log.DefaultLogger.Info("killed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid, "usedTime", (time.Duration(time.Now().UnixMilli()-t1) * time.Millisecond).String())
|
log.DefaultLogger.Info("killed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid, "usedTime", (time.Duration(time.Now().UnixMilli()-t1) * time.Millisecond).String())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
}
|
}
|
||||||
err := kill(pid, syscall.SIGKILL)
|
err := kill(pid, syscall.SIGKILL)
|
||||||
if checkProcess(pid) {
|
if processIsExists(pid) {
|
||||||
log.DefaultLogger.Error("fource kill failed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid, "err", err)
|
log.DefaultLogger.Error("fource kill failed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid, "err", err)
|
||||||
} else {
|
} else {
|
||||||
log.DefaultLogger.Info("fource killed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid)
|
log.DefaultLogger.Info("fource killed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid)
|
||||||
@ -186,20 +212,26 @@ func killProcess(pid int, mainFile string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkProcess(pid int) bool {
|
func processIsExists(pid int) bool {
|
||||||
// return kill(pid, 0) == nil
|
if proc, err := os.FindProcess(pid); err == nil {
|
||||||
_, err := os.FindProcess(pid)
|
if err2 := proc.Signal(syscall.Signal(0)); err2 == nil {
|
||||||
return err == nil
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func printUsage() {
|
func printUsage() {
|
||||||
fmt.Println(appName, appVersion)
|
fmt.Println(appName, appVersion)
|
||||||
fmt.Println("Usage:")
|
fmt.Println("Usage:")
|
||||||
fmt.Println(" ", appName, "[-main mainFile] ...", "run script")
|
fmt.Println(" ", appName, "[-main mainFile] ...", "run script")
|
||||||
fmt.Println(" ", appName, "version", "- show version")
|
fmt.Println(" ", appName, "-version|-v", "show version")
|
||||||
fmt.Println(" ", appName, "export", "- export for development")
|
fmt.Println(" ", appName, "-export", "export for development")
|
||||||
|
fmt.Println(" ", appName, "-env|-e", "set env")
|
||||||
fmt.Println(" ", appName, "start [-id id] [-main mainFile]", "start server")
|
fmt.Println(" ", appName, "start [-id id] [-main mainFile]", "start server")
|
||||||
fmt.Println(" ", appName, "stop [-id id]", "stop server")
|
fmt.Println(" ", appName, "stop [-id id]", "stop server")
|
||||||
fmt.Println(" ", appName, "restart [-id id] [-main mainFile]", "restart server")
|
fmt.Println(" ", appName, "restart [-id id] [-main mainFile]", "restart server")
|
||||||
|
fmt.Println(" ", appName, "reload [-id id] [-main mainFile]", "reload config")
|
||||||
|
fmt.Println(" ", appName, "test", "test *_test.js")
|
||||||
fmt.Println(" ", appName, "help", "- show help")
|
fmt.Println(" ", appName, "help", "- show help")
|
||||||
}
|
}
|
||||||
|
8
tests/main.js
Normal file
8
tests/main.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import cli from 'client'
|
||||||
|
|
||||||
|
let w = cli.open({
|
||||||
|
title: 'Hello',
|
||||||
|
html: '<div>Hello</div>',
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user