Browse Source

rm old beams, make erlcinfo graph per app isntad of global to project

pull/327/head
Tristan Sloughter 10 years ago
parent
commit
a447067888
4 changed files with 65 additions and 22 deletions
  1. +3
    -3
      src/rebar_dir.erl
  2. +33
    -13
      src/rebar_erlc_compiler.erl
  3. +8
    -4
      src/rebar_prv_eunit.erl
  4. +21
    -2
      test/rebar_compile_SUITE.erl

+ 3
- 3
src/rebar_dir.erl View File

@ -12,7 +12,7 @@
global_config/1, global_config/1,
global_config/0, global_config/0,
global_cache_dir/1, global_cache_dir/1,
local_cache_dir/0,
local_cache_dir/1,
get_cwd/0, get_cwd/0,
template_globals/1, template_globals/1,
template_dir/1, template_dir/1,
@ -85,8 +85,8 @@ global_cache_dir(State) ->
Home = home_dir(), Home = home_dir(),
rebar_state:get(State, global_rebar_dir, filename:join([Home, ".cache", "rebar3"])). rebar_state:get(State, global_rebar_dir, filename:join([Home, ".cache", "rebar3"])).
local_cache_dir() ->
filename:join(get_cwd(), ".rebar3").
local_cache_dir(Dir) ->
filename:join(Dir, ".rebar3").
get_cwd() -> get_cwd() ->
{ok, Dir} = file:get_cwd(), {ok, Dir} = file:get_cwd(),

+ 33
- 13
src/rebar_erlc_compiler.erl View File

