diff options
author | Martin Polden <mpolden@mpolden.no> | 2021-09-10 18:57:11 +0200 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2021-09-10 18:57:32 +0200 |
commit | b15be314c1481bb5325ce6e3264451df76d2bd69 (patch) | |
tree | 4ae225a235b16667553511b09e9e6a483a3e7064 | |
parent | 438d1a57510f9756362f2a8e84f7e55ff6a9ff68 (diff) |
watcher: Support custom handler per path
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | cmd/unp/main.go | 3 | ||||
-rw-r--r-- | watcher/config.go | 18 | ||||
-rw-r--r-- | watcher/config_test.go | 7 | ||||
-rw-r--r-- | watcher/watcher.go | 42 | ||||
-rw-r--r-- | watcher/watcher_test.go | 57 |
6 files changed, 69 insertions, 62 deletions
@@ -79,8 +79,8 @@ option: Variable | Description | Example -------- | ---------------------------------------------- | ------- -`Base` | Basename of the archive file | `baz.rar` -`Dir` | Directory holding the archive file | `/tmp/foo/bar` +`Base` | Basename of the file triggering the event | `baz.rar` +`Dir` | Directory holding the file | `/tmp/foo/bar` `Name` | Full path to archive file triggering the event | `/tmp/foo/bar/baz.rar` The template is compiled using the diff --git a/cmd/unp/main.go b/cmd/unp/main.go index 2a16d46..2adcdd8 100644 --- a/cmd/unp/main.go +++ b/cmd/unp/main.go @@ -6,7 +6,6 @@ import ( "log" "os" - "github.com/mpolden/unp/rar" "github.com/mpolden/unp/watcher" ) @@ -30,6 +29,6 @@ func main() { } log := log.New(os.Stderr, "unp: ", 0) - w := watcher.New(cfg, rar.NewHandler(), log) + w := watcher.New(cfg, log) w.Start() } diff --git a/watcher/config.go b/watcher/config.go index 55d0d34..a28f5cf 100644 --- a/watcher/config.go +++ b/watcher/config.go @@ -9,6 +9,8 @@ import ( "os/exec" "path/filepath" "strings" + + "github.com/mpolden/unp/rar" ) type Config struct { @@ -20,6 +22,8 @@ type Config struct { type Path struct { Name string + Handler string + handler Handler MaxDepth int MinDepth int SkipHidden bool @@ -67,7 +71,7 @@ func readConfig(r io.Reader) (Config, error) { if cfg.BufferSize <= 0 { cfg.BufferSize = 1024 } - if err := cfg.validate(); err != nil { + if err := cfg.load(); err != nil { return Config{}, err } return cfg, nil @@ -105,8 +109,8 @@ func (c *Config) JSON() ([]byte, error) { return json.MarshalIndent(c, "", " ") } -func (c *Config) validate() error { - for _, p := range c.Paths { +func (c *Config) load() error { + for i, p := range c.Paths { fi, err := os.Stat(p.Name) if err != nil { return err @@ -123,6 +127,14 @@ func (c *Config) validate() error { if err := isExecutable(p.PostCommand); err != nil { return err } + switch p.Handler { + case "rar", "": + c.Paths[i].handler = rar.NewHandler() + case "script": + c.Paths[i].handler = &scriptHandler{} + default: + return fmt.Errorf("invalid handler: %q", p.Handler) + } } return nil } diff --git a/watcher/config_test.go b/watcher/config_test.go index b1f8b29..934553f 100644 --- a/watcher/config_test.go +++ b/watcher/config_test.go @@ -2,16 +2,13 @@ package watcher import ( "fmt" - "os" "strings" "testing" ) func TestReadConfig(t *testing.T) { - path1 := tempDir() - defer os.RemoveAll(path1) - path2 := tempDir() - defer os.RemoveAll(path2) + path1 := t.TempDir() + path2 := t.TempDir() jsonConfig := fmt.Sprintf(` { "Default": { diff --git a/watcher/watcher.go b/watcher/watcher.go index 9df1fe4..cc3ef79 100644 --- a/watcher/watcher.go +++ b/watcher/watcher.go @@ -11,6 +11,7 @@ import ( "log" + "github.com/mpolden/unp/executil" "github.com/mpolden/unp/pathutil" "github.com/rjeczalik/notify" ) @@ -19,15 +20,25 @@ type Handler interface { Handle(filename, postCommand string, remove bool) error } +type scriptHandler struct{} + +func (h *scriptHandler) Handle(filename, postCommand string, remove bool) error { + data := executil.CommandData{ + Dir: filepath.Dir(filename), + Base: filepath.Base(filename), + Name: filename, + } + return executil.Run(postCommand, data) +} + type Watcher struct { - config Config - handler Handler - events chan notify.EventInfo - signal chan os.Signal - done chan bool - log *log.Logger - mu sync.Mutex - wg sync.WaitGroup + config Config + events chan notify.EventInfo + signal chan os.Signal + done chan bool + log *log.Logger + mu sync.Mutex + wg sync.WaitGroup } func (w *Watcher) handle(name string) error { @@ -49,7 +60,7 @@ func (w *Watcher) handle(name string) error { } return fmt.Errorf("no match found: %s", name) } - return w.handler.Handle(name, p.PostCommand, p.Remove) + return p.handler.Handle(name, p.PostCommand, p.Remove) } func (w *Watcher) watch() { @@ -156,18 +167,17 @@ func (w *Watcher) Stop() { w.done <- true } -func New(cfg Config, handler Handler, log *log.Logger) *Watcher { +func New(cfg Config, log *log.Logger) *Watcher { // Buffer events so that we don't miss any events := make(chan notify.EventInfo, cfg.BufferSize) sig := make(chan os.Signal, 1) done := make(chan bool, 1) signal.Notify(sig) return &Watcher{ - config: cfg, - events: events, - log: log, - handler: handler, - signal: sig, - done: done, + config: cfg, + events: events, + log: log, + signal: sig, + done: done, } } diff --git a/watcher/watcher_test.go b/watcher/watcher_test.go index 94e3329..6920231 100644 --- a/watcher/watcher_test.go +++ b/watcher/watcher_test.go @@ -2,7 +2,7 @@ package watcher import ( "fmt" - "io/ioutil" + "io" "log" "os" "path/filepath" @@ -37,30 +37,20 @@ func (h *testHandler) awaitFile(file string) (bool, error) { return h.files[0] == file, nil } -func tempDir() string { - dir, err := ioutil.TempDir("", "unp") - if err != nil { - panic(err) - } - path, err := filepath.EvalSymlinks(dir) - if err != nil { - panic(err) - } - return path -} - func testWatcher(dir string, handler Handler) *Watcher { cfg := Config{ BufferSize: 10, - Paths: []Path{{Name: dir, MaxDepth: 100, Patterns: []string{"*"}}}, + Paths: []Path{{handler: handler, Name: dir, MaxDepth: 100, Patterns: []string{"*"}}}, } - log := log.New(ioutil.Discard, "", 0) - return New(cfg, handler, log) + log := log.New(io.Discard, "", 0) + return New(cfg, log) } func TestWatching(t *testing.T) { - dir := tempDir() - defer os.RemoveAll(dir) + dir, err := filepath.EvalSymlinks(t.TempDir()) + if err != nil { + t.Fatal(err) + } h := testHandler{} w := testWatcher(dir, &h) @@ -69,7 +59,7 @@ func TestWatching(t *testing.T) { defer w.Stop() f := filepath.Join(dir, "foo") - if err := ioutil.WriteFile(f, []byte{0}, 0644); err != nil { + if err := os.WriteFile(f, []byte{0}, 0644); err != nil { t.Fatal(err) } @@ -83,8 +73,7 @@ func TestWatching(t *testing.T) { } func TestRescanning(t *testing.T) { - dir := tempDir() - defer os.RemoveAll(dir) + dir := t.TempDir() f1 := filepath.Join(dir, "foo") f2 := filepath.Join(dir, "bar") @@ -94,10 +83,10 @@ func TestRescanning(t *testing.T) { defer w.Stop() // Files are written before watcher is started - if err := ioutil.WriteFile(f1, []byte{0}, 0644); err != nil { + if err := os.WriteFile(f1, []byte{0}, 0644); err != nil { t.Fatal(err) } - if err := ioutil.WriteFile(f2, []byte{0}, 0644); err != nil { + if err := os.WriteFile(f2, []byte{0}, 0644); err != nil { t.Fatal(err) } @@ -126,24 +115,22 @@ func TestReloading(t *testing.T) { w := testWatcher("", h) defer w.Stop() - tmp, err := ioutil.TempFile("", "unp") - if err != nil { - t.Fatal(err) - } - defer os.Remove(tmp.Name()) - w.config = Config{filename: tmp.Name()} + configFile := filepath.Join(t.TempDir(), "config") + w.config = Config{filename: configFile} // Start serving with empty config w.goServe() w.watch() // Create a new directory - dir := tempDir() - defer os.RemoveAll(dir) + dir, err := filepath.EvalSymlinks(t.TempDir()) + if err != nil { + t.Fatal(err) + } // Write config that references directory cfg := fmt.Sprintf(`{"Paths": [{"Name": "%s", "Patterns": ["*"], "MaxDepth": 100}]}`, dir) - if err := ioutil.WriteFile(tmp.Name(), []byte(cfg), 0644); err != nil { + if err := os.WriteFile(configFile, []byte(cfg), 0644); err != nil { t.Fatal(err) } @@ -159,11 +146,13 @@ func TestReloading(t *testing.T) { } } + // Override handler + w.config.Paths[0].handler = h + f := filepath.Join(dir, "foo") - if err := ioutil.WriteFile(f, []byte{0}, 0644); err != nil { + if err := os.WriteFile(f, []byte{0}, 0644); err != nil { t.Fatal(err) } - ok, err := h.awaitFile(f) if err != nil { t.Fatal(err) |