summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/rebar_prv_upgrade.erl62
-rw-r--r--test/rebar_upgrade_SUITE.erl32
2 files changed, 72 insertions, 22 deletions
diff --git a/src/rebar_prv_upgrade.erl b/src/rebar_prv_upgrade.erl
index 97d1953..a2864ab 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..cfe1d8a 100644
--- a/test/rebar_upgrade_SUITE.erl
+++ b/test/rebar_upgrade_SUITE.erl
@@ -9,7 +9,7 @@ groups() ->
[{all, [], [top_a, top_b, top_c, top_d1, top_d2, top_e,
pair_a, pair_b, pair_ab, pair_c, pair_all,
triplet_a, triplet_b, triplet_c,
- tree_a, tree_b, tree_c, tree_c2, tree_ac, tree_all,
+ tree_a, tree_b, tree_c, tree_c2, tree_cj, tree_ac, tree_all,
delete_d, promote, stable_lock, fwd_lock,
compile_upgrade_parity]},
{git, [], [{group, all}]},
@@ -327,6 +327,25 @@ upgrades(tree_c2) ->
{"C", [{"A","1"}, "D", "J", "E",
{"B","1"}, "F", "G",
{"C","1"}, "H", {"I", "2"}, "K"]}};
+upgrades(tree_cj) ->
+ {[{"A", "1", [{"D",[{"J", "1",[]}]},
+ {"E",[{"I","1",[]}]}]},
+ {"B", "1", [{"F",[]},
+ {"G",[]}]},
+ {"C", "1", [{"H",[]},
+ {"I","1",[]}]}
+ ],
+ [{"A", "1", [{"D",[{"J", "2", []}]},
+ {"E",[{"I","1",[]}]}]},
+ {"B", "1", [{"F",[]},
+ {"G",[]}]},
+ {"C", "1", [{"H",[]},
+ {"I","1",[]}]}
+ ],
+ ["C","J"],
+ {"C", [{"A","1"}, "D", {"J", "1"}, "E", {"I","1"},
+ {"B","1"}, "F", "G",
+ {"C","1"}, "H"]}};
upgrades(tree_ac) ->
{[{"A", "1", [{"D",[{"J",[]}]},
{"E",[{"I","1",[]}]}]},
@@ -481,6 +500,7 @@ tree_a(Config) -> run(Config).
tree_b(Config) -> run(Config).
tree_c(Config) -> run(Config).
tree_c2(Config) -> run(Config).
+tree_cj(Config) -> run(Config).
tree_ac(Config) -> run(Config).
tree_all(Config) -> run(Config).
promote(Config) -> run(Config).
@@ -561,13 +581,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), []),