github.com/pbberlin/tools@v0.0.0-20160910141205-7aa5421c2169/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 }