Lifecycle hooks
Ghciwatch supports a number of lifecycle hook options
like --test-ghci
,
--before-startup-shell
, and
--after-restart-ghci
.
Lifecycle hooks can be defined multiple times and run in sequence. For example:
ghciwatch --test-ghci TestMain.testMain \
--test-ghci 'if myGreeting /= "Hello, world!" then error else ()'
This command will first run TestMain.testMain
and then the check for
myGreeting
.
Types of hooks
Lifecycle hooks come in two main variants: shell commands and GHCi commands.
GHCi commands
GHCi lifecycle hook options (like --test-ghci
and
--after-startup-ghci
) end in -ghci
and
define a command to be executed in the GHCi session.
When running a test suite, you can use a hook like --after-startup-ghci ':set args "--match=/MyModule/"'
to filter HSpec items or otherwise
set command-line arguments for the test suite.
Note that any GHCi command is allowed, so there’s nothing to stop you from
setting a hook like :set prompt λ>
that breaks ghciwatch’s ability to detect
when reloads are complete.
Output printed by GHCi, including by GHCi lifecycle hooks, is printed to ghciwatch’s stdout.
Shell commands
Shell lifecycle hook options (like --test-shell
) end
in -shell
and define a shell command to be executed.
Arguments can be quoted with standard sh
syntax as defined in POSIX.1-2008
§2.2 (however, note that no variable expansion is performed).
If a shell lifecycle hook begins with async:
, as in --after-reload-shell 'async:tags'
, the command will be run asynchronously and ghciwatch will
continue to execute as normal.
If a shell lifecycle hook fails (exits with a non-zero status code), a message indicating the command that failed and the contents of its standard output and standard error streams will be printed.
Detecting if code is running in ghciwatch
Before launching the GHCi session, ghciwatch sets the IN_GHCIWATCH
environment variable. GHCi and shell command lifecycle hooks can read this
environment variable to determine if they’re being run inside a ghciwatch session.
This is particularly useful for code which may be compiled, run in a plain
ghci
session, or run in a ghciwatch-managed GHCi session.
List of lifecycle hooks
Before startup
Hook: --before-startup-shell
.
When: Before the --command
is executed to spawn a GHCi
session.
No GHCi session exists when this hook is run, so only a shell hook is available.
Good for running tools like hpack
to generate .cabal
files.
After startup
Hooks: --after-startup-shell
,
--after-startup-ghci
.
When: After the --command
executed to spawn a GHCi
session has finished loading and the error log has been
written, but before eval commands and test
suites are executed.
Test
Hooks: --test-shell
,
--test-ghci
.
When: After the GHCi session starts up or a reload or restart completes.
Note that if compilation fails, test suites and eval commands will not run.
Before reload
Hooks: --before-reload-shell
,
--before-reload-ghci
.
When: After file changes are detected but before a :reload
or :add
command
is sent to the GHCi session.
Note that the before-reload hooks are not executed before a restart.
After reload
Hooks: --after-reload-shell
,
--after-reload-ghci
.
When: After a reload has completed, after the error log has been written, but before eval commands and test suites are executed.
Before restart
Hooks: --before-restart-shell
,
--before-restart-ghci
.
When: After file changes that require a restart are detected but before the
GHCi session is SIGKILL
ed.
The GHCi session is restarted when .cabal
files change, when Haskell modules
are deleted or moved, or when any files specified by
--restart-globs
are changed.
After restart
Hooks: --after-restart-shell
,
--after-restart-ghci
.
When: After the GHCi session has been restarted, the error log has been written, and the after startup hooks have run, but before eval commands and test suites are executed.