diff options
Diffstat (limited to 'lib/reltool')
14 files changed, 222 insertions, 49 deletions
diff --git a/lib/reltool/doc/src/notes.xml b/lib/reltool/doc/src/notes.xml index 6df4924d0a..25d983afd3 100644 --- a/lib/reltool/doc/src/notes.xml +++ b/lib/reltool/doc/src/notes.xml @@ -546,8 +546,8 @@ <p>The handling of applications included in releases has been improved. Applications that are required to be started before other applications in a release are now - automatically included in the release. The <c>kernel</c> - and <c>stdlib</c> applications are always included as + automatically included in the release. The Kernel + and STDLIB applications are always included as they are mandatory.</p> <p>Applications that are (explicitly or implicitly) included in a release are now automatically included as diff --git a/lib/reltool/doc/src/part.xml b/lib/reltool/doc/src/part.xml index 5904084879..e608d548ea 100644 --- a/lib/reltool/doc/src/part.xml +++ b/lib/reltool/doc/src/part.xml @@ -31,7 +31,7 @@ <rev>%VSN%</rev> </header> <description> - <p><c>Reltool</c> is a release management tool. It analyses a given + <p>Reltool is a release management tool. It analyses a given Erlang/OTP installation and determines various dependencies between applications. The <c>graphical</c> frontend depicts the dependencies and enables interactive customization of a diff --git a/lib/reltool/doc/src/ref_man.xml b/lib/reltool/doc/src/ref_man.xml index 38f270b79a..1684f075ff 100644 --- a/lib/reltool/doc/src/ref_man.xml +++ b/lib/reltool/doc/src/ref_man.xml @@ -31,7 +31,7 @@ <rev>%VSN%</rev> </header> <description> - <p><c>Reltool</c> is a release management tool. It analyses a given + <p>Reltool is a release management tool. It analyses a given Erlang/OTP installation and determines various dependencies between applications. The <c>graphical</c> frontend depicts the dependencies and enables interactive customization of a diff --git a/lib/reltool/doc/src/reltool.xml b/lib/reltool/doc/src/reltool.xml index 38448e7961..5bfbee966b 100644 --- a/lib/reltool/doc/src/reltool.xml +++ b/lib/reltool/doc/src/reltool.xml @@ -47,7 +47,7 @@ <p>The tool uses an installed Erlang/OTP system as input. <c>root_dir</c> is the root directory of the analysed system and - it defaults to the system executing <c>reltool</c>. Applications + it defaults to the system executing Reltool. Applications may also be located outside <c>root_dir</c>. <c>lib_dirs</c> defines library directories where additional applications may reside and it defaults to the directories @@ -56,7 +56,7 @@ <p>An application directory <c>AppDir</c> under a library directory is recognized by the existence of an <c>AppDir/ebin</c> - directory. If this does not exist, <c>reltool</c> will not + directory. If this does not exist, Reltool will not consider <c>AppDir</c> at all when looking for applications.</p> <p>It is recommended that application directories are named as the @@ -81,14 +81,14 @@ <tag><c>config</c></tag> <item> <p>This is the main option and it controls the configuration - of <c>reltool</c>. It can either be a <c>sys</c> tuple or + of Reltool. It can either be a <c>sys</c> tuple or a name of a <c>file</c> containing a sys tuple.</p> </item> <tag><c>trap_exit</c></tag> <item> <p>This option controls the error handling behavior of - <c>reltool</c>. By default the window processes traps + Reltool. By default the window processes traps exit, but this behavior can altered by setting <c>trap_exit</c> to <c>false</c>.</p> </item> diff --git a/lib/reltool/doc/src/reltool_intro.xml b/lib/reltool/doc/src/reltool_intro.xml index 8e232b8838..2980ad7977 100644 --- a/lib/reltool/doc/src/reltool_intro.xml +++ b/lib/reltool/doc/src/reltool_intro.xml @@ -34,7 +34,7 @@ <rev>%VSN%</rev> <file>reltool_intro.xml</file> </header> - <p><c>Reltool</c> is a release management tool. It analyses a given + <p>Reltool is a release management tool. It analyses a given Erlang/OTP installation and determines various dependencies between applications. The <c>graphical</c> frontend depicts the dependencies and enables interactive customization of a target system. The backend provides a @@ -82,7 +82,7 @@ and about the Erlang/OTP development system:</p> <list type="bulleted"> <item> - <p>the Reference Manual of <c>Reltool</c></p> + <p>the Reference Manual of Reltool</p> </item> <item> <p>the Erlang/OTP <c>System Principles</c></p> diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl index 9ac22b9450..89b5f3a997 100644 --- a/lib/reltool/src/reltool.hrl +++ b/lib/reltool/src/reltool.hrl @@ -154,19 +154,19 @@ -record(app_info, { - description = "" :: string(), - id = "" :: string(), - vsn = "" :: app_vsn(), - modules = [] :: [mod_name()], - maxP = infinity :: integer() | infinity, - maxT = infinity :: integer() | infinity, - registered = [] :: [atom()], - incl_apps = [] :: [app_name()], - applications = [] :: [app_name()], - env = [] :: [{atom(), term()}], - mod = undefined :: {mod_name(), [term()]} | undefined, - start_phases = undefined :: [{atom(), term()}] | undefined, - runtime_dependencies = [] :: [string()] + description = "" :: '_' | string(), + id = "" :: '_' | string(), + vsn = "" :: '_' | app_vsn(), + modules = [] :: '_' | [mod_name()], + maxP = infinity :: '_' | integer() | infinity, + maxT = infinity :: '_' | integer() | infinity, + registered = [] :: '_' | [atom()], + incl_apps = [] :: '_' | '$3' | [app_name()], + applications = [] :: '_' | '$2' | [app_name()], + env = [] :: '_' | [{atom(), term()}], + mod = undefined :: '_' | {mod_name(), [term()]} | undefined, + start_phases = undefined :: '_' | [{atom(), term()}] | undefined, + runtime_dependencies = [] :: '_' | [string()] }). -record(regexp, {source, compiled}). diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl index 21a4485f94..89e90670cf 100644 --- a/lib/reltool/src/reltool_server.erl +++ b/lib/reltool/src/reltool_server.erl @@ -530,9 +530,14 @@ analyse(#state{sys=Sys} = S, Apps, Status) -> %% Write all #app to app_tab and all #mod to mod_tab. Status2 = apps_init_is_included(S, Apps, RelApps, Status), + %% For each application that is not (directly or indirectly) part + %% of a release, but still has #app.is_included==true, propagate + %% is_included to the dependencies specified in the .app files. + app_propagate_is_included(S), + %% For each module that has #mod.is_included==true, propagate %% is_included to the modules it uses. - propagate_is_included(S), + mod_propagate_is_included(S), %% Insert reverse dependencies - i.e. for each %% #mod{name=Mod, uses_mods=[UsedMod]}, @@ -565,31 +570,34 @@ apps_in_rels(Rels, Apps) -> apps_in_rel(#rel{name = RelName, rel_apps = RelApps}, Apps) -> Mandatory = [{RelName, kernel}, {RelName, stdlib}], - Other = + Explicit0 = [{RelName, AppName} || #rel_app{name=AppName} <- RelApps], + Explicit = Mandatory ++ Explicit0, + Deps = [{RelName, AppName} || RA <- RelApps, - AppName <- [RA#rel_app.name | + AppName <- + case lists:keyfind(RA#rel_app.name, + #app.name, + Apps) of + App=#app{info = #app_info{applications = AA}} -> %% Included applications in rel shall overwrite included %% applications in .app. I.e. included applications in %% .app shall only be used if it is not defined in rel. - case RA#rel_app.incl_apps of - undefined -> - case lists:keyfind(RA#rel_app.name, - #app.name, - Apps) of - #app{info = #app_info{incl_apps = IA}} -> - IA; - false -> - reltool_utils:throw_error( - "Release ~tp uses non existing " - "application ~w", - [RelName,RA#rel_app.name]) - end; - IA -> - IA - end], - not lists:keymember(AppName, 2, Mandatory)], - more_apps_in_rels(Mandatory ++ Other, Apps, []). + IA = case RA#rel_app.incl_apps of + undefined -> + (App#app.info)#app_info.incl_apps; + RelIA -> + RelIA + end, + AA ++ IA; + false -> + reltool_utils:throw_error( + "Release ~tp uses non existing " + "application ~w", + [RelName,RA#rel_app.name]) + end, + not lists:keymember(AppName, 2, Explicit)], + more_apps_in_rels(Deps, Apps, Explicit). more_apps_in_rels([{RelName, AppName} = RA | RelApps], Apps, Acc) -> case lists:member(RA, Acc) of @@ -597,8 +605,8 @@ more_apps_in_rels([{RelName, AppName} = RA | RelApps], Apps, Acc) -> more_apps_in_rels(RelApps, Apps, Acc); false -> case lists:keyfind(AppName, #app.name, Apps) of - #app{info = #app_info{applications = InfoApps}} -> - Extra = [{RelName, N} || N <- InfoApps], + #app{info = #app_info{applications = AA, incl_apps=IA}} -> + Extra = [{RelName, N} || N <- AA++IA], Acc2 = more_apps_in_rels(Extra, Apps, [RA | Acc]), more_apps_in_rels(RelApps, Apps, Acc2); false -> @@ -610,7 +618,6 @@ more_apps_in_rels([{RelName, AppName} = RA | RelApps], Apps, Acc) -> more_apps_in_rels([], _Apps, Acc) -> Acc. - apps_init_is_included(S, Apps, RelApps, Status) -> lists:foldl(fun(App, AccStatus) -> app_init_is_included(S, App, RelApps, AccStatus) @@ -745,6 +752,100 @@ false_to_undefined(Bool) -> _ -> Bool end. +get_no_rel_apps_and_dependencies(S) -> + ets:select(S#state.app_tab, [{#app{name='$1', + is_included=true, + info=#app_info{applications='$2', + incl_apps='$3', + _='_'}, + rels=[], + _='_'}, + [], + [{{'$1','$2','$3'}}]}]). + +app_propagate_is_included(S) -> + lists:foreach( + fun({AppName,DepNames1,DepNames2}) -> + app_mark_is_included(S,AppName,DepNames1++DepNames2) + end, + get_no_rel_apps_and_dependencies(S)). + +app_mark_is_included(#state{app_tab=AppTab, mod_tab=ModTab, sys=Sys}=S,UsedByName,[AppName|AppNames]) -> + case ets:lookup(AppTab, AppName) of + [A] -> + case A#app.is_included of + undefined -> + %% Not yet marked => mark and propagate + A2 = + case A#app.incl_cond of + include -> + A#app{is_pre_included = true, + is_included = true}; + exclude -> + A#app{is_pre_included = false, + is_included = false}; + AppInclCond when AppInclCond==undefined; + AppInclCond==derived -> + A#app{is_included = true} + end, + ets:insert(AppTab, A2), + + ModCond = + case A#app.mod_cond of + undefined -> Sys#sys.mod_cond; + _ -> A#app.mod_cond + end, + Filter = + fun(M) -> + case ModCond of + all -> true; + app -> M#mod.is_app_mod; + ebin -> M#mod.is_ebin_mod; + derived -> false; + none -> false + end + end, + Mods = lists:filter(Filter, A#app.mods), + %% Mark the modules of this app, but no need to go + %% recursive on modules since this is done in + %% mod_mark_is_included. + [case M#mod.is_included of + undefined -> + M2 = + case M#mod.incl_cond of + include -> + M#mod{is_pre_included = true, + is_included = true}; + exclude -> + M#mod{is_pre_included = false, + is_included = false}; + ModInclCond when ModInclCond==undefined; + ModInclCond==derived -> + M#mod{is_included = true} + end, + ets:insert(ModTab, M2); + _ -> + ok + end || M <- Mods], + + %% Go recursive on dependencies + #app{info=#app_info{applications=DepNames1, + incl_apps=DepNames2}} = A, + app_mark_is_included(S,AppName,DepNames1++DepNames2); + _ -> + %% Already marked + ok + end; + [] -> + %% Missing app + reltool_utils:throw_error( + "Application ~tp uses non existing application ~w", + [UsedByName,AppName]) + end, + app_mark_is_included(S, UsedByName, AppNames); +app_mark_is_included(_S, _UsedByName, []) -> + ok. + %% Return the list for {ModName, UsesModNames} for all modules where %% #mod.is_included==true. get_all_mods_and_dependencies(S) -> @@ -755,7 +856,7 @@ get_all_mods_and_dependencies(S) -> [], [{{'$1','$2'}}]}]). -propagate_is_included(S) -> +mod_propagate_is_included(S) -> case lists:flatmap( fun({ModName,UsesModNames}) -> mod_mark_is_included(S,ModName,UsesModNames,[]) diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl index e9bd46fb27..e8dfea94da 100644 --- a/lib/reltool/test/reltool_server_SUITE.erl +++ b/lib/reltool/test/reltool_server_SUITE.erl @@ -142,6 +142,7 @@ all() -> save_config, dependencies, mod_incl_cond_derived, + dep_in_app_not_xref, use_selected_vsn, use_selected_vsn_relative_path, non_standard_vsn_id, @@ -408,7 +409,6 @@ create_release_sort(Config) -> {app,tools,[{mod_cond,app},{incl_cond,include}]} ]}, %% Generate release - ?msym({ok, {release, {RelName1, RelVsn}, {erts, _}, [{kernel, _}, @@ -2304,6 +2304,7 @@ dependencies(Config) -> ok. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Test that incl_cond on mod level overwrites mod_cond on app level %% Uses same test applications as dependencies/1 above mod_incl_cond_derived(Config) -> @@ -2346,6 +2347,40 @@ mod_incl_cond_derived(Config) -> ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% ERL-167, OTP-11993: For applications that are not included in a +%% release spec ('rel'), dependencies in the .app files are not +%% considered - only those found with xref. +dep_in_app_not_xref(Config) -> + RelName = "Just testing...", + RelVsn = "1.0", + Sys = + {sys, + [ + {lib_dirs,[filename:join(datadir(Config),"dep_in_app_not_xref")]}, + {incl_cond,exclude}, + {incl_archive_filters,[]}, + {erts,[{incl_cond,exclude}]}, + {boot_rel, RelName}, + {rel, RelName, RelVsn, [kernel, stdlib]}, + {app,kernel,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,x,[{incl_cond,include}]}, + {app,y,[{incl_cond,derived}]}, + {app,z,[{incl_cond,derived}]} + ]}, + + TargetDir = filename:join([?WORK_DIR, "target_dep_in_app_not_xref"]), + ?m(ok, reltool_utils:recursive_delete(TargetDir)), + ?m(ok, file:make_dir(TargetDir)), + ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Sys}])]), + ok = ?m(ok, reltool:create_target([{config, Sys}], TargetDir)), + ?log("~p~n",[file:list_dir(filename:join([TargetDir,"lib"]))]), + + ?m(true, filelib:is_dir(filename:join([TargetDir,"lib","y-1.0"]))), + ?m(true, filelib:is_dir(filename:join([TargetDir,"lib","z-1.0"]))), + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% use_selected_vsn(Config) -> LibDir1 = filename:join(datadir(Config),"use_selected_vsn"), B1Dir = filename:join(LibDir1,"b-1.0"), diff --git a/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/x-1.0/ebin/x.app b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/x-1.0/ebin/x.app new file mode 100644 index 0000000000..fe922e3a41 --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/x-1.0/ebin/x.app @@ -0,0 +1,7 @@ +% -*-erlang-*- +{application, x, + [{description, "Main application in reltool dependency test"}, + {vsn, "1.0"}, + {modules, [x1]}, + {registered, []}, + {applications, [kernel, stdlib, y]}]}. diff --git a/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/x-1.0/src/x1.erl b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/x-1.0/src/x1.erl new file mode 100644 index 0000000000..bf1e7f9279 --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/x-1.0/src/x1.erl @@ -0,0 +1,5 @@ +-module(x1). +-compile(export_all). + +f() -> + ok. diff --git a/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/y-1.0/ebin/y.app b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/y-1.0/ebin/y.app new file mode 100644 index 0000000000..a21cfe6c21 --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/y-1.0/ebin/y.app @@ -0,0 +1,8 @@ +% -*-erlang-*- +{application, y, + [{description, "Library application in reltool dependency test"}, + {vsn, "1.0"}, + {modules, [y1]}, + {registered, []}, + {applications, [kernel, stdlib]}, + {included_applications, [z]}]}. diff --git a/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/y-1.0/src/y1.erl b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/y-1.0/src/y1.erl new file mode 100644 index 0000000000..902a7e21f3 --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/y-1.0/src/y1.erl @@ -0,0 +1,5 @@ +-module(y1). +-compile(export_all). + +f() -> + ok. diff --git a/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/z-1.0/ebin/z.app b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/z-1.0/ebin/z.app new file mode 100644 index 0000000000..437a0968e9 --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/z-1.0/ebin/z.app @@ -0,0 +1,7 @@ +% -*-erlang-*- +{application, z, + [{description, "Library application in reltool dependency test"}, + {vsn, "1.0"}, + {modules, [z1]}, + {registered, []}, + {applications, [kernel, stdlib]}]}. diff --git a/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/z-1.0/src/z1.erl b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/z-1.0/src/z1.erl new file mode 100644 index 0000000000..97ef90b87f --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/z-1.0/src/z1.erl @@ -0,0 +1,5 @@ +-module(z1). +-compile(export_all). + +f() -> + ok. |