summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/rebar_prv_upgrade.erl62
-rw-r--r--test/rebar_upgrade_SUITE.erl10
2 files changed, 51 insertions, 21 deletions
diff --git a/src/rebar_prv_upgrade.erl b/src/rebar_prv_upgrade.erl
index 97d1953..476d62f 100644
--- a/src/rebar_prv_upgrade.erl
+++ b/src/rebar_prv_upgrade.erl
@@ -47,7 +47,8 @@ do(State) ->
Locks = rebar_state:get(State, {locks, default}, []),
Deps = rebar_state:get(State, deps, []),
Names = parse_names(ec_cnv:to_binary(proplists:get_value(package, Args, <<"">>)), Locks),
- case prepare_locks(Names, Deps, Locks, []) of
+ DepsDict = deps_dict(rebar_state:all_deps(State)),
+ case prepare_locks(Names, Deps, Locks, [], DepsDict) of
{error, Reason} ->
{error, Reason};
{Locks0, _Unlocks0} ->
@@ -92,54 +93,77 @@ parse_names(Bin, Locks) ->
Other -> Other
end.
-prepare_locks([], _, Locks, Unlocks) ->
+prepare_locks([], _, Locks, Unlocks, _Dict) ->
{Locks, Unlocks};
-prepare_locks([Name|Names], Deps, Locks, Unlocks) ->
+prepare_locks([Name|Names], Deps, Locks, Unlocks, Dict) ->
AtomName = binary_to_atom(Name, utf8),
case lists:keyfind(Name, 1, Locks) of
{_, _, 0} = Lock ->
case rebar_utils:tup_find(AtomName, Deps) of
false ->
?WARN("Dependency ~s has been removed and will not be upgraded", [Name]),
- prepare_locks(Names, Deps, Locks, Unlocks);
+ prepare_locks(Names, Deps, Locks, Unlocks, Dict);
Dep ->
- {Source, NewLocks, NewUnlocks} = prepare_lock(Dep, Lock, Locks),
+ {Source, NewLocks, NewUnlocks} = prepare_lock(Dep, Lock, Locks, Dict),
prepare_locks(Names, Deps, NewLocks,
- [{Name, Source, 0} | NewUnlocks ++ Unlocks])
+ [{Name, Source, 0} | NewUnlocks ++ Unlocks], Dict)
end;
{_, _, Level} = Lock when Level > 0 ->
case rebar_utils:tup_find(AtomName, Deps) of
false ->
?PRV_ERROR({transitive_dependency, Name});
Dep -> % Dep has been promoted
- {Source, NewLocks, NewUnlocks} = prepare_lock(Dep, Lock, Locks),
+ {Source, NewLocks, NewUnlocks} = prepare_lock(Dep, Lock, Locks, Dict),
prepare_locks(Names, Deps, NewLocks,
- [{Name, Source, 0} | NewUnlocks ++ Unlocks])
+ [{Name, Source, 0} | NewUnlocks ++ Unlocks], Dict)
end;
false ->
?PRV_ERROR({unknown_dependency, Name})
end.
-prepare_lock(Dep, Lock, Locks) ->
- Source = case Dep of
- {_, SrcOrVsn} -> SrcOrVsn;
- {_, _, Src} -> Src;
+prepare_lock(Dep, Lock, Locks, Dict) ->
+ {Name1, Source} = case Dep of
+ {Name, SrcOrVsn} -> {Name, SrcOrVsn};
+ {Name, _, Src} -> {Name, Src};
_ when is_atom(Dep) ->
%% version-free package. Must unlock whatever matches in locks
{_, Vsn, _} = lists:keyfind(ec_cnv:to_binary(Dep), 1, Locks),
- Vsn
+ {Dep, Vsn}
end,
- {NewLocks, NewUnlocks} = unlock_higher_than(0, Locks -- [Lock]),
+ Children = all_children(Name1, Dict),
+ {NewLocks, NewUnlocks} = unlock_children(Children, Locks -- [Lock]),
{Source, NewLocks, NewUnlocks}.
top_level_deps(Deps, Locks) ->
[Dep || Dep <- Deps, lists:keymember(0, 3, Locks)].
-unlock_higher_than(Level, Locks) -> unlock_higher_than(Level, Locks, [], []).
+unlock_children(Children, Locks) ->
+ unlock_children(Children, Locks, [], []).
-unlock_higher_than(_, [], Locks, Unlocks) ->
+unlock_children(_, [], Locks, Unlocks) ->
{Locks, Unlocks};
-unlock_higher_than(Level, [App = {_,_,AppLevel} | Apps], Locks, Unlocks) ->
- if AppLevel > Level -> unlock_higher_than(Level, Apps, Locks, [App | Unlocks]);
- AppLevel =< Level -> unlock_higher_than(Level, Apps, [App | Locks], Unlocks)
+unlock_children(Children, [App = {Name,_,_} | Apps], Locks, Unlocks) ->
+ case lists:member(ec_cnv:to_binary(Name), Children) of
+ true ->
+ unlock_children(Children, Apps, Locks, [App | Unlocks]);
+ false ->
+ unlock_children(Children, Apps, [App | Locks], Unlocks)
+ end.
+
+deps_dict(Deps) ->
+ lists:foldl(fun(App, Dict) ->
+ Name = rebar_app_info:name(App),
+ Parent = rebar_app_info:parent(App),
+ dict:append_list(Parent, [Name], Dict)
+ end, dict:new(), Deps).
+
+all_children(Name, Dict) ->
+ lists:flatten(all_children_(Name, Dict)).
+
+all_children_(Name, Dict) ->
+ case dict:find(ec_cnv:to_binary(Name), Dict) of
+ {ok, Children} ->
+ Children ++ [all_children_(Child, Dict) || Child <- Children];
+ error ->
+ []
end.
diff --git a/test/rebar_upgrade_SUITE.erl b/test/rebar_upgrade_SUITE.erl
index 54f16da..d9cd49a 100644
--- a/test/rebar_upgrade_SUITE.erl
+++ b/test/rebar_upgrade_SUITE.erl
@@ -561,13 +561,19 @@ run(Config) ->
{error, Term} -> {error, Term};
_ -> {ok, Unlocks}
end,
- apply(?config(mock_update, Config), []),
+
+ meck:new(rebar_prv_upgrade, [passthrough]),
+ meck:expect(rebar_prv_upgrade, do, fun(S) ->
+ apply(?config(mock_update, Config), []),
+ meck:passthrough([S])
+ end),
NewRebarConf = rebar_test_utils:create_config(?config(apps, Config),
[{deps, ?config(next_top_deps, Config)}]),
{ok, NewRebarConfig} = file:consult(NewRebarConf),
rebar_test_utils:run_and_check(
Config, NewRebarConfig, ["upgrade", App], Expectation
- ).
+ ),
+ meck:unload(rebar_prv_upgrade).
novsn_pkg(Config) ->
apply(?config(mock, Config), []),