瀏覽代碼

only upgrade children and transitive children of dep being upgraded

This commit replaces the method of upgrading by unlocking all transitive
deps by one that utilizes the parent element of each app to only
unlock transitive deps of children of the top level deps being upgraded.

Additionally the run function of upgrade_SUITE is modified to only create
the mock updates before the upgrade provider is run, instead of before
any provider is run, which would cause improper behavior in install_deps.
pull/840/head
Tristan Sloughter 9 年之前
父節點
當前提交
dfa668f211
共有 2 個檔案被更改,包括 51 行新增21 行删除
  1. +43
    -19
      src/rebar_prv_upgrade.erl
  2. +8
    -2
      test/rebar_upgrade_SUITE.erl

+ 43
- 19
src/rebar_prv_upgrade.erl 查看文件

@ -47,7 +47,8 @@ do(State) ->
Locks = rebar_state:get(State, {locks, default}, []), Locks = rebar_state:get(State, {locks, default}, []),
Deps = rebar_state:get(State, deps, []), Deps = rebar_state:get(State, deps, []),
Names = parse_names(ec_cnv:to_binary(proplists:get_value(package, Args, <<"">>)), Locks), 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} ->
{error, Reason}; {error, Reason};
{Locks0, _Unlocks0} -> {Locks0, _Unlocks0} ->
@ -92,54 +93,77 @@ parse_names(Bin, Locks) ->
Other -> Other Other -> Other
end. end.
prepare_locks([], _, Locks, Unlocks) ->
prepare_locks([], _, Locks, Unlocks, _Dict) ->
{Locks, Unlocks}; {Locks, Unlocks};
prepare_locks([Name|Names], Deps, Locks, Unlocks) ->
prepare_locks([Name|Names], Deps, Locks, Unlocks, Dict) ->
AtomName = binary_to_atom(Name, utf8), AtomName = binary_to_atom(Name, utf8),
case lists:keyfind(Name, 1, Locks) of case lists:keyfind(Name, 1, Locks) of
{_, _, 0} = Lock -> {_, _, 0} = Lock ->
case rebar_utils:tup_find(AtomName, Deps) of case rebar_utils:tup_find(AtomName, Deps) of
false -> false ->
?WARN("Dependency ~s has been removed and will not be upgraded", [Name]), ?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 -> Dep ->
{Source, NewLocks, NewUnlocks} = prepare_lock(Dep, Lock, Locks),
{Source, NewLocks, NewUnlocks} = prepare_lock(Dep, Lock, Locks, Dict),
prepare_locks(Names, Deps, NewLocks, prepare_locks(Names, Deps, NewLocks,
[{Name, Source, 0} | NewUnlocks ++ Unlocks])
[{Name, Source, 0} | NewUnlocks ++ Unlocks], Dict)
end; end;
{_, _, Level} = Lock when Level > 0 -> {_, _, Level} = Lock when Level > 0 ->
case rebar_utils:tup_find(AtomName, Deps) of case rebar_utils:tup_find(AtomName, Deps) of
false -> false ->
?PRV_ERROR({transitive_dependency, Name}); ?PRV_ERROR({transitive_dependency, Name});
Dep -> % Dep has been promoted 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, prepare_locks(Names, Deps, NewLocks,
[{Name, Source, 0} | NewUnlocks ++ Unlocks])
[{Name, Source, 0} | NewUnlocks ++ Unlocks], Dict)
end; end;
false -> false ->
?PRV_ERROR({unknown_dependency, Name}) ?PRV_ERROR({unknown_dependency, Name})
end. 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) -> _ when is_atom(Dep) ->
%% version-free package. Must unlock whatever matches in locks %% version-free package. Must unlock whatever matches in locks
{_, Vsn, _} = lists:keyfind(ec_cnv:to_binary(Dep), 1, Locks), {_, Vsn, _} = lists:keyfind(ec_cnv:to_binary(Dep), 1, Locks),
Vsn
{Dep, Vsn}
end, end,
{NewLocks, NewUnlocks} = unlock_higher_than(0, Locks -- [Lock]),
Children = all_children(Name1, Dict),
{NewLocks, NewUnlocks} = unlock_children(Children, Locks -- [Lock]),
{Source, NewLocks, NewUnlocks}. {Source, NewLocks, NewUnlocks}.
top_level_deps(Deps, Locks) -> top_level_deps(Deps, Locks) ->
[Dep || Dep <- Deps, lists:keymember(0, 3, 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}; {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. end.

+ 8
- 2
test/rebar_upgrade_SUITE.erl 查看文件

@ -561,13 +561,19 @@ run(Config) ->
{error, Term} -> {error, Term}; {error, Term} -> {error, Term};
_ -> {ok, Unlocks} _ -> {ok, Unlocks}
end, 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), NewRebarConf = rebar_test_utils:create_config(?config(apps, Config),
[{deps, ?config(next_top_deps, Config)}]), [{deps, ?config(next_top_deps, Config)}]),
{ok, NewRebarConfig} = file:consult(NewRebarConf), {ok, NewRebarConfig} = file:consult(NewRebarConf),
rebar_test_utils:run_and_check( rebar_test_utils:run_and_check(
Config, NewRebarConfig, ["upgrade", App], Expectation Config, NewRebarConfig, ["upgrade", App], Expectation
).
),
meck:unload(rebar_prv_upgrade).
novsn_pkg(Config) -> novsn_pkg(Config) ->
apply(?config(mock, Config), []), apply(?config(mock, Config), []),

Loading…
取消
儲存