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.erl26
1 files changed, 20 insertions, 6 deletions
diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl
index 55dca3d..65aabff 100644
--- a/src/rebar_prv_install_deps.erl
+++ b/src/rebar_prv_install_deps.erl
@@ -140,7 +140,9 @@ handle_deps_as_profile(Profile, State, Deps, Upgrade) ->
DepsDir = profile_dep_dir(State, Profile),
Deps1 = rebar_app_utils:parse_deps(DepsDir, Deps, State, Locks, Level),
ProfileLevelDeps = [{Profile, Deps1, Level}],
- handle_profile_level(ProfileLevelDeps, [], sets:new(), Upgrade, Locks, State).
+ RootSeen = sets:from_list([rebar_app_info:name(AppInfo)
+ || AppInfo <- rebar_state:project_apps(State)]),
+ handle_profile_level(ProfileLevelDeps, [], RootSeen, RootSeen, Upgrade, Locks, State).
%% ===================================================================
%% Internal functions
@@ -153,7 +155,9 @@ deps_per_profile(Profiles, Upgrade, State) ->
Deps = lists:foldl(fun(Profile, DepAcc) ->
[parsed_profile_deps(State, Profile, Level) | DepAcc]
end, [], Profiles),
- handle_profile_level(Deps, [], sets:new(), Upgrade, Locks, State).
+ RootSeen = sets:from_list([rebar_app_info:name(AppInfo)
+ || AppInfo <- rebar_state:project_apps(State)]),
+ handle_profile_level(Deps, [], RootSeen, RootSeen, Upgrade, Locks, State).
parsed_profile_deps(State, Profile, Level) ->
ParsedDeps = rebar_state:get(State, {parsed_deps, Profile}, []),
@@ -162,17 +166,27 @@ parsed_profile_deps(State, Profile, Level) ->
%% Level-order traversal of all dependencies, across profiles.
%% If profiles x,y,z are present, then the traversal will go:
%% x0, y0, z0, x1, y1, z1, ..., xN, yN, zN.
-handle_profile_level([], Apps, _Seen, _Upgrade, _Locks, State) ->
+%%
+%% There are two 'seen' sets: one for the top-level apps (`RootSeen') and
+%% one for all dependencies (`Seen'). The former is used to know when
+%% to skip the resolving of dependencies altogether (since they're already
+%% top-level apps), while the latter is used to prevent reprocessing
+%% deps more than one.
+handle_profile_level([], Apps, _RootSeen, _Seen, _Upgrade, _Locks, State) ->
{Apps, State};
-handle_profile_level([{Profile, Deps, Level} | Rest], Apps, Seen, Upgrade, Locks, State) ->
+handle_profile_level([{Profile, Deps, Level} | Rest], Apps, RootSeen, Seen, Upgrade, Locks, State) ->
+ Deps0 = [rebar_app_utils:expand_deps_sources(Dep, State)
+ || Dep <- Deps,
+ %% skip top-level apps being double-declared
+ not sets:is_element(rebar_app_info:name(Dep), RootSeen)],
{Deps1, Apps1, State1, Seen1} =
- update_deps(Profile, Level, Deps, Apps
+ update_deps(Profile, Level, Deps0, Apps
,State, Upgrade, Seen, Locks),
Deps2 = case Deps1 of
[] -> Rest;
_ -> Rest ++ [{Profile, Deps1, Level+1}]
end,
- handle_profile_level(Deps2, Apps1, sets:union(Seen, Seen1), Upgrade, Locks, State1).
+ handle_profile_level(Deps2, Apps1, RootSeen, sets:union(Seen, Seen1), Upgrade, Locks, State1).
find_cycles(Apps) ->
case rebar_digraph:compile_order(Apps) of