@ -118,7 +118,7 @@ clean(_Config, AppDir) ->
|| F <- YrlFiles ]), || F <- YrlFiles ]),
%% Delete the build graph, if any %% Delete the build graph, if any
rebar_file_utils:rm_rf(erlcinfo_file()),
rebar_file_utils:rm_rf(erlcinfo_file(AppDir)),
%% Erlang compilation is recursive, so it's possible that we have a nested %% Erlang compilation is recursive, so it's possible that we have a nested
%% directory structure in ebin with .beam files within. As such, we want %% directory structure in ebin with .beam files within. As such, we want
@ -152,7 +152,14 @@ doterl_compile(Config, Dir, OutDir, MoreSources, ErlOpts) ->
true = code:add_path(filename:absname(OutDir)), true = code:add_path(filename:absname(OutDir)),
OutDir1 = proplists:get_value(outdir, ErlOpts, OutDir), OutDir1 = proplists:get_value(outdir, ErlOpts, OutDir),
G = init_erlcinfo(proplists:get_all_values(i, ErlOpts), AllErlFiles),
G = init_erlcinfo(proplists:get_all_values(i, ErlOpts), AllErlFiles, Dir),
%% A source file may have been renamed or deleted. Remove it from the graph
%% and remove any beam file for that source if it exists.
Vertices = digraph:vertices(G),
[maybe_rm_beam_and_edge(G, OutDir, File) || File <- lists:sort(Vertices) -- lists:sort(AllErlFiles),
filename:extension(File) =:= ".erl"],
NeededErlFiles = needed_files(G, ErlOpts, Dir, OutDir1, AllErlFiles), NeededErlFiles = needed_files(G, ErlOpts, Dir, OutDir1, AllErlFiles),
ErlFirstFiles = erl_first_files(Config, NeededErlFiles), ErlFirstFiles = erl_first_files(Config, NeededErlFiles),
{DepErls, OtherErls} = lists:partition( {DepErls, OtherErls} = lists:partition(
@ -186,6 +193,19 @@ needed_files(G, ErlOpts, Dir, OutDir, SourceFiles) ->
orelse opts_changed(Opts, TargetBase) orelse opts_changed(Opts, TargetBase)
end, SourceFiles). end, SourceFiles).
maybe_rm_beam_and_edge(G, OutDir, Source) ->
%% This is NOT a double check it is the only check that the source file is actually gone
case filelib:is_regular(Source) of
true ->
%% Actually exists, don't delete
ok;
false ->
Target = target_base(OutDir, Source) ++ ".beam",
?DEBUG("Source ~s is gone, deleting previous beam file if it exists ~s", [Source, Target]),
file:delete(Target),
digraph:del_vertex(G, Source)
end.
opts_changed(Opts, ObjectFile) -> opts_changed(Opts, ObjectFile) ->
case code:load_abs(ObjectFile) of case code:load_abs(ObjectFile) of
{module, Mod} -> {module, Mod} ->
@ -196,24 +216,24 @@ opts_changed(Opts, ObjectFile) ->
{error, _} -> true {error, _} -> true
end. end.
erlcinfo_file() ->
filename:join(rebar_dir:local_cache_dir(), ?ERLCINFO_FILE).
erlcinfo_file(Dir) ->
filename:join(rebar_dir:local_cache_dir(Dir), ?ERLCINFO_FILE).
%% Get dependency graph of given Erls files and their dependencies (header files, %% Get dependency graph of given Erls files and their dependencies (header files,
%% parse transforms, behaviours etc.) located in their directories or given %% parse transforms, behaviours etc.) located in their directories or given
%% InclDirs. Note that last modification times stored in vertices already respect %% InclDirs. Note that last modification times stored in vertices already respect
%% dependencies induced by given graph G. %% dependencies induced by given graph G.
init_erlcinfo(InclDirs, Erls) ->
init_erlcinfo(InclDirs, Erls, Dir) ->
G = digraph:new([acyclic]), G = digraph:new([acyclic]),
try restore_erlcinfo(G, InclDirs)
try restore_erlcinfo(G, InclDirs, Dir)
catch catch
_:_ -> _:_ ->
?WARN("Failed to restore ~s file. Discarding it.~n", [erlcinfo_file()]),
file:delete(erlcinfo_file())
?WARN("Failed to restore ~s file. Discarding it.~n", [erlcinfo_file(Dir)]),
file:delete(erlcinfo_file(Dir))
end, end,
Dirs = source_and_include_dirs(InclDirs, Erls), Dirs = source_and_include_dirs(InclDirs, Erls),
Modified = lists:foldl(update_erlcinfo_fun(G, Dirs), false, Erls), Modified = lists:foldl(update_erlcinfo_fun(G, Dirs), false, Erls),
if Modified -> store_erlcinfo(G, InclDirs); not Modified -> ok end,
if Modified -> store_erlcinfo(G, InclDirs, Dir); not Modified -> ok end,
G. G.
source_and_include_dirs(InclDirs, Erls) -> source_and_include_dirs(InclDirs, Erls) ->
@ -275,8 +295,8 @@ modify_erlcinfo(G, Source, LastModified, Dir, Dirs) ->
end, AbsIncls), end, AbsIncls),
modified. modified.
restore_erlcinfo(G, InclDirs) ->
case file:read_file(erlcinfo_file()) of
restore_erlcinfo(G, InclDirs, Dir) ->
case file:read_file(erlcinfo_file(Dir)) of
{ok, Data} -> {ok, Data} ->
% Since externally passed InclDirs can influence erlcinfo graph (see % Since externally passed InclDirs can influence erlcinfo graph (see
% modify_erlcinfo), we have to check here that they didn't change. % modify_erlcinfo), we have to check here that they didn't change.
@ -294,10 +314,10 @@ restore_erlcinfo(G, InclDirs) ->
ok ok
end. end.
store_erlcinfo(G, InclDirs) ->
store_erlcinfo(G, InclDirs, Dir) ->
Vs = lists:map(fun(V) -> digraph:vertex(G, V) end, digraph:vertices(G)), Vs = lists:map(fun(V) -> digraph:vertex(G, V) end, digraph:vertices(G)),
Es = lists:map(fun(E) -> digraph:edge(G, E) end, digraph:edges(G)), Es = lists:map(fun(E) -> digraph:edge(G, E) end, digraph:edges(G)),
File = erlcinfo_file(),
File = erlcinfo_file(Dir),
ok = filelib:ensure_dir(File), ok = filelib:ensure_dir(File),
Data = term_to_binary(#erlcinfo{info={Vs, Es, InclDirs}}, [{compressed, 2}]), Data = term_to_binary(#erlcinfo{info={Vs, Es, InclDirs}}, [{compressed, 2}]),
file:write_file(File, Data). file:write_file(File, Data).

+ 8
- 4
src/rebar_prv_eunit.erl View File

@ -44,10 +44,14 @@ do(State) ->
case prepare_tests(State) of case prepare_tests(State) of
{ok, Tests} -> {ok, Tests} ->
{ok, State1} = do_tests(State, Tests),
%% Run eunit provider posthooks
rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State1),
{ok, State1};
case do_tests(State, Tests) of
{ok, State1} ->
%% Run eunit provider posthooks
rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State1),
{ok, State1};
Error ->
Error
end;
Error -> Error ->
Error Error
end. end.

