diff options
-rw-r--r-- | src/rlx_app_discovery.erl | 11 | ||||
-rw-r--r-- | src/rlx_config.erl | 2 | ||||
-rw-r--r-- | src/rlx_prv_assembler.erl | 44 | ||||
-rw-r--r-- | src/rlx_state.erl | 12 | ||||
-rw-r--r-- | test/rlx_release_SUITE.erl | 30 |
5 files changed, 94 insertions, 5 deletions
diff --git a/src/rlx_app_discovery.erl b/src/rlx_app_discovery.erl index 6ac8d11..3d58185 100644 --- a/src/rlx_app_discovery.erl +++ b/src/rlx_app_discovery.erl @@ -118,8 +118,10 @@ resolve_app_metadata(State, LibDirs) -> end] of [] -> SkipApps = rlx_state:skip_apps(State), - AppMeta1 = [App || {ok, App} <- setup_overrides(State, AppMeta0), - not lists:keymember(rlx_app_info:name(App), 1, SkipApps)], + ExcludeApps = rlx_state:exclude_apps(State), + AppMeta1 = [rm_exclude_apps(App, ExcludeApps) || + {ok, App} <- setup_overrides(State, AppMeta0), + not lists:keymember(rlx_app_info:name(App), 1, SkipApps++ExcludeApps)], ec_cmd_log:debug(rlx_state:log(State), fun() -> ["Resolved the following OTP Applications from the system: \n", @@ -129,6 +131,11 @@ resolve_app_metadata(State, LibDirs) -> Errors -> ?RLX_ERROR(Errors) end. +%% Apps listed in {exclude_apps, [...]} must be removed from applications lists +rm_exclude_apps(App, ExcludeApps) -> + ActiveApps = lists:subtract(rlx_app_info:active_deps(App), ExcludeApps), + LibraryApps = lists:subtract(rlx_app_info:library_deps(App), ExcludeApps), + rlx_app_info:library_deps(rlx_app_info:active_deps(App, ActiveApps), LibraryApps). app_name({warning, _}) -> undefined; diff --git a/src/rlx_config.erl b/src/rlx_config.erl index 045bf33..df08342 100644 --- a/src/rlx_config.erl +++ b/src/rlx_config.erl @@ -182,6 +182,8 @@ load_terms({add_providers, Providers0}, {ok, State0}) -> end; 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({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 ee81631..9799204 100644 --- a/src/rlx_prv_assembler.erl +++ b/src/rlx_prv_assembler.erl @@ -203,9 +203,49 @@ copy_app_(App, AppDir, TargetDir, IncludeSrc) -> remove_symlink_or_directory(TargetDir), case rlx_app_info:link(App) of true -> - link_directory(AppDir, TargetDir); + link_directory(AppDir, TargetDir), + rewrite_app_file(App, AppDir); false -> - copy_directory(AppDir, TargetDir, IncludeSrc) + copy_directory(AppDir, TargetDir, IncludeSrc), + rewrite_app_file(App, TargetDir) + end. + +%% If excluded apps exist in this App's applications list we must write a new .app +rewrite_app_file(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. + +write_file_if_contents_differ(Filename, Bytes) -> + ToWrite = iolist_to_binary(Bytes), + case file:read_file(Filename) of + {ok, ToWrite} -> + ok; + {ok, _} -> + file:write_file(Filename, ToWrite); + {error, _} -> + file:write_file(Filename, ToWrite) end. remove_symlink_or_directory(TargetDir) -> diff --git a/src/rlx_state.erl b/src/rlx_state.erl index f21b682..3bd818a 100644 --- a/src/rlx_state.erl +++ b/src/rlx_state.erl @@ -36,6 +36,8 @@ overrides/2, skip_apps/1, skip_apps/2, + exclude_apps/1, + exclude_apps/2, debug_info/1, debug_info/2, goals/1, @@ -104,6 +106,7 @@ sys_config :: file:filename() | undefined, overrides=[] :: [{AppName::atom(), Directory::file:filename()}], skip_apps=[] :: [AppName::atom()], + exclude_apps=[] :: [AppName::atom()], debug_info=keep :: keep | strip, configured_releases :: releases(), realized_releases :: releases(), @@ -186,6 +189,15 @@ skip_apps(#state_t{skip_apps=Apps}) -> skip_apps(State, SkipApps) -> State#state_t{skip_apps=SkipApps}. +-spec exclude_apps(t()) -> [AppName::atom()]. +exclude_apps(#state_t{exclude_apps=Apps}) -> + Apps. + +%% @doc the application overrides for the system +-spec exclude_apps(t(), [AppName::atom()]) -> t(). +exclude_apps(State, SkipApps) -> + State#state_t{exclude_apps=SkipApps}. + -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 f123e79..e7b6c22 100644 --- a/test/rlx_release_SUITE.erl +++ b/test/rlx_release_SUITE.erl @@ -29,6 +29,7 @@ make_scriptless_release/1, make_overridden_release/1, make_skip_app_release/1, + make_exclude_app_release/1, make_auto_skip_empty_app_release/1, make_app_type_none_release/1, make_rerun_overridden_release/1, @@ -68,7 +69,7 @@ init_per_testcase(_, Config) -> all() -> [make_release, make_extend_release, make_scriptless_release, make_overridden_release, make_auto_skip_empty_app_release, - make_skip_app_release, make_app_type_none_release, + make_skip_app_release, make_exclude_app_release, make_app_type_none_release, make_implicit_config_release, make_rerun_overridden_release, overlay_release, make_goalless_release, make_depfree_release, make_invalid_config_release, make_relup_release, make_relup_release2, @@ -309,6 +310,33 @@ make_skip_app_release(Config) -> ?assertNot(lists:member({goal_app_2, "0.0.1"}, AppSpecs)), ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)). +%% Test to ensure that an excluded app and its deps are not included in a release +make_exclude_app_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, non_goal_2], []), + rlx_test_utils:create_app(LibDir1, "non_goal_2", "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_apps, [non_goal_1]}]), + OutputDir = filename:join([proplists:get_value(data_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)), + ?assertNot(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), + ?assertNot(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), + ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)). + make_auto_skip_empty_app_release(Config) -> DataDir = proplists:get_value(data_dir, Config), EmptyAppDir1 = filename:join([DataDir, rlx_test_utils:create_random_name("skip_app_dir_")]), |