diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/rebar_prv_install_deps.erl | 26 |
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. + |