diff --git a/.github/workflows/shelltests.yml b/.github/workflows/shelltests.yml new file mode 100644 index 000000000..55edb2f05 --- /dev/null +++ b/.github/workflows/shelltests.yml @@ -0,0 +1,35 @@ +name: Shell tests + +on: + pull_request: + branches: + - 'master' + push: + branches: + - 'master' + +jobs: + shelltests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: erlef/setup-beam@v1 + with: + otp-version: '24.0.1' + elixir-version: '1.12' + - name: Compile + run: ./bootstrap + - name: Install + run: | + sudo cp ./rebar3 /usr/local/bin/ + + - name: Checkout shell tests + run: git clone https://github.com/tsloughter/rebar3_tests + + - name: Install and run shelltestrunner + run: | + sudo apt-get update + sudo apt-get install -y shelltestrunner build-essential + cd rebar3_tests + mix local.hex --force + ./run_tests.sh diff --git a/bootstrap b/bootstrap index 5b54876f8..9632b6c77 100755 --- a/bootstrap +++ b/bootstrap @@ -44,7 +44,7 @@ main(_) -> bootstrap_rebar3(), %% Build rebar.app from rebar.app.src - {ok, App} = rebar_app_info:new(rebar, "3.16.1", filename:absname("_build/default/lib/rebar/")), + {ok, App} = rebar_app_info:new(rebar, "3.17.0", filename:absname("_build/default/lib/rebar/")), rebar_otp_app:compile(rebar_state:new(), App), %% Because we are compiling files that are loaded already we want to silence @@ -747,30 +747,32 @@ chr([], _C, _I) -> 0. %% These two functions are ports of rebar_uri module calls that %% can't be called before the app is built; they're utility functions for %% forwards and backwards compat so we need them to be current. +-ifdef(OTP_RELEASE). rebar_uri_parse(URIString) -> %% we drop rebar_uri:apply_opts since it's a noop as called here - try uri_string:parse(URIString) of + case uri_string:parse(URIString) of Map = #{userinfo := _} -> Map; Map when is_map(Map) -> Map#{userinfo => ""}; Res -> Res - catch - error:undef -> - %% Taken from rebar_uri and trimmed down. - case http_uri:parse(URIString, []) of - {error, Reason} -> - {error, "", Reason}; - {ok, {Scheme, UserInfo, Host, Port, Path, Query}} -> - #{ - scheme => atom_to_list(Scheme), - host => Host, port => Port, path => Path, - query => case Query of - [] -> ""; - _ -> string:substr(Query, 2) - end, - userinfo => UserInfo - } - end end. +-else. +rebar_uri_parse(URIString) -> + %% Taken from rebar_uri and trimmed down. + case http_uri:parse(URIString, []) of + {error, Reason} -> + {error, "", Reason}; + {ok, {Scheme, UserInfo, Host, Port, Path, Query}} -> + #{ + scheme => atom_to_list(Scheme), + host => Host, port => Port, path => Path, + query => case Query of + [] -> ""; + _ -> string:substr(Query, 2) + end, + userinfo => UserInfo + } + end. +-endif. %% Taken from rebar_uri.erl rebar_uri_percent_decode(URIMap) when is_map(URIMap)-> diff --git a/rebar.config b/rebar.config index 7106ddd50..5120fac6d 100644 --- a/rebar.config +++ b/rebar.config @@ -23,17 +23,18 @@ {escript_name, rebar3}. {escript_wrappers_windows, ["cmd", "powershell"]}. -{escript_comment, "%%Rebar3 3.16.1\n"}. +{escript_comment, "%%Rebar3 3.17.0\n"}. {escript_emu_args, "%%! +sbtu +A1\n"}. -%% escript_incl_extra is for internal rebar-private use only. +%% escript_incl_priv is for internal rebar-private use only. %% Do not use outside rebar. Config interface is not stable. -{escript_incl_extra, [{"relx/priv/templates/*", "_build/default/lib/"}, - {"rebar/priv/templates/*", "_build/default/lib/"}]}. +{escript_incl_priv, [{relx, "templates/*"}, + {rebar, "templates/*"}]}. {overrides, [{add, relx, [{erl_opts, [{d, 'RLX_LOG', rebar_log}]}]}]}. {erl_opts, [warnings_as_errors, {platform_define, "^(2[1-9])|(20\\\\.3)", filelib_find_source}, + {platform_define, "^(1|(20))", no_customize_hostname_check}, {platform_define, "^(20)", fun_stacktrace} ]}. @@ -66,10 +67,6 @@ {bootstrap, []}, {prod, [ - {escript_incl_extra, [ - {"relx/priv/templates/*", "_build/prod/lib/"}, - {"rebar/priv/templates/*", "_build/prod/lib/"} - ]}, {erl_opts, [no_debug_info]}, {overrides, [ {override, erlware_commons, [ diff --git a/rebar.lock b/rebar.lock index f8e951c9f..e98ff18bf 100644 --- a/rebar.lock +++ b/rebar.lock @@ -7,7 +7,7 @@ {<<"eunit_formatters">>,{pkg,<<"eunit_formatters">>,<<"0.5.0">>},0}, {<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0}, {<<"providers">>,{pkg,<<"providers">>,<<"1.8.1">>},0}, - {<<"relx">>,{pkg,<<"relx">>,<<"4.4.0">>},0}, + {<<"relx">>,{pkg,<<"relx">>,<<"4.5.0">>},0}, {<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.6">>},0}]}. [ {pkg_hash,[ @@ -19,7 +19,7 @@ {<<"eunit_formatters">>, <<"6A9133943D36A465D804C1C5B6E6839030434B8879C5600D7DDB5B3BAD4CCB59">>}, {<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>}, {<<"providers">>, <<"70B4197869514344A8A60E2B2A4EF41CA03DEF43CFB1712ECF076A0F3C62F083">>}, - {<<"relx">>, <<"A7483BF5B82821D9CC992EF51F0B2DBFE05ADACD976807D42907C02C0C038B9C">>}, + {<<"relx">>, <<"2BF90A855023023EDD000641033D1AB9F4EBD4314D1739F691E16FE03CB35B85">>}, {<<"ssl_verify_fun">>, <<"CF344F5692C82D2CD7554F5EC8FD961548D4FD09E7D22F5B62482E5AEAEBD4B0">>}]}, {pkg_hash_ext,[ {<<"bbmustache">>, <<"43EFFA3FD4BB9523157AF5A9E2276C493495B8459FC8737144AA186CB13CE2EE">>}, @@ -30,6 +30,6 @@ {<<"eunit_formatters">>, <<"D6C8BA213424944E6E05BBC097C32001CDD0ABE3925D02454F229B20D68763C9">>}, {<<"getopt">>, <<"53E1AB83B9CEB65C9672D3E7A35B8092E9BDC9B3EE80721471A161C10C59959C">>}, {<<"providers">>, <<"E45745ADE9C476A9A469EA0840E418AB19360DC44F01A233304E118A44486BA0">>}, - {<<"relx">>, <<"55C0ED63BB5D55EB983A19EB94D7F3075DF6D126DBDFF43102A6660A91FCE925">>}, + {<<"relx">>, <<"DDB58F20CCE6CA63F5A2725E925816DD7213476698A3F3C3CB4FA8C272202C52">>}, {<<"ssl_verify_fun">>, <<"BDB0D2471F453C88FF3908E7686F86F9BE327D065CC1EC16FA4540197EA04680">>}]} ]. diff --git a/src/rebar.app.src.script b/src/rebar.app.src.script index 1bf95282d..f2f63458f 100644 --- a/src/rebar.app.src.script +++ b/src/rebar.app.src.script @@ -3,7 +3,7 @@ {application, rebar, [{description, "Rebar: Erlang Build Tool"}, - {vsn, "3.16.1"}, + {vsn, "3.17.0"}, {modules, []}, {registered, []}, {applications, [kernel, diff --git a/src/rebar_app_discover.erl b/src/rebar_app_discover.erl index 3070b5170..a1400c688 100644 --- a/src/rebar_app_discover.erl +++ b/src/rebar_app_discover.erl @@ -256,7 +256,7 @@ app_dirs(LibDir, SrcDirs, State) -> ]), EbinPath = filename:join([LibDir, "ebin", "*.app"]), - MixExsPath = filename:join([LibDir, "src", "mix.exs"]), + MixExsPath = filename:join([LibDir, "mix.exs"]), lists:usort(lists:foldl(fun(Path, Acc) -> Files = filelib:wildcard(rebar_utils:to_list(Path)), @@ -344,14 +344,18 @@ find_app(AppInfo, AppDir, SrcDirs, Validate, State) -> {true, rebar_app_info:t()} | false. find_app_(AppInfo, AppDir, SrcDirs, Validate, State) -> Extensions = rebar_state:get(State, application_resource_extensions, ?DEFAULT_APP_RESOURCE_EXT), + NormSrcDirs = [case SrcDir of + {ActualSrcDir, _Opts} -> ActualSrcDir; + _ -> SrcDir + end || SrcDir <- SrcDirs], ResourceFiles = [ {app, filelib:wildcard(filename:join([AppDir, "ebin", "*.app"]))}, - {mix_exs, filelib:wildcard(filename:join([AppDir, "src", "mix.exs"]))} | - [ - {extension_type(Ext), lists:append([ filelib:wildcard(filename:join([AppDir, SrcDir, "*" ++ Ext])) - || SrcDir <- SrcDirs])} - || Ext <- Extensions - ]], + {mix_exs, filelib:wildcard(filename:join([AppDir, "mix.exs"]))} + | [{extension_type(Ext), + lists:append([filelib:wildcard(filename:join([AppDir, SrcDir, "*" ++ Ext])) + || SrcDir <- NormSrcDirs])} + || Ext <- Extensions] + ], FlattenedResourceFiles = flatten_resource_files(ResourceFiles), try_handle_resource_files(AppInfo, AppDir, FlattenedResourceFiles, Validate). @@ -447,8 +451,14 @@ try_handle_resource_files(AppInfo, AppDir, [{app, AppFile} | Rest], Validate) -> try_handle_resource_files(AppInfo, AppDir, [{Type, AppSrcFile} | _Rest], Validate) when Type =:= app_src orelse Type =:= script -> try_handle_app_src_file(AppInfo, AppDir, AppSrcFile, Validate); -try_handle_resource_files(AppInfo, _AppDir, [{mix_exs, _AppSrcFile} | _Rest], _Validate) -> - {true, rebar_app_info:project_type(AppInfo, mix)}; +try_handle_resource_files(AppInfo, AppDir, [{mix_exs, _MixExs} | Rest], Validate) -> + %% prefer a rebar3 buildable app if both are found + case try_handle_resource_files(AppInfo, AppDir, Rest, Validate) of + false -> + {true, rebar_app_info:project_type(AppInfo, mix)}; + {true, _}=Result -> + Result + end; try_handle_resource_files(_AppInfo, _AppDir, [], _Validate) -> false. diff --git a/src/rebar_compiler_dag.erl b/src/rebar_compiler_dag.erl index fcb418cc8..0cd75aea0 100644 --- a/src/rebar_compiler_dag.erl +++ b/src/rebar_compiler_dag.erl @@ -269,10 +269,53 @@ compile_order(G, AppDefs, SrcExt, ArtifactExt) -> end end end, new_cache(), digraph:edges(G)), - Sorted = lists:reverse(digraph_utils:topsort(AppDAG)), + Standalone = [Name || {Name, _} <- AppDefs], + Sorted = interleave(Standalone, AppDAG), digraph:delete(AppDAG), - Standalone = [Name || {Name, _} <- AppDefs] -- Sorted, - Standalone ++ Sorted. + Sorted. + +%% Assume that the standalone app list respects the +%% rebar.config deps order, and enforce the sorted app +%% constraints onto it such that we're always respecting +%% the hard dependencies. +%% +%% What we do here is a sort of run-length reordering based +%% on DAG information, which preserves the original dependency +%% order as declared, but successfully interleaves hard deps +%% to come first. +%% +%% Note that this approach is required as opposed to topsort +%% because when the original DAG reports two distinct set of +%% app dependencies that are joined by an invisible compile-time +%% one (e.g. a parse_transform runtime dep between both sets), +%% then the topological sort can't provide the right ordering +%% information because it's flattened into one list, but +%% this one can. +interleave(Apps, DAG) -> + interleave(Apps, DAG, sets:new()). + +interleave([], _, _) -> + []; +interleave([App|Apps], DAG, Expanded) -> + case sets:is_element(App, Expanded) of + true -> + [App|interleave(Apps, DAG, Expanded)]; + false -> + %% The DAG functions don't make it easy on insert to check for + %% duplicate edges across apps, so we clean them up here. + Deps = dedupe(digraph:out_neighbours(DAG, App)) -- sets:to_list(Expanded), + interleave(Deps ++ [App|Apps -- Deps], DAG, sets:add_element(App, Expanded)) + end. + +dedupe(L) -> dedupe(L, sets:new()). + +dedupe([], _) -> + []; +dedupe([H|T], Set) -> + case sets:is_element(H, Set) of + true -> dedupe(T, Set); + false -> [H|dedupe(T, sets:add_element(H, Set))] + end. add_one_dependency_to_digraph(V1, V2, Cache, AppDefs, AppDAG) -> %% First resolve the file we depend on so that we can shortcut resolution diff --git a/src/rebar_file_utils.erl b/src/rebar_file_utils.erl index 425f4c520..1b9916f5a 100644 --- a/src/rebar_file_utils.erl +++ b/src/rebar_file_utils.erl @@ -406,7 +406,7 @@ system_tmpdir(PathComponents) -> "win32" -> "./tmp"; _SysArch -> - "/tmp" + os:getenv("TMPDIR", "/tmp") end, filename:join([Tmp|PathComponents]). diff --git a/src/rebar_prv_dialyzer.erl b/src/rebar_prv_dialyzer.erl index 9c2fee5ae..f4a4d0cbc 100644 --- a/src/rebar_prv_dialyzer.erl +++ b/src/rebar_prv_dialyzer.erl @@ -352,7 +352,7 @@ read_plt(_State, Plt) -> {error, not_valid} -> error; {error, read_error} -> - Error = io_lib:format("Could not read the PLT file ~ts", [rebar_dir:format_source_file_name(Plt)]), + Error = io_lib:format("Could not read the PLT file ~ts", [format_path(Plt)]), throw({dialyzer_error, Error}) end. @@ -370,7 +370,7 @@ read_plt_files(Plt, Files) -> [] -> {ok, Files}; Missing -> - ?INFO("Could not find ~p files in ~ts...", [length(Missing), rebar_dir:format_source_file_name(Plt)]), + ?INFO("Could not find ~p files in ~ts...", [length(Missing), format_path(Plt)]), ?DEBUG("Could not find files: ~p", [Missing]), error end. @@ -389,19 +389,19 @@ check_plt(State, Plt, Output, OldList, FilesList) -> remove_plt(State, _Plt, _Output, []) -> {0, State}; remove_plt(State, Plt, Output, Files) -> - ?INFO("Removing ~b files from ~ts...", [length(Files), rebar_dir:format_source_file_name(Plt)]), + ?INFO("Removing ~b files from ~ts...", [length(Files), format_path(Plt)]), run_plt(State, Plt, Output, plt_remove, Files). check_plt(State, _Plt, _Output, []) -> {0, State}; check_plt(State, Plt, Output, Files) -> - ?INFO("Checking ~b files in ~ts...", [length(Files), rebar_dir:format_source_file_name(Plt)]), + ?INFO("Checking ~b files in ~ts...", [length(Files), format_path(Plt)]), run_plt(State, Plt, Output, plt_check, Files). add_plt(State, _Plt, _Output, []) -> {0, State}; add_plt(State, Plt, Output, Files) -> - ?INFO("Adding ~b files to ~ts...", [length(Files), rebar_dir:format_source_file_name(Plt)]), + ?INFO("Adding ~b files to ~ts...", [length(Files), format_path(Plt)]), run_plt(State, Plt, Output, plt_add, Files). run_plt(State, Plt, Output, Analysis, Files) -> @@ -419,8 +419,7 @@ build_proj_plt(Args, State, Plt, Output, Files) -> ?INFO("Updating base plt...", []), BaseFiles = base_plt_files(State), {BaseWarnings, State1} = update_base_plt(State, BasePlt, Output, BaseFiles), - ?INFO("Copying ~ts to ~ts...", [rebar_dir:format_source_file_name(BasePlt), - rebar_dir:format_source_file_name(Plt)]), + ?INFO("Copying ~ts to ~ts...", [format_path(BasePlt), format_path(Plt)]), _ = filelib:ensure_dir(Plt), case file:copy(BasePlt, Plt) of {ok, _} -> @@ -462,7 +461,7 @@ update_base_plt(State, BasePlt, Output, BaseFiles) -> end. build_plt(State, Plt, _, []) -> - ?INFO("Building with no files in ~ts...", [rebar_dir:format_source_file_name(Plt)]), + ?INFO("Building with no files in ~ts...", [format_path(Plt)]), Opts = [{get_warnings, false}, {output_plt, Plt}, {apps, [erts]}], @@ -473,7 +472,7 @@ build_plt(State, Plt, _, []) -> _ = dialyzer:run([{analysis_type, plt_remove}, {init_plt, Plt} | Opts]), {0, State}; build_plt(State, Plt, Output, Files) -> - ?INFO("Building with ~b files in ~ts...", [length(Files), rebar_dir:format_source_file_name(Plt)]), + ?INFO("Building with ~b files in ~ts...", [length(Files), format_path(Plt)]), GetWarnings = get_config(State, get_warnings, false), Opts = [{analysis_type, plt_build}, {get_warnings, GetWarnings}, @@ -492,10 +491,10 @@ succ_typings(Args, State, Plt, Output) -> end. succ_typings_(State, Plt, _, []) -> - ?INFO("Analyzing no files with ~ts...", [rebar_dir:format_source_file_name(Plt)]), + ?INFO("Analyzing no files with ~ts...", [format_path(Plt)]), {0, State}; succ_typings_(State, Plt, Output, Files) -> - ?INFO("Analyzing ~b files with ~ts...", [length(Files), rebar_dir:format_source_file_name(Plt)]), + ?INFO("Analyzing ~b files with ~ts...", [length(Files), format_path(Plt)]), Opts = [{analysis_type, succ_typings}, {get_warnings, true}, {from, byte_code}, @@ -660,3 +659,13 @@ dialyzer_version() -> version_tuple(Major, Minor, Patch) -> {list_to_integer(Major), list_to_integer(Minor), list_to_integer(Patch)}. + +format_path(Path) -> + Normalized = rebar_dir:format_source_file_name(Path), + case filelib:is_file(Normalized) of + true -> Normalized; + false -> rebar_dir:format_source_file_name(Path, abs_path_opts()) + end. + +abs_path_opts() -> + dict:from_list([{compiler_source_format, absolute}]). diff --git a/src/rebar_prv_escriptize.erl b/src/rebar_prv_escriptize.erl index 69ee4041c..bad8d67ee 100644 --- a/src/rebar_prv_escriptize.erl +++ b/src/rebar_prv_escriptize.erl @@ -206,10 +206,26 @@ get_app_beams(App, Path) -> load_files(Prefix, "*.app", Path). get_extra(State) -> - Extra = rebar_state:get(State, escript_incl_extra, []), + AllApps = rebar_state:all_deps(State) ++ rebar_state:project_apps(State), + InclPriv = rebar_state:get(State, escript_incl_priv, []), + InclPrivPaths = lists:map(fun(Entry) -> + resolve_incl_priv(Entry, AllApps) + end, InclPriv), + % `escript_incl_extra` is kept for historical reasons as its internal use in + % rebar3 has been replaced with `escript_incl_priv`. + InclExtraPaths = rebar_state:get(State, escript_incl_extra, []), lists:foldl(fun({Wildcard, Dir}, Files) -> load_files(Wildcard, Dir) ++ Files - end, [], Extra). + end, [], InclPrivPaths ++ InclExtraPaths). + +% Converts a wildcard path relative to an app (e.g., `priv/*`) into a wildcard +% path with with the app name included (e.g., `relx/priv/*`). +resolve_incl_priv({AppName, PrivWildcard}, AllApps) when is_atom(AppName) -> + {ok, AppInfo} = + rebar_app_utils:find(rebar_utils:to_binary(AppName), AllApps), + AppOutDir = rebar_app_info:out_dir(AppInfo), + Wildcard = filename:join([atom_to_list(AppName), "priv", PrivWildcard]), + {Wildcard, filename:dirname(AppOutDir)}. load_files(Wildcard, Dir) -> load_files("", Wildcard, Dir). diff --git a/src/rebar_prv_plugins_upgrade.erl b/src/rebar_prv_plugins_upgrade.erl index 944791138..7b2481535 100644 --- a/src/rebar_prv_plugins_upgrade.erl +++ b/src/rebar_prv_plugins_upgrade.erl @@ -101,7 +101,7 @@ build_plugin(ToBuild, State) -> maybe_update_pkg(Tup, State) when is_tuple(Tup) -> maybe_update_pkg(element(1, Tup), State); maybe_update_pkg(Name, State) -> - try rebar_app_utils:parse_dep(root, unicode:characters_to_binary(?DEFAULT_PLUGINS_DIR), Name, State, [], 0) of + try rebar_app_utils:parse_dep(Name, root, unicode:characters_to_list(?DEFAULT_PLUGINS_DIR), State, [], 0) of AppInfo -> Source = rebar_app_info:source(AppInfo), case element(1, Source) of diff --git a/src/rebar_prv_xref.erl b/src/rebar_prv_xref.erl index 8e691a3b4..ead9408a5 100644 --- a/src/rebar_prv_xref.erl +++ b/src/rebar_prv_xref.erl @@ -7,7 +7,8 @@ -export([init/1, do/1, - format_error/1]). + format_error/1, + filter_xref_results/3]). -include("rebar.hrl"). -include_lib("providers/include/providers.hrl"). @@ -180,9 +181,6 @@ get_behaviour_callbacks(exports_not_used, Attributes) -> get_behaviour_callbacks(_XrefCheck, _Attributes) -> []. -parse_xref_result({_, MFAt}) -> MFAt; -parse_xref_result(MFAt) -> MFAt. - filter_xref_results(XrefCheck, XrefIgnores, XrefResults) -> SearchModules = lists:usort( lists:map( @@ -194,10 +192,16 @@ filter_xref_results(XrefCheck, XrefIgnores, XrefResults) -> Ignores = XrefIgnores ++ lists:flatmap(fun(Module) -> get_xref_ignorelist(Module, XrefCheck) end, SearchModules), + lists:filter( fun(Result) -> pred_xref_result(Result, Ignores) end, XrefResults). + +pred_xref_result({Src, Dest}, Ignores) -> pred_xref_result1(Src, Ignores) + andalso pred_xref_result1(Dest, Ignores); +pred_xref_result(Vertex, Ignores) -> pred_xref_result1(Vertex, Ignores). - [Result || Result <- XrefResults, - not lists:member(element(1, Result), Ignores) - andalso not lists:member(parse_xref_result(Result), Ignores)]. +pred_xref_result1(Vertex, Ignores) -> + Mod = case Vertex of {Module, _Func, _Arity} -> Module; + _ -> Vertex end, + not lists:member(Vertex, Ignores) andalso not lists:member(Mod, Ignores). display_results(XrefResults, QueryResults) -> [lists:map(fun display_xref_results_for_type/1, XrefResults), @@ -293,7 +297,7 @@ find_function_source(M, F, A, Bin) -> find_function_source_in_abstract_code(F, A, AbstractCode) -> %% Extract the original source filename from the abstract code - [{attribute, _, file, {Source0, _}} | _] = AbstractCode, + [{attribute, _, file, {Source0, _}} | _] = [Attr || Attr = {attribute, _, file, _} <- AbstractCode], Source = rebar_dir:make_relative_path(Source0, rebar_dir:get_cwd()), %% Extract the line number for a given function def Fn = [E || E <- AbstractCode, diff --git a/src/rebar_relx.erl b/src/rebar_relx.erl index 05ef6de4a..2216eb001 100644 --- a/src/rebar_relx.erl +++ b/src/rebar_relx.erl @@ -42,7 +42,11 @@ do(Provider, State) -> Args = [include_erts, system_libs, vm_args, sys_config], RelxConfig2 = maybe_obey_command_args(RelxConfig1, Opts, Args), - {ok, RelxState} = rlx_config:to_state(RelxConfig2), + {ok, RelxState_0} = rlx_config:to_state(RelxConfig2), + XrefIgnores = rebar_state:get(State, xref_ignores, []), + RelxState = rlx_state:filter_xref_warning(RelxState_0, + fun(Warnings) -> + rebar_prv_xref:filter_xref_results(undefined_function_calls, XrefIgnores, Warnings) end), Providers = rebar_state:providers(State), Cwd = rebar_state:dir(State), diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl index 922034581..d5a6b4b8b 100644 --- a/src/rebar_utils.erl +++ b/src/rebar_utils.erl @@ -1042,6 +1042,24 @@ ssl_opts(Url) -> [{verify, verify_none}] end. +%% @private Determines which CA Certs to use for the HTTPS request. +%% If the user sets the value {ssl_cacerts_path, "path to pem"} in their +%% global rebar.config file, the pem will be encoded and used for the +%% SSL connection. Otherwise, CA Certs from `certifi` will be used. +%% This functionality is useful (needed) for Corporate Proxies that rewrite Certs. +%% See ssl_opts/2 +get_cacerts() -> + GlobalConfigFile = rebar_dir:global_config(), + Config = rebar_config:consult_file(GlobalConfigFile), + case proplists:get_value(ssl_cacerts_path, Config) of + undefined -> + certifi:cacerts(); + Path -> + {ok, Bin} = file:read_file(Path), + Pems = public_key:pem_decode(Bin), + [Der || {'Certificate', Der, _} <- Pems] + end. + %%------------------------------------------------------------------------------ %% @doc %% Return the SSL options adequate for the project based on @@ -1058,15 +1076,25 @@ ssl_opts(ssl_verify_enabled, Url) -> #{host := Hostname} = rebar_uri:parse(rebar_utils:to_list(Url)), VerifyFun = {fun ssl_verify_hostname:verify_fun/3, [{check_hostname, Hostname}]}, - CACerts = certifi:cacerts(), - [{verify, verify_peer}, {depth, 2}, {cacerts, CACerts}, - {partial_chain, fun partial_chain/1}, {verify_fun, VerifyFun}]; + CACerts = get_cacerts(), + SslOpts = [{verify, verify_peer}, {depth, 2}, {cacerts, CACerts}, + {partial_chain, fun partial_chain/1}, {verify_fun, VerifyFun}], + check_hostname_opt(SslOpts); false -> ?WARN("Insecure HTTPS request (peer verification disabled), " "please update to OTP 17.4 or later", []), [{verify, verify_none}] end. +-ifdef(no_customize_hostname_check). +check_hostname_opt(Opts) -> + Opts. +-else. +check_hostname_opt(Opts) -> + MatchFun = public_key:pkix_verify_hostname_match_fun(https), + [{customize_hostname_check, [{match_fun, MatchFun}]} | Opts]. +-endif. + -spec partial_chain(Certs) -> Res when Certs :: list(any()), Res :: unknown_ca | {trusted_ca, any()}. diff --git a/test/rebar_file_utils_SUITE.erl b/test/rebar_file_utils_SUITE.erl index d771a82fa..9b97bd412 100644 --- a/test/rebar_file_utils_SUITE.erl +++ b/test/rebar_file_utils_SUITE.erl @@ -31,6 +31,8 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("kernel/include/file.hrl"). +-define(TMPDIR, "/test"). + all() -> [{group, tmpdir}, @@ -52,8 +54,19 @@ groups() -> init_per_group(reset_dir, Config) -> TmpDir = rebar_file_utils:system_tmpdir(["rebar_file_utils_SUITE", "resetable"]), - [{tmpdir, TmpDir}|Config]; + [{tmpdir, TmpDir} | Config]; +init_per_group(tmpdir, Config) -> + PreviousTmpDir = os:getenv("TMPDIR"), + os:putenv("TMPDIR", ?TMPDIR), + [{previous_tmp, PreviousTmpDir} | Config]; init_per_group(_, Config) -> Config. + +end_per_group(tmpdir, Config) -> + case ?config(previous_tmp, Config) of + false -> os:unsetenv("TMPDIR"); + Val -> os:putenv("TMPDIR", Val) + end, + Config; end_per_group(_, Config) -> Config. init_per_testcase(Test, Config) -> @@ -72,26 +85,26 @@ end_per_testcase(_Test, Config) -> raw_tmpdir(_Config) -> case rebar_file_utils:system_tmpdir() of - "/tmp" -> ok; + ?TMPDIR -> ok; "./tmp" -> ok end. empty_tmpdir(_Config) -> case rebar_file_utils:system_tmpdir([]) of - "/tmp" -> ok; + ?TMPDIR -> ok; "./tmp" -> ok end. simple_tmpdir(_Config) -> case rebar_file_utils:system_tmpdir(["test"]) of - "/tmp/test" -> ok; - "./tmp/test" -> ok + ?TMPDIR ++ "/test" -> ok; + "./tmp/test" -> ok end. multi_tmpdir(_Config) -> case rebar_file_utils:system_tmpdir(["a", "b", "c"]) of - "/tmp/a/b/c" -> ok; - "./tmp/a/b/c" -> ok + ?TMPDIR ++ "/a/b/c" -> ok; + "./tmp/a/b/c" -> ok end. reset_nonexistent_dir(Config) -> diff --git a/test/rebar_xref_SUITE.erl b/test/rebar_xref_SUITE.erl index 9f4bc7dec..090808859 100644 --- a/test/rebar_xref_SUITE.erl +++ b/test/rebar_xref_SUITE.erl @@ -231,7 +231,7 @@ get_module_body(ignoremod, AppName, IgnoreXref) -> "localfunc1(A, B) -> {A, B}.\n", % used local "localfunc2() -> ok.\n", % unused local "fdeprecated() -> ok.\n" % deprecated function - + "undef_call() -> non_existent_mod:func().\n" % undef function call ]; get_module_body(ignoremod2, AppName, IgnoreXref) -> ["-module(", AppName, "_ignoremod2).\n", @@ -241,7 +241,7 @@ get_module_body(ignoremod2, AppName, IgnoreXref) -> "localfunc1(A, B) -> {A, B}.\n", % used local "localfunc2() -> ok.\n", % unused local "fdeprecated() -> ok.\n" % deprecated function - + "undef_call() -> non_existent_mod:func().\n" % undef function call ]; get_module_body(othermod, AppName, IgnoreXref) -> ["-module(", AppName, "_othermod).\n",