summaryrefslogtreecommitdiff
path: root/src/rebar_app_info.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/rebar_app_info.erl')
-rw-r--r--src/rebar_app_info.erl192
1 files changed, 159 insertions, 33 deletions
diff --git a/src/rebar_app_info.erl b/src/rebar_app_info.erl
index bb5104e..92706f3 100644
--- a/src/rebar_app_info.erl
+++ b/src/rebar_app_info.erl
@@ -1,15 +1,15 @@
-module(rebar_app_info).
--export([new/1,
+-export([new/0,
+ new/1,
new/2,
new/3,
new/4,
new/5,
+ update_opts/3,
discover/1,
name/1,
name/2,
- config/1,
- config/2,
app_file_src/1,
app_file_src/2,
app_file_src_script/1,
@@ -35,21 +35,35 @@
dir/2,
out_dir/1,
out_dir/2,
+ default/1,
+ default/2,
+ opts/1,
+ opts/2,
+ get/2,
+ get/3,
+ set/3,
resource_type/1,
resource_type/2,
source/1,
source/2,
- state/1,
- state/2,
- state_or_new/2,
is_lock/1,
is_lock/2,
is_checkout/1,
is_checkout/2,
valid/1,
- valid/2]).
+ valid/2,
+
+ verify_otp_vsn/1,
+ has_all_artifacts/1,
+
+ apply_overrides/2,
+ add_to_profile/3,
+ apply_profiles/2,
+ deduplicate/1,
+ do_deduplicate/2]).
-include("rebar.hrl").
+-include_lib("providers/include/providers.hrl").
-export_type([t/0]).
@@ -57,19 +71,19 @@
app_file_src :: file:filename_all() | undefined,
app_file_src_script:: file:filename_all() | undefined,
app_file :: file:filename_all() | undefined,
- config :: rebar_state:t() | undefined,
original_vsn :: binary() | string() | undefined,
parent=root :: binary() | root,
app_details=[] :: list(),
applications=[] :: list(),
deps=[] :: list(),
profiles=[default] :: [atom()],
+ default=dict:new() :: rebar_dict(),
+ opts=dict:new() :: rebar_dict(),
dep_level=0 :: integer(),
dir :: file:name(),
out_dir :: file:name(),
resource_type :: pkg | src,
source :: string() | tuple() | undefined,
- state :: rebar_state:t() | undefined,
is_lock=false :: boolean(),
is_checkout=false :: boolean(),
valid :: boolean()}).
@@ -84,6 +98,10 @@
%% ============================================================================
%% @doc Build a new, empty, app info value. This is not of a lot of use and you
%% probably wont be doing this much.
+-spec new() -> t().
+new() ->
+ #app_info_t{}.
+
-spec new(atom() | binary() | string()) ->
{ok, t()}.
new(AppName) ->
@@ -125,6 +143,36 @@ new(Parent, AppName, Vsn, Dir, Deps) ->
out_dir=ec_cnv:to_list(Dir),
deps=Deps}}.
+update_opts(AppInfo, Opts, Config) ->
+ LockDeps = case resource_type(AppInfo) of
+ pkg ->
+ Deps = deps(AppInfo),
+ [{{locks, default}, Deps}, {{deps, default}, Deps}];
+ _ ->
+ deps_from_config(dir(AppInfo), Config)
+ end,
+
+ Plugins = proplists:get_value(plugins, Config, []),
+ Terms = LockDeps++[{{plugins, default}, Plugins} | Config],
+ true = rebar_config:verify_config_format(Terms),
+ LocalOpts = dict:from_list(Terms),
+
+ NewOpts = rebar_opts:merge_opts(LocalOpts, Opts),
+
+ AppInfo#app_info_t{opts=NewOpts
+ ,default=NewOpts}.
+
+deps_from_config(Dir, Config) ->
+ case rebar_config:consult_lock_file(filename:join(Dir, ?LOCK_FILE)) of
+ [D] ->
+ %% We want the top level deps only from the lock file.
+ %% This ensures deterministic overrides for configs.
+ Deps = [X || X <- D, element(3, X) =:= 0],
+ [{{locks, default}, D}, {{deps, default}, Deps}];
+ _ ->
+ [{{deps, default}, proplists:get_value(deps, Config, [])}]
+ end.
+
%% @doc discover a complete version of the app info with all fields set.
-spec discover(file:filename_all()) -> {ok, t()} | not_found.
discover(Dir) ->
@@ -143,13 +191,33 @@ name(#app_info_t{name=Name}) ->
name(AppInfo=#app_info_t{}, AppName) ->
AppInfo#app_info_t{name=ec_cnv:to_binary(AppName)}.
--spec config(t()) -> rebar_state:t().
-config(#app_info_t{config=Config}) ->
- Config.
+opts(#app_info_t{opts=Opts}) ->
+ Opts.
+
+opts(AppInfo, Opts) ->
+ AppInfo#app_info_t{opts=Opts}.
+
+default(#app_info_t{default=Default}) ->
+ Default.
+
+default(AppInfo, Default) ->
+ AppInfo#app_info_t{default=Default}.
+
+get(AppInfo, Key) ->
+ {ok, Value} = dict:find(Key, AppInfo#app_info_t.opts),
+ Value.
+
+get(AppInfo, Key, Default) ->
+ case dict:find(Key, AppInfo#app_info_t.opts) of
+ {ok, Value} ->
+ Value;
+ error ->
+ Default
+ end.
--spec config(t(), rebar_state:t()) -> t().
-config(AppInfo=#app_info_t{}, Config) ->
- AppInfo#app_info_t{config=Config}.
+-spec set(t(), any(), any()) -> t().
+set(AppInfo=#app_info_t{opts=Opts}, Key, Value) ->
+ AppInfo#app_info_t{opts = dict:store(Key, Value, Opts)}.
-spec app_file_src(t()) -> file:filename_all() | undefined.
app_file_src(#app_info_t{app_file_src=undefined, dir=Dir, name=Name}) ->
@@ -305,22 +373,6 @@ source(AppInfo=#app_info_t{}, Source) ->
source(#app_info_t{source=Source}) ->
Source.
--spec state(t(), rebar_state:t() | undefined) -> t().
-state(AppInfo=#app_info_t{}, State) ->
- AppInfo#app_info_t{state=State}.
-
--spec state(t()) -> rebar_state:t() | undefined.
-state(#app_info_t{state=State}) ->
- State.
-
--spec state_or_new(rebar_state:t(), t()) -> rebar_state:t().
-state_or_new(State, AppInfo=#app_info_t{state=undefined}) ->
- AppDir = dir(AppInfo),
- C = rebar_config:consult(AppDir),
- rebar_state:new(State, C, AppInfo);
-state_or_new(_State, #app_info_t{state=State}) ->
- State.
-
-spec is_lock(t(), boolean()) -> t().
is_lock(AppInfo=#app_info_t{}, IsLock) ->
AppInfo#app_info_t{is_lock=IsLock}.
@@ -338,9 +390,9 @@ is_checkout(#app_info_t{is_checkout=IsCheckout}) ->
IsCheckout.
-spec valid(t()) -> boolean().
-valid(AppInfo=#app_info_t{valid=undefined, state=State}) ->
+valid(AppInfo=#app_info_t{valid=undefined}) ->
case rebar_app_utils:validate_application_info(AppInfo) =:= true
- andalso rebar_state:has_all_artifacts(State) =:= true of
+ andalso has_all_artifacts(AppInfo) =:= true of
true ->
true;
_ ->
@@ -352,3 +404,77 @@ valid(#app_info_t{valid=Valid}) ->
-spec valid(t(), boolean()) -> t().
valid(AppInfo=#app_info_t{}, Valid) ->
AppInfo#app_info_t{valid=Valid}.
+
+verify_otp_vsn(AppInfo) ->
+ rebar_utils:check_min_otp_version(rebar_app_info:get(AppInfo, minimum_otp_vsn, undefined)),
+ rebar_utils:check_blacklisted_otp_versions(rebar_app_info:get(AppInfo, blacklisted_otp_vsns, [])).
+
+-spec has_all_artifacts(#app_info_t{}) -> true | {false, file:filename()}.
+has_all_artifacts(AppInfo) ->
+ Artifacts = rebar_app_info:get(AppInfo, artifacts, []),
+ Dir = dir(AppInfo),
+ all(Dir, Artifacts).
+
+all(_, []) ->
+ true;
+all(Dir, [File|Artifacts]) ->
+ case filelib:is_regular(filename:join(Dir, File)) of
+ false ->
+ ?DEBUG("Missing artifact ~s", [filename:join(Dir, File)]),
+ {false, File};
+ true ->
+ all(Dir, Artifacts)
+ end.
+
+%%%%%
+
+apply_overrides(Overrides, AppInfo) ->
+ Name = binary_to_atom(rebar_app_info:name(AppInfo), utf8),
+ Opts = rebar_opts:apply_overrides(opts(AppInfo), Name, Overrides),
+ AppInfo#app_info_t{default=Opts, opts=Opts}.
+
+add_to_profile(AppInfo, Profile, KVs) when is_atom(Profile), is_list(KVs) ->
+ Opts = rebar_opts:add_to_profile(opts(AppInfo), Profile, KVs),
+ AppInfo#app_info_t{opts=Opts}.
+
+apply_profiles(AppInfo, Profile) when not is_list(Profile) ->
+ apply_profiles(AppInfo, [Profile]);
+apply_profiles(AppInfo, [default]) ->
+ AppInfo;
+apply_profiles(AppInfo=#app_info_t{default = Defaults, profiles=CurrentProfiles}, Profiles) ->
+ 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;
+ _ ->
+ deduplicate(CurrentProfiles ++ Profiles)
+ end,
+
+ ConfigProfiles = rebar_app_info:get(AppInfo, profiles, []),
+
+ NewOpts =
+ lists:foldl(fun(default, OptsAcc) ->
+ OptsAcc;
+ (Profile, OptsAcc) ->
+ case proplists:get_value(Profile, ConfigProfiles, []) of
+ OptsList when is_list(OptsList) ->
+ ProfileOpts = dict:from_list(OptsList),
+ rebar_opts:merge_opts(Profile, ProfileOpts, OptsAcc);
+ Other ->
+ throw(?PRV_ERROR({profile_not_list, Profile, Other}))
+ end
+ end, Defaults, AppliedProfiles),
+ AppInfo#app_info_t{profiles = AppliedProfiles, opts=NewOpts}.
+
+deduplicate(Profiles) ->
+ do_deduplicate(lists:reverse(Profiles), []).
+
+do_deduplicate([], Acc) ->
+ Acc;
+do_deduplicate([Head | Rest], Acc) ->
+ case lists:member(Head, Acc) of
+ true -> do_deduplicate(Rest, Acc);
+ false -> do_deduplicate(Rest, [Head | Acc])
+ end.