initial commit
1 file changed, 126 insertions(+), 0 deletions(-)
changed files
A main.go
@@ -0,0 +1,126 @@ +package main + +import ( + "context" + "flag" + "log" + "os" + "os/signal" + "strings" + "sync" + "syscall" + "time" + + "github.com/fsnotify/fsnotify" + + "alin.ovh/erl/command" + "alin.ovh/erl/state" + "alin.ovh/erl/watcher" +) + +var ( + Exec = flag.String("exec", "", "command to execute on file change") +) + +func Start(ctx context.Context, w watcher.Watcher, sm *state.StateMachine) { + var wg sync.WaitGroup + + wg.Add(1) + go func(events <-chan watcher.Event, errors <-chan error) { + defer wg.Done() + sm.SendEvent(state.Start) + for { + select { + case <-ctx.Done(): + sm.SendEvent(state.Signal) + + return + case event, ok := <-events: + if !ok { + return + } + + // skip if _only_ chmod + if event.Op == fsnotify.Chmod { + continue + } + + log.Printf("event: %s %s\n", event.Name, event.Op.String()) + if event.Op.Has(fsnotify.Create) { + stat, err := os.Stat(event.Name) + if err != nil { + log.Printf("Error getting file info: %v\n", err) + + continue + } + if stat.IsDir() { + err = w.AddRecursive(event.Name) + if err != nil { + log.Printf("Error adding directory to watcher: %v\n", err) + } + } + } + if event.Op.Has(fsnotify.Remove) { + for _, dir := range w.WatchList() { + if strings.HasPrefix(dir, event.Name) { + err := w.Remove(dir) + if err != nil { + log.Printf("Error removing directory from watcher: %v\n", err) + } + } + } + } + + sm.SendEvent(state.Restart) + + time.Sleep(100 * time.Millisecond) + + case err, ok := <-errors: + if !ok { + return + } + log.Printf("Error: %v\n", err) + } + } + }(w.Monitor()) + + err := w.AddRecursive(".") + if err != nil { + log.Fatalf("failed to add directory to watcher: %v", err) + } + + <-ctx.Done() + log.Println("shutting down") + + sm.SendEvent(state.Signal) + + wg.Wait() +} + +func main() { + log.SetFlags(log.Lmsgprefix) + flag.Parse() + + program := *Exec + if program == "" { + log.Fatal("no command provided") + } + + watcher, err := watcher.New() + if err != nil { + log.Fatal(err) + } + defer watcher.Close() + + ctx, cancel := signal.NotifyContext( + context.Background(), + os.Interrupt, + syscall.SIGHUP, + syscall.SIGTERM, + ) + defer cancel() + + cmd := command.New(program, flag.Args(), command.Options{}) + sm := state.New(cmd, log.New(os.Stderr, "state: ", log.Lmsgprefix)) + Start(ctx, watcher, sm) +}