diff options
| -rw-r--r-- | THANKS | 1 | ||||
| -rw-r--r-- | src/rebar_app_discover.erl | 4 | ||||
| -rw-r--r-- | src/rebar_prv_install_deps.erl | 3 | ||||
| -rw-r--r-- | src/rebar_utils.erl | 52 | ||||
| -rw-r--r-- | test/rebar_utils_SUITE.erl | 69 | 
5 files changed, 127 insertions, 2 deletions
| @@ -135,3 +135,4 @@ Pierre Fenoll  David Kubecka  Stefan Grundmann  Carlos Eduardo de Paula +Derek Brown
\ No newline at end of file diff --git a/src/rebar_app_discover.erl b/src/rebar_app_discover.erl index f55a4d5..95b3273 100644 --- a/src/rebar_app_discover.erl +++ b/src/rebar_app_discover.erl @@ -51,6 +51,10 @@ merge_deps(AppInfo, State) ->                   rebar_state:apply_profiles(                     rebar_state:new(reset_hooks(rebar_state:opts(State, Default)), C,                                    rebar_app_info:dir(AppInfo)), CurrentProfiles), Name), + +    rebar_utils:check_min_otp_version(rebar_state:get(AppState, minimum_otp_vsn, undefined)), +    rebar_utils:check_blacklisted_otp_versions(rebar_state:get(AppState, blacklisted_otp_vsns, [])), +      AppState1 = rebar_state:set(AppState, artifacts, []),      AppInfo1 = rebar_app_info:state(AppInfo, AppState1), diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl index 8bb394a..69956f0 100644 --- a/src/rebar_prv_install_deps.erl +++ b/src/rebar_prv_install_deps.erl @@ -386,6 +386,9 @@ handle_dep(State, Profile, DepsDir, AppInfo, Locks, Level) ->      S4 = rebar_state:set(S3, {plugins, Profile}, Plugins),      AppInfo1 = rebar_app_info:state(AppInfo, S4), +    rebar_utils:check_min_otp_version(rebar_state:get(S4, minimum_otp_vsn, undefined)), +    rebar_utils:check_blacklisted_otp_versions(rebar_state:get(S4, blacklisted_otp_vsns, [])), +      %% Dep may have plugins to install. Find and install here.      S5 = rebar_plugins:install(S4),      AppInfo2 = rebar_app_info:state(AppInfo1, S5), diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl index c8b9e10..bcb4777 100644 --- a/src/rebar_utils.erl +++ b/src/rebar_utils.erl @@ -60,7 +60,9 @@           set_httpc_options/0,           escape_chars/1,           escape_double_quotes/1, -         escape_double_quotes_weak/1]). +         escape_double_quotes_weak/1, +         check_min_otp_version/1, +         check_blacklisted_otp_versions/1]).  %% for internal use only  -export([otp_release/0]). @@ -299,9 +301,57 @@ line_count(PatchLines) ->      Tokenized = string:tokens(PatchLines, "\n"),      {ok, length(Tokenized)}. +check_min_otp_version(undefined) -> +    ok; +check_min_otp_version(MinOtpVersion) -> +    %% Fully-qualify with ?MODULE so the function can be meck'd in rebar_utils_SUITE +    OtpRelease = ?MODULE:otp_release(), +    ParsedMin = version_tuple(MinOtpVersion), +    ParsedVsn = version_tuple(OtpRelease), + +    case ParsedVsn >= ParsedMin of +        true -> +            ?DEBUG("~s satisfies the requirement for minimum OTP version ~s", +                   [OtpRelease, MinOtpVersion]); +        false -> +            ?ABORT("OTP release ~s or later is required. Version in use: ~s", +                   [MinOtpVersion, OtpRelease]) +    end. + +check_blacklisted_otp_versions(undefined) -> +    ok; +check_blacklisted_otp_versions(BlacklistedRegexes) -> +    %% Fully-qualify with ?MODULE so the function can be meck'd in rebar_utils_SUITE +    OtpRelease = ?MODULE:otp_release(), +    lists:foreach( +        fun(BlacklistedRegex) -> abort_if_blacklisted(BlacklistedRegex, OtpRelease) end, +        BlacklistedRegexes). + +abort_if_blacklisted(BlacklistedRegex, OtpRelease) -> +    case re:run(OtpRelease, BlacklistedRegex, [{capture, none}]) of +        match -> +            ?ABORT("OTP release ~s matches blacklisted version ~s", +                   [OtpRelease, BlacklistedRegex]); +        nomatch -> +            ?DEBUG("~s does not match blacklisted OTP version ~s", +                   [OtpRelease, BlacklistedRegex]) +    end. + +  %% ====================================================================  %% Internal functions  %% ==================================================================== +version_tuple(OtpRelease) -> +    case re:run(OtpRelease, "R?(\\d+)B?.?-?(\\d+)?.?-?(\\d+)?", [{capture, all, list}]) of +        {match, [_Full, Maj, Min, Patch]} -> +            {list_to_integer(Maj), list_to_integer(Min), list_to_integer(Patch)}; +        {match, [_Full, Maj, Min]} -> +            {list_to_integer(Maj), list_to_integer(Min), 0}; +        {match, [_Full, Maj]} -> +            {list_to_integer(Maj), 0, 0}; +        nomatch -> +            ?ABORT("Minimum OTP release unable to be parsed: ~s", [OtpRelease]) +    end.  otp_release() ->      otp_release1(erlang:system_info(otp_release)). diff --git a/test/rebar_utils_SUITE.erl b/test/rebar_utils_SUITE.erl index f04ab63..24e8afe 100644 --- a/test/rebar_utils_SUITE.erl +++ b/test/rebar_utils_SUITE.erl @@ -1,6 +1,8 @@  -module(rebar_utils_SUITE).  -export([all/0, +         init_per_testcase/2, +         end_per_testcase/2,           groups/0,           init_per_group/2,           end_per_group/2, @@ -22,12 +24,23 @@           task_with_flag_with_commas/1,           task_with_multiple_flags/1,           special_task_do/1, +         valid_otp_version/1, +         valid_old_format_otp_version/1, +         valid_otp_version_equal/1, +         invalid_otp_version/1, +         nonblacklisted_otp_version/1, +         blacklisted_otp_version/1,           sh_does_not_miss_messages/1]).  -include_lib("common_test/include/ct.hrl").  -include_lib("eunit/include/eunit.hrl").  -include_lib("kernel/include/file.hrl"). +init_per_testcase(_, Config) -> +    rebar_test_utils:init_rebar_state(Config). + +end_per_testcase(_, _Config) -> +    catch meck:unload().  all() ->      [{group, args_to_tasks}, @@ -51,7 +64,14 @@ groups() ->                            task_with_flag_with_trailing_comma,                            task_with_flag_with_commas,                            task_with_multiple_flags, -                          special_task_do]}]. +                          special_task_do, +                          valid_otp_version, +                          valid_old_format_otp_version, +                          valid_otp_version_equal, +                          invalid_otp_version, +                          nonblacklisted_otp_version, +                          blacklisted_otp_version +    ]}].  init_per_group(_, Config) -> Config.  end_per_group(_, Config) -> Config. @@ -120,6 +140,53 @@ special_task_do(_Config) ->                                                                          "do",                                                                          "bar,",                                                                          "baz"]). + +valid_otp_version(_Config) -> +    meck:new(rebar_utils, [passthrough]), +    meck:expect(rebar_utils, otp_release, fun() -> "42.4" end), +    rebar_utils:check_min_otp_version("42.3"), +    meck:unload(rebar_utils). + +valid_old_format_otp_version(_Config) -> +    meck:new(rebar_utils, [passthrough]), +    meck:expect(rebar_utils, otp_release, fun() -> "R15B03-1" end), +    rebar_utils:check_min_otp_version("14"), + +    meck:expect(rebar_utils, otp_release, fun() -> "R16B03" end), +    rebar_utils:check_min_otp_version("16.0"), + +    meck:expect(rebar_utils, otp_release, fun() -> "18.0.1" end), +    rebar_utils:check_min_otp_version("17.5.4"), + +    meck:expect(rebar_utils, otp_release, fun() -> "18.0-rc1" end), +    ?assertException(throw, rebar_abort, rebar_utils:check_min_otp_version("19")), + +    meck:unload(rebar_utils). + +valid_otp_version_equal(_Config) -> +    meck:new(rebar_utils, [passthrough]), +    meck:expect(rebar_utils, otp_release, fun() -> "42.3" end), +    rebar_utils:check_min_otp_version("42.3"), +    meck:unload(rebar_utils). + +invalid_otp_version(_Config) -> +    meck:new(rebar_utils, [passthrough]), +    meck:expect(rebar_utils, otp_release, fun() -> "17.4" end), +    ?assertException(throw, rebar_abort, rebar_utils:check_min_otp_version("42.3")), +    meck:unload(rebar_utils). + +nonblacklisted_otp_version(_Config) -> +    meck:new(rebar_utils, [passthrough]), +    meck:expect(rebar_utils, otp_release, fun() -> "42.4" end), +    rebar_utils:check_blacklisted_otp_versions(["1\\.2", "42\\.3"]), +    meck:unload(rebar_utils). + +blacklisted_otp_version(_Config) -> +    meck:new(rebar_utils, [passthrough]), +    meck:expect(rebar_utils, otp_release, fun() -> "42.4" end), +    ?assertException(throw, rebar_abort, rebar_utils:check_blacklisted_otp_versions(["1\\.2", "42\\.[1-4]"])), +    meck:unload(rebar_utils). +  sh_does_not_miss_messages(_Config) ->      Source = "~nmain(_) ->~n io:format(\"donotmissme\").~n",      file:write_file("do_not_miss_messages", io_lib:format(Source,[])), | 
