Parcourir la source

Fix testcases, add multi-app upgrade support

todo:
- relock stuff
- default to all apps needing upgrade
- more tests?
- pkgs?
pull/126/head
Fred Hebert il y a 10 ans
Parent
révision
62dc8fa9c7
4 fichiers modifiés avec 135 ajouts et 34 suppressions
  1. +21
    -5
      src/rebar_prv_install_deps.erl
  2. +54
    -17
      src/rebar_prv_upgrade.erl
  3. +1
    -2
      test/mock_git_resource.erl
  4. +59
    -10
      test/rebar_upgrade_SUITE.erl

+ 21
- 5
src/rebar_prv_install_deps.erl Voir le fichier

@ -252,7 +252,22 @@ update_src_deps(Profile, Level, SrcDeps, PkgDeps, SrcApps, State, Upgrade, Seen,
true ->
ok
end,
{SrcDepsAcc, PkgDepsAcc, SrcAppsAcc, StateAcc, SeenAcc, LocksAcc};
%% scan for app children here if upgrading
case Upgrade of
false ->
{SrcDepsAcc, PkgDepsAcc, SrcAppsAcc, StateAcc, SeenAcc, LocksAcc};
true ->
{SrcDepsAcc1, PkgDepsAcc1, SrcAppsAcc1, StateAcc2, LocksAcc1} =
handle_dep(AppInfo
,SrcDepsAcc
,PkgDepsAcc
,SrcAppsAcc
,Level
,StateAcc
,LocksAcc),
{SrcDepsAcc1, PkgDepsAcc1, SrcAppsAcc1, StateAcc2, SeenAcc, LocksAcc1}
end;
false ->
{SeenAcc1, StateAcc1} = maybe_lock(Profile, AppInfo, SeenAcc, StateAcc, Level),
{SrcDepsAcc1, PkgDepsAcc1, SrcAppsAcc1, StateAcc2, LocksAcc1} =
@ -302,10 +317,10 @@ handle_upgrade(AppInfo, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) ->
,Locks);
false ->
{SrcDeps, PkgDeps, SrcApps, State, Locks}
{[AppInfo|SrcDeps], PkgDeps, SrcApps, State, Locks}
end;
_StillLocked ->
{SrcDeps, PkgDeps, SrcApps, State, Locks}
{[AppInfo|SrcDeps], PkgDeps, SrcApps, State, Locks}
end.
handle_dep(AppInfo, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) ->
@ -452,8 +467,9 @@ fetch_app(AppInfo, AppDir) ->
Result
end.
maybe_upgrade(_AppInfo, _AppDir, false) ->
false;
maybe_upgrade(AppInfo, AppDir, false) ->
Source = rebar_app_info:source(AppInfo),
rebar_fetch:needs_update(AppDir, Source);
maybe_upgrade(AppInfo, AppDir, true) ->
Source = rebar_app_info:source(AppInfo),
case rebar_fetch:needs_update(AppDir, Source) of

+ 54
- 17
src/rebar_prv_upgrade.erl Voir le fichier

@ -29,47 +29,84 @@ init(State) ->
{module, ?MODULE},
{bare, false},
{deps, ?DEPS},
{example, "rebar upgrade cowboy"},
{example, "rebar upgrade cowboy[,ranch]"},
{short_desc, "Upgrade dependency."},
{desc, ""},
{opts, [
{package, undefined, undefined, string, "Package to upgrade."}
{package, undefined, undefined, string, "Packages to upgrade."}
]}])),
{ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
{Args, _} = rebar_state:command_parsed_args(State),
Name = ec_cnv:to_binary(proplists:get_value(package, Args)),
Names = parse_names(ec_cnv:to_binary(proplists:get_value(package, Args))),
%% TODO: support many names. Only a subtree can be updated per app
%% mentioned. When no app is named, unlock *everything*
Locks = rebar_state:get(State, {locks, default}, []),
Deps = rebar_state:get(State, deps),
case prepare_locks(Names, Deps, Locks, []) of
{error, Reason} ->
{error, Reason};
{Locks0, Unlocks0} ->
Deps0 = top_level_deps(Deps, Locks),
State1 = rebar_state:set(State, {deps, default}, Deps0),
State2 = rebar_state:set(State1, {locks, default}, Locks0),
State3 = rebar_state:set(State2, upgrade, true),
Res = rebar_prv_install_deps:do(State3),
case Res of
{ok, S} ->
ct:pal("original locks ~p", [Locks]),
ct:pal("new locks ~p", [Locks0]),
ct:pal("old deps: ~p", [Deps]),
ct:pal("new deps: ~p", [Deps0]),
ct:pal("Unlocks: ~p", [Unlocks0]),
%% TODO: replace new locks onto the old locks list
rebar_prv_lock:do(S);
_ -> Res
end
end.
parse_names(Bin) ->
lists:usort(re:split(Bin, <<" *, *">>, [trim])).
prepare_locks([], _, Locks, Unlocks) ->
{Locks, Unlocks};
prepare_locks([Name|Names], Deps, Locks, Unlocks) ->
case lists:keyfind(Name, 1, Locks) of
{_, _, 0} = Lock ->
Deps = rebar_state:get(State, deps),
case lists:keyfind(binary_to_atom(Name, utf8), 1, Deps) of
AtomName = binary_to_atom(Name, utf8),
case lists:keyfind(AtomName, 1, Deps) of
false ->
{error, unknown_dependency};
{error, {unknown_dependency, Name}};
Dep ->
Source = case Dep of
{_, Src} -> Src;
{_, _, Src} -> Src
end,
NewLocks = unlock_higher_than(0, Locks -- [Lock]),
State1 = rebar_state:set(State, {deps, default}, [{Name, Source, 0} | NewLocks]),
State2 = rebar_state:set(State1, {locks, default}, NewLocks),
State3 = rebar_state:set(State2, upgrade, true),
rebar_prv_install_deps:do(State3)
{NewLocks, NewUnlocks} = unlock_higher_than(0, Locks -- [Lock]),
prepare_locks(Names,
%deps_like_locks(Deps, [{Name,Source,0} | NewLocks]),
Deps,
NewLocks,
[{Name, Source, 0} | NewUnlocks ++ Unlocks])
end;
{_, _, Level} when Level > 0 ->
{error, transitive_dependency};
{error, {transitive_dependency,Name}};
false ->
{error, unknown_dependency}
{error, {unknown_dependency,Name}}
end.
top_level_deps(Deps, Locks) ->
[Dep || Dep <- Deps, lists:keymember(0, 3, Locks)].
unlock_higher_than(Level, Locks) -> unlock_higher_than(Level, Locks, [], []).
unlock_higher_than(_, []) -> [];
unlock_higher_than(Level, [App = {_,_,AppLevel} | Apps]) ->
if AppLevel > Level -> unlock_higher_than(Level, Apps);
AppLevel =< Level -> [App | unlock_higher_than(Level, Apps)]
unlock_higher_than(_, [], 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)
end.
-spec format_error(any()) -> iolist().

+ 1
- 2
test/mock_git_resource.erl Voir le fichier

@ -60,7 +60,7 @@ mock_update(Opts) ->
?MOD, needs_update,
fun(_Dir, {git, Url, _Ref}) ->
App = app(Url),
ct:pal("Needed update? ~p -> ~p", [App, lists:member(App, ToUpdate)]),
ct:pal("Needed update? ~p (~p) -> ~p", [App, {Url,_Ref}, lists:member(App, ToUpdate)]),
lists:member(App, ToUpdate)
end).
@ -108,7 +108,6 @@ mock_download(Opts) ->
{git, Url, {_, Vsn}} = normalize_git(Git, Overrides, Default),
App = app(Url),
AppDeps = proplists:get_value({App,Vsn}, Deps, []),
ct:pal("creating app ~p", [{Dir, App, Vsn, AppDeps}]),
rebar_test_utils:create_app(
Dir, App, Vsn,
[element(1,D) || D <- AppDeps]

+ 59
- 10
test/rebar_upgrade_SUITE.erl Voir le fichier

@ -7,9 +7,9 @@ all() -> [{group, git}].%, {group, pkg}].
groups() ->
[{all, [], [top_a, top_b, top_c, top_d1, top_d2, top_e,
pair_a, pair_b, pair_c,
pair_a, pair_b, pair_ab, pair_c,
triplet_a, triplet_b, triplet_c,
tree_a, tree_b, tree_c]},
tree_a, tree_b, tree_c, tree_c2, tree_ac]},
{git, [], [{group, all}]},
{pkg, [], [{group, all}]}].
@ -83,7 +83,7 @@ upgrades(top_b) ->
%% Modified apps, gobally
["A","B","D"],
%% upgrade vs. new tree
{"B", {error, transitive_dependency}}};
{"B", {error, {transitive_dependency, <<"B">>}}}};
upgrades(top_c) ->
%% Original tree
{[{"A", "1", [{"B", [{"D", "1", []}]},
@ -96,7 +96,7 @@ upgrades(top_c) ->
%% Modified apps, gobally
["A","B","D"],
%% upgrade vs. new tree
{"C", {error, transitive_dependency}}};
{"C", {error, {transitive_dependency, <<"C">>}}}};
upgrades(top_d1) ->
%% Original tree
{[{"A", "1", [{"B", [{"D", "1", []}]},
@ -109,7 +109,7 @@ upgrades(top_d1) ->
%% Modified apps, gobally
["A","B","D"],
%% upgrade vs. new tree
{"D", {error, transitive_dependency}}};
{"D", {error, {transitive_dependency, <<"D">>}}}};
upgrades(top_d2) ->
%% Original tree
{[{"A", "1", [{"B", [{"D", "1", []}]},
@ -122,7 +122,7 @@ upgrades(top_d2) ->
%% Modified apps, gobally
["A","B","D"],
%% upgrade vs. new tree
{"D", {error, transitive_dependency}}};
{"D", {error, {transitive_dependency, <<"D">>}}}};
upgrades(top_e) ->
%% Original tree
{[{"A", "1", [{"B", [{"D", "1", []}]},
@ -135,7 +135,7 @@ upgrades(top_e) ->
%% Modified apps, gobally
["A","B","D"],
%% upgrade vs. new tree
{"E", {error, unknown_dependency}}};
{"E", {error, {unknown_dependency, <<"E">>}}}};
upgrades(pair_a) ->
{[{"A", "1", [{"C", "1", []}]},
{"B", "1", [{"D", "1", []}]}
@ -154,6 +154,15 @@ upgrades(pair_b) ->
],
["A","B","C","D"],
{"B", [{"A","1"},{"C","1"},{"B","2"},{"D","2"}]}};
upgrades(pair_ab) ->
{[{"A", "1", [{"C", "1", []}]},
{"B", "1", [{"D", "1", []}]}
],
[{"A", "2", [{"C", "2", []}]},
{"B", "2", [{"D", "2", []}]}
],
["A","B","C","D"],
{"A,B", [{"A","2"},{"C","2"},{"B","2"},{"D","2"}]}};
upgrades(pair_c) ->
{[{"A", "1", [{"C", "1", []}]},
{"B", "1", [{"D", "1", []}]}
@ -162,7 +171,7 @@ upgrades(pair_c) ->
{"B", "2", [{"D", "2", []}]}
],
["A","B","C","D"],
{"C", {error, transitive_dependency}}};
{"C", {error, {transitive_dependency, <<"C">>}}}};
upgrades(triplet_a) ->
{[{"A", "1", [{"D",[]},
{"E","3",[]}]},
@ -264,10 +273,47 @@ upgrades(tree_c) ->
{"G",[]}]},
{"C", "1", [{"H",[]}]}
],
["C"],
["C","I"],
{"C", [{"A","1"}, "D", "J", "E", {"I","1"},
{"B","1"}, "F", "G",
{"C","1"}, "H"]}}.
{"C","1"}, "H"]}};
upgrades(tree_c2) ->
{[{"A", "1", [{"D",[{"J",[]}]},
{"E",[{"I","1",[]}]}]},
{"B", "1", [{"F",[]},
{"G",[]}]},
{"C", "1", [{"H",[]},
{"I","2",[]}]}
],
[{"A", "1", [{"D",[{"J",[]}]},
{"E",[{"I","1",[]}]}]},
{"B", "1", [{"F",[]},
{"G",[]}]},
{"C", "1", [{"H",[{"K",[]}]},
{"I","2",[]}]}
],
["C", "H"],
{"C", [{"A","1"}, "D", "J", "E",
{"B","1"}, "F", "G",
{"C","1"}, "H", {"I", "2"}, "K"]}};
upgrades(tree_ac) ->
{[{"A", "1", [{"D",[{"J",[]}]},
{"E",[{"I","1",[]}]}]},
{"B", "1", [{"F",[]},
{"G",[]}]},
{"C", "1", [{"H",[]},
{"I","2",[]}]}
],
[{"A", "1", [{"D",[{"J",[]}]},
{"E",[{"I","1",[]}]}]},
{"B", "1", [{"F",[]},
{"G",[]}]},
{"C", "1", [{"H",[]}]}
],
["C","I"],
{"C, A", [{"A","1"}, "D", "J", "E", {"I","1"},
{"B","1"}, "F", "G",
{"C","1"}, "H"]}}.
%% TODO: add a test that verifies that unlocking files and then
%% running the upgrade code is enough to properly upgrade things.
@ -345,6 +391,7 @@ top_e(Config) -> run(Config).
pair_a(Config) -> run(Config).
pair_b(Config) -> run(Config).
pair_ab(Config) -> run(Config).
pair_c(Config) -> run(Config).
triplet_a(Config) -> run(Config).
@ -354,6 +401,8 @@ triplet_c(Config) -> run(Config).
tree_a(Config) -> run(Config).
tree_b(Config) -> run(Config).
tree_c(Config) -> run(Config).
tree_c2(Config) -> run(Config).
tree_ac(Config) -> run(Config).
run(Config) ->
apply(?config(mock, Config), []),

Chargement…
Annuler
Enregistrer