diff options
| author | Fred Hebert <mononcqc@ferd.ca> | 2017-05-19 22:52:55 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-05-19 22:52:55 -0400 | 
| commit | eaf2e5496303cd75dc5939d4554942a8365f4777 (patch) | |
| tree | 2d614f55878c969f796d9dbc84f2acf7352db363 | |
| parent | c4e9655daef2390d724bf72346c1da5949252eb8 (diff) | |
| parent | 0ce1a4f5fea0a0a58b862e1e375043e7696f9bff (diff) | |
Merge pull request #1540 from ferd/allow-profile-deps-upgrade
Allow profile deps upgrade
| -rw-r--r-- | src/rebar_prv_upgrade.erl | 46 | ||||
| -rw-r--r-- | test/rebar_upgrade_SUITE.erl | 93 | 
2 files changed, 130 insertions, 9 deletions
| diff --git a/src/rebar_prv_upgrade.erl b/src/rebar_prv_upgrade.erl index 34631ff..2de30e4 100644 --- a/src/rebar_prv_upgrade.erl +++ b/src/rebar_prv_upgrade.erl @@ -70,7 +70,9 @@ do(State) ->                     is_atom(Dep) orelse is_atom(element(1, Dep))],      Names = parse_names(ec_cnv:to_binary(proplists:get_value(package, Args, <<"">>)), Locks),      DepsDict = deps_dict(rebar_state:all_deps(State)), -    case prepare_locks(Names, Deps, Locks, [], DepsDict) of +    AltDeps = find_non_default_deps(Deps, State), +    FilteredNames = cull_default_names_if_profiles(Names, Deps, State), +    case prepare_locks(FilteredNames, Deps, Locks, [], DepsDict, AltDeps) of          {error, Reason} ->              {error, Reason};          {Locks0, _Unlocks0} -> @@ -115,20 +117,45 @@ parse_names(Bin, Locks) ->          Other -> Other      end. -prepare_locks([], _, Locks, Unlocks, _Dict) -> +%% Find alternative deps in non-default profiles since they may +%% need to be passed through (they are never locked) +find_non_default_deps(Deps, State) -> +    AltProfiles = rebar_state:current_profiles(State) -- [default], +    AltProfileDeps = lists:append([ +        rebar_state:get(State, {deps, Profile}, []) || Profile <- AltProfiles] +    ), +    [Dep || Dep <- AltProfileDeps, +            is_atom(Dep) orelse is_atom(element(1, Dep)) +            andalso not lists:member(Dep, Deps)]. + +%% If any alt profiles are used, remove the default profiles from +%% the upgrade list and warn about it. +cull_default_names_if_profiles(Names, Deps, State) -> +    case rebar_state:current_profiles(State) of +        [default] -> +            Names; +        _ -> +            ?INFO("Dependencies in the default profile will not be upgraded", []), +            lists:filter(fun(Name) -> +                AtomName = binary_to_atom(Name, utf8), +                rebar_utils:tup_find(AtomName, Deps) == false +            end, Names) +    end. + +prepare_locks([], _, Locks, Unlocks, _Dict, _AltDeps) ->      {Locks, Unlocks}; -prepare_locks([Name|Names], Deps, Locks, Unlocks, Dict) -> +prepare_locks([Name|Names], Deps, Locks, Unlocks, Dict, AltDeps) ->      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, Dict); +                    prepare_locks(Names, Deps, Locks, Unlocks, Dict, AltDeps);                  Dep ->                      {Source, NewLocks, NewUnlocks} = prepare_lock(Dep, Lock, Locks, Dict),                      prepare_locks(Names, Deps, NewLocks, -                                  [{Name, Source, 0} | NewUnlocks ++ Unlocks], Dict) +                                  [{Name, Source, 0} | NewUnlocks ++ Unlocks], Dict, AltDeps)              end;          {_, _, Level} = Lock when Level > 0 ->              case rebar_utils:tup_find(AtomName, Deps) of @@ -137,10 +164,15 @@ prepare_locks([Name|Names], Deps, Locks, Unlocks, Dict) ->                  Dep -> % Dep has been promoted                      {Source, NewLocks, NewUnlocks} = prepare_lock(Dep, Lock, Locks, Dict),                      prepare_locks(Names, Deps, NewLocks, -                                  [{Name, Source, 0} | NewUnlocks ++ Unlocks], Dict) +                                  [{Name, Source, 0} | NewUnlocks ++ Unlocks], Dict, AltDeps)              end;          false -> -            ?PRV_ERROR({unknown_dependency, Name}) +            case rebar_utils:tup_find(AtomName, AltDeps) of +                false -> +                    ?PRV_ERROR({unknown_dependency, Name}); +                _ -> % non-default profile dependency found, pass through +                    prepare_locks(Names, Deps, Locks, Unlocks, Dict, AltDeps) +            end      end.  prepare_lock(Dep, Lock, Locks, Dict) -> diff --git a/test/rebar_upgrade_SUITE.erl b/test/rebar_upgrade_SUITE.erl index 66e1fdf..45a7433 100644 --- a/test/rebar_upgrade_SUITE.erl +++ b/test/rebar_upgrade_SUITE.erl @@ -11,7 +11,8 @@ groups() ->                  triplet_a, triplet_b, triplet_c,                  tree_a, tree_b, tree_c, tree_c2, tree_cj, tree_ac, tree_all,                  delete_d, promote, stable_lock, fwd_lock, -                compile_upgrade_parity, umbrella_config]}, +                compile_upgrade_parity, umbrella_config, +                profiles, profiles_exclusion]},       {git, [], [{group, all}]},       {pkg, [], [{group, all}]}]. @@ -78,6 +79,23 @@ setup_project(Case=umbrella_config, Config0, Deps, UpDeps) ->      [{rebarconfig, TopConf},       {rebarumbrella, RebarConf},       {next_top_deps, rebar_test_utils:top_level_deps(UpDeps)} | Config]; +setup_project(Case, Config0, Deps, UpDeps) when Case == profiles; +                                                Case == profiles_exclusion -> +    DepsType = ?config(deps_type, Config0), +    NameRoot = atom_to_list(Case)++"_"++atom_to_list(DepsType), +    Config = rebar_test_utils:init_rebar_state(Config0, NameRoot++"_"), +    AppDir = filename:join([?config(apps, Config), "apps", NameRoot]), +    rebar_test_utils:create_app(AppDir, "Root", "0.0.0", [kernel, stdlib]), +    [Top|ProfileDeps] = rebar_test_utils:top_level_deps(Deps), +    RebarConf = rebar_test_utils:create_config(AppDir, [ +        {deps, [Top]}, +        {profiles, [{fake, [{deps, ProfileDeps}]}]} +    ]), +    [NextTop|NextPDeps] = rebar_test_utils:top_level_deps(UpDeps), +    NextConfig = [{deps, [NextTop]}, +                  {profiles, [{fake, [{deps, NextPDeps}]}]}], +    [{rebarconfig, RebarConf}, +     {next_config, NextConfig} | Config];  setup_project(Case, Config0, Deps, UpDeps) ->      DepsType = ?config(deps_type, Config0),      Config = rebar_test_utils:init_rebar_state( @@ -454,7 +472,47 @@ upgrades(umbrella_config) ->      {[{"A", "1", []}],       [{"A", "2", []}],       ["A"], -     {"A", [{"A","2"}]}}. +     {"A", [{"A","2"}]}}; +upgrades(profiles) -> +    %% Ensure that we can unlock deps under a given profile; +    %% B and C should both be in a custom profile +    %% and must not be locked. +    {[{"A", "1", [{"D",[]}, +                  {"E","3",[]}]}, +      {"B", "1", [{"F","1",[]}, +                  {"G",[]}]}, +      {"C", "0", [{"H","3",[]}, +                  {"I",[]}]}], +     [{"A", "2", [{"D",[]}, +                  {"E","2",[]}]}, +      {"B", "2", [{"F","2",[]}, +                  {"G",[]}]}, +      {"C", "1", [{"H","4",[]}, +                  {"I",[]}]}], +     ["A","B","C","E","F","H"], +     {"C", [{"A","1"}, "D", {"E","3"}, +            {"B","2"}, {"F","2"}, "G", +            {"C","1"}, {"H","4"}, "I"]}}; +upgrades(profiles_exclusion) -> +    %% Ensure that we can unlock deps under a given profile; +    %% B and C should both be in a custom profile +    %% and must not be locked. +    {[{"A", "1", [{"D",[]}, +                  {"E","3",[]}]}, +      {"B", "1", [{"F","1",[]}, +                  {"G",[]}]}, +      {"C", "0", [{"H","3",[]}, +                  {"I",[]}]}], +     [{"A", "2", [{"D",[]}, +                  {"E","2",[]}]}, +      {"B", "2", [{"F","2",[]}, +                  {"G",[]}]}, +      {"C", "1", [{"H","4",[]}, +                  {"I",[]}]}], +     ["A","B","C","E","F","H"], +     {"A", [{"A","1"}, "D", {"E","3"}, +            {"B","2"}, {"F","2"}, "G", +            {"C","1"}, {"H","4"}, "I"]}}.  %% TODO: add a test that verifies that unlocking files and then  %% running the upgrade code is enough to properly upgrade things. @@ -613,6 +671,37 @@ umbrella_config(Config) ->       ),      meck:unload(rebar_prv_upgrade). +profiles(Config) -> +    apply(?config(mock, Config), []), +    {ok, TopConfig} = file:consult(?config(rebarconfig, Config)), +    %% Install dependencies before re-mocking for an upgrade +    rebar_test_utils:run_and_check(Config, TopConfig, ["lock"], {ok, []}), +    %% Install test deps along with them +    rebar_test_utils:run_and_check(Config, TopConfig, ["as","fake","lock"], {ok, []}), +    {App, Unlocks} = ?config(expected, Config), +    ct:pal("Upgrades: ~p -> ~p", [App, Unlocks]), +    Expectation = case Unlocks of +        {error, Term} -> {error, Term}; +        _ -> {ok, [T || T <- Unlocks, +                        element(1,T) == dep orelse +                        lists:member(element(2,T), ["A","D","E"])]} +    end, + +    meck:new(rebar_prv_app_discovery, [passthrough]), +    meck:expect(rebar_prv_app_discovery, do, fun(S) -> +                                               apply(?config(mock_update, Config), []), +                                               meck:passthrough([S]) +                                       end), +    NewRebarConf = rebar_test_utils:create_config(?config(apps, Config), +                                                  ?config(next_config, Config)), +    {ok, NewRebarConfig} = file:consult(NewRebarConf), +    rebar_test_utils:run_and_check( +        Config, NewRebarConfig, ["as","fake","upgrade", App], Expectation +     ), +    meck:unload(rebar_prv_app_discovery). + +profiles_exclusion(Config) -> profiles(Config). +  run(Config) ->      apply(?config(mock, Config), []),      ConfigPath = ?config(rebarconfig, Config), | 
