コード例 #1
0
ファイル: example_fsevents_test.go プロジェクト: kaocs/notify
// 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
		}
	}
}
コード例 #2
0
ファイル: main.go プロジェクト: neil-ca-moore/language-tool
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
}
コード例 #3
0
ファイル: example_test.go プロジェクト: kaocs/notify
// 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")
	}
}
コード例 #4
0
ファイル: watch_fsevents.go プロジェクト: zchee/go-sandbox
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.")
	// }
}
コード例 #5
0
ファイル: example_readdcw_test.go プロジェクト: kaocs/notify
// 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")
		}
	}
}
コード例 #6
0
ファイル: watch.go プロジェクト: expanse-project/go-expanse
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
			}
		}
	}
}
コード例 #7
0
ファイル: example_fsevents_test.go プロジェクト: kaocs/notify
// 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&notify.FSEventsIsFile != 0:
			kind = "file"
		case flags&notify.FSEventsIsDir != 0:
			kind = "dir"
		case flags&notify.FSEventsIsSymlink != 0:
			kind = "symlink"
		}

		log.Printf("The %s under path %s has been %sd\n", kind, ei.Path(), ei.Event())
	}
}
コード例 #8
0
ファイル: assetmgr.go プロジェクト: hlandau/degoutils
func (m *Manager) notifyLoop() {
	defer notify.Stop(m.eventsChan)

	for {
		select {
		case ev := <-m.eventsChan:
			m.fileChanged(ev.Path())

		case <-m.stopChan:
			return
		}
	}
}
コード例 #9
0
ファイル: Users.go プロジェクト: LicaSterian/unsub
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()
}
コード例 #10
0
ファイル: dispatcher.go プロジェクト: martinp/gounpack
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")
		}
	}
}
コード例 #11
0
ファイル: main.go プロジェクト: unbalancedparentheses/stalk
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)
			}
		}
	}()
}
コード例 #12
0
ファイル: eventwatch.go プロジェクト: zchee/go-sandbox
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)
}
コード例 #13
0
ファイル: example_test.go プロジェクト: kaocs/notify
// 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)
}
コード例 #14
0
ファイル: taken.go プロジェクト: nohupped/taken
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()
			}

		}

	}

}
コード例 #15
0
ファイル: monitor.go プロジェクト: alecthomas/buildkit
// 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)
		}
	}
}
コード例 #16
0
ファイル: example_inotify_test.go プロジェクト: kaocs/notify
// 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)
		}
	}
}
コード例 #17
0
ファイル: example_fsevents_test.go プロジェクト: kaocs/notify
// 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.")
	}
}
コード例 #18
0
ファイル: example_inotify_test.go プロジェクト: kaocs/notify
// 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.")
	}
}
コード例 #19
0
ファイル: main.go プロジェクト: fanyang1988/etcddir
/*
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}
	}
}
コード例 #20
0
ファイル: watch.go プロジェクト: shaunstanislaus/modd
// 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
}
コード例 #21
0
ファイル: watch.go プロジェクト: johnjohnsp1/modd
// Stop watching
func (w *Watcher) Stop() {
	notify.Stop(w.evtch)
}
コード例 #22
0
ファイル: main.go プロジェクト: getapp/golisten
func (w *watcher) Close() {
	notify.Stop(w.events)
}
コード例 #23
0
ファイル: taitan.go プロジェクト: datasektionen/taitan
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)
	}
}
コード例 #24
0
ファイル: watcher.go プロジェクト: crackcomm/renderer
// Stop - Stops watcher.
func (w *Watcher) Stop() {
	if w.events != nil {
		notify.Stop(w.events)
		close(w.events)
	}
}
コード例 #25
0
ファイル: client-fs.go プロジェクト: balamurugana/mc
// 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
}