summaryrefslogtreecommitdiff
path: root/src/rebar_core.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/rebar_core.erl')
-rw-r--r--src/rebar_core.erl48
1 files changed, 39 insertions, 9 deletions
diff --git a/src/rebar_core.erl b/src/rebar_core.erl
index da8c3e6..6a1cdbf 100644
--- a/src/rebar_core.erl
+++ b/src/rebar_core.erl
@@ -24,6 +24,8 @@
%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%% THE SOFTWARE.
%% -------------------------------------------------------------------
+%% @doc Module providing core functionality about command dispatch, namespacing,
+%% and chaining for rebar3.
-module(rebar_core).
-export([init_command/2, process_namespace/2, process_command/2, do/2, format_error/1]).
@@ -31,6 +33,12 @@
-include("rebar.hrl").
-include_lib("providers/include/providers.hrl").
+%% @doc initial command set up; based on the first fragment of the
+%% command, dispatch to special environments. The keywords for
+%% `do' and `as' are implicitly reserved here, barring them from
+%% being used as other commands or namespaces.
+-spec init_command(rebar_state:t(), atom()) ->
+ {ok, rebar_state:t()} | {error, term()}.
init_command(State, do) ->
process_command(rebar_state:namespace(State, default), do);
init_command(State, as) ->
@@ -43,6 +51,14 @@ init_command(State, Command) ->
{error, Reason}
end.
+%% @doc parse the commands starting at the namespace level;
+%% a namespace is found if the first keyword to match is not
+%% belonging to an existing provider, and iff the keyword also
+%% matches a registered namespace.
+%% The command to run is returned last; for namespaces, some
+%% magic is done implicitly calling `do' as an indirect dispatcher.
+-spec process_namespace(rebar_state:t(), atom()) ->
+ {error, term()} | {ok, rebar_state:t(), atom()}.
process_namespace(_State, as) ->
{error, "Namespace 'as' is forbidden"};
process_namespace(State, Command) ->
@@ -61,7 +77,15 @@ process_namespace(State, Command) ->
{ok, rebar_state:namespace(State, default), Command}
end.
--spec process_command(rebar_state:t(), atom()) -> {ok, rebar_state:t()} | {error, string()} | {error, {module(), any()}}.
+%% @doc Dispatches a given command based on the current state.
+%% This requires mapping a command name to a specific provider.
+%% `as' and `do' are still treated as special providers here.
+%% Basic profile application may also be run.
+%%
+%% The function also takes care of expanding a provider to its
+%% dependencies in the proper order.
+-spec process_command(rebar_state:t(), atom()) ->
+ {ok, rebar_state:t()} | {error, string()} | {error, {module(), any()}}.
process_command(State, Command) ->
%% ? rebar_prv_install_deps:setup_env(State),
Providers = rebar_state:providers(State),
@@ -95,19 +119,24 @@ process_command(State, Command) ->
State2 = rebar_state:command_parsed_args(State1, Args),
do(TargetProviders, State2);
{error, {invalid_option, Option}} ->
- {error, io_lib:format("Invalid option ~s on task ~p", [Option, Command])};
+ {error, io_lib:format("Invalid option ~ts on task ~p", [Option, Command])};
{error, {invalid_option_arg, {Option, Arg}}} ->
- {error, io_lib:format("Invalid argument ~s to option ~s", [Arg, Option])};
+ {error, io_lib:format("Invalid argument ~ts to option ~ts", [Arg, Option])};
{error, {missing_option_arg, Option}} ->
- {error, io_lib:format("Missing argument to option ~s", [Option])}
+ {error, io_lib:format("Missing argument to option ~ts", [Option])}
end
end
end.
--spec do([{atom(), atom()}], rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()} | {error, {module(), any()}}.
+%% @doc execute the selected providers. If a chain of providers
+%% has been returned, run them one after the other, while piping
+%% the state from the first into the next one.
+-spec do([{atom(), atom()}], rebar_state:t()) ->
+ {ok, rebar_state:t()} | {error, string()} | {error, {module(), any()}}.
do([], State) ->
{ok, State};
do([ProviderName | Rest], State) ->
+ ?DEBUG("Provider: ~p", [ProviderName]),
%% Special providers like 'as', 'do' or some hooks may be passed
%% as a tuple {Namespace, Name}, otherwise not. Handle them
%% on a per-need basis.
@@ -128,8 +157,7 @@ do([ProviderName | Rest], State) ->
{error, Error} ->
{error, Error}
catch
- error:undef ->
- Stack = erlang:get_stacktrace(),
+ ?WITH_STACKTRACE(error,undef,Stack)
case Stack of
[{ProviderName, do, [_], _}|_] ->
%% This should really only happen if a plugin provider doesn't export do/1
@@ -142,7 +170,9 @@ do([ProviderName | Rest], State) ->
{error, ProviderName}
end.
+%% @doc convert a given exception's payload into an io description.
+-spec format_error(any()) -> iolist().
format_error({bad_provider_namespace, {Namespace, Name}}) ->
- io_lib:format("Undefined command ~s in namespace ~s", [Name, Namespace]);
+ io_lib:format("Undefined command ~ts in namespace ~ts", [Name, Namespace]);
format_error({bad_provider_namespace, Name}) ->
- io_lib:format("Undefined command ~s", [Name]).
+ io_lib:format("Undefined command ~ts", [Name]).