Why
--watch hard-fails when neither inotifywait nor fswatch is installed (src/watch.sh:33 prints an install hint and exits). On CI containers, fresh macOS machines, and minimal images that's a dead end, while a portable polling fallback is cheap to provide. Watchers in most test frameworks degrade to polling for exactly this reason.
Proposal
Add a pure-shell polling backend as the third branch of the backend detection (src/watch.sh:12-15):
- Change detection without GNU/BSD
stat divergence: use a sentinel file + find:
touch "$sentinel" at loop start,
- sleep
BASHUNIT_WATCH_INTERVAL (new env, default 2 seconds),
find <watched paths> -name '*.sh' -newer "$sentinel" -print (mirror whatever file set the inotify/fswatch branches watch — check src/watch.sh:67+ for the current event filters) — non-empty output means rerun.
This avoids parsing stat (whose flags differ between macOS -f %m and GNU -c %Y) and works on Bash 3.0.
- Print a one-line notice when falling back: polling mode + interval + hint that installing
fswatch/inotifywait gives instant triggers. Keep the current install-hint text as part of that notice instead of an error.
- Sentinel lives under the existing temp-dir helpers (
temp_dir) and is cleaned on exit (reuse watch mode's existing trap/cleanup if present — read the full file first).
Edge cases
- First iteration must run the suite immediately (current behavior), then start polling.
- Deleted files don't show up via
-newer; acceptable for a fallback — note it in docs.
BASHUNIT_WATCH_INTERVAL validation: positive integer, else default with a warning (follow how other numeric envs are validated in src/env.sh).
Tests first (TDD)
Watch mode loops forever, so test the pieces: unit-test the new "detect changes since sentinel" function (touch sentinel, touch a file, assert detection; no changes, assert none). For the backend selection, unit-test that the poller is chosen when both commands are missing (mock bashunit::watch::_command_exists). Follow existing patterns in tests/unit/watch_test.sh if present — grep first.
Constraints
- Bash 3.0+;
find -newer is POSIX.
- No behavior change when
inotifywait/fswatch exist.
- Docs page for watch mode + CHANGELOG.md entry.
Acceptance criteria
Line references valid at commit 1ae3e82.
Why
--watchhard-fails when neitherinotifywaitnorfswatchis installed (src/watch.sh:33prints an install hint and exits). On CI containers, fresh macOS machines, and minimal images that's a dead end, while a portable polling fallback is cheap to provide. Watchers in most test frameworks degrade to polling for exactly this reason.Proposal
Add a pure-shell polling backend as the third branch of the backend detection (
src/watch.sh:12-15):statdivergence: use a sentinel file +find:touch "$sentinel"at loop start,BASHUNIT_WATCH_INTERVAL(new env, default2seconds),find <watched paths> -name '*.sh' -newer "$sentinel" -print(mirror whatever file set the inotify/fswatch branches watch — checksrc/watch.sh:67+for the current event filters) — non-empty output means rerun.This avoids parsing
stat(whose flags differ between macOS-f %mand GNU-c %Y) and works on Bash 3.0.fswatch/inotifywaitgives instant triggers. Keep the current install-hint text as part of that notice instead of an error.temp_dir) and is cleaned on exit (reuse watch mode's existing trap/cleanup if present — read the full file first).Edge cases
-newer; acceptable for a fallback — note it in docs.BASHUNIT_WATCH_INTERVALvalidation: positive integer, else default with a warning (follow how other numeric envs are validated insrc/env.sh).Tests first (TDD)
Watch mode loops forever, so test the pieces: unit-test the new "detect changes since sentinel" function (touch sentinel, touch a file, assert detection; no changes, assert none). For the backend selection, unit-test that the poller is chosen when both commands are missing (mock
bashunit::watch::_command_exists). Follow existing patterns intests/unit/watch_test.shif present — grep first.Constraints
find -neweris POSIX.inotifywait/fswatchexist.Acceptance criteria
./bashunit tests/and./bashunit --parallel tests/pass.make sa,make lintpass;shfmt -w .produces no diff.fswatchaway, run--watch, edit a test file, suite reruns within the interval.Line references valid at commit 1ae3e82.