// FSEvents may report multiple filesystem actions with one, coalesced event. // Notify unscoalesces such event and dispatches series of single events // back to the user. // // This example shows how to coalesce events by investigating notify.(*FSEvent).ID // field, for the science. func ExampleWatch_darwinCoalesce() { // Make the channels buffered to ensure no event is dropped. Notify will drop // an event if the receiver is not able to keep up the sending pace. c := make(chan notify.EventInfo, 4) // Set up a watchpoint listetning for events within current working directory. // Dispatch all platform-independent separately to c. if err := notify.Watch(".", c, notify.All); err != nil { log.Fatal(err) } defer notify.Stop(c) var id uint64 var coalesced []notify.EventInfo for ei := range c { switch n := ei.Sys().(*notify.FSEvent).ID; { case id == 0: id = n coalesced = []notify.EventInfo{ei} case id == n: coalesced = append(coalesced, ei) default: log.Printf("FSEvents reported a filesystem action with the following"+ " coalesced events %v groupped by %d ID\n", coalesced, id) return } } }
func setUpFolderListener(path string, stop <-chan bool) { os.RemoveAll(path) os.Mkdir(path, os.ModePerm) replacer := replacer.NewMakerRegistry(path) for _, format := range allFormats() { for _, class := range allClasses() { replacer.Add(format, class) } } c := make(chan notify.EventInfo, 1000) if err := notify.Watch(path, c, notify.Rename, notify.Remove); err != nil { log.Fatal(err) } defer notify.Stop(c) go func() { for { select { case event := <-c: replacer.Replace(event.Path()) } } }() <-stop }
// This example shows why it is important to not create leaks by stoping // a channel when it's no longer being used. func ExampleStop() { waitfor := func(path string, e notify.Event, timeout time.Duration) bool { dir, file := filepath.Split(path) c := make(chan notify.EventInfo, 1) if err := notify.Watch(dir, c, e); err != nil { log.Fatal(err) } // Clean up watchpoint associated with c. If Stop was not called upon // return the channel would be leaked as notify holds the only reference // to it and does not release it on its own. defer notify.Stop(c) t := time.After(timeout) for { select { case ei := <-c: if filepath.Base(ei.Path()) == file { return true } case <-t: return false } } } if waitfor("index.lock", notify.Create, 5*time.Second) { log.Println("The git repository was locked") } if waitfor("index.lock", notify.Remove, 5*time.Second) { log.Println("The git repository was unlocked") } }
func main() { // Make the channel buffered to ensure no event is dropped. Notify will drop // an event if the receiver is not able to keep up the sending pace. c := make(chan notify.EventInfo, 1) // Set up a watchpoint listening for inotify-specific events within a // current working directory. Dispatch each InCloseWrite and InMovedTo // events separately to c. if err := notify.Watch(".", c, notify.FSEventsModified, notify.FSEventsRemoved); err != nil { log.Fatal(err) } defer notify.Stop(c) // Block until an event is received. switch ei := <-c; ei.Event() { case notify.FSEventsChangeOwner: log.Println("The owner of", ei.Path(), "has changed.") case notify.FSEventsMount: log.Println("The path", ei.Path(), "has been mounted.") } // switch ei := <-c; ei.Event() { // case notify.FSEventsModified: // log.Println("Editing of", ei.Path(), "file is done.") // case notify.FSEventsRemoved: // log.Println("File", ei.Path(), "was swapped/moved into the watched directory.") // } }
// This example shows how to watch directory-name changes in the working directory subtree. func ExampleWatch_windows() { // Make the channel buffered to ensure no event is dropped. Notify will drop // an event if the receiver is not able to keep up the sending pace. c := make(chan notify.EventInfo, 4) // Since notify package behaves exactly like ReadDirectoryChangesW function, // we must register notify.FileNotifyChangeDirName filter and wait for one // of FileAction* events. if err := notify.Watch("./...", c, notify.FileNotifyChangeDirName); err != nil { log.Fatal(err) } defer notify.Stop(c) // Wait for actions. for ei := range c { switch ei.Event() { case notify.FileActionAdded, notify.FileActionRenamedNewName: log.Println("Created:", ei.Path()) case notify.FileActionRemoved, notify.FileActionRenamedOldName: log.Println("Removed:", ei.Path()) case notify.FileActionModified: panic("notify: unexpected action") } } }
func (w *watcher) loop() { defer func() { w.ac.mu.Lock() w.running = false w.starting = false w.ac.mu.Unlock() }() err := notify.Watch(w.ac.keydir, w.ev, notify.All) if err != nil { glog.V(logger.Detail).Infof("can't watch %s: %v", w.ac.keydir, err) return } defer notify.Stop(w.ev) glog.V(logger.Detail).Infof("now watching %s", w.ac.keydir) defer glog.V(logger.Detail).Infof("no longer watching %s", w.ac.keydir) w.ac.mu.Lock() w.running = true w.ac.mu.Unlock() // Wait for file system events and reload. // When an event occurs, the reload call is delayed a bit so that // multiple events arriving quickly only cause a single reload. var ( debounce = time.NewTimer(0) debounceDuration = 500 * time.Millisecond inCycle, hadEvent bool ) defer debounce.Stop() for { select { case <-w.quit: return case <-w.ev: if !inCycle { debounce.Reset(debounceDuration) inCycle = true } else { hadEvent = true } case <-debounce.C: w.ac.mu.Lock() w.ac.reload() w.ac.mu.Unlock() if hadEvent { debounce.Reset(debounceDuration) inCycle, hadEvent = true, false } else { inCycle, hadEvent = false, false } } } }
// This example shows how to work with EventInfo's underlying FSEvent struct. // Investigating notify.(*FSEvent).Flags field we are able to say whether // the event's path is a file or a directory and many more. func ExampleWatch_darwinDirFileSymlink() { var must = func(err error) { if err != nil { log.Fatal(err) } } var stop = func(c ...chan<- notify.EventInfo) { for _, c := range c { notify.Stop(c) } } // Make the channels buffered to ensure no event is dropped. Notify will drop // an event if the receiver is not able to keep up the sending pace. dir := make(chan notify.EventInfo, 1) file := make(chan notify.EventInfo, 1) symlink := make(chan notify.EventInfo, 1) all := make(chan notify.EventInfo, 1) // Set up a single watchpoint listening for FSEvents-specific events on // multiple user-provided channels. must(notify.Watch(".", dir, notify.FSEventsIsDir)) must(notify.Watch(".", file, notify.FSEventsIsFile)) must(notify.Watch(".", symlink, notify.FSEventsIsSymlink)) must(notify.Watch(".", all, notify.All)) defer stop(dir, file, symlink, all) // Block until an event is received. select { case ei := <-dir: log.Println("The directory", ei.Path(), "has changed") case ei := <-file: log.Println("The file", ei.Path(), "has changed") case ei := <-symlink: log.Println("The symlink", ei.Path(), "has changed") case ei := <-all: var kind string // Investigate underlying *notify.FSEvent struct to access more // information about the event. switch flags := ei.Sys().(*notify.FSEvent).Flags; { case flags¬ify.FSEventsIsFile != 0: kind = "file" case flags¬ify.FSEventsIsDir != 0: kind = "dir" case flags¬ify.FSEventsIsSymlink != 0: kind = "symlink" } log.Printf("The %s under path %s has been %sd\n", kind, ei.Path(), ei.Event()) } }
func (m *Manager) notifyLoop() { defer notify.Stop(m.eventsChan) for { select { case ev := <-m.eventsChan: m.fileChanged(ev.Path()) case <-m.stopChan: return } } }
func watchFile() { c := make(chan notify.EventInfo, 1) if err := notify.Watch("./users.txt", c, 0x04000); err != nil { fmt.Println("error watching users file", err) } defer notify.Stop(c) // Block until an event is received. ei := <-c fmt.Println("Users - watchFile - users file has been changed", ei.Event()) parseAndSetUsers() go watchFile() }
func (d *Dispatcher) reload() { for { s := <-d.signal d.log.Infof("Received %s, reloading configuration", s) cfg, err := ReadConfig(d.Config.filename) if err == nil { d.log.Info("Removing all watches") notify.Stop(d.watcher) d.Config = cfg d.watch() } else { d.log.WithError(err).Errorf("Failed to read config") } } }
func handleOsSignal(watch chan notify.EventInfo) { osSignal := make(chan os.Signal, 1) signal.Notify(osSignal, os.Interrupt) go func() { for { signalNumber := <-osSignal if signalNumber == syscall.SIGINT || signalNumber == syscall.SIGKILL { notify.Stop(watch) os.Exit(1) } } }() }
func main() { // Make the channel buffered to ensure no event is dropped. Notify will drop // an event if the receiver is not able to keep up the sending pace. c := make(chan notify.EventInfo, 1) // Set up a watchpoint listening on events within current working directory. // Dispatch each create and remove events separately to c. if err := notify.Watch(".", c, notify.Create, notify.Remove); err != nil { log.Fatal(err) } defer notify.Stop(c) // Block until an event is received. ei := <-c log.Println("Got event:", ei) }
// This example shows how to set up a recursive watchpoint. func ExampleWatch_recursive() { // Make the channel buffered to ensure no event is dropped. Notify will drop // an event if the receiver is not able to keep up the sending pace. c := make(chan notify.EventInfo, 1) // Set up a watchpoint listening for events within a directory tree rooted // at current working directory. Dispatch remove events to c. if err := notify.Watch("./...", c, notify.Remove); err != nil { log.Fatal(err) } defer notify.Stop(c) // Block until an event is received. ei := <-c log.Println("Got event:", ei) }
func main() { repotmp := "/repo/PKGBUILD/" currentuser, _ := user.Current() homedirs, _ := getHomes("/home/*") logFile := StartLog("/var/log/pkgbuild.log", currentuser) defer logFile.Close() Info.Println("\n\n\t\tI don't know who you are\n\t\tI don't know what you are syncing\n\t\tIf you are syncing via rsync, I can tell you \n\t\tI don't have the condition to pick it\n\t\tBut what I do have are a very particular set of channels\n\t\tChannels that pick up debs and push it to the repo\n\t\tI will look for debs in", homedirs, ", \n\t\tI will find it, and I will add it to repo . . .\n") fmt.Println("\n\n\t\tI don't know who you are\n\t\tI don't know what you are syncing\n\t\tIf you are syncing via rsync, I can tell you \n\t\tI don't have the condition to pick it\n\t\tBut what I do have are a very particular set of channels\n\t\tChannels that pick up debs and push it to the repo\n\t\tI will look for debs in", homedirs, ", \n\t\tI will find it, and I will add it to repo . . .\n") Info.Println("Starting taken . . .\nUse scp to copy deb files.") fmt.Println("Starting taken . . .\nUse scp to copy deb files.") Info.Println("Deb files will be moved to ", repotmp, "before pushing to repo") c := make(chan notify.EventInfo, 20) for _, i := range homedirs { if err := notify.Watch(i, c, notify.InCloseWrite, notify.Create); err != nil { log.Fatal(err) } } /*if err := notify.Watch("/home/girishg/", c, notify.InCloseWrite, notify.All); err != nil { log.Fatal(err) } if err := notify.Watch("/home/anotheruser/", c, notify.InCloseWrite, notify.All); err != nil { log.Fatal(err) }*/ defer notify.Stop(c) for ei := range c { switch ei.Event() { case notify.Create: Info.Println(ei.Event(), ei.Path()) case notify.InCloseWrite: Info.Println(ei.Event(), ei.Path()) if ValidateDeb(ei.Path()) { debfile := moveDebs(ei.Path(), repotmp) CallAptlyAdd(debfile) CallAptlyShow() CallAptlyPublish() } } } }
// Unmonitor the given path. func (f *FileMonitor) Unmonitor(id string, globs []*glob.Glob) { for _, g := range globs { entries, ok := f.monitors[g.Dir()] if !ok { continue } entry, ok := entries[id] if !ok { continue } entry.globs.Remove(g) if len(entry.globs) == 0 { notify.Stop(entry.ch) close(entry.ch) delete(entries, id) } } }
// This example shows how to use Sys() method from EventInfo interface to tie // two separate events generated by rename(2) function. func ExampleWatch_linuxMove() { // Make the channel buffered to ensure no event is dropped. Notify will drop // an event if the receiver is not able to keep up the sending pace. c := make(chan notify.EventInfo, 2) // Set up a watchpoint listening for inotify-specific events within a // current working directory. Dispatch each InMovedFrom and InMovedTo // events separately to c. if err := notify.Watch(".", c, notify.InMovedFrom, notify.InMovedTo); err != nil { log.Fatal(err) } defer notify.Stop(c) // Inotify reports move filesystem action by sending two events tied with // unique cookie value (uint32): one of the events is of InMovedFrom type // carrying move source path, while the second one is of InMoveTo type // carrying move destination path. moves := make(map[uint32]struct { From string To string }) // Wait for moves. for ei := range c { cookie := ei.Sys().(*syscall.InotifyEvent).Cookie info := moves[cookie] switch ei.Event() { case notify.InMovedFrom: info.From = ei.Path() case notify.InMovedTo: info.To = ei.Path() } moves[cookie] = info if cookie != 0 && info.From != "" && info.To != "" { log.Println("File:", info.From, "was renamed to", info.To) delete(moves, cookie) } } }
// This example shows how to use FSEvents-specifc event values. func ExampleWatch_darwin() { // Make the channel buffered to ensure no event is dropped. Notify will drop // an event if the receiver is not able to keep up the sending pace. c := make(chan notify.EventInfo, 1) // Set up a watchpoint listening for FSEvents-specific events within a // current working directory. Dispatch each FSEventsChangeOwner and FSEventsMount // events separately to c. if err := notify.Watch(".", c, notify.FSEventsChangeOwner, notify.FSEventsMount); err != nil { log.Fatal(err) } defer notify.Stop(c) // Block until an event is received. switch ei := <-c; ei.Event() { case notify.FSEventsChangeOwner: log.Println("The owner of", ei.Path(), "has changed.") case notify.FSEventsMount: log.Println("The path", ei.Path(), "has been mounted.") } }
// This example shows how to watch changes made on file-system by text editor // when saving a file. Usually, either InCloseWrite or InMovedTo (when swapping // with a temporary file) event is created. func ExampleWatch_linux() { // Make the channel buffered to ensure no event is dropped. Notify will drop // an event if the receiver is not able to keep up the sending pace. c := make(chan notify.EventInfo, 1) // Set up a watchpoint listening for inotify-specific events within a // current working directory. Dispatch each InCloseWrite and InMovedTo // events separately to c. if err := notify.Watch(".", c, notify.InCloseWrite, notify.InMovedTo); err != nil { log.Fatal(err) } defer notify.Stop(c) // Block until an event is received. switch ei := <-c; ei.Event() { case notify.InCloseWrite: log.Println("Editing of", ei.Path(), "file is done.") case notify.InMovedTo: log.Println("File", ei.Path(), "was swapped/moved into the watched directory.") } }
/* Monitoring changes in file system. It designed for run in separate goroutine. */ func fileMon(path string, bus chan fileChangeEvent) { // Make the channel buffered to ensure no event is dropped. Notify will drop // an event if the receiver is not able to keep up the sending pace. c := make(chan notify.EventInfo, 1) // Set up a watchpoint listening on events within current working directory. // Dispatch each create and remove events separately to c. if err := notify.Watch(path+"/...", c, notify.All); err != nil { log.Fatal(err) } defer notify.Stop(c) // Block until an event is received. for { event := <-c fstat, err := os.Lstat(event.Path()) if os.IsNotExist(err) { bus <- fileChangeEvent{Path: event.Path(), IsRemoved: true} continue } if err != nil { log.Println(err) continue } if fstat.IsDir() { bus <- fileChangeEvent{Path: event.Path(), IsDir: true} continue } content, err := ioutil.ReadFile(event.Path()) if err != nil { log.Println(err) } bus <- fileChangeEvent{Path: event.Path(), Content: content} } }
// Watch watches a set of paths. Mod structs representing a changeset are sent // on the channel ch. // // Watch applies heuristics to cope with transient files and unreliable event // notifications. Modifications are batched up until there is a a lull in the // stream of changes of duration lullTime. This lets us represent processes // that progressively affect multiple files, like rendering, as a single // changeset. // // All paths emitted are slash-delimited. func Watch(paths []string, lullTime time.Duration, ch chan *Mod) (*Watcher, error) { evtch := make(chan notify.EventInfo, 4096) for _, p := range paths { err := notify.Watch(p, evtch, notify.All) if err != nil { notify.Stop(evtch) return nil, err } } go func() { for { b := batch(lullTime, MaxLullWait, statExistenceChecker{}, evtch) if b != nil && !b.Empty() { ret, err := b.normPaths(paths) if err != nil { Logger.Shout("Error normalising paths: %s", err) } ch <- ret } } }() return &Watcher{evtch}, nil }
// Stop watching func (w *Watcher) Stop() { notify.Stop(w.evtch) }
func (w *watcher) Close() { notify.Stop(w.events) }
func main() { setVerbosity() // Get port or die. port := getEnv("PORT") // Get content or die. getContent() root := getRoot() log.WithField("Root", root).Info("Our root directory") // We'll parse and store the responses ahead of time. resps, err := pages.Load(root) if err != nil { log.Fatalf("pages.Load: unexpected error: %s", err) } log.WithField("Resps", resps).Debug("The parsed responses") responses = Atomic{Resps: resps} log.Info("Starting server.") log.Info("Listening on port: ", port) // If jumpfile exists. if _, err := os.Stat(root + "/jumpfile.json"); err == nil { buf, err := ioutil.ReadFile(root + "/jumpfile.json") if err != nil { log.Warningln("jumpfile readfile: unexpected error: %s", err) } err = json.Unmarshal(buf, &jumpfile) if err != nil { log.Warningln("jumpfile unmarshal: unexpected error: %s", err) } log.Debugln(jumpfile) } else { log.Infoln("No jumpfile found") } // Our request handler. http.HandleFunc("/", handler) if watch { events := make(chan notify.EventInfo, 5) if err := notify.Watch(fmt.Sprintf("%s/...", root), events, notify.Create, notify.Remove, notify.Write, notify.Rename); err != nil { log.Warningln("notify.Watch:", err) } defer notify.Stop(events) go func() { for event := range events { log.Info("event:", event) // Lacks error handling as this should not run in production. responses.Resps, _ = pages.Load(getRoot()) } }() } // Listen on port and serve with our handler. err = http.ListenAndServe(":"+port, nil) if err != nil { panic(err) } }
// Stop - Stops watcher. func (w *Watcher) Stop() { if w.events != nil { notify.Stop(w.events) close(w.events) } }
// Watches for all fs events on an input path. func (f *fsClient) Watch(params watchParams) (*watchObject, *probe.Error) { eventChan := make(chan Event) errorChan := make(chan *probe.Error) doneChan := make(chan bool) // Make the channel buffered to ensure no event is dropped. Notify will drop // an event if the receiver is not able to keep up the sending pace. neventChan := make(chan notify.EventInfo, 1) var fsEvents []notify.Event for _, event := range params.events { switch event { case "put": fsEvents = append(fsEvents, EventTypePut...) case "delete": fsEvents = append(fsEvents, EventTypeDelete...) default: return nil, errInvalidArgument().Trace(event) } } // Set up a watchpoint listening for events within a directory tree rooted // at current working directory. Dispatch remove events to c. recursivePath := f.PathURL.Path if params.recursive { recursivePath = f.PathURL.Path + "..." } if e := notify.Watch(recursivePath, neventChan, fsEvents...); e != nil { return nil, probe.NewError(e) } // wait for doneChan to close the watcher, eventChan and errorChan go func() { <-doneChan close(eventChan) close(errorChan) notify.Stop(neventChan) }() timeFormatFS := "2006-01-02T15:04:05.000Z" // Get fsnotify notifications for events and errors, and sent them // using eventChan and errorChan go func() { for { select { case event, ok := <-neventChan: if !ok { return } if isIgnoredFile(event.Path()) { continue } var i os.FileInfo if IsPutEvent(event.Event()) { // Look for any writes, send a response to indicate a full copy. var e error i, e = os.Stat(event.Path()) if e != nil { if os.IsNotExist(e) { continue } errorChan <- probe.NewError(e) continue } if i.IsDir() { // we want files continue } eventChan <- Event{ Time: time.Now().Format(timeFormatFS), Size: i.Size(), Path: event.Path(), Client: f, Type: EventCreate, } } else if IsDeleteEvent(event.Event()) { eventChan <- Event{ Time: time.Now().Format(timeFormatFS), Path: event.Path(), Client: f, Type: EventRemove, } } } } }() return &watchObject{ events: eventChan, errors: errorChan, done: doneChan, }, nil }