All checks were successful
/ Deploy blog to deuterium (push) Successful in 1m9s
Signed-off-by: Naman Sood <mail@nsood.in>
119 lines
2.6 KiB
Go
119 lines
2.6 KiB
Go
package watcher
|
|
|
|
import (
|
|
"iter"
|
|
"log"
|
|
"os"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/rjeczalik/notify"
|
|
)
|
|
|
|
type WatchEventKind int
|
|
|
|
const (
|
|
Update WatchEventKind = iota
|
|
Clean
|
|
)
|
|
|
|
// WatchEvent represents a change to a watched folder. It notes which file
|
|
// changed and what change happened to it.
|
|
type WatchEvent struct {
|
|
File string
|
|
Kind WatchEventKind
|
|
}
|
|
|
|
func updated(f string) *WatchEvent {
|
|
return &WatchEvent{
|
|
File: f,
|
|
Kind: Update,
|
|
}
|
|
}
|
|
|
|
func cleaned(f string) *WatchEvent {
|
|
return &WatchEvent{
|
|
File: f,
|
|
Kind: Clean,
|
|
}
|
|
}
|
|
|
|
// Watcher classifies notify.Events into updates and deletes, and calls the
|
|
// respective functions for a file when those events happen to that file.
|
|
func Watch(folder string, up Updater[string]) {
|
|
cwd, err := os.Getwd()
|
|
if err != nil {
|
|
log.Fatal("could not get current working directory for listener!")
|
|
}
|
|
cwd = cwd + "/"
|
|
|
|
c := make(chan notify.EventInfo, 1)
|
|
|
|
var events []notify.Event
|
|
|
|
// inotify events prevent double-firing of
|
|
// certain events in Linux.
|
|
if runtime.GOOS == "linux" {
|
|
events = []notify.Event{
|
|
notify.InCloseWrite,
|
|
notify.InMovedFrom,
|
|
notify.InMovedTo,
|
|
notify.InDelete,
|
|
}
|
|
} else {
|
|
events = []notify.Event{
|
|
notify.Create,
|
|
notify.Remove,
|
|
notify.Rename,
|
|
notify.Write,
|
|
}
|
|
}
|
|
|
|
err = notify.Watch(folder, c, events...)
|
|
|
|
if err != nil {
|
|
log.Fatalf("could not setup watcher for folder %s: %s", folder, err)
|
|
}
|
|
|
|
defer notify.Stop(c)
|
|
for {
|
|
ei := <-c
|
|
log.Printf("event: %s", ei.Event())
|
|
switch ei.Event() {
|
|
case notify.InCloseWrite, notify.InMovedTo, notify.Create, notify.Rename, notify.Write:
|
|
filePath := strings.TrimPrefix(ei.Path(), cwd)
|
|
log.Printf("updating file %s", filePath)
|
|
err := up.Fetch(strings.TrimPrefix(filePath, folder))
|
|
if err != nil {
|
|
log.Printf("up.Fetch(%q): %v", filePath, err)
|
|
}
|
|
case notify.InMovedFrom, notify.InDelete, notify.Remove:
|
|
filePath := strings.TrimPrefix(ei.Path(), cwd)
|
|
log.Printf("cleaning file %s", filePath)
|
|
err := up.Delete(strings.TrimPrefix(filePath, folder))
|
|
if err != nil {
|
|
log.Printf("up.Delete(%q): %v", filePath, err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Updater is a key-value store which can be informed when to recompute values
|
|
// for a particular key. Updaters are normally also AutoMaps.
|
|
type Updater[K any] interface {
|
|
Fetch(K) error
|
|
Delete(K) error
|
|
}
|
|
|
|
// AutoMap is a key-value store where the values are automatically computed by
|
|
// the store itself, based on the key.
|
|
type AutoMap[K, V any] interface {
|
|
Get(K) (V, bool)
|
|
}
|
|
|
|
// OrderedAutoMap is an AutoMap that provides an iterator over its
|
|
// currently-existing keys in a known order.
|
|
type OrderedAutoMap[K, V any] interface {
|
|
AutoMap[K, V]
|
|
All() iter.Seq2[K, V]
|
|
}
|