A CLI app to watch directories for changes and run chains of commands upon detecting a change.
The information below may be outdated. For the latest version, check the repository.
Waechter
A CLI app to watch directories for changes and run chains of commands upon detecting a change.
Table of Contents
Installation and setup
The app requires no installation as such. If Go and Docker are installed in the system, you may give Waechter a test run right away.
Compiling
You can always download a precompiled binary from the releases page, but it’s also perfectly OK to compile Waechter yourself. Provided that you have Go installed, all you need to do is:
$ git clone https://github.com/nekr0z/waechter.git
$ cd waechter
$ go build
Configuration
Waechter is configured by means of a YAML file containing up to two documents (an example can be found in this repository). The first YAML document should include one or more directories to watch:
|
|
Each directory must have a valid path
(either absolute or relative, but be careful with relative paths as those are resolved relative to the working directory at the time Waechter is run) and a list of commands
to run. Note that the commands will be run directly, without spawning a shell, so if you need to do some shell scripting or piping, you’ll need to wrap your commands in shell scripts as applicable.
The optional log_file
parameter indicates the file to store the output of the executed commands (combined stdout
and stderr
). If no log_file
is provided, the output is redirected to stdout
of Waechter. log_file
is always appended, so make sure to rotate logs as applicable.
The optional include_regexp
is a list of regular expressions that filenames can be matched against. If the list is not empty, only changes in the files with names matching a regular expression from the list will be registered. Invalid expressions (such as \K
, for example) get dropped, so the list may end up empty and no files will be ignored.
In the same way, the optional exclude_regexp
is a list of regular expressions that gets the matching filenames to be ignored when wathching for changes. If a filename matches both and include_regexp
and an exclude_regexp
, the file is ignored.
The optional second YAML document in the config file sets the database configuration:
|
|
The only supported type
currently is “postgres”, that is, a PostgreSQL database. location
should contain a connection string, both keyword/value and URI formats are supported. changes
and commands
are the names of the tables (one for storing the filesystem events, the other for storing the commands executed by Waechter). Each table can be omitted, in which case the corresponding data will not be stored.
The schema used for both tables can be found here.
An example PostgreSQL installation is provided by means of a Docker Compose file. To run it, have Docker and Docker Compose installed, and from the cloned repository do:
$ cd postrges
$ sudo docker compose up
This will configure and run a PostgreSQL setup that corresponds to the configuration in the example config file. The Adminer interface will be exposed at localhost:8080 where you can use PostgreSQL
driver, postgres
user with example
password to access the postgres
database and access the recorded entries.
Usage
Run Waechter with
$ waechter /path/to/config.yaml
(compiled version), or
$ go run main.go /path/to/config.yaml
Testing with a sample configuration
To test with the provided sample configuration, you may use the PostgreSQL Docker Compose setup (as explained above):
$ git clone https://github.com/nekr0z/waechter.git
$ cd waechter
$ go build
$ cd postgres
$ sudo docker compose up -d
$ cd ..
$ waechter testdata/config.yaml
The current directory will be watched, and you can create, modify and delete files to trigger the commands. Issue a SIGTERM
(by hitting Ctrl+C
) to stop Waechter.
Usage details
- if several commands are provided for a single path, they are run one by one in the order specified; if one of the commands exits with an error, the rest of the commands are not run;
- the directories are watched recursively; Waechter tries its best to add the newly created subdirectories recursively, too, but that has not been tested on all filesystems;
- Waechter uses
inotify
to detect changes; the usual issues apply, so you may want to tweak your system accordingly; - there’s a 100 ms timer that is started whenever a change is detected; if a change occurs on the same file before this timer expires, it is reset for another 100 ms; only after the file expires are the commands executed; this behaviour guards against the situations when a file is written to continuously in small chunks (such as when a Go binary is compiled), and it makes sense to wait for the whole write to finish before triggering the commands execution;
- if a set of commands is already running when a new change is detected, a new run is queued and will be performed as soon as the current run is finished; at most one “next” run will be queued, and the commands will not be executed concurrently; however, each path is watched separately, so whenever paths overlap (or several Waechter instances are run simultaneously), a single change can trigger concurrent commands execution;
- regular expressions in
include_regexp
andexclude_regexp
are matched against the path (relative or absolute, depending on how thepath
is defined), not just the name of the file; - upon exiting (when
SIGTERM
is received) Waechter sends aSIGKILL
to all the running commands; - Waechter should work on any system it compiles on, but has only been tested in Linux.
Development
Pull requests are always welcome!
Credits
This software depends upon (and incorporates when compiled) the following software or parts thereof:
- fsnotify Copyright © 2012 The Go Authors. Copyright © fsnotify Authors.
- go-yaml/yaml Copyright (c) 2006-2010 Kirill Simonov. Copyright (c) 2006-2011 Kirill Simonov. Copyright (c) 2011-2019 Canonical Ltd.
- jackc/pgx Copyright (c) 2013-2021 Jack Christensen.
- The Go Programming Language Copyright © 2009 The Go Authors