76 lines
1.5 KiB
Go
76 lines
1.5 KiB
Go
package main
|
|
|
|
import (
|
|
"log"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/fsnotify/fsnotify"
|
|
)
|
|
|
|
type Watcher struct {
|
|
w *fsnotify.Watcher
|
|
g *Generator
|
|
done chan struct{}
|
|
}
|
|
|
|
func NewWatcher(dir string, g *Generator) (*Watcher, error) {
|
|
w, err := fsnotify.NewWatcher()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := w.Add(dir); err != nil {
|
|
w.Close()
|
|
return nil, err
|
|
}
|
|
return &Watcher{w: w, g: g, done: make(chan struct{})}, nil
|
|
}
|
|
|
|
// Watch blocks, watching for changes and triggering rebuilds.
|
|
// Rapid events (e.g. scp writing an image then its sidecar) are debounced
|
|
// with a 500 ms window so only one rebuild fires per logical upload.
|
|
func (w *Watcher) Watch() {
|
|
var timer *time.Timer
|
|
rebuild := func() {
|
|
if err := w.g.Build(); err != nil {
|
|
log.Printf("rebuild: %v", err)
|
|
}
|
|
}
|
|
|
|
for {
|
|
select {
|
|
case event, ok := <-w.w.Events:
|
|
if !ok {
|
|
return
|
|
}
|
|
if !isRelevant(event.Name) {
|
|
continue
|
|
}
|
|
if event.Has(fsnotify.Create) || event.Has(fsnotify.Write) || event.Has(fsnotify.Remove) {
|
|
if timer != nil {
|
|
timer.Stop()
|
|
}
|
|
timer = time.AfterFunc(500*time.Millisecond, rebuild)
|
|
}
|
|
case err, ok := <-w.w.Errors:
|
|
if !ok {
|
|
return
|
|
}
|
|
log.Printf("watcher: %v", err)
|
|
case <-w.done:
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func (w *Watcher) Close() {
|
|
close(w.done)
|
|
w.w.Close()
|
|
}
|
|
|
|
func isRelevant(name string) bool {
|
|
ext := strings.ToLower(filepath.Ext(name))
|
|
return ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".toml"
|
|
}
|