diff --git a/runner/logger.go b/runner/logger.go index ae2f3b1..da075f8 100644 --- a/runner/logger.go +++ b/runner/logger.go @@ -4,6 +4,7 @@ import ( "fmt" logPkg "log" "time" + "strings" "github.com/mattn/go-colorable" ) @@ -35,7 +36,7 @@ func fatal(err error) { type appLogWriter struct{} func (a appLogWriter) Write(p []byte) (n int, err error) { - appLog(string(p)) + appLog(strings.Replace(string(p), "%", "%%", -1)) return len(p), nil } diff --git a/runner/settings.go b/runner/settings.go index 10117ec..3304e3f 100644 --- a/runner/settings.go +++ b/runner/settings.go @@ -20,6 +20,7 @@ const ( var settings = map[string]string{ "config_path": "./runner.conf", "root": ".", + "env": ".env", "tmp_path": "./tmp", "build_name": "runner-build", "build_log": "runner-build-errors.log", @@ -112,6 +113,10 @@ func root() string { return settings["root"] } +func envFile() string { + return settings["env"] +} + func tmpPath() string { return settings["tmp_path"] } diff --git a/runner/start.go b/runner/start.go index e22923a..fab9fb4 100644 --- a/runner/start.go +++ b/runner/start.go @@ -6,6 +6,7 @@ import ( "runtime" "strings" "time" + "github.com/joho/godotenv" ) var ( @@ -73,6 +74,7 @@ func start() { } run() } + watch() started = true mainLog(strings.Repeat("-", 20)) @@ -94,6 +96,12 @@ func initLogFuncs() { } func setEnvVars() { + if _, err := os.Stat(envFile()); !os.IsNotExist(err) { + err := godotenv.Load(envFile()) + if err != nil { + fatal(err) + } + } os.Setenv("DEV_RUNNER", "1") wd, err := os.Getwd() if err == nil { @@ -113,8 +121,8 @@ func Start() { initSettings() initLogFuncs() initFolders() + initWatcher() setEnvVars() - watch() start() startChannel <- "/" diff --git a/runner/watcher.go b/runner/watcher.go index 1f3f1ac..96818ec 100644 --- a/runner/watcher.go +++ b/runner/watcher.go @@ -2,18 +2,60 @@ package runner import ( "os" - "path/filepath" "strings" - + "fmt" "github.com/howeyc/fsnotify" + "io" + "io/ioutil" + "os/exec" + "runtime" ) -func watchFolder(path string) { - watcher, err := fsnotify.NewWatcher() +var watchedFolders = map[string]struct{}{} +var pkgName = "" +var pkgPath = "" +var goPaths = []string{} +var watcher *fsnotify.Watcher + +func initWatcher() { + // parse running package name + separator := ":" + if runtime.GOOS == "windows" { + separator = ";" + } + goPaths = strings.Split(os.Getenv("GOPATH"), separator) + root := root() + dir, err := os.Getwd() if err != nil { fatal(err) } + if root != "." { + pkgName = root + for _, gopath := range goPaths { + pkgPath = gopath + "/src/" + pkgName + e, err := exists(pkgPath) + if err != nil { + fatal(err) + } + if e { + break + } + } + } else { + for _, gopath := range goPaths { + if strings.HasPrefix(dir, gopath) && len(dir) > len(gopath)+5 { + pkgName = dir[len(gopath)+5:] + pkgPath = dir + break + } + } + } + // init watcher + watcher, err = fsnotify.NewWatcher() + if err != nil { + fatal(err) + } go func() { for { select { @@ -27,31 +69,90 @@ func watchFolder(path string) { } } }() +} + +// exists returns whether the given file or directory exists or not +func exists(path string) (bool, error) { + _, err := os.Stat(path) + if err == nil { + return true, nil + } + if os.IsNotExist(err) { + return false, nil + } + return true, err +} - watcherLog("Watching %s", path) - err = watcher.Watch(path) +func getFolders() map[string]struct{} { + cmd := exec.Command("go", "list", "-f", `{{ join .Deps "\n" }}`, pkgName) + stderr, err := cmd.StderrPipe() if err != nil { fatal(err) } + + stdout, err := cmd.StdoutPipe() + if err != nil { + fatal(err) + } + + err = cmd.Start() + if err != nil { + fatal(err) + } + + imps, _ := ioutil.ReadAll(stdout) + io.Copy(os.Stderr, stderr) + + err = cmd.Wait() + if err != nil { + fatal(err) + } + + _imps := strings.Split(strings.Trim(string(imps), "\n"), "\n") + _watchedFolders := map[string]struct{}{pkgPath: struct{}{}} + for _, imp := range _imps { + for _, gopath := range goPaths { + path := fmt.Sprintf("%s/src/%s", gopath, imp) + e, err := exists(path) + if err != nil { + fatal(err) + } + if e { + _watchedFolders[path] = struct{}{} + break + } + } + } + + return _watchedFolders } func watch() { - root := root() - filepath.Walk(root, func(path string, info os.FileInfo, err error) error { - if info.IsDir() && !isTmpDir(path) { - if len(path) > 1 && strings.HasPrefix(filepath.Base(path), ".") { - return filepath.SkipDir + _watchedFolders := getFolders() + for folder, _ := range watchedFolders { + _, ok := _watchedFolders[folder] + if !ok { + watcherLog("remove watch %s", folder) + err := watcher.RemoveWatch(folder) + if err != nil { + fatal(err) } - - if isIgnoredFolder(path) { - watcherLog("Ignoring %s", path) - return filepath.SkipDir + } + } + for folder, _ := range _watchedFolders { + _, ok := watchedFolders[folder] + if !ok && !isTmpDir(folder) { + if isIgnoredFolder(folder) { + watcherLog("Ignoring %s", folder) + continue + } + watcherLog("add watch %s", folder) + err := watcher.Watch(folder) + if err != nil { + fatal(err) } - - watchFolder(path) } - - return err - }) + } + watchedFolders = _watchedFolders }