From 3da4cc222197e01886d3baaeca7a380e02ff3125 Mon Sep 17 00:00:00 2001 From: Fred Hebert Date: Fri, 25 Nov 2016 21:32:43 -0500 Subject: Type specifications and edocs improvements Includes improvments and function documentation for all modules (in alphabetical order) up to rebar_core, and may have included more in other modules as I saw fit to dig and understand more of the internals. --- src/r3.erl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/r3.erl') diff --git a/src/r3.erl b/src/r3.erl index 5e8b26d..d0d6c47 100644 --- a/src/r3.erl +++ b/src/r3.erl @@ -1,7 +1,12 @@ -%%% external alias for rebar_agent +%%% @doc external alias for `rebar_agent' for more convenient +%%% calls from a shell. -module(r3). -export([do/1, do/2]). +%% @doc alias for `rebar_agent:do/1' +-spec do(atom()) -> ok | {error, term()}. do(Command) -> rebar_agent:do(Command). +%% @doc alias for `rebar_agent:do/2' +-spec do(atom(), atom()) -> ok | {error, term()}. do(Namespace, Command) -> rebar_agent:do(Namespace, Command). -- cgit v1.1 From 03425c788c0e1ac38a3172f6c13a42cd1ffa4b4a Mon Sep 17 00:00:00 2001 From: Fred Hebert Date: Mon, 24 Apr 2017 19:43:44 -0400 Subject: Abuse error_handler to get free metacalls in r3 This uses the very risky '$handle_undefined_function'/2 export from the r3 and rebar_agent modules to allow meta-calls that can support plugins and all other rebar3 extensions. This is nasty but very tempting. Currently we only support: - r3:do(Command) - r3:do(Namespace, Command) There is currently no way to pass arguments to the function such that we can, for example, run cover analysis or tests on a subset of suites. With the new abuse of '$handle_undefined_function'/2, we can detect the unused commands (since they are not exported) and re-route them: - r3:Command() - r3:Command("--args=as a string") - r3:Command(Namespace, "--args=as a string") Of course, in doing so, we make it impossible to use the 'do' provider (as in 'rebar3 do ct -c, cover') since the 'do' function is already required for things to work. Since the previous function had very strict guards, we can, without conflict, add manual overrides that simulate the meta-calls fine. Sample run: https://gist.github.com/ferd/2c06d59c7083c146d25e4ee301de0073 --- src/r3.erl | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/r3.erl') diff --git a/src/r3.erl b/src/r3.erl index d0d6c47..bbf9eea 100644 --- a/src/r3.erl +++ b/src/r3.erl @@ -2,6 +2,7 @@ %%% calls from a shell. -module(r3). -export([do/1, do/2]). +-export(['$handle_undefined_function'/2]). %% @doc alias for `rebar_agent:do/1' -spec do(atom()) -> ok | {error, term()}. @@ -10,3 +11,7 @@ do(Command) -> rebar_agent:do(Command). %% @doc alias for `rebar_agent:do/2' -spec do(atom(), atom()) -> ok | {error, term()}. do(Namespace, Command) -> rebar_agent:do(Namespace, Command). + +%% @private defer to rebar_agent +'$handle_undefined_function'(Cmd, Args) -> + rebar_agent:'$handle_undefined_function'(Cmd, Args). -- cgit v1.1 From 9b03dacf2b7829b584d26a999f80c315ae8ce897 Mon Sep 17 00:00:00 2001 From: Fred Hebert Date: Mon, 22 Oct 2018 19:46:09 -0400 Subject: 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> % 2> r3:resume(). ok 3> ..... %%% rebar_as_SUITE: ........... %%% rebar_compile_SUITE: ...... ... --- src/r3.erl | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) (limited to 'src/r3.erl') diff --git a/src/r3.erl b/src/r3.erl index bbf9eea..a79cc3a 100644 --- a/src/r3.erl +++ b/src/r3.erl @@ -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). -- cgit v1.1