mirror of
https://github.com/correl/rebar.git
synced 2024-11-23 19:19:54 +00:00
Provide package support for eunit; build_plt now includes listed applications; begin including -spec annotations
This commit is contained in:
parent
30a3816c86
commit
788bd3df72
6 changed files with 85 additions and 49 deletions
|
@ -188,7 +188,7 @@ process_dir(Dir, ParentConfig, Commands) ->
|
|||
|
||||
%% Get the list of modules for "any dir". This is a catch-all list of modules
|
||||
%% that are processed in addion to modules associated with this directory
|
||||
%5 type. These any_dir modules are processed FIRST.
|
||||
%% type. These any_dir modules are processed FIRST.
|
||||
{ok, AnyDirModules} = application:get_env(rebar, any_dir_modules),
|
||||
Modules = AnyDirModules ++ DirModules,
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
%% @doc rebar_dialyzer supports the following commands:
|
||||
%% <ul>
|
||||
%% <li>analyze (essentially "dialyzer -r ebin")</li>
|
||||
%% <li>build_plt (essentially "dialyzer --build_plt -r &rt;stdlib_lib< &rt;kernel_lib< &rt;mnesia_lib<")</li>
|
||||
%% <li>build_plt (essentially "dialyzer --build_plt -r <app_dirs>")</li>
|
||||
%% <li>check_plt (essentially "dialyzer --check_plt")</li>
|
||||
%% </ul>
|
||||
%% A single option <code>plt</code> can be presented in the <code>dialyzer_opts</code>
|
||||
|
@ -59,8 +59,8 @@
|
|||
%% @doc Perform static analysis on the contents of the ebin directory.
|
||||
%% @spec analyze(Config::#config{}, File::string()) -> ok.
|
||||
-spec(analyze(Config::#config{}, File::string()) -> ok).
|
||||
analyze(Config, _File) ->
|
||||
Plt = plt_path(Config),
|
||||
analyze(Config, File) ->
|
||||
Plt = plt_path(Config, File),
|
||||
case dialyzer:plt_info(Plt) of
|
||||
{ok, _} ->
|
||||
try dialyzer:run([{files_rec, ["ebin"]}, {init_plt, Plt}]) of
|
||||
|
@ -82,17 +82,14 @@ analyze(Config, _File) ->
|
|||
%% @doc Build the PLT.
|
||||
%% @spec build_plt(Config::#config{}, File::string()) -> ok
|
||||
-spec(build_plt(Config::#config{}, File::string()) -> ok).
|
||||
build_plt(Config, _File) ->
|
||||
Plt = plt_path(Config),
|
||||
build_plt(Config, File) ->
|
||||
Plt = plt_path(Config, File),
|
||||
|
||||
{ok, _AppName, AppData} = rebar_app_utils:load_app_file(File),
|
||||
Apps = proplists:get_value(applications, AppData),
|
||||
|
||||
%% This is the recommended minimal PLT for OTP
|
||||
%% (see http://www.erlang.org/doc/apps/dialyzer/dialyzer_chapter.html#id2256857).
|
||||
Warnings = dialyzer:run([{analysis_type, plt_build},
|
||||
{files_rec, [
|
||||
filename:join(code:lib_dir(stdlib), "ebin"),
|
||||
filename:join(code:lib_dir(kernel), "ebin"),
|
||||
filename:join(code:lib_dir(mnesia), "ebin")
|
||||
]},
|
||||
{files_rec, app_dirs(Apps)},
|
||||
{output_plt, Plt}]),
|
||||
case Warnings of
|
||||
[] ->
|
||||
|
@ -105,8 +102,8 @@ build_plt(Config, _File) ->
|
|||
%% @doc Check whether the PLT is up-to-date (rebuilding it if not).
|
||||
%% @spec check_plt(Config::#config{}, File::string()) -> ok
|
||||
-spec(check_plt(Config::#config{}, File::string()) -> ok).
|
||||
check_plt(Config, _File) ->
|
||||
Plt = plt_path(Config),
|
||||
check_plt(Config, File) ->
|
||||
Plt = plt_path(Config, File),
|
||||
try dialyzer:run([{analysis_type, plt_check}, {init_plt, Plt}]) of
|
||||
[] ->
|
||||
?CONSOLE("The PLT ~s is up-to-date~n", [Plt]);
|
||||
|
@ -123,8 +120,15 @@ check_plt(Config, _File) ->
|
|||
%% Internal functions
|
||||
%% ===================================================================
|
||||
|
||||
%% @doc Obtain the library paths for the supplied applications.
|
||||
%% @spec app_dirs(Apps::[atom()]) -> [string()]
|
||||
-spec(app_dirs(Apps::[atom()]) -> [string()]).
|
||||
app_dirs(Apps) ->
|
||||
[filename:join(Path, "ebin") ||
|
||||
Path <- lists:map(fun(App) -> code:lib_dir(App) end, Apps), erlang:is_list(Path)].
|
||||
|
||||
%% @doc Render the warnings on the console.
|
||||
%% @spec output_warnings(Warnings::[warning()]) -> void()
|
||||
%% @spec output_warnings(Warnings::[warning()]) -> none()
|
||||
-spec(output_warnings(Warnings::[warning()]) -> none()).
|
||||
output_warnings(Warnings) ->
|
||||
lists:foreach(fun(Warning) ->
|
||||
|
@ -133,13 +137,14 @@ output_warnings(Warnings) ->
|
|||
|
||||
%% @doc If the plt option is present in rebar.config return its value, otherwise
|
||||
%% return $HOME/.dialyzer_plt.
|
||||
%% @spec plt_path(Config::#config{}) -> string()
|
||||
-spec(plt_path(Config::#config{}) -> string()).
|
||||
plt_path(Config) ->
|
||||
%% @spec plt_path(Config::#config{}, File::string()) -> string()
|
||||
-spec(plt_path(Config::#config{}, File::string()) -> string()).
|
||||
plt_path(Config, File) ->
|
||||
{ok, AppName, _AppData} = rebar_app_utils:load_app_file(File),
|
||||
DialyzerOpts = rebar_config:get(Config, dialyzer_opts, []),
|
||||
case proplists:get_value(plt, DialyzerOpts) of
|
||||
undefined ->
|
||||
filename:join(os:getenv("HOME"), ".dialyzer_plt");
|
||||
filename:join(os:getenv("HOME"), "." ++ atom_to_list(AppName) ++ "_dialyzer_plt");
|
||||
Plt ->
|
||||
Plt
|
||||
end.
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
%%
|
||||
%% rebar: Erlang Build Tools
|
||||
%%
|
||||
%% Copyright (c) 2009 Dave Smith (dizzyd@dizzyd.com)
|
||||
%% Copyright (c) 2009, 2010 Dave Smith (dizzyd@dizzyd.com)
|
||||
%%
|
||||
%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -38,12 +38,14 @@
|
|||
%% Public API
|
||||
%% ===================================================================
|
||||
|
||||
-spec compile(Config::#config{}, AppFile::string()) -> 'ok'.
|
||||
compile(Config, _AppFile) ->
|
||||
doterl_compile(Config, "ebin"),
|
||||
rebar_base_compiler:run(Config, rebar_config:get_list(Config, mib_first_files, []),
|
||||
"mibs", ".mib", "priv/mibs", ".bin",
|
||||
fun compile_mib/3).
|
||||
|
||||
-spec clean(Config::#config{}, AppFile::string()) -> 'ok'.
|
||||
clean(_Config, _AppFile) ->
|
||||
%% TODO: This would be more portable if it used Erlang to traverse
|
||||
%% the dir structure and delete each file; however it would also
|
||||
|
@ -64,26 +66,33 @@ clean(_Config, _AppFile) ->
|
|||
%% .erl Compilation API (externally used by only eunit)
|
||||
%% ===================================================================
|
||||
|
||||
-spec doterl_compile(Config::#config{}, OutDir::string()) -> 'ok'.
|
||||
doterl_compile(Config, OutDir) ->
|
||||
doterl_compile(Config, OutDir, []).
|
||||
|
||||
doterl_compile(Config, OutDir, MoreSources) ->
|
||||
FirstErls = rebar_config:get_list(Config, erl_first_files, []),
|
||||
RestErls = [Source || Source <- rebar_utils:find_files("src", ".*\\.erl\$") ++ MoreSources,
|
||||
ErlOpts = rebar_config:get(Config, erl_opts, []),
|
||||
%% Support the src_dirs option allowing multiple directories to
|
||||
%% contain erlang source. This might be used, for example, should eunit tests be
|
||||
%% separated from the core application source.
|
||||
SrcDirs = src_dirs(proplists:append_values(src_dirs, ErlOpts)),
|
||||
RestErls = [Source || Source <- gather_src(SrcDirs, []) ++ MoreSources,
|
||||
lists:member(Source, FirstErls) == false],
|
||||
rebar_base_compiler:run(Config, FirstErls, RestErls,
|
||||
fun(S, C) -> internal_erl_compile(S, C, OutDir) end).
|
||||
|
||||
|
||||
|
||||
%% ===================================================================
|
||||
%% Internal functions
|
||||
%% ===================================================================
|
||||
|
||||
-spec include_path(Source::string(), Config::#config{}) -> [string()].
|
||||
include_path(Source, Config) ->
|
||||
ErlOpts = rebar_config:get(Config, erl_opts, []),
|
||||
[filename:dirname(Source)] ++ proplists:get_all_values(i, ErlOpts).
|
||||
|
||||
-spec inspect(Source::string(), IncludePath::[string()]) -> {string(), [string()]}.
|
||||
inspect(Source, IncludePath) ->
|
||||
ModuleDefault = filename:basename(Source, ".erl"),
|
||||
case epp:open(Source, IncludePath) of
|
||||
|
@ -94,9 +103,10 @@ inspect(Source, IncludePath) ->
|
|||
{ModuleDefault, []}
|
||||
end.
|
||||
|
||||
-spec inspect_epp(Epp::pid(), Module::string(), Includes::[string()]) -> {string(), [string()]}.
|
||||
inspect_epp(Epp, Module, Includes) ->
|
||||
case epp:parse_erl_form(Epp) of
|
||||
{ok, {attribute, _, module, ActualModule}} when is_list(ActualModule) ->
|
||||
{ok, {attribute, _, module, ActualModule}} ->
|
||||
%% If the module name includes package info, we get a list of atoms...
|
||||
case is_list(ActualModule) of
|
||||
true ->
|
||||
|
@ -116,12 +126,13 @@ inspect_epp(Epp, Module, Includes) ->
|
|||
inspect_epp(Epp, Module, Includes)
|
||||
end.
|
||||
|
||||
-spec needs_compile(Source::string(), Target::string(), Hrls::[string()]) -> boolean().
|
||||
needs_compile(Source, Target, Hrls) ->
|
||||
TargetLastMod = filelib:last_modified(Target),
|
||||
lists:any(fun(I) -> TargetLastMod < filelib:last_modified(I) end,
|
||||
[Source] ++ Hrls).
|
||||
|
||||
|
||||
-spec internal_erl_compile(Source::string(), Config::#config{}, Outdir::string()) -> 'ok' | 'skipped'.
|
||||
internal_erl_compile(Source, Config, Outdir) ->
|
||||
%% Determine the target name and includes list by inspecting the source file
|
||||
{Module, Hrls} = inspect(Source, include_path(Source, Config)),
|
||||
|
@ -154,6 +165,7 @@ internal_erl_compile(Source, Config, Outdir) ->
|
|||
skipped
|
||||
end.
|
||||
|
||||
-spec compile_mib(Source::string(), Target::string(), Config::#config{}) -> 'ok'.
|
||||
compile_mib(Source, Target, Config) ->
|
||||
ok = rebar_utils:ensure_dir(Target),
|
||||
Opts = [{outdir, "priv/mibs"}, {i, ["priv/mibs"]}] ++
|
||||
|
@ -165,9 +177,22 @@ compile_mib(Source, Target, Config) ->
|
|||
?FAIL
|
||||
end.
|
||||
|
||||
gather_src([], Srcs) ->
|
||||
Srcs;
|
||||
gather_src([Dir|Rest], Srcs) ->
|
||||
gather_src(Rest, Srcs ++ rebar_utils:find_files(Dir, ".*\\.erl\$")).
|
||||
|
||||
-spec src_dirs(SrcDirs::[string()]) -> [string()].
|
||||
src_dirs([]) ->
|
||||
["src"];
|
||||
src_dirs(SrcDirs) ->
|
||||
SrcDirs ++ src_dirs([]).
|
||||
|
||||
-spec dirs(Dir::string()) -> [string()].
|
||||
dirs(Dir) ->
|
||||
[F || F <- filelib:wildcard(filename:join([Dir, "*"])), filelib:is_dir(F)].
|
||||
|
||||
-spec delete_dir(Dir::string(), Subdirs::[string()]) -> 'ok' | {'error', atom()}.
|
||||
delete_dir(Dir, []) ->
|
||||
file:del_dir(Dir);
|
||||
delete_dir(Dir, Subdirs) ->
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
%%
|
||||
%% rebar: Erlang Build Tools
|
||||
%%
|
||||
%% Copyright (c) 2009 Dave Smith (dizzyd@dizzyd.com)
|
||||
%% Copyright (c) 2009, 2010 Dave Smith (dizzyd@dizzyd.com)
|
||||
%%
|
||||
%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -24,14 +24,21 @@
|
|||
%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
%% THE SOFTWARE.
|
||||
%% -------------------------------------------------------------------
|
||||
%%
|
||||
%% Targets:
|
||||
%% eunit - runs eunit tests
|
||||
%% clean - remove .eunit directory
|
||||
%%
|
||||
%% Global options:
|
||||
%% verbose=1 - show extra output from the eunit test
|
||||
%% suite="foo"" - runs test/foo_tests.erl
|
||||
%% @author Dave Smith <dizzyd@dizzyd.com>
|
||||
%% @doc rebar_eunit supports the following commands:
|
||||
%% <ul>
|
||||
%% <li>eunit - runs eunit tests</li>
|
||||
%% <li>clean - remove .eunit directory</li>
|
||||
%% </ul>
|
||||
%% The following Global options are supported:
|
||||
%% <ul>
|
||||
%% <li>verbose=1 - show extra output from the eunit test</li>
|
||||
%% <li>suite="foo"" - runs test/foo_tests.erl</li>
|
||||
%% </ul>
|
||||
%% Additionally, for projects that have separate folders for the core
|
||||
%% implementation, and for the unit tests, then the following <code>rebar.config</code>
|
||||
%% option can be provided: <code>{eunit_compile_opts, [{src_dirs, ["dir"]}]}.</code>.
|
||||
%% @copyright 2009, 2010 Dave Smith
|
||||
%% -------------------------------------------------------------------
|
||||
-module(rebar_eunit).
|
||||
|
||||
|
@ -61,9 +68,7 @@ eunit(Config, _File) ->
|
|||
%% with that scan and causes any cover compilation info to be lost. So,
|
||||
%% we do it by hand. :(
|
||||
%%
|
||||
%% TODO: Not currently compatible with package modules
|
||||
Modules = [list_to_atom(filename:basename(N, ".beam")) ||
|
||||
N <- filelib:wildcard("*.beam", ?EUNIT_DIR)],
|
||||
Modules = [rebar_utils:beam_to_mod(?EUNIT_DIR, N) || N <- rebar_utils:beams(?EUNIT_DIR)],
|
||||
|
||||
%% TODO: If there are other wildcards specified in eunit_sources, compile them
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ validate_modules(AppName, undefined) ->
|
|||
validate_modules(AppName, Mods) ->
|
||||
%% Construct two sets -- one for the actual .beam files in ebin/ and one for the modules
|
||||
%% listed in the .app file
|
||||
EbinSet = ordsets:from_list([beam_to_mod(N) || N <- beams()]),
|
||||
EbinSet = ordsets:from_list([rebar_utils:beam_to_mod("ebin", N) || N <- rebar_utils:beams("ebin")]),
|
||||
ModSet = ordsets:from_list(Mods),
|
||||
|
||||
%% Identify .beam files listed in the .app, but not present in ebin/
|
||||
|
@ -155,12 +155,3 @@ validate_modules(AppName, Mods) ->
|
|||
[AppName, Msg2]),
|
||||
?FAIL
|
||||
end.
|
||||
|
||||
beam_to_mod(Filename) ->
|
||||
["ebin" | Rest] = filename:split(Filename),
|
||||
list_to_atom(filename:basename(string:join(Rest, "."), ".beam")).
|
||||
|
||||
beams() ->
|
||||
filelib:fold_files("ebin", ".*\.beam\$", true,
|
||||
fun(F, Acc) -> [F | Acc] end, []).
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
%%
|
||||
%% rebar: Erlang Build Tools
|
||||
%%
|
||||
%% Copyright (c) 2009 Dave Smith (dizzyd@dizzyd.com)
|
||||
%% Copyright (c) 2009, 2010 Dave Smith (dizzyd@dizzyd.com)
|
||||
%%
|
||||
%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -33,7 +33,8 @@
|
|||
sh_failfast/2,
|
||||
find_files/2,
|
||||
now_str/0,
|
||||
ensure_dir/1]).
|
||||
ensure_dir/1,
|
||||
beam_to_mod/2, beams/1]).
|
||||
|
||||
-include("rebar.hrl").
|
||||
|
||||
|
@ -132,3 +133,12 @@ sh_loop(Port) ->
|
|||
{Port, {exit_status, Rc}} ->
|
||||
{error, Rc}
|
||||
end.
|
||||
|
||||
beam_to_mod(Dir, Filename) ->
|
||||
[Dir | Rest] = filename:split(Filename),
|
||||
list_to_atom(filename:basename(string:join(Rest, "."), ".beam")).
|
||||
|
||||
beams(Dir) ->
|
||||
filelib:fold_files(Dir, ".*\.beam\$", true,
|
||||
fun(F, Acc) -> [F | Acc] end, []).
|
||||
|
||||
|
|
Loading…
Reference in a new issue