浏览代码

Merge pull request #99 from tuncer/fixes-and-updates

Fixes and updates
pull/3/head
Dave Smith 12 年前
父节点
当前提交
00164b280a
共有 8 个文件被更改,包括 125 次插入87 次删除
  1. +0
    -7
      .hgignore
  2. +0
    -1
      .hgtags
  3. +1
    -0
      Makefile
  4. +11
    -0
      THANKS
  5. +3
    -1
      rebar.config.sample
  6. +22
    -16
      src/rebar_core.erl
  7. +10
    -4
      src/rebar_ct.erl
  8. +78
    -58
      src/rebar_xref.erl

+ 0
- 7
.hgignore 查看文件

@ -1,7 +0,0 @@
\.beam
^rebar$
.~
\.orig
\.swp
rt.work/*
^.gitignore$

+ 0
- 1
.hgtags 查看文件

@ -1 +0,0 @@
e8747041ef63f1b394d3b156c72c5bc12e92ecc4 RELEASE-1

+ 1
- 0
Makefile 查看文件

@ -10,6 +10,7 @@ clean:
@rm -rf rebar ebin/*.beam inttest/rt.work rt.work .eunit
distclean: clean
@rm -f dialyzer_warnings
@rm -rf deps
debug:

+ 11
- 0
THANKS 查看文件

@ -109,3 +109,14 @@ Daniel White
Martin Schut
Serge Aleynikov
Magnus Henoch
Artem Teslenko
Jeremie Lasalle Ratelle
Jose Valim
Krzysztof Rutka
Mats Cronqvist
Matthew Conway
Giacomo Olgeni
Pedram Nimreezi
Sylvain Benner
Oliver Ferrigni
Dave Thomas

+ 3
- 1
rebar.config.sample 查看文件

@ -209,7 +209,9 @@
{xref_warnings, false}.
%% xref checks to run
{xref_checks, [exports_not_used, undefined_function_calls]}.
{xref_checks, [undefined_function_calls, undefined_functions,
locals_not_used, exports_not_used,
deprecated_function_calls, deprecated_functions]}.
%% Optional custom xref queries (xref manual has details) specified as
%% {xref_queries, [{query_string(), expected_query_result()},...]}

+ 22
- 16
src/rebar_core.erl 查看文件

@ -533,21 +533,7 @@ plugin_modules(Config, PredirsAssoc, FoundModules, MissingModules) ->
load_plugin_modules(Config, PredirsAssoc, Modules) ->
Cwd = rebar_utils:get_cwd(),
PluginDirs = case rebar_config:get_local(Config, plugin_dir, undefined) of
undefined ->
% Plugin can be in the project's "plugins" folder
[filename:join(Cwd, "plugins")];
Dir ->
[Dir]
end ++
% We also want to include this case:
% Plugin can be in "plugins" directory of the plugin base directory. For
% example, Cwd depends on Plugin, and deps/Plugin/plugins/Plugin.erl is the
% plugin.
[
filename:join(Dir, "plugins") ||
Dir <- get_plugin_base_dirs(Cwd, PredirsAssoc)
],
PluginDirs = get_all_plugin_dirs(Config, Cwd, PredirsAssoc),
%% Find relevant sources in base_dir and plugin_dir
Erls = string:join([atom_to_list(M)++"\\.erl" || M <- Modules], "|"),
@ -562,12 +548,32 @@ load_plugin_modules(Config, PredirsAssoc, Modules) ->
NotLoaded = [V || V <- Modules, FilterMissing(V)],
{Loaded, NotLoaded}.
get_all_plugin_dirs(Config, Cwd, PredirsAssoc) ->
get_plugin_dir(Config, Cwd) ++ get_base_plugin_dirs(Cwd, PredirsAssoc).
get_plugin_dir(Config, Cwd) ->
case rebar_config:get_local(Config, plugin_dir, undefined) of
undefined ->
%% Plugin can be in the project's "plugins" folder
[filename:join(Cwd, "plugins")];
Dir ->
[Dir]
end.
%% We also want to include this case:
%% Plugin can be in "plugins" directory of the plugin base directory.
%% For example, Cwd depends on Plugin, and deps/Plugin/plugins/Plugin.erl
%% is the plugin.
get_base_plugin_dirs(Cwd, PredirsAssoc) ->
[filename:join(Dir, "plugins") ||
Dir <- get_plugin_base_dirs(Cwd, PredirsAssoc)].
%% @doc PredirsAssoc is a dictionary of plugindir -> 'parent' pairs
%% 'parent' in this case depends on plugin; therefore we have to give
%% all plugins that Cwd ('parent' in this case) depends on.
get_plugin_base_dirs(Cwd, PredirsAssoc) ->
[PluginDir || {PluginDir, Master} <- dict:to_list(PredirsAssoc),
Master =:= Cwd].
Master =:= Cwd].
is_missing_plugin(Loaded) ->
fun(Mod) -> not lists:member(Mod, Loaded) end.

+ 10
- 4
src/rebar_ct.erl 查看文件

@ -108,7 +108,8 @@ run_test(TestDir, LogDir, Config, _File) ->
" 2>&1 | tee -a " ++ RawLog
end,
case rebar_utils:sh(Cmd ++ Output, [{env,[{"TESTDIR", TestDir}]}, return_on_error]) of
ShOpts = [{env,[{"TESTDIR", TestDir}]}, return_on_error],
case rebar_utils:sh(Cmd ++ Output, ShOpts) of
{ok,_} ->
%% in older versions of ct_run, this could have been a failure
%% that returned a non-0 code. Check for that!
@ -135,11 +136,16 @@ clear_log(LogDir, RawLog) ->
check_success_log(Config, RawLog) ->
check_log(Config, RawLog, fun(Msg) -> ?CONSOLE("DONE.\n~s\n", [Msg]) end).
check_fail_log(Config, RawLog, Command, {Rc, Output}) ->
check_log(Config, RawLog, fun(_Msg) ->
-type err_handler() :: fun((string()) -> no_return()).
-spec failure_logger(string(), {integer(), string()}) -> err_handler().
failure_logger(Command, {Rc, Output}) ->
fun(_Msg) ->
?ABORT("~s failed with error: ~w and output:~n~s~n",
[Command, Rc, Output])
end).
end.
check_fail_log(Config, RawLog, Command, Result) ->
check_log(Config, RawLog, failure_logger(Command, Result)).
check_log(Config,RawLog,Fun) ->
{ok, Msg} =

+ 78
- 58
src/rebar_xref.erl 查看文件

@ -37,6 +37,9 @@
-export([xref/2]).
%% for internal use only
-export([info/2]).
%% ===================================================================
%% Public API
%% ===================================================================
@ -58,14 +61,15 @@ xref(Config, _) ->
%% Get list of xref checks we want to run
ConfXrefChecks = rebar_config:get(Config, xref_checks,
[exports_not_used,
undefined_function_calls]),
[exports_not_used,
undefined_function_calls]),
SupportedXrefs = [undefined_function_calls, undefined_functions,
locals_not_used, exports_not_used,
deprecated_function_calls, deprecated_functions],
locals_not_used, exports_not_used,
deprecated_function_calls, deprecated_functions],
XrefChecks = sets:to_list(sets:intersection(sets:from_list(SupportedXrefs),
XrefChecks = sets:to_list(sets:intersection(
sets:from_list(SupportedXrefs),
sets:from_list(ConfXrefChecks))),
%% Run xref checks
@ -92,17 +96,37 @@ xref(Config, _) ->
%% Internal functions
%% ===================================================================
info(help, xref) ->
?CONSOLE(
"Run cross reference analysis.~n"
"~n"
"Valid rebar.config options:~n"
" ~p~n"
" ~p~n"
" ~p~n",
[
{xref_warnings, false},
{xref_checks, [undefined_function_calls, undefined_functions,
locals_not_used, exports_not_used,
deprecated_function_calls, deprecated_functions]},
{xref_queries,
[{"(xc - uc) || (xu - x - b"
" - (\"mod\":\".*foo\"/\"4\"))",[]}]}
]).
xref_checks(XrefChecks) ->
XrefWarnCount = lists:foldl(
fun(XrefCheck, Acc) ->
{ok, Results} = xref:analyze(xref, XrefCheck),
FilteredResults =filter_xref_results(XrefCheck, Results),
lists:foreach(fun(Res) -> display_xrefresult(XrefCheck, Res) end, FilteredResults),
Acc + length(FilteredResults)
end,
0, XrefChecks),
XrefWarnCount = lists:foldl(fun run_xref_check/2, 0, XrefChecks),
XrefWarnCount =:= 0.
run_xref_check(XrefCheck, Acc) ->
{ok, Results} = xref:analyze(xref, XrefCheck),
FilteredResults =filter_xref_results(XrefCheck, Results),
lists:foreach(fun(Res) ->
display_xref_result(XrefCheck, Res)
end,
FilteredResults),
Acc + length(FilteredResults).
check_query({Query, Value}) ->
{ok, Answer} = xref:q(xref, Query),
case Answer =:= Value of
@ -141,78 +165,75 @@ get_xref_ignorelist(Mod, XrefCheck) ->
_Class:_Error -> []
end,
Ignore_xref = keyall(ignore_xref, Attributes),
IgnoreXref = keyall(ignore_xref, Attributes),
Behaviour_callbacks = case XrefCheck of
exports_not_used -> [B:behaviour_info(callbacks) || B <- keyall(behaviour, Attributes)];
_ -> []
end,
BehaviourCallbacks = get_behaviour_callbacks(XrefCheck, Attributes),
% And create a flat {M,F,A} list
%% And create a flat {M,F,A} list
lists:foldl(
fun(El,Acc) ->
case El of
{F, A} -> [{Mod,F,A} | Acc];
{M, F, A} -> [{M,F,A} | Acc]
end
end, [],lists:flatten([Ignore_xref, Behaviour_callbacks])).
fun({F, A}, Acc) -> [{Mod,F,A} | Acc];
({M, F, A}, Acc) -> [{M,F,A} | Acc]
end, [], lists:flatten([IgnoreXref, BehaviourCallbacks])).
keyall(Key, List) ->
lists:flatmap(fun({K, L}) when Key =:= K -> L; (_) -> [] end, List).
parse_xref_result(XrefResult) ->
case XrefResult of
{_, MFAt} -> MFAt;
MFAt -> MFAt
end.
get_behaviour_callbacks(exports_not_used, Attributes) ->
[B:behaviour_info(callbacks) || B <- keyall(behaviour, Attributes)];
get_behaviour_callbacks(_XrefCheck, _Attributes) ->
[].
parse_xref_result({_, MFAt}) -> MFAt;
parse_xref_result(MFAt) -> MFAt.
filter_xref_results(XrefCheck, XrefResults) ->
SearchModules = lists:usort(lists:map(
fun(Res) ->
case Res of
{Mt,_Ft,_At} -> Mt;
{{Ms,_Fs,_As},{_Mt,_Ft,_At}} -> Ms;
_ -> undefined
end
end, XrefResults)),
Ignores = lists:flatten([
get_xref_ignorelist(Module,XrefCheck) || Module <- SearchModules]),
SearchModules = lists:usort(
lists:map(
fun({Mt,_Ft,_At}) -> Mt;
({{Ms,_Fs,_As},{_Mt,_Ft,_At}}) -> Ms;
(_) -> undefined
end, XrefResults)),
Ignores = lists:flatmap(fun(Module) ->
get_xref_ignorelist(Module, XrefCheck)
end, SearchModules),
[Result || Result <- XrefResults,
not lists:member(parse_xref_result(Result),Ignores)].
not lists:member(parse_xref_result(Result), Ignores)].
display_xrefresult(Type, XrefResult) ->
display_xref_result(Type, XrefResult) ->
{ Source, SMFA, TMFA } = case XrefResult of
{MFASource, MFATarget} ->
{format_mfa_source(MFASource), format_mfa(MFASource),
format_mfa(MFATarget)};
MFATarget ->
{format_mfa_source(MFATarget), format_mfa(MFATarget),
undefined}
end,
{MFASource, MFATarget} ->
{format_mfa_source(MFASource),
format_mfa(MFASource),
format_mfa(MFATarget)};
MFATarget ->
{format_mfa_source(MFATarget),
format_mfa(MFATarget),
undefined}
end,
case Type of
undefined_function_calls ->
?CONSOLE("~sWarning: ~s calls undefined function ~s (Xref)\n",
[Source, SMFA, TMFA]);
[Source, SMFA, TMFA]);
undefined_functions ->
?CONSOLE("~sWarning: ~s is undefined function (Xref)\n",
[Source, SMFA]);
[Source, SMFA]);
locals_not_used ->
?CONSOLE("~sWarning: ~s is unused local function (Xref)\n",
[Source, SMFA]);
[Source, SMFA]);
exports_not_used ->
?CONSOLE("~sWarning: ~s is unused export (Xref)\n",
[Source, SMFA]);
[Source, SMFA]);
deprecated_function_calls ->
?CONSOLE("~sWarning: ~s calls deprecated function ~s (Xref)\n",
[Source, SMFA, TMFA]);
[Source, SMFA, TMFA]);
deprecated_functions ->
?CONSOLE("~sWarning: ~s is deprecated function (Xref)\n",
[Source, SMFA]);
[Source, SMFA]);
Other ->
?CONSOLE("~sWarning: ~s - ~s xref check: ~s (Xref)\n",
[Source, SMFA, TMFA, Other])
[Source, SMFA, TMFA, Other])
end.
format_mfa({M, F, A}) ->
@ -236,7 +257,6 @@ safe_element(N, Tuple) ->
Value
end.
%%
%% Given a MFA, find the file and LOC where it's defined. Note that
%% xref doesn't work if there is no abstract_code, so we can avoid

正在加载...
取消
保存