summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--src/rebar3.erl5
-rw-r--r--src/rebar_erlc_compiler.erl25
-rw-r--r--src/rebar_file_utils.erl15
-rw-r--r--src/rebar_prv_common_test.erl5
-rw-r--r--src/rebar_prv_xref.erl3
-rw-r--r--src/rebar_utils.erl10
-rw-r--r--test/rebar_compile_SUITE.erl71
-rw-r--r--test/rebar_xref_SUITE.erl2
9 files changed, 117 insertions, 21 deletions
diff --git a/.travis.yml b/.travis.yml
index dbb4f26..5e17e50 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,7 @@ sudo: false
language: erlang
install: 'true'
otp_release:
-- 19.0
+- 19.1
- 18.0
- 17.5
- R16B03-1
diff --git a/src/rebar3.erl b/src/rebar3.erl
index c665f20..47dc25a 100644
--- a/src/rebar3.erl
+++ b/src/rebar3.erl
@@ -286,10 +286,11 @@ handle_error({error, Error}) when is_list(Error) ->
handle_error(Error) ->
%% Nothing should percolate up from rebar_core;
%% Dump this error to console
- ?CRASHDUMP("Error: ~p~n~p~n~n", [Error, erlang:get_stacktrace()]),
+ StackTrace = erlang:get_stacktrace(),
+ ?CRASHDUMP("Error: ~p~n~p~n~n", [Error, StackTrace]),
?ERROR("Uncaught error in rebar_core. Run with DEBUG=1 to see stacktrace or consult rebar3.crashdump", []),
?DEBUG("Uncaught error: ~p", [Error]),
- case erlang:get_stacktrace() of
+ case StackTrace of
[] -> ok;
Trace ->
?DEBUG("Stack trace to the error location:~n~p", [Trace])
diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl
index b148172..36a247e 100644
--- a/src/rebar_erlc_compiler.erl
+++ b/src/rebar_erlc_compiler.erl
@@ -203,8 +203,8 @@ compile_dirs(RebarOpts, BaseDir, SrcDirs, OutDir, Opts) ->
G = init_erlcinfo(include_abs_dirs(ErlOpts, BaseDir), AllErlFiles, BaseDir, OutDir),
{ParseTransforms, Rest} = split_source_files(AllErlFiles, ErlOpts),
- NeededErlFiles = case needed_files(G, ErlOpts, BaseDir, OutDir, ParseTransforms) of
- [] -> needed_files(G, ErlOpts, BaseDir, OutDir, Rest);
+ NeededErlFiles = case needed_files(G, ErlOpts, RebarOpts, BaseDir, OutDir, ParseTransforms) of
+ [] -> needed_files(G, ErlOpts, RebarOpts, BaseDir, OutDir, Rest);
%% at least one parse transform in the opts needs updating, so recompile all
_ -> AllErlFiles
end,
@@ -224,7 +224,7 @@ compile_dirs(RebarOpts, BaseDir, SrcDirs, OutDir, Opts) ->
true -> ErlOptsFirst;
false -> ErlOpts
end,
- internal_erl_compile(C, BaseDir, S, OutDir, ErlOpts1)
+ internal_erl_compile(C, BaseDir, S, OutDir, ErlOpts1, RebarOpts)
end)
after
true = digraph:delete(SubGraph),
@@ -312,13 +312,15 @@ filename_to_atom(F) -> list_to_atom(filename:rootname(filename:basename(F))).
%% Get subset of SourceFiles which need to be recompiled, respecting
%% dependencies induced by given graph G.
-needed_files(G, ErlOpts, Dir, OutDir, SourceFiles) ->
+needed_files(G, ErlOpts, RebarOpts, Dir, OutDir, SourceFiles) ->
lists:filter(fun(Source) ->
TargetBase = target_base(OutDir, Source),
Target = TargetBase ++ ".beam",
+ PrivIncludes = [{i, filename:join(Dir, Src)}
+ || Src <- rebar_dir:all_src_dirs(RebarOpts, ["src"], [])],
AllOpts = [{outdir, filename:dirname(Target)}
,{i, filename:join(Dir, "include")}
- ,{i, Dir}] ++ ErlOpts,
+ ,{i, Dir}] ++ PrivIncludes ++ ErlOpts,
digraph:vertex(G, Source) > {Source, filelib:last_modified(Target)}
orelse opts_changed(AllOpts, TargetBase)
orelse erl_compiler_opts_set()
@@ -518,12 +520,15 @@ expand_file_names(Files, Dirs) ->
end, Files).
-spec internal_erl_compile(rebar_dict(), file:filename(), file:filename(),
- file:filename(), list()) -> ok | {ok, any()} | {error, any(), any()}.
-internal_erl_compile(Opts, Dir, Module, OutDir, ErlOpts) ->
+ file:filename(), list(), rebar_dict()) ->
+ ok | {ok, any()} | {error, any(), any()}.
+internal_erl_compile(Opts, Dir, Module, OutDir, ErlOpts, RebarOpts) ->
Target = target_base(OutDir, Module) ++ ".beam",
ok = filelib:ensure_dir(Target),
- AllOpts = [{outdir, filename:dirname(Target)}] ++ ErlOpts ++
- [{i, filename:join(Dir, "include")}, {i, Dir}, return],
+ PrivIncludes = [{i, filename:join(Dir, Src)}
+ || Src <- rebar_dir:all_src_dirs(RebarOpts, ["src"], [])],
+ AllOpts = [{outdir, filename:dirname(Target)}] ++ ErlOpts ++ PrivIncludes ++
+ [{i, filename:join(Dir, "include")}, {i, Dir}, return],
case compile:file(Module, AllOpts) of
{ok, _Mod} ->
ok;
@@ -668,6 +673,8 @@ process_attr(include_lib, Form, Includes, Dir) ->
[FileNode] = erl_syntax:attribute_arguments(Form),
RawFile = erl_syntax:string_value(FileNode),
maybe_expand_include_lib_path(RawFile, Dir) ++ Includes;
+process_attr(behavior, Form, Includes, _Dir) ->
+ process_attr(behaviour, Form, Includes, _Dir);
process_attr(behaviour, Form, Includes, _Dir) ->
[FileNode] = erl_syntax:attribute_arguments(Form),
File = module_to_erl(erl_syntax:atom_value(FileNode)),
diff --git a/src/rebar_file_utils.erl b/src/rebar_file_utils.erl
index 437780d..6721b5a 100644
--- a/src/rebar_file_utils.erl
+++ b/src/rebar_file_utils.erl
@@ -72,11 +72,16 @@ consult_config(State, Filename) ->
[T] -> T;
[] -> []
end,
- SubConfigs = [consult_config(State, Entry ++ ".config") ||
- Entry <- Config, is_list(Entry)
- ],
-
- [Config | lists:merge(SubConfigs)].
+ JoinedConfig = lists:flatmap(
+ fun (SubConfig) when is_list(SubConfig) ->
+ case lists:suffix(".config", SubConfig) of
+ false -> consult_config(State, SubConfig ++ ".config");
+ true -> consult_config(State, SubConfig)
+ end;
+ (Entry) -> [Entry]
+ end, Config),
+ %% Backwards compatibility
+ [JoinedConfig].
format_error({bad_term_file, AppFile, Reason}) ->
io_lib:format("Error reading file ~s: ~s", [AppFile, file:format_error(Reason)]).
diff --git a/src/rebar_prv_common_test.erl b/src/rebar_prv_common_test.erl
index 1e0632e..46bd1a7 100644
--- a/src/rebar_prv_common_test.erl
+++ b/src/rebar_prv_common_test.erl
@@ -221,8 +221,13 @@ select_tests(State, ProjectApps, CmdOpts, CfgOpts) ->
Configs = lists:flatmap(fun(Filename) ->
rebar_file_utils:consult_config(State, Filename)
end, SysConfigs),
+ %% NB: load the applications (from user directories too) to support OTP < 17
+ %% to our best ability.
+ OldPath = code:get_path(),
+ code:add_pathsa(rebar_state:code_paths(State, all_deps)),
[application:load(Application) || Config <- Configs, {Application, _} <- Config],
rebar_utils:reread_config(Configs),
+ code:set_path(OldPath),
Merged = lists:ukeymerge(1,
lists:ukeysort(1, CmdOpts),
diff --git a/src/rebar_prv_xref.erl b/src/rebar_prv_xref.erl
index 45badd3..3d74c9a 100644
--- a/src/rebar_prv_xref.erl
+++ b/src/rebar_prv_xref.erl
@@ -165,7 +165,8 @@ keyall(Key, List) ->
lists:flatmap(fun({K, L}) when Key =:= K -> L; (_) -> [] end, List).
get_behaviour_callbacks(exports_not_used, Attributes) ->
- [B:behaviour_info(callbacks) || B <- keyall(behaviour, Attributes)];
+ [B:behaviour_info(callbacks) || B <- keyall(behaviour, Attributes) ++
+ keyall(behavior, Attributes)];
get_behaviour_callbacks(_XrefCheck, _Attributes) ->
[].
diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl
index aa9e268..f55f40f 100644
--- a/src/rebar_utils.erl
+++ b/src/rebar_utils.erl
@@ -414,8 +414,16 @@ user_agent() ->
?FMT("Rebar/~s (OTP/~s)", [Vsn, otp_release()]).
reread_config(ConfigList) ->
+ %% NB: we attempt to mimic -config here, which survives app reload,
+ %% hence {persistent, true}.
+ SetEnv = case version_tuple(?MODULE:otp_release()) of
+ {X, _, _} when X =< 17 ->
+ fun application:set_env/3;
+ _ ->
+ fun (App, Key, Val) -> application:set_env(App, Key, Val, [{persistent, true}]) end
+ end,
try
- [application:set_env(Application, Key, Val)
+ [SetEnv(Application, Key, Val)
|| Config <- ConfigList,
{Application, Items} <- Config,
{Key, Val} <- Items]
diff --git a/test/rebar_compile_SUITE.erl b/test/rebar_compile_SUITE.erl
index cb16304..f31ab39 100644
--- a/test/rebar_compile_SUITE.erl
+++ b/test/rebar_compile_SUITE.erl
@@ -42,6 +42,8 @@
deps_build_in_prod/1,
include_file_relative_to_working_directory/1,
include_file_in_src/1,
+ include_file_relative_to_working_directory_test/1,
+ include_file_in_src_test/1,
always_recompile_when_erl_compiler_options_set/1,
recompile_when_parse_transform_inline_changes/1,
recompile_when_parse_transform_as_opt_changes/1]).
@@ -68,6 +70,7 @@ all() ->
umbrella_mib_first_test, only_default_transitive_deps,
clean_all, override_deps, profile_override_deps, deps_build_in_prod,
include_file_relative_to_working_directory, include_file_in_src,
+ include_file_relative_to_working_directory_test, include_file_in_src_test,
recompile_when_parse_transform_as_opt_changes,
recompile_when_parse_transform_inline_changes] ++
case erlang:function_exported(os, unsetenv, 1) of
@@ -769,7 +772,7 @@ dont_recompile_when_opts_dont_change(Config) ->
NewModTime = [filelib:last_modified(filename:join([EbinDir, F]))
|| F <- NewFiles, filename:extension(F) == ".beam"],
- ?assert(ModTime == NewModTime).
+ ?assertEqual(ModTime, NewModTime).
dont_recompile_yrl_or_xrl(Config) ->
AppDir = ?config(apps, Config),
@@ -1314,6 +1317,72 @@ include_file_in_src(Config) ->
["compile"],
{ok, [{app, Name}]}).
+%% verify that the proper include path is defined
+%% according the erlang doc which states:
+%% If the filename File is absolute (possibly after variable substitution),
+%% the include file with that name is included. Otherwise, the specified file
+%% is searched for in the following directories, and in this order:
+%% * The current working directory
+%% * The directory where the module is being compiled
+%% * The directories given by the include option
+%%
+%% This test ensures that things keep working when additional directories
+%% are used for apps, such as the test/ directory within the test profile.
+include_file_relative_to_working_directory_test(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ Src = <<"-module(test).\n"
+"\n"
+"-include(\"include/test.hrl\").\n"
+"\n"
+"test() -> ?TEST_MACRO.\n"
+"\n">>,
+ Include = <<"-define(TEST_MACRO, test).\n">>,
+
+ ok = filelib:ensure_dir(filename:join([AppDir, "src", "dummy"])),
+ ok = filelib:ensure_dir(filename:join([AppDir, "test", "dummy"])),
+ ok = file:write_file(filename:join([AppDir, "test", "test.erl"]), Src),
+
+ ok = filelib:ensure_dir(filename:join([AppDir, "include", "dummy"])),
+ ok = file:write_file(filename:join([AppDir, "include", "test.hrl"]), Include),
+
+ RebarConfig = [],
+ rebar_test_utils:run_and_check(Config, RebarConfig,
+ ["as", "test", "compile"],
+ {ok, [{app, Name}]}).
+
+%% Same as `include_file_in_src/1' but using the `test/' directory
+%% within the test profile.
+include_file_in_src_test(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ Src = <<"-module(test).\n"
+"\n"
+"-include(\"test.hrl\").\n"
+"\n"
+"test() -> ?TEST_MACRO.\n"
+"\n">>,
+ Include = <<"-define(TEST_MACRO, test).\n">>,
+
+ ok = filelib:ensure_dir(filename:join([AppDir, "src", "dummy"])),
+ ok = filelib:ensure_dir(filename:join([AppDir, "test", "dummy"])),
+ ok = file:write_file(filename:join([AppDir, "test", "test.erl"]), Src),
+
+ ok = file:write_file(filename:join([AppDir, "src", "test.hrl"]), Include),
+
+ RebarConfig = [],
+ rebar_test_utils:run_and_check(Config, RebarConfig,
+ ["as", "test", "compile"],
+ {ok, [{app, Name}]}).
+
always_recompile_when_erl_compiler_options_set(Config) ->
%% save existing env to restore after test
ExistingEnv = os:getenv("ERL_COMPILER_OPTIONS"),
diff --git a/test/rebar_xref_SUITE.erl b/test/rebar_xref_SUITE.erl
index 75d6786..09f73a7 100644
--- a/test/rebar_xref_SUITE.erl
+++ b/test/rebar_xref_SUITE.erl
@@ -150,7 +150,7 @@ get_module_body(mymod, AppName, IgnoreXref) ->
["-ignore_xref([{other2,1},{localfunc2,0},{fdeprecated,0}]).\n"
|| X <- [IgnoreXref], X =:= true],
"-behaviour(", AppName, "_behaviour1).\n", % 2 behaviours
- "-behaviour(", AppName, "_behaviour2).\n",
+ "-behavior(", AppName, "_behaviour2).\n",
"-deprecated({fdeprecated,0}).\n", % deprecated function
"bh1_a(A) -> localfunc1(bh1_a, A).\n", % behaviour functions
"bh1_b(A) -> localfunc1(bh1_b, A).\n",