diff --git a/cmd/start.go b/cmd/start.go index 9cfb2b17..0aecbed3 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -129,13 +129,15 @@ var startCmd = &cobra.Command{ } - // start watching - if mode == "development" && !startDisableWatching { - // Watching - fmt.Println(color.WhiteString("\n---------------------------------")) - fmt.Println(color.WhiteString(L("Watching"))) - fmt.Println(color.WhiteString("---------------------------------")) - // service.Watch(config.Conf) + srv, err := service.Start(config.Conf) + defer func() { + service.Stop(srv) + fmt.Println(color.GreenString(L("✨EXITED✨"))) + }() + + if err != nil { + fmt.Println(color.RedString(L("Fatal: %s"), err.Error())) + os.Exit(1) } // print the messages under the production mode @@ -147,11 +149,15 @@ var startCmd = &cobra.Command{ printStores(true) } - srv, err := service.Start(config.Conf) - defer func() { - service.Stop(srv) - fmt.Println(color.GreenString(L("✨EXITED✨"))) - }() + // start watching + watchDone := make(chan uint8, 1) + if mode == "development" && !startDisableWatching { + // Watching + fmt.Println(color.WhiteString("\n---------------------------------")) + fmt.Println(color.WhiteString(L("Watching"))) + fmt.Println(color.WhiteString("---------------------------------")) + go service.Watch(srv, watchDone) + } for { select { @@ -170,6 +176,7 @@ var startCmd = &cobra.Command{ } case <-interrupt: + watchDone <- 1 return } } diff --git a/service/watch.go b/service/watch.go index 48a2f755..ac636a18 100644 --- a/service/watch.go +++ b/service/watch.go @@ -13,6 +13,8 @@ import ( "github.com/fatih/color" "github.com/fsnotify/fsnotify" + "github.com/yaoapp/gou/application" + "github.com/yaoapp/gou/server/http" "github.com/yaoapp/kun/log" "github.com/yaoapp/yao/config" "github.com/yaoapp/yao/engine" @@ -27,12 +29,41 @@ var handlers = map[string]func(root string, file string, event string, cfg confi } // Watch the application code change for hot update -func Watch(cfg config.Config) (err error) { - go func() { err = watchStart(cfg) }() - select { - case <-watchReady: - return nil +func Watch(srv *http.Server, interrupt chan uint8) (err error) { + + if application.App == nil { + return fmt.Errorf("Application is not initialized") } + + return application.App.Watch(func(event, name string) { + if strings.Contains(event, "CHMOD") { + return + } + + // Reload + err = engine.Reload(config.Conf) + if err != nil { + fmt.Println(color.RedString("[Watch] Reload: %s", err.Error())) + return + } + fmt.Println(color.GreenString("[Watch] Reload Completed")) + + // Model + if strings.HasPrefix(name, "/models") { + fmt.Println(color.GreenString("[Watch] Model: %s changed (Please run yao migrate manually)", name)) + } + + // Restart + if strings.HasPrefix(name, "/apis") { + err = srv.Restart() + if err != nil { + fmt.Println(color.RedString("[Watch] Restart: %s", err.Error())) + return + } + fmt.Println(color.GreenString("[Watch] Restart Completed")) + } + + }, interrupt) } // StopWatch stop watching the code change diff --git a/service/watch_test.go b/service/watch_test.go index aad54ec9..d62b7380 100644 --- a/service/watch_test.go +++ b/service/watch_test.go @@ -1,153 +1,31 @@ package service import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" "testing" "time" "github.com/yaoapp/yao/config" - "github.com/yaoapp/yao/share" + "github.com/yaoapp/yao/engine" ) func TestWatch(t *testing.T) { - - share.DBConnect(config.Conf.DB) - err := Watch(config.Conf) + err := engine.Load(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(config.Conf) - // 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) + srv, err := Start(config.Conf) if err != nil { t.Fatal(err) } - time.Sleep(1 * time.Second) -} + defer Stop(srv) -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) -} + done := make(chan uint8, 1) + go Watch(srv, done) -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) + select { + case <-time.After(200 * time.Millisecond): + done <- 1 + return } - 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) }