diff --git a/command/command.go b/command/command.go index 8e992a0..6fe6453 100644 --- a/command/command.go +++ b/command/command.go @@ -14,7 +14,7 @@ import ( type Command interface { String() string - Start(delay time.Duration) + Start(delay time.Duration, haveBuild bool) Terminate(wait time.Duration) } @@ -47,7 +47,7 @@ func (c *command) String() string { return fmt.Sprintf("%s %s", c.name, strings.Join(c.args, " ")) } -func (c *command) Start(delay time.Duration) { +func (c *command) Start(delay time.Duration, haveBuild bool) { time.Sleep(delay) // delay for a while to avoid start too frequently c.mutex.Lock() @@ -85,7 +85,11 @@ func (c *command) Start(delay time.Duration) { cmd.Wait() if cmd.ProcessState.Success() { - log.Println("- Done.") + if haveBuild { + log.Println("Restart application success!") + } else { + log.Println("Start application success!") + } } else { log.Println("- Terminated.") } diff --git a/command/empty.go b/command/empty.go index df37966..041f0d2 100644 --- a/command/empty.go +++ b/command/empty.go @@ -1,23 +1,27 @@ package command -import "time" +import ( + "time" +) -// An empty command is a command that do nothing type empty string func Empty() Command { return empty("Empty command") } -func (c empty) String() string { - return string(c) +func (e empty) String() string { + return string(e) } -func (c empty) Start(delay time.Duration) { +func (e empty) Start(delay time.Duration, haveBuild bool) { // Start an empty command just do nothing but delay for given duration <-time.After(delay) } -func (c empty) Terminate(wait time.Duration) { +func (e empty) Terminate(wait time.Duration) { // Terminate empty command just return immediately without any error } + +// ProcessState contains information about an exited process, +// available after a call to Wait or Run. diff --git a/main.go b/main.go index 024dc3a..2d3235b 100644 --- a/main.go +++ b/main.go @@ -4,10 +4,13 @@ package main import ( "github.com/shanzi/wu/command" "github.com/shanzi/wu/runner" + "log" "os" "os/signal" "path/filepath" + // "wu/command" + // "wu/runner" ) func init() { diff --git a/runner/runner.go b/runner/runner.go index b1e42c7..50bd5d8 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -6,6 +6,7 @@ import ( "log" "strings" "time" + // "wu/command" ) type Runner interface { @@ -51,10 +52,10 @@ func (r *runner) Start() { log.Fatal("Failed to initialize watcher:", err) } matched := match(changed, r.patterns) - log.Println("Start watching...") // Run the command once at initially - r.command.Start(200 * time.Millisecond) + haveBuild := false + r.command.Start(200*time.Millisecond, haveBuild) for fp := range matched { files := gather(fp, matched, 500*time.Millisecond) @@ -64,7 +65,8 @@ func (r *runner) Start() { log.Println("File changed:", strings.Join(files, ", ")) // Run new command - r.command.Start(200 * time.Millisecond) + haveBuild = true + r.command.Start(200*time.Millisecond, haveBuild) } } diff --git a/runner/utils.go b/runner/utils.go index 53409bd..4322333 100644 --- a/runner/utils.go +++ b/runner/utils.go @@ -2,6 +2,7 @@ package runner import ( "github.com/fsnotify/fsnotify" + "io/ioutil" "log" "os" "path/filepath" @@ -15,13 +16,6 @@ func watch(path string, abort <-chan struct{}) (<-chan string, error) { return nil, err } - for p := range list(path) { - err = watcher.Add(p) - if err != nil { - log.Printf("Failed to watch: %s, error: %s", p, err) - } - } - out := make(chan string) go func() { defer close(out) @@ -40,16 +34,36 @@ func watch(path string, abort <-chan struct{}) (<-chan string, error) { info, err := os.Stat(fp.Name) if err == nil && info.IsDir() { // Add newly created sub directories to watch list + log.Printf("Add newly diectory ( %s )\n", fp.Name) watcher.Add(fp.Name) } } - out <- fp.Name + + if fp.Op&fsnotify.Write == fsnotify.Write || fp.Op == fsnotify.Remove || fp.Op == fsnotify.Rename { + out <- fp.Name + } + case err := <-watcher.Errors: log.Println("Watch Error:", err) } } }() + // Start watch + { + var paths []string + currpath, _ := os.Getwd() + + readAppDirectories(currpath, &paths) + + log.Println("Start watching...") + + for _, dir := range paths { + watcher.Add(dir) + log.Printf("Directory( %s )\n", dir) + } + } + return out, nil } @@ -60,6 +74,13 @@ func match(in <-chan string, patterns []string) <-chan string { defer close(out) for fp := range in { info, err := os.Stat(fp) + + if os.IsNotExist(err) { + log.Printf("Dictory (%s) have been removed\n", fp) + log.Println("here=======here") + continue + } + if os.IsNotExist(err) || !info.IsDir() { _, fn := filepath.Split(fp) for _, p := range patterns { @@ -74,39 +95,6 @@ func match(in <-chan string, patterns []string) <-chan string { return out } -func list(root string) <-chan string { - out := make(chan string) - - info, err := os.Stat(root) - if err != nil { - log.Fatalf("Failed to visit %s, error: %s\n", root, err) - } - if !info.IsDir() { - go func() { - defer close(out) - out <- root - }() - - return out - } - - go func() { - defer close(out) - filepath.Walk(root, func(path string, info os.FileInfo, err error) error { - if info.IsDir() { - if err != nil { - log.Printf("Failed to visit directory: %s, error: %s", path, err) - return err - } - out <- path - } - return nil - }) - }() - - return out -} - // gather delays further operations for a while and gather // all changes happened in this period func gather(first string, changes <-chan string, delay time.Duration) []string { @@ -132,3 +120,28 @@ loop: sort.Strings(ret) return ret } + +func readAppDirectories(directory string, paths *[]string) { + fileInfos, err := ioutil.ReadDir(directory) + + if err != nil { + return + } + + haveDir := false + for _, fileinfo := range fileInfos { + if fileinfo.IsDir() == true && fileinfo.Name() != "." && fileinfo.Name() != ".git" { + readAppDirectories(directory+"/"+fileinfo.Name(), paths) + continue + } + + if haveDir { + continue + } + + if filepath.Ext(fileinfo.Name()) == ".go" { + *paths = append(*paths, directory) + haveDir = true + } + } +}