summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortheiw <none@none>2010-02-05 17:34:38 +0000
committertheiw <none@none>2010-02-05 17:34:38 +0000
commit788bd3df726933334ee9c570e1e920829c5d1c4c (patch)
treeed11edbb52295a81179f7e181c40a4ce30827c87 /src
parent30a3816c8649bbafb3695780c78c4eabbaa92eda (diff)
Provide package support for eunit; build_plt now includes listed applications; begin including -spec annotations
Diffstat (limited to 'src')
-rw-r--r--src/rebar_core.erl2
-rw-r--r--src/rebar_dialyzer.erl43
-rw-r--r--src/rebar_erlc_compiler.erl35
-rw-r--r--src/rebar_eunit.erl29
-rw-r--r--src/rebar_otp_app.erl11
-rw-r--r--src/rebar_utils.erl14
6 files changed, 85 insertions, 49 deletions
diff --git a/src/rebar_core.erl b/src/rebar_core.erl
index 68391e7..1cefe84 100644
--- a/src/rebar_core.erl
+++ b/src/rebar_core.erl
@@ -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,
diff --git a/src/rebar_dialyzer.erl b/src/rebar_dialyzer.erl
index c725e48..35bb201 100644
--- a/src/rebar_dialyzer.erl
+++ b/src/rebar_dialyzer.erl
@@ -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&lt; &rt;kernel_lib&lt; &rt;mnesia_lib&lt;")</li>
+%% <li>build_plt (essentially "dialyzer --build_plt -r &lt;app_dirs&gt;")</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),
- %% This is the recommended minimal PLT for OTP
- %% (see http://www.erlang.org/doc/apps/dialyzer/dialyzer_chapter.html#id2256857).
+ {ok, _AppName, AppData} = rebar_app_utils:load_app_file(File),
+ Apps = proplists:get_value(applications, AppData),
+
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.
diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl
index 04878c3..51b7f17 100644
--- a/src/rebar_erlc_compiler.erl
+++ b/src/rebar_erlc_compiler.erl
@@ -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) ->
diff --git a/src/rebar_eunit.erl b/src/rebar_eunit.erl
index 6ef7a25..d51c35d 100644
--- a/src/rebar_eunit.erl
+++ b/src/rebar_eunit.erl
@@ -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
diff --git a/src/rebar_otp_app.erl b/src/rebar_otp_app.erl
index 136c5cb..f20ce0c 100644
--- a/src/rebar_otp_app.erl
+++ b/src/rebar_otp_app.erl
@@ -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, []).
-
diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl
index 5f1612c..7265058 100644
--- a/src/rebar_utils.erl
+++ b/src/rebar_utils.erl
@@ -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, []).
+