Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Major cleanup: throw alot away, reimplement DirWatcher

  • Loading branch information...
commit 582f8d6b1c954e601c5fe14a2a4d2cff2b3ee322 1 parent ea41c70
@mrnugget authored
View
49 dir_watcher.go
@@ -0,0 +1,49 @@
+package main
+
+import (
+ "github.com/howeyc/fsnotify"
+)
+
+const fileChanBuf = 500
+
+func WatchDirs(dirs []string) (d *DirWatcher, err error) {
+ bufevents := make(chan *fsnotify.FileEvent, fileChanBuf)
+
+ watcher, err := fsnotify.NewWatcher()
+ if err != nil {
+ return nil, err
+ }
+
+ d = &DirWatcher{bufevents, watcher}
+
+ go d.proxyEvents()
+
+ for _, dir := range dirs {
+ err = watcher.Watch(dir)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return
+}
+
+type DirWatcher struct {
+ Events chan *fsnotify.FileEvent
+ watcher *fsnotify.Watcher
+}
+
+func (d *DirWatcher) Stop() (err error) {
+ err = d.watcher.Close()
+ return
+}
+
+func (d *DirWatcher) proxyEvents() {
+ for {
+ select {
+ case ev := <-d.watcher.Event:
+ d.Events <- ev
+ case <-d.watcher.Error:
+ break
+ }
+ }
+}
View
64 dir_watcher_test.go
@@ -0,0 +1,64 @@
+package main
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "runtime"
+ "testing"
+ "time"
+)
+
+var (
+ _, filename, _, _ = runtime.Caller(0)
+ fixtures = filepath.Dir(filename) + "/fixtures"
+)
+
+func TestEvents(t *testing.T) {
+ sub1 := fixtures + "/sub1"
+ sub2 := fixtures + "/sub2"
+
+ dirs := []string{sub1, sub2}
+
+ watcher, err := WatchDirs(dirs)
+ checkErr(t, err)
+
+ // Rewrite file to trigger Modify event
+ content, err := ioutil.ReadFile(sub1 + "/foobar.txt")
+ checkErr(t, err)
+ err = ioutil.WriteFile(sub1 + "/foobar.txt", content, 0644)
+ checkErr(t, err)
+
+ ev := <-watcher.Events
+ if !ev.IsModify() && ev.Name != sub1 + "/foobar.txt" {
+ t.Fatal("Wrong event")
+ }
+
+ // Create file to trigger create event
+ err = ioutil.WriteFile(sub2 + "/hello.txt", []byte("Hello World!"), 0644)
+ checkErr(t, err)
+
+ ev = <-watcher.Events
+ if !ev.IsCreate() && ev.Name != sub2 + "/hello.txt" {
+ t.Fatal("Wrong event")
+ }
+
+ time.Sleep(1 * time.Millisecond)
+
+ // Remove newly created file
+ err = os.Remove(sub2 + "/hello.txt")
+ checkErr(t, err)
+
+ ev = <-watcher.Events
+ if !ev.IsDelete() && ev.Name != sub2 + "/hello.txt" {
+ t.Fatal("Wrong event")
+ }
+
+ watcher.Stop()
+}
+
+func checkErr(t *testing.T, err error) {
+ if err != nil {
+ t.Fatal(err)
+ }
+}
View
0  watchgopher/fixtures/foobar.txt → fixtures/sub1/foobar.txt
File renamed without changes
View
0  fixtures/sub2/.gitignore
No changes.
View
37 watchgopher.go
@@ -1,30 +1,19 @@
package main
-import (
- "flag"
- "fmt"
- "github.com/mrnugget/watchgopher/watchgopher"
- "os"
- "time"
-)
-
-var interval = flag.Duration("interval", 60*time.Second, "when to check")
-var path string
-
func main() {
- flag.Parse()
+ // @TODO: Read configuration file either from `~/.watchgopher` or from
+ // first command line argument
+
+ // @TODO: Parse configuration file to get which directories to watch,
+ // which pattern to match for which directory, which scripts to run on
+ // event
- path = flag.Arg(0)
- if path == "" {
- fmt.Println("You have to provide a path to watch")
- os.Exit(1)
- }
- if path == "." {
- path, _ = os.Getwd()
- }
+ // @TODO: Watch directories for events (see `dir_watcher.go`) and pass
+ // events to a manager, which checks for appliance of configuration
- err := watchgopher.Watch(path, *interval)
- if err != nil {
- panic(err)
- }
+ // @TODO: If filename matches a pattern (e.g. `*.jpg`), pass it to a worker,
+ // that shells out and runs configured command with two arguments:
+ // `~/bin/script EVENTTYPE FILENAME`, where EVENTTYPE can be CREATE, DELETE,
+ // MODIFY, RENAME and FILENAME is the absolute path to the file which
+ // triggered the event
}
View
16 watchgopher/actions.go
@@ -1,16 +0,0 @@
-package watchgopher
-
-import (
- "fmt"
- "regexp"
-)
-
-type Action func(path string)
-
-func Unzipper(path string) {
- ok, err := regexp.MatchString(`^.*\.zip$`, path)
-
- if err == nil && ok {
- fmt.Println("IT IS A ZIP!")
- }
-}
View
83 watchgopher/dir.go
@@ -1,83 +0,0 @@
-package watchgopher
-
-import (
- "github.com/howeyc/fsnotify"
- "io/ioutil"
- "os"
- "path"
-)
-
-const fileChanBuf = 500
-
-func NewDir(path string) (d *Dir, err error) {
- files := make(map[string]os.FileInfo)
- events := make(chan *fsnotify.FileEvent, fileChanBuf)
-
- watcher, err := fsnotify.NewWatcher()
- if err != nil {
- return nil, err
- }
-
- return &Dir{path, files, events, watcher}, nil
-}
-
-type Dir struct {
- Path string
- Files map[string]os.FileInfo
- Events chan *fsnotify.FileEvent
- watcher *fsnotify.Watcher
-}
-
-func (d *Dir) Listen() (err error) {
- err = d.scan()
- if err != nil {
- return
- }
-
- err = d.watcher.Watch(d.Path)
- if err != nil {
- return
- }
-
- go d.proxyEvents()
- return nil
-}
-
-func (d *Dir) Stop() (err error) {
- err = d.watcher.Close()
- return
-}
-
-func (d *Dir) proxyEvents() {
- for {
- select {
- case ev := <-d.watcher.Event:
- if ev.IsRename() || ev.IsDelete() {
- delete(d.Files, ev.Name)
- }
- if ev.IsCreate() || ev.IsModify() {
- fi, err := os.Stat(ev.Name)
- if err != nil {
- break
- }
- d.Files[ev.Name] = fi
- }
- d.Events <- ev
- case <-d.watcher.Error:
- break
- }
- }
-}
-
-func (d *Dir) scan() (err error) {
- files, err := ioutil.ReadDir(d.Path)
- if err != nil {
- return
- }
-
- for _, f := range files {
- d.Files[path.Join(d.Path, f.Name())] = f
- }
-
- return nil
-}
View
79 watchgopher/dir_test.go
@@ -1,79 +0,0 @@
-package watchgopher
-
-import (
- "io/ioutil"
- "os"
- "path/filepath"
- "runtime"
- "testing"
- "time"
-)
-
-var (
- _, filename, _, _ = runtime.Caller(0)
- fixtures = filepath.Dir(filename) + "/fixtures"
-)
-
-func TestFiles(t *testing.T) {
- dir, err := NewDir(fixtures)
- checkErr(t, err)
-
- err = dir.Listen()
- checkErr(t, err)
- defer dir.Stop()
-
- _, ok := dir.Files[fixtures+"/foobar.txt"]
- if !ok {
- t.Errorf("dir.Files does not include right files")
- }
-
- _, ok = dir.Files[fixtures+"/hello_world.txt"]
- if !ok {
- t.Errorf("dir.Files does not include right files")
- }
-}
-
-func TestEvents(t *testing.T) {
- testfilepath := fixtures + "/testfile.txt"
-
- dir, err := NewDir(fixtures)
- checkErr(t, err)
-
- err = dir.Listen()
- checkErr(t, err)
- defer dir.Stop()
-
- err = ioutil.WriteFile(testfilepath, []byte("Hello World!"), 0644)
- checkErr(t, err)
-
- time.Sleep(1 * time.Millisecond)
-
- _, ok := dir.Files[testfilepath]
- if !ok {
- t.Errorf("Did not add the created file to dir.Files")
- }
-
- err = os.Remove(testfilepath)
- checkErr(t, err)
-
- createev := <-dir.Events
- if createev.Name != testfilepath && !createev.IsCreate() {
- t.Fatal("Did not receive the right event")
- }
-
- deleteev := <-dir.Events
- if deleteev.Name != testfilepath && !deleteev.IsDelete() {
- t.Fatal("Did not receive the right event")
- }
-
- file, ok := dir.Files[testfilepath]
- if file != nil && ok {
- t.Errorf("Did not remove the deleted file from dir.Files")
- }
-}
-
-func checkErr(t *testing.T, err error) {
- if err != nil {
- t.Fatal(err)
- }
-}
View
1  watchgopher/fixtures/hello_world.txt
@@ -1 +0,0 @@
-Hello World
View
62 watchgopher/monitor.go
@@ -1,62 +0,0 @@
-package watchgopher
-
-import (
- "fmt"
- "time"
-)
-
-func Watch(path string, interval time.Duration) (err error) {
- fmt.Println("PATH:", path)
- fmt.Println("INTERVAL:", interval)
- fmt.Println("Watchgopher is watching...")
-
- dir, err := NewDir(path)
- if err != nil {
- return
- }
-
- ticker := time.Tick(interval)
- actions := []Action{Unzipper}
- queue := make(chan string)
-
- monitor := &Monitor{dir, ticker, actions, queue}
- monitor.start()
-
- return nil
-}
-
-type Monitor struct {
- dir *Dir
- ticker <-chan time.Time
- actions []Action
- queue chan string
-}
-
-func (m *Monitor) start() {
- go m.workOff(m.queue)
-
- err := m.dir.Listen()
- if err != nil {
- panic(err)
- }
-
- for {
- select {
- case ev := <-m.dir.Events:
- m.queue <- ev.Name
- case <-m.ticker:
- m.dir.scan()
- for fpath, _ := range m.dir.Files {
- m.queue <- fpath
- }
- }
- }
-}
-
-func (m *Monitor) workOff(queue chan string) {
- for fpath := range queue {
- for _, action := range m.actions {
- action(fpath)
- }
- }
-}
Please sign in to comment.
Something went wrong with that request. Please try again.