summaryrefslogtreecommitdiff
path: root/src/rebar_prv_install_deps.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/rebar_prv_install_deps.erl')
-rw-r--r--src/rebar_prv_install_deps.erl143
1 files changed, 82 insertions, 61 deletions
diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl
index 3e13fc2..ebb877b 100644
--- a/src/rebar_prv_install_deps.erl
+++ b/src/rebar_prv_install_deps.erl
@@ -42,6 +42,11 @@
-define(PROVIDER, install_deps).
-define(DEPS, [app_discovery]).
+-type src_dep() :: {atom(), string(), {atom(), string(), string()}}.
+-type binary_dep() :: {atom(), binary()} | atom().
+
+-type dep() :: src_dep() | binary_dep().
+
%% ===================================================================
%% Public API
%% ===================================================================
@@ -60,53 +65,9 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()}.
do(State) ->
- %% Read in package index and dep graph
- {Packages, Graph} = rebar_packages:get_packages(State),
case rebar_state:get(State, locks, []) of
[] ->
- case rebar_state:get(State, deps, []) of
- [] ->
- {ok, State};
- Deps ->
- %% Split source deps form binary deps, needed to keep backwards compatibility
- DepsDir = get_deps_dir(State),
- {SrcDeps, Goals} = parse_deps(DepsDir, Deps),
- State1 = rebar_state:src_deps(rebar_state:goals(State, Goals), lists:ukeysort(2, SrcDeps)),
- State2 = update_src_deps(State1),
- case rebar_state:goals(State2) of
- [] ->
- ProjectApps = lists:map(fun(X) ->
- rebar_app_info:deps(X, [rebar_app_info:name(Y) || Y <- SrcDeps])
- end, rebar_state:apps_to_build(State2)),
- FinalDeps = ProjectApps ++ rebar_state:src_deps(State2),
- {ok, Sort} = rebar_topo:sort_apps(FinalDeps),
- State3 = rebar_state:apps_to_build(State2, Sort),
- {ok, State3};
- Goals1 ->
- {ok, Solved} = rlx_depsolver:solve(Graph, Goals1),
- Final = lists:map(fun({Name, Vsn}) ->
- FmtVsn = ec_cnv:to_binary(rlx_depsolver:format_version(Vsn)),
- {ok, P} = dict:find({Name, FmtVsn}, Packages),
- PkgDeps = proplists:get_value(<<"deps">>, P),
- Link = proplists:get_value(<<"link">>, P),
- Source = {Name, FmtVsn, Link},
- {ok, AppInfo} = rebar_app_info:new(Name, FmtVsn),
- AppInfo1 = rebar_app_info:deps(AppInfo, PkgDeps),
- AppInfo2 =
- rebar_app_info:dir(AppInfo1, get_deps_dir(DepsDir, <<Name/binary, "-", FmtVsn/binary>>)),
- AppInfo3 = rebar_app_info:source(AppInfo2, Source),
- ok = maybe_fetch(AppInfo3),
- AppInfo3
- end, Solved),
- ProjectApps = lists:map(fun(X) ->
- rebar_app_info:deps(X, [rebar_app_info:name(Y) || Y <- SrcDeps] ++ [element(1, G) || G <- Goals1])
- end, rebar_state:apps_to_build(State2)),
- FinalDeps = ProjectApps ++ rebar_state:src_deps(State2) ++ Final,
- {ok, Sort} = rebar_topo:sort_apps(FinalDeps),
- State3 = rebar_state:apps_to_build(State2, Sort),
- {ok, State3}
- end
- end;
+ handle_deps(State, rebar_state:get(State, deps, []));
_Locks ->
{ok, State}
end.
@@ -130,10 +91,12 @@ setup_env(State) ->
[{"REBAR_DEPS_DIR", DepsDir}, ERL_LIBS].
+-spec get_deps_dir(rebar_state:t()) -> file:filename_all().
get_deps_dir(State) ->
BaseDir = rebar_state:get(State, base_dir, ""),
get_deps_dir(BaseDir, "deps").
+-spec get_deps_dir(file:filename_all(), rebar_state:t()) -> file:filename_all().
get_deps_dir(DepsDir, App) ->
filename:join(DepsDir, App).
@@ -141,28 +104,84 @@ get_deps_dir(DepsDir, App) ->
%% Internal functions
%% ===================================================================
+handle_deps(State, []) ->
+ {ok, State};
+handle_deps(State, Deps) ->
+ %% Read in package index and dep graph
+ {Packages, Graph} = rebar_packages:get_packages(State),
+ ProjectApps = rebar_state:project_apps(State),
+
+ %% Split source deps form binary deps, needed to keep backwards compatibility
+ DepsDir = get_deps_dir(State),
+ {SrcDeps, BinaryDeps} = parse_deps(DepsDir, Deps),
+ State1 = rebar_state:src_deps(rebar_state:binary_deps(State, BinaryDeps),
+ lists:ukeysort(2, SrcDeps)),
+
+ %% Fetch transitive src deps
+ State2 = update_src_deps(State1),
+ Solved = case rebar_state:binary_deps(State2) of
+ [] -> %% No binary deps
+ [];
+ BinaryDeps1 ->
+ %% Find binary deps needed
+ {ok, S} = rlx_depsolver:solve(Graph, BinaryDeps1),
+
+ %% Create app_info record for each binary dep
+ lists:map(fun({Name, Vsn}) ->
+ AppInfo = package_to_app(DepsDir
+ ,Packages
+ ,Name
+ ,Vsn),
+ ok = maybe_fetch(AppInfo),
+ AppInfo
+ end, S)
+ end,
+
+ FinalDeps = ProjectApps ++ rebar_state:src_deps(State2) ++ Solved,
+ %% Sort all apps to build order
+ {ok, Sort} = rebar_topo:sort_apps(FinalDeps),
+ {ok, rebar_state:project_apps(State2, Sort)}.
+
+-spec package_to_app(file:name(), dict:dict(), binary(), binary()) -> rebar_app_info:t().
+package_to_app(DepsDir, Packages, Name, Vsn) ->
+ FmtVsn = ec_cnv:to_binary(rlx_depsolver:format_version(Vsn)),
+
+ {ok, P} = dict:find({Name, FmtVsn}, Packages),
+ PkgDeps = proplists:get_value(<<"deps">>, P),
+ Link = proplists:get_value(<<"link">>, P),
+
+ {ok, AppInfo} = rebar_app_info:new(Name, FmtVsn),
+ AppInfo1 = rebar_app_info:deps(AppInfo, PkgDeps),
+ AppInfo2 =
+ rebar_app_info:dir(AppInfo1, get_deps_dir(DepsDir, <<Name/binary, "-", FmtVsn/binary>>)),
+ rebar_app_info:source(AppInfo2, {Name, FmtVsn, Link}).
+
+-spec update_src_deps(rebar_state:t()) -> rebat_state:t().
update_src_deps(State) ->
SrcDeps = rebar_state:src_deps(State),
DepsDir = get_deps_dir(State),
- case lists:foldl(fun(AppInfo, {SrcDepsAcc, GoalsAcc}) ->
+ case lists:foldl(fun(AppInfo, {SrcDepsAcc, BinaryDepsAcc}) ->
ok = maybe_fetch(AppInfo),
- {NewSrcDeps, NewGoals} = handle_dep(DepsDir, AppInfo),
- {lists:ukeymerge(2, SrcDepsAcc, lists:ukeysort(2, NewSrcDeps)), NewGoals++GoalsAcc}
- end, {SrcDeps, rebar_state:goals(State)}, SrcDeps) of
- {SrcDeps, NewGoals} ->
- rebar_state:goals(State, NewGoals);
- {NewSrcDeps, NewGoals} ->
- io:format("NEWSRC ~p~n", [NewSrcDeps]),
- State1 = rebar_state:src_deps(rebar_state:goals(State, NewGoals), NewSrcDeps),
+ {AppInfo1, NewSrcDeps, NewBinaryDeps} = handle_dep(DepsDir, AppInfo),
+ {lists:ukeymerge(2, lists:ukeysort(2, [AppInfo1 | SrcDepsAcc]), lists:ukeysort(2, NewSrcDeps)), NewBinaryDeps++BinaryDepsAcc}
+ end, {[], rebar_state:binary_deps(State)}, SrcDeps) of
+ {NewSrcDeps, NewBinaryDeps} when length(SrcDeps) =:= length(NewSrcDeps) ->
+ rebar_state:src_deps(rebar_state:binary_deps(State, NewBinaryDeps), NewSrcDeps);
+ {NewSrcDeps, NewBinaryDeps} ->
+ State1 = rebar_state:src_deps(rebar_state:binary_deps(State, NewBinaryDeps), NewSrcDeps),
update_src_deps(State1)
end.
+-spec handle_dep(binary(), rebar_state:t()) -> {[rebar_app_info:t()], [binary_dep()]}.
handle_dep(DepsDir, AppInfo) ->
C = rebar_config:consult(rebar_app_info:dir(AppInfo)),
S = rebar_state:new(rebar_state:new(), C, rebar_app_info:dir(AppInfo)),
Deps = rebar_state:get(S, deps, []),
- parse_deps(DepsDir, Deps).
+ AppInfo1 = rebar_app_info:deps(AppInfo, rebar_state:deps_names(S)),
+ {SrcDeps, BinaryDeps} = parse_deps(DepsDir, Deps),
+ {AppInfo1, SrcDeps, BinaryDeps}.
+-spec maybe_fetch(rebar_app_info:t()) -> ok.
maybe_fetch(AppInfo) ->
AppDir = rebar_app_info:dir(AppInfo),
case filelib:is_dir(AppDir) of
@@ -174,19 +193,21 @@ maybe_fetch(AppInfo) ->
ok
end.
+-spec parse_deps(binary(), [dep()]) -> {[rebar_app_info:t()], [binary_dep()]}.
parse_deps(DepsDir, Deps) ->
- lists:foldl(fun({Name, Vsn}, {SrcDepsAcc, GoalsAcc}) ->
+ lists:foldl(fun({Name, Vsn}, {SrcDepsAcc, BinaryDepsAcc}) ->
{SrcDepsAcc, [parse_goal(ec_cnv:to_binary(Name)
- ,ec_cnv:to_binary(Vsn)) | GoalsAcc]};
- (Name, {SrcDepsAcc, GoalsAcc}) when is_atom(Name) ->
- {SrcDepsAcc, [ec_cnv:to_binary(Name) | GoalsAcc]};
- ({Name, _, Source}, {SrcDepsAcc, GoalsAcc}) ->
+ ,ec_cnv:to_binary(Vsn)) | BinaryDepsAcc]};
+ (Name, {SrcDepsAcc, BinaryDepsAcc}) when is_atom(Name) ->
+ {SrcDepsAcc, [ec_cnv:to_binary(Name) | BinaryDepsAcc]};
+ ({Name, _, Source}, {SrcDepsAcc, BinaryDepsAcc}) ->
{ok, Dep} = rebar_app_info:new(Name),
Dep1 = rebar_app_info:source(
rebar_app_info:dir(Dep, get_deps_dir(DepsDir, Name)), Source),
- {[Dep1 | SrcDepsAcc], GoalsAcc}
+ {[Dep1 | SrcDepsAcc], BinaryDepsAcc}
end, {[], []}, Deps).
+-spec parse_goal(binary(), binary()) -> binary_dep().
parse_goal(Name, Constraint) ->
case re:run(Constraint, "([^\\d]*)(\\d.*)", [{capture, [1,2], binary}]) of
{match, [<<>>, Vsn]} ->