ifft 0.1.0

IF Filsystem-event Then...
# IF Filesystem-event Then (IFFT)

IF a filesystem event (create, write, remove, chmod) occurs in a watched folder
that is not filtered out by an exclusion rule THEN execute a shell command.

Use this to watch for code changes to trigger: process restart; code
compilation; or test run.

## Installation

You'll need [rust installed](https://www.rust-lang.org/tools/install) on your
machine.

```
cargo install ifft
```

## Usage

Create a config file (`ifft_config.toml`):

```toml
# The top-level folder to watch. Relative paths specified elsewhere will be
# relative to this folder. Supports ~ and env vars ($VAR).
root = "~/src"
# Never trigger on a backup or swap file. (VIM specific)
not = [
    "*~",
    "*.swp",
]

[[ifft]]
# my-c-prog is a folder in ~/src
# If any .c or .h files change, recompile.
if = "my-c-prog/**/*.{c,h}"
then = "make"
working_dir = "my-c-prog"

[[ifft]]
if = "my-rust-prog/*"
# Ignore changes in the target folder to avoid recursive triggering.
not = ["my-rust-prog/target/*"]
then = "cargo build"
working_dir = "my-rust-prog"

# Contrived example to demonstrate other features.
[[ifft]]
# Omitting the if condition -> trigger on all events under root.
# if =
# {{}} is substituted with the absolute path to the triggering file.
then = "cp -R {{}} ."
# working_dir can be an absolute path.
working_dir = "/tmp"
```

Run `ifft`:

```bash
ifft path/to/ifft_config.toml
```

Output:

`ifft` is verbose for easy debugging. Triggers report the match condition and
the exit code, stdout, and stderr of the triggered command:

```
[2019-01-31 04:51:28Z] Event: Create("/home/ken/src/my-rust-prog/src/main.rs")
  Matched if-cond: "my-rust-prog/*"
  Executing: "cargo build" from "/home/ken/src/my-rust-prog"
  Exit code: 0
  Stdout:
  Stderr:
       Compiling my-rust-prog v0.1.0 (/home/ken/src/my-rust-prog)
        Finished dev [unoptimized + debuginfo] target(s) in 0.27s
[2019-01-31 04:51:28Z] Event: Create("/home/ken/src/my-rust-prog/target/debug/incremental/my_rust_prog-1m194buzrsqka/s-f91jk9lg3a-wlnrr5.lock")
[2019-01-31 04:51:28Z] Event: Write("/home/ken/src/my-rust-prog/target/debug/deps/my_rust_prog-b5f4d74ed1175a94.d")
```

## Features

* Configure with a `toml` file.
* Use glob patterns for `if` and `not` conditions.
* `root` as an absolute path independent from `if` conditions as relative paths.
* `root` supports shell expansion: `~` and environment variables.
* Global `not` filtering and per-trigger `not` filtering.

## Platforms

Tested on Linux and OS X. Untested elsewhere.

## Usage with VirtualBox Shared Folders

On the guest OS, VirtualBox Shared Folders do not generate filesystem event
notifications. You'll need to use a separate filesystem event forwarder such as
[notify-forwarder](https://github.com/mhallin/notify-forwarder).

## Alternatives

* [watchexec]https://github.com/watchexec/watchexec is a more full-featured
  program.
* [entr]http://eradman.com/entrproject/ has a clean Unixy interface.

## Todo

* [] Add `.gitignore` parsing support.
* [] Flag to ignore hidden files.
* [] Flag to control verbosity of prints.
* [] Group events in quick succession together and trigger only once.
* [] Allow customization of type of FS events that trigger.
* [] Low priority: Compute the optimal path prefix for watching.
* [] Performance: Do not compile glob before each use. Current hack to make it
  easy to access the glob pattern string if an error occurs.