diff options
author | Stuart Thackray <stuart.thackray@gmail.com> | 2018-12-11 08:53:29 +0200 |
---|---|---|
committer | Stuart Thackray <stuart.thackray@gmail.com> | 2018-12-11 08:53:29 +0200 |
commit | ebfa797c1f5d038b99beaf658757d974412a15c7 (patch) | |
tree | 9765880a7f0119c265d85f8bac7afea8d9542080 /src/rebar_core.erl | |
parent | 71187514dabdd94aa333495d92df84a2e750099f (diff) | |
parent | 8e28561d4e14ea85d42d17ab5a0f17f5f1c696d2 (diff) |
Update from Upstream
Diffstat (limited to 'src/rebar_core.erl')
-rw-r--r-- | src/rebar_core.erl | 48 |
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]). |