summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/rebar_prv_install_deps.erl26
1 files changed, 24 insertions, 2 deletions
diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl
index 068c4c8..0187b4f 100644
--- a/src/rebar_prv_install_deps.erl
+++ b/src/rebar_prv_install_deps.erl
@@ -206,10 +206,23 @@ maybe_lock(Profile, AppInfo, Seen, State, Level) ->
default ->
case sets:is_element(Name, Seen) of
false ->
+ %% Check whether the currently existing lock is
+ %% deeper than the current one (which can happen
+ %% during an upgrade). If the current app is
+ %% shallower than the existing lock, replace the
+ %% existing lock. This prevents weird transient
+ %% lock-tree states (which would self-heal on a
+ %% later run) after a `rebar3 upgrade <app>'
+ %% command when a deep dep switches lineages for
+ %% another newer parent.
Locks = rebar_state:lock(State),
- case lists:any(fun(App) -> rebar_app_info:name(App) =:= Name end, Locks) of
- true ->
+ case find_app_and_level_by_name(Locks, Name) of
+ {ok, _App, LockLvl} when LockLvl =< Level ->
{sets:add_element(Name, Seen), State};
+ {ok, App, _LockLvl} ->
+ LockedApp = rebar_app_info:dep_level(AppInfo, Level),
+ {sets:add_element(Name, Seen),
+ rebar_state:lock(State, [LockedApp | Locks -- [App]])};
false ->
{sets:add_element(Name, Seen),
rebar_state:lock(State, rebar_app_info:dep_level(AppInfo, Level))}
@@ -426,3 +439,12 @@ not_needs_compile(App) ->
not(rebar_app_info:is_checkout(App))
andalso rebar_app_info:valid(App)
andalso rebar_app_info:has_all_artifacts(App) =:= true.
+
+find_app_and_level_by_name([], _) ->
+ false;
+find_app_and_level_by_name([App|Apps], Name) ->
+ case rebar_app_info:name(App) of
+ Name -> {ok, App, rebar_app_info:dep_level(App)};
+ _ -> find_app_and_level_by_name(Apps, Name)
+ end.
+