-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathmain.go
140 lines (124 loc) · 2.6 KB
/
main.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
130
131
132
133
134
135
136
137
138
139
140
package main
import (
"flag"
fn "github.com/howeyc/fsnotify"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
)
var (
runningApp *exec.Cmd
appName string
// 由于 fsnotify 的文件产生的事件与期望的不一样, 所以只能使用 time 来确定
modifyUnixTimes = make(map[string]int64)
)
func main() {
args := flag.Args()
if len(args) == 1 {
appName = args[0]
} else if len(args) > 1 {
log.Fatalln("只允许一个参数")
} else {
abs, err := filepath.Abs("./")
if err != nil {
log.Fatalln(err)
}
appName = filepath.Base(abs)
}
paths, err := Walk("./")
if err != nil {
log.Fatalln(err)
}
Build()
go Start()
Watch(paths)
}
func Walk(rootDir string) (paths []string, err error) {
err = filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
if !info.IsDir() || strings.Contains(path, ".git") {
return nil
}
paths = append(paths, path)
return nil
})
if err != nil {
return
}
return
}
func Watch(paths []string) {
watcher, err := fn.NewWatcher()
if err != nil {
log.Fatalln(err)
}
done := make(chan bool)
go func() {
for {
select {
case ev := <-watcher.Event:
if filepath.Ext(ev.Name) == ".go" {
reBuild := false
t, ok := modifyUnixTimes[ev.Name]
if !ok {
modifyUnixTimes[ev.Name] = time.Now().Unix()
reBuild = true
} else {
nt := time.Now().Unix()
reBuild = (nt - t) > 2
modifyUnixTimes[ev.Name] = nt
}
if reBuild {
Rebuild()
}
}
case err := <-watcher.Error:
log.Println("error:", err)
}
}
}()
for _, path := range paths {
err = watcher.Watch(path)
if err != nil {
log.Fatalln(err)
}
}
log.Println("Begin to watch app:", appName)
<-done
watcher.Close()
}
func Build() (err error) {
begin := time.Now().UnixNano()
cmd := exec.Command("go", "build")
// 将执行的错误和输出都显示到当前的 标准输出, 标准错误 设备中
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run() // Wait for build
log.Println("Build passed:", (time.Now().UnixNano()-begin)/1000/1000, "ms")
return
}
// Golang 的应用使用 build, 然后再 run 避免直接使用 run 会出现文件缺少引入的问题
func Rebuild() {
err := Build()
if err != nil {
log.Println(err)
} else {
ReStart()
}
}
func ReStart() {
if runningApp != nil {
log.Println("Kill old running app:", appName)
runningApp.Process.Kill()
}
Start()
}
func Start() {
runningApp = exec.Command("./" + appName)
runningApp.Stdout = os.Stdout
runningApp.Stderr = os.Stderr
log.Println("Start running app:", appName)
go runningApp.Run()
}