func matches(s, pattern string) bool {
	return regexp.MustCompile(pattern).MatchString(s)
}
Returns whether 's' matches 'pattern'
package main
import (
	"flag"
	"fmt"
	"github.com/howeyc/fsnotify"
	"github.com/remogatto/application"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"sync"
	"syscall"
	"time"
)
const (
	DISCARD_TIME = 1 * time.Second
	RERUN_TIME   = 2 * time.Second
)
var (
	events  map[string]*eventOnFile
	rwMutex sync.RWMutex
)
type eventOnFile struct {
	fsnotifyEvent *fsnotify.FileEvent
	time          time.Time
}
func addEvent(event *eventOnFile) *eventOnFile {
	rwMutex.Lock()
	events[event.fsnotifyEvent.Name] = event
	rwMutex.Unlock()
	return event
}
func getEvent(filename string) *eventOnFile {
	rwMutex.RLock()
	event, ok := events[filename]
	rwMutex.RUnlock()
	if ok {
		return event
	}
	return nil
}
type sigterm struct {
	hitCounter byte
	paths   []string
}
func (h *sigterm) HandleSignal(s os.Signal) {
	switch ss := s.(type) {
	case syscall.Signal:
		switch ss {
		case syscall.SIGTERM, syscall.SIGINT:
			if h.hitCounter > 0 {
				application.Exit()
				return
			}
			application.Printf("Hit CTRL-C again to exit, otherwise tests will run again in %s.", RERUN_TIME)
			h.hitCounter++
			go func() {
				time.Sleep(RERUN_TIME)
				execGoTest(h.paths)
				h.hitCounter = 0
			}()
		}
	}
}
type watcherLoop struct {
	pause, terminate chan int
	initialPath string
	paths         []string
}
func newWatcherLoop(initialPath string) *watcherLoop {
	return &watcherLoop{make(chan int), make(chan int), initialPath, folders(initialPath)}
}
func (l *watcherLoop) Pause() chan int {
	return l.pause
}
func (l *watcherLoop) Terminate() chan int {
	return l.terminate
}
func (l *watcherLoop) Run() {
	execGoTest(l.paths)
	watcher, err := fsnotify.NewWatcher()
	for _, path := range l.paths {
		err = watcher.Watch(path)
		if err != nil {
			application.Fatal(err.Error())
		}
		application.Printf("Start watching path %s", path)
	}
	for {
		select {
		case <-l.pause:
			l.pause <- 0
		case <-l.terminate:
			watcher.Close()
			l.terminate <- 0
			return
		case ev := <-watcher.Event:
			if ev.IsModify() {
				if matches(ev.Name, ".*\\.go$") {
					if application.Verbose {
						application.Logf("Event %s occured for file %s", ev, ev.Name)
					}
					event := getEvent(ev.Name)
					if event == nil {
						event = addEvent(&eventOnFile{ev, time.Now()})
						application.Logf("Run the tests")
						execGoTest(l.paths)
					} else if time.Now().Sub(event.time) > DISCARD_TIME {
						event.time = time.Now()
						application.Logf("Run the tests")
						execGoTest(l.paths)
					} else {
						if application.Verbose {
							application.Logf("Event %s was discarded for file %s", ev, ev.Name)
						}
					}
				}
			}
		case err := <-watcher.Error:
			application.Fatal(err.Error())
		}
	}
}
func usage() {
	fmt.Fprintf(os.Stderr, "PrettyAutoTest continously watches for changes in folder and re-run the tests\n\n")
	fmt.Fprintf(os.Stderr, "Usage:\n\n")
	fmt.Fprintf(os.Stderr, "\tprettyautotest [options]\n\n")
	fmt.Fprintf(os.Stderr, "Options are:\n\n")
	flag.PrintDefaults()
}