summaryrefslogtreecommitdiff
path: root/src/mongo/gotools/vendor/src/github.com/smartystreets/goconvey/web/server/watch/integration.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/gotools/vendor/src/github.com/smartystreets/goconvey/web/server/watch/integration.go')
-rw-r--r--src/mongo/gotools/vendor/src/github.com/smartystreets/goconvey/web/server/watch/integration.go185
1 files changed, 185 insertions, 0 deletions
diff --git a/src/mongo/gotools/vendor/src/github.com/smartystreets/goconvey/web/server/watch/integration.go b/src/mongo/gotools/vendor/src/github.com/smartystreets/goconvey/web/server/watch/integration.go
new file mode 100644
index 00000000000..941241ab86a
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/smartystreets/goconvey/web/server/watch/integration.go
@@ -0,0 +1,185 @@
+package watch
+
+import (
+ "log"
+ "os"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/smartystreets/goconvey/web/server/messaging"
+)
+
+type Watcher struct {
+ nap time.Duration
+ rootFolder string
+ folderDepth int
+ ignoredFolders map[string]struct{}
+ fileSystemState int64
+ paused bool
+ stopped bool
+ watchSuffixes []string
+ excludedDirs []string
+
+ input chan messaging.WatcherCommand
+ output chan messaging.Folders
+
+ lock sync.RWMutex
+}
+
+func NewWatcher(rootFolder string, folderDepth int, nap time.Duration,
+ input chan messaging.WatcherCommand, output chan messaging.Folders, watchSuffixes string, excludedDirs []string) *Watcher {
+
+ return &Watcher{
+ nap: nap,
+ rootFolder: rootFolder,
+ folderDepth: folderDepth,
+ input: input,
+ output: output,
+ watchSuffixes: strings.Split(watchSuffixes, ","),
+ excludedDirs: excludedDirs,
+
+ ignoredFolders: make(map[string]struct{}),
+ }
+}
+
+func (this *Watcher) Listen() {
+ for {
+ if this.stopped {
+ return
+ }
+
+ select {
+
+ case command := <-this.input:
+ this.respond(command)
+
+ default:
+ if !this.paused {
+ this.scan()
+ }
+ time.Sleep(nap)
+ }
+ }
+}
+
+func (this *Watcher) respond(command messaging.WatcherCommand) {
+ switch command.Instruction {
+
+ case messaging.WatcherAdjustRoot:
+ log.Println("Adjusting root...")
+ this.rootFolder = command.Details
+ this.execute()
+
+ case messaging.WatcherIgnore:
+ log.Println("Ignoring specified folders")
+ this.ignore(command.Details)
+ // Prevent a filesystem change due to the number of active folders changing
+ _, checksum := this.gather()
+ this.set(checksum)
+
+ case messaging.WatcherReinstate:
+ log.Println("Reinstating specified folders")
+ this.reinstate(command.Details)
+ // Prevent a filesystem change due to the number of active folders changing
+ _, checksum := this.gather()
+ this.set(checksum)
+
+ case messaging.WatcherPause:
+ log.Println("Pausing watcher...")
+ this.paused = true
+
+ case messaging.WatcherResume:
+ log.Println("Resuming watcher...")
+ this.paused = false
+
+ case messaging.WatcherExecute:
+ log.Println("Gathering folders for immediate execution...")
+ this.execute()
+
+ case messaging.WatcherStop:
+ log.Println("Stopping the watcher...")
+ close(this.output)
+ this.stopped = true
+
+ default:
+ log.Println("Unrecognized command from server:", command.Instruction)
+ }
+}
+
+func (this *Watcher) execute() {
+ folders, _ := this.gather()
+ this.sendToExecutor(folders)
+}
+
+func (this *Watcher) scan() {
+ folders, checksum := this.gather()
+
+ if checksum == this.fileSystemState {
+ return
+ }
+
+ log.Println("File system state modified, publishing current folders...", this.fileSystemState, checksum)
+
+ defer this.set(checksum)
+ this.sendToExecutor(folders)
+}
+
+func (this *Watcher) gather() (folders messaging.Folders, checksum int64) {
+ items := YieldFileSystemItems(this.rootFolder, this.excludedDirs)
+ folderItems, profileItems, goFileItems := Categorize(items, this.rootFolder, this.watchSuffixes)
+
+ for _, item := range profileItems {
+ // TODO: don't even bother if the item's size is over a few hundred bytes...
+ contents := ReadContents(item.Path)
+ item.ProfileDisabled, item.ProfileTags, item.ProfileArguments = ParseProfile(contents)
+ }
+
+ folders = CreateFolders(folderItems)
+ LimitDepth(folders, this.folderDepth)
+ AttachProfiles(folders, profileItems)
+ this.protectedRead(func() { MarkIgnored(folders, this.ignoredFolders) })
+
+ active := ActiveFolders(folders)
+ checksum = int64(len(active))
+ checksum += Sum(active, profileItems)
+ checksum += Sum(active, goFileItems)
+
+ return folders, checksum
+}
+
+func (this *Watcher) set(state int64) {
+ this.fileSystemState = state
+}
+
+func (this *Watcher) sendToExecutor(folders messaging.Folders) {
+ this.output <- folders
+}
+
+func (this *Watcher) ignore(paths string) {
+ this.protectedWrite(func() {
+ for _, folder := range strings.Split(paths, string(os.PathListSeparator)) {
+ this.ignoredFolders[folder] = struct{}{}
+ log.Println("Currently ignored folders:", this.ignoredFolders)
+ }
+ })
+}
+func (this *Watcher) reinstate(paths string) {
+ this.protectedWrite(func() {
+ for _, folder := range strings.Split(paths, string(os.PathListSeparator)) {
+ delete(this.ignoredFolders, folder)
+ }
+ })
+}
+func (this *Watcher) protectedWrite(protected func()) {
+ this.lock.Lock()
+ defer this.lock.Unlock()
+ protected()
+}
+func (this *Watcher) protectedRead(protected func()) {
+ this.lock.RLock()
+ defer this.lock.RUnlock()
+ protected()
+}
+
+const nap = time.Millisecond * 250