summaryrefslogtreecommitdiff
path: root/src/rebar_state.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/rebar_state.erl')
-rw-r--r--src/rebar_state.erl165
1 files changed, 121 insertions, 44 deletions
diff --git a/src/rebar_state.erl b/src/rebar_state.erl
index bdd4aeb..31d3a08 100644
--- a/src/rebar_state.erl
+++ b/src/rebar_state.erl
@@ -38,6 +38,12 @@
to_list/1,
+ compilers/1, compilers/2,
+ prepend_compilers/2, append_compilers/2,
+
+ project_builders/1, add_project_builder/3,
+
+ create_resources/2, set_resources/2,
resources/1, resources/2, add_resource/2,
providers/1, providers/2, add_provider/2,
allow_provider_overrides/1, allow_provider_overrides/2
@@ -59,12 +65,14 @@
command_args = [],
command_parsed_args = {[], []},
- current_app :: rebar_app_info:t(),
+ current_app :: undefined | rebar_app_info:t(),
project_apps = [] :: [rebar_app_info:t()],
deps_to_build = [] :: [rebar_app_info:t()],
all_plugin_deps = [] :: [rebar_app_info:t()],
all_deps = [] :: [rebar_app_info:t()],
+ compilers = [] :: [{compiler_type(), extension(), extension(), compile_fun()}],
+ project_builders = [] :: [{rebar_app_info:project_type(), module()}],
resources = [],
providers = [],
allow_provider_overrides = false :: boolean()}).
@@ -73,28 +81,30 @@
-type t() :: #state_t{}.
+-type compiler_type() :: atom().
+-type extension() :: string().
+-type compile_fun() :: fun(([file:filename()], rebar_app_info:t(), list()) -> ok).
+
-spec new() -> t().
new() ->
- BaseState = base_state(),
+ BaseState = base_state(dict:new()),
BaseState#state_t{dir = rebar_dir:get_cwd()}.
-spec new(list()) -> t().
new(Config) when is_list(Config) ->
- BaseState = base_state(),
Opts = base_opts(Config),
- BaseState#state_t { dir = rebar_dir:get_cwd(),
- default = Opts,
- opts = Opts }.
+ BaseState = base_state(Opts),
+ BaseState#state_t{dir=rebar_dir:get_cwd(),
+ default=Opts}.
-spec new(t() | atom(), list()) -> t().
new(Profile, Config) when is_atom(Profile)
, is_list(Config) ->
- BaseState = base_state(),
Opts = base_opts(Config),
- BaseState#state_t { dir = rebar_dir:get_cwd(),
- current_profiles = [Profile],
- default = Opts,
- opts = Opts };
+ BaseState = base_state(Opts),
+ BaseState#state_t{dir = rebar_dir:get_cwd(),
+ current_profiles = [Profile],
+ default = Opts};
new(ParentState=#state_t{}, Config) ->
%% Load terms from rebar.config, if it exists
Dir = rebar_dir:get_cwd(),
@@ -129,20 +139,15 @@ deps_from_config(Dir, Config) ->
[{{locks, default}, D}, {{deps, default}, Deps}]
end.
-base_state() ->
- case application:get_env(rebar, resources) of
- undefined ->
- Resources = [];
- {ok, Resources} ->
- Resources
- end,
- #state_t{resources=Resources}.
+base_state(Opts) ->
+ #state_t{opts=Opts}.
base_opts(Config) ->
Deps = proplists:get_value(deps, Config, []),
Plugins = proplists:get_value(plugins, Config, []),
ProjectPlugins = proplists:get_value(project_plugins, Config, []),
- Terms = [{{deps, default}, Deps}, {{plugins, default}, Plugins}, {{project_plugins, default}, ProjectPlugins} | Config],
+ Terms = [{{deps, default}, Deps}, {{plugins, default}, Plugins},
+ {{project_plugins, default}, ProjectPlugins} | Config],
true = rebar_config:verify_config_format(Terms),
dict:from_list(Terms).
@@ -182,7 +187,7 @@ all(_, []) ->
all(Dir, [File|Artifacts]) ->
case filelib:is_regular(filename:join(Dir, File)) of
false ->
- ?DEBUG("Missing artifact ~s", [filename:join(Dir, File)]),
+ ?DEBUG("Missing artifact ~ts", [filename:join(Dir, File)]),
{false, File};
true ->
all(Dir, Artifacts)
@@ -257,12 +262,15 @@ apply_profiles(State, Profile) when not is_list(Profile) ->
apply_profiles(State, [default]) ->
State;
apply_profiles(State=#state_t{default = Defaults, current_profiles=CurrentProfiles}, Profiles) ->
+ ProvidedProfiles = lists:prefix([default|Profiles], CurrentProfiles),
AppliedProfiles = case Profiles of
%% Head of list global profile is special, only for use by rebar3
%% It does not clash if a user does `rebar3 as global...` but when
%% it is the head we must make sure not to prepend `default`
[global | _] ->
Profiles;
+ _ when ProvidedProfiles ->
+ deduplicate(CurrentProfiles);
_ ->
deduplicate(CurrentProfiles ++ Profiles)
end,
@@ -302,9 +310,9 @@ dir(State=#state_t{}, Dir) ->
deps_names(Deps) when is_list(Deps) ->
lists:map(fun(Dep) when is_tuple(Dep) ->
- ec_cnv:to_binary(element(1, Dep));
+ rebar_utils:to_binary(element(1, Dep));
(Dep) when is_atom(Dep) ->
- ec_cnv:to_binary(Dep)
+ rebar_utils:to_binary(Dep)
end, Deps);
deps_names(State) ->
Deps = rebar_state:get(State, deps, []),
@@ -356,18 +364,80 @@ namespace(#state_t{namespace=Namespace}) ->
namespace(State=#state_t{}, Namespace) ->
State#state_t{namespace=Namespace}.
--spec resources(t()) -> [{rebar_resource:type(), module()}].
+-spec resources(t()) -> [{rebar_resource_v2:type(), module()}].
resources(#state_t{resources=Resources}) ->
Resources.
--spec resources(t(), [{rebar_resource:type(), module()}]) -> t().
-resources(State, NewResources) ->
- State#state_t{resources=NewResources}.
+-spec set_resources(t(), [{rebar_resource_v2:type(), module()}]) -> t().
+set_resources(State, Resources) ->
+ State#state_t{resources=Resources}.
--spec add_resource(t(), {rebar_resource:type(), module()}) -> t().
-add_resource(State=#state_t{resources=Resources}, Resource) ->
+-spec resources(t(), [{rebar_resource_v2:type(), module()}]) -> t().
+resources(State, NewResources) ->
+ lists:foldl(fun(Resource, StateAcc) ->
+ add_resource(StateAcc, Resource)
+ end, State, NewResources).
+
+-spec add_resource(t(), {rebar_resource_v2:type(), module()}) -> t().
+add_resource(State=#state_t{resources=Resources}, {ResourceType, ResourceModule}) ->
+ _ = code:ensure_loaded(ResourceModule),
+ Resource = case erlang:function_exported(ResourceModule, init, 2) of
+ true ->
+ case ResourceModule:init(ResourceType, State) of
+ {ok, R=#resource{}} ->
+ R;
+ _ ->
+ %% init didn't return a resource
+ %% must be an old resource
+ warn_old_resource(ResourceModule),
+ rebar_resource:new(ResourceType,
+ ResourceModule,
+ #{})
+ end;
+ false ->
+ %% no init, must be initial implementation
+ warn_old_resource(ResourceModule),
+ rebar_resource:new(ResourceType,
+ ResourceModule,
+ #{})
+ end,
State#state_t{resources=[Resource | Resources]}.
+warn_old_resource(ResourceModule) ->
+ ?WARN("Using custom resource ~s that implements a deprecated api. "
+ "It should be upgraded to rebar_resource_v2.", [ResourceModule]).
+
+compilers(#state_t{compilers=Compilers}) ->
+ Compilers.
+
+prepend_compilers(State=#state_t{compilers=Compilers}, NewCompilers) ->
+ State#state_t{compilers=NewCompilers++Compilers}.
+
+append_compilers(State=#state_t{compilers=Compilers}, NewCompilers) ->
+ State#state_t{compilers=Compilers++NewCompilers}.
+
+compilers(State, Compilers) ->
+ State#state_t{compilers=Compilers}.
+
+project_builders(#state_t{project_builders=ProjectBuilders}) ->
+ ProjectBuilders.
+
+add_project_builder(State=#state_t{project_builders=ProjectBuilders}, Type, Module) ->
+ _ = code:ensure_loaded(Module),
+ case erlang:function_exported(Module, build, 1) of
+ true ->
+ State#state_t{project_builders=[{Type, Module} | ProjectBuilders]};
+ false ->
+ ?WARN("Unable to add project builder for type ~s, required function ~s:build/1 not found.",
+ [Type, Module]),
+ State
+ end.
+
+create_resources(Resources, State) ->
+ lists:foldl(fun(R, StateAcc) ->
+ add_resource(StateAcc, R)
+ end, State, Resources).
+
providers(#state_t{providers=Providers}) ->
Providers.
@@ -391,7 +461,7 @@ add_provider(State=#state_t{providers=Providers, allow_provider_overrides=false}
case {providers:impl(P), providers:namespace(P)} of
{Name, Namespace} ->
?DEBUG("Not adding provider ~p ~p from module ~p because it already exists from module ~p",
- [Namespace, Name, providers:module(P), Module]),
+ [Namespace, Name, Module, providers:module(P)]),
true;
_ ->
false
@@ -415,26 +485,33 @@ create_logic_providers(ProviderModules, State0) ->
end
end, State0, ProviderModules)
catch
- C:T ->
- ?DEBUG("~p: ~p ~p", [C, T, erlang:get_stacktrace()]),
- ?CRASHDUMP("~p: ~p~n~p~n~n~p", [C, T, erlang:get_stacktrace(), State0]),
+ ?WITH_STACKTRACE(C,T,S)
+ ?DEBUG("~p: ~p ~p", [C, T, S]),
+ ?CRASHDUMP("~p: ~p~n~p~n~n~p", [C, T, S, State0]),
throw({error, "Failed creating providers. Run with DEBUG=1 for stacktrace or consult rebar3.crashdump."})
end.
to_list(#state_t{} = State) ->
Fields = record_info(fields, state_t),
Values = tl(tuple_to_list(State)),
- DictSz = tuple_size(dict:new()),
- lists:zip(Fields, [reformat(I, DictSz) || I <- Values]).
-
-reformat({K,V}, DSz) when is_list(V) ->
- {K, [reformat(I, DSz) || I <- V]};
-reformat(V, DSz) when is_tuple(V), element(1,V) =:= dict, tuple_size(V) =:= DSz ->
- [reformat(I, DSz) || I <- dict:to_list(V)];
-reformat({K,V}, DSz) when is_tuple(V), element(1,V) =:= dict, tuple_size(V) =:= DSz ->
- {K, [reformat(I, DSz) || I <- dict:to_list(V)]};
-reformat(Other, _DSz) ->
- Other.
+ lists:zip(Fields, [reformat(I) || I <- Values]).
+
+reformat({K,V}) when is_list(V) ->
+ {K, [reformat(I) || I <- V]};
+reformat({K,V}) ->
+ try
+ {K, [reformat(I) || I <- dict:to_list(V)]}
+ catch
+ error:{badrecord,dict} ->
+ {K,V}
+ end;
+reformat(V) ->
+ try
+ [reformat(I) || I <- dict:to_list(V)]
+ catch
+ error:{badrecord,dict} ->
+ V
+ end.
%% ===================================================================
%% Internal functions