-
Notifications
You must be signed in to change notification settings - Fork 1
/
kick.go
182 lines (139 loc) · 3.79 KB
/
kick.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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// The Isomorphic Go Project
// Copyright (c) Wirecog, LLC. All rights reserved.
// Use of this source code is governed by a BSD-style
// license, which can be found in the LICENSE file.
package main
import (
"flag"
"fmt"
"log"
"os"
"os/exec"
"os/signal"
"path/filepath"
"runtime"
"github.com/fsnotify/fsnotify"
)
var appPath string
var mainSourceFile string
var gopherjsAppPath string
func buildGopherJSProject() {
if gopherjsAppPath != "" {
cwd, err := os.Getwd()
if err != nil {
log.Fatal("Encountered an error while attempting to get the cwd: ", err)
} else {
os.Chdir(gopherjsAppPath)
gjsCommand := exec.Command("gopherjs", "build")
if runtime.GOOS == "windows" {
// workaround as described here: https://github.com/gopherjs/gopherjs/issues/688
gjsCommand.Env = append(os.Environ(), "GOOS=darwin")
}
gjsCommand.Stdout = os.Stdout
gjsCommand.Stderr = os.Stderr
gjsCommand.Start()
os.Chdir(cwd)
}
}
}
func restart(cmd *exec.Cmd) *exec.Cmd {
var newCommand *exec.Cmd
stop(cmd)
newCommand = start()
return newCommand
}
func initializeWatcher(shouldRestart chan bool, dirList []string) {
supportedExtensions := map[string]int{".go": 1, ".html": 1, ".tmpl": 1}
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
done := make(chan bool)
go func() {
for {
select {
case event := <-watcher.Events:
if event.Op == fsnotify.Write || event.Op == fsnotify.Rename {
if _, ok := supportedExtensions[filepath.Ext(event.Name)]; ok {
shouldRestart <- true
}
}
case err := <-watcher.Errors:
if err != nil {
log.Println("error:", err)
}
}
}
}()
err = watcher.Add(appPath)
if err != nil {
log.Fatal(err)
}
// watch subdirectories also
for _, element := range dirList {
watcher.Add(element)
}
<-done
}
func pathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return true, err
}
func main() {
flag.StringVar(&appPath, "appPath", "", "The path to your Go project")
flag.StringVar(&mainSourceFile, "mainSourceFile", "", "The Go source file with the main func()")
flag.StringVar(&gopherjsAppPath, "gopherjsAppPath", "", "The path to your GopherJS project (optional)")
flag.Parse()
// Exit if no appPath is supplied
if appPath == "" {
fmt.Println("You must supply the appPath parameter")
os.Exit(1)
}
if appPathExists, appPathErr := pathExists(appPath); appPathExists != true || appPathErr != nil {
fmt.Println("The path you specified to your Go application project does not exist.")
os.Exit(1)
}
if mainSourceFile == "" {
fmt.Println("You must supply the mainSourceFile parameter")
os.Exit(1)
}
if sourceFileExists, sourceFilePathErr := pathExists(appPath + "/" + mainSourceFile); sourceFileExists != true || sourceFilePathErr != nil {
fmt.Println("The path to the main source file you provided does not exist.")
os.Exit(1)
}
if gopherjsAppPath != "" {
if gopherjsFileExists, gopherjsFileErr := pathExists(gopherjsAppPath); gopherjsFileExists != true || gopherjsFileErr != nil {
fmt.Println("The path you specified to the GopherJS application project does not exist.")
os.Exit(1)
}
}
dirList := []string{}
filepath.Walk(appPath, func(path string, f os.FileInfo, err error) error {
if f.IsDir() == true {
dirList = append(dirList, path)
}
return nil
})
shouldRestart := make(chan bool, 1)
go initializeWatcher(shouldRestart, dirList)
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
cmd := start()
for {
select {
case <-interrupt:
stop(cmd)
os.Exit(0)
case <-shouldRestart:
fmt.Println("\nInstant KickStart Applied! (Recompiling and restarting project.)")
cmd = restart(cmd)
}
}
}