diff options
author | Tristan Sloughter <[email protected]> | 2016-11-26 11:14:03 -0800 |
---|---|---|
committer | GitHub <[email protected]> | 2016-11-26 11:14:03 -0800 |
commit | 81aa66f952f494568428ff8f547e29b92117b776 (patch) | |
tree | 3f73ccce546074bdb7c3f1d886751022dd32a38d | |
parent | aa37a7c556094c356a719ded1d30f7749a3c11f7 (diff) | |
parent | 81369d99a9b6ee5caae6b5e6a5faffb8a65fb588 (diff) | |
download | relx-81aa66f952f494568428ff8f547e29b92117b776.tar.gz relx-81aa66f952f494568428ff8f547e29b92117b776.tar.bz2 relx-81aa66f952f494568428ff8f547e29b92117b776.zip |
Merge pull request #541 from lrascao/feature/exclude_modules
Provide a new config directive that allows per-app module exclusion
-rw-r--r-- | src/rlx_config.erl | 2 | ||||
-rw-r--r-- | src/rlx_prv_assembler.erl | 102 | ||||
-rw-r--r-- | src/rlx_state.erl | 14 | ||||
-rw-r--r-- | test/rlx_release_SUITE.erl | 45 | ||||
-rw-r--r-- | test/rlx_test_utils.erl | 39 |
5 files changed, 154 insertions, 48 deletions
diff --git a/src/rlx_config.erl b/src/rlx_config.erl index 1dbfa13..dfcb511 100644 --- a/src/rlx_config.erl +++ b/src/rlx_config.erl @@ -173,6 +173,8 @@ load_terms({skip_apps, SkipApps0}, {ok, State0}) -> {ok, rlx_state:skip_apps(State0, SkipApps0)}; load_terms({exclude_apps, ExcludeApps0}, {ok, State0}) -> {ok, rlx_state:exclude_apps(State0, ExcludeApps0)}; +load_terms({exclude_modules, ExcludeModules0}, {ok, State0}) -> + {ok, rlx_state:exclude_modules(State0, ExcludeModules0)}; load_terms({debug_info, DebugInfo}, {ok, State0}) -> {ok, rlx_state:debug_info(State0, DebugInfo)}; load_terms({overrides, Overrides0}, {ok, State0}) -> diff --git a/src/rlx_prv_assembler.erl b/src/rlx_prv_assembler.erl index 6074a1b..a17d0f4 100644 --- a/src/rlx_prv_assembler.erl +++ b/src/rlx_prv_assembler.erl @@ -162,7 +162,7 @@ copy_app_directories_to_output(State, Release, OutputDir) -> false end, lists:flatten(ec_plists:map(fun(App) -> - copy_app(LibDir, App, IncludeSrc, IncludeErts) + copy_app(State, LibDir, App, IncludeSrc, IncludeErts) end, Apps))), case Result of [E | _] -> @@ -179,7 +179,7 @@ prepare_applications(State, Apps) -> Apps end. -copy_app(LibDir, App, IncludeSrc, IncludeErts) -> +copy_app(State, LibDir, App, IncludeSrc, IncludeErts) -> AppName = erlang:atom_to_list(rlx_app_info:name(App)), AppVsn = rlx_app_info:original_vsn(App), AppDir = rlx_app_info:dir(App), @@ -196,52 +196,67 @@ copy_app(LibDir, App, IncludeSrc, IncludeErts) -> true -> []; false -> - copy_app_(App, AppDir, TargetDir, IncludeSrc) + copy_app_(State, App, AppDir, TargetDir, IncludeSrc) end; _ -> - copy_app_(App, AppDir, TargetDir, IncludeSrc) + copy_app_(State, App, AppDir, TargetDir, IncludeSrc) end end. is_erts_lib(Dir) -> lists:prefix(filename:split(list_to_binary(code:lib_dir())), filename:split(Dir)). -copy_app_(App, AppDir, TargetDir, IncludeSrc) -> +copy_app_(State, App, AppDir, TargetDir, IncludeSrc) -> remove_symlink_or_directory(TargetDir), case rlx_app_info:link(App) of true -> link_directory(AppDir, TargetDir), - rewrite_app_file(App, AppDir); + rewrite_app_file(State, App, AppDir); false -> - copy_directory(AppDir, TargetDir, IncludeSrc), - rewrite_app_file(App, TargetDir) + copy_directory(State, App, AppDir, TargetDir, IncludeSrc), + rewrite_app_file(State, App, TargetDir) end. %% If excluded apps exist in this App's applications list we must write a new .app -rewrite_app_file(App, TargetDir) -> +rewrite_app_file(State, App, TargetDir) -> Name = rlx_app_info:name(App), ActiveDeps = rlx_app_info:active_deps(App), IncludedDeps = rlx_app_info:library_deps(App), AppFile = filename:join([TargetDir, "ebin", ec_cnv:to_list(Name) ++ ".app"]), - {ok, [{application, AppName, AppData}]} = file:consult(AppFile), - OldActiveDeps = proplists:get_value(applications, AppData, []), - OldIncludedDeps = proplists:get_value(included_applications, AppData, []), - - case {OldActiveDeps, OldIncludedDeps} of - {ActiveDeps, IncludedDeps} -> - ok; - _ -> - AppData1 = lists:keyreplace(applications - ,1 - ,AppData - ,{applications, ActiveDeps}), - AppData2 = lists:keyreplace(included_applications - ,1 - ,AppData1 - ,{included_applications, IncludedDeps}), - Spec = io_lib:format("~p.\n", [{application, AppName, AppData2}]), - write_file_if_contents_differ(AppFile, Spec) - end. + {ok, [{application, AppName, AppData0}]} = file:consult(AppFile), + OldActiveDeps = proplists:get_value(applications, AppData0, []), + OldIncludedDeps = proplists:get_value(included_applications, AppData0, []), + OldModules = proplists:get_value(modules, AppData0, []), + ExcludedModules = proplists:get_value(Name, + rlx_state:exclude_modules(State), []), + + %% maybe replace excluded apps + AppData2 = + case {OldActiveDeps, OldIncludedDeps} of + {ActiveDeps, IncludedDeps} -> + AppData0; + _ -> + AppData1 = lists:keyreplace(applications + ,1 + ,AppData0 + ,{applications, ActiveDeps}), + lists:keyreplace(included_applications + ,1 + ,AppData1 + ,{included_applications, IncludedDeps}) + end, + %% maybe replace excluded modules + AppData3 = + case ExcludedModules of + [] -> AppData2; + _ -> + lists:keyreplace(modules + ,1 + ,AppData2 + ,{modules, OldModules -- ExcludedModules}) + end, + Spec = io_lib:format("~p.\n", [{application, AppName, AppData3}]), + write_file_if_contents_differ(AppFile, Spec). write_file_if_contents_differ(Filename, Bytes) -> ToWrite = iolist_to_binary(Bytes), @@ -275,8 +290,8 @@ link_directory(AppDir, TargetDir) -> ok end. -copy_directory(AppDir, TargetDir, IncludeSrc) -> - [copy_dir(AppDir, TargetDir, SubDir) +copy_directory(State, App, AppDir, TargetDir, IncludeSrc) -> + [copy_dir(State, App, AppDir, TargetDir, SubDir) || SubDir <- ["ebin", "include", "priv", @@ -289,13 +304,20 @@ copy_directory(AppDir, TargetDir, IncludeSrc) -> [] end]]. -copy_dir(AppDir, TargetDir, SubDir) -> +copy_dir(State, App, AppDir, TargetDir, SubDir) -> SubSource = filename:join(AppDir, SubDir), SubTarget = filename:join(TargetDir, SubDir), case ec_file:is_dir(SubSource) of true -> ok = rlx_util:mkdir_p(SubTarget), - case ec_file:copy(SubSource, SubTarget, [recursive]) of + %% get a list of the modules to be excluded from this app + AppName = rlx_app_info:name(App), + ExcludedModules = proplists:get_value(AppName, rlx_state:exclude_modules(State), + []), + ExcludedFiles = [filename:join([binary_to_list(SubSource), + atom_to_list(M) ++ ".beam"]) || + M <- ExcludedModules], + case copy_dir(SubSource, SubTarget, ExcludedFiles) of {error, E} -> ?RLX_ERROR({ec_file_error, AppDir, SubTarget, E}); ok -> @@ -305,6 +327,22 @@ copy_dir(AppDir, TargetDir, SubDir) -> ok end. +%% no files are excluded, just copy the whole dir +copy_dir(SourceDir, TargetDir, []) -> + case ec_file:copy(SourceDir, TargetDir, [recursive]) of + {error, E} -> {error, E}; + ok -> + ok + end; +copy_dir(SourceDir, TargetDir, ExcludeFiles) -> + SourceFiles = filelib:wildcard( + filename:join([binary_to_list(SourceDir), "*"])), + lists:foreach(fun(F) -> + ok = ec_file:copy(F, + filename:join([TargetDir, + filename:basename(F)])) + end, SourceFiles -- ExcludeFiles). + create_release_info(State0, Release0, OutputDir) -> RelName = atom_to_list(rlx_release:name(Release0)), ReleaseDir = rlx_util:release_output_dir(State0, Release0), diff --git a/src/rlx_state.erl b/src/rlx_state.erl index 6974d52..75a5cba 100644 --- a/src/rlx_state.erl +++ b/src/rlx_state.erl @@ -82,7 +82,9 @@ upfrom/1, upfrom/2, format/1, - format/2]). + format/2, + exclude_modules/1, + exclude_modules/2]). -export_type([t/0, @@ -107,6 +109,7 @@ overrides=[] :: [{AppName::atom(), Directory::file:filename()}], skip_apps=[] :: [AppName::atom()], exclude_apps=[] :: [AppName::atom()], + exclude_modules=[] :: [{App::atom(), [Module::atom()]}], debug_info=keep :: keep | strip, configured_releases :: releases(), realized_releases :: releases(), @@ -200,6 +203,15 @@ exclude_apps(#state_t{exclude_apps=Apps}) -> exclude_apps(State, SkipApps) -> State#state_t{exclude_apps=SkipApps}. +-spec exclude_modules(t()) -> [{App::atom(), [Module::atom()]}]. +exclude_modules(#state_t{exclude_modules=Modules}) -> + Modules. + +%% @doc modules to be excluded from the release +-spec exclude_modules(t(), [{App::atom(), [Module::atom()]}]) -> t(). +exclude_modules(State, SkipModules) -> + State#state_t{exclude_modules=SkipModules}. + -spec debug_info(t()) -> keep | strip. debug_info(#state_t{debug_info=DebugInfo}) -> DebugInfo. diff --git a/test/rlx_release_SUITE.erl b/test/rlx_release_SUITE.erl index a017297..c9430fd 100644 --- a/test/rlx_release_SUITE.erl +++ b/test/rlx_release_SUITE.erl @@ -55,7 +55,8 @@ make_included_nodetool_release/1, make_not_included_nodetool_release/1, make_src_release/1, - make_excluded_src_release/1]). + make_excluded_src_release/1, + make_exclude_modules_release/1]). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -91,7 +92,7 @@ all() -> make_config_script_release, make_release_twice, make_release_twice_dev_mode, make_erts_release, make_erts_config_release, make_included_nodetool_release, make_not_included_nodetool_release, - make_src_release, make_excluded_src_release]. + make_src_release, make_excluded_src_release, make_exclude_modules_release]. add_providers(Config) -> LibDir1 = proplists:get_value(lib1, Config), @@ -1401,6 +1402,46 @@ make_excluded_src_release(Config) -> ?assert(not ec_file:exists(filename:join([OutputDir, "foo", "lib", "goal_app_1-0.0.1", "src"]))). +%% Test to ensure that excluded modules don't end up in the release +make_exclude_modules_release(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel, non_goal_1], []), + rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], []), + + ConfigFile = filename:join([LibDir1, "relx.config"]), + rlx_test_utils:write_config(ConfigFile, + [{release, {foo, "0.0.1"}, + [goal_app_1]}, + {exclude_modules, [{non_goal_1, [a_real_beamnon_goal_1]}]}]), + OutputDir = filename:join([proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")]), + {ok, Cwd} = file:get_cwd(), + {ok, State} = relx:do(Cwd, undefined, undefined, [], [LibDir1], 3, + OutputDir, [], + ConfigFile), + [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rlx_state:realized_releases(State)), + AppSpecs = rlx_release:applications(Release), + ?assert(lists:keymember(stdlib, 1, AppSpecs)), + ?assert(lists:keymember(kernel, 1, AppSpecs)), + ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)), + %% ensure that the excluded module beam file didn't get copied + ?assert(not ec_file:exists(filename:join([OutputDir, "foo", "lib", + "non_goal_1-0.0.1", "ebin", + "a_real_beamnon_goal_1.beam"]))), + + ?assertMatch({ok, [{application,non_goal_1, + [{description,[]}, + {vsn,"0.0.1"}, + {modules,[]}, + {included_applications,[]}, + {registered,[]}, + {applications,[stdlib,kernel]}]}]}, + file:consult(filename:join([OutputDir, "foo", "lib", + "non_goal_1-0.0.1", "ebin", + "non_goal_1.app"]))). + + %%%=================================================================== %%% Helper Functions %%%=================================================================== diff --git a/test/rlx_test_utils.erl b/test/rlx_test_utils.erl index f120c75..12d757f 100644 --- a/test/rlx_test_utils.erl +++ b/test/rlx_test_utils.erl @@ -6,9 +6,9 @@ create_app(Dir, Name, Vsn, Deps, LibDeps) -> AppDir = filename:join([Dir, Name ++ "-" ++ Vsn]), - write_app_file(AppDir, Name, Vsn, Deps, LibDeps), + write_app_file(AppDir, Name, Vsn, app_modules(Name), Deps, LibDeps), write_src_file(AppDir, Name), - write_beam_file(AppDir, Name), + compile_src_files(AppDir), rlx_app_info:new(erlang:list_to_atom(Name), Vsn, AppDir, Deps, []). @@ -21,19 +21,18 @@ create_full_app(Dir, Name, Vsn, Deps, LibDeps) -> create_empty_app(Dir, Name, Vsn, Deps, LibDeps) -> AppDir = filename:join([Dir, Name ++ "-" ++ Vsn]), - write_app_file(AppDir, Name, Vsn, Deps, LibDeps), + write_app_file(AppDir, Name, Vsn, [], Deps, LibDeps), rlx_app_info:new(erlang:list_to_atom(Name), Vsn, AppDir, Deps, []). -write_beam_file(Dir, Name) -> - Beam = filename:join([Dir, "ebin", "not_a_real_beam" ++ Name ++ ".beam"]), - ok = filelib:ensure_dir(Beam), - ok = ec_file:write_term(Beam, testing_purposes_only). +app_modules(Name) -> + [list_to_atom(M ++ Name) || + M <- ["a_real_beam"]]. write_src_file(Dir, Name) -> - Src = filename:join([Dir, "src", "not_a_real_beam" ++ Name ++ ".erl"]), + Src = filename:join([Dir, "src", "a_real_beam" ++ Name ++ ".erl"]), ok = filelib:ensure_dir(Src), - ok = ec_file:write_term(Src, testing_purposes_only). + ok = file:write_file(Src, beam_file_contents("a_real_beam"++Name)). write_appup_file(AppInfo, DownVsn) -> Dir = rlx_app_info:dir(AppInfo), @@ -43,16 +42,27 @@ write_appup_file(AppInfo, DownVsn) -> ok = filelib:ensure_dir(Filename), ok = ec_file:write_term(Filename, {Vsn, [{DownVsn, []}], [{DownVsn, []}]}). -write_app_file(Dir, Name, Version, Deps, LibDeps) -> +write_app_file(Dir, Name, Version, Modules, Deps, LibDeps) -> Filename = filename:join([Dir, "ebin", Name ++ ".app"]), ok = filelib:ensure_dir(Filename), - ok = ec_file:write_term(Filename, get_app_metadata(Name, Version, Deps, LibDeps)). + ok = ec_file:write_term(Filename, get_app_metadata(Name, Version, Modules, + Deps, LibDeps)). + +compile_src_files(Dir) -> + %% compile all *.erl files in src to ebin + SrcDir = filename:join([Dir, "src"]), + OutputDir = filename:join([Dir, "ebin"]), + lists:foreach(fun(SrcFile) -> + {ok, _} = compile:file(SrcFile, [{outdir, OutputDir}, + return_errors]) + end, ec_file:find(SrcDir, "\\.erl")), + ok. -get_app_metadata(Name, Vsn, Deps, LibDeps) -> +get_app_metadata(Name, Vsn, Modules, Deps, LibDeps) -> {application, erlang:list_to_atom(Name), [{description, ""}, {vsn, Vsn}, - {modules, []}, + {modules, Modules}, {included_applications, LibDeps}, {registered, []}, {applications, Deps}]}. @@ -161,6 +171,9 @@ write_config(Filename, Values) -> ok = ec_file:write(Filename, [io_lib:format("~p.\n", [Val]) || Val <- Values]). +beam_file_contents(Name) -> + "-module("++Name++").". + test_template_contents() -> "{erts_vsn, \"{{erts_vsn}}\"}.\n" "{release_erts_version, \"{{release_erts_version}}\"}.\n" |