+ 21
- 2
test/rebar_compile_SUITE.erl View File

@ -16,6 +16,7 @@
dont_recompile_when_opts_dont_change/1, dont_recompile_when_opts_dont_change/1,
dont_recompile_yrl_or_xrl/1, dont_recompile_yrl_or_xrl/1,
deps_in_path/1, deps_in_path/1,
delete_beam_if_source_deleted/1,
checkout_priority/1, checkout_priority/1,
compile_plugins/1]). compile_plugins/1]).
@ -43,7 +44,8 @@ all() ->
build_checkout_apps, build_checkout_deps, build_checkout_apps, build_checkout_deps,
build_all_srcdirs, recompile_when_hrl_changes, build_all_srcdirs, recompile_when_hrl_changes,
recompile_when_opts_change, dont_recompile_when_opts_dont_change, recompile_when_opts_change, dont_recompile_when_opts_dont_change,
dont_recompile_yrl_or_xrl, deps_in_path, checkout_priority, compile_plugins].
dont_recompile_yrl_or_xrl, delete_beam_if_source_deleted,
deps_in_path, checkout_priority, compile_plugins].
build_basic_app(Config) -> build_basic_app(Config) ->
AppDir = ?config(apps, Config), AppDir = ?config(apps, Config),
@ -258,6 +260,24 @@ dont_recompile_yrl_or_xrl(Config) ->
?assert(ModTime == NewModTime). ?assert(ModTime == NewModTime).
delete_beam_if_source_deleted(Config) ->
AppDir = ?config(apps, Config),
Name = rebar_test_utils:create_random_name("app1_"),
Vsn = rebar_test_utils:create_random_vsn(),
rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
SrcDir = filename:join([AppDir, "_build", "default", "lib", Name, "src"]),
?assert(filelib:is_regular(filename:join(EbinDir, "not_a_real_src_" ++ Name ++ ".beam"))),
file:delete(filename:join(SrcDir, "not_a_real_src_" ++ Name ++ ".erl")),
rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
?assertNot(filelib:is_regular(filename:join(EbinDir, "not_a_real_src_" ++ Name ++ ".beam"))).
deps_in_path(Config) -> deps_in_path(Config) ->
AppDir = ?config(apps, Config), AppDir = ?config(apps, Config),
StartPaths = code:get_path(), StartPaths = code:get_path(),
@ -374,7 +394,6 @@ checkout_priority(Config) ->
%% Tests that compiling a project installs and compiles the plugins of deps %% Tests that compiling a project installs and compiles the plugins of deps
compile_plugins(Config) -> compile_plugins(Config) ->
AppDir = ?config(apps, Config), AppDir = ?config(apps, Config),
PluginsDir = filename:join([?config(base_dir, Config), "default", "plugins"]),
Name = rebar_test_utils:create_random_name("app1_"), Name = rebar_test_utils:create_random_name("app1_"),
Vsn = rebar_test_utils:create_random_vsn(), Vsn = rebar_test_utils:create_random_vsn(),

Loading…
Cancel
Save