From 0cf1a553de559221284bf46c32013f7a1ac2e98e Mon Sep 17 00:00:00 2001 From: sun shengxiang Date: Sat, 6 Jul 2013 15:30:57 +0800 Subject: [PATCH 1/3] half work --- createapp.go | 1 + start.go | 24 +++++++---- util.go | 30 ++++++++++++++ watch.go | 113 +++++++++++++++++++++++++++++++++++---------------- 4 files changed, 125 insertions(+), 43 deletions(-) create mode 100644 util.go 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..8eb4d42 100644 --- a/start.go +++ b/start.go @@ -4,6 +4,7 @@ import ( "fmt" "os" path "path/filepath" + "runtime" ) var cmdStart = &Command{ @@ -32,22 +33,31 @@ 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() } + //go Start(args[0]) + //for { + // select { + // case <-restart: + // go Start(args[0]) + // case err := <-builderror: + // fmt.Println("build error:", err) + // } + //} } 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..e21e27b 100644 --- a/watch.go +++ b/watch.go @@ -1,27 +1,33 @@ package main import ( - "bytes" "fmt" "github.com/howeyc/fsnotify" - "io" + //"io" "log" "os" "os/exec" "runtime" + "sync" + "time" ) var ( builderror chan string restart chan bool cmd *exec.Cmd + state sync.Mutex + running bool ) func init() { builderror = make(chan string) - restart = make(chan bool) + //restart = make(chan bool) + running = false } +var eventTime = make(map[string]time.Time) + func NewWatcher(paths []string) { watcher, err := fsnotify.NewWatcher() if err != nil { @@ -32,8 +38,21 @@ func NewWatcher(paths []string) { for { select { case e := <-watcher.Event: - fmt.Println(e) - go Autobuild() + + isbuild := true + if t, ok := eventTime[e.String()]; ok { + //Debugf("%s pk %s", t, time.Now()) + if t.Add(time.Millisecond * 500).After(time.Now()) { + isbuild = false + } + } + Debugf("isbuild:%v", isbuild) + eventTime[e.String()] = time.Now() + + if isbuild { + fmt.Println(e) + go Autobuild() + } case err := <-watcher.Error: log.Fatal("error:", err) } @@ -64,23 +83,18 @@ func Autobuild() { } }() - fmt.Println("Autobuild") + fmt.Println("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() + builderror <- err.Error() + return } + Restart(appname) } func Kill() { @@ -90,31 +104,58 @@ func Kill() { } } +func Restart(appname string) { + Kill() + go Start() +} 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) - } + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + ch := Go(func() error { + state.Lock() + defer state.Unlock() + running = true + return cmd.Run() + }) for { - buf := make([]byte, 1024) - count, err := r.Read(buf) - if err != nil || count == 0 { - fmt.Println("process exit") - restart <- true + select { + case err := <-ch: + fmt.Println("cmd start error: ", err) + state.Lock() + defer state.Unlock() + running = false return - } else { - fmt.Println("result:", string(buf)) + case <-time.After(2 * time.Second): } } + + //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)) + // } + //} } From 9e602fd75f7f4a50a80c57a6e9168cc4bc962292 Mon Sep 17 00:00:00 2001 From: sun shengxiang Date: Sat, 6 Jul 2013 16:13:30 +0800 Subject: [PATCH 2/3] remove useless codes --- start.go | 9 ------ watch.go | 90 +++++++++++++++----------------------------------------- 2 files changed, 23 insertions(+), 76 deletions(-) diff --git a/start.go b/start.go index 8eb4d42..4e8acef 100644 --- a/start.go +++ b/start.go @@ -51,13 +51,4 @@ func startapp(cmd *Command, args []string) { for { runtime.Gosched() } - //go Start(args[0]) - //for { - // select { - // case <-restart: - // go Start(args[0]) - // case err := <-builderror: - // fmt.Println("build error:", err) - // } - //} } diff --git a/watch.go b/watch.go index e21e27b..ef581ad 100644 --- a/watch.go +++ b/watch.go @@ -3,7 +3,6 @@ package main import ( "fmt" "github.com/howeyc/fsnotify" - //"io" "log" "os" "os/exec" @@ -13,21 +12,12 @@ import ( ) var ( - builderror chan string - restart chan bool - cmd *exec.Cmd - state sync.Mutex - running bool + restart chan bool + cmd *exec.Cmd + state sync.Mutex + eventTime = make(map[string]time.Time) ) -func init() { - builderror = make(chan string) - //restart = make(chan bool) - running = false -} - -var eventTime = make(map[string]time.Time) - func NewWatcher(paths []string) { watcher, err := fsnotify.NewWatcher() if err != nil { @@ -38,15 +28,14 @@ func NewWatcher(paths []string) { for { select { case e := <-watcher.Event: - isbuild := true if t, ok := eventTime[e.String()]; ok { - //Debugf("%s pk %s", t, time.Now()) + // 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 } } - Debugf("isbuild:%v", isbuild) eventTime[e.String()] = time.Now() if isbuild { @@ -69,6 +58,8 @@ func NewWatcher(paths []string) { } func Autobuild() { + state.Lock() + defer state.Unlock() defer func() { if err := recover(); err != nil { str := "" @@ -79,35 +70,42 @@ func Autobuild() { } str = str + fmt.Sprintf("%v,%v", file, line) } - builderror <- str } }() - fmt.Println("autobuild") + fmt.Println("start autobuild") path, _ := os.Getwd() os.Chdir(path) bcmd := exec.Command("go", "build") bcmd.Stdout = os.Stdout bcmd.Stderr = os.Stderr err := bcmd.Run() + if err != nil { - builderror <- err.Error() + 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() + go Start(appname) } + func Start(appname string) { fmt.Println("start", appname) @@ -115,47 +113,5 @@ func Start(appname string) { cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - ch := Go(func() error { - state.Lock() - defer state.Unlock() - running = true - return cmd.Run() - }) - for { - select { - case err := <-ch: - fmt.Println("cmd start error: ", err) - state.Lock() - defer state.Unlock() - running = false - return - case <-time.After(2 * time.Second): - } - } - - //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)) - // } - //} + go cmd.Run() } From df0fb8595be358bec54604f9242d7cdbdc63eac9 Mon Sep 17 00:00:00 2001 From: ssx Date: Sat, 6 Jul 2013 16:23:35 +0800 Subject: [PATCH 3/3] remove useless codes again --- watch.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/watch.go b/watch.go index ef581ad..3188777 100644 --- a/watch.go +++ b/watch.go @@ -6,13 +6,11 @@ import ( "log" "os" "os/exec" - "runtime" "sync" "time" ) var ( - restart chan bool cmd *exec.Cmd state sync.Mutex eventTime = make(map[string]time.Time) @@ -60,19 +58,7 @@ func NewWatcher(paths []string) { func Autobuild() { state.Lock() defer state.Unlock() - 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) - } - } - }() fmt.Println("start autobuild") path, _ := os.Getwd() os.Chdir(path)