From 04fedc7422c26002785f6e7cb6e814fdb8a2f0dd Mon Sep 17 00:00:00 2001 From: Derek Brown Date: Tue, 2 Jun 2015 15:12:12 -0400 Subject: Add functions to validate OTP release in use In the spirit of Original Rebar's "require_min_otp_vsn", this adds rebar_utils:check_min_otp_version/1 (taking a string containing the minimum version) and rebar_utils:check_blacklisted_otp_versions/1 (taking a list of regular expression strings), as well as tests in rebar_utils_SUITE. They're currently only called by the tests- how/where to best place calls to them from non-test code needs to be determined (at which point two corresponding rebar.config keys can be supported). For example, the version probably shouldn't be enforced when just running "rebar3 help". --- src/rebar_utils.erl | 46 ++++++++++++++++++++++++++++++++++++++++- test/rebar_utils_SUITE.erl | 51 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 95 insertions(+), 2 deletions(-) diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl index 6eb4f4b..26125a3 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,10 +301,52 @@ 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(), + {MinMajor, MinMinor} = split_version(MinOtpVersion), + {OtpMajor, OtpMinor} = split_version(OtpRelease), + + case {OtpMajor, OtpMinor} >= {MinMajor, MinMinor} of + true -> + ?DEBUG("~s satisfies the requirement for minimum OTP version ~s", + [OtpRelease, MinOtpVersion]); + false -> + ?ABORT("OTP release ~s or later is required. Verion 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 %% ==================================================================== +split_version(Version) -> + list_to_tuple(lists:map( + fun(S) -> list_to_integer(S) end, + string:tokens(Version, "."))). + 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..d766af4 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,22 @@ task_with_flag_with_commas/1, task_with_multiple_flags/1, special_task_do/1, + valid_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 +63,13 @@ 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_otp_version_equal, + invalid_otp_version, + nonblacklisted_otp_version, + blacklisted_otp_version + ]}]. init_per_group(_, Config) -> Config. end_per_group(_, Config) -> Config. @@ -120,6 +138,37 @@ 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_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,[])), -- cgit v1.1 From 6e9df6cc577f84cac330065c26ba2ada7bc56a32 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Fri, 24 Jul 2015 21:40:43 -0500 Subject: parse old format of OTP versions --- src/rebar_utils.erl | 19 ++++++++++++------- test/rebar_utils_SUITE.erl | 8 ++++++++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl index 26125a3..c71808d 100644 --- a/src/rebar_utils.erl +++ b/src/rebar_utils.erl @@ -306,8 +306,8 @@ check_min_otp_version(undefined) -> check_min_otp_version(MinOtpVersion) -> %% Fully-qualify with ?MODULE so the function can be meck'd in rebar_utils_SUITE OtpRelease = ?MODULE:otp_release(), - {MinMajor, MinMinor} = split_version(MinOtpVersion), - {OtpMajor, OtpMinor} = split_version(OtpRelease), + {MinMajor, MinMinor} = version_tuple(MinOtpVersion), + {OtpMajor, OtpMinor} = version_tuple(OtpRelease), case {OtpMajor, OtpMinor} >= {MinMajor, MinMinor} of true -> @@ -341,11 +341,16 @@ abort_if_blacklisted(BlacklistedRegex, OtpRelease) -> %% ==================================================================== %% Internal functions %% ==================================================================== - -split_version(Version) -> - list_to_tuple(lists:map( - fun(S) -> list_to_integer(S) end, - string:tokens(Version, "."))). +version_tuple(OtpRelease) -> + case re:run(OtpRelease, "R?(\\d+)B?-?(\\d+)?", [{capture, all, list}]) of + {match, [_Full, Maj, Min]} -> + {list_to_integer(Maj), list_to_integer(Min)}; + {match, [_Full, Maj]} -> + {list_to_integer(Maj), 0}; + nomatch -> + ?WARN("", []), + {0,0} + 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 d766af4..144b840 100644 --- a/test/rebar_utils_SUITE.erl +++ b/test/rebar_utils_SUITE.erl @@ -25,6 +25,7 @@ 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, @@ -65,6 +66,7 @@ groups() -> task_with_multiple_flags, special_task_do, valid_otp_version, + valid_old_format_otp_version, valid_otp_version_equal, invalid_otp_version, nonblacklisted_otp_version, @@ -145,6 +147,12 @@ valid_otp_version(_Config) -> 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("R15"), + meck:unload(rebar_utils). + valid_otp_version_equal(_Config) -> meck:new(rebar_utils, [passthrough]), meck:expect(rebar_utils, otp_release, fun() -> "42.3" end), -- cgit v1.1 From 90fbd6dbb9a1a8d1185fc521ffd2d391e8befcdf Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Sat, 25 Jul 2015 11:43:54 -0500 Subject: add support for old format otp versions --- src/rebar_app_discover.erl | 4 ++++ src/rebar_prv_install_deps.erl | 3 +++ src/rebar_utils.erl | 31 ++++++++++++++++--------------- test/rebar_utils_SUITE.erl | 12 +++++++++++- 4 files changed, 34 insertions(+), 16 deletions(-) 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 c71808d..5763718 100644 --- a/src/rebar_utils.erl +++ b/src/rebar_utils.erl @@ -306,16 +306,16 @@ check_min_otp_version(undefined) -> check_min_otp_version(MinOtpVersion) -> %% Fully-qualify with ?MODULE so the function can be meck'd in rebar_utils_SUITE OtpRelease = ?MODULE:otp_release(), - {MinMajor, MinMinor} = version_tuple(MinOtpVersion), - {OtpMajor, OtpMinor} = version_tuple(OtpRelease), + ParsedMin = version_tuple(MinOtpVersion), + ParsedVsn = version_tuple(OtpRelease), - case {OtpMajor, OtpMinor} >= {MinMajor, MinMinor} of + case ParsedVsn >= ParsedMin of true -> ?DEBUG("~s satisfies the requirement for minimum OTP version ~s", - [OtpRelease, MinOtpVersion]); + [OtpRelease, MinOtpVersion]); false -> - ?ABORT("OTP release ~s or later is required. Verion in use: ~s", - [MinOtpVersion, OtpRelease]) + ?ABORT("OTP release ~s or later is required. Version in use: ~s", + [MinOtpVersion, OtpRelease]) end. check_blacklisted_otp_versions(undefined) -> @@ -331,10 +331,10 @@ 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]) + [OtpRelease, BlacklistedRegex]); + nomatch -> + ?DEBUG("~s does not match blacklisted OTP version ~s", + [OtpRelease, BlacklistedRegex]) end. @@ -342,14 +342,15 @@ abort_if_blacklisted(BlacklistedRegex, OtpRelease) -> %% Internal functions %% ==================================================================== version_tuple(OtpRelease) -> - case re:run(OtpRelease, "R?(\\d+)B?-?(\\d+)?", [{capture, all, list}]) of + 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)}; + {list_to_integer(Maj), list_to_integer(Min), 0}; {match, [_Full, Maj]} -> - {list_to_integer(Maj), 0}; + {list_to_integer(Maj), 0, 0}; nomatch -> - ?WARN("", []), - {0,0} + ?ABORT("Minimum OTP release unable to be parsed: ~s", [OtpRelease]) end. otp_release() -> diff --git a/test/rebar_utils_SUITE.erl b/test/rebar_utils_SUITE.erl index 144b840..24e8afe 100644 --- a/test/rebar_utils_SUITE.erl +++ b/test/rebar_utils_SUITE.erl @@ -150,7 +150,17 @@ valid_otp_version(_Config) -> 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("R15"), + 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) -> -- cgit v1.1 From c983675b9ef8499a41e18ee6b8d83d11d75bd6b7 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Sat, 25 Jul 2015 11:45:00 -0500 Subject: add Derek Brown to THANKS --- THANKS | 1 + 1 file changed, 1 insertion(+) diff --git a/THANKS b/THANKS index d813970..cf59ef1 100644 --- a/THANKS +++ b/THANKS @@ -135,3 +135,4 @@ Pierre Fenoll David Kubecka Stefan Grundmann Carlos Eduardo de Paula +Derek Brown \ No newline at end of file -- cgit v1.1