|
|
@ -1,162 +0,0 @@ |
|
|
|
-module(rebar_provider). |
|
|
|
|
|
|
|
%% API |
|
|
|
-export([create/1, |
|
|
|
new/2, |
|
|
|
do/2, |
|
|
|
impl/1, |
|
|
|
get_provider/2, |
|
|
|
get_target_providers/2, |
|
|
|
help/1, |
|
|
|
format/1]). |
|
|
|
|
|
|
|
-export_type([t/0]). |
|
|
|
|
|
|
|
-include("rebar.hrl"). |
|
|
|
|
|
|
|
%%%=================================================================== |
|
|
|
%%% Types |
|
|
|
%%%=================================================================== |
|
|
|
|
|
|
|
-type t() :: record(provider). |
|
|
|
|
|
|
|
-type provider_name() :: atom(). |
|
|
|
|
|
|
|
-callback init(rebar_state:t()) -> {ok, rebar_state:t()}. |
|
|
|
-callback do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. |
|
|
|
|
|
|
|
%%%=================================================================== |
|
|
|
%%% API |
|
|
|
%%%=================================================================== |
|
|
|
|
|
|
|
%% @doc create a new provider object from the specified module. The |
|
|
|
%% module should implement the provider behaviour. |
|
|
|
%% |
|
|
|
%% @param ModuleName The module name. |
|
|
|
%% @param State0 The current state of the system |
|
|
|
-spec new(module(), rebar_state:t()) -> {ok, rebar_state:t()}. |
|
|
|
new(ModuleName, State) when is_atom(ModuleName) -> |
|
|
|
case code:which(ModuleName) of |
|
|
|
non_existing -> |
|
|
|
?ERROR("Module ~p does not exist.", [ModuleName]), |
|
|
|
{ok, State}; |
|
|
|
_ -> |
|
|
|
ModuleName:init(State) |
|
|
|
end. |
|
|
|
|
|
|
|
-spec create(list()) -> t(). |
|
|
|
create(Attrs) -> |
|
|
|
#provider{name=proplists:get_value(name, Attrs, undefined) |
|
|
|
,provider_impl=proplists:get_value(provider_impl, Attrs, undefined) |
|
|
|
,bare=proplists:get_value(bare, Attrs, false) |
|
|
|
,deps=proplists:get_value(deps, Attrs, []) |
|
|
|
,desc=proplists:get_value(desc, Attrs, "") |
|
|
|
,short_desc=proplists:get_value(short_desc, Attrs, "") |
|
|
|
,example=proplists:get_value(example, Attrs, "") |
|
|
|
,opts=proplists:get_value(opts, Attrs, [])}. |
|
|
|
|
|
|
|
%% @doc Manipulate the state of the system, that new state |
|
|
|
%% |
|
|
|
%% @param Provider the provider object |
|
|
|
%% @param State the current state of the system |
|
|
|
-spec do(Provider::t(), rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. |
|
|
|
do(Provider, State) -> |
|
|
|
{PreHooks, PostHooks} = rebar_state:hooks(State, Provider#provider.name), |
|
|
|
run_all([PreHooks++Provider | PostHooks], State). |
|
|
|
|
|
|
|
-spec run_all([t()], rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. |
|
|
|
run_all([], State) -> |
|
|
|
{ok, State}; |
|
|
|
run_all([Provider | Rest], State) -> |
|
|
|
case (Provider#provider.provider_impl):do(State) of |
|
|
|
{ok, State1} -> |
|
|
|
run_all(Rest, State1); |
|
|
|
{error, Error} -> |
|
|
|
{error, Error} |
|
|
|
end. |
|
|
|
|
|
|
|
%%% @doc get the name of the module that implements the provider |
|
|
|
%%% @param Provider the provider object |
|
|
|
-spec impl(Provider::t()) -> module(). |
|
|
|
impl(Provider) -> |
|
|
|
Provider#provider.name. |
|
|
|
|
|
|
|
help(State) -> |
|
|
|
Providers = rebar_state:providers(State), |
|
|
|
Help = lists:sort([{ec_cnv:to_list(P#provider.name), P#provider.short_desc} || P <- Providers, |
|
|
|
P#provider.bare =/= true]), |
|
|
|
Longest = lists:max([length(X) || {X, _} <- Help]), |
|
|
|
|
|
|
|
lists:foreach(fun({Name, ShortDesc}) -> |
|
|
|
Length = length(Name), |
|
|
|
Spacing = lists:duplicate(Longest - Length + 8, " "), |
|
|
|
io:format("~s~s~s~n", [Name, Spacing, ShortDesc]) |
|
|
|
end, Help). |
|
|
|
|
|
|
|
|
|
|
|
%% @doc print the provider module name |
|
|
|
%% |
|
|
|
%% @param T - The provider |
|
|
|
%% @return An iolist describing the provider |
|
|
|
-spec format(t()) -> iolist(). |
|
|
|
format(#provider{name=Name}) -> |
|
|
|
atom_to_list(Name). |
|
|
|
|
|
|
|
get_target_providers(Target, State) -> |
|
|
|
Providers = rebar_state:providers(State), |
|
|
|
TargetProviders = lists:filter(fun(#provider{name=T}) when T =:= Target-> |
|
|
|
true; |
|
|
|
(_) -> |
|
|
|
false |
|
|
|
end, Providers), |
|
|
|
process_deps(TargetProviders, Providers). |
|
|
|
|
|
|
|
-spec get_provider(provider_name(), [t()]) -> t(). |
|
|
|
get_provider(ProviderName, [Provider = #provider{name = ProviderName} | _]) -> |
|
|
|
Provider; |
|
|
|
get_provider(ProviderName, [_ | Rest]) -> |
|
|
|
get_provider(ProviderName, Rest); |
|
|
|
get_provider(_ProviderName, _) -> |
|
|
|
[]. |
|
|
|
|
|
|
|
process_deps([], _Providers) -> |
|
|
|
[]; |
|
|
|
process_deps(TargetProviders, Providers) -> |
|
|
|
DepChain = lists:flatmap(fun(Provider) -> |
|
|
|
{DC, _, _} = process_deps(Provider, Providers, []), |
|
|
|
DC |
|
|
|
end, TargetProviders), |
|
|
|
['NONE' | Rest] = |
|
|
|
reorder_providers(lists:flatten([{'NONE', P#provider.name} || P <- TargetProviders] ++ DepChain)), |
|
|
|
Rest. |
|
|
|
|
|
|
|
process_deps(Provider, Providers, Seen) -> |
|
|
|
case lists:member(Provider, Seen) of |
|
|
|
true -> |
|
|
|
{[], Providers, Seen}; |
|
|
|
false -> |
|
|
|
Deps = Provider#provider.deps, |
|
|
|
DepList = lists:map(fun(Dep) -> |
|
|
|
{Dep, Provider#provider.name} |
|
|
|
end, Deps), |
|
|
|
{NewDeps, _, NewSeen} = |
|
|
|
lists:foldl(fun(Arg, Acc) -> |
|
|
|
process_dep(Arg, Acc) |
|
|
|
end, |
|
|
|
{[], Providers, Seen}, Deps), |
|
|
|
{[DepList | NewDeps], Providers, NewSeen} |
|
|
|
end. |
|
|
|
|
|
|
|
process_dep(ProviderName, {Deps, Providers, Seen}) -> |
|
|
|
Provider = get_provider(ProviderName, Providers), |
|
|
|
{NewDeps, _, NewSeen} = process_deps(Provider, Providers, [ProviderName | Seen]), |
|
|
|
{[Deps | NewDeps], Providers, NewSeen}. |
|
|
|
|
|
|
|
%% @doc Reorder the providers according to thier dependency set. |
|
|
|
reorder_providers(OProviderList) -> |
|
|
|
case rebar_topo:sort(OProviderList) of |
|
|
|
{ok, ProviderList} -> |
|
|
|
ProviderList; |
|
|
|
{error, {cycle, _}} -> |
|
|
|
?ERROR("There was a cycle in the provider list. Unable to complete build!", []) |
|
|
|
end. |