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.erl131
1 files changed, 115 insertions, 16 deletions
diff --git a/src/rebar_app_info.erl b/src/rebar_app_info.erl
index 4f19d77..fdaadb8 100644
--- a/src/rebar_app_info.erl
+++ b/src/rebar_app_info.erl
@@ -103,11 +103,13 @@
new() ->
#app_info_t{}.
+%% @doc Build a new app info value with only the app name set.
-spec new(atom() | binary() | string()) ->
{ok, t()}.
new(AppName) ->
{ok, #app_info_t{name=ec_cnv:to_binary(AppName)}}.
+%% @doc Build a new app info value with only the name and version set.
-spec new(atom() | binary() | string(), binary() | string()) ->
{ok, t()}.
new(AppName, Vsn) ->
@@ -144,6 +146,9 @@ new(Parent, AppName, Vsn, Dir, Deps) ->
out_dir=ec_cnv:to_list(Dir),
deps=Deps}}.
+%% @doc update the opts based on the contents of a config
+%% file for the app
+-spec update_opts(t(), rebar_dict(), [any()]) -> t().
update_opts(AppInfo, Opts, Config) ->
LockDeps = case resource_type(AppInfo) of
pkg ->
@@ -163,6 +168,8 @@ update_opts(AppInfo, Opts, Config) ->
AppInfo#app_info_t{opts=NewOpts
,default=NewOpts}.
+%% @private extract the deps for an app in `Dir' based on its config file data
+-spec deps_from_config(file:filename(), [any()]) -> [{tuple(), any()}, ...].
deps_from_config(Dir, Config) ->
case rebar_config:consult_lock_file(filename:join(Dir, ?LOCK_FILE)) of
[] ->
@@ -184,30 +191,48 @@ discover(Dir) ->
not_found
end.
+%% @doc get the name of the app.
-spec name(t()) -> binary().
name(#app_info_t{name=Name}) ->
Name.
+%% @doc set the name of the app.
-spec name(t(), atom() | binary() | string()) -> t().
name(AppInfo=#app_info_t{}, AppName) ->
AppInfo#app_info_t{name=ec_cnv:to_binary(AppName)}.
+%% @doc get the dictionary of options for the app.
+-spec opts(t()) -> rebar_dict().
opts(#app_info_t{opts=Opts}) ->
Opts.
+%% @doc set the dictionary of options for the app.
+-spec opts(t(), rebar_dict()) -> t().
opts(AppInfo, Opts) ->
AppInfo#app_info_t{opts=Opts}.
+%% @doc get the dictionary of options under the default profile.
+%% Represents a root set prior to applying other profiles.
+-spec default(t()) -> rebar_dict().
default(#app_info_t{default=Default}) ->
Default.
+%% @doc set the dictionary of options under the default profile.
+%% Useful when re-applying profile.
+-spec default(t(), rebar_dict()) -> t().
default(AppInfo, Default) ->
AppInfo#app_info_t{default=Default}.
+%% @doc look up a value in the dictionary of options; fails if
+%% the key for it does not exist.
+-spec get(t(), term()) -> term().
get(AppInfo, Key) ->
{ok, Value} = dict:find(Key, AppInfo#app_info_t.opts),
Value.
+%% @doc look up a value in the dictionary of options; returns
+%% a `Default' value otherwise.
+-spec get(t(), term(), term()) -> term().
get(AppInfo, Key, Default) ->
case dict:find(Key, AppInfo#app_info_t.opts) of
{ok, Value} ->
@@ -216,10 +241,12 @@ get(AppInfo, Key, Default) ->
Default
end.
+%% @doc sets a given value in the dictionary of options for the app.
-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)}.
+%% @doc finds the .app.src file for an app, if any.
-spec app_file_src(t()) -> file:filename_all() | undefined.
app_file_src(#app_info_t{app_file_src=undefined, dir=Dir, name=Name}) ->
AppFileSrc = filename:join([ec_cnv:to_list(Dir), "src", ec_cnv:to_list(Name)++".app.src"]),
@@ -232,12 +259,15 @@ app_file_src(#app_info_t{app_file_src=undefined, dir=Dir, name=Name}) ->
app_file_src(#app_info_t{app_file_src=AppFileSrc}) ->
ec_cnv:to_list(AppFileSrc).
+%% @doc sets the .app.src file for an app. An app without such a file
+%% can explicitly be set with `undefined'.
-spec app_file_src(t(), file:filename_all() | undefined) -> t().
app_file_src(AppInfo=#app_info_t{}, undefined) ->
AppInfo#app_info_t{app_file_src=undefined};
app_file_src(AppInfo=#app_info_t{}, AppFileSrc) ->
AppInfo#app_info_t{app_file_src=ec_cnv:to_list(AppFileSrc)}.
+%% @doc finds the .app.src.script file for an app, if any.
-spec app_file_src_script(t()) -> file:filename_all() | undefined.
app_file_src_script(#app_info_t{app_file_src_script=undefined, dir=Dir, name=Name}) ->
AppFileSrcScript = filename:join([ec_cnv:to_list(Dir), "src", ec_cnv:to_list(Name)++".app.src.script"]),
@@ -250,12 +280,15 @@ app_file_src_script(#app_info_t{app_file_src_script=undefined, dir=Dir, name=Nam
app_file_src_script(#app_info_t{app_file_src_script=AppFileSrcScript}) ->
ec_cnv:to_list(AppFileSrcScript).
+%% @doc sets the .app.src.script file for an app. An app without such a file
+%% can explicitly be set with `undefined'.
-spec app_file_src_script(t(), file:filename_all()) -> t().
app_file_src_script(AppInfo=#app_info_t{}, undefined) ->
AppInfo#app_info_t{app_file_src_script=undefined};
app_file_src_script(AppInfo=#app_info_t{}, AppFileSrcScript) ->
AppInfo#app_info_t{app_file_src_script=ec_cnv:to_list(AppFileSrcScript)}.
+%% @doc finds the .app file for an app, if any.
-spec app_file(t()) -> file:filename_all() | undefined.
app_file(#app_info_t{app_file=undefined, out_dir=Dir, name=Name}) ->
AppFile = filename:join([ec_cnv:to_list(Dir), "ebin", ec_cnv:to_list(Name)++".app"]),
@@ -268,10 +301,13 @@ app_file(#app_info_t{app_file=undefined, out_dir=Dir, name=Name}) ->
app_file(#app_info_t{app_file=AppFile}) ->
AppFile.
+%% @doc sets the .app file for an app.
-spec app_file(t(), file:filename_all()) -> t().
app_file(AppInfo=#app_info_t{}, AppFile) ->
AppInfo#app_info_t{app_file=AppFile}.
+%% @doc returns the information stored in the app's app file,
+%% or if none, from the .app.src file.
-spec app_details(t()) -> list().
app_details(AppInfo=#app_info_t{app_details=[]}) ->
case app_file(AppInfo) of
@@ -290,59 +326,83 @@ app_details(AppInfo=#app_info_t{app_details=[]}) ->
app_details(#app_info_t{app_details=AppDetails}) ->
AppDetails.
+%% @doc stores the information that would be returned from the
+%% app file, when reading from `app_details/1'.
-spec app_details(t(), list()) -> t().
app_details(AppInfo=#app_info_t{}, AppDetails) ->
AppInfo#app_info_t{app_details=AppDetails}.
+%% @doc returns the app's parent in the dep tree.
+-spec parent(t()) -> root | binary().
parent(#app_info_t{parent=Parent}) ->
Parent.
+%% @doc sets the app's parent.
-spec parent(t(), binary() | root) -> t().
parent(AppInfo=#app_info_t{}, Parent) ->
AppInfo#app_info_t{parent=Parent}.
+%% @doc returns the original version of the app (unevaluated if
+%% asking for a semver)
-spec original_vsn(t()) -> string().
original_vsn(#app_info_t{original_vsn=Vsn}) ->
Vsn.
+%% @doc stores the original version of the app (unevaluated if
+%% asking for a semver)
-spec original_vsn(t(), string()) -> t().
original_vsn(AppInfo=#app_info_t{}, Vsn) ->
AppInfo#app_info_t{original_vsn=Vsn}.
+%% @doc returns the list of applications the app depends on.
-spec applications(t()) -> list().
applications(#app_info_t{applications=Applications}) ->
Applications.
+%% @doc sets the list of applications the app depends on.
+%% Should be obtained from the app file.
-spec applications(t(), list()) -> t().
applications(AppInfo=#app_info_t{}, Applications) ->
AppInfo#app_info_t{applications=Applications}.
+%% @doc returns the list of active profiles
-spec profiles(t()) -> list().
profiles(#app_info_t{profiles=Profiles}) ->
Profiles.
+%% @doc sets the list of active profiles
-spec profiles(t(), list()) -> t().
profiles(AppInfo=#app_info_t{}, Profiles) ->
AppInfo#app_info_t{profiles=Profiles}.
+%% @doc returns the list of dependencies
-spec deps(t()) -> list().
deps(#app_info_t{deps=Deps}) ->
Deps.
+%% @doc sets the list of dependencies.
-spec deps(t(), list()) -> t().
deps(AppInfo=#app_info_t{}, Deps) ->
AppInfo#app_info_t{deps=Deps}.
-dep_level(AppInfo=#app_info_t{}, Level) ->
- AppInfo#app_info_t{dep_level=Level}.
-
+%% @doc returns the level the app has in the lock files or in the
+%% dep tree.
+-spec dep_level(t()) -> non_neg_integer().
dep_level(#app_info_t{dep_level=Level}) ->
Level.
+%% @doc sets the level the app has in the lock files or in the
+%% dep tree.
+-spec dep_level(t(), non_neg_integer()) -> t().
+dep_level(AppInfo=#app_info_t{}, Level) ->
+ AppInfo#app_info_t{dep_level=Level}.
+
+%% @doc returns the directory that contains the app.
-spec dir(t()) -> file:name().
dir(#app_info_t{dir=Dir}) ->
Dir.
+%% @doc sets the directory that contains the app.
-spec dir(t(), file:name()) -> t().
dir(AppInfo=#app_info_t{out_dir=undefined}, Dir) ->
AppInfo#app_info_t{dir=ec_cnv:to_list(Dir),
@@ -350,54 +410,69 @@ dir(AppInfo=#app_info_t{out_dir=undefined}, Dir) ->
dir(AppInfo=#app_info_t{}, Dir) ->
AppInfo#app_info_t{dir=ec_cnv:to_list(Dir)}.
+%% @doc returns the directory where build artifacts for the app
+%% should go
-spec out_dir(t()) -> file:name().
out_dir(#app_info_t{out_dir=OutDir}) ->
OutDir.
+%% @doc sets the directory where build artifacts for the app
+%% should go
-spec out_dir(t(), file:name()) -> t().
out_dir(AppInfo=#app_info_t{}, OutDir) ->
AppInfo#app_info_t{out_dir=ec_cnv:to_list(OutDir)}.
+%% @doc gets the directory where ebin files for the app should go
-spec ebin_dir(t()) -> file:name().
ebin_dir(#app_info_t{out_dir=OutDir}) ->
ec_cnv:to_list(filename:join(OutDir, "ebin")).
+%% @doc gets the directory where private files for the app should go
-spec priv_dir(t()) -> file:name().
priv_dir(#app_info_t{out_dir=OutDir}) ->
ec_cnv:to_list(filename:join(OutDir, "priv")).
--spec resource_type(t(), pkg | src) -> t().
-resource_type(AppInfo=#app_info_t{}, Type) ->
- AppInfo#app_info_t{resource_type=Type}.
-
+%% @doc returns whether the app is source app or a package app.
-spec resource_type(t()) -> pkg | src.
resource_type(#app_info_t{resource_type=ResourceType}) ->
ResourceType.
--spec source(t(), string() | tuple() | checkout) -> t().
-source(AppInfo=#app_info_t{}, Source) ->
- AppInfo#app_info_t{source=Source}.
+%% @doc sets whether the app is source app or a package app.
+-spec resource_type(t(), pkg | src) -> t().
+resource_type(AppInfo=#app_info_t{}, Type) ->
+ AppInfo#app_info_t{resource_type=Type}.
+%% @doc finds the source specification for the app
-spec source(t()) -> string() | tuple().
source(#app_info_t{source=Source}) ->
Source.
--spec is_lock(t(), boolean()) -> t().
-is_lock(AppInfo=#app_info_t{}, IsLock) ->
- AppInfo#app_info_t{is_lock=IsLock}.
+%% @doc sets the source specification for the app
+-spec source(t(), string() | tuple() | checkout) -> t().
+source(AppInfo=#app_info_t{}, Source) ->
+ AppInfo#app_info_t{source=Source}.
+%% @doc returns the lock status for the app
-spec is_lock(t()) -> boolean().
is_lock(#app_info_t{is_lock=IsLock}) ->
IsLock.
--spec is_checkout(t(), boolean()) -> t().
-is_checkout(AppInfo=#app_info_t{}, IsCheckout) ->
- AppInfo#app_info_t{is_checkout=IsCheckout}.
+%% @doc sets the lock status for the app
+-spec is_lock(t(), boolean()) -> t().
+is_lock(AppInfo=#app_info_t{}, IsLock) ->
+ AppInfo#app_info_t{is_lock=IsLock}.
+%% @doc returns whether the app is a checkout app or not
-spec is_checkout(t()) -> boolean().
is_checkout(#app_info_t{is_checkout=IsCheckout}) ->
IsCheckout.
+%% @doc sets whether the app is a checkout app or not
+-spec is_checkout(t(), boolean()) -> t().
+is_checkout(AppInfo=#app_info_t{}, IsCheckout) ->
+ AppInfo#app_info_t{is_checkout=IsCheckout}.
+
+%% @doc returns whether the app is valid (built) or not
-spec valid(t()) -> boolean().
valid(AppInfo=#app_info_t{valid=undefined}) ->
case rebar_app_utils:validate_application_info(AppInfo) =:= true
@@ -410,14 +485,22 @@ valid(AppInfo=#app_info_t{valid=undefined}) ->
valid(#app_info_t{valid=Valid}) ->
Valid.
+%% @doc sets whether the app is valid (built) or not. If left unset,
+%% rebar3 will do the detection of the status itself.
-spec valid(t(), boolean()) -> t().
valid(AppInfo=#app_info_t{}, Valid) ->
AppInfo#app_info_t{valid=Valid}.
+%% @doc checks whether the app can be built with the current
+%% Erlang/OTP version. If the check fails, the function raises
+%% an exception and displays an error.
+-spec verify_otp_vsn(t()) -> ok | no_return().
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, [])).
+%% @doc checks whether all the build artifacts for an app to be considered
+%% valid are present.
-spec has_all_artifacts(#app_info_t{}) -> true | {false, file:filename()}.
has_all_artifacts(AppInfo) ->
Artifacts = rebar_app_info:get(AppInfo, artifacts, []),
@@ -427,6 +510,10 @@ has_all_artifacts(AppInfo) ->
,{out_dir, OutDir}],
all(OutDir, Context, Artifacts).
+%% @private checks that all files/artifacts in the directory are found.
+%% Template evaluation must happen and a bbmustache context needs to
+%% be provided.
+-spec all(file:filename(), term(), [string()]) -> true | {false, string()}.
all(_, _, []) ->
true;
all(Dir, Context, [File|Artifacts]) ->
@@ -441,15 +528,23 @@ all(Dir, Context, [File|Artifacts]) ->
%%%%%
+%% @doc given a set of override rules, modify the app info accordingly
+-spec apply_overrides(list(), t()) -> t().
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}.
+%% @doc adds a new profile with its own config to the app data
+-spec add_to_profile(t(), atom(), [{_,_}]) -> t().
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}.
+%% @doc applies and merges the profile configuration in the specified order
+%% of profiles (or for a single profile) and returns an app info record
+%% with the resulting configuration
+-spec apply_profiles(t(), atom() | [atom(),...]) -> t().
apply_profiles(AppInfo, Profile) when not is_list(Profile) ->
apply_profiles(AppInfo, [Profile]);
apply_profiles(AppInfo, [default]) ->
@@ -481,9 +576,13 @@ apply_profiles(AppInfo=#app_info_t{default = Defaults, profiles=CurrentProfiles}
end, Defaults, AppliedProfiles),
AppInfo#app_info_t{profiles = AppliedProfiles, opts=NewOpts}.
+%% @private drops duplicated profile definitions
+-spec deduplicate(list()) -> list().
deduplicate(Profiles) ->
do_deduplicate(lists:reverse(Profiles), []).
+%% @private drops duplicated profile definitions
+-spec do_deduplicate(list(), list()) -> list().
do_deduplicate([], Acc) ->
Acc;
do_deduplicate([Head | Rest], Acc) ->