diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl index fa35fed..2a14503 100644 --- a/src/rebar_utils.erl +++ b/src/rebar_utils.erl @@ -32,31 +32,43 @@ wordsize/0, sh/2, sh_send/3, - find_files/2, find_files/3, + find_files/2, + find_files/3, now_str/0, ensure_dir/1, - beam_to_mod/2, beams/1, + beam_to_mod/2, + beams/1, erl_to_mod/1, - abort/0, abort/2, + abort/0, + abort/2, escript_foldl/3, find_executable/1, prop_check/3, expand_code_path/0, expand_env_variable/3, vcs_vsn/3, - deprecated/3, deprecated/4, - get_deprecated_global/4, get_deprecated_global/5, - get_experimental_global/3, get_experimental_local/3, - get_deprecated_list/4, get_deprecated_list/5, - get_deprecated_local/4, get_deprecated_local/5, + deprecated/3, + deprecated/4, + get_deprecated_global/4, + get_deprecated_global/5, + get_experimental_global/3, + get_experimental_local/3, + get_deprecated_list/4, + get_deprecated_list/5, + get_deprecated_local/4, + get_deprecated_local/5, delayed_halt/1, erl_opts/1, src_dirs/1, ebin_dir/0, base_dir/1, - processing_base_dir/1, processing_base_dir/2, + processing_base_dir/1, + processing_base_dir/2, patch_env/2]). +%% for internal use only +-export([otp_release/0]). + -include("rebar.hrl"). %% ==================================================================== @@ -77,7 +89,7 @@ is_arch(ArchRegex) -> get_arch() -> Words = wordsize(), - erlang:system_info(otp_release) ++ "-" + otp_release() ++ "-" ++ erlang:system_info(system_architecture) ++ "-" ++ Words. wordsize() -> @@ -90,7 +102,8 @@ wordsize() -> end. sh_send(Command0, String, Options0) -> - ?INFO("sh_send info:\n\tcwd: ~p\n\tcmd: ~s < ~s\n", [get_cwd(), Command0, String]), + ?INFO("sh_send info:\n\tcwd: ~p\n\tcmd: ~s < ~s\n", + [get_cwd(), Command0, String]), ?DEBUG("\topts: ~p\n", [Options0]), DefaultOptions = [use_stdout, abort_on_error], @@ -339,12 +352,14 @@ processing_base_dir(Config, Dir) -> AbsDir = filename:absname(Dir), AbsDir =:= base_dir(Config). -%% @doc Returns the list of environment variables including 'REBAR' which points to the -%% rebar executable used to execute the currently running command. The environment is -%% not modified if rebar was invoked programmatically. --spec patch_env(rebar_config:config(), [{string(), string()}]) -> [{string(), string()}]. +%% @doc Returns the list of environment variables including 'REBAR' which +%% points to the rebar executable used to execute the currently running +%% command. The environment is not modified if rebar was invoked +%% programmatically. +-spec patch_env(rebar_config:config(), [{string(), string()}]) + -> [{string(), string()}]. patch_env(Config, []) -> - % if we reached an empty list the env did not contain the REBAR variable + %% If we reached an empty list, the env did not contain the REBAR variable. case rebar_config:get_xconf(Config, escript, "") of "" -> % rebar was invoked programmatically []; @@ -360,6 +375,42 @@ patch_env(Config, [E | Rest]) -> %% Internal functions %% ==================================================================== +otp_release() -> + otp_release1(erlang:system_info(otp_release)). + +%% If OTP <= R16, otp_release is already what we want. +otp_release1([$R,N|_]=Rel) when is_integer(N) -> + Rel; +%% If OTP >= 17.x, erlang:system_info(otp_release) returns just the +%% major version number, we have to read the full version from +%% a file. See http://www.erlang.org/doc/system_principles/versions.html +%% Read vsn strinf from the 'OTP_VERSION' file and return as list without +%% the "\n". +otp_release1(Rel) -> + File = filename:join([code:root_dir(), "releases", Rel, "OTP_VERSION"]), + {ok, Vsn} = file:read_file(File), + + %% NOTE: It's fine to rely on the binary module here because we + %% can be sure that it's available when the otp_release string + %% does not begin with $R. + Size = byte_size(Vsn), + %% The shortest vsn string consists of at least two digits + %% followed by "\n". Therefore, it's safe to assume Size >= 3. + case binary:part(Vsn, {Size, -3}) of + <<"**\n">> -> + %% The OTP documentation mentions that a system patched + %% using the otp_patch_apply tool available to licensed + %% customers will leave a '**' suffix in the version as a + %% flag saying the system consists of application versions + %% from multiple OTP versions. We ignore this flag and + %% drop the suffix, given for all intents and purposes, we + %% cannot obtain relevant information from it as far as + %% tooling is concerned. + binary:bin_to_list(Vsn, {0, Size - 3}); + _ -> + binary:bin_to_list(Vsn, {0, Size - 1}) + end. + get_deprecated_3(Get, Config, OldOpt, NewOpt, Default, When) -> case Get(Config, NewOpt, Default) of Default -> diff --git a/test/rebar_otp_release_tests.erl b/test/rebar_otp_release_tests.erl new file mode 100644 index 0000000..61efdad --- /dev/null +++ b/test/rebar_otp_release_tests.erl @@ -0,0 +1,47 @@ +%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- +%% ex: ts=4 sw=4 et +%% ------------------------------------------------------------------- +%% +%% rebar: Erlang Build Tools +%% +%% Copyright (c) 2014 Tuncer Ayaz +%% +%% Permission is hereby granted, free of charge, to any person obtaining a copy +%% of this software and associated documentation files (the "Software"), to deal +%% in the Software without restriction, including without limitation the rights +%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +%% copies of the Software, and to permit persons to whom the Software is +%% furnished to do so, subject to the following conditions: +%% +%% The above copyright notice and this permission notice shall be included in +%% all copies or substantial portions of the Software. +%% +%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +%% THE SOFTWARE. +%% ------------------------------------------------------------------- +-module(rebar_otp_release_tests). + +-include_lib("eunit/include/eunit.hrl"). + +check_otp_release_test() -> + case rebar_utils:otp_release() of + %% <= R16 + [$R,N|_] when is_integer(N) -> + ?assert(true); + %% >= 17.x + [N|_]=Rel when is_integer(N) -> + %% Check that it has at least Major.Minor + ?assert(length(string:tokens(Rel, ".")) > 1), + + %% If otp_patch_apply was used and the release version has + %% a "**" suffix, we drop that part in otp_release/0. + ?assertEqual(0, string:str(Rel, "*")), + + %% Check that "\n" is dropped in otp_release/0. + ?assertEqual(0, string:str(Rel, "\n")) + end.