diff --git a/pkg/watch/notify_test.go b/pkg/watch/notify_test.go index 7d87def1d..7acb5d5c1 100644 --- a/pkg/watch/notify_test.go +++ b/pkg/watch/notify_test.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "os" "path/filepath" + "runtime" "strings" "testing" "time" @@ -309,6 +310,29 @@ func TestWatchBothDirAndFile(t *testing.T) { f.assertEvents(fileB) } +func TestWatchNonexistentDirectory(t *testing.T) { + f := newNotifyFixture(t) + defer f.tearDown() + + root := f.JoinPath("root") + err := os.Mkdir(root, 0777) + if err != nil { + t.Fatal(err) + } + parent := f.JoinPath("root", "parent") + file := f.JoinPath("root", "parent", "a") + + f.watch(file) + f.fsync() + f.events = nil + f.WriteFile(file, "hello") + if runtime.GOOS == "darwin" { + f.assertEvents(file) + } else { + f.assertEvents(parent, file) + } +} + type notifyFixture struct { *tempdir.TempDirFixture notify Notify diff --git a/pkg/watch/watcher_naive.go b/pkg/watch/watcher_naive.go index 47bdd9a60..83c0275c2 100644 --- a/pkg/watch/watcher_naive.go +++ b/pkg/watch/watcher_naive.go @@ -3,6 +3,7 @@ package watch import ( + "fmt" "log" "os" "path/filepath" @@ -31,12 +32,11 @@ func (d *naiveNotify) Add(name string) error { // if it's a file that doesn't exist, watch its parent if os.IsNotExist(err) { - parent := filepath.Join(name, "..") - err = d.watcher.Add(parent) + err, fileWatched := d.watchUpRecursively(name) if err != nil { - return errors.Wrapf(err, "notify.Add(%q)", name) + return errors.Wrapf(err, "watchUpRecursively(%q)", name) } - d.watchList[parent] = true + d.watchList[fileWatched] = true } else if fi.IsDir() { err = d.watchRecursively(name) if err != nil { @@ -71,6 +71,24 @@ func (d *naiveNotify) watchRecursively(dir string) error { }) } +func (d *naiveNotify) watchUpRecursively(path string) (error, string) { + if path == string(filepath.Separator) { + return fmt.Errorf("cannot watch root directory"), "" + } + + _, err := os.Stat(path) + if err != nil && !os.IsNotExist(err) { + return errors.Wrapf(err, "os.Stat(%q)", path), "" + } + + if os.IsNotExist(err) { + parent := filepath.Dir(path) + return d.watchUpRecursively(parent) + } + + return d.watcher.Add(path), path +} + func (d *naiveNotify) Close() error { return d.watcher.Close() }