aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2021-09-10 18:57:11 +0200
committerMartin Polden <mpolden@mpolden.no>2021-09-10 18:57:32 +0200
commitb15be314c1481bb5325ce6e3264451df76d2bd69 (patch)
tree4ae225a235b16667553511b09e9e6a483a3e7064
parent438d1a57510f9756362f2a8e84f7e55ff6a9ff68 (diff)
watcher: Support custom handler per path
-rw-r--r--README.md4
-rw-r--r--cmd/unp/main.go3
-rw-r--r--watcher/config.go18
-rw-r--r--watcher/config_test.go7
-rw-r--r--watcher/watcher.go42
-rw-r--r--watcher/watcher_test.go57
6 files changed, 69 insertions, 62 deletions
diff --git a/README.md b/README.md
index d200192..da59b77 100644
--- a/README.md
+++ b/README.md
@@ -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)