diff options
-rw-r--r-- | rebar.config.sample | 3 | ||||
-rw-r--r-- | src/rebar_app_utils.erl | 11 | ||||
-rw-r--r-- | src/rebar_prv_cover.erl | 41 | ||||
-rw-r--r-- | test/rebar_cover_SUITE.erl | 48 |
4 files changed, 89 insertions, 14 deletions
diff --git a/rebar.config.sample b/rebar.config.sample index 54f32b2..be3da71 100644 --- a/rebar.config.sample +++ b/rebar.config.sample @@ -57,6 +57,9 @@ %% is `false' {cover_enabled, false}. +%% Modules to exclude from cover +{cover_excl_mods, []}. + %% Options to pass to cover provider {cover_opts, [verbose]}. diff --git a/src/rebar_app_utils.erl b/src/rebar_app_utils.erl index 50c6314..847b0a5 100644 --- a/src/rebar_app_utils.erl +++ b/src/rebar_app_utils.erl @@ -190,7 +190,7 @@ update_source(AppInfo, {pkg, PkgName, PkgVsn, Hash}, State) -> %% store the expected hash for the dependency Hash1 = case Hash of undefined -> % unknown, define the hash since we know the dep - rebar_packages:registry_checksum({pkg, PkgName1, PkgVsn1, Hash}, State); + fetch_checksum(PkgName1, PkgVsn1, Hash, State); _ -> % keep as is Hash end, @@ -203,6 +203,15 @@ update_source(AppInfo, {pkg, PkgName, PkgVsn, Hash}, State) -> update_source(AppInfo, Source, _State) -> rebar_app_info:source(AppInfo, Source). +fetch_checksum(PkgName, PkgVsn, Hash, State) -> + try + rebar_packages:registry_checksum({pkg, PkgName, PkgVsn, Hash}, State) + catch + _:_ -> + ?INFO("Package ~s-~s not found. Fetching registry updates and trying again...", [PkgName, PkgVsn]), + {ok, _} = rebar_prv_update:do(State), + rebar_packages:registry_checksum({pkg, PkgName, PkgVsn, Hash}, State) + end. format_error({missing_package, Package}) -> io_lib:format("Package not found in registry: ~s", [Package]); diff --git a/src/rebar_prv_cover.erl b/src/rebar_prv_cover.erl index 464967b..401c331 100644 --- a/src/rebar_prv_cover.erl +++ b/src/rebar_prv_cover.erl @@ -303,23 +303,44 @@ cover_compile(State, Dirs) -> {ok, CoverPid} = start_cover(), %% redirect cover output true = redirect_cover_output(State, CoverPid), + ExclMods = rebar_state:get(State, cover_excl_mods, []), + lists:foreach(fun(Dir) -> - ?DEBUG("cover compiling ~p", [Dir]), - case catch(cover:compile_beam_directory(Dir)) of + case file:list_dir(Dir) of + {ok, Files} -> + ?DEBUG("cover compiling ~p", [Dir]), + [cover_compile_file(filename:join(Dir, File)) + || File <- Files, + filename:extension(File) == ".beam", + not is_ignored(Dir, File, ExclMods)], + ok; {error, eacces} -> ?WARN("Directory ~p not readable, modules will not be included in coverage", [Dir]); {error, enoent} -> ?WARN("Directory ~p not found", [Dir]); - {'EXIT', {Reason, _}} -> - ?WARN("Cover compilation for directory ~p failed: ~p", [Dir, Reason]); - Results -> - %% print any warnings about modules that failed to cover compile - lists:foreach(fun print_cover_warnings/1, lists:flatten(Results)) + {error, Reason} -> + ?WARN("Directory ~p error ~p", [Dir, Reason]) end end, Dirs), rebar_utils:cleanup_code_path(rebar_state:code_paths(State, default)), ok. +is_ignored(Dir, File, ExclMods) -> + Ignored = lists:any(fun(Excl) -> + File =:= atom_to_list(Excl) ++ ".beam" + end, + ExclMods), + Ignored andalso ?DEBUG("cover ignoring ~p ~p", [Dir, File]), + Ignored. + +cover_compile_file(FileName) -> + case catch(cover:compile_beam(FileName)) of + {error, Reason} -> + ?WARN("Cover compilation failed: ~p", [Reason]); + {ok, _} -> + ok + end. + app_dirs(Apps) -> lists:foldl(fun app_ebin_dirs/2, [], Apps). @@ -349,16 +370,14 @@ redirect_cover_output(State, CoverPid) -> [append]), group_leader(F, CoverPid). -print_cover_warnings({ok, _}) -> ok; -print_cover_warnings({error, Error}) -> - ?WARN("Cover compilation failed: ~p", [Error]). - write_coverdata(State, Task) -> DataDir = cover_dir(State), ok = filelib:ensure_dir(filename:join([DataDir, "dummy.log"])), ExportFile = filename:join([DataDir, atom_to_list(Task) ++ ".coverdata"]), case cover:export(ExportFile) of ok -> + %% dump accumulated coverdata after writing + ok = cover:reset(), ?DEBUG("Cover data written to ~p.", [ExportFile]); {error, Reason} -> ?WARN("Cover data export failed: ~p", [Reason]) diff --git a/test/rebar_cover_SUITE.erl b/test/rebar_cover_SUITE.erl index 841e29f..4192f4a 100644 --- a/test/rebar_cover_SUITE.erl +++ b/test/rebar_cover_SUITE.erl @@ -12,7 +12,9 @@ root_extra_src_dirs/1, index_written/1, flag_verbose/1, - config_verbose/1]). + config_verbose/1, + excl_mods/1, + coverdata_is_reset_on_write/1]). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -35,7 +37,8 @@ all() -> basic_extra_src_dirs, release_extra_src_dirs, root_extra_src_dirs, index_written, - flag_verbose, config_verbose]. + flag_verbose, config_verbose, + excl_mods, coverdata_is_reset_on_write]. flag_coverdata_written(Config) -> AppDir = ?config(apps, Config), @@ -206,3 +209,44 @@ config_verbose(Config) -> {ok, [{app, Name}]}), true = filelib:is_file(filename:join([AppDir, "_build", "test", "cover", "index.html"])). + +excl_mods(Config) -> + AppDir = ?config(apps, Config), + + Name1 = rebar_test_utils:create_random_name("relapp1_"), + Vsn1 = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(filename:join([AppDir, "apps", Name1]), Name1, Vsn1, [kernel, stdlib]), + + Name2 = rebar_test_utils:create_random_name("relapp2_"), + Vsn2 = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(filename:join([AppDir, "apps", Name2]), Name2, Vsn2, [kernel, stdlib]), + + Mod1 = list_to_atom(Name1), + Mod2 = list_to_atom(Name2), + RebarConfig = [{erl_opts, [{d, some_define}]}, + {cover_excl_mods, [Mod2]}], + + rebar_test_utils:run_and_check(Config, + RebarConfig, + ["eunit", "--cover"], + {ok, [{app, Name1}, {app, Name2}]}), + + {file, _} = cover:is_compiled(Mod1), + false = cover:is_compiled(Mod2). + +coverdata_is_reset_on_write(Config) -> + AppDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("coverdata_is_reset_on_write_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_eunit_app(AppDir, Name, Vsn, [kernel, stdlib]), + + RebarConfig = [{erl_opts, [{d, some_define}]}, {cover_enabled, true}], + rebar_test_utils:run_and_check(Config, + RebarConfig, + ["eunit"], + {ok, [{app, Name}]}), + + Res = lists:map(fun(M) -> cover:analyse(M) end, cover:modules()), + Ok = lists:foldl(fun({ok, R}, Acc) -> R ++ Acc end, [], Res), + [] = lists:filter(fun({_, {0,_}}) -> false; (_) -> true end, Ok). |