1
This commit is contained in:
commit
308a8afc62
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
.*
|
||||
!.gitignore
|
||||
go.sum
|
||||
build
|
||||
release
|
||||
node_modules
|
||||
package.json
|
46
README.md
Normal file
46
README.md
Normal file
@ -0,0 +1,46 @@
|
||||
# ag - tools for apigo.cc/gojs
|
||||
|
||||
## Install
|
||||
|
||||
```shell
|
||||
go install apigo.cc/ag@latest
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
tools for apigo.cc/gojs
|
||||
|
||||
Usage:
|
||||
ag [command] [...]
|
||||
ag [short command] [...]
|
||||
|
||||
Commands:
|
||||
init [i] [service|client] init a new project for empty dir
|
||||
build [b] [all|os arch] build project
|
||||
pack [p] [all|os arch] pack project
|
||||
run [r] [args...] run project
|
||||
buildrun [rr] [args...] build and run project
|
||||
watch [w] [args...] run and watch project
|
||||
buildwatch [ww] [args...] build and run and watch project
|
||||
test [t] [args...] test project
|
||||
buildtest [tt] [args...] build and test project
|
||||
tidy [td] tidy project, run go mod tidy
|
||||
check [ck] check go modules version
|
||||
export [e] export typescript code for dev
|
||||
tags [] show git tags
|
||||
add tag [t+] [version] add git tag and push, if no new tag specified will use last tag +1
|
||||
commit [c+] comment commit git repo and push, comment is need
|
||||
|
||||
Examples:
|
||||
ag init init a new default project
|
||||
ag init service init a new service project
|
||||
ag init client init a new client project
|
||||
ag init all init a new project use all modules by apigo.cc/ag/all included
|
||||
ag build build project
|
||||
ag build all build project for all platforms
|
||||
ag run run project
|
||||
ag test test project
|
||||
|
||||
```
|
||||
|
18
go.mod
Normal file
18
go.mod
Normal file
@ -0,0 +1,18 @@
|
||||
module apigo.cc/ag
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/ssgo/httpclient v1.7.8
|
||||
github.com/ssgo/tool v0.4.27
|
||||
github.com/ssgo/u v1.7.9
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/ssgo/config v1.7.7 // indirect
|
||||
github.com/ssgo/log v1.7.7 // indirect
|
||||
github.com/ssgo/standard v1.7.7 // indirect
|
||||
golang.org/x/net v0.30.0 // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
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}}
|
||||
}
|
7
templates/_gitignore
Normal file
7
templates/_gitignore
Normal file
@ -0,0 +1,7 @@
|
||||
.*
|
||||
!.gitignore
|
||||
go.sum
|
||||
build
|
||||
release
|
||||
node_modules
|
||||
package.json
|
224
templates/_main.go
Normal file
224
templates/_main.go
Normal file
@ -0,0 +1,224 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"apigo.cc/gojs"
|
||||
{{range $pkg, $ver := .Module}}
|
||||
_ "{{$pkg}}"
|
||||
{{- end}}
|
||||
{{range $pkg, $ver := .ExtraImport}}
|
||||
_ "{{$pkg}}"
|
||||
{{- end}}
|
||||
"github.com/ssgo/log"
|
||||
"github.com/ssgo/u"
|
||||
)
|
||||
|
||||
var _mainFile = "{{.Main}}"
|
||||
var appName = "{{.Name}}"
|
||||
var appVersion = "{{.Version}}"
|
||||
var idFixMatcher = regexp.MustCompile(`[^a-zA-Z0-9_]`)
|
||||
|
||||
// TODO embed .CacheFiles
|
||||
|
||||
func init() {
|
||||
{{- range $alias, $pkg := .ModuleAlias }}
|
||||
gojs.Alias("{{$alias}}", "{{$pkg}}")
|
||||
{{- end}}
|
||||
}
|
||||
|
||||
func setSSKey(key, iv []byte) {
|
||||
gojs.SetSSKey(key, iv)
|
||||
}
|
||||
|
||||
func main() {
|
||||
if appName == "" {
|
||||
appName = filepath.Base(os.Args[0])
|
||||
appName = strings.TrimSuffix(appName, ".exe")
|
||||
}
|
||||
|
||||
if appVersion == "" {
|
||||
appVersion = "0.0.1"
|
||||
}
|
||||
|
||||
cmd := ""
|
||||
id := ""
|
||||
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()
|
||||
return
|
||||
case "--version", "-version", "-v":
|
||||
fmt.Println(appName, appVersion)
|
||||
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 cmd != "test" {
|
||||
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()
|
||||
pidFile := filepath.Join(homeDir, ".pids", id+".pid")
|
||||
pid := u.Int(u.ReadFileN(pidFile))
|
||||
switch cmd {
|
||||
case "start":
|
||||
if pid > 0 && processIsExists(pid) {
|
||||
log.DefaultLogger.Info("process already started", "pid", pid)
|
||||
} else {
|
||||
startProcess(pidFile, startArgs)
|
||||
}
|
||||
case "stop":
|
||||
if pid > 0 {
|
||||
killProcess(pid, mainFile)
|
||||
_ = os.Remove(pidFile)
|
||||
}
|
||||
case "reload":
|
||||
if pid > 0 {
|
||||
kill(pid, syscall.Signal(0x1e))
|
||||
}
|
||||
case "restart":
|
||||
if pid > 0 {
|
||||
killProcess(pid, mainFile)
|
||||
_ = os.Remove(pidFile)
|
||||
}
|
||||
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:
|
||||
defer os.Remove(pidFile)
|
||||
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, startArgs []string) {
|
||||
cmd := exec.Command(os.Args[0], startArgs...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Start(); err == nil {
|
||||
u.WriteFile(pidFile, u.String(cmd.Process.Pid))
|
||||
log.DefaultLogger.Info("started", "appName", appName, "appVersion", appVersion, "startArgs", startArgs, "pid", cmd.Process.Pid)
|
||||
} else {
|
||||
log.DefaultLogger.Error("start failed", "appName", appName, "appVersion", appVersion, "startArgs", startArgs, "err", err)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func kill(pid int, sig os.Signal) error {
|
||||
if proc, err := os.FindProcess(pid); err == nil {
|
||||
return proc.Signal(sig)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func killProcess(pid int, mainFile string) {
|
||||
if err := kill(pid, syscall.SIGTERM); err == nil {
|
||||
log.DefaultLogger.Info("killing", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid)
|
||||
t1 := time.Now().UnixMilli()
|
||||
for i := 0; i < 100; i++ {
|
||||
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())
|
||||
return
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
err := kill(pid, syscall.SIGKILL)
|
||||
if processIsExists(pid) {
|
||||
log.DefaultLogger.Error("fource kill failed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid, "err", err)
|
||||
} else {
|
||||
log.DefaultLogger.Info("fource killed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func processIsExists(pid int) bool {
|
||||
if proc, err := os.FindProcess(pid); err == nil {
|
||||
if err2 := proc.Signal(syscall.Signal(0)); err2 == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func printUsage() {
|
||||
fmt.Println(appName, appVersion)
|
||||
fmt.Println("Usage:")
|
||||
fmt.Println(" ", appName, "[-main mainFile] ...", "run script")
|
||||
fmt.Println(" ", appName, "-version|-v", "show version")
|
||||
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, "stop [-id id]", "stop 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")
|
||||
}
|
35
tests/apigo.yml
Normal file
35
tests/apigo.yml
Normal file
@ -0,0 +1,35 @@
|
||||
name:
|
||||
version: v0.0.1
|
||||
main: main.js
|
||||
target:
|
||||
darwin: amd64 arm64
|
||||
linux: amd64 arm64
|
||||
windows: amd64
|
||||
module:
|
||||
apigo.cc/gojs/console: latest
|
||||
apigo.cc/gojs/util: latest
|
||||
apigo.cc/gojs/log: latest
|
||||
apigo.cc/gojs/file: latest
|
||||
apigo.cc/gojs/http: latest
|
||||
apigo.cc/gojs/db: latest
|
||||
apigo.cc/gojs/client: latest
|
||||
apigo.cc/gojs/service: latest
|
||||
apigo.cc/ai/llm: latest
|
||||
modulealias:
|
||||
extraimport:
|
||||
apigo.cc/ai/llm/openai: latest
|
||||
apigo.cc/ai/llm/zhipu: latest
|
||||
modernc.org/sqlite: latest
|
||||
cachefile:
|
||||
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
|
8
tests/client_test.js
Normal file
8
tests/client_test.js
Normal file
@ -0,0 +1,8 @@
|
||||
import cli from 'client'
|
||||
|
||||
let w = cli.open({
|
||||
title: 'Hello',
|
||||
html: '<div>Hello999</div>',
|
||||
width: 800,
|
||||
height: 600,
|
||||
})
|
69
tests/go.mod
Normal file
69
tests/go.mod
Normal file
@ -0,0 +1,69 @@
|
||||
module tests
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
apigo.cc/ai/llm v0.0.2
|
||||
apigo.cc/gojs v0.0.3
|
||||
apigo.cc/gojs/client v0.0.1
|
||||
apigo.cc/gojs/console v0.0.1
|
||||
apigo.cc/gojs/db v0.0.1
|
||||
apigo.cc/gojs/file v0.0.1
|
||||
apigo.cc/gojs/http v0.0.3
|
||||
apigo.cc/gojs/log v0.0.1
|
||||
apigo.cc/gojs/service v0.0.1
|
||||
apigo.cc/gojs/util v0.0.2
|
||||
github.com/ssgo/log v1.7.7
|
||||
github.com/ssgo/u v1.7.9
|
||||
modernc.org/sqlite v1.33.1
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/dlclark/regexp2 v1.11.4 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-resty/resty/v2 v2.15.2 // indirect
|
||||
github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
|
||||
github.com/go-sql-driver/mysql v1.8.1 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
||||
github.com/gomodule/redigo v1.9.2 // indirect
|
||||
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/sashabaranov/go-openai v1.32.0 // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.24.5 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/ssgo/config v1.7.7 // indirect
|
||||
github.com/ssgo/dao v0.1.5 // indirect
|
||||
github.com/ssgo/db v1.7.9 // indirect
|
||||
github.com/ssgo/discover v1.7.9 // indirect
|
||||
github.com/ssgo/httpclient v1.7.8 // 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/tool v0.4.27 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
||||
github.com/tklauser/numcpus v0.8.0 // indirect
|
||||
github.com/webview/webview_go v0.0.0-20240831120633-6173450d4dd6 // indirect
|
||||
github.com/yankeguo/zhipu v0.1.2 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
golang.org/x/net v0.30.0 // indirect
|
||||
golang.org/x/sys v0.26.0 // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
|
||||
modernc.org/libc v1.55.3 // indirect
|
||||
modernc.org/mathutil v1.6.0 // indirect
|
||||
modernc.org/memory v1.8.0 // indirect
|
||||
modernc.org/strutil v1.2.0 // indirect
|
||||
modernc.org/token v1.1.0 // indirect
|
||||
)
|
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
|
237
tests/main.go
Normal file
237
tests/main.go
Normal file
@ -0,0 +1,237 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"apigo.cc/gojs"
|
||||
|
||||
_ "apigo.cc/ai/llm"
|
||||
_ "apigo.cc/gojs/client"
|
||||
_ "apigo.cc/gojs/console"
|
||||
_ "apigo.cc/gojs/db"
|
||||
_ "apigo.cc/gojs/file"
|
||||
_ "apigo.cc/gojs/http"
|
||||
_ "apigo.cc/gojs/log"
|
||||
_ "apigo.cc/gojs/service"
|
||||
_ "apigo.cc/gojs/util"
|
||||
|
||||
_ "apigo.cc/ai/llm/openai"
|
||||
_ "apigo.cc/ai/llm/zhipu"
|
||||
|
||||
"github.com/ssgo/log"
|
||||
"github.com/ssgo/u"
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
var _mainFile = "main.js"
|
||||
var appName = "tests"
|
||||
var appVersion = "v0.0.1"
|
||||
var idFixMatcher = regexp.MustCompile(`[^a-zA-Z0-9_]`)
|
||||
|
||||
func init() {
|
||||
gojs.Alias("ai/llm", "apigo.cc/ai/llm")
|
||||
gojs.Alias("client", "apigo.cc/gojs/client")
|
||||
gojs.Alias("console", "apigo.cc/gojs/console")
|
||||
gojs.Alias("db", "apigo.cc/gojs/db")
|
||||
gojs.Alias("file", "apigo.cc/gojs/file")
|
||||
gojs.Alias("http", "apigo.cc/gojs/http")
|
||||
gojs.Alias("log", "apigo.cc/gojs/log")
|
||||
gojs.Alias("service", "apigo.cc/gojs/service")
|
||||
gojs.Alias("util", "apigo.cc/gojs/util")
|
||||
}
|
||||
|
||||
func setSSKey(key, iv []byte) {
|
||||
gojs.SetSSKey(key, iv)
|
||||
}
|
||||
|
||||
func main() {
|
||||
if appName == "" {
|
||||
appName = filepath.Base(os.Args[0])
|
||||
appName = strings.TrimSuffix(appName, ".exe")
|
||||
}
|
||||
|
||||
if appVersion == "" {
|
||||
appVersion = "0.0.1"
|
||||
}
|
||||
|
||||
cmd := ""
|
||||
id := ""
|
||||
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()
|
||||
return
|
||||
case "--version", "-version", "-v":
|
||||
fmt.Println(appName, appVersion)
|
||||
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 cmd != "test" {
|
||||
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()
|
||||
pidFile := filepath.Join(homeDir, ".pids", id+".pid")
|
||||
pid := u.Int(u.ReadFileN(pidFile))
|
||||
switch cmd {
|
||||
case "start":
|
||||
if pid > 0 && processIsExists(pid) {
|
||||
log.DefaultLogger.Info("process already started", "pid", pid)
|
||||
} else {
|
||||
startProcess(pidFile, startArgs)
|
||||
}
|
||||
case "stop":
|
||||
if pid > 0 {
|
||||
killProcess(pid, mainFile)
|
||||
_ = os.Remove(pidFile)
|
||||
}
|
||||
case "reload":
|
||||
if pid > 0 {
|
||||
kill(pid, syscall.Signal(0x1e))
|
||||
}
|
||||
case "restart":
|
||||
if pid > 0 {
|
||||
killProcess(pid, mainFile)
|
||||
_ = os.Remove(pidFile)
|
||||
}
|
||||
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:
|
||||
defer os.Remove(pidFile)
|
||||
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, startArgs []string) {
|
||||
cmd := exec.Command(os.Args[0], startArgs...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Start(); err == nil {
|
||||
u.WriteFile(pidFile, u.String(cmd.Process.Pid))
|
||||
log.DefaultLogger.Info("started", "appName", appName, "appVersion", appVersion, "startArgs", startArgs, "pid", cmd.Process.Pid)
|
||||
} else {
|
||||
log.DefaultLogger.Error("start failed", "appName", appName, "appVersion", appVersion, "startArgs", startArgs, "err", err)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func kill(pid int, sig os.Signal) error {
|
||||
if proc, err := os.FindProcess(pid); err == nil {
|
||||
return proc.Signal(sig)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func killProcess(pid int, mainFile string) {
|
||||
if err := kill(pid, syscall.SIGTERM); err == nil {
|
||||
log.DefaultLogger.Info("killing", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid)
|
||||
t1 := time.Now().UnixMilli()
|
||||
for i := 0; i < 100; i++ {
|
||||
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())
|
||||
return
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
err := kill(pid, syscall.SIGKILL)
|
||||
if processIsExists(pid) {
|
||||
log.DefaultLogger.Error("fource kill failed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid, "err", err)
|
||||
} else {
|
||||
log.DefaultLogger.Info("fource killed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func processIsExists(pid int) bool {
|
||||
if proc, err := os.FindProcess(pid); err == nil {
|
||||
if err2 := proc.Signal(syscall.Signal(0)); err2 == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func printUsage() {
|
||||
fmt.Println(appName, appVersion)
|
||||
fmt.Println("Usage:")
|
||||
fmt.Println(" ", appName, "[-main mainFile] ...", "run script")
|
||||
fmt.Println(" ", appName, "-version|-v", "show version")
|
||||
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, "stop [-id id]", "stop 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")
|
||||
}
|
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