Assemble Dirs passed to update_erlcinfo in one place

Current separation of part of the logic into include_path
obscures the purpose of Dirs (see expand_file_names).
Moreover for each particular Erl its source file was included
twice in Dirs, which is now corrected.

Also InclDirs (specified in erl_opts) as part of erlcinfo
since they can affect resulting graph, which needs to be
therefore regenerated when InclDirs change.  See added
test as an example.
This commit is contained in:
David Kubecka 2015-03-23 04:10:11 +01:00
parent df97a49ce7
commit 22acf8db67
6 changed files with 56 additions and 29 deletions

View file

@ -32,13 +32,22 @@
files() ->
[{copy, "../../rebar", "rebar"},
{copy, "src", "src"}].
{copy, "rebar.config", "rebar.config"},
{copy, "src", "src"},
{copy, "include", "include"},
{copy, "extra_include", "extra_include"}].
run(_Dir) ->
compile_all(ok, ""),
check_beams_ok(),
check_beams_untouched(),
modify_and_recompile_ok(),
modify_and_recompile_ok("src/lisp.erl", "ebin/lisp.beam"),
clean_all_ok(),
compile_all(error, "-C rebar.config.non-existing"),
compile_all(ok, ""),
modify_and_recompile_ok("extra_include/extra.hrl", "ebin/java.beam"),
ok.
check_beams_ok() ->
@ -49,9 +58,9 @@ check_beams_untouched() ->
Beams = filelib:wildcard("ebin/*.beam"),
compile_all_and_assert_mtimes(Beams, fun erlang:'=:='/2).
modify_and_recompile_ok() ->
touch(["src/lisp.erl"]),
compile_all_and_assert_mtimes(["ebin/lisp.beam"], fun erlang:'<'/2).
modify_and_recompile_ok(TouchFile, CheckFile) ->
touch([TouchFile]),
compile_all_and_assert_mtimes([CheckFile], fun erlang:'<'/2).
compile_all_and_assert_mtimes(Beams, Cmp) ->
BeamsModifiedBefore = mtime_ns(Beams),

View file

@ -0,0 +1,3 @@
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ts=4 sw=4 ft=erlang et
-define(CONCISE, impossible).

View file

@ -0,0 +1,3 @@
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ts=4 sw=4 ft=erlang et
-define(FUN, fake).

View file

@ -0,0 +1,6 @@
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ts=4 sw=4 ft=erlang et
{erl_opts,
[
{i, "extra_include"}
]}.

View file

@ -0,0 +1,11 @@
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ts=4 sw=4 ft=erlang et
-module(java).
-export([factory/0]).
-include("lambda.hrl").
-include("extra.hrl").
factory() ->
?FUN.

View file

@ -40,11 +40,11 @@
-define(ERLCINFO_FILE, "erlcinfo").
-type erlc_info_v() :: {digraph:vertex(), term()} | 'false'.
-type erlc_info_e() :: {digraph:vertex(), digraph:vertex()}.
-type erlc_info() :: {list(erlc_info_v()), list(erlc_info_e())}.
-type erlc_info() :: {list(erlc_info_v()), list(erlc_info_e()), list(string())}.
-record(erlcinfo,
{
vsn = ?ERLCINFO_VSN :: pos_integer(),
info = {[], []} :: erlc_info()
info = {[], [], []} :: erlc_info()
}).
-ifdef(namespaced_types).
@ -387,10 +387,6 @@ u_add_element(Elem, [Elem|_]=Set) -> Set;
u_add_element(Elem, [E1|Set]) -> [E1|u_add_element(Elem, Set)];
u_add_element(Elem, []) -> [Elem].
-spec include_path(file:filename(), list()) -> [file:filename(), ...].
include_path(Source, InclDirs) ->
lists:usort(["include", filename:dirname(Source) |InclDirs]).
-spec needs_compile(file:filename(), file:filename(),
[string()]) -> boolean().
needs_compile(Source, Target, Parents) ->
@ -403,26 +399,22 @@ erlcinfo_file() ->
init_erlcinfo(InclDirs, Erls) ->
G = digraph:new(),
try restore_erlcinfo(G)
try restore_erlcinfo(G, InclDirs)
catch
_ ->
_:_ ->
?WARN("Failed to restore ~s file. Discarding it.~n", [erlcinfo_file()]),
ok = file:delete(erlcinfo_file())
end,
%% Get a unique list of dirs based on the source files' locations.
%% This is used for finding files in sub dirs of the configured
%% src_dirs. For example, src/sub_dir/foo.erl.
Dirs = sets:to_list(lists:foldl(
fun(Erl, Acc) ->
Dir = filename:dirname(Erl),
sets:add_element(Dir, Acc)
end, sets:new(), Erls)),
Updates = [update_erlcinfo(G, Erl, include_path(Erl, InclDirs) ++ Dirs)
|| Erl <- Erls],
Dirs = source_and_include_dirs(InclDirs, Erls),
Updates = [update_erlcinfo(G, Erl, Dirs) || Erl <- Erls],
Modified = lists:member(modified, Updates),
ok = store_erlcinfo(G, Modified),
ok = store_erlcinfo(G, Modified, InclDirs),
G.
source_and_include_dirs(InclDirs, Erls) ->
SourceDirs = lists:map(fun filename:dirname/1, Erls),
lists:usort(["include" | InclDirs ++ SourceDirs]).
update_erlcinfo(G, Source, Dirs) ->
case digraph:vertex(G, Source) of
{_, LastUpdated} ->
@ -457,10 +449,13 @@ modify_erlcinfo(G, Source, Dirs) ->
digraph:add_edge(G, Source, Incl)
end, AbsIncls).
restore_erlcinfo(G) ->
restore_erlcinfo(G, InclDirs) ->
case file:read_file(erlcinfo_file()) of
{ok, Data} ->
#erlcinfo{vsn=?ERLCINFO_VSN, info={Vs, Es}} = binary_to_term(Data),
%% Since externally passed InclDirs can influence erlcinfo graph (see
%% modify_erlcinfo), we have to check here that they didn't change.
#erlcinfo{vsn=?ERLCINFO_VSN, info={Vs, Es, InclDirs}} =
binary_to_term(Data),
lists:foreach(
fun({V, LastUpdated}) ->
digraph:add_vertex(G, V, LastUpdated)
@ -473,9 +468,9 @@ restore_erlcinfo(G) ->
ok
end.
store_erlcinfo(_G, _Modified = false) ->
store_erlcinfo(_G, _Modified = false, _InclDirs) ->
ok;
store_erlcinfo(G, _Modified) ->
store_erlcinfo(G, _Modified, InclDirs) ->
Vs = lists:map(
fun(V) ->
digraph:vertex(G, V)
@ -490,7 +485,7 @@ store_erlcinfo(G, _Modified) ->
end, Vs),
File = erlcinfo_file(),
ok = filelib:ensure_dir(File),
Data = term_to_binary(#erlcinfo{info={Vs, Es}}, [{compressed, 9}]),
Data = term_to_binary(#erlcinfo{info={Vs, Es, InclDirs}}, [{compressed, 9}]),
file:write_file(File, Data).
%% NOTE: If, for example, one of the entries in Files refers to