summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFred Hebert <mononcqc@ferd.ca>2015-02-11 14:00:43 +0000
committerFred Hebert <mononcqc@ferd.ca>2015-02-11 21:57:58 +0000
commit62dc8fa9c745cca60f45ad301e05c8b70517626c (patch)
tree1352b91f9d350f0e818754683f94a7b9eadbbc93
parentf5acdfb9a5f600ae260a36a1fadd45576a1536fd (diff)
Fix testcases, add multi-app upgrade support
todo: - relock stuff - default to all apps needing upgrade - more tests? - pkgs?
-rw-r--r--src/rebar_prv_install_deps.erl26
-rw-r--r--src/rebar_prv_upgrade.erl71
-rw-r--r--test/mock_git_resource.erl3
-rw-r--r--test/rebar_upgrade_SUITE.erl69
4 files changed, 135 insertions, 34 deletions
diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl
index 0e54324..dab4c24 100644
--- a/src/rebar_prv_install_deps.erl
+++ b/src/rebar_prv_install_deps.erl
@@ -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
diff --git a/src/rebar_prv_upgrade.erl b/src/rebar_prv_upgrade.erl
index e43841c..b9c6495 100644
--- a/src/rebar_prv_upgrade.erl
+++ b/src/rebar_prv_upgrade.erl
@@ -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().
diff --git a/test/mock_git_resource.erl b/test/mock_git_resource.erl
index 5d8288e..2f7a72d 100644
--- a/test/mock_git_resource.erl
+++ b/test/mock_git_resource.erl
@@ -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]
diff --git a/test/rebar_upgrade_SUITE.erl b/test/rebar_upgrade_SUITE.erl
index 0727fff..6491527 100644
--- a/test/rebar_upgrade_SUITE.erl
+++ b/test/rebar_upgrade_SUITE.erl
@@ -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), []),