diff options
author | Fred Hebert <mononcqc@ferd.ca> | 2018-10-22 19:46:09 -0400 |
---|---|---|
committer | Fred Hebert <mononcqc@ferd.ca> | 2018-10-22 20:35:44 -0400 |
commit | 9b03dacf2b7829b584d26a999f80c315ae8ce897 (patch) | |
tree | 582cac5837e98a614b345bbd1cbf0e99c00038b7 /src/r3.erl | |
parent | 78e0d7923d78d912844e413bc82aa24ff1484d6e (diff) |
Allow Breakpoints during task runs
This is mostly useful for tests, where a test suite of any kind can be
interrupted halfway through so that the user can probe the running
system to see what is happening.
This is done as follows:
1. the user must call `r3:break()` in a test suite
2. the user runs the task as `r3:async_do(ct)`
3. the test holds up and the user can do whatever
4. the user calls `r3:resume()` and the test proceeds as normal
A safeguard is added so that breakpoints are only triggered in the shell
in async mode
Sample session:
$ rebar3 shell
...
1> rebar_agent:async_do(ct).
ok
...
Running Common Test suites...
%%% rebar_alias_SUITE: .
=== BREAK ===
2> % <do some checks>
2> r3:resume().
ok
3> .....
%%% rebar_as_SUITE: ...........
%%% rebar_compile_SUITE: ......
...
Diffstat (limited to 'src/r3.erl')
-rw-r--r-- | src/r3.erl | 43 |
1 files changed, 42 insertions, 1 deletions
@@ -1,8 +1,9 @@ %%% @doc external alias for `rebar_agent' for more convenient %%% calls from a shell. -module(r3). --export([do/1, do/2]). +-export([do/1, do/2, async_do/1, async_do/2, break/0, resume/0]). -export(['$handle_undefined_function'/2]). +-include("rebar.hrl"). %% @doc alias for `rebar_agent:do/1' -spec do(atom()) -> ok | {error, term()}. @@ -12,6 +13,46 @@ do(Command) -> rebar_agent:do(Command). -spec do(atom(), atom()) -> ok | {error, term()}. do(Namespace, Command) -> rebar_agent:do(Namespace, Command). +%% @async_doc alias for `rebar_agent:async_do/1' +-spec async_do(atom()) -> ok | {error, term()}. +async_do(Command) -> rebar_agent:async_do(Command). + +%% @async_doc alias for `rebar_agent:async_do/2' +-spec async_do(atom(), atom()) -> ok | {error, term()}. +async_do(Namespace, Command) -> rebar_agent:async_do(Namespace, Command). + +break() -> + case whereis(rebar_agent) of % is the shell running + undefined -> + ok; + Pid -> + {dictionary, Dict} = process_info(Pid, dictionary), + case lists:keyfind(cmd_type, 1, Dict) of + {cmd_type, async} -> + Self = self(), + Ref = make_ref(), + spawn_link(fun() -> + register(r3_breakpoint_handler, self()), + receive + resume -> + Self ! Ref + end + end), + io:format(user, "~n=== BREAK ===~n", []), + receive + Ref -> ok + end; + _ -> + ?DEBUG("ignoring breakpoint since command is not run " + "in async mode", []), + ok + end + end. + +resume() -> + r3_breakpoint_handler ! resume, + ok. + %% @private defer to rebar_agent '$handle_undefined_function'(Cmd, Args) -> rebar_agent:'$handle_undefined_function'(Cmd, Args). |