diff options
-rw-r--r-- | src/rebar_dir.erl | 6 | ||||
-rw-r--r-- | src/rebar_erlc_compiler.erl | 46 | ||||
-rw-r--r-- | src/rebar_prv_eunit.erl | 12 | ||||
-rw-r--r-- | test/rebar_compile_SUITE.erl | 23 |
4 files changed, 65 insertions, 22 deletions
diff --git a/src/rebar_dir.erl b/src/rebar_dir.erl index 4a9bf09..7903ed5 100644 --- a/src/rebar_dir.erl +++ b/src/rebar_dir.erl @@ -12,7 +12,7 @@ global_config/1, global_config/0, global_cache_dir/1, - local_cache_dir/0, + local_cache_dir/1, get_cwd/0, template_globals/1, template_dir/1, @@ -85,8 +85,8 @@ global_cache_dir(State) -> Home = home_dir(), 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() -> {ok, Dir} = file:get_cwd(), diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl index 5bd04d2..50d180c 100644 --- a/src/rebar_erlc_compiler.erl +++ b/src/rebar_erlc_compiler.erl @@ -118,7 +118,7 @@ clean(_Config, AppDir) -> || F <- YrlFiles ]), %% 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 %% 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)), 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), ErlFirstFiles = erl_first_files(Config, NeededErlFiles), {DepErls, OtherErls} = lists:partition( @@ -186,6 +193,19 @@ needed_files(G, ErlOpts, Dir, OutDir, SourceFiles) -> orelse opts_changed(Opts, TargetBase) 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) -> case code:load_abs(ObjectFile) of {module, Mod} -> @@ -196,24 +216,24 @@ opts_changed(Opts, ObjectFile) -> {error, _} -> true 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, %% parse transforms, behaviours etc.) located in their directories or given %% InclDirs. Note that last modification times stored in vertices already respect %% dependencies induced by given graph G. -init_erlcinfo(InclDirs, Erls) -> +init_erlcinfo(InclDirs, Erls, Dir) -> G = digraph:new([acyclic]), - try restore_erlcinfo(G, InclDirs) + try restore_erlcinfo(G, InclDirs, Dir) 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, Dirs = source_and_include_dirs(InclDirs, 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. source_and_include_dirs(InclDirs, Erls) -> @@ -275,8 +295,8 @@ modify_erlcinfo(G, Source, LastModified, Dir, Dirs) -> end, AbsIncls), 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} -> % Since externally passed InclDirs can influence erlcinfo graph (see % modify_erlcinfo), we have to check here that they didn't change. @@ -294,10 +314,10 @@ restore_erlcinfo(G, InclDirs) -> ok end. -store_erlcinfo(G, InclDirs) -> +store_erlcinfo(G, InclDirs, Dir) -> 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)), - File = erlcinfo_file(), + File = erlcinfo_file(Dir), ok = filelib:ensure_dir(File), Data = term_to_binary(#erlcinfo{info={Vs, Es, InclDirs}}, [{compressed, 2}]), file:write_file(File, Data). diff --git a/src/rebar_prv_eunit.erl b/src/rebar_prv_eunit.erl index 3e57fb0..0ea3ae8 100644 --- a/src/rebar_prv_eunit.erl +++ b/src/rebar_prv_eunit.erl @@ -44,10 +44,14 @@ do(State) -> case prepare_tests(State) of {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 end. diff --git a/test/rebar_compile_SUITE.erl b/test/rebar_compile_SUITE.erl index c0308d6..bc72913 100644 --- a/test/rebar_compile_SUITE.erl +++ b/test/rebar_compile_SUITE.erl @@ -16,6 +16,7 @@ dont_recompile_when_opts_dont_change/1, dont_recompile_yrl_or_xrl/1, deps_in_path/1, + delete_beam_if_source_deleted/1, checkout_priority/1, compile_plugins/1]). @@ -43,7 +44,8 @@ all() -> build_checkout_apps, build_checkout_deps, build_all_srcdirs, recompile_when_hrl_changes, 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) -> AppDir = ?config(apps, Config), @@ -258,6 +260,24 @@ dont_recompile_yrl_or_xrl(Config) -> ?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) -> AppDir = ?config(apps, Config), StartPaths = code:get_path(), @@ -374,7 +394,6 @@ checkout_priority(Config) -> %% Tests that compiling a project installs and compiles the plugins of deps compile_plugins(Config) -> AppDir = ?config(apps, Config), - PluginsDir = filename:join([?config(base_dir, Config), "default", "plugins"]), Name = rebar_test_utils:create_random_name("app1_"), Vsn = rebar_test_utils:create_random_vsn(), |