-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwatch.go
129 lines (116 loc) · 2.61 KB
/
watch.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package main
import (
"errors"
"fmt"
"sync"
// "log"
"os"
"os/exec"
"os/signal"
"strings"
"syscall"
"time"
"github.com/charmbracelet/log"
"github.com/fsnotify/fsnotify"
"github.com/spf13/cobra"
)
var (
command string
processMutex sync.Mutex
)
var watchCommand = &cobra.Command{
Use: "watch",
Short: "watch a file for change",
Long: "watch a file for change",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
for _, path := range args {
_, err := os.Stat(path)
if err != nil {
return err
}
}
} else {
return errors.New("at list 1 file must be specified")
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
watcher, err := fsnotify.NewWatcher()
if err != nil {
return err
}
defer watcher.Close()
errs := make(chan error, 1)
fullCommand := strings.Split(command, " ")
command := fullCommand[0]
arguments := make([]string, 0, len(fullCommand)-1)
if len(fullCommand) > 1 {
arguments = append(arguments, fullCommand[1:]...)
}
lastEventTime := time.Unix(0, 0)
var process *exec.Cmd
go func() {
for {
select {
case event := <-watcher.Events:
if event.Name == "" || (event.Op != fsnotify.Write && event.Op != fsnotify.Create) || time.Since(lastEventTime) <= time.Second/10 {
continue
}
lastEventTime = time.Now()
log.Info(event)
processMutex.Lock()
if err := kill(process); err != nil {
log.Error(err)
}
process, err = start(command, arguments...)
processMutex.Unlock()
if err != nil {
errs <- err
return
}
case err := <-watcher.Errors:
if err != nil {
log.Error(err)
}
}
}
}()
go func() {
for _, path := range args {
if err := watcher.Add(path); err != nil {
errs <- err
}
if verbose {
log.Info("watching", path)
}
}
}()
signals := make(chan os.Signal, 1)
signal.Notify(signals, os.Interrupt, syscall.SIGINT, syscall.SIGQUIT)
select {
case <-signals:
processMutex.Lock()
if err := kill(process); err != nil {
log.Error(err)
}
processMutex.Unlock()
fmt.Print("\r")
return nil
case err := <-errs:
processMutex.Lock()
if err := kill(process); err != nil {
log.Error(err)
}
processMutex.Unlock()
log.Error(err)
return err
}
},
}
func init() {
watchCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, "log a list of watched files")
watchCommand.Flags().StringVarP(&command, "command", "c", "", "command to run after each file change")
watchCommand.MarkFlagRequired("command")
RootCommand.AddCommand(watchCommand)
}