[change] Refactoring Watch
This commit is contained in:
parent
6283b6e34c
commit
7517e4652a
7 changed files with 391 additions and 407 deletions
|
|
@ -45,6 +45,7 @@ var langs = map[string]string{
|
||||||
"NEXT:": "下一步:",
|
"NEXT:": "下一步:",
|
||||||
"Listening": " 监听",
|
"Listening": " 监听",
|
||||||
"✨LISTENING✨": "✨服务正在运行✨",
|
"✨LISTENING✨": "✨服务正在运行✨",
|
||||||
|
"✨STOPPED✨": "✨服务已停止✨",
|
||||||
"SessionPort": "会话服务端口",
|
"SessionPort": "会话服务端口",
|
||||||
"Force migrate": "强制更新数据表结构",
|
"Force migrate": "强制更新数据表结构",
|
||||||
"Migrate is not allowed on production mode.": "Migrate 不能再生产环境下使用",
|
"Migrate is not allowed on production mode.": "Migrate 不能再生产环境下使用",
|
||||||
|
|
|
||||||
20
cmd/start.go
20
cmd/start.go
|
|
@ -3,8 +3,10 @@ package cmd
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
@ -24,6 +26,11 @@ var startCmd = &cobra.Command{
|
||||||
Short: L("Start Engine"),
|
Short: L("Start Engine"),
|
||||||
Long: L("Start Engine"),
|
Long: L("Start Engine"),
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
|
// recive interrupt signal
|
||||||
|
interrupt := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
|
||||||
|
|
||||||
// defer service.Stop(func() { fmt.Println(L("Service stopped")) })
|
// defer service.Stop(func() { fmt.Println(L("Service stopped")) })
|
||||||
Boot()
|
Boot()
|
||||||
|
|
||||||
|
|
@ -94,9 +101,18 @@ var startCmd = &cobra.Command{
|
||||||
if mode == "development" {
|
if mode == "development" {
|
||||||
service.Watch(config.Conf)
|
service.Watch(config.Conf)
|
||||||
}
|
}
|
||||||
|
go service.Start()
|
||||||
fmt.Println(color.GreenString(L("✨LISTENING✨")))
|
fmt.Println(color.GreenString(L("✨LISTENING✨")))
|
||||||
service.Start()
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-interrupt:
|
||||||
|
service.Stop(func() {
|
||||||
|
fmt.Println(color.GreenString(L("✨STOPPED✨")))
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
4
go.mod
4
go.mod
|
|
@ -8,7 +8,7 @@ require (
|
||||||
github.com/caarlos0/env/v6 v6.9.1
|
github.com/caarlos0/env/v6 v6.9.1
|
||||||
github.com/elazarl/go-bindata-assetfs v1.0.1
|
github.com/elazarl/go-bindata-assetfs v1.0.1
|
||||||
github.com/fatih/color v1.13.0
|
github.com/fatih/color v1.13.0
|
||||||
github.com/fsnotify/fsnotify v1.5.1
|
github.com/fsnotify/fsnotify v1.5.4
|
||||||
github.com/gin-gonic/gin v1.7.7
|
github.com/gin-gonic/gin v1.7.7
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
github.com/joho/godotenv v1.3.0
|
github.com/joho/godotenv v1.3.0
|
||||||
|
|
@ -63,6 +63,7 @@ require (
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/richardlehane/mscfb v1.0.3 // indirect
|
github.com/richardlehane/mscfb v1.0.3 // indirect
|
||||||
github.com/richardlehane/msoleps v1.0.1 // indirect
|
github.com/richardlehane/msoleps v1.0.1 // indirect
|
||||||
|
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||||
github.com/satori/go.uuid v1.2.0 // indirect
|
github.com/satori/go.uuid v1.2.0 // indirect
|
||||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
|
@ -76,7 +77,6 @@ require (
|
||||||
github.com/tidwall/rtred v0.1.2 // indirect
|
github.com/tidwall/rtred v0.1.2 // indirect
|
||||||
github.com/tidwall/tinyqueue v0.1.1 // indirect
|
github.com/tidwall/tinyqueue v0.1.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.1.7 // indirect
|
github.com/ugorji/go/codec v1.1.7 // indirect
|
||||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
|
||||||
github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 // indirect
|
github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 // indirect
|
||||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d // indirect
|
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d // indirect
|
||||||
golang.org/x/mod v0.4.2 // indirect
|
golang.org/x/mod v0.4.2 // indirect
|
||||||
|
|
|
||||||
4
go.sum
4
go.sum
|
|
@ -97,6 +97,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||||
|
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||||
|
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
|
|
@ -581,6 +583,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
|
@ -773,6 +776,7 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
|
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
|
||||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/yaoapp/gou"
|
"github.com/yaoapp/gou"
|
||||||
|
"github.com/yaoapp/kun/log"
|
||||||
"github.com/yaoapp/yao/config"
|
"github.com/yaoapp/yao/config"
|
||||||
"github.com/yaoapp/yao/share"
|
"github.com/yaoapp/yao/share"
|
||||||
)
|
)
|
||||||
|
|
@ -68,3 +71,16 @@ func Stop(onComplete func()) {
|
||||||
onComplete()
|
onComplete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StopWithContext stop with timeout
|
||||||
|
func StopWithContext(ctx context.Context, onComplete func()) {
|
||||||
|
shutdown <- true
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
log.Error("[STOP] canceled (%v)", ctx.Err())
|
||||||
|
onComplete()
|
||||||
|
case <-shutdownComplete:
|
||||||
|
share.SessionStop()
|
||||||
|
onComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
600
service/watch.go
600
service/watch.go
|
|
@ -1,459 +1,253 @@
|
||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
|
"github.com/fsnotify/fsnotify"
|
||||||
"github.com/yaoapp/gou"
|
"github.com/yaoapp/gou"
|
||||||
"github.com/yaoapp/yao/chart"
|
"github.com/yaoapp/kun/log"
|
||||||
"github.com/yaoapp/yao/config"
|
"github.com/yaoapp/yao/config"
|
||||||
"github.com/yaoapp/yao/engine"
|
"github.com/yaoapp/yao/engine"
|
||||||
"github.com/yaoapp/yao/page"
|
|
||||||
"github.com/yaoapp/yao/share"
|
"github.com/yaoapp/yao/share"
|
||||||
"github.com/yaoapp/yao/table"
|
|
||||||
"github.com/yaoapp/yao/workflow"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Watch 监听应用目录文件变更
|
var watchShutdown = make(chan bool, 1) // shutdown signal
|
||||||
func Watch(cfg config.Config) {
|
var watchReady = make(chan bool, 1) // ready signal
|
||||||
if os.Getenv("YAO_DEV") != "" {
|
var excludes = map[string]bool{"ui": true, "db": true, "data": true}
|
||||||
WatchEngine(filepath.Join(os.Getenv("YAO_DEV"), "/yao"))
|
var hanlders = map[string]func(root string, file string, event string, cfg config.Config){
|
||||||
}
|
"models": watchModel,
|
||||||
WatchModel(filepath.Join(cfg.Root, "models"), "")
|
|
||||||
WatchAPI(filepath.Join(cfg.Root, "apis"), "")
|
|
||||||
WatchFlow(filepath.Join(cfg.Root, "flows"), "")
|
|
||||||
WatchPlugin(filepath.Join(cfg.Root, "plugins"))
|
|
||||||
WatchTable(filepath.Join(cfg.Root, "tables"), "")
|
|
||||||
WatchChart(filepath.Join(cfg.Root, "charts"), "")
|
|
||||||
WatchPage(filepath.Join(cfg.Root, "pages"), "")
|
|
||||||
WatchWorkFlow(filepath.Join(cfg.Root, "workflows"), "")
|
|
||||||
|
|
||||||
// 看板大屏
|
|
||||||
WatchPage(filepath.Join(cfg.Root, "kanban"), "")
|
|
||||||
WatchPage(filepath.Join(cfg.Root, "screen"), "")
|
|
||||||
|
|
||||||
// 监听脚本 & libs更新
|
|
||||||
WatchGlobal(filepath.Join(cfg.Root, "libs"))
|
|
||||||
WatchGlobal(filepath.Join(cfg.Root, "scripts"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WatchEngine 监听监听引擎内建数据变更
|
// Watch the application code change for hot update
|
||||||
func WatchEngine(root string) {
|
func Watch(cfg config.Config) (err error) {
|
||||||
root = share.DirAbs(root)
|
go func() { err = watchStart(cfg) }()
|
||||||
WatchModel(filepath.Join(root, "models"), "xiang.")
|
select {
|
||||||
WatchAPI(filepath.Join(root, "apis"), "xiang.")
|
case <-watchReady:
|
||||||
WatchFlow(filepath.Join(root, "flows"), "xiang.")
|
return nil
|
||||||
WatchTable(filepath.Join(root, "tables"), "xiang.")
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WatchGlobal 监听通用程序更新
|
// StopWatch stop watching the code change
|
||||||
func WatchGlobal(root string) {
|
func StopWatch() {
|
||||||
if share.DirNotExists(root) {
|
watchShutdown <- true
|
||||||
return
|
time.Sleep(200 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func watchStart(cfg config.Config) error {
|
||||||
|
|
||||||
|
root := cfg.Root
|
||||||
|
|
||||||
|
// recive interrupt signal
|
||||||
|
interrupt := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
|
||||||
|
|
||||||
|
shutdown := make(chan bool, 1)
|
||||||
|
|
||||||
|
watcher, err := fsnotify.NewWatcher()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
root = share.DirAbs(root)
|
defer watcher.Close()
|
||||||
go share.Watch(root, func(op string, filename string) {
|
|
||||||
if !strings.HasSuffix(filename, ".json") && !strings.HasSuffix(filename, ".js") {
|
root, err = filepath.Abs(root)
|
||||||
return
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
dirs, err := ioutil.ReadDir(root)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add path
|
||||||
|
for _, dir := range dirs {
|
||||||
|
if !dir.IsDir() {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重启服务器
|
name := dir.Name()
|
||||||
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
if _, has := hanlders[name]; !has {
|
||||||
err := engine.Load(config.Conf)
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
filename := filepath.Join(root, name)
|
||||||
|
err := watcher.Add(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(color.GreenString("[Watch] Watching %s", name))
|
||||||
|
log.Info("[Watch] Watching: %s", filename)
|
||||||
|
|
||||||
|
// sub dir
|
||||||
|
err = filepath.WalkDir(filename, func(path string, d fs.DirEntry, err error) error {
|
||||||
|
if !d.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("[Watch] Watching: %s", path)
|
||||||
|
err = watcher.Add(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(color.RedString("Fatal: %s", err.Error()))
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
StopWithouttSession(func() {
|
return nil
|
||||||
fmt.Println(color.GreenString("Service Restarted"))
|
})
|
||||||
go StartWithouttSession()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// WatchModel 监听业务接口更新
|
if err != nil {
|
||||||
func WatchModel(root string, prefix string) {
|
return err
|
||||||
if share.DirNotExists(root) {
|
}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
root = share.DirAbs(root)
|
|
||||||
go share.Watch(root, func(op string, filename string) {
|
|
||||||
|
|
||||||
if !strings.HasSuffix(filename, ".json") {
|
// event hanlder
|
||||||
return
|
go func() {
|
||||||
}
|
for {
|
||||||
if op == "write" || op == "create" {
|
select {
|
||||||
name := prefix + share.SpecName(root, filename)
|
case <-shutdown:
|
||||||
content := share.ReadFile(filename)
|
log.Info("[Watch] The event handler exit")
|
||||||
_, err := gou.LoadModelReturn(string(content), name) // Reload
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(color.RedString("Fatal: %s", err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
|
||||||
fmt.Println(color.GreenString("Model %s Reloaded", name))
|
|
||||||
} else if op == "remove" || op == "rename" {
|
|
||||||
name := prefix + share.SpecName(root, filename)
|
|
||||||
if _, has := gou.Models[name]; has {
|
|
||||||
delete(gou.Models, name)
|
|
||||||
fmt.Println(color.RedString("Model %s Removed", name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// WatchAPI 监听业务接口更新
|
case event, ok := <-watcher.Events:
|
||||||
func WatchAPI(root string, prefix string) {
|
if !ok {
|
||||||
if share.DirNotExists(root) {
|
return
|
||||||
return
|
}
|
||||||
}
|
relpath := strings.TrimPrefix(event.Name, root)
|
||||||
root = share.DirAbs(root)
|
if strings.HasPrefix(relpath, string(os.PathSeparator)) {
|
||||||
go share.Watch(root, func(op string, filename string) {
|
relpath = strings.TrimPrefix(relpath, string(os.PathSeparator))
|
||||||
|
}
|
||||||
|
|
||||||
if !strings.HasSuffix(filename, ".json") {
|
pi := strings.Split(relpath, string(os.PathSeparator))
|
||||||
return
|
widget := pi[0]
|
||||||
}
|
|
||||||
|
|
||||||
if op == "write" || op == "create" {
|
watchHanler := watchReload
|
||||||
name := prefix + share.SpecName(root, filename)
|
if hanlder, has := hanlders[widget]; has {
|
||||||
content := share.ReadFile(filename)
|
watchHanler = hanlder
|
||||||
_, err := gou.LoadAPIReturn(string(content), name) // Reload
|
}
|
||||||
if err != nil {
|
|
||||||
fmt.Println(color.RedString("Fatal: %s", err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println(color.GreenString("API %s Reloaded", name))
|
|
||||||
|
|
||||||
} else if op == "remove" || op == "rename" {
|
if _, has := excludes[widget]; !has {
|
||||||
name := prefix + share.SpecName(root, filename)
|
base := filepath.Base(event.Name)
|
||||||
if _, has := gou.APIs[name]; has {
|
isdir := true
|
||||||
delete(gou.APIs, name)
|
if strings.HasSuffix(base, ".yao") || strings.HasSuffix(base, ".json") {
|
||||||
fmt.Println(color.RedString("API %s Removed", name))
|
isdir = false
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重启服务器
|
|
||||||
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
|
||||||
StopWithouttSession(func() {
|
|
||||||
fmt.Println(color.GreenString("Service Restarted"))
|
|
||||||
go StartWithouttSession()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// WatchFlow 监听业务逻辑变更
|
|
||||||
func WatchFlow(root string, prefix string) {
|
|
||||||
if share.DirNotExists(root) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
root = share.DirAbs(root)
|
|
||||||
go share.Watch(root, func(op string, filename string) {
|
|
||||||
if !strings.HasSuffix(filename, ".json") && !strings.HasSuffix(filename, ".js") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasSuffix(filename, ".js") {
|
|
||||||
name := prefix + share.SpecName(root, filename)
|
|
||||||
name = strings.ReplaceAll(name, ".", "/")
|
|
||||||
filename = filepath.Join(root, name+".flow.json")
|
|
||||||
}
|
|
||||||
|
|
||||||
if op == "write" || op == "create" {
|
|
||||||
name := prefix + share.SpecName(root, filename)
|
|
||||||
content := share.ReadFile(filename)
|
|
||||||
flow, err := gou.LoadFlowReturn(string(content), name) // Reload
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(color.RedString("Fatal: %s", err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if flow != nil { // Reload Script
|
|
||||||
dir := filepath.Dir(filename)
|
|
||||||
share.Walk(dir, ".js", func(root, filename string) {
|
|
||||||
script := share.ScriptName(filename)
|
|
||||||
content := share.ReadFile(filename)
|
|
||||||
_, err := flow.LoadScriptReturn(string(content), script)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(color.RedString("Fatal: %s", err.Error()))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(color.GreenString("Flow %s Reloaded", name))
|
events := strings.Split(event.Op.String(), "|")
|
||||||
|
for _, eventType := range events {
|
||||||
|
|
||||||
} else if op == "remove" || op == "rename" {
|
// ADD / REMOVE Watching dir
|
||||||
name := prefix + share.SpecName(root, filename)
|
if isdir {
|
||||||
if _, has := gou.Flows[name]; has {
|
switch eventType {
|
||||||
delete(gou.Flows, name)
|
case "CREATE":
|
||||||
fmt.Println(color.RedString("Flow %s Removed", name))
|
log.Info("[Watch] Watching: %s", event.Name)
|
||||||
}
|
watcher.Add(event.Name)
|
||||||
}
|
break
|
||||||
})
|
case "REMOVE":
|
||||||
}
|
log.Info("[Watch] Unwatching: %s", event.Name)
|
||||||
|
watcher.Remove(event.Name)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// WatchPlugin 监听业务插件变更
|
log.Info("[Watch] %s %s", eventType, event.Name)
|
||||||
func WatchPlugin(root string) {
|
watchHanler(root, event.Name, eventType, cfg)
|
||||||
if share.DirNotExists(root) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
root = share.DirAbs(root)
|
|
||||||
go share.Watch(root, func(op string, filename string) {
|
|
||||||
|
|
||||||
if !strings.HasSuffix(filename, ".so") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if op == "write" || op == "create" {
|
|
||||||
name := share.SpecName(root, filename)
|
|
||||||
_, err := gou.LoadPluginReturn(filename, name) // Reload
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(color.RedString("Fatal: %s", err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println(color.GreenString("Plugin %s Reloaded", name))
|
|
||||||
|
|
||||||
} else if op == "remove" || op == "rename" {
|
|
||||||
name := share.SpecName(root, filename)
|
|
||||||
if _, has := gou.Plugins[name]; has {
|
|
||||||
delete(gou.Plugins, name)
|
|
||||||
fmt.Println(color.RedString("Plugin %s Removed", name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// WatchTable 监听数据表格更新
|
|
||||||
func WatchTable(root string, prefix string) {
|
|
||||||
if share.DirNotExists(root) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
root = share.DirAbs(root)
|
|
||||||
go share.Watch(root, func(op string, filename string) {
|
|
||||||
|
|
||||||
if !strings.HasSuffix(filename, ".json") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if op == "write" || op == "create" {
|
|
||||||
name := prefix + share.SpecName(root, filename)
|
|
||||||
content := share.ReadFile(filename)
|
|
||||||
_, err := table.LoadTable(string(content), name) // Reload Table
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(color.RedString("Fatal: %s", err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
api, has := gou.APIs["xiang.table"]
|
|
||||||
if has {
|
|
||||||
_, err := gou.LoadAPIReturn(api.Source, api.Name)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(color.RedString("Fatal: %s", err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Println(color.GreenString("Table %s Reloaded", name))
|
|
||||||
|
|
||||||
} else if op == "remove" || op == "rename" {
|
|
||||||
name := prefix + share.SpecName(root, filename)
|
|
||||||
if _, has := table.Tables[name]; has {
|
|
||||||
delete(table.Tables, name)
|
|
||||||
fmt.Println(color.RedString("Table %s Removed", name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重启服务器
|
|
||||||
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
|
||||||
StopWithouttSession(func() {
|
|
||||||
fmt.Println(color.GreenString("Service Restarted"))
|
|
||||||
go StartWithouttSession()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// WatchChart 监听分析图表更新
|
|
||||||
func WatchChart(root string, prefix string) {
|
|
||||||
if share.DirNotExists(root) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
root = share.DirAbs(root)
|
|
||||||
go share.Watch(root, func(op string, filename string) {
|
|
||||||
if !strings.HasSuffix(filename, ".json") && !strings.HasSuffix(filename, ".js") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasSuffix(filename, ".js") {
|
|
||||||
name := prefix + share.SpecName(root, filename)
|
|
||||||
name = strings.ReplaceAll(name, ".", "/")
|
|
||||||
filename = filepath.Join(root, name+".chart.json")
|
|
||||||
}
|
|
||||||
|
|
||||||
if op == "write" || op == "create" {
|
|
||||||
name := prefix + share.SpecName(root, filename)
|
|
||||||
content := share.ReadFile(filename)
|
|
||||||
chart, err := chart.LoadChart(content, name) // Relaod
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(color.RedString("Fatal: %s", err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if chart != nil { // Reload Script
|
|
||||||
dir := filepath.Dir(filename)
|
|
||||||
share.Walk(dir, ".js", func(root, filename string) {
|
|
||||||
script := share.ScriptName(filename)
|
|
||||||
content := share.ReadFile(filename)
|
|
||||||
_, err := chart.LoadScriptReturn(string(content), script)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(color.RedString("Fatal: %s", err.Error()))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
break
|
||||||
|
|
||||||
api, has := gou.APIs["xiang.chart"]
|
case err, ok := <-watcher.Errors:
|
||||||
if has {
|
if !ok {
|
||||||
_, err := gou.LoadAPIReturn(api.Source, api.Name)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(color.RedString("Fatal: %s", err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
fmt.Println(color.RedString("[Watch] %s", err.Error()))
|
||||||
fmt.Println(color.GreenString("Chart %s Reloaded", name))
|
log.Error("[Watch] %s", err.Error())
|
||||||
|
break
|
||||||
} else if op == "remove" || op == "rename" {
|
|
||||||
name := prefix + share.SpecName(root, filename)
|
|
||||||
if _, has := chart.Charts[name]; has {
|
|
||||||
delete(chart.Charts, name)
|
|
||||||
fmt.Println(color.RedString("Chart %s Removed", name))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// 重启服务器
|
fmt.Println(color.GreenString("[Watch] Started"))
|
||||||
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
watchReady <- true
|
||||||
StopWithouttSession(func() {
|
|
||||||
fmt.Println(color.GreenString("Service Restarted"))
|
for {
|
||||||
go StartWithouttSession()
|
select {
|
||||||
})
|
case <-watchShutdown:
|
||||||
|
shutdown <- true
|
||||||
|
log.Info("[Watch] Stopped")
|
||||||
|
fmt.Println(color.YellowString("[Watch] Stopped"))
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case <-interrupt:
|
||||||
|
shutdown <- true
|
||||||
|
log.Info("[Watch] Stopped")
|
||||||
|
fmt.Println(color.YellowString("[Watch] Stopped"))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WatchPage 监听页面更新
|
func watchModel(root string, file string, event string, cfg config.Config) {
|
||||||
func WatchPage(root string, prefix string) {
|
name := share.SpecName(root, file)
|
||||||
if share.DirNotExists(root) {
|
switch event {
|
||||||
return
|
case "CREATE":
|
||||||
}
|
content, err := ioutil.ReadFile(file)
|
||||||
root = share.DirAbs(root)
|
if err != nil {
|
||||||
go share.Watch(root, func(op string, filename string) {
|
fmt.Println(color.RedString("[Watch] Model: %s %s", name, err.Error()))
|
||||||
if !strings.HasSuffix(filename, ".json") && !strings.HasSuffix(filename, ".js") {
|
return
|
||||||
|
}
|
||||||
|
mod, err := gou.LoadModelReturn(string(content), name)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(color.RedString("[Watch] Model: %s %s", name, err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasSuffix(filename, ".js") {
|
mod.Migrate(true)
|
||||||
name := prefix + share.SpecName(root, filename)
|
fmt.Println(color.GreenString("[Watch] Model: %s Created", name))
|
||||||
name = strings.ReplaceAll(name, ".", "/")
|
break
|
||||||
filename = filepath.Join(root, name+".page.json")
|
|
||||||
}
|
|
||||||
|
|
||||||
if op == "write" || op == "create" {
|
case "WRITE":
|
||||||
name := prefix + share.SpecName(root, filename)
|
content, err := ioutil.ReadFile(file)
|
||||||
content := share.ReadFile(filename)
|
if err != nil {
|
||||||
page, err := page.LoadPage(content, name) // Relaod
|
fmt.Println(color.RedString("[Watch] Model: %s %s", name, err.Error()))
|
||||||
if err != nil {
|
|
||||||
fmt.Println(color.RedString("Fatal: %s", err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if page != nil { // Reload Script
|
|
||||||
dir := filepath.Dir(filename)
|
|
||||||
share.Walk(dir, ".js", func(root, filename string) {
|
|
||||||
script := share.ScriptName(filename)
|
|
||||||
content := share.ReadFile(filename)
|
|
||||||
_, err := page.LoadScriptReturn(string(content), script)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(color.RedString("Fatal: %s", err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
api, has := gou.APIs["xiang.page"]
|
|
||||||
if has {
|
|
||||||
_, err := gou.LoadAPIReturn(api.Source, api.Name)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(color.RedString("Fatal: %s", err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Println(color.GreenString("Page %s Reloaded", name))
|
|
||||||
|
|
||||||
} else if op == "remove" || op == "rename" {
|
|
||||||
name := prefix + share.SpecName(root, filename)
|
|
||||||
if _, has := page.Pages[name]; has {
|
|
||||||
delete(page.Pages, name)
|
|
||||||
fmt.Println(color.RedString("Page %s Removed", name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重启服务器
|
|
||||||
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
|
||||||
StopWithouttSession(func() {
|
|
||||||
fmt.Println(color.GreenString("Service Restarted"))
|
|
||||||
go StartWithouttSession()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// WatchWorkFlow 监听工作流更新
|
|
||||||
func WatchWorkFlow(root string, prefix string) {
|
|
||||||
if share.DirNotExists(root) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
root = share.DirAbs(root)
|
|
||||||
go share.Watch(root, func(op string, filename string) {
|
|
||||||
if !strings.HasSuffix(filename, ".json") {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
mod, err := gou.LoadModelReturn(string(content), name)
|
||||||
if op == "write" || op == "create" {
|
if err != nil {
|
||||||
name := prefix + share.SpecName(root, filename)
|
fmt.Println(color.RedString("[Watch] Model: %s %s", name, err.Error()))
|
||||||
content := share.ReadFile(filename)
|
return
|
||||||
_, err := workflow.LoadWorkFlow(content, name) // Relaod
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(color.RedString("Fatal: %s", err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
api, has := gou.APIs["xiang.workflow."+name]
|
|
||||||
if has {
|
|
||||||
_, err := gou.LoadAPIReturn(api.Source, api.Name)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(color.RedString("Fatal: %s", err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Println(color.GreenString("Workflow %s Reloaded", name))
|
|
||||||
|
|
||||||
} else if op == "remove" || op == "rename" {
|
|
||||||
name := prefix + share.SpecName(root, filename)
|
|
||||||
if _, has := workflow.WorkFlows[name]; has {
|
|
||||||
delete(workflow.WorkFlows, name)
|
|
||||||
fmt.Println(color.RedString("Workflow %s Removed", name))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
mod.Migrate(false)
|
||||||
|
fmt.Println(color.GreenString("[Watch] Model: %s Reloaded", name))
|
||||||
|
break
|
||||||
|
|
||||||
// 重启服务器
|
case "REMOVE", "RENAME":
|
||||||
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
delete(gou.Models, name)
|
||||||
StopWithouttSession(func() {
|
fmt.Println(color.GreenString("[Watch] Model: %s Removed", name))
|
||||||
fmt.Println(color.GreenString("Service Restarted"))
|
break
|
||||||
go StartWithouttSession()
|
}
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
func watchReload(root string, file string, event string, cfg config.Config) {
|
||||||
|
err := engine.Load(config.Conf) // 加载脚本等
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(color.RedString("[Watch] Reload: %s", err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restart Server
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
StopWithContext(ctx, func() {
|
||||||
|
go Start()
|
||||||
|
fmt.Println(color.GreenString("[Watch] Reload Completed"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
153
service/watch_test.go
Normal file
153
service/watch_test.go
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/yaoapp/yao/config"
|
||||||
|
"github.com/yaoapp/yao/share"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWatch(t *testing.T) {
|
||||||
|
|
||||||
|
share.DBConnect(config.Conf.DB)
|
||||||
|
err := Watch(config.Conf)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer StopWatch()
|
||||||
|
|
||||||
|
createDir(t)
|
||||||
|
renameDir(t)
|
||||||
|
|
||||||
|
createModel(t)
|
||||||
|
changeModel(t)
|
||||||
|
renameModel(t)
|
||||||
|
removeModel(t)
|
||||||
|
|
||||||
|
createModel(t)
|
||||||
|
removeDir(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWatchReload(t *testing.T) {
|
||||||
|
go Start()
|
||||||
|
defer Stop(func() {})
|
||||||
|
share.DBConnect(config.Conf.DB)
|
||||||
|
watchReload("", "", "", config.Conf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createDir(t *testing.T) {
|
||||||
|
root := config.Conf.Root
|
||||||
|
file := filepath.Join(root, "models", "watch", "test")
|
||||||
|
fmt.Println("CREATE-DIR", file)
|
||||||
|
err := os.MkdirAll(file, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func renameDir(t *testing.T) {
|
||||||
|
root := config.Conf.Root
|
||||||
|
file := filepath.Join(root, "models", "watch", "test")
|
||||||
|
new := filepath.Join(root, "models", "watch", "test_new")
|
||||||
|
fmt.Println("RENAME-DIR", file)
|
||||||
|
err := os.Rename(file, new)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeDir(t *testing.T) {
|
||||||
|
root := config.Conf.Root
|
||||||
|
file := filepath.Join(root, "models", "watch")
|
||||||
|
fmt.Println("REMOVE-DIR", file)
|
||||||
|
err := os.RemoveAll(file)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createModel(t *testing.T) {
|
||||||
|
dsl := `
|
||||||
|
{
|
||||||
|
"name": "watch-test",
|
||||||
|
"table": {
|
||||||
|
"name": "watch_test",
|
||||||
|
"comment": "WatchTest",
|
||||||
|
"engine": "InnoDB"
|
||||||
|
},
|
||||||
|
"columns": [
|
||||||
|
{ "name": "id", "type": "ID" },
|
||||||
|
{ "label": "Name", "name": "name", "type": "string", "index": true }
|
||||||
|
],
|
||||||
|
"relations": {},
|
||||||
|
"option": { "timestamps": true, "soft_deletes": true }
|
||||||
|
}
|
||||||
|
`
|
||||||
|
root := config.Conf.Root
|
||||||
|
file := filepath.Join(root, "models", "watch", "test_new", "watch.mod.json")
|
||||||
|
fmt.Println("CREATE", file)
|
||||||
|
err := ioutil.WriteFile(file, []byte(dsl), 0644)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func changeModel(t *testing.T) {
|
||||||
|
dsl := `
|
||||||
|
{
|
||||||
|
"name": "watch-test",
|
||||||
|
"table": {
|
||||||
|
"name": "watch_test",
|
||||||
|
"comment": "WatchTest",
|
||||||
|
"engine": "InnoDB"
|
||||||
|
},
|
||||||
|
"columns": [
|
||||||
|
{ "name": "id", "type": "ID" },
|
||||||
|
{ "label": "Name", "name": "name", "type": "string", "index": true },
|
||||||
|
{ "label": "Data", "name": "data", "type": "json", "nullable": true }
|
||||||
|
],
|
||||||
|
"relations": {},
|
||||||
|
"option": { "timestamps": true, "soft_deletes": true }
|
||||||
|
}
|
||||||
|
`
|
||||||
|
root := config.Conf.Root
|
||||||
|
file := filepath.Join(root, "models", "watch", "test_new", "watch.mod.json")
|
||||||
|
fmt.Println("CHANGE", file)
|
||||||
|
err := ioutil.WriteFile(file, []byte(dsl), 0644)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func renameModel(t *testing.T) {
|
||||||
|
root := config.Conf.Root
|
||||||
|
file := filepath.Join(root, "models", "watch", "test_new", "watch.mod.json")
|
||||||
|
new := filepath.Join(root, "models", "watch", "test_new", "watch_new.mod.json")
|
||||||
|
fmt.Println("RENAME", new)
|
||||||
|
err := os.Rename(file, new)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeModel(t *testing.T) {
|
||||||
|
root := config.Conf.Root
|
||||||
|
file := filepath.Join(root, "models", "watch", "test_new", "watch_new.mod.json")
|
||||||
|
fmt.Println("REMOVE", file)
|
||||||
|
err := os.Remove(file)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue