func (w watcher) pipeEvents(events chan interface{}) {
	for {
		select {
		case ev := <-w.Event:
			events <- ev
		case err := <-w.Error:
			log.Println("fsnotify error:", err)
		}
	}
}
pipeEvents sends valid events to `events` and errors to stderr
package main
import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
	"github.com/howeyc/fsnotify"
)
var (
	verbose = flag.Bool("v", false, "verbose")
	depth   = flag.Int("depth", 1, "recursion depth")
	dir     = flag.String("dir", ".", "directory root to use for watching")
	quiet   = flag.Duration("quiet", 800*time.Millisecond, "quiet period after command execution")
	wait    = flag.Duration("wait", 10*time.Millisecond, "time to wait between change detection and exec")
	ignore  = flag.String("ignore", "", "path ignore pattern")
)
func usage() {
	fmt.Fprintf(os.Stderr, "usage: %s [flags] [command to execute and args]\n", os.Args[0])
	flag.PrintDefaults()
}
func main() {
	flag.Usage = usage
	flag.Parse()
	watcher, err := newWatcher()
	if err != nil {
		log.Fatal(err)
	}
	if len(flag.Args()) == 0 {
		flag.Usage()
		os.Exit(1)
	}
	cmd, args := flag.Args()[0], flag.Args()[1:]
	fileEvents := make(chan interface{}, 100)
	go watcher.pipeEvents(fileEvents)
	if *ignore != "" {
		fileEvents = filter(fileEvents, func(e interface{}) bool {
			fe := e.(*fsnotify.FileEvent)
			wd, _ := os.Getwd()
			relPath, _ := filepath.Rel(wd, fe.Name)
			ignored, err := filepath.Match(*ignore, relPath)
			if err != nil {
				fmt.Fprintln(os.Stderr, "error performing match:", err)
			}
			return !ignored
		})
	}
	go watchAndExecute(fileEvents, cmd, args)
	defer watcher.Close()
	dir, err := filepath.Abs(*dir)
	if err != nil {
		log.Fatal(err)
	}
	err = watcher.watchDirAndChildren(dir, *depth)
	if err != nil {
		log.Fatal(err)
	}
	select {}
}
type watcher struct {
	*fsnotify.Watcher
}
func newWatcher() (watcher, error) {
	fsnw, err := fsnotify.NewWatcher()
	return watcher{fsnw}, err
}
func watchAndExecute(fileEvents chan interface{}, cmd string, args []string) {
	for {
		time.Sleep(*wait)
		c := exec.Command(cmd, args...)
		c.Stdout = os.Stdout
		c.Stderr = os.Stderr
		c.Stdin = os.Stdin
		fmt.Fprintln(os.Stderr, "running", cmd, args)
		if err := c.Run(); err != nil {
			fmt.Fprintln(os.Stderr, "error running:", err)
		}
		if *verbose {
			fmt.Fprintln(os.Stderr, "done.")
		}
		drainFor(*quiet, fileEvents)
		ev := <-fileEvents
		if *verbose {
			fmt.Fprintln(os.Stderr, "File changed:", ev)
		}
	}
}
func (w watcher) watchDirAndChildren(path string, depth int) error {
	if err := w.Watch(path); err != nil {
		return err
	}
	baseNumSeps := strings.Count(path, string(os.PathSeparator))
	return filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			pathDepth := strings.Count(path, string(os.PathSeparator)) - baseNumSeps
			if pathDepth > depth {
				return filepath.SkipDir
			}
			if *verbose {
				fmt.Fprintln(os.Stderr, "Watching", path)
			}
			if err := w.Watch(path); err != nil {
				return err
			}
		}
		return nil
	})
}