--watch
This commit is contained in:
250
vendor/github.com/andreaskoch/go-fswatch/folder.go
generated
vendored
Normal file
250
vendor/github.com/andreaskoch/go-fswatch/folder.go
generated
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
// Copyright 2013 Andreas Koch. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package fswatch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
var numberOfFolderWatchers int
|
||||
|
||||
func init() {
|
||||
numberOfFolderWatchers = 0
|
||||
}
|
||||
|
||||
func NumberOfFolderWatchers() int {
|
||||
return numberOfFolderWatchers
|
||||
}
|
||||
|
||||
type FolderWatcher struct {
|
||||
changeDetails chan *FolderChange
|
||||
|
||||
modified chan bool
|
||||
moved chan bool
|
||||
stopped chan bool
|
||||
|
||||
recurse bool
|
||||
skipFile func(path string) bool
|
||||
|
||||
debug bool
|
||||
folder string
|
||||
running bool
|
||||
wasStopped bool
|
||||
checkInterval time.Duration
|
||||
|
||||
previousEntries []string
|
||||
}
|
||||
|
||||
func NewFolderWatcher(folderPath string, recurse bool, skipFile func(path string) bool, checkIntervalInSeconds int) *FolderWatcher {
|
||||
|
||||
if checkIntervalInSeconds < 1 {
|
||||
panic(fmt.Sprintf("Cannot create a folder watcher with a check interval of %v seconds.", checkIntervalInSeconds))
|
||||
}
|
||||
|
||||
return &FolderWatcher{
|
||||
|
||||
modified: make(chan bool),
|
||||
moved: make(chan bool),
|
||||
stopped: make(chan bool),
|
||||
|
||||
changeDetails: make(chan *FolderChange),
|
||||
|
||||
recurse: recurse,
|
||||
skipFile: skipFile,
|
||||
|
||||
debug: true,
|
||||
folder: folderPath,
|
||||
checkInterval: time.Duration(checkIntervalInSeconds),
|
||||
}
|
||||
}
|
||||
|
||||
func (folderWatcher *FolderWatcher) String() string {
|
||||
return fmt.Sprintf("Folderwatcher %q", folderWatcher.folder)
|
||||
}
|
||||
|
||||
func (folderWatcher *FolderWatcher) Modified() chan bool {
|
||||
return folderWatcher.modified
|
||||
}
|
||||
|
||||
func (folderWatcher *FolderWatcher) Moved() chan bool {
|
||||
return folderWatcher.moved
|
||||
}
|
||||
|
||||
func (folderWatcher *FolderWatcher) Stopped() chan bool {
|
||||
return folderWatcher.stopped
|
||||
}
|
||||
|
||||
func (folderWatcher *FolderWatcher) ChangeDetails() chan *FolderChange {
|
||||
return folderWatcher.changeDetails
|
||||
}
|
||||
|
||||
func (folderWatcher *FolderWatcher) Start() {
|
||||
folderWatcher.running = true
|
||||
sleepInterval := time.Second * folderWatcher.checkInterval
|
||||
|
||||
go func() {
|
||||
|
||||
// get existing entries
|
||||
var entryList []string
|
||||
directory := folderWatcher.folder
|
||||
|
||||
previousEntryList := folderWatcher.getPreviousEntryList()
|
||||
|
||||
if previousEntryList != nil {
|
||||
|
||||
// use the entry list from a previous run
|
||||
entryList = previousEntryList
|
||||
|
||||
} else {
|
||||
|
||||
// use a new entry list
|
||||
newEntryList, _ := getFolderEntries(directory, folderWatcher.recurse, folderWatcher.skipFile)
|
||||
entryList = newEntryList
|
||||
}
|
||||
|
||||
// increment watcher count
|
||||
numberOfFolderWatchers++
|
||||
|
||||
for folderWatcher.wasStopped == false {
|
||||
|
||||
// get new entries
|
||||
updatedEntryList, _ := getFolderEntries(directory, folderWatcher.recurse, folderWatcher.skipFile)
|
||||
|
||||
// check for new items
|
||||
newItems := make([]string, 0)
|
||||
modifiedItems := make([]string, 0)
|
||||
|
||||
for _, entry := range updatedEntryList {
|
||||
|
||||
if isNewItem := !sliceContainsElement(entryList, entry); isNewItem {
|
||||
// entry is new
|
||||
newItems = append(newItems, entry)
|
||||
continue
|
||||
}
|
||||
|
||||
// check if the file changed
|
||||
if newModTime, err := getLastModTimeFromFile(entry); err == nil {
|
||||
|
||||
// check if file has been modified
|
||||
timeOfLastCheck := time.Now().Add(sleepInterval * -1)
|
||||
|
||||
if timeOfLastCheck.Before(newModTime) {
|
||||
|
||||
// existing entry has been modified
|
||||
modifiedItems = append(modifiedItems, entry)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// check for moved items
|
||||
movedItems := make([]string, 0)
|
||||
for _, entry := range entryList {
|
||||
isMoved := !sliceContainsElement(updatedEntryList, entry)
|
||||
if isMoved {
|
||||
movedItems = append(movedItems, entry)
|
||||
}
|
||||
}
|
||||
|
||||
// assign the new list
|
||||
entryList = updatedEntryList
|
||||
|
||||
// sleep
|
||||
time.Sleep(sleepInterval)
|
||||
|
||||
// check if something happened
|
||||
if len(newItems) > 0 || len(movedItems) > 0 || len(modifiedItems) > 0 {
|
||||
|
||||
// send out change
|
||||
go func() {
|
||||
folderWatcher.modified <- true
|
||||
}()
|
||||
|
||||
go func() {
|
||||
log("Folder %q changed", directory)
|
||||
folderWatcher.changeDetails <- newFolderChange(newItems, movedItems, modifiedItems)
|
||||
}()
|
||||
} else {
|
||||
log("No change in folder %q", directory)
|
||||
}
|
||||
}
|
||||
|
||||
folderWatcher.running = false
|
||||
|
||||
// capture the entry list for a restart
|
||||
folderWatcher.captureEntryList(entryList)
|
||||
|
||||
// inform channel-subscribers
|
||||
go func() {
|
||||
folderWatcher.stopped <- true
|
||||
}()
|
||||
|
||||
// decrement the watch counter
|
||||
numberOfFolderWatchers--
|
||||
|
||||
// final log message
|
||||
log("Stopped folder watcher %q", folderWatcher.String())
|
||||
}()
|
||||
}
|
||||
|
||||
func (folderWatcher *FolderWatcher) Stop() {
|
||||
log("Stopping folder watcher %q", folderWatcher.String())
|
||||
folderWatcher.wasStopped = true
|
||||
}
|
||||
|
||||
func (folderWatcher *FolderWatcher) IsRunning() bool {
|
||||
return folderWatcher.running
|
||||
}
|
||||
|
||||
func (folderWatcher *FolderWatcher) getPreviousEntryList() []string {
|
||||
return folderWatcher.previousEntries
|
||||
}
|
||||
|
||||
// Remember the entry list for a later restart
|
||||
func (folderWatcher *FolderWatcher) captureEntryList(list []string) {
|
||||
folderWatcher.previousEntries = list
|
||||
}
|
||||
|
||||
func getFolderEntries(directory string, recurse bool, skipFile func(path string) bool) ([]string, error) {
|
||||
|
||||
// the return array
|
||||
entries := make([]string, 0)
|
||||
|
||||
// read the entries of the specified directory
|
||||
directoryEntries, err := ioutil.ReadDir(directory)
|
||||
if err != nil {
|
||||
return entries, err
|
||||
}
|
||||
|
||||
for _, entry := range directoryEntries {
|
||||
|
||||
// get the full path
|
||||
subEntryPath := filepath.Join(directory, entry.Name())
|
||||
|
||||
// recurse or append
|
||||
if recurse && entry.IsDir() {
|
||||
|
||||
// recurse (ignore errors, unreadable sub directories don't hurt much)
|
||||
subFolderEntries, _ := getFolderEntries(subEntryPath, recurse, skipFile)
|
||||
entries = append(entries, subFolderEntries...)
|
||||
|
||||
} else {
|
||||
|
||||
// check if the enty shall be ignored
|
||||
if skipFile(subEntryPath) {
|
||||
continue
|
||||
}
|
||||
|
||||
// append entry
|
||||
entries = append(entries, subEntryPath)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return entries, nil
|
||||
}
|
Reference in New Issue
Block a user