From 02af35eff609634347448fa7fd197aa5a503b00e Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Sat, 29 Sep 2018 12:33:28 -0600 Subject: [PATCH] fix check that modules in .app modules list are from src_dirs --- rebar.config | 1 + src/rebar3.erl | 1 - src/rebar_compiler.erl | 3 +- src/rebar_otp_app.erl | 35 ++++++------------ src/rebar_utils.erl | 80 +++++++++++++++++++++++++++++++++++++++--- 5 files changed, 87 insertions(+), 33 deletions(-) diff --git a/rebar.config b/rebar.config index f481e285..41a622bb 100644 --- a/rebar.config +++ b/rebar.config @@ -33,6 +33,7 @@ {erl_opts, [{platform_define, "^[0-9]+", namespaced_types}, {platform_define, "^(19|2)", rand_only}, {platform_define, "^2", unicode_str}, + {platform_define, "^2", filelib_find_source}, {platform_define, "^(R|1|20)", fun_stacktrace}, warnings_as_errors ]}. diff --git a/src/rebar3.erl b/src/rebar3.erl index 3bc66678..c931a855 100644 --- a/src/rebar3.erl +++ b/src/rebar3.erl @@ -411,7 +411,6 @@ test_state(State) -> ProfileOpts = proplists:get_value(test, Profiles, []), ErlOpts = proplists:get_value(erl_opts, ProfileOpts, []), TestOpts = safe_define_test_macro(ErlOpts), - %% [{erl_opts, TestOpts}]. [{extra_src_dirs, ["test"]}, {erl_opts, TestOpts}]. -spec safe_define_test_macro([any()]) -> [any()] | [{'d',atom()} | any()]. diff --git a/src/rebar_compiler.erl b/src/rebar_compiler.erl index b75bad4a..c2c514a9 100644 --- a/src/rebar_compiler.erl +++ b/src/rebar_compiler.erl @@ -24,7 +24,7 @@ ok | {ok, [string()]} | {ok, [string()], [string()]}. -define(DAG_VSN, 2). --define(DAG_FILE, "erlcinfo"). +-define(DAG_FILE, "source.dag"). -type dag_v() :: {digraph:vertex(), term()} | 'false'. -type dag_e() :: {digraph:vertex(), digraph:vertex()}. -type dag() :: {list(dag_v()), list(dag_e()), list(string())}. @@ -132,7 +132,6 @@ run_on_extra_src_dirs([Dir | Rest], CompilerMod, AppInfo, Fun) -> end, run_on_extra_src_dirs(Rest, CompilerMod, AppInfo, Fun). - %% These functions are here for the ultimate goal of getting rid of %% rebar_base_compiler. This can't be done because of existing plugins. diff --git a/src/rebar_otp_app.erl b/src/rebar_otp_app.erl index 1d854da3..33e35adb 100644 --- a/src/rebar_otp_app.erl +++ b/src/rebar_otp_app.erl @@ -125,7 +125,7 @@ preprocess(State, AppInfo, AppSrcFile) -> %% Setup file .app filename and write new contents EbinDir = rebar_app_info:ebin_dir(AppInfo), - filelib:ensure_dir(filename:join(EbinDir, "dummy.beam")), + rebar_file_utils:ensure_dir(EbinDir), AppFile = rebar_app_utils:app_src_to_app(OutDir, AppSrcFile), ok = rebar_file_utils:write_file_if_contents_differ(AppFile, Spec, utf8), @@ -163,32 +163,17 @@ validate_name(AppName, File) -> ebin_modules(AppInfo, Dir) -> Beams = lists:sort(rebar_utils:beams(filename:join(Dir, "ebin"))), - ExtraDirs = extra_dirs(AppInfo), - F = fun(Beam) -> not in_extra_dir(AppInfo, Beam, ExtraDirs) end, - Filtered = lists:filter(F, Beams), + SrcDirs = rebar_dir:src_dirs(rebar_app_info:opts(AppInfo), ["src"]), + FindSourceRules = [{".beam", ".erl", + [{"ebin", SrcDir} || SrcDir <- SrcDirs]}], + Filtered = lists:filter(fun(Beam) -> + rebar_utils:find_source(filename:basename(Beam), + filename:dirname(Beam), + FindSourceRules) + =/= {error, not_found} + end, Beams), [rebar_utils:beam_to_mod(N) || N <- Filtered]. -extra_dirs(State) -> - Extras = rebar_dir:extra_src_dirs(rebar_app_info:opts(State)), - SrcDirs = rebar_dir:src_dirs(rebar_app_info:opts(State), ["src"]), - %% remove any dirs that are defined in `src_dirs` from `extra_src_dirs` - Extras -- SrcDirs. - -in_extra_dir(AppInfo, Beam, Dirs) -> - lists:any(fun(Dir) -> lists:prefix(filename:join([rebar_app_info:out_dir(AppInfo), Dir]), - beam_src(Beam)) end, - Dirs). - -beam_src(Beam) -> - case beam_lib:chunks(Beam, [compile_info]) of - {ok, {_mod, Chunks}} -> - CompileInfo = proplists:get_value(compile_info, Chunks, []), - proplists:get_value(source, CompileInfo, []); - {error, beam_lib, Reason} -> - ?WARN("Couldn't read debug info from ~p for reason: ~p", [Beam, Reason]), - [] - end. - ensure_registered(AppData) -> case lists:keyfind(registered, 1, AppData) of false -> diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl index 5d773056..419802a6 100644 --- a/src/rebar_utils.erl +++ b/src/rebar_utils.erl @@ -38,8 +38,8 @@ find_files/2, find_files/3, find_files_in_dirs/3, + find_source/3, beam_to_mod/1, - beam_to_mod/2, erl_to_mod/1, beams/1, find_executable/1, @@ -678,10 +678,6 @@ sh_loop(Port, Fun, Acc) -> end end. -beam_to_mod(Dir, Filename) -> - [Dir | Rest] = filename:split(Filename), - list_to_atom(filename:basename(rebar_string:join(Rest, "."), ".beam")). - beam_to_mod(Filename) -> list_to_atom(filename:basename(Filename, ".beam")). @@ -1081,3 +1077,77 @@ version_pad([Major, Minor, Patch]) -> {list_to_integer(Major), list_to_integer(Minor), list_to_integer(Patch)}; version_pad([Major, Minor, Patch | _]) -> {list_to_integer(Major), list_to_integer(Minor), list_to_integer(Patch)}. + + +-ifdef(filelib_find_source). +find_source(Filename, Dir, Rules) -> + filelib:find_source(Filename, Dir, Rules). +-else. +%% Looks for a file relative to a given directory + +-type find_file_rule() :: {ObjDirSuffix::string(), SrcDirSuffix::string()}. + +%% Looks for a source file relative to the object file name and directory + +-type find_source_rule() :: {ObjExtension::string(), SrcExtension::string(), + [find_file_rule()]}. + +keep_suffix_search_rules(Rules) -> + [T || {_,_,_}=T <- Rules]. + +-spec find_source(file:filename(), file:filename(), [find_source_rule()]) -> + {ok, file:filename()} | {error, not_found}. +find_source(Filename, Dir, Rules) -> + try_suffix_rules(keep_suffix_search_rules(Rules), Filename, Dir). + +try_suffix_rules(Rules, Filename, Dir) -> + Ext = filename:extension(Filename), + try_suffix_rules(Rules, filename:rootname(Filename, Ext), Dir, Ext). + +try_suffix_rules([{Ext,Src,Rules}|Rest], Root, Dir, Ext) + when is_list(Src), is_list(Rules) -> + case try_dir_rules(add_local_search(Rules), Root ++ Src, Dir) of + {ok, File} -> {ok, File}; + _Other -> + try_suffix_rules(Rest, Root, Dir, Ext) + end; +try_suffix_rules([_|Rest], Root, Dir, Ext) -> + try_suffix_rules(Rest, Root, Dir, Ext); +try_suffix_rules([], _Root, _Dir, _Ext) -> + {error, not_found}. + +%% ensuring we check the directory of the object file before any other directory +add_local_search(Rules) -> + Local = {"",""}, + [Local] ++ lists:filter(fun (X) -> X =/= Local end, Rules). + +try_dir_rules([{From, To}|Rest], Filename, Dir) + when is_list(From), is_list(To) -> + case try_dir_rule(Dir, Filename, From, To) of + {ok, File} -> {ok, File}; + error -> try_dir_rules(Rest, Filename, Dir) + end; +try_dir_rules([], _Filename, _Dir) -> + {error, not_found}. + +try_dir_rule(Dir, Filename, From, To) -> + case lists:suffix(From, Dir) of + true -> + NewDir = lists:sublist(Dir, 1, length(Dir)-length(From))++To, + Src = filename:join(NewDir, Filename), + case filelib:is_regular(Src) of + true -> {ok, Src}; + false -> find_regular_file(filelib:wildcard(Src)) + end; + false -> + error + end. + +find_regular_file([]) -> + error; +find_regular_file([File|Files]) -> + case filelib:is_regular(File) of + true -> {ok, File}; + false -> find_regular_file(Files) + end. +-endif.