github.com/mattevans/edward@v1.9.2/runner/watch.go (about) 1 package runner 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 8 "github.com/mattevans/edward/home" 9 10 "github.com/pkg/errors" 11 "github.com/mattevans/edward/builder" 12 "github.com/mattevans/edward/services" 13 "github.com/mattevans/edward/tracker" 14 fsnotify "gopkg.in/fsnotify.v1" 15 ) 16 17 // BeginWatch starts auto-restart watches for the provided services. The function returned will close the 18 // watcher. 19 func BeginWatch(dirConfig *home.EdwardConfiguration, service services.ServiceOrGroup, restart func() error) (func(), error) { 20 watches, err := service.Watch() 21 if err != nil { 22 return nil, errors.WithStack(err) 23 } 24 if len(watches) == 0 { 25 return nil, nil 26 } 27 28 var watchers []*fsnotify.Watcher 29 for _, watch := range watches { 30 watcher, err := startWatch(dirConfig, &watch, restart) 31 if err != nil { 32 return nil, errors.WithStack(err) 33 } 34 watchers = append(watchers, watcher) 35 } 36 37 closeAll := func() { 38 log.Printf("Closing watchers") 39 for _, watch := range watchers { 40 watch.Close() 41 } 42 } 43 return closeAll, nil 44 } 45 46 func startWatch(dirConfig *home.EdwardConfiguration, watch *services.ServiceWatch, restart func() error) (*fsnotify.Watcher, error) { 47 watcher, err := fsnotify.NewWatcher() 48 if err != nil { 49 return nil, errors.WithStack(err) 50 } 51 52 go func() { 53 for event := range watcher.Events { 54 if event.Op == fsnotify.Write { 55 var wasExcluded bool 56 for _, excluded := range watch.ExcludedPaths { 57 if strings.HasPrefix(event.Name, excluded) { 58 log.Printf("File is under excluded path: %v\n", excluded) 59 wasExcluded = true 60 break 61 } 62 } 63 64 if wasExcluded { 65 continue 66 } 67 fmt.Printf("Rebuilding %v\n", watch.Service.GetName()) 68 err = rebuildService(dirConfig, watch.Service, restart) 69 if err != nil { 70 log.Printf("Could not rebuild %v: %v\n", watch.Service.GetName(), err) 71 } 72 } 73 } 74 log.Printf("No more events in watcher") 75 }() 76 77 for _, dir := range watch.IncludedPaths { 78 log.Printf("Adding: %s\n", dir) 79 err = watcher.Add(dir) 80 if err != nil { 81 log.Printf("%v\n", err) 82 watcher.Close() 83 return nil, errors.WithStack(err) 84 } 85 } 86 return watcher, nil 87 } 88 89 func rebuildService(dirConfig *home.EdwardConfiguration, service *services.ServiceConfig, restart func() error) error { 90 b := builder.New(services.OperationConfig{}, services.ContextOverride{}) 91 err := b.BuildWithTracker(dirConfig, tracker.NewTask(func(updatedTask tracker.Task) {}), service, true) 92 if err != nil { 93 return fmt.Errorf("build failed: %v", err) 94 } 95 log.Printf("Build succeeded\n") 96 err = restart() 97 if err != nil { 98 return errors.WithStack(err) 99 } 100 return nil 101 }