commit ac0e6e576a84925e673ace66c86951d5a0842dc5 Author: Jordan Orelli Date: Wed Dec 17 20:23:01 2014 +0000 initial commit diff --git a/main.go b/main.go new file mode 100644 index 0000000..7bf9fa3 --- /dev/null +++ b/main.go @@ -0,0 +1,125 @@ +package main + +import ( + "code.google.com/p/go.exp/inotify" + "flag" + "fmt" + "os" +) + +var options struct { + track trackMask +} + +func main() { + flag.Parse() + if options.track == 0 { + options.track = trackMask(inotify.IN_ALL_EVENTS) + } + + w, err := inotify.NewWatcher() + if err != nil { + bail(1, "couldn't create new watcher: %v", err) + } + + if flag.NArg() > 0 { + for _, path := range flag.Args() { + if err := w.AddWatch(path, uint32(options.track)); err != nil { + // if err := w.Watch(d); err != nil { + bail(1, "couldn't add watch: %v", err) + } + } + } else { + d, err := os.Getwd() + if err != nil { + bail(1, "couldn't get current directory: %v", err) + } + if err := w.AddWatch(d, uint32(options.track)); err != nil { + // if err := w.Watch(d); err != nil { + bail(1, "couldn't add watch: %v", err) + } + } + + cookies := make(map[uint32]*inotify.Event, 4) + + for { + select { + case ev := <-w.Event: + if ev.Mask&inotify.IN_ACCESS > 0 { + fmt.Printf("access %s\n", ev.Name) + } + if ev.Mask&inotify.IN_ATTRIB > 0 { + fmt.Printf("attrib %s\n", ev.Name) + } + if ev.Mask&inotify.IN_CLOSE > 0 { + fmt.Printf("close %s\n", ev.Name) + } + if ev.Mask&inotify.IN_CLOSE_NOWRITE > 0 { + fmt.Printf("close-nowrite %s\n", ev.Name) + } + if ev.Mask&inotify.IN_CLOSE_WRITE > 0 { + fmt.Printf("close-write %s\n", ev.Name) + } + if ev.Mask&inotify.IN_CREATE > 0 { + fmt.Printf("create %s\n", ev.Name) + } + if ev.Mask&inotify.IN_DELETE > 0 { + fmt.Printf("delete %s\n", ev.Name) + } + if ev.Mask&inotify.IN_DELETE_SELF > 0 { + fmt.Printf("delete-self %s\n", ev.Name) + } + if ev.Mask&inotify.IN_DONT_FOLLOW > 0 { + fmt.Printf("dont-follow %s\n", ev.Name) + } + if ev.Mask&inotify.IN_IGNORED > 0 { + fmt.Printf("ignored %s\n", ev.Name) + } + // if ev.Mask & inotify.IN_ISDIR > 0 { + // fmt.Printf("isdir %s\n", ev.Name) + // } + if ev.Mask&inotify.IN_MODIFY > 0 { + fmt.Printf("modify %s\n", ev.Name) + } + if ev.Mask&inotify.IN_MOVE > 0 { + prev, ok := cookies[ev.Cookie] + if !ok { + cookies[ev.Cookie] = ev + } else { + fmt.Printf("move %s -> %s\n", prev.Name, ev.Name) + delete(cookies, ev.Cookie) + } + } + if ev.Mask&inotify.IN_MOVED_FROM > 0 { + fmt.Printf("moved-from %s\n", ev.Name) + } + if ev.Mask&inotify.IN_MOVED_TO > 0 { + fmt.Printf("moved-to %s\n", ev.Name) + } + if ev.Mask&inotify.IN_MOVE_SELF > 0 { + fmt.Printf("move-self %s\n", ev.Name) + } + if ev.Mask&inotify.IN_ONESHOT > 0 { + fmt.Printf("oneshot %s\n", ev.Name) + } + if ev.Mask&inotify.IN_ONLYDIR > 0 { + fmt.Printf("onlydir %s\n", ev.Name) + } + if ev.Mask&inotify.IN_OPEN > 0 { + fmt.Printf("open %s\n", ev.Name) + } + if ev.Mask&inotify.IN_Q_OVERFLOW > 0 { + fmt.Printf("q-overflow %s\n", ev.Name) + } + if ev.Mask&inotify.IN_UNMOUNT > 0 { + fmt.Printf("unmount %s\n", ev.Name) + } + case err := <-w.Error: + bail(1, "error on watcher: %v", err) + } + } +} + +func init() { + flag.Var(&options.track, "track", "comma-separated list of events to track") +} diff --git a/misc.go b/misc.go new file mode 100644 index 0000000..723d0af --- /dev/null +++ b/misc.go @@ -0,0 +1,21 @@ +package main + +import ( + "fmt" + "os" + "strings" +) + +// writes out a message and then exits with the status coded provided by +// status. Since bail calls os.Exit, defered functions are not run. +func bail(status int, template string, args ...interface{}) { + if !strings.HasSuffix(template, "\n") { + template += "\n" + } + if status == 0 { + fmt.Fprintf(os.Stdout, template, args...) + } else { + fmt.Fprintf(os.Stderr, template, args...) + } + os.Exit(status) +} diff --git a/track.go b/track.go new file mode 100644 index 0000000..242c835 --- /dev/null +++ b/track.go @@ -0,0 +1,120 @@ +package main + +import ( + "code.google.com/p/go.exp/inotify" + "fmt" + "strings" +) + +type trackMask uint32 + +func (t *trackMask) String() string { + parts := make([]string, 0, 8) + if uint32(*t)&inotify.IN_ACCESS > 0 { + parts = append(parts, "access") + } + if uint32(*t)&inotify.IN_ALL_EVENTS > 0 { + parts = append(parts, "all") + } + if uint32(*t)&inotify.IN_ATTRIB > 0 { + parts = append(parts, "attrib") + } + if uint32(*t)&inotify.IN_CLOSE > 0 { + parts = append(parts, "close") + } + if uint32(*t)&inotify.IN_CLOSE_NOWRITE > 0 { + parts = append(parts, "close-nowrite") + } + if uint32(*t)&inotify.IN_CLOSE_WRITE > 0 { + parts = append(parts, "close-write") + } + if uint32(*t)&inotify.IN_CREATE > 0 { + parts = append(parts, "create") + } + if uint32(*t)&inotify.IN_DELETE > 0 { + parts = append(parts, "delete") + } + if uint32(*t)&inotify.IN_DELETE_SELF > 0 { + parts = append(parts, "delete-self") + } + if uint32(*t)&inotify.IN_MODIFY > 0 { + parts = append(parts, "modify") + } + if uint32(*t)&inotify.IN_MOVE > 0 { + parts = append(parts, "move") + } + if uint32(*t)&inotify.IN_MOVED_FROM > 0 { + parts = append(parts, "moved-from") + } + if uint32(*t)&inotify.IN_MOVED_TO > 0 { + parts = append(parts, "moved-to") + } + if uint32(*t)&inotify.IN_MOVE_SELF > 0 { + parts = append(parts, "move-self") + } + if uint32(*t)&inotify.IN_OPEN > 0 { + parts = append(parts, "open") + } + if uint32(*t)&inotify.IN_ISDIR > 0 { + parts = append(parts, "isdir") + } + if uint32(*t)&inotify.IN_IGNORED > 0 { + parts = append(parts, "ignored") + } + if uint32(*t)&inotify.IN_Q_OVERFLOW > 0 { + parts = append(parts, "q-overflow") + } + if uint32(*t)&inotify.IN_UNMOUNT > 0 { + parts = append(parts, "unmount") + } + return strings.Join(parts, ",") +} + +func (t *trackMask) Set(v string) error { + parts := strings.Split(v, ",") + for _, part := range parts { + switch part { + case "access": + *t |= trackMask(inotify.IN_ACCESS) + case "all": + *t |= trackMask(inotify.IN_ALL_EVENTS) + case "attrib": + *t |= trackMask(inotify.IN_ATTRIB) + case "close": + *t |= trackMask(inotify.IN_CLOSE) + case "close-nowrite": + *t |= trackMask(inotify.IN_CLOSE_NOWRITE) + case "close-write": + *t |= trackMask(inotify.IN_CLOSE_WRITE) + case "create": + *t |= trackMask(inotify.IN_CREATE) + case "delete": + *t |= trackMask(inotify.IN_DELETE) + case "delete-self": + *t |= trackMask(inotify.IN_DELETE_SELF) + case "modify": + *t |= trackMask(inotify.IN_MODIFY) + case "move": + *t |= trackMask(inotify.IN_MOVE) + case "moved-from": + *t |= trackMask(inotify.IN_MOVED_FROM) + case "moved-to": + *t |= trackMask(inotify.IN_MOVED_TO) + case "move-self": + *t |= trackMask(inotify.IN_MOVE_SELF) + case "open": + *t |= trackMask(inotify.IN_OPEN) + case "isdir": + *t |= trackMask(inotify.IN_ISDIR) + case "ignored": + *t |= trackMask(inotify.IN_IGNORED) + case "q-overflow": + *t |= trackMask(inotify.IN_Q_OVERFLOW) + case "unmount": + *t |= trackMask(inotify.IN_UNMOUNT) + default: + return fmt.Errorf("unrecognized event type: %s", part) + } + } + return nil +}