diff --git a/priv/shell-completion/bash/rebar b/priv/shell-completion/bash/rebar index 005325d..968287c 100644 --- a/priv/shell-completion/bash/rebar +++ b/priv/shell-completion/bash/rebar @@ -9,10 +9,11 @@ _rebar() sopts="-h -c -v -V -f -j" lopts=" --help --commands --verbose --force --jobs= --version" cmdsnvars="check-deps clean compile create create-app create-node ct \ - doc delete-deps escriptize eunit get-deps generate generate-upgrade \ - help list-deps list-templates update-deps version xref overlay \ - apps= case= force=1 jobs= suites= verbose=1 appid= previous_release= \ - nodeid= root_dir= skip_deps=true skip_apps= template= template_dir=" + doc delete-deps escriptize eunit eunit-compile get-deps generate \ + generate-upgrade help list-deps list-templates update-deps version \ + xref overlay apps= case= force=1 jobs= suites= verbose=1 appid= \ + previous_release= nodeid= root_dir= skip_deps=true skip_apps= \ + template= template_dir=" if [[ ${cur} == --* ]] ; then COMPREPLY=( $(compgen -W "${lopts}" -- ${cur}) ) diff --git a/src/rebar.erl b/src/rebar.erl index 21e662b..54e27b6 100644 --- a/src/rebar.erl +++ b/src/rebar.erl @@ -298,6 +298,7 @@ generate-upgrade previous_release=path Build an upgrade package generate-appups previous_release=path Generate appup files eunit [suites=foo] Run eunit [test/foo_tests.erl] tests +eunit-compile Compile sources for EUnit run ct [suites=] [case=] Run common_test suites xref Run cross reference analysis @@ -361,10 +362,9 @@ filter_flags(Config, [Item | Rest], Commands) -> command_names() -> ["check-deps", "clean", "compile", "create", "create-app", "create-node", - "ct", "delete-deps", "doc", "eunit", "generate", "generate-appups", - "generate-upgrade", "get-deps", "help", "list-deps", "list-templates", - "update-deps", "overlay", "shell", "version", "xref"]. - + "ct", "delete-deps", "doc", "eunit", "eunit-compile", "generate", + "generate-appups", "generate-upgrade", "get-deps", "help", "list-deps", + "list-templates", "update-deps", "overlay", "shell", "version", "xref"]. unabbreviate_command_names([]) -> []; diff --git a/src/rebar_eunit.erl b/src/rebar_eunit.erl index 32b39c1..b1e061b 100644 --- a/src/rebar_eunit.erl +++ b/src/rebar_eunit.erl @@ -54,7 +54,8 @@ -module(rebar_eunit). -export([eunit/2, - clean/2]). + clean/2, + 'eunit-compile'/2]). -include("rebar.hrl"). @@ -65,62 +66,11 @@ %% =================================================================== eunit(Config, _AppFile) -> - %% Make sure ?EUNIT_DIR/ and ebin/ directory exists (append dummy module) - ok = filelib:ensure_dir(filename:join(eunit_dir(), "dummy")), - ok = filelib:ensure_dir(filename:join(ebin_dir(), "dummy")), + ok = ensure_dirs(), + %% Save code path + CodePath = setup_code_path(), - %% Setup code path prior to compilation so that parse_transforms - %% and the like work properly. Also, be sure to add ebin_dir() - %% to the END of the code path so that we don't have to jump - %% through hoops to access the .app file - CodePath = code:get_path(), - true = code:add_patha(eunit_dir()), - true = code:add_pathz(ebin_dir()), - - %% Obtain all the test modules for inclusion in the compile stage. - %% Notice: this could also be achieved with the following - %% rebar.config option: {eunit_compile_opts, [{src_dirs, ["test"]}]} - TestErls = rebar_utils:find_files("test", ".*\\.erl\$"), - - %% Copy source files to eunit dir for cover in case they are not directly - %% in src but in a subdirectory of src. Cover only looks in cwd and ../src - %% for source files. Also copy files from src_dirs. - ErlOpts = rebar_utils:erl_opts(Config), - - SrcDirs = rebar_utils:src_dirs(proplists:append_values(src_dirs, ErlOpts)), - SrcErls = lists:foldl( - fun(Dir, Acc) -> - Files = rebar_utils:find_files(Dir, ".*\\.erl\$"), - lists:append(Acc, Files) - end, [], SrcDirs), - - %% If it is not the first time rebar eunit is executed, there will be source - %% files already present in ?EUNIT_DIR. Since some SCMs (like Perforce) set - %% the source files as being read only (unless they are checked out), we - %% need to be sure that the files already present in ?EUNIT_DIR are writable - %% before doing the copy. This is done here by removing any file that was - %% already present before calling rebar_file_utils:cp_r. - - %% Get the full path to a file that was previously copied in ?EUNIT_DIR - ToCleanUp = fun(F, Acc) -> - F2 = filename:basename(F), - F3 = filename:join([?EUNIT_DIR, F2]), - case filelib:is_regular(F3) of - true -> [F3|Acc]; - false -> Acc - end - end, - - ok = rebar_file_utils:delete_each(lists:foldl(ToCleanUp, [], TestErls)), - ok = rebar_file_utils:delete_each(lists:foldl(ToCleanUp, [], SrcErls)), - - ok = rebar_file_utils:cp_r(SrcErls ++ TestErls, ?EUNIT_DIR), - - %% Compile erlang code to ?EUNIT_DIR, using a tweaked config - %% with appropriate defines for eunit, and include all the test modules - %% as well. - ok = rebar_erlc_compiler:doterl_compile(eunit_config(Config), - ?EUNIT_DIR, TestErls), + {ok, SrcErls} = eunit_compile(Config), %% Build a list of all the .beams in ?EUNIT_DIR -- use this for %% cover and eunit testing. Normally you can just tell cover @@ -171,10 +121,81 @@ eunit(Config, _AppFile) -> clean(_Config, _File) -> rebar_file_utils:rm_rf(?EUNIT_DIR). +'eunit-compile'(Config, _File) -> + ok = ensure_dirs(), + %% Save code path + CodePath = setup_code_path(), + {ok, _SrcErls} = eunit_compile(Config), + %% Restore code path + true = code:set_path(CodePath), + ok. + %% =================================================================== %% Internal functions %% =================================================================== +eunit_compile(Config) -> + %% Obtain all the test modules for inclusion in the compile stage. + %% Notice: this could also be achieved with the following + %% rebar.config option: {eunit_compile_opts, [{src_dirs, ["test"]}]} + TestErls = rebar_utils:find_files("test", ".*\\.erl\$"), + + %% Copy source files to eunit dir for cover in case they are not directly + %% in src but in a subdirectory of src. Cover only looks in cwd and ../src + %% for source files. Also copy files from src_dirs. + ErlOpts = rebar_utils:erl_opts(Config), + + SrcDirs = rebar_utils:src_dirs(proplists:append_values(src_dirs, ErlOpts)), + SrcErls = lists:foldl( + fun(Dir, Acc) -> + Files = rebar_utils:find_files(Dir, ".*\\.erl\$"), + lists:append(Acc, Files) + end, [], SrcDirs), + + %% If it is not the first time rebar eunit is executed, there will be source + %% files already present in ?EUNIT_DIR. Since some SCMs (like Perforce) set + %% the source files as being read only (unless they are checked out), we + %% need to be sure that the files already present in ?EUNIT_DIR are writable + %% before doing the copy. This is done here by removing any file that was + %% already present before calling rebar_file_utils:cp_r. + + %% Get the full path to a file that was previously copied in ?EUNIT_DIR + ToCleanUp = fun(F, Acc) -> + F2 = filename:basename(F), + F3 = filename:join([?EUNIT_DIR, F2]), + case filelib:is_regular(F3) of + true -> [F3|Acc]; + false -> Acc + end + end, + + ok = rebar_file_utils:delete_each(lists:foldl(ToCleanUp, [], TestErls)), + ok = rebar_file_utils:delete_each(lists:foldl(ToCleanUp, [], SrcErls)), + + ok = rebar_file_utils:cp_r(SrcErls ++ TestErls, ?EUNIT_DIR), + + %% Compile erlang code to ?EUNIT_DIR, using a tweaked config + %% with appropriate defines for eunit, and include all the test modules + %% as well. + ok = rebar_erlc_compiler:doterl_compile(eunit_config(Config), + ?EUNIT_DIR, TestErls), + {ok, SrcErls}. + +ensure_dirs() -> + %% Make sure ?EUNIT_DIR/ and ebin/ directory exists (append dummy module) + ok = filelib:ensure_dir(filename:join(eunit_dir(), "dummy")), + ok = filelib:ensure_dir(filename:join(ebin_dir(), "dummy")). + +setup_code_path() -> + %% Setup code path prior to compilation so that parse_transforms + %% and the like work properly. Also, be sure to add ebin_dir() + %% to the END of the code path so that we don't have to jump + %% through hoops to access the .app file + CodePath = code:get_path(), + true = code:add_patha(eunit_dir()), + true = code:add_pathz(ebin_dir()), + CodePath. + eunit_dir() -> filename:join(rebar_utils:get_cwd(), ?EUNIT_DIR).