diff options
-rw-r--r-- | src/rebar_prv_install_deps.erl | 26 | ||||
-rw-r--r-- | src/rebar_prv_upgrade.erl | 71 | ||||
-rw-r--r-- | test/mock_git_resource.erl | 3 | ||||
-rw-r--r-- | test/rebar_upgrade_SUITE.erl | 69 |
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), []), |