diff --git a/createapp.go b/createapp.go index 176cc19..7c2fce9 100644 --- a/createapp.go +++ b/createapp.go @@ -45,6 +45,7 @@ func createapp(cmd *Command, args []string) { } gopath := os.Getenv("GOPATH") + Debugf("gopath:%s", gopath) if gopath == "" { fmt.Println("you should set GOPATH in the env") os.Exit(2) diff --git a/start.go b/start.go index de09dfa..4e8acef 100644 --- a/start.go +++ b/start.go @@ -4,6 +4,7 @@ import ( "fmt" "os" path "path/filepath" + "runtime" ) var cmdStart = &Command{ @@ -32,22 +33,22 @@ func init() { cmdStart.Run = startapp } +var appname string + func startapp(cmd *Command, args []string) { if len(args) != 1 { fmt.Println("error args") os.Exit(2) } crupath, _ := os.Getwd() + Debugf("current path:%s\n", crupath) + var paths []string paths = append(paths, path.Join(crupath, "controllers"), path.Join(crupath, "models")) NewWatcher(paths) - go Start(args[0]) + appname = args[0] + Autobuild() for { - select { - case <-restart: - go Start(args[0]) - case <-builderror: - fmt.Println("build error:", builderror) - } + runtime.Gosched() } } diff --git a/util.go b/util.go new file mode 100644 index 0000000..f8b7e13 --- /dev/null +++ b/util.go @@ -0,0 +1,30 @@ +package main + +import "fmt" +import "os" +import "runtime" +import "path/filepath" + +// Go is a basic promise implementation: it wraps calls a function in a goroutine +// and returns a channel which will later return the function's return value. +func Go(f func() error) chan error { + ch := make(chan error) + go func() { + ch <- f() + }() + return ch +} + +// if os.env DEBUG set, debug is on +func Debugf(format string, a ...interface{}) { + if os.Getenv("DEBUG") != "" { + _, file, line, ok := runtime.Caller(1) + if !ok { + file = "" + line = -1 + } else { + file = filepath.Base(file) + } + fmt.Fprintf(os.Stderr, fmt.Sprintf("[debug] %s:%d %s\n", file, line, format), a...) + } +} diff --git a/watch.go b/watch.go index 97a65f9..3188777 100644 --- a/watch.go +++ b/watch.go @@ -1,27 +1,21 @@ package main import ( - "bytes" "fmt" "github.com/howeyc/fsnotify" - "io" "log" "os" "os/exec" - "runtime" + "sync" + "time" ) var ( - builderror chan string - restart chan bool - cmd *exec.Cmd + cmd *exec.Cmd + state sync.Mutex + eventTime = make(map[string]time.Time) ) -func init() { - builderror = make(chan string) - restart = make(chan bool) -} - func NewWatcher(paths []string) { watcher, err := fsnotify.NewWatcher() if err != nil { @@ -32,8 +26,20 @@ func NewWatcher(paths []string) { for { select { case e := <-watcher.Event: - fmt.Println(e) - go Autobuild() + isbuild := true + if t, ok := eventTime[e.String()]; ok { + // if 500ms change many times, then ignore it. + // for liteide often gofmt code after save. + if t.Add(time.Millisecond * 500).After(time.Now()) { + isbuild = false + } + } + eventTime[e.String()] = time.Now() + + if isbuild { + fmt.Println(e) + go Autobuild() + } case err := <-watcher.Error: log.Fatal("error:", err) } @@ -50,71 +56,48 @@ func NewWatcher(paths []string) { } func Autobuild() { - defer func() { - if err := recover(); err != nil { - str := "" - for i := 1; ; i += 1 { - _, file, line, ok := runtime.Caller(i) - if !ok { - break - } - str = str + fmt.Sprintf("%v,%v", file, line) - } - builderror <- str + state.Lock() + defer state.Unlock() - } - }() - fmt.Println("Autobuild") + fmt.Println("start autobuild") path, _ := os.Getwd() os.Chdir(path) bcmd := exec.Command("go", "build") - var out bytes.Buffer - var berr bytes.Buffer - bcmd.Stdout = &out - bcmd.Stderr = &berr + bcmd.Stdout = os.Stdout + bcmd.Stderr = os.Stderr err := bcmd.Run() + if err != nil { - fmt.Println("run error", err) - } - if out.String() == "" { - Kill() - } else { - builderror <- berr.String() + fmt.Println("============== build failed ===================") + return } + fmt.Println("build success") + Restart(appname) } func Kill() { - err := cmd.Process.Kill() - if err != nil { - panic(err) + defer func() { + if e := recover(); e != nil { + fmt.Println("Kill -> ", e) + } + }() + if cmd != nil { + cmd.Process.Kill() } } +func Restart(appname string) { + Debugf("kill running process") + Kill() + go Start(appname) +} + func Start(appname string) { fmt.Println("start", appname) + cmd = exec.Command(appname) - stdout, err := cmd.StdoutPipe() - if err != nil { - fmt.Println("stdout:", err) - } - stderr, err := cmd.StderrPipe() - if err != nil { - fmt.Println("stdin:", err) - } - r := io.MultiReader(stdout, stderr) - err = cmd.Start() - if err != nil { - fmt.Println("cmd start:", err) - } - for { - buf := make([]byte, 1024) - count, err := r.Read(buf) - if err != nil || count == 0 { - fmt.Println("process exit") - restart <- true - return - } else { - fmt.Println("result:", string(buf)) - } - } + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + go cmd.Run() }