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

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions