summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/rebar_base_compiler.erl43
-rw-r--r--src/rebar_erlc_compiler.erl17
-rw-r--r--src/rebar_file_utils.erl35
-rw-r--r--src/rebar_prv_common_test.erl25
-rw-r--r--src/rebar_prv_shell.erl32
-rw-r--r--src/rebar_utils.erl14
-rw-r--r--test/rebar_ct_SUITE.erl48
-rw-r--r--test/rebar_file_utils_SUITE.erl28
8 files changed, 194 insertions, 48 deletions
diff --git a/src/rebar_base_compiler.erl b/src/rebar_base_compiler.erl
index 31292af..6b8c7ca 100644
--- a/src/rebar_base_compiler.erl
+++ b/src/rebar_base_compiler.erl
@@ -32,7 +32,11 @@
run/7,
run/8,
ok_tuple/2,
- error_tuple/4]).
+ error_tuple/4,
+ format_error_source/2]).
+
+-define(DEFAULT_COMPILER_SOURCE_FORMAT, relative).
+
%% ===================================================================
%% Public API
@@ -76,6 +80,28 @@ error_tuple(Source, Es, Ws, Opts) ->
{error, format_errors(Source, Es),
format_warnings(Source, Ws, Opts)}.
+format_error_source(Path, Opts) ->
+ Type = case rebar_opts:get(Opts, compiler_source_format,
+ ?DEFAULT_COMPILER_SOURCE_FORMAT) of
+ V when V == absolute; V == relative; V == build ->
+ V;
+ Other ->
+ ?WARN("Invalid argument ~p for compiler_source_format - "
+ "assuming ~s~n", [Other, ?DEFAULT_COMPILER_SOURCE_FORMAT]),
+ ?DEFAULT_COMPILER_SOURCE_FORMAT
+ end,
+ case Type of
+ absolute -> resolve_linked_source(Path);
+ build -> Path;
+ relative ->
+ Cwd = rebar_dir:get_cwd(),
+ rebar_dir:make_relative_path(resolve_linked_source(Path), Cwd)
+ end.
+
+resolve_linked_source(Src) ->
+ {Dir, Base} = rebar_file_utils:split_dirname(Src),
+ filename:join(rebar_file_utils:resolve_link(Dir), Base).
+
%% ===================================================================
%% Internal functions
%% ===================================================================
@@ -114,7 +140,8 @@ compile_each([Source | Rest], Config, CompileFn) ->
skipped ->
?DEBUG("~sSkipped ~s", [rebar_utils:indent(1), filename:basename(Source)]);
Error ->
- ?ERROR("Compiling ~s failed", [Source]),
+ NewSource = format_error_source(Source, Config),
+ ?ERROR("Compiling ~s failed", [NewSource]),
maybe_report(Error),
?DEBUG("Compilation failed: ~p", [Error]),
?FAIL
@@ -153,12 +180,12 @@ format_errors(_MainSource, Extra, Errors) ->
end
|| {Source, Descs} <- Errors].
-format_error(AbsSource, Extra, {{Line, Column}, Mod, Desc}) ->
+format_error(Source, Extra, {{Line, Column}, Mod, Desc}) ->
ErrorDesc = Mod:format_error(Desc),
- ?FMT("~s:~w:~w: ~s~s~n", [AbsSource, Line, Column, Extra, ErrorDesc]);
-format_error(AbsSource, Extra, {Line, Mod, Desc}) ->
+ ?FMT("~s:~w:~w: ~s~s~n", [Source, Line, Column, Extra, ErrorDesc]);
+format_error(Source, Extra, {Line, Mod, Desc}) ->
ErrorDesc = Mod:format_error(Desc),
- ?FMT("~s:~w: ~s~s~n", [AbsSource, Line, Extra, ErrorDesc]);
-format_error(AbsSource, Extra, {Mod, Desc}) ->
+ ?FMT("~s:~w: ~s~s~n", [Source, Line, Extra, ErrorDesc]);
+format_error(Source, Extra, {Mod, Desc}) ->
ErrorDesc = Mod:format_error(Desc),
- ?FMT("~s: ~s~s~n", [AbsSource, Extra, ErrorDesc]).
+ ?FMT("~s: ~s~s~n", [Source, Extra, ErrorDesc]).
diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl
index 2a9f310..bdd1868 100644
--- a/src/rebar_erlc_compiler.erl
+++ b/src/rebar_erlc_compiler.erl
@@ -54,7 +54,6 @@
-define(DEFAULT_OUTDIR, "ebin").
-define(RE_PREFIX, "^[^._]").
-
%% ===================================================================
%% Public API
%% ===================================================================
@@ -507,7 +506,7 @@ expand_file_names(Files, Dirs) ->
-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) ->
+internal_erl_compile(Opts, Dir, Module, OutDir, ErlOpts) ->
Target = target_base(OutDir, Module) ++ ".beam",
ok = filelib:ensure_dir(Target),
AllOpts = [{outdir, filename:dirname(Target)}] ++ ErlOpts ++
@@ -516,11 +515,21 @@ internal_erl_compile(_Opts, Dir, Module, OutDir, ErlOpts) ->
{ok, _Mod} ->
ok;
{ok, _Mod, Ws} ->
- rebar_base_compiler:ok_tuple(Module, Ws);
+ FormattedWs = format_error_sources(Ws, Opts),
+ rebar_base_compiler:ok_tuple(Module, FormattedWs);
{error, Es, Ws} ->
- rebar_base_compiler:error_tuple(Module, Es, Ws, AllOpts)
+ error_tuple(Module, Es, Ws, AllOpts, Opts)
end.
+error_tuple(Module, Es, Ws, AllOpts, Opts) ->
+ FormattedEs = format_error_sources(Es, Opts),
+ FormattedWs = format_error_sources(Ws, Opts),
+ rebar_base_compiler:error_tuple(Module, FormattedEs, FormattedWs, AllOpts).
+
+format_error_sources(Es, Opts) ->
+ [{rebar_base_compiler:format_error_source(Src, Opts), Desc}
+ || {Src, Desc} <- Es].
+
target_base(OutDir, Source) ->
filename:join(OutDir, filename:basename(Source, ".erl")).
diff --git a/src/rebar_file_utils.erl b/src/rebar_file_utils.erl
index 0f84520..667be62 100644
--- a/src/rebar_file_utils.erl
+++ b/src/rebar_file_utils.erl
@@ -27,6 +27,7 @@
-module(rebar_file_utils).
-export([try_consult/1,
+ consult_config/2,
format_error/1,
symlink_or_copy/2,
rm_rf/1,
@@ -39,7 +40,9 @@
reset_dir/1,
touch/1,
path_from_ancestor/2,
- canonical_path/1]).
+ canonical_path/1,
+ resolve_link/1,
+ split_dirname/1]).
-include("rebar.hrl").
@@ -61,6 +64,20 @@ try_consult(File) ->
throw(?PRV_ERROR({bad_term_file, File, Reason}))
end.
+-spec consult_config(rebar_state:t(), string()) -> [[tuple()]].
+consult_config(State, Filename) ->
+ Fullpath = filename:join(rebar_dir:root_dir(State), Filename),
+ ?DEBUG("Loading configuration from ~p", [Fullpath]),
+ Config = case try_consult(Fullpath) of
+ [T] -> T;
+ [] -> []
+ end,
+ SubConfigs = [consult_config(State, Entry ++ ".config") ||
+ Entry <- Config, is_list(Entry)
+ ],
+
+ [Config | lists:merge(SubConfigs)].
+
format_error({bad_term_file, AppFile, Reason}) ->
io_lib:format("Error reading file ~s: ~s", [AppFile, file:format_error(Reason)]).
@@ -273,6 +290,22 @@ canonical_path([_|Acc], [".."|Rest]) -> canonical_path(Acc, Rest);
canonical_path([], [".."|Rest]) -> canonical_path([], Rest);
canonical_path(Acc, [Component|Rest]) -> canonical_path([Component|Acc], Rest).
+%% returns canonical target of path if path is a link, otherwise returns path
+-spec resolve_link(string()) -> string().
+
+resolve_link(Path) ->
+ case file:read_link(Path) of
+ {ok, Target} ->
+ canonical_path(filename:absname(Target, filename:dirname(Path)));
+ {error, _} -> Path
+ end.
+
+%% splits a path into dirname and basename
+-spec split_dirname(string()) -> {string(), string()}.
+
+split_dirname(Path) ->
+ {filename:dirname(Path), filename:basename(Path)}.
+
%% ===================================================================
%% Internal functions
%% ===================================================================
diff --git a/src/rebar_prv_common_test.erl b/src/rebar_prv_common_test.erl
index 5712fbf..fbd0e89 100644
--- a/src/rebar_prv_common_test.erl
+++ b/src/rebar_prv_common_test.erl
@@ -116,6 +116,7 @@ prepare_tests(State) ->
%% rebar.config test options
CfgOpts = cfgopts(State),
ProjectApps = rebar_state:project_apps(State),
+
%% prioritize tests to run first trying any command line specified
%% tests falling back to tests specified in the config file finally
%% running a default set if no other tests are present
@@ -215,6 +216,14 @@ add_hooks(Opts, State) ->
select_tests(_, _, {error, _} = Error, _) -> Error;
select_tests(_, _, _, {error, _} = Error) -> Error;
select_tests(State, ProjectApps, CmdOpts, CfgOpts) ->
+ %% set application env if sys_config argument is provided
+ SysConfigs = sys_config_list(CmdOpts, CfgOpts),
+ Configs = lists:flatmap(fun(Filename) ->
+ rebar_file_utils:consult_config(State, Filename)
+ end, SysConfigs),
+ [application:load(Application) || Config <- SysConfigs, {Application, _} <- Config],
+ rebar_utils:reread_config(Configs),
+
Merged = lists:ukeymerge(1,
lists:ukeysort(1, CmdOpts),
lists:ukeysort(1, CfgOpts)),
@@ -229,6 +238,17 @@ select_tests(State, ProjectApps, CmdOpts, CfgOpts) ->
end,
discover_tests(State, ProjectApps, Opts).
+sys_config_list(CmdOpts, CfgOpts) ->
+ CmdSysConfigs = split_string(proplists:get_value(sys_config, CmdOpts, "")),
+ case proplists:get_value(sys_config, CfgOpts, []) of
+ [H | _]=Configs when is_list(H) ->
+ Configs ++ CmdSysConfigs;
+ [] ->
+ CmdSysConfigs;
+ Configs ->
+ [Configs | CmdSysConfigs]
+ end.
+
discover_tests(State, ProjectApps, Opts) ->
case {proplists:get_value(suite, Opts), proplists:get_value(dir, Opts)} of
%% no dirs or suites defined, try using `$APP/test` and `$ROOT/test`
@@ -647,7 +667,8 @@ ct_opts(_State) ->
{verbose, $v, "verbose", boolean, help(verbose)},
{name, undefined, "name", atom, help(name)},
{sname, undefined, "sname", atom, help(sname)},
- {setcookie, undefined, "setcookie", atom, help(setcookie)}
+ {setcookie, undefined, "setcookie", atom, help(setcookie)},
+ {sys_config, undefined, "sys_config", string, help(sys_config)} %% comma-seperated list
].
help(dir) ->
@@ -662,6 +683,8 @@ help(label) ->
"Test label";
help(config) ->
"List of config files";
+help(sys_config) ->
+ "List of application config files";
help(allow_user_terms) ->
"Allow user defined config values in config files";
help(logdir) ->
diff --git a/src/rebar_prv_shell.erl b/src/rebar_prv_shell.erl
index a5457ad..2e6c296 100644
--- a/src/rebar_prv_shell.erl
+++ b/src/rebar_prv_shell.erl
@@ -111,7 +111,7 @@ shell(State) ->
%% Hack to fool the init process into thinking we have stopped and the normal
%% node start process can go on. Without it, init:get_status() always return
%% '{starting, started}' instead of '{started, started}'
- init ! {'EXIT', self(), normal},
+ init ! {'EXIT', self(), normal},
gen_server:enter_loop(rebar_agent, [], GenState, {local, rebar_agent}, hibernate).
info() ->
@@ -332,16 +332,7 @@ reread_config(State) ->
no_config ->
ok;
ConfigList ->
- try
- [application:set_env(Application, Key, Val)
- || Config <- ConfigList,
- {Application, Items} <- Config,
- {Key, Val} <- Items]
- catch _:_ ->
- ?ERROR("The configuration file submitted could not be read "
- "and will be ignored.", [])
- end,
- ok
+ rebar_utils:reread_config(ConfigList)
end.
boot_apps(Apps) ->
@@ -406,7 +397,7 @@ find_config(State) ->
no_value ->
no_config;
Filename when is_list(Filename) ->
- consult_config(State, Filename)
+ rebar_file_utils:consult_config(State, Filename)
end.
-spec first_value([Fun], State) -> no_value | Value when
@@ -414,7 +405,7 @@ find_config(State) ->
State :: rebar_state:t(),
Fun :: fun ((State) -> no_value | Value).
first_value([], _) -> no_value;
-first_value([Fun | Rest], State) ->
+first_value([Fun | Rest], State) ->
case Fun(State) of
no_value ->
first_value(Rest, State);
@@ -445,18 +436,3 @@ find_config_rebar(State) ->
find_config_relx(State) ->
debug_get_value(sys_config, rebar_state:get(State, relx, []), no_value,
"Found config from relx.").
-
--spec consult_config(rebar_state:t(), string()) -> [[tuple()]].
-consult_config(State, Filename) ->
- Fullpath = filename:join(rebar_dir:root_dir(State), Filename),
- ?DEBUG("Loading configuration from ~p", [Fullpath]),
- Config = case rebar_file_utils:try_consult(Fullpath) of
- [T] -> T;
- [] -> []
- end,
- SubConfigs = [consult_config(State, Entry ++ ".config") ||
- Entry <- Config, is_list(Entry)
- ],
-
- [Config | lists:merge(SubConfigs)].
-
diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl
index ce6996c..aa9e268 100644
--- a/src/rebar_utils.erl
+++ b/src/rebar_utils.erl
@@ -69,7 +69,8 @@
check_blacklisted_otp_versions/1,
info_useless/2,
list_dir/1,
- user_agent/0]).
+ user_agent/0,
+ reread_config/1]).
%% for internal use only
-export([otp_release/0]).
@@ -412,6 +413,17 @@ user_agent() ->
{ok, Vsn} = application:get_key(rebar, vsn),
?FMT("Rebar/~s (OTP/~s)", [Vsn, otp_release()]).
+reread_config(ConfigList) ->
+ try
+ [application:set_env(Application, Key, Val)
+ || Config <- ConfigList,
+ {Application, Items} <- Config,
+ {Key, Val} <- Items]
+ catch _:_ ->
+ ?ERROR("The configuration file submitted could not be read "
+ "and will be ignored.", [])
+ end.
+
%% ====================================================================
%% Internal functions
%% ====================================================================
diff --git a/test/rebar_ct_SUITE.erl b/test/rebar_ct_SUITE.erl
index e409c29..c10875b 100644
--- a/test/rebar_ct_SUITE.erl
+++ b/test/rebar_ct_SUITE.erl
@@ -41,6 +41,7 @@
cmd_scale_timetraps/1,
cmd_create_priv_dir/1,
cmd_include_dir/1,
+ cmd_sys_config/1,
cfg_opts/1,
cfg_arbitrary_opts/1,
cfg_test_spec/1,
@@ -51,6 +52,7 @@
misspecified_ct_compile_opts/1,
misspecified_ct_first_files/1]).
+-include_lib("eunit/include/eunit.hrl").
-include_lib("common_test/include/ct.hrl").
all() -> [{group, basic_app},
@@ -102,7 +104,8 @@ groups() -> [{basic_app, [], [basic_app_default_dirs,
cmd_multiply_timetraps,
cmd_scale_timetraps,
cmd_create_priv_dir,
- cmd_include_dir]},
+ cmd_include_dir,
+ cmd_sys_config]},
{cover, [], [cover_compiled]}].
init_per_group(basic_app, Config) ->
@@ -1020,7 +1023,41 @@ cmd_include_dir(Config) ->
CompileOpts = proplists:get_value(options, Info),
true = lists:member({i, "foo/bar/baz"}, CompileOpts),
true = lists:member({i, "qux"}, CompileOpts).
-
+
+cmd_sys_config(Config) ->
+ State = ?config(result, Config),
+ AppDir = ?config(apps, Config),
+ Name = ?config(name, Config),
+ AppName = list_to_atom(Name),
+
+ {ok, _} = rebar_prv_common_test:prepare_tests(State),
+ ?assertEqual(undefined, application:get_env(AppName, key)),
+
+ CfgFile = filename:join([AppDir, "config", "cfg_sys.config"]),
+ ok = filelib:ensure_dir(CfgFile),
+ ok = file:write_file(CfgFile, cfg_sys_config_file(AppName)),
+ RebarConfig = [{ct_opts, [{sys_config, CfgFile}]}],
+ {ok, State1} = rebar_test_utils:run_and_check(Config, RebarConfig, ["as", "test", "lock"], return),
+
+ {ok, _} = rebar_prv_common_test:prepare_tests(State1),
+ ?assertEqual({ok, cfg_value}, application:get_env(AppName, key)),
+
+ Providers = rebar_state:providers(State1),
+ Namespace = rebar_state:namespace(State1),
+ CommandProvider = providers:get_provider(ct, Providers, Namespace),
+ GetOptSpec = providers:opts(CommandProvider),
+
+ CmdFile = filename:join([AppDir, "config", "cmd_sys.config"]),
+ ok = filelib:ensure_dir(CmdFile),
+ ok = file:write_file(CmdFile, cmd_sys_config_file(AppName)),
+ {ok, GetOptResult} = getopt:parse(GetOptSpec, ["--sys_config="++CmdFile]),
+ State2 = rebar_state:command_parsed_args(State1, GetOptResult),
+
+ {ok, _} = rebar_prv_common_test:prepare_tests(State2),
+
+ ?assertEqual({ok ,cmd_value}, application:get_env(AppName, key)).
+
+
cfg_opts(Config) ->
C = rebar_test_utils:init_rebar_state(Config, "ct_cfg_opts_"),
@@ -1181,10 +1218,15 @@ misspecified_ct_first_files(Config) ->
{badconfig, {"Value `~p' of option `~p' must be a list", {some_file, ct_first_files}}} = Error.
-
%% helper for generating test data
test_suite(Name) ->
io_lib:format("-module(~ts_SUITE).\n"
"-compile(export_all).\n"
"all() -> [some_test].\n"
"some_test(_) -> ok.\n", [Name]).
+
+cmd_sys_config_file(AppName) ->
+ io_lib:format("[{~s, [{key, cmd_value}]}].", [AppName]).
+
+cfg_sys_config_file(AppName) ->
+ io_lib:format("[{~s, [{key, cfg_value}]}].", [AppName]).
diff --git a/test/rebar_file_utils_SUITE.erl b/test/rebar_file_utils_SUITE.erl
index c1f85b3..a44a06d 100644
--- a/test/rebar_file_utils_SUITE.erl
+++ b/test/rebar_file_utils_SUITE.erl
@@ -12,7 +12,9 @@
reset_empty_dir/1,
reset_dir/1,
path_from_ancestor/1,
- canonical_path/1]).
+ canonical_path/1,
+ resolve_link/1,
+ split_dirname/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -22,7 +24,10 @@
all() ->
[{group, tmpdir},
{group, reset_dir},
- path_from_ancestor, canonical_path].
+ path_from_ancestor,
+ canonical_path,
+ resolve_link,
+ split_dirname].
groups() ->
[{tmpdir, [], [raw_tmpdir, empty_tmpdir, simple_tmpdir, multi_tmpdir]},
@@ -111,3 +116,22 @@ canonical_path(_Config) ->
?assertEqual(Root ++ "foo", rebar_file_utils:canonical_path("/foo/./.")),
?assertEqual(filename:nativename(Root ++ "foo/bar"),
rebar_file_utils:canonical_path("/foo/./bar")).
+
+resolve_link(_Config) ->
+ TmpDir = rebar_file_utils:system_tmpdir(
+ ["rebar_file_utils_SUITE", "resolve_link"]),
+ Link = filename:join(TmpDir, "link"),
+ Target = filename:join(TmpDir, "link-target"),
+ ec_file:remove(TmpDir, [recursive]),
+ ok = filelib:ensure_dir(Target),
+ ok = file:write_file(Target, <<>>),
+ ok = file:make_symlink(Target, Link),
+ ?assertEqual(Target, rebar_file_utils:resolve_link(Link)).
+
+split_dirname(_Config) ->
+ ?assertEqual({".", ""}, rebar_file_utils:split_dirname("")),
+ ?assertEqual({"/", ""}, rebar_file_utils:split_dirname("/")),
+ ?assertEqual({"/", "foo"}, rebar_file_utils:split_dirname("/foo")),
+ ?assertEqual({".", "foo"}, rebar_file_utils:split_dirname("foo")),
+ ?assertEqual({"/foo", "bar"}, rebar_file_utils:split_dirname("/foo/bar")),
+ ?assertEqual({"foo", "bar"}, rebar_file_utils:split_dirname("foo/bar")).