diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl index 6f7e3a3f..ef3e7fc3 100644 --- a/src/rebar_erlc_compiler.erl +++ b/src/rebar_erlc_compiler.erl @@ -129,9 +129,11 @@ doterl_compile(Config, OutDir, MoreSources) -> %% contain erlang source. This might be used, for example, should %% eunit tests be separated from the core application source. SrcDirs = rebar_utils:src_dirs(proplists:append_values(src_dirs, ErlOpts)), - RestErls = [Source || Source <- gather_src(SrcDirs, []) ++ MoreSources, + RestErls = [Source || Source <- gather_src(SrcDirs, [], erl) ++ MoreSources, not lists:member(Source, FirstErls)], + Cores = [Source || Source <- gather_src(SrcDirs, [], core) ++ MoreSources], + %% Split RestErls so that parse_transforms and behaviours are instead added %% to erl_first_files, parse transforms first. %% This should probably be somewhat combined with inspect_epp @@ -159,6 +161,10 @@ doterl_compile(Config, OutDir, MoreSources) -> fun(S, C) -> internal_erl_compile(S, C, OutDir, ErlOpts) end), + rebar_base_compiler:run(Config, [], Cores, + fun(S, C) -> + internal_core_compile(S, C, OutDir, ErlOpts) + end), true = code:set_path(CurrPath), ok. @@ -177,7 +183,8 @@ include_path(Source, Config) -> -spec inspect(Source::file:filename(), IncludePath::[file:filename(), ...]) -> {string(), [string()]}. inspect(Source, IncludePath) -> - ModuleDefault = filename:basename(Source, ".erl"), + Extension = filename:extension(Source), + ModuleDefault = filename:basename(Source, Extension), case epp:open(Source, IncludePath) of {ok, Epp} -> inspect_epp(Epp, Source, ModuleDefault, []); @@ -229,6 +236,37 @@ needs_compile(Source, Target, Hrls) -> lists:any(fun(I) -> TargetLastMod < filelib:last_modified(I) end, [Source] ++ Hrls). +-spec internal_core_compile(Source::file:filename(), + Config::rebar_config:config(), + Outdir::file:filename(), + ErlOpts::list()) -> 'ok' | 'skipped'. +internal_core_compile(Source, Config, Outdir, ErlOpts) -> + %% Determine the target name and includes list by inspecting the source file + {Module, Hrls} = inspect(Source, include_path(Source, Config)), + + %% Construct the target filename + Target = filename:join([Outdir,Module]) ++ ".beam", + ok = filelib:ensure_dir(Target), + + %% If the file needs compilation, based on last mod date of includes or + %% the target + case needs_compile(Source, Target, Hrls) of + true -> + Opts = [from_core, {outdir, filename:dirname(Target)}] ++ + ErlOpts ++ [{i, "include"}, return], + case compile:file(Source, Opts) of + {ok, _Mod} -> + ok; + {ok, _Mod, Ws} -> + rebar_base_compiler:ok_tuple(Source, Ws); + {error, Es, Ws} -> + rebar_base_compiler:error_tuple(Source, Es, Ws, Opts) + end; + false -> + skipped + end. + + -spec internal_erl_compile(Source::file:filename(), Config::rebar_config:config(), Outdir::file:filename(), @@ -306,10 +344,14 @@ compile_xrl_yrl(Source, Target, Opts, Mod) -> skipped end. -gather_src([], Srcs) -> +gather_src([], Srcs, _Type) -> Srcs; -gather_src([Dir|Rest], Srcs) -> - gather_src(Rest, Srcs ++ rebar_utils:find_files(Dir, ".*\\.erl\$")). +gather_src([Dir|Rest], Srcs, erl) -> + Erls = rebar_utils:find_files(Dir, ".*\\.erl\$"), + gather_src(Rest, Srcs ++ Erls, erl); +gather_src([Dir|Rest], Srcs, core) -> + Cores = rebar_utils:find_files(Dir, ".*\\.core\$"), + gather_src(Rest, Srcs ++ Cores, core). -spec dirs(Dir::file:filename()) -> [file:filename()]. diff --git a/test/rebar_eunit_tests.erl b/test/rebar_eunit_tests.erl index 72fb3ea7..b0014c53 100644 --- a/test/rebar_eunit_tests.erl +++ b/test/rebar_eunit_tests.erl @@ -46,17 +46,18 @@ eunit_test_() -> {"Ensure EUnit runs with tests in a 'test' dir and no defined suite", - setup, fun() -> setup_basic_project(), rebar("-v eunit") end, + setup, fun() -> setup_core_project(), rebar("-v eunit") end, fun teardown/1, fun(RebarOut) -> [{"Tests in 'test' directory are found and run", ?_assert(string:str(RebarOut, "myapp_mymod_tests:") =/= 0)}, + {"", fun() -> ?assertEqual(RebarOut, false) end}, {"Tests in 'src' directory are found and run", ?_assert(string:str(RebarOut, "myapp_mymod:") =/= 0)}, {"Tests are only run once", - ?_assert(string:str(RebarOut, "All 2 tests passed") =/= 0)}] + ?_assert(string:str(RebarOut, "All 3 tests passed") =/= 0)}] end}. cover_test_() -> @@ -141,10 +142,27 @@ basic_setup_test_() -> ["test/myapp_mymod_tests.erl", "src/myapp_mymod.erl"])}. +basic_core_test_() -> + {"Create a core project with a 'test' directory, a test, and a module", + setup, fun setup_core_project/0, fun teardown/1, + + %% Test the setup function + assert_dirs_in("Core Project", + ["src", "ebin", "test"]) ++ + assert_files_in("Core Project", + ["src/myapp_mycoremod.core"])}. + %% ==================================================================== %% Setup and Teardown %% ==================================================================== +-define(myapp_mycoremod, + ["module 'myapp_mycoremod' [ 'myfunc'/0 ] attributes [ ]\n", + "\n", + "'myfunc'/0 = fun() ->\n", + " []\n", + "end"]). + -define(myapp_mymod, ["-module(myapp_mymod).\n", "-export([myfunc/0]).\n", @@ -156,7 +174,8 @@ basic_setup_test_() -> ["-module(myapp_mymod_tests).\n", "-compile([export_all]).\n", "-include_lib(\"eunit/include/eunit.hrl\").\n", - "myfunc_test() -> ?assertMatch(ok, myapp_mymod:myfunc()).\n"]). + "myfunc_test() -> ?assertMatch(ok, myapp_mymod:myfunc()).\n", + "myfunc_core_test() -> ?assertMatch([], myapp_mycoremod:myfunc()).\n"]). -define(mysuite, ["-module(mysuite).\n", @@ -186,6 +205,10 @@ setup_basic_project() -> ok = file:write_file("test/myapp_mymod_tests.erl", ?myapp_mymod_tests), ok = file:write_file("src/myapp_mymod.erl", ?myapp_mymod). +setup_core_project() -> + setup_basic_project(), + ok = file:write_file("src/myapp_mycoremod.core", ?myapp_mycoremod). + setup_cover_project() -> setup_basic_project(), ok = file:write_file("rebar.config", "{cover_enabled, true}.\n").