github.com/aarzilli/tools@v0.0.0-20151123112009-0d27094f75e0/os/osutilpb/watch_directory.go-disabled-for-appengine (about)

     1  package osutilpb
     2  
     3  // commented due to appengine upload error
     4  // github.com/go-fsnotify/fsnotify/
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"log"
    10  	"os"
    11  	"path/filepath"
    12  	"runtime"
    13  	"strings"
    14  	"sync"
    15  	"time"
    16  
    17  	"github.com/go-fsnotify/fsnotify"
    18  	"github.com/spf13/afero"
    19  	"github.com/spf13/fsync"
    20  	// _ "gopkg.in/fsnotify.v1"
    21  )
    22  
    23  var WorkingDir = "c:\\temp\\"
    24  var FilePathSeparator = "\\"
    25  var serverPort = 1313
    26  var liveReload = false
    27  
    28  var SourceFs afero.Fs = new(afero.OsFs)
    29  var DestinationFS afero.Fs = new(afero.OsFs)
    30  var OsFs afero.Fs = new(afero.OsFs)
    31  
    32  func init() {
    33  	// WatchDir()
    34  }
    35  
    36  func getDirList() []string {
    37  	return []string{"ch1", "ch2"}
    38  
    39  }
    40  
    41  func WatchDir() {
    42  
    43  	// Watch runs its own server as part of the routine
    44  	watched := getDirList()
    45  	workingDir := AbsPathify(WorkingDir)
    46  	for i, dir := range watched {
    47  		watched[i], _ = GetRelativePath(dir, workingDir)
    48  	}
    49  	unique := strings.Join(RemoveSubpaths(watched), ",")
    50  
    51  	fmt.Printf("Watching for changes in %s/{%s}\n", workingDir, unique)
    52  	err := NewWatcher(serverPort)
    53  	if err != nil {
    54  		fmt.Println(err)
    55  	}
    56  
    57  }
    58  
    59  func AbsPathify(inPath string) string {
    60  	if filepath.IsAbs(inPath) {
    61  		return filepath.Clean(inPath)
    62  	}
    63  
    64  	// todo consider move workingDir to argument list
    65  	return filepath.Clean(filepath.Join(WorkingDir, inPath))
    66  }
    67  
    68  func MakeStaticPathRelative(inPath string) (string, error) {
    69  	staticDir := GetStaticDirPath()
    70  	themeStaticDir := GetStaticDirPath()
    71  
    72  	return MakePathRelative(inPath, staticDir, themeStaticDir)
    73  }
    74  
    75  func MakePathRelative(inPath string, possibleDirectories ...string) (string, error) {
    76  
    77  	for _, currentPath := range possibleDirectories {
    78  		if strings.HasPrefix(inPath, currentPath) {
    79  			return strings.TrimPrefix(inPath, currentPath), nil
    80  		}
    81  	}
    82  	return inPath, errors.New("Can't extract relative path, unknown prefix")
    83  }
    84  
    85  func GetStaticDirPath() string {
    86  	return AbsPathify("static")
    87  }
    88  
    89  // GetRelativePath returns the relative path of a given path.
    90  func GetRelativePath(path, base string) (final string, err error) {
    91  	if filepath.IsAbs(path) && base == "" {
    92  		return "", errors.New("source: missing base directory")
    93  	}
    94  	name := filepath.Clean(path)
    95  	base = filepath.Clean(base)
    96  
    97  	name, err = filepath.Rel(base, name)
    98  	if err != nil {
    99  		return "", err
   100  	}
   101  
   102  	if strings.HasSuffix(filepath.FromSlash(path), FilePathSeparator) && !strings.HasSuffix(name, FilePathSeparator) {
   103  		name += FilePathSeparator
   104  	}
   105  	return name, nil
   106  }
   107  
   108  // RemoveSubpaths takes a list of paths and removes everything that
   109  // contains another path in the list as a prefix. Ignores any empty
   110  // strings. Used mostly for logging.
   111  //
   112  // e.g. ["hello/world", "hello", "foo/bar", ""] -> ["hello", "foo/bar"]
   113  func RemoveSubpaths(paths []string) []string {
   114  	a := make([]string, 0)
   115  	for _, cur := range paths {
   116  		// ignore trivial case
   117  		if cur == "" {
   118  			continue
   119  		}
   120  
   121  		isDupe := false
   122  		for i, old := range a {
   123  			if strings.HasPrefix(cur, old) {
   124  				isDupe = true
   125  				break
   126  			} else if strings.HasPrefix(old, cur) {
   127  				a[i] = cur
   128  				isDupe = true
   129  				break
   130  			}
   131  		}
   132  
   133  		if !isDupe {
   134  			a = append(a, cur)
   135  		}
   136  	}
   137  
   138  	return a
   139  }
   140  
   141  // NewWatcher creates a new watcher to watch filesystem events.
   142  func NewWatcher(port int) error {
   143  
   144  	if runtime.GOOS == "darwin" {
   145  		// tweakLimit()
   146  	}
   147  
   148  	watcher, err := NewWatcher2(1 * time.Second)
   149  	var wg sync.WaitGroup
   150  
   151  	if err != nil {
   152  		fmt.Println(err)
   153  		return err
   154  	}
   155  
   156  	defer watcher.Close()
   157  
   158  	wg.Add(1)
   159  
   160  	for _, d := range getDirList() {
   161  		if d != "" {
   162  			_ = watcher.Add(d)
   163  		}
   164  	}
   165  
   166  	go func() {
   167  		for {
   168  			select {
   169  			case evs := <-watcher.Events:
   170  				log.Println("File System Event:", evs)
   171  
   172  				staticChanged := false
   173  				dynamicChanged := false
   174  				staticFilesChanged := make(map[string]bool)
   175  
   176  				for _, ev := range evs {
   177  					ext := filepath.Ext(ev.Name)
   178  					istemp := strings.HasSuffix(ext, "~") || (ext == ".swp") || (ext == ".swx") || (ext == ".tmp") || strings.HasPrefix(ext, ".goutputstream")
   179  					if istemp {
   180  						continue
   181  					}
   182  					// renames are always followed with Create/Modify
   183  					if ev.Op&fsnotify.Rename == fsnotify.Rename {
   184  						continue
   185  					}
   186  
   187  					isstatic := true
   188  					if isstatic {
   189  						if staticPath, err := MakeStaticPathRelative(ev.Name); err == nil {
   190  							staticFilesChanged[staticPath] = true
   191  						}
   192  					}
   193  
   194  					// add new directory to watch list
   195  					if s, err := os.Stat(ev.Name); err == nil && s.Mode().IsDir() {
   196  						if ev.Op&fsnotify.Create == fsnotify.Create {
   197  							watcher.Add(ev.Name)
   198  						}
   199  					}
   200  				}
   201  
   202  				if staticChanged {
   203  					log.Printf("Static file changed, syncing\n\n")
   204  					copyStatic()
   205  
   206  					// livereload.ForceRefresh()
   207  
   208  				}
   209  
   210  				if dynamicChanged {
   211  					fmt.Print("\nChange detected, rebuilding site\n")
   212  				}
   213  			case err := <-watcher.Errors:
   214  				if err != nil {
   215  					fmt.Println("error:", err)
   216  				}
   217  			}
   218  		}
   219  	}()
   220  
   221  	if port > 0 {
   222  		if liveReload {
   223  		}
   224  
   225  		// go serve(port)
   226  	}
   227  
   228  	wg.Wait()
   229  	return nil
   230  }
   231  
   232  // ==================0
   233  
   234  type Batcher struct {
   235  	*fsnotify.Watcher
   236  	interval time.Duration
   237  	done     chan struct{}
   238  
   239  	Events chan []fsnotify.Event // Events are returned on this channel
   240  }
   241  
   242  func NewWatcher2(interval time.Duration) (*Batcher, error) {
   243  	watcher, err := fsnotify.NewWatcher()
   244  
   245  	batcher := &Batcher{}
   246  	batcher.Watcher = watcher
   247  	batcher.interval = interval
   248  	batcher.done = make(chan struct{}, 1)
   249  	batcher.Events = make(chan []fsnotify.Event, 1)
   250  
   251  	if err == nil {
   252  		go batcher.run()
   253  	}
   254  
   255  	return batcher, err
   256  }
   257  
   258  func (b *Batcher) run() {
   259  	tick := time.Tick(b.interval)
   260  	evs := make([]fsnotify.Event, 0)
   261  OuterLoop:
   262  	for {
   263  		select {
   264  		case ev := <-b.Watcher.Events:
   265  			evs = append(evs, ev)
   266  		case <-tick:
   267  			if len(evs) == 0 {
   268  				continue
   269  			}
   270  			b.Events <- evs
   271  			evs = make([]fsnotify.Event, 0)
   272  		case <-b.done:
   273  			break OuterLoop
   274  		}
   275  	}
   276  	close(b.done)
   277  }
   278  
   279  func (b *Batcher) Close() {
   280  	b.done <- struct{}{}
   281  	b.Watcher.Close()
   282  }
   283  
   284  func copyStatic() error {
   285  	staticDir := AbsPathify("static") + "/"
   286  	if _, err := os.Stat(staticDir); os.IsNotExist(err) {
   287  		log.Println("Unable to find Static Directory:", staticDir)
   288  		return nil
   289  	}
   290  
   291  	publishDir := AbsPathify("public") + "/"
   292  
   293  	syncer := fsync.NewSyncer()
   294  	syncer.NoTimes = true
   295  	syncer.SrcFs = SourceFs
   296  	syncer.DestFs = DestinationFS
   297  
   298  	// Copy Static to Destination
   299  	log.Println("syncing from", staticDir, "to", publishDir)
   300  	return syncer.Sync(publishDir, staticDir)
   301  }