Skip to content

feat(watch): pure-shell polling fallback when inotifywait/fswatch are missing #779

Description

@Chemaclass

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):

  1. 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.
  2. 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.
  3. 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

  • ./bashunit tests/ and ./bashunit --parallel tests/ pass.
  • make sa, make lint pass; shfmt -w . produces no diff.
  • Manual check documented in PR: rename fswatch away, run --watch, edit a test file, suite reruns within the interval.

Line references valid at commit 1ae3e82.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Fields

No fields configured for issues without a type.

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions