From 40014d4b190c86044df5f1aa70dad7138d531b7b Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Wed, 4 Jan 2012 16:09:01 +0100
Subject: [reltool] Add more test cases and fix bugs
OTP-9794
The following test cases are added for the inteface from GUI to
reltool_server:
* get_config
* get_apps
* set_app_and_undo
* set_apps_and_undo
* load_config_and_undo
* reset_config_and_undo
* save_config
The following bugs were found and corrected:
* If set_apps failed, then the state of reltool_server would not
be reset to how it was before the failing operation - and every
operation done afterwards would also (seem to) fail.
* undo_config did not work after reset_config - since faulty #sys
record was stored as old_sys.
* undo_config did not work after set_app (used when changing the
content of an application from the GUI) - since old_sys was not
set. Also old_status was not set causing possible warnings to
disappear.
* undo_config did not work after set_apps (used e.g. when
excluding or including an application from the GUI) - since
old_sys was not set. Also old_status was not set causing
possible warnings to disappear.
---
lib/reltool/src/reltool.hrl | 6 +-
lib/reltool/src/reltool_server.erl | 59 ++--
lib/reltool/test/reltool_server_SUITE.erl | 391 ++++++++++++++++++++-
.../faulty_app_file/a-1.0/ebin/a.app | 1 +
.../faulty_app_file/a-1.0/src/a.erl | 49 +++
.../faulty_app_file/a-1.0/src/a_sup.erl | 37 ++
6 files changed, 509 insertions(+), 34 deletions(-)
create mode 100644 lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/ebin/a.app
create mode 100644 lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/src/a.erl
create mode 100644 lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/src/a_sup.erl
diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl
index 93f47f6381..8e80c80e10 100644
--- a/lib/reltool/src/reltool.hrl
+++ b/lib/reltool/src/reltool.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -199,8 +199,8 @@
used_by_mods :: [mod_name()],
uses_apps :: [app_name()],
used_by_apps :: [app_name()],
- is_pre_included :: boolean(),
- is_included :: boolean(),
+ is_pre_included :: boolean() | undefined,
+ is_included :: boolean() | undefined,
rels :: [rel_name()]
}).
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index 692baea0a4..fdb9e08a90 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -254,7 +254,7 @@ loop(#state{common = C, sys = Sys} = S) ->
{S2, Status} = parse_options(S#state.options),
S3 = shrink_sys(S2),
{S4, Status2} = refresh(S3, true, Status),
- {S5, Status3} = analyse(S4#state{old_sys = S4#state.sys}, Status2),
+ {S5, Status3} = analyse(S4#state{old_sys = S#state.sys}, Status2),
S6 =
case Status3 of
{ok, _Warnings} ->
@@ -266,11 +266,11 @@ loop(#state{common = C, sys = Sys} = S) ->
reltool_utils:reply(ReplyTo, Ref, Status3),
?MODULE:loop(S6);
{call, ReplyTo, Ref, undo_config} ->
- reltool_utils:reply(ReplyTo, Ref, ok),
S2 = S#state{sys = S#state.old_sys,
old_sys = S#state.sys,
status = S#state.old_status,
old_status = S#state.status},
+ reltool_utils:reply(ReplyTo, Ref, ok),
?MODULE:loop(S2);
{call, ReplyTo, Ref, {get_rel, RelName}} ->
Sys = S#state.sys,
@@ -319,19 +319,21 @@ loop(#state{common = C, sys = Sys} = S) ->
?MODULE:loop(S);
{call, ReplyTo, Ref, {set_app, App}} ->
{S2, Status} = do_set_app(S, App, {ok, []}),
- {S3, Status2} = analyse(S2, Status),
- case Status2 of
- {ok, Warnings} ->
- App2 = ?KEYSEARCH(App#app.name,
- #app.name,
- (S3#state.sys)#sys.apps),
- reltool_utils:reply(ReplyTo, Ref, {ok, App2, Warnings}),
- ?MODULE:loop(S3);
- {error, Reason} ->
- %% Keep old state
- reltool_utils:reply(ReplyTo, Ref, {error, Reason}),
- ?MODULE:loop(S)
- end;
+ {S3, Status2} = analyse(S2#state{old_sys=S#state.sys}, Status),
+ {S4, Reply} =
+ case Status2 of
+ {ok, Warnings} ->
+ App2 = ?KEYSEARCH(App#app.name,
+ #app.name,
+ (S3#state.sys)#sys.apps),
+ {S3#state{status=Status2, old_status=S#state.status},
+ {ok, App2, Warnings}};
+ {error, _} ->
+ %% Keep old state
+ {S, Status2}
+ end,
+ reltool_utils:reply(ReplyTo, Ref, Reply),
+ ?MODULE:loop(S4);
{call, ReplyTo, Ref, {get_apps, Kind}} ->
AppNames =
case Kind of
@@ -361,9 +363,17 @@ loop(#state{common = C, sys = Sys} = S) ->
lists:foldl(fun(A, {X, Y}) -> do_set_app(X, A, Y) end,
{S, {ok, []}},
Apps),
- {S3, Status2} = analyse(S2, Status),
+ {S3, Status2} = analyse(S2#state{old_sys = S#state.sys}, Status),
+ S4 =
+ case Status2 of
+ {ok, _Warnings} ->
+ S3#state{status=Status2, old_status=S#state.status};
+ {error, _} ->
+ %% Keep old state
+ S
+ end,
reltool_utils:reply(ReplyTo, Ref, Status2),
- ?MODULE:loop(S3);
+ ?MODULE:loop(S4);
{call, ReplyTo, Ref, get_sys} ->
reltool_utils:reply(ReplyTo, Ref, {ok, Sys#sys{apps = undefined}}),
?MODULE:loop(S);
@@ -374,19 +384,16 @@ loop(#state{common = C, sys = Sys} = S) ->
(Sys2#sys.lib_dirs =/= Sys#sys.lib_dirs) orelse
(Sys2#sys.escripts =/= Sys#sys.escripts),
{S3, Status} = refresh(S2, Force, {ok, []}),
- {S4, Status2} =
- analyse(S3#state{old_sys = S#state.sys}, Status),
- {S5, Status3} =
+ {S4, Status2} = analyse(S3#state{old_sys = S#state.sys}, Status),
+ S5 =
case Status2 of
{ok, _Warnings} -> % BUGBUG: handle warnings
- {S4#state{status = Status2,
- old_status = S#state.status},
- Status2};
+ S4#state{status = Status2, old_status = S#state.status};
{error, _} ->
%% Keep old state
- {S, Status2}
+ S
end,
- reltool_utils:reply(ReplyTo, Ref, Status3),
+ reltool_utils:reply(ReplyTo, Ref, Status2),
?MODULE:loop(S5);
{call, ReplyTo, Ref, get_status} ->
reltool_utils:reply(ReplyTo, Ref, S#state.status),
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index 9ed79e8c95..588db837e4 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -24,6 +24,7 @@
-compile(export_all).
+-include_lib("reltool/src/reltool.hrl").
-include("reltool_test_lib.hrl").
-include_lib("common_test/include/ct.hrl").
@@ -51,10 +52,12 @@ end_per_testcase(Func,Config) ->
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [start_server, set_config, create_release,
+ [start_server, set_config, get_config, create_release,
create_script, create_target, create_embedded,
create_standalone, create_old_target,
- otp_9135, otp_9229_exclude_app, otp_9229_exclude_mod].
+ otp_9135, otp_9229_exclude_app, otp_9229_exclude_mod,
+ get_apps, set_app_and_undo, set_apps_and_undo,
+ load_config_and_undo, reset_config_and_undo, save_config].
groups() ->
[].
@@ -111,6 +114,83 @@ set_config(_Config) ->
?m(ok, reltool:stop(Pid)),
ok.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Check that get_config returns the expected derivates and defaults
+%% as specified
+get_config(_Config) ->
+ Sys = {sys,[{incl_cond, exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]}]},
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
+ ?m({ok, Sys}, reltool:get_config(Pid)),
+ ?m({ok, Sys}, reltool:get_config(Pid,false,false)),
+
+ ?msym({ok,{sys,[{incl_cond, exclude},
+ {erts,[]},
+ {app,kernel,[{incl_cond,include},{mod,_,[]}|_]},
+ {app,sasl,[{incl_cond,include},{mod,_,[]}|_]},
+ {app,stdlib,[{incl_cond,include},{mod,_,[]}|_]}]}},
+ reltool:get_config(Pid,false,true)),
+
+ ?msym({ok,{sys,[{root_dir,_},
+ {lib_dirs,_},
+ {mod_cond,all},
+ {incl_cond,exclude},
+ {app,kernel,[{incl_cond,include},{vsn,undefined}]},
+ {app,sasl,[{incl_cond,include},{vsn,undefined}]},
+ {app,stdlib,[{incl_cond,include},{vsn,undefined}]},
+ {boot_rel,"start_clean"},
+ {rel,"start_clean","1.0",[]},
+ {rel,"start_sasl","1.0",[sasl]},
+ {emu_name,"beam"},
+ {relocatable,true},
+ {profile,development},
+ {incl_sys_filters,[".*"]},
+ {excl_sys_filters,[]},
+ {incl_app_filters,[".*"]},
+ {excl_app_filters,[]},
+ {incl_archive_filters,[".*"]},
+ {excl_archive_filters,["^include$","^priv$"]},
+ {archive_opts,[]},
+ {rel_app_type,permanent},
+ {app_file,keep},
+ {debug_info,keep}]}},
+ reltool:get_config(Pid,true,false)),
+
+ KVsn = latest(kernel),
+ StdVsn = latest(stdlib),
+
+ ?msym({ok,{sys,[{root_dir,_},
+ {lib_dirs,_},
+ {mod_cond,all},
+ {incl_cond,exclude},
+ {erts,[]},
+ {app,kernel,[{incl_cond,include},{vsn,KVsn},{mod,_,[]}|_]},
+ {app,sasl,[{incl_cond,include},{vsn,_},{mod,_,[]}|_]},
+ {app,stdlib,[{incl_cond,include},{vsn,StdVsn},{mod,_,[]}|_]},
+ {boot_rel,"start_clean"},
+ {rel,"start_clean","1.0",[]},
+ {rel,"start_sasl","1.0",[sasl]},
+ {emu_name,"beam"},
+ {relocatable,true},
+ {profile,development},
+ {incl_sys_filters,[".*"]},
+ {excl_sys_filters,[]},
+ {incl_app_filters,[".*"]},
+ {excl_app_filters,[]},
+ {incl_archive_filters,[".*"]},
+ {excl_archive_filters,["^include$","^priv$"]},
+ {archive_opts,[]},
+ {rel_app_type,permanent},
+ {app_file,keep},
+ {debug_info,keep}]}},
+ reltool:get_config(Pid,true,true)),
+
+ ?m(ok, reltool:stop(Pid)),
+ ok.
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% OTP-9135, test that app_file option can be set to all | keep | strip
@@ -389,7 +469,7 @@ otp_9229_exclude_app(Config) ->
?m(ok, reltool_utils:recursive_delete(TargetDir)),
?m(ok, file:make_dir(TargetDir)),
?log("SPEC: ~p\n", [reltool:get_target_spec([{config, ExclApp}])]),
- {ok,["Module mylib exists in applications x and y. Using module from application x."]} = reltool:get_status([{config, ExclApp}]),
+ ?m({ok,["Module mylib exists in applications x and y. Using module from application x."]}, reltool:get_status([{config, ExclApp}])),
?m(ok, reltool:create_target([{config, ExclApp}], TargetDir)),
Erl = filename:join([TargetDir, "bin", "erl"]),
@@ -436,7 +516,7 @@ otp_9229_exclude_mod(Config) ->
?m(ok, reltool_utils:recursive_delete(TargetDir)),
?m(ok, file:make_dir(TargetDir)),
?log("SPEC: ~p\n", [reltool:get_target_spec([{config, ExclMod}])]),
- {ok,["Module mylib exists in applications x and y. Using module from application x."]} = reltool:get_status([{config, ExclMod}]),
+ ?m({ok,["Module mylib exists in applications x and y. Using module from application x."]}, reltool:get_status([{config, ExclMod}])),
?m(ok, reltool:create_target([{config, ExclMod}], TargetDir)),
Erl = filename:join([TargetDir, "bin", "erl"]),
@@ -466,7 +546,296 @@ otp_9229_exclude_mod(Config) ->
ok.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Test the interface used by the GUI:
+%% get_app
+%% get_apps
+%% set_app
+%% set_apps
+%% load_config
+%% reset_config
+%%
+%% Also, for each operation which manipulates the config test
+%% undo_config - that it is properly undone, and that warnings are
+%% re-displayed.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+get_apps(_Config) ->
+ Sys = {sys,[{app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,tools,[{incl_cond,derived}]},
+ {app,runtime_tools,[{incl_cond,exclude}]}]},
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
+
+ {ok,Sasl} = ?msym({ok,#app{name=sasl}}, reltool_server:get_app(Pid,sasl)),
+ {ok,[#app{name=kernel},
+ #app{name=sasl}=Sasl,
+ #app{name=stdlib}] = White} =
+ ?msym({ok,_}, reltool_server:get_apps(Pid,whitelist)),
+ {ok,[#app{name=runtime_tools}] = Black} =
+ ?msym({ok,_}, reltool_server:get_apps(Pid,blacklist)),
+
+ {ok,Derived} = ?msym({ok,_}, reltool_server:get_apps(Pid,derived)),
+ true = lists:keymember(tools,#app.name,Derived),
+
+ {ok,Source} = ?msym({ok,_}, reltool_server:get_apps(Pid,source)),
+ true = lists:keymember(common_test,#app.name,Source),
+
+ %% Check that the four lists are disjoint
+ Number = length(White) + length(Black) + length(Derived) + length(Source),
+ WN = lists:usort([N || #app{name=N} <- White]),
+ BN = lists:usort([N || #app{name=N} <- Black]),
+ DN = lists:usort([N || #app{name=N} <- Derived]),
+ SN = lists:usort([N || #app{name=N} <- Source]),
+ AllN = lists:umerge([WN,BN,DN,SN]),
+ ?m(Number,length(AllN)),
+
+ ?m(ok, reltool:stop(Pid)),
+
+ ok.
+
+set_app_and_undo(Config) ->
+ Sys = {sys,[{lib_dirs,[filename:join(datadir(Config),"faulty_app_file")]},
+ {incl_cond, exclude},
+ {app,a,[{incl_cond,include}]},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,tools,[{incl_cond,include}]}]},
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
+ ?m({ok, Sys}, reltool:get_config(Pid)),
+
+ %% Exclude one module with set_app
+ {ok,Tools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
+ Mods = Tools#app.mods,
+ Cover = lists:keyfind(cover,#mod.name,Mods),
+ ExclCover = Cover#mod{incl_cond=exclude},
+ Tools1 = Tools#app{mods = lists:keyreplace(cover,#mod.name,Mods,ExclCover)},
+ {ok,ToolsNoCover,[]} = ?msym({ok,_,[]}, reltool_server:set_app(Pid,Tools1)),
+ ?m({ok,ToolsNoCover}, reltool_server:get_app(Pid,tools)),
+
+ %% Undo
+ ?m(ok, reltool_server:undo_config(Pid)),
+ ?m({ok,Tools}, reltool_server:get_app(Pid,tools)),
+ %%! warning can come twice here... :(
+ ?msym({ok,["a: Cannot parse app file"++_|_]}, reltool:get_status(Pid)),
+
+ %% Undo again, to check that it toggles
+ ?m(ok, reltool_server:undo_config(Pid)),
+ ?m({ok,ToolsNoCover}, reltool_server:get_app(Pid,tools)),
+ ?m({ok,[]}, reltool:get_status(Pid)),
+
+ ?m(ok, reltool:stop(Pid)),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+set_apps_and_undo(Config) ->
+ Sys = {sys,[{lib_dirs,[filename:join(datadir(Config),"faulty_app_file")]},
+ {incl_cond, exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,tools,[{incl_cond,include}]}]},
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
+ ?m({ok, Sys}, reltool:get_config(Pid)),
+
+ %% Exclude one application with set_apps
+ {ok,Tools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
+ ExclTools = Tools#app{incl_cond=exclude},
+ ?m({ok,[]}, reltool_server:set_apps(Pid,[ExclTools])),
+ {ok,NoTools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
+ ?m(false, NoTools#app.is_pre_included),
+ ?m(false, NoTools#app.is_included),
+
+ %% Undo
+ ?m(ok, reltool_server:undo_config(Pid)),
+ ?m({ok,Tools}, reltool_server:get_app(Pid,tools)),
+ %%! warning can come twice here... :(
+ ?msym({ok,["a: Cannot parse app file"++_|_]}, reltool:get_status(Pid)),
+
+ %% Undo again, to check that it toggles
+ ?m(ok, reltool_server:undo_config(Pid)),
+ ?m({ok,NoTools}, reltool_server:get_app(Pid,tools)),
+ ?m({ok,[]}, reltool:get_status(Pid)),
+
+ ?m(ok, reltool:stop(Pid)),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+load_config_and_undo(Config) ->
+ Sys1 = {sys,[{incl_cond, exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,tools,[{incl_cond,include}]}]},
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
+ ?m({ok, Sys1}, reltool:get_config(Pid)),
+
+ %% Check that tools is included
+ {ok,Tools1} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
+ ?m(true, Tools1#app.is_pre_included),
+ ?m(true, Tools1#app.is_included),
+
+ %% Exclude one application with set_apps
+ Sys2 = {sys,[{lib_dirs,[filename:join(datadir(Config),"faulty_app_file")]},
+ {incl_cond, exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,tools,[{incl_cond,derived}]},
+ {app,a,[{incl_cond,include}]}]},
+ ?msym({ok,["a: Cannot parse app file"++_]},
+ reltool_server:load_config(Pid,Sys2)),
+
+ %% Check that tools is included (since it is used by sasl) but not
+ %% pre-included (neither included or excluded => undefined)
+ {ok,Tools2} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
+ ?m(undefined, Tools2#app.is_pre_included),
+ ?m(true, Tools2#app.is_included),
+
+ %% Undo
+ ?m(ok, reltool_server:undo_config(Pid)),
+ ?m({ok,Tools1}, reltool_server:get_app(Pid,tools)),
+ ?m({ok,[]}, reltool:get_status(Pid)),
+
+ %% Undo again, to check that it toggles
+ ?m(ok, reltool_server:undo_config(Pid)),
+ ?m({ok,Tools2}, reltool_server:get_app(Pid,tools)),
+ ?msym({ok,["a: Cannot parse app file"++_]}, reltool:get_status(Pid)),
+ ?m(ok, reltool:stop(Pid)),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+reset_config_and_undo(Config) ->
+ Sys1 = {sys,[{lib_dirs,[filename:join(datadir(Config),"faulty_app_file")]},
+ {incl_cond, exclude},
+ {app,a,[{incl_cond,include}]},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,tools,[{incl_cond,include}]}]},
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
+ ?m({ok, Sys1}, reltool:get_config(Pid)),
+
+ %% Check that tools is included
+ {ok,Tools1} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
+ ?m(true, Tools1#app.is_pre_included),
+ ?m(true, Tools1#app.is_included),
+
+ %% Exclude one application with set_apps
+ Sys2 = {sys,[{incl_cond, exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,tools,[{incl_cond,exclude}]}]},
+ ?m({ok,[]}, reltool_server:load_config(Pid,Sys2)),
+
+ %% Check that tools is excluded
+ {ok,Tools2} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
+ ?m(false, Tools2#app.is_pre_included),
+ ?m(false, Tools2#app.is_included),
+
+ %% Reset
+ %%! warning can come twice here... :(
+ ?msym({ok,["a: Cannot parse app file"++_|_]},
+ reltool_server:reset_config(Pid)),
+ ?m({ok,Tools1}, reltool_server:get_app(Pid,tools)),
+
+ %% Undo again, to check that it toggles
+ ?m(ok, reltool_server:undo_config(Pid)),
+ ?m({ok,Tools2}, reltool_server:get_app(Pid,tools)),
+ ?m({ok,[]}, reltool:get_status(Pid)),
+
+ ?m(ok, reltool:stop(Pid)),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+save_config(Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ Sys = {sys,[{incl_cond, exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]}]},
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
+ ?m({ok, Sys}, reltool:get_config(Pid)),
+
+ Simple = filename:join(PrivDir,"save_simple.reltool"),
+ ?m(ok, reltool_server:save_config(Pid,Simple,false,false)),
+ ?m({ok,[Sys]}, file:consult(Simple)),
+
+ Derivates = filename:join(PrivDir,"save_derivates.reltool"),
+ ?m(ok, reltool_server:save_config(Pid,Derivates,false,true)),
+ ?msym({ok,[{sys,[{incl_cond, exclude},
+ {erts,[]},
+ {app,kernel,[{incl_cond,include},{mod,_,[]}|_]},
+ {app,sasl,[{incl_cond,include},{mod,_,[]}|_]},
+ {app,stdlib,[{incl_cond,include},{mod,_,[]}|_]}]}]},
+ file:consult(Derivates)),
+
+ Defaults = filename:join(PrivDir,"save_defaults.reltool"),
+ ?m(ok, reltool_server:save_config(Pid,Defaults,true,false)),
+ ?msym({ok,[{sys,[{root_dir,_},
+ {lib_dirs,_},
+ {mod_cond,all},
+ {incl_cond,exclude},
+ {app,kernel,[{incl_cond,include},{vsn,undefined}]},
+ {app,sasl,[{incl_cond,include},{vsn,undefined}]},
+ {app,stdlib,[{incl_cond,include},{vsn,undefined}]},
+ {boot_rel,"start_clean"},
+ {rel,"start_clean","1.0",[]},
+ {rel,"start_sasl","1.0",[sasl]},
+ {emu_name,"beam"},
+ {relocatable,true},
+ {profile,development},
+ {incl_sys_filters,[".*"]},
+ {excl_sys_filters,[]},
+ {incl_app_filters,[".*"]},
+ {excl_app_filters,[]},
+ {incl_archive_filters,[".*"]},
+ {excl_archive_filters,["^include$","^priv$"]},
+ {archive_opts,[]},
+ {rel_app_type,permanent},
+ {app_file,keep},
+ {debug_info,keep}]}]},
+ file:consult(Defaults)),
+
+ KVsn = latest(kernel),
+ StdVsn = latest(stdlib),
+
+ All = filename:join(PrivDir,"save_all.reltool"),
+ ?m(ok, reltool_server:save_config(Pid,All,true,true)),
+ ?msym({ok,[{sys,[{root_dir,_},
+ {lib_dirs,_},
+ {mod_cond,all},
+ {incl_cond,exclude},
+ {erts,[]},
+ {app,kernel,[{incl_cond,include},{vsn,KVsn},{mod,_,[]}|_]},
+ {app,sasl,[{incl_cond,include},{vsn,_},{mod,_,[]}|_]},
+ {app,stdlib,[{incl_cond,include},{vsn,StdVsn},{mod,_,[]}|_]},
+ {boot_rel,"start_clean"},
+ {rel,"start_clean","1.0",[]},
+ {rel,"start_sasl","1.0",[sasl]},
+ {emu_name,"beam"},
+ {relocatable,true},
+ {profile,development},
+ {incl_sys_filters,[".*"]},
+ {excl_sys_filters,[]},
+ {incl_app_filters,[".*"]},
+ {excl_app_filters,[]},
+ {incl_archive_filters,[".*"]},
+ {excl_archive_filters,["^include$","^priv$"]},
+ {archive_opts,[]},
+ {rel_app_type,permanent},
+ {app_file,keep},
+ {debug_info,keep}]}]},
+ file:consult(All)),
+
+ ?m(ok, reltool:stop(Pid)),
+ ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -478,6 +847,18 @@ erl_libs() ->
LibStr -> string:tokens(LibStr, ":;")
end.
+datadir(Config) ->
+ %% Removes the trailing slash...
+ filename:nativename(?config(data_dir,Config)).
+
+latest(App) ->
+ AppStr = atom_to_list(App),
+ AppDirs = filelib:wildcard(filename:join(code:lib_dir(),AppStr++"-*")),
+ [LatestAppDir|_] = lists:reverse(AppDirs),
+ [_,Vsn] = string:tokens(filename:basename(LatestAppDir),"-"),
+ Vsn.
+
+
diff_script(Script, Script) ->
equal;
diff_script({script, Rel, Commands1}, {script, Rel, Commands2}) ->
diff --git a/lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/ebin/a.app b/lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/ebin/a.app
new file mode 100644
index 0000000000..ea77103598
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/ebin/a.app
@@ -0,0 +1 @@
+faulty app file
diff --git a/lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/src/a.erl b/lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/src/a.erl
new file mode 100644
index 0000000000..bb500bed69
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/src/a.erl
@@ -0,0 +1,49 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+%% AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(a).
+
+
+-behaviour(gen_server).
+
+-vsn(1).
+
+%% External exports
+-export([start_link/0, a/0]).
+%% Internal exports
+-export([init/1, handle_call/3, handle_info/2, terminate/2]).
+
+start_link() -> gen_server:start_link({local, aa}, a, [], []).
+
+a() -> gen_server:call(aa, a).
+
+%%-----------------------------------------------------------------
+%% Callback functions from gen_server
+%%-----------------------------------------------------------------
+init([]) ->
+ process_flag(trap_exit, true),
+ {ok, state}.
+
+handle_call(a, _From, State) ->
+ X = application:get_all_env(a),
+ {reply, X, State}.
+
+handle_info(_, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
diff --git a/lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/src/a_sup.erl b/lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/src/a_sup.erl
new file mode 100644
index 0000000000..a141c1767b
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/src/a_sup.erl
@@ -0,0 +1,37 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+%% AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(a_sup).
+
+
+-behaviour(supervisor).
+
+%% External exports
+-export([start/2]).
+
+%% Internal exports
+-export([init/1]).
+
+start(_, _) ->
+ supervisor:start_link({local, a_sup}, a_sup, []).
+
+init([]) ->
+ SupFlags = {one_for_one, 4, 3600},
+ Config = {a,
+ {a, start_link, []},
+ permanent, 2000, worker, [a]},
+ {ok, {SupFlags, [Config]}}.
--
cgit v1.2.3
From e610c1e38219b7038f2e42b233ef226508535a90 Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Mon, 9 Jan 2012 15:42:29 +0100
Subject: [reltool] Add test of dependencies derived through calls to external
apps
OTP-9794
This is a test of the mechanism with which reltool_server decides
which applications to include and not, based on function calls between
applications. This is also the mechanism which forms the base for the
application- and module dependency graphs.
---
lib/reltool/test/reltool_server_SUITE.erl | 142 ++++++++++++++++++++-
.../test/reltool_server_SUITE_data/Makefile.src | 23 +++-
.../dependencies/x-1.0/ebin/x.app | 7 +
.../dependencies/x-1.0/src/x1.erl | 5 +
.../dependencies/x-1.0/src/x2.erl | 5 +
.../dependencies/x-1.0/src/x3.erl | 5 +
.../dependencies/y-1.0/ebin/y.app | 7 +
.../dependencies/y-1.0/src/y1.erl | 5 +
.../dependencies/y-1.0/src/y2.erl | 5 +
.../dependencies/z-1.0/ebin/z.app | 7 +
.../dependencies/z-1.0/src/z1.erl | 5 +
11 files changed, 214 insertions(+), 2 deletions(-)
create mode 100644 lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/ebin/x.app
create mode 100644 lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x1.erl
create mode 100644 lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x2.erl
create mode 100644 lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x3.erl
create mode 100644 lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/ebin/y.app
create mode 100644 lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/src/y1.erl
create mode 100644 lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/src/y2.erl
create mode 100644 lib/reltool/test/reltool_server_SUITE_data/dependencies/z-1.0/ebin/z.app
create mode 100644 lib/reltool/test/reltool_server_SUITE_data/dependencies/z-1.0/src/z1.erl
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index 588db837e4..90288020f1 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -57,7 +57,8 @@ all() ->
create_standalone, create_old_target,
otp_9135, otp_9229_exclude_app, otp_9229_exclude_mod,
get_apps, set_app_and_undo, set_apps_and_undo,
- load_config_and_undo, reset_config_and_undo, save_config].
+ load_config_and_undo, reset_config_and_undo, save_config,
+ dependencies].
groups() ->
[].
@@ -837,6 +838,143 @@ save_config(Config) ->
?m(ok, reltool:stop(Pid)),
ok.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Test calculation of dependencies
+%% The following test applications are used
+%%
+%% x-1.0: x1.erl x2.erl x3.erl
+%% \ / (x2 calls y1, x3 calls y2)
+%% y-1.0: y1.erl y2.erl
+%% \ (y1 calls z1)
+%% z-1.0 z1.erl
+%%
+%% Test includes x and derives y and z.
+%%
+dependencies(Config) ->
+ PrivDir = ?config(priv_dir,Config),
+
+ %% Default: all modules included => y and z are included (derived)
+ Sys = {sys,[{lib_dirs,[filename:join(datadir(Config),"dependencies")]},
+ {incl_cond, exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,x,[{incl_cond,include}]},
+ {app,y,[{incl_cond,derived}]},
+ {app,z,[{incl_cond,derived}]}]},
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
+
+ ?msym({ok,[#app{name=kernel},
+ #app{name=sasl},
+ #app{name=stdlib},
+ #app{name=x,uses_apps=[y]}]},
+ reltool_server:get_apps(Pid,whitelist)),
+ {ok, Der} = ?msym({ok,_},
+ reltool_server:get_apps(Pid,derived)),
+ ?msym([#app{name=y,uses_apps=[z]},
+ #app{name=z}],
+ rm_missing_app(Der)),
+ ?msym({ok,[]},
+ reltool_server:get_apps(Pid,source)),
+
+ %% Excluding x2 => y still included since y2 is used by x3
+ %% z still included since z1 is used by y1
+ Sys2 = {sys,[{lib_dirs,[filename:join(datadir(Config),"dependencies")]},
+ {incl_cond, exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,x,[{incl_cond,include},{mod,x2,[{incl_cond,exclude}]}]},
+ {app,y,[{incl_cond,derived}]},
+ {app,z,[{incl_cond,derived}]}]},
+ ?m({ok,[]}, reltool_server:load_config(Pid,Sys2)),
+ ?msym({ok,[#app{name=kernel},
+ #app{name=sasl},
+ #app{name=stdlib},
+ #app{name=x,uses_apps=[y]}]},
+ reltool_server:get_apps(Pid,whitelist)),
+ {ok, Der2} = ?msym({ok,_},
+ reltool_server:get_apps(Pid,derived)),
+ ?msym([#app{name=y,uses_apps=[z]},
+ #app{name=z}],
+ rm_missing_app(Der2)),
+ ?msym({ok,[]},
+ reltool_server:get_apps(Pid,source)),
+
+ %% Excluding x3 => y still included since y1 is used by x2
+ %% z still included since z1 is used by y1
+ Sys3 = {sys,[{lib_dirs,[filename:join(datadir(Config),"dependencies")]},
+ {incl_cond, exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,x,[{incl_cond,include},{mod,x3,[{incl_cond,exclude}]}]},
+ {app,y,[{incl_cond,derived}]},
+ {app,z,[{incl_cond,derived}]}]},
+ ?m({ok,[]}, reltool_server:load_config(Pid,Sys3)),
+ ?msym({ok,[#app{name=kernel},
+ #app{name=sasl},
+ #app{name=stdlib},
+ #app{name=x,uses_apps=[y]}]},
+ reltool_server:get_apps(Pid,whitelist)),
+ {ok, Der3} = ?msym({ok,_},
+ reltool_server:get_apps(Pid,derived)),
+ ?msym([#app{name=y,uses_apps=[z]},
+ #app{name=z}],
+ rm_missing_app(Der3)),
+ ?msym({ok,[]},
+ reltool_server:get_apps(Pid,source)),
+
+ %% Excluding x2 and x3 => y and z excluded
+ Sys4 = {sys,[{lib_dirs,[filename:join(datadir(Config),"dependencies")]},
+ {incl_cond, exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,x,[{incl_cond,include},
+ {mod,x2,[{incl_cond,exclude}]},
+ {mod,x3,[{incl_cond,exclude}]}]},
+ {app,y,[{incl_cond,derived}]},
+ {app,z,[{incl_cond,derived}]}]},
+ ?m({ok,[]}, reltool_server:load_config(Pid,Sys4)),
+ ?msym({ok,[#app{name=kernel},
+ #app{name=sasl},
+ #app{name=stdlib},
+ #app{name=x,uses_apps=[]}]},
+ reltool_server:get_apps(Pid,whitelist)),
+ {ok, Der4} = ?msym({ok,_},
+ reltool_server:get_apps(Pid,derived)),
+ ?msym([], rm_missing_app(Der4)),
+ ?msym({ok,[#app{name=y},
+ #app{name=z}]},
+ reltool_server:get_apps(Pid,source)),
+
+ %% Excluding y1 => y still included since y2 is used by x3
+ %% z excluded since not used by any other than y1
+ Sys5 = {sys,[{lib_dirs,[filename:join(datadir(Config),"dependencies")]},
+ {incl_cond, exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,x,[{incl_cond,include}]},
+ {app,y,[{incl_cond,derived},
+ {mod,y1,[{incl_cond,exclude}]}]},
+ {app,z,[{incl_cond,derived}]}]},
+ ?m({ok,[]}, reltool_server:load_config(Pid,Sys5)),
+ ?msym({ok,[#app{name=kernel},
+ #app{name=sasl},
+ #app{name=stdlib},
+ #app{name=x,uses_apps=[y]}]},
+ reltool_server:get_apps(Pid,whitelist)),
+ {ok, Der5} = ?msym({ok,_},
+ reltool_server:get_apps(Pid,derived)),
+ ?msym([#app{name=y,uses_apps=[]}], rm_missing_app(Der5)),
+ ?msym({ok,[#app{name=z}]},
+ reltool_server:get_apps(Pid,source)),
+
+ ?m(ok, reltool:stop(Pid)),
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Library functions
@@ -858,6 +996,8 @@ latest(App) ->
[_,Vsn] = string:tokens(filename:basename(LatestAppDir),"-"),
Vsn.
+rm_missing_app(Apps) ->
+ lists:keydelete(?MISSING_APP_NAME,#app.name,Apps).
diff_script(Script, Script) ->
equal;
diff --git a/lib/reltool/test/reltool_server_SUITE_data/Makefile.src b/lib/reltool/test/reltool_server_SUITE_data/Makefile.src
index 049e8dd6cc..35a239bfe2 100644
--- a/lib/reltool/test/reltool_server_SUITE_data/Makefile.src
+++ b/lib/reltool/test/reltool_server_SUITE_data/Makefile.src
@@ -6,8 +6,16 @@ OTP9229= \
otp_9229/y-1.0/ebin/y.@EMULATOR@ \
otp_9229/y-1.0/ebin/mylib.@EMULATOR@
+DEPENDENCIES= \
+ dependencies/x-1.0/ebin/x1.@EMULATOR@ \
+ dependencies/x-1.0/ebin/x2.@EMULATOR@ \
+ dependencies/x-1.0/ebin/x3.@EMULATOR@ \
+ dependencies/y-1.0/ebin/y1.@EMULATOR@ \
+ dependencies/y-1.0/ebin/y2.@EMULATOR@ \
+ dependencies/z-1.0/ebin/z1.@EMULATOR@
-all: $(OTP9229)
+
+all: $(OTP9229) $(DEPENDENCIES)
otp_9229/x-1.0/ebin/x.@EMULATOR@: otp_9229/x-1.0/src/x.erl
erlc $(EFLAGS) -ootp_9229/x-1.0/ebin otp_9229/x-1.0/src/x.erl
@@ -17,3 +25,16 @@ otp_9229/y-1.0/ebin/y.@EMULATOR@: otp_9229/y-1.0/src/y.erl
erlc $(EFLAGS) -ootp_9229/y-1.0/ebin otp_9229/y-1.0/src/y.erl
otp_9229/y-1.0/ebin/mylib.@EMULATOR@: otp_9229/y-1.0/src/mylib.erl
erlc $(EFLAGS) -ootp_9229/y-1.0/ebin otp_9229/y-1.0/src/mylib.erl
+
+dependencies/x-1.0/ebin/x1.@EMULATOR@: dependencies/x-1.0/src/x1.erl
+ erlc $(EFLAGS) -odependencies/x-1.0/ebin dependencies/x-1.0/src/x1.erl
+dependencies/x-1.0/ebin/x2.@EMULATOR@: dependencies/x-1.0/src/x2.erl
+ erlc $(EFLAGS) -odependencies/x-1.0/ebin dependencies/x-1.0/src/x2.erl
+dependencies/x-1.0/ebin/x3.@EMULATOR@: dependencies/x-1.0/src/x3.erl
+ erlc $(EFLAGS) -odependencies/x-1.0/ebin dependencies/x-1.0/src/x3.erl
+dependencies/y-1.0/ebin/y1.@EMULATOR@: dependencies/y-1.0/src/y1.erl
+ erlc $(EFLAGS) -odependencies/y-1.0/ebin dependencies/y-1.0/src/y1.erl
+dependencies/y-1.0/ebin/y2.@EMULATOR@: dependencies/y-1.0/src/y2.erl
+ erlc $(EFLAGS) -odependencies/y-1.0/ebin dependencies/y-1.0/src/y2.erl
+dependencies/z-1.0/ebin/z1.@EMULATOR@: dependencies/z-1.0/src/z1.erl
+ erlc $(EFLAGS) -odependencies/z-1.0/ebin dependencies/z-1.0/src/z1.erl
diff --git a/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/ebin/x.app b/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/ebin/x.app
new file mode 100644
index 0000000000..ccaab8a8c7
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/dependencies/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,x2,x3]},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.
diff --git a/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x1.erl b/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x1.erl
new file mode 100644
index 0000000000..bf1e7f9279
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/dependencies/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/dependencies/x-1.0/src/x2.erl b/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x2.erl
new file mode 100644
index 0000000000..82191ba278
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x2.erl
@@ -0,0 +1,5 @@
+-module(x2).
+-compile(export_all).
+
+f() ->
+ y1:f().
diff --git a/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x3.erl b/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x3.erl
new file mode 100644
index 0000000000..618c75c9a7
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x3.erl
@@ -0,0 +1,5 @@
+-module(x3).
+-compile(export_all).
+
+f() ->
+ y2:f().
diff --git a/lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/ebin/y.app b/lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/ebin/y.app
new file mode 100644
index 0000000000..d9dac371d7
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/ebin/y.app
@@ -0,0 +1,7 @@
+% -*-erlang-*-
+{application, y,
+ [{description, "Library application in reltool dependency test"},
+ {vsn, "1.0"},
+ {modules, [y1,y2]},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.
diff --git a/lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/src/y1.erl b/lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/src/y1.erl
new file mode 100644
index 0000000000..dd21b33292
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/src/y1.erl
@@ -0,0 +1,5 @@
+-module(y1).
+-compile(export_all).
+
+f() ->
+ z1:f().
diff --git a/lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/src/y2.erl b/lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/src/y2.erl
new file mode 100644
index 0000000000..bf8ddf6080
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/src/y2.erl
@@ -0,0 +1,5 @@
+-module(y2).
+-compile(export_all).
+
+f() ->
+ ok.
diff --git a/lib/reltool/test/reltool_server_SUITE_data/dependencies/z-1.0/ebin/z.app b/lib/reltool/test/reltool_server_SUITE_data/dependencies/z-1.0/ebin/z.app
new file mode 100644
index 0000000000..437a0968e9
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/dependencies/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/dependencies/z-1.0/src/z1.erl b/lib/reltool/test/reltool_server_SUITE_data/dependencies/z-1.0/src/z1.erl
new file mode 100644
index 0000000000..97ef90b87f
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/dependencies/z-1.0/src/z1.erl
@@ -0,0 +1,5 @@
+-module(z1).
+-compile(export_all).
+
+f() ->
+ ok.
--
cgit v1.2.3
From 06ea8c9f62e265bc045eb92d522e84a5f208f8cd Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Fri, 13 Jan 2012 14:54:50 +0100
Subject: [reltool] Ensure that tests do not try to start node if target was
not created
OTP-9794
Some test cases in reltool_server_SUITE tried to create a target
system and then start a node running this system. If creation of the
target system failed, an attempt would still be made to start the
node. This has been corrected so the test is immediately terminated if
the target system could not be created.
---
lib/reltool/test/reltool_server_SUITE.erl | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index 90288020f1..086ada41e0 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -324,7 +324,7 @@ create_target(_Config) ->
?m(ok, reltool_utils:recursive_delete(TargetDir)),
?m(ok, file:make_dir(TargetDir)),
?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Config}])]),
- ?m(ok, reltool:create_target([{config, Config}], TargetDir)),
+ ok = ?m(ok, reltool:create_target([{config, Config}], TargetDir)),
Erl = filename:join([TargetDir, "bin", "erl"]),
{ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
@@ -357,7 +357,7 @@ create_embedded(_Config) ->
TargetDir = filename:join([?WORK_DIR, "target_embedded"]),
?m(ok, reltool_utils:recursive_delete(TargetDir)),
?m(ok, file:make_dir(TargetDir)),
- ?m(ok, reltool:create_target([{config, Config}], TargetDir)),
+ ok = ?m(ok, reltool:create_target([{config, Config}], TargetDir)),
Erl = filename:join([TargetDir, "bin", "erl"]),
{ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
@@ -387,7 +387,7 @@ create_standalone(_Config) ->
TargetDir = filename:join([?WORK_DIR, "target_standalone"]),
?m(ok, reltool_utils:recursive_delete(TargetDir)),
?m(ok, file:make_dir(TargetDir)),
- ?m(ok, reltool:create_target([{config, Config}], TargetDir)),
+ ok = ?m(ok, reltool:create_target([{config, Config}], TargetDir)),
BinDir = filename:join([TargetDir, "bin"]),
Erl = filename:join([BinDir, "erl"]),
@@ -431,10 +431,10 @@ create_old_target(_Config) ->
TargetDir = filename:join([?WORK_DIR, "target_old_style"]),
?m(ok, reltool_utils:recursive_delete(TargetDir)),
?m(ok, file:make_dir(TargetDir)),
- ?m(ok, reltool:create_target([{config, Config}], TargetDir)),
+ ok = ?m(ok, reltool:create_target([{config, Config}], TargetDir)),
%% io:format("Will fail on Windows (should patch erl.ini)\n", []),
- ?m(ok, reltool:install(RelName2, TargetDir)),
+ ok = ?m(ok, reltool:install(RelName2, TargetDir)),
Erl = filename:join([TargetDir, "bin", "erl"]),
{ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
@@ -471,7 +471,7 @@ otp_9229_exclude_app(Config) ->
?m(ok, file:make_dir(TargetDir)),
?log("SPEC: ~p\n", [reltool:get_target_spec([{config, ExclApp}])]),
?m({ok,["Module mylib exists in applications x and y. Using module from application x."]}, reltool:get_status([{config, ExclApp}])),
- ?m(ok, reltool:create_target([{config, ExclApp}], TargetDir)),
+ ok = ?m(ok, reltool:create_target([{config, ExclApp}], TargetDir)),
Erl = filename:join([TargetDir, "bin", "erl"]),
{ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
@@ -518,7 +518,7 @@ otp_9229_exclude_mod(Config) ->
?m(ok, file:make_dir(TargetDir)),
?log("SPEC: ~p\n", [reltool:get_target_spec([{config, ExclMod}])]),
?m({ok,["Module mylib exists in applications x and y. Using module from application x."]}, reltool:get_status([{config, ExclMod}])),
- ?m(ok, reltool:create_target([{config, ExclMod}], TargetDir)),
+ ok = ?m(ok, reltool:create_target([{config, ExclMod}], TargetDir)),
Erl = filename:join([TargetDir, "bin", "erl"]),
{ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
--
cgit v1.2.3
From 610280492bca33c851eabda0a2daf5cf141ea090 Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Fri, 20 Jan 2012 17:10:31 +0100
Subject: [reltool] Add test case for reltool_server:get_mod
OTP-9794
This test case revealed a bug that occurs when calling
reltool_server:get_mod after reltool_server:undo_config. get_mod reads
from the module table (ets) and not from the reltool_server state,
while undo_config only changes the state. This bug has been corrected,
so undo_config now updates both state and tables (it does the same as
set_sys).
---
lib/reltool/src/reltool_server.erl | 30 ++++++--
lib/reltool/src/reltool_sys_win.erl | 25 +++++--
lib/reltool/test/reltool_server_SUITE.erl | 116 ++++++++++++++++++++++--------
3 files changed, 133 insertions(+), 38 deletions(-)
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index fdb9e08a90..7dc2d21158 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -266,12 +266,30 @@ loop(#state{common = C, sys = Sys} = S) ->
reltool_utils:reply(ReplyTo, Ref, Status3),
?MODULE:loop(S6);
{call, ReplyTo, Ref, undo_config} ->
- S2 = S#state{sys = S#state.old_sys,
- old_sys = S#state.sys,
- status = S#state.old_status,
- old_status = S#state.status},
- reltool_utils:reply(ReplyTo, Ref, ok),
- ?MODULE:loop(S2);
+ OldSys = S#state.old_sys,
+ S2 = S#state{sys = OldSys,
+ old_sys = Sys},
+ %%! Possibly skip old_status here, since we do all job again!
+ %%! If so, consider if it is correct to use Force or not -
+ %%! since warnings from refresh_app will not re-appear here
+ %%! in undo if Force==false.
+ Force =
+ (OldSys#sys.root_dir =/= Sys#sys.root_dir) orelse
+ (OldSys#sys.lib_dirs =/= Sys#sys.lib_dirs) orelse
+ (OldSys#sys.escripts =/= Sys#sys.escripts),
+
+ {S3, Status} = refresh(S2, Force, S#state.old_status),
+ {S4, Status2} = analyse(S3, Status),
+ S5 =
+ case Status2 of
+ {ok, _Warnings} -> % BUGBUG: handle warnings
+ S4#state{status = Status2, old_status = S#state.status};
+ {error, _} ->
+ %% Keep old state
+ S
+ end,
+ reltool_utils:reply(ReplyTo, Ref, Status2),
+ ?MODULE:loop(S5);
{call, ReplyTo, Ref, {get_rel, RelName}} ->
Sys = S#state.sys,
Reply =
diff --git a/lib/reltool/src/reltool_sys_win.erl b/lib/reltool/src/reltool_sys_win.erl
index 8b0f64eb45..f29a95af38 100644
--- a/lib/reltool/src/reltool_sys_win.erl
+++ b/lib/reltool/src/reltool_sys_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1290,7 +1290,15 @@ reset_config(#state{status_bar = Bar} = S) ->
undo_config(#state{status_bar = Bar} = S) ->
wxStatusBar:setStatusText(Bar, "Processing libraries..."),
- ok = reltool_server:undo_config(S#state.server_pid),
+ case reltool_server:undo_config(S#state.server_pid) of
+ {ok, []} ->
+ ok;
+ {ok, Warnings} ->
+ Msg = lists:flatten([[W, $\n] || W <- Warnings]),
+ display_message(Msg, ?wxICON_WARNING);
+ {error, Reason} ->
+ display_message(Reason, ?wxICON_ERROR)
+ end,
refresh(S).
load_config(#state{status_bar = Bar, config_file = OldFile} = S) ->
@@ -1444,8 +1452,17 @@ undo_dialog(S, Warnings) ->
?wxID_OK ->
true;
?wxID_CANCEL ->
- reltool_server:undo_config(S#state.server_pid),
- false
+ case reltool_server:undo_config(S#state.server_pid) of
+ {ok, _} ->
+ false;
+ {error, Reason} ->
+ Msg = "FATAL - undo failed:\n\n" ++
+ Reason ++
+ "\n\nTerminating...",
+ display_message(Msg, ?wxICON_ERROR),
+ io:format("~p(~p): ~s\n", [?MODULE, ?LINE, Reason]),
+ exit(Reason)
+ end
end.
display_message(Message, Icon) ->
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index 086ada41e0..79c6854465 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -56,7 +56,7 @@ all() ->
create_script, create_target, create_embedded,
create_standalone, create_old_target,
otp_9135, otp_9229_exclude_app, otp_9229_exclude_mod,
- get_apps, set_app_and_undo, set_apps_and_undo,
+ get_apps, get_mod, set_app_and_undo, set_apps_and_undo,
load_config_and_undo, reset_config_and_undo, save_config,
dependencies].
@@ -595,6 +595,29 @@ get_apps(_Config) ->
ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+get_mod(_Config) ->
+ Sys = {sys,[{app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,tools,[{incl_cond,derived}]},
+ {app,runtime_tools,[{incl_cond,exclude}]}]},
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
+
+ %% Read app and get a module from the #app record
+ {ok,Tools} = ?msym({ok,#app{name=tools}}, reltool_server:get_app(Pid,tools)),
+ Cover = lists:keyfind(cover,#mod.name,Tools#app.mods),
+
+ %% get_mod - and check that it is equal to the one in #app.mods
+ ?m({ok,Cover}, reltool_server:get_mod(Pid,cover)),
+
+ ?m(ok, reltool:stop(Pid)),
+
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
set_app_and_undo(Config) ->
Sys = {sys,[{lib_dirs,[filename:join(datadir(Config),"faulty_app_file")]},
{incl_cond, exclude},
@@ -606,25 +629,32 @@ set_app_and_undo(Config) ->
{ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
?m({ok, Sys}, reltool:get_config(Pid)),
- %% Exclude one module with set_app
+ %% Get app and mod
{ok,Tools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
- Mods = Tools#app.mods,
- Cover = lists:keyfind(cover,#mod.name,Mods),
+ {ok,Cover} = ?msym({ok,#mod{name=cover, is_included=true}},
+ reltool_server:get_mod(Pid,cover)),
+
+ %% Exclude one module with set_app
ExclCover = Cover#mod{incl_cond=exclude},
+ Mods = Tools#app.mods,
Tools1 = Tools#app{mods = lists:keyreplace(cover,#mod.name,Mods,ExclCover)},
{ok,ToolsNoCover,[]} = ?msym({ok,_,[]}, reltool_server:set_app(Pid,Tools1)),
+
+ %% Check that the module is no longer included
?m({ok,ToolsNoCover}, reltool_server:get_app(Pid,tools)),
+ {ok,NoIncludeCover} = ?msym({ok,#mod{name=cover, is_included=false}},
+ reltool_server:get_mod(Pid,cover)),
%% Undo
- ?m(ok, reltool_server:undo_config(Pid)),
- ?m({ok,Tools}, reltool_server:get_app(Pid,tools)),
%%! warning can come twice here... :(
- ?msym({ok,["a: Cannot parse app file"++_|_]}, reltool:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:undo_config(Pid)),
+ ?m({ok,Tools}, reltool_server:get_app(Pid,tools)),
+ ?m({ok,Cover}, reltool_server:get_mod(Pid,cover)),
%% Undo again, to check that it toggles
- ?m(ok, reltool_server:undo_config(Pid)),
+ ?m({ok,[]}, reltool_server:undo_config(Pid)),
?m({ok,ToolsNoCover}, reltool_server:get_app(Pid,tools)),
- ?m({ok,[]}, reltool:get_status(Pid)),
+ ?m({ok,NoIncludeCover}, reltool_server:get_mod(Pid,cover)),
?m(ok, reltool:stop(Pid)),
ok.
@@ -641,24 +671,34 @@ set_apps_and_undo(Config) ->
{ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
?m({ok, Sys}, reltool:get_config(Pid)),
- %% Exclude one application with set_apps
+ %% Get app and mod
{ok,Tools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
+ ?m(true, Tools#app.is_pre_included),
+ ?m(true, Tools#app.is_included),
+ {ok,Cover} = ?msym({ok,#mod{name=cover, is_included=true}},
+ reltool_server:get_mod(Pid,cover)),
+
+ %% Exclude one application with set_apps
ExclTools = Tools#app{incl_cond=exclude},
?m({ok,[]}, reltool_server:set_apps(Pid,[ExclTools])),
+
+ %% Check that the app and its modules (one of them) are no longer included
{ok,NoTools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
?m(false, NoTools#app.is_pre_included),
?m(false, NoTools#app.is_included),
+ {ok,NoIncludeCover} = ?msym({ok,#mod{name=cover, is_included=false}},
+ reltool_server:get_mod(Pid,cover)),
%% Undo
- ?m(ok, reltool_server:undo_config(Pid)),
- ?m({ok,Tools}, reltool_server:get_app(Pid,tools)),
%%! warning can come twice here... :(
- ?msym({ok,["a: Cannot parse app file"++_|_]}, reltool:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:undo_config(Pid)),
+ ?m({ok,Tools}, reltool_server:get_app(Pid,tools)),
+ ?m({ok,Cover}, reltool_server:get_mod(Pid,cover)),
%% Undo again, to check that it toggles
- ?m(ok, reltool_server:undo_config(Pid)),
+ ?m({ok,[]}, reltool_server:undo_config(Pid)),
?m({ok,NoTools}, reltool_server:get_app(Pid,tools)),
- ?m({ok,[]}, reltool:get_status(Pid)),
+ ?m({ok,NoIncludeCover}, reltool_server:get_mod(Pid,cover)),
?m(ok, reltool:stop(Pid)),
ok.
@@ -674,12 +714,16 @@ load_config_and_undo(Config) ->
{ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
?m({ok, Sys1}, reltool:get_config(Pid)),
- %% Check that tools is included
+ %% Get app and mod
{ok,Tools1} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
?m(true, Tools1#app.is_pre_included),
?m(true, Tools1#app.is_included),
+ {ok,Cover1} = ?msym({ok,#mod{name=cover,
+ is_included=true,
+ is_pre_included=true}},
+ reltool_server:get_mod(Pid,cover)),
- %% Exclude one application with set_apps
+ %% Change tools from include to derived by loading new config
Sys2 = {sys,[{lib_dirs,[filename:join(datadir(Config),"faulty_app_file")]},
{incl_cond, exclude},
{app,kernel,[{incl_cond,include}]},
@@ -695,16 +739,20 @@ load_config_and_undo(Config) ->
{ok,Tools2} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
?m(undefined, Tools2#app.is_pre_included),
?m(true, Tools2#app.is_included),
+ {ok,Cover2} = ?msym({ok,#mod{name=cover,
+ is_included=true,
+ is_pre_included=undefined}},
+ reltool_server:get_mod(Pid,cover)),
%% Undo
- ?m(ok, reltool_server:undo_config(Pid)),
+ ?m({ok,[]}, reltool_server:undo_config(Pid)),
?m({ok,Tools1}, reltool_server:get_app(Pid,tools)),
- ?m({ok,[]}, reltool:get_status(Pid)),
+ ?m({ok,Cover1}, reltool_server:get_mod(Pid,cover)),
%% Undo again, to check that it toggles
- ?m(ok, reltool_server:undo_config(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:undo_config(Pid)),
?m({ok,Tools2}, reltool_server:get_app(Pid,tools)),
- ?msym({ok,["a: Cannot parse app file"++_]}, reltool:get_status(Pid)),
+ ?m({ok,Cover2}, reltool_server:get_mod(Pid,cover)),
?m(ok, reltool:stop(Pid)),
ok.
@@ -722,12 +770,16 @@ reset_config_and_undo(Config) ->
{ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
?m({ok, Sys1}, reltool:get_config(Pid)),
- %% Check that tools is included
+ %% Get app and mod
{ok,Tools1} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
?m(true, Tools1#app.is_pre_included),
?m(true, Tools1#app.is_included),
+ {ok,Cover1} = ?msym({ok,#mod{name=cover,
+ is_included=true,
+ is_pre_included=true}},
+ reltool_server:get_mod(Pid,cover)),
- %% Exclude one application with set_apps
+ %% Exclude tools by loading new config
Sys2 = {sys,[{incl_cond, exclude},
{app,kernel,[{incl_cond,include}]},
{app,sasl,[{incl_cond,include}]},
@@ -739,17 +791,27 @@ reset_config_and_undo(Config) ->
{ok,Tools2} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
?m(false, Tools2#app.is_pre_included),
?m(false, Tools2#app.is_included),
+ {ok,Cover2} = ?msym({ok,#mod{name=cover,
+ is_included=false,
+ is_pre_included=false}},
+ reltool_server:get_mod(Pid,cover)),
%% Reset
%%! warning can come twice here... :(
?msym({ok,["a: Cannot parse app file"++_|_]},
reltool_server:reset_config(Pid)),
?m({ok,Tools1}, reltool_server:get_app(Pid,tools)),
+ ?m({ok,Cover1}, reltool_server:get_mod(Pid,cover)),
- %% Undo again, to check that it toggles
- ?m(ok, reltool_server:undo_config(Pid)),
+ %% Undo
+ ?m({ok,[]}, reltool_server:undo_config(Pid)),
?m({ok,Tools2}, reltool_server:get_app(Pid,tools)),
- ?m({ok,[]}, reltool:get_status(Pid)),
+ ?m({ok,Cover2}, reltool_server:get_mod(Pid,cover)),
+
+ %% Undo again, to check that it toggles
+ ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:undo_config(Pid)),
+ ?m({ok,Tools1}, reltool_server:get_app(Pid,tools)),
+ ?m({ok,Cover1}, reltool_server:get_mod(Pid,cover)),
?m(ok, reltool:stop(Pid)),
ok.
@@ -851,8 +913,6 @@ save_config(Config) ->
%% Test includes x and derives y and z.
%%
dependencies(Config) ->
- PrivDir = ?config(priv_dir,Config),
-
%% Default: all modules included => y and z are included (derived)
Sys = {sys,[{lib_dirs,[filename:join(datadir(Config),"dependencies")]},
{incl_cond, exclude},
--
cgit v1.2.3
From f515a08b3a57c854ee547e6c84c39e2fd14a27da Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Tue, 24 Jan 2012 15:46:31 +0100
Subject: [reltool] Add more tests
OTP-9794
Test cases are added for the following functions:
* reltool_server:get_sys
* reltool_server:set_sys
* reltool_server:get_status
* reltool_server:gen_rel_files
* reltool:eval_target_spec
* reltool:get_server
---
lib/reltool/test/reltool_server_SUITE.erl | 156 +++++++++++++++++++++++++++---
lib/reltool/test/reltool_wx_SUITE.erl | 8 +-
2 files changed, 151 insertions(+), 13 deletions(-)
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index 79c6854465..fc2d844d07 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -54,11 +54,11 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[start_server, set_config, get_config, create_release,
create_script, create_target, create_embedded,
- create_standalone, create_old_target,
+ create_standalone, create_old_target, eval_target_spec,
otp_9135, otp_9229_exclude_app, otp_9229_exclude_mod,
- get_apps, get_mod, set_app_and_undo, set_apps_and_undo,
- load_config_and_undo, reset_config_and_undo, save_config,
- dependencies].
+ get_apps, get_mod, get_sys, set_app_and_undo, set_apps_and_undo,
+ set_sys_and_undo, load_config_and_undo, reset_config_and_undo,
+ gen_rel_files, save_config, dependencies].
groups() ->
[].
@@ -442,6 +442,38 @@ create_old_target(_Config) ->
ok.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate target system with eval_target_spec/3
+
+eval_target_spec(_Config) ->
+ %% Configure the server
+ RelName1 = "Just testing",
+ RelName2 = "Just testing with SASL",
+ RelVsn = "1.0",
+ Config =
+ {sys,
+ [
+ {root_dir, code:root_dir()},
+ {lib_dirs, []},
+ {boot_rel, RelName2},
+ {rel, RelName1, RelVsn, [stdlib, kernel]},
+ {rel, RelName2, RelVsn, [sasl, stdlib, kernel]},
+ {app, sasl, [{incl_cond, include}]}
+ ]},
+
+ %% Generate target file
+ TargetDir = filename:join([?WORK_DIR, "eval_target_spec"]),
+ ?m(ok, reltool_utils:recursive_delete(TargetDir)),
+ ?m(ok, file:make_dir(TargetDir)),
+ {ok, Spec} = ?msym({ok,_}, reltool:get_target_spec([{config, Config}])),
+ ok = ?m(ok, reltool:eval_target_spec(Spec, code:root_dir(), TargetDir)),
+
+ Erl = filename:join([TargetDir, "bin", "erl"]),
+ {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
+ ?msym(ok, stop_node(Node)),
+
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% OTP-9229 - handle duplicated module names, i.e. same module name
%% exists in two applications.
@@ -556,9 +588,8 @@ otp_9229_exclude_mod(Config) ->
%% load_config
%% reset_config
%%
-%% Also, for each operation which manipulates the config test
-%% undo_config - that it is properly undone, and that warnings are
-%% re-displayed.
+%% Also, for each operation which manipulates the config, test
+%% get_status and undo_config.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
get_apps(_Config) ->
Sys = {sys,[{app,kernel,[{incl_cond,include}]},
@@ -592,7 +623,6 @@ get_apps(_Config) ->
?m(Number,length(AllN)),
?m(ok, reltool:stop(Pid)),
-
ok.
@@ -613,10 +643,24 @@ get_mod(_Config) ->
?m({ok,Cover}, reltool_server:get_mod(Pid,cover)),
?m(ok, reltool:stop(Pid)),
-
ok.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+get_sys(_Config) ->
+ Sys = {sys,[{app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,tools,[{incl_cond,derived}]},
+ {app,runtime_tools,[{incl_cond,exclude}]}]},
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
+
+ RootDir = code:root_dir(),
+ ?msym({ok,#sys{root_dir=RootDir,apps=undefined}},reltool_server:get_sys(Pid)),
+
+ ?m(ok, reltool:stop(Pid)),
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
set_app_and_undo(Config) ->
Sys = {sys,[{lib_dirs,[filename:join(datadir(Config),"faulty_app_file")]},
@@ -628,6 +672,7 @@ set_app_and_undo(Config) ->
{app,tools,[{incl_cond,include}]}]},
{ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
?m({ok, Sys}, reltool:get_config(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
%% Get app and mod
{ok,Tools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
@@ -639,6 +684,7 @@ set_app_and_undo(Config) ->
Mods = Tools#app.mods,
Tools1 = Tools#app{mods = lists:keyreplace(cover,#mod.name,Mods,ExclCover)},
{ok,ToolsNoCover,[]} = ?msym({ok,_,[]}, reltool_server:set_app(Pid,Tools1)),
+ ?m({ok,[]}, reltool_server:get_status(Pid)),
%% Check that the module is no longer included
?m({ok,ToolsNoCover}, reltool_server:get_app(Pid,tools)),
@@ -650,11 +696,13 @@ set_app_and_undo(Config) ->
?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:undo_config(Pid)),
?m({ok,Tools}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover}, reltool_server:get_mod(Pid,cover)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
%% Undo again, to check that it toggles
?m({ok,[]}, reltool_server:undo_config(Pid)),
?m({ok,ToolsNoCover}, reltool_server:get_app(Pid,tools)),
?m({ok,NoIncludeCover}, reltool_server:get_mod(Pid,cover)),
+ ?m({ok,[]}, reltool_server:get_status(Pid)),
?m(ok, reltool:stop(Pid)),
ok.
@@ -670,6 +718,7 @@ set_apps_and_undo(Config) ->
{app,tools,[{incl_cond,include}]}]},
{ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
?m({ok, Sys}, reltool:get_config(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
%% Get app and mod
{ok,Tools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
@@ -681,6 +730,7 @@ set_apps_and_undo(Config) ->
%% Exclude one application with set_apps
ExclTools = Tools#app{incl_cond=exclude},
?m({ok,[]}, reltool_server:set_apps(Pid,[ExclTools])),
+ ?m({ok,[]}, reltool_server:get_status(Pid)),
%% Check that the app and its modules (one of them) are no longer included
{ok,NoTools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
@@ -694,16 +744,53 @@ set_apps_and_undo(Config) ->
?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:undo_config(Pid)),
?m({ok,Tools}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover}, reltool_server:get_mod(Pid,cover)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
%% Undo again, to check that it toggles
?m({ok,[]}, reltool_server:undo_config(Pid)),
?m({ok,NoTools}, reltool_server:get_app(Pid,tools)),
?m({ok,NoIncludeCover}, reltool_server:get_mod(Pid,cover)),
+ ?m({ok,[]}, reltool_server:get_status(Pid)),
?m(ok, reltool:stop(Pid)),
ok.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+set_sys_and_undo(Config) ->
+ Sys1 = {sys,[{incl_cond, exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,tools,[{incl_cond,include}]}]},
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
+ ?m({ok,[]}, reltool_server:get_status(Pid)),
+
+ %% Read sys record
+ {ok, SysRec} = reltool_server:get_sys(Pid),
+
+ %% Set lib dirs by call to set_sys
+ NewLib = filename:join(datadir(Config),"faulty_app_file"),
+ NewLibDirs = [NewLib | SysRec#sys.lib_dirs],
+ NewSysRec = SysRec#sys{lib_dirs=NewLibDirs},
+ ?msym({ok,["a: Cannot parse app file"++_|_]},
+ reltool_server:set_sys(Pid, NewSysRec)),
+ ?m({ok,NewSysRec}, reltool_server:get_sys(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
+
+ %% Undo
+ ?m({ok,[]}, reltool_server:undo_config(Pid)),
+ ?m({ok,SysRec}, reltool_server:get_sys(Pid)),
+ ?m({ok,[]}, reltool_server:get_status(Pid)),
+
+ %% Undo again, to check that it toggles
+ ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:undo_config(Pid)),
+ ?m({ok,NewSysRec}, reltool_server:get_sys(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
+
+ ?m(ok, reltool:stop(Pid)),
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
load_config_and_undo(Config) ->
Sys1 = {sys,[{incl_cond, exclude},
@@ -713,6 +800,7 @@ load_config_and_undo(Config) ->
{app,tools,[{incl_cond,include}]}]},
{ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
?m({ok, Sys1}, reltool:get_config(Pid)),
+ ?m({ok,[]}, reltool_server:get_status(Pid)),
%% Get app and mod
{ok,Tools1} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
@@ -725,14 +813,17 @@ load_config_and_undo(Config) ->
%% Change tools from include to derived by loading new config
Sys2 = {sys,[{lib_dirs,[filename:join(datadir(Config),"faulty_app_file")]},
- {incl_cond, exclude},
+ {app,a,[{incl_cond,include}]},
{app,kernel,[{incl_cond,include}]},
{app,sasl,[{incl_cond,include}]},
{app,stdlib,[{incl_cond,include}]},
- {app,tools,[{incl_cond,derived}]},
- {app,a,[{incl_cond,include}]}]},
+ {app,tools,[{incl_cond,derived}]}]},
?msym({ok,["a: Cannot parse app file"++_]},
reltool_server:load_config(Pid,Sys2)),
+%%% OTP-0702, 15) ?m({ok, Sys2}, reltool:get_config(Pid)),
+%%% Note that {incl_cond,exclude} is removed compared to Sys1 -
+%%% config is merged, not overwritten - is this correct???
+ ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
%% Check that tools is included (since it is used by sasl) but not
%% pre-included (neither included or excluded => undefined)
@@ -748,11 +839,13 @@ load_config_and_undo(Config) ->
?m({ok,[]}, reltool_server:undo_config(Pid)),
?m({ok,Tools1}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover1}, reltool_server:get_mod(Pid,cover)),
+ ?m({ok,[]}, reltool_server:get_status(Pid)),
%% Undo again, to check that it toggles
?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:undo_config(Pid)),
?m({ok,Tools2}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover2}, reltool_server:get_mod(Pid,cover)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
?m(ok, reltool:stop(Pid)),
ok.
@@ -769,6 +862,7 @@ reset_config_and_undo(Config) ->
{app,tools,[{incl_cond,include}]}]},
{ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
?m({ok, Sys1}, reltool:get_config(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
%% Get app and mod
{ok,Tools1} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
@@ -786,6 +880,7 @@ reset_config_and_undo(Config) ->
{app,stdlib,[{incl_cond,include}]},
{app,tools,[{incl_cond,exclude}]}]},
?m({ok,[]}, reltool_server:load_config(Pid,Sys2)),
+ ?m({ok,[]}, reltool_server:get_status(Pid)),
%% Check that tools is excluded
{ok,Tools2} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
@@ -802,16 +897,53 @@ reset_config_and_undo(Config) ->
reltool_server:reset_config(Pid)),
?m({ok,Tools1}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover1}, reltool_server:get_mod(Pid,cover)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
%% Undo
?m({ok,[]}, reltool_server:undo_config(Pid)),
?m({ok,Tools2}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover2}, reltool_server:get_mod(Pid,cover)),
+ ?m({ok,[]}, reltool_server:get_status(Pid)),
%% Undo again, to check that it toggles
?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:undo_config(Pid)),
?m({ok,Tools1}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover1}, reltool_server:get_mod(Pid,cover)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
+
+ ?m(ok, reltool:stop(Pid)),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+gen_rel_files(_Config) ->
+ %% Configure the server
+ RelName = "gen_fel_files_test",
+ RelVsn = "1.0",
+ Sys =
+ {sys,
+ [
+ {lib_dirs, []},
+ {boot_rel, RelName},
+ {rel, RelName, RelVsn, [kernel, stdlib]}
+ ]},
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
+
+ %% Generate .rel, .script and .boot
+ Dir = filename:join(?WORK_DIR,"gen_rel_files"),
+ ok = file:make_dir(Dir),
+ ?m({ok,[]}, reltool_server:gen_rel_files(Pid,Dir)),
+
+ Script = RelName ++ ".script",
+ Rel = RelName ++ ".rel",
+ Boot = RelName ++ ".boot",
+ {ok,Files} = ?msym({ok,_}, file:list_dir(Dir)),
+ [Boot,Rel,Script] = lists:sort(Files),
+
+ %% Check that contents is reasonable
+ {ok,[S]} = ?msym({ok,[{script,_,_}]},file:consult(filename:join(Dir,Script))),
+ ?msym({ok,[{release,_,_,_}]}, file:consult(filename:join(Dir,Rel))),
+ {ok,Bin} = ?msym({ok,_}, file:read_file(filename:join(Dir,Boot))),
+ ?m(S,binary_to_term(Bin)),
?m(ok, reltool:stop(Pid)),
ok.
diff --git a/lib/reltool/test/reltool_wx_SUITE.erl b/lib/reltool/test/reltool_wx_SUITE.erl
index 424bc7d189..51f433f206 100644
--- a/lib/reltool/test/reltool_wx_SUITE.erl
+++ b/lib/reltool/test/reltool_wx_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -63,6 +63,12 @@ start_all_windows(_Config) ->
{ok, SysPid} = ?msym({ok, _}, reltool:start([{trap_exit, false}])),
{ok, AppPid} = ?msym({ok, _}, reltool_sys_win:open_app(SysPid, stdlib)),
?msym({ok, _}, reltool_app_win:open_mod(AppPid, escript)),
+
+ %% Test that server pid can be fetched, and that server is alive
+ {ok, Server} = ?msym({ok,_}, reltool:get_server(SysPid)),
+ ?m(true, erlang:is_process_alive(Server)),
+ ?m({ok,{sys,[]}}, reltool:get_config(Server)),
+
timer:sleep(timer:seconds(10)),
?m(ok, reltool:stop(SysPid)),
--
cgit v1.2.3
From 3fef8ee7031a16a038c9f87dc8cf8ea44064e6ed Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Wed, 25 Jan 2012 16:24:35 +0100
Subject: [reltool] Add more GUI tests
OTP-9794
This commit adds a test suite for manual testing of the reltool
GUI. By use of test_server:break/1 function, it guides the user
through a set of tests in the GUI.
Some minor checks are also added to the automatic GUI test,
reltool_wx_SUITE.
---
lib/reltool/test/Makefile | 3 +-
lib/reltool/test/reltool.spec | 1 +
lib/reltool/test/reltool_manual_gui_SUITE.erl | 247 +++++++++++++++++++++
.../reltool_manual_gui_SUITE_data/Makefile.src | 28 +++
.../dependencies/x-1.0/ebin/x.app | 7 +
.../dependencies/x-1.0/src/x1.erl | 5 +
.../dependencies/x-1.0/src/x2.erl | 5 +
.../dependencies/x-1.0/src/x3.erl | 5 +
.../dependencies/y-1.0/ebin/y.app | 7 +
.../dependencies/y-1.0/src/y1.erl | 5 +
.../dependencies/y-1.0/src/y2.erl | 5 +
.../dependencies/y-1.0/src/y3.erl | 5 +
.../dependencies/z-1.0/ebin/z.app | 7 +
.../dependencies/z-1.0/src/z1.erl | 5 +
.../faulty_app_file/a-1.0/ebin/a.app | 1 +
.../faulty_app_file/a-1.0/src/a.erl | 49 ++++
.../faulty_app_file/a-1.0/src/a_sup.erl | 37 +++
lib/reltool/test/reltool_wx_SUITE.erl | 37 ++-
18 files changed, 455 insertions(+), 4 deletions(-)
create mode 100644 lib/reltool/test/reltool_manual_gui_SUITE.erl
create mode 100644 lib/reltool/test/reltool_manual_gui_SUITE_data/Makefile.src
create mode 100644 lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/ebin/x.app
create mode 100644 lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x1.erl
create mode 100644 lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x2.erl
create mode 100644 lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x3.erl
create mode 100644 lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/ebin/y.app
create mode 100644 lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y1.erl
create mode 100644 lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y2.erl
create mode 100644 lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y3.erl
create mode 100644 lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/z-1.0/ebin/z.app
create mode 100644 lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/z-1.0/src/z1.erl
create mode 100644 lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/ebin/a.app
create mode 100644 lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/src/a.erl
create mode 100644 lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/src/a_sup.erl
diff --git a/lib/reltool/test/Makefile b/lib/reltool/test/Makefile
index 767454b66a..d8a7adb837 100644
--- a/lib/reltool/test/Makefile
+++ b/lib/reltool/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2011. All Rights Reserved.
+# Copyright Ericsson AB 2009-2012. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -28,6 +28,7 @@ MODULES= \
reltool_app_SUITE \
reltool_wx_SUITE \
reltool_server_SUITE \
+ reltool_manual_gui_SUITE \
reltool_test_lib
diff --git a/lib/reltool/test/reltool.spec b/lib/reltool/test/reltool.spec
index 2995720105..2501a7a203 100644
--- a/lib/reltool/test/reltool.spec
+++ b/lib/reltool/test/reltool.spec
@@ -1 +1,2 @@
{suites,"../reltool_test",all}.
+{skip_suites,"../reltool_test",[reltool_manual_gui_SUITE],"Manual only"}.
diff --git a/lib/reltool/test/reltool_manual_gui_SUITE.erl b/lib/reltool/test/reltool_manual_gui_SUITE.erl
new file mode 100644
index 0000000000..c6b1d56988
--- /dev/null
+++ b/lib/reltool/test/reltool_manual_gui_SUITE.erl
@@ -0,0 +1,247 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+
+-module(reltool_manual_gui_SUITE).
+
+-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
+ init_per_suite/1, end_per_suite/1,
+ init_per_testcase/2, end_per_testcase/2]).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include("reltool_test_lib.hrl").
+
+%% Initialization functions.
+init_per_suite(Config) ->
+ reltool_test_lib:wx_init_per_suite(Config).
+
+end_per_suite(Config) ->
+ reltool_test_lib:wx_end_per_suite(Config).
+
+init_per_testcase(Func,Config) ->
+ reltool_test_lib:init_per_testcase(Func,Config).
+end_per_testcase(Func,Config) ->
+ reltool_test_lib:end_per_testcase(Func,Config).
+
+%% SUITE specification
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [config, depgraphs].
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+
+%% The test cases
+
+%% Semi-automatic walkthrough of the GUI
+config(Config) ->
+ DataDir = ?config(data_dir,Config),
+ PrivDir = ?config(priv_dir,Config),
+ {ok, SysPid} = ?msym({ok, _}, reltool:start([])),
+ link(SysPid),
+
+ SimpleConfigFile = create_simple_config(PrivDir),
+ WarningConfigFile = create_warning_config(PrivDir,DataDir),
+
+ break("there are no modules in the 'Included' and 'Excluded' columns",
+ {"load configuration ~p",[SimpleConfigFile]}),
+ break("kernel, stdlib and sasl are included and all other are excluded",
+ "undo"),
+ break("we are back to default - no included and no excluded applications",
+ "undo again"),
+ break("kernel, stdlib and sasl are included and all other are excluded",
+ {"load configuration ~p, but click 'cancel' in the warning dialog",
+ [WarningConfigFile]}),
+ break("no change is done",
+ "load same configuration again and this time click 'ok' in the dialog"),
+ break("application a is added in the 'Included' column",
+ "reset configuration"),
+ break("we are back to default - no included and no excluded applications",
+ "undo"),
+ break("a warning dialog is displayed, with only an ok button",
+ "click ok"),
+ break("a, kernel, stdlib and sasl are included and all other are excluded",
+ "select application a from 'Included' column and click red cross to "
+ "exclude it"),
+ break("application a is moved to 'Excluded' column",
+ "select application tools from 'Excluded' column and click green V to "
+ "include it"),
+ break("application tools is moved to 'Included' column",
+ "select application runtime-tools from 'Excluded' column and click "
+ "green V to include it"),
+ break("application runtime-tools is moved to 'Included' column",
+ "undo"),
+
+ ExplicitConfig = filename:join(PrivDir,"explicit.config"),
+ break("application runtime-tools is moved back to 'Excluded' column",
+ {"save configuration as 'explicit' to ~p",[ExplicitConfig]}),
+ ExpectedExplicitConfig =
+ {sys,[{lib_dirs,[filename:join(DataDir,"faulty_app_file")]},
+ {incl_cond,exclude},
+ {app,a,[{incl_cond,exclude}]},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,tools,[{incl_cond,include}]}]},
+ check_config(ExpectedExplicitConfig,ExplicitConfig),
+
+ break("The saved configuration file is checked and is ok.\n"
+ "Now go to the 'Libraries' tab and change the root directory to "
+ "some invalid directory."),
+ break("an error dialog occurs saying that there is no lib dir",
+ {"add library directory ~p, and click 'ok' in warning dialog",
+ [filename:join(DataDir,"dependencies")]}),
+ break("applications x, y and z are added to the 'Excluded' column in "
+ "'Applications' tab",
+ "go to the 'System settings' tab and set application inclusion policy "
+ "to 'derived'"),
+ break("a is excluded, kernel, stdlib, sasl and tools are included and "
+ "x, y and z are available in the 'Applications' tab",
+ "undo, and click ok in the warning dialog"),
+ break("all non included application are moved to the 'Excluded' column "
+ "and that 'Application inclusion policy' under 'System settings' "
+ "tab is set back to 'exclude'",
+ "undo again"),
+ break("applications x, y and z are in the 'Available' column",
+ "open application x, go to the 'Application settings' tab and set "
+ "'Application inclusion policy' to 'Use application specific config' "
+ "and 'include'. Close the window"),
+ break("application x is moved to the 'Included' column and z and y are moved "
+ "to the 'Derived' column in the system window",
+ "open application y"),
+ break("modules y1, y2 and y3 are in the 'Derived' column",
+ "go to 'Application dependencies' tab"),
+ break("application y is used by x, requires kernel and stdlib, and uses z",
+ "go to 'Module dependencies' tab"),
+ break("y is used by x2 and x3, and uses z1",
+ "got to 'Application settings' tab and select "
+ "'Source selection policy' 'Use selected version'"),
+ break("'Directories' frame becomes enabled (clickable)",
+ "select 'Module inclusion policy' 'Use application specific config' "
+ "and select 'app file + derived'"),
+ break("module y3 is moved to the 'Available' column in the 'Modules' tab",
+ "open module y1"),
+ break("module y1 is used by x2 and uses z1",
+ "go to the 'Code' tab and double click the line with call to z1:f()"),
+ break("new tab is opened with module z1",
+ "find something"),
+ break("it is found",
+ "goto some line"),
+ break("the cursor is moved to that line",
+ "click the 'Back' button"),
+ break("the cursor is moved back to the line of your previous 'find'",
+ "terminate the application window (but keep the module window)."),
+
+ {ok,ServerPid} = reltool:get_server(SysPid),
+ unlink(SysPid),
+ break("the system window is still alive",
+ "terminate reltool by hitting 'Ctrl-q' when system window is active"),
+ false = erlang:is_process_alive(SysPid),
+ false = erlang:is_process_alive(ServerPid),
+
+ break("Check that both module window and system window are terminated"),
+
+ ok.
+
+
+depgraphs(Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ SimpleConfigFile = create_simple_config(PrivDir),
+ {ok, SysPid} = ?msym({ok, _}, reltool:start([{config,SimpleConfigFile}])),
+ link(SysPid),
+
+ break("Open the application dependency graph and \n\n"
+ "*move the complete graph by left clicking somewhere over it and drag\n"
+ "*move one node left clicking the node and drag\n"
+ "*lock node to position by holding down shift while releasing\n"
+ "*select several nodes with ctrl and left mouse button\n"
+ "*lock/unlock selected nodes with suitable buttons\n"
+ "*freeze\n"
+ "*reset\n"
+ "*left slider: push nodes apart\n"
+ "*right slider: pull nodes together\n"
+ "*middle slider: adjust length of links\n"
+ "*select node and delete\n"),
+ break("Open the module dependency graph and meditate over it... "),
+
+ unlink(SysPid),
+ break("Terminate reltool from the file menu in the system window"),
+ false = erlang:is_process_alive(SysPid),
+
+ break("Check that system window and graphs are terminated"),
+
+ ok.
+
+
+
+
+%%%-----------------------------------------------------------------
+%%% Internal functions
+break(CheckStr,DoStr) when is_list(CheckStr), is_list(DoStr) ->
+ Str = io_lib:format("Check that ~s.~n~nThen ~s.",[CheckStr,DoStr]),
+ break(Str);
+break(Check,Do) ->
+ CheckStr =
+ case Check of
+ {CheckFormat,CheckArgs} -> io_lib:format(CheckFormat,CheckArgs);
+ _ -> Check
+ end,
+ DoStr =
+ case Do of
+ {DoFormat,DoArgs} -> io_lib:format(DoFormat,DoArgs);
+ _ -> Do
+ end,
+ break(CheckStr,DoStr).
+
+break(Str) ->
+ test_server:break(Str).
+
+check_config(Expected,File) ->
+ {ok,[Config]} = file:consult(File),
+ ?m(Expected,Config).
+
+create_simple_config(PrivDir) ->
+ SimpleConfigFile = filename:join(PrivDir,"simple.config"),
+ SimpleConfig = {sys,[{incl_cond,exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]}]},
+ ok=file:write_file(SimpleConfigFile,io_lib:format("~p.~n",[SimpleConfig])),
+ SimpleConfigFile.
+
+create_warning_config(PrivDir,DataDir) ->
+ WarningConfigFile = filename:join(PrivDir,"warning.config"),
+ FaultyAppFileDir = filename:join(DataDir,"faulty_app_file"),
+ WarningConfig = {sys,[{lib_dirs,[FaultyAppFileDir]},
+ {incl_cond,exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,a,[{incl_cond,include}]}
+ ]},
+ ok=file:write_file(WarningConfigFile,io_lib:format("~p.~n",[WarningConfig])),
+ WarningConfigFile.
diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/Makefile.src b/lib/reltool/test/reltool_manual_gui_SUITE_data/Makefile.src
new file mode 100644
index 0000000000..9a340274ad
--- /dev/null
+++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/Makefile.src
@@ -0,0 +1,28 @@
+EFLAGS=+debug_info
+
+DEPENDENCIES= \
+ dependencies/x-1.0/ebin/x1.@EMULATOR@ \
+ dependencies/x-1.0/ebin/x2.@EMULATOR@ \
+ dependencies/x-1.0/ebin/x3.@EMULATOR@ \
+ dependencies/y-1.0/ebin/y1.@EMULATOR@ \
+ dependencies/y-1.0/ebin/y2.@EMULATOR@ \
+ dependencies/y-1.0/ebin/y3.@EMULATOR@ \
+ dependencies/z-1.0/ebin/z1.@EMULATOR@
+
+
+all: $(DEPENDENCIES)
+
+dependencies/x-1.0/ebin/x1.@EMULATOR@: dependencies/x-1.0/src/x1.erl
+ erlc $(EFLAGS) -odependencies/x-1.0/ebin dependencies/x-1.0/src/x1.erl
+dependencies/x-1.0/ebin/x2.@EMULATOR@: dependencies/x-1.0/src/x2.erl
+ erlc $(EFLAGS) -odependencies/x-1.0/ebin dependencies/x-1.0/src/x2.erl
+dependencies/x-1.0/ebin/x3.@EMULATOR@: dependencies/x-1.0/src/x3.erl
+ erlc $(EFLAGS) -odependencies/x-1.0/ebin dependencies/x-1.0/src/x3.erl
+dependencies/y-1.0/ebin/y1.@EMULATOR@: dependencies/y-1.0/src/y1.erl
+ erlc $(EFLAGS) -odependencies/y-1.0/ebin dependencies/y-1.0/src/y1.erl
+dependencies/y-1.0/ebin/y2.@EMULATOR@: dependencies/y-1.0/src/y2.erl
+ erlc $(EFLAGS) -odependencies/y-1.0/ebin dependencies/y-1.0/src/y2.erl
+dependencies/y-1.0/ebin/y3.@EMULATOR@: dependencies/y-1.0/src/y3.erl
+ erlc $(EFLAGS) -odependencies/y-1.0/ebin dependencies/y-1.0/src/y3.erl
+dependencies/z-1.0/ebin/z1.@EMULATOR@: dependencies/z-1.0/src/z1.erl
+ erlc $(EFLAGS) -odependencies/z-1.0/ebin dependencies/z-1.0/src/z1.erl
diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/ebin/x.app b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/ebin/x.app
new file mode 100644
index 0000000000..ccaab8a8c7
--- /dev/null
+++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/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,x2,x3]},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.
diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x1.erl b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x1.erl
new file mode 100644
index 0000000000..bf1e7f9279
--- /dev/null
+++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x1.erl
@@ -0,0 +1,5 @@
+-module(x1).
+-compile(export_all).
+
+f() ->
+ ok.
diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x2.erl b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x2.erl
new file mode 100644
index 0000000000..82191ba278
--- /dev/null
+++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x2.erl
@@ -0,0 +1,5 @@
+-module(x2).
+-compile(export_all).
+
+f() ->
+ y1:f().
diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x3.erl b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x3.erl
new file mode 100644
index 0000000000..618c75c9a7
--- /dev/null
+++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x3.erl
@@ -0,0 +1,5 @@
+-module(x3).
+-compile(export_all).
+
+f() ->
+ y2:f().
diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/ebin/y.app b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/ebin/y.app
new file mode 100644
index 0000000000..4f9b610b69
--- /dev/null
+++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/ebin/y.app
@@ -0,0 +1,7 @@
+% -*-erlang-*-
+{application, y,
+ [{description, "Library application in reltool dependency test"},
+ {vsn, "1.0"},
+ {modules, [y1,y2]}, % y3 is skipped on purpose - to test module inclusion policy
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.
diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y1.erl b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y1.erl
new file mode 100644
index 0000000000..dd21b33292
--- /dev/null
+++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y1.erl
@@ -0,0 +1,5 @@
+-module(y1).
+-compile(export_all).
+
+f() ->
+ z1:f().
diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y2.erl b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y2.erl
new file mode 100644
index 0000000000..bf8ddf6080
--- /dev/null
+++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y2.erl
@@ -0,0 +1,5 @@
+-module(y2).
+-compile(export_all).
+
+f() ->
+ ok.
diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y3.erl b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y3.erl
new file mode 100644
index 0000000000..915d64d5b9
--- /dev/null
+++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y3.erl
@@ -0,0 +1,5 @@
+-module(y3).
+-compile(export_all).
+
+f() ->
+ ok.
diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/z-1.0/ebin/z.app b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/z-1.0/ebin/z.app
new file mode 100644
index 0000000000..437a0968e9
--- /dev/null
+++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/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_manual_gui_SUITE_data/dependencies/z-1.0/src/z1.erl b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/z-1.0/src/z1.erl
new file mode 100644
index 0000000000..97ef90b87f
--- /dev/null
+++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/z-1.0/src/z1.erl
@@ -0,0 +1,5 @@
+-module(z1).
+-compile(export_all).
+
+f() ->
+ ok.
diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/ebin/a.app b/lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/ebin/a.app
new file mode 100644
index 0000000000..ea77103598
--- /dev/null
+++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/ebin/a.app
@@ -0,0 +1 @@
+faulty app file
diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/src/a.erl b/lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/src/a.erl
new file mode 100644
index 0000000000..bb500bed69
--- /dev/null
+++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/src/a.erl
@@ -0,0 +1,49 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+%% AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(a).
+
+
+-behaviour(gen_server).
+
+-vsn(1).
+
+%% External exports
+-export([start_link/0, a/0]).
+%% Internal exports
+-export([init/1, handle_call/3, handle_info/2, terminate/2]).
+
+start_link() -> gen_server:start_link({local, aa}, a, [], []).
+
+a() -> gen_server:call(aa, a).
+
+%%-----------------------------------------------------------------
+%% Callback functions from gen_server
+%%-----------------------------------------------------------------
+init([]) ->
+ process_flag(trap_exit, true),
+ {ok, state}.
+
+handle_call(a, _From, State) ->
+ X = application:get_all_env(a),
+ {reply, X, State}.
+
+handle_info(_, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/src/a_sup.erl b/lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/src/a_sup.erl
new file mode 100644
index 0000000000..a141c1767b
--- /dev/null
+++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/src/a_sup.erl
@@ -0,0 +1,37 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+%% AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(a_sup).
+
+
+-behaviour(supervisor).
+
+%% External exports
+-export([start/2]).
+
+%% Internal exports
+-export([init/1]).
+
+start(_, _) ->
+ supervisor:start_link({local, a_sup}, a_sup, []).
+
+init([]) ->
+ SupFlags = {one_for_one, 4, 3600},
+ Config = {a,
+ {a, start_link, []},
+ permanent, 2000, worker, [a]},
+ {ok, {SupFlags, [Config]}}.
diff --git a/lib/reltool/test/reltool_wx_SUITE.erl b/lib/reltool/test/reltool_wx_SUITE.erl
index 51f433f206..13d71f4fd6 100644
--- a/lib/reltool/test/reltool_wx_SUITE.erl
+++ b/lib/reltool/test/reltool_wx_SUITE.erl
@@ -61,15 +61,46 @@ start_all_windows(TestInfo) when is_atom(TestInfo) ->
reltool_test_lib:tc_info(TestInfo);
start_all_windows(_Config) ->
{ok, SysPid} = ?msym({ok, _}, reltool:start([{trap_exit, false}])),
+ erlang:monitor(process,SysPid),
{ok, AppPid} = ?msym({ok, _}, reltool_sys_win:open_app(SysPid, stdlib)),
- ?msym({ok, _}, reltool_app_win:open_mod(AppPid, escript)),
+ erlang:monitor(process,AppPid),
+ {ok, ModPid} = ?msym({ok, _}, reltool_app_win:open_mod(AppPid, escript)),
+ erlang:monitor(process,ModPid),
+
+ %% Let all windows get started
+ timer:sleep(timer:seconds(10)),
%% Test that server pid can be fetched, and that server is alive
{ok, Server} = ?msym({ok,_}, reltool:get_server(SysPid)),
?m(true, erlang:is_process_alive(Server)),
?m({ok,{sys,[]}}, reltool:get_config(Server)),
- timer:sleep(timer:seconds(10)),
+ %% Terminate
+ check_no_win_crash(),
?m(ok, reltool:stop(SysPid)),
-
+ wait_terminate([{sys,SysPid},{app,AppPid},{mod,ModPid}]),
+
ok.
+
+
+%%%-----------------------------------------------------------------
+%%% Internal functions
+check_no_win_crash() ->
+ receive {'DOWN',_,_,_,_} = Down ->
+ ct:log("Unexpected termination of window:~n~p",[Down]),
+ ct:fail("window crashed")
+ after 0 ->
+ ok
+ end.
+
+wait_terminate([]) ->
+ ok;
+wait_terminate([{Win,P}|Rest]) ->
+ receive
+ {'DOWN',_,process,P,shutdown} ->
+ wait_terminate(Rest);
+ {'DOWN',_,process,P,Reason} ->
+ ct:log("~p window terminated with unexpected reason:~n~p",
+ [Win,Reason]),
+ ct:fail("unexpected exit reason from window")
+ end.
--
cgit v1.2.3
From 523573110b7afc1491c1e67865303da2468bcf0f Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Mon, 30 Jan 2012 14:43:06 +0100
Subject: [reltool] Add tests for sorting of applications in .rel and .script
files
OTP-9794
Test cases create_release_sort and create_script_sort are added. The
test are temporarily skipped since they detected quite a few bugs that
will be corrected with OTP-9792.
The following bug is corrected in this commit:'
reltool_server did not recognize {App,InclApps} inside a 'rel'
specification in the reltool config, e.g.
{rel, "myrel", "1.0", [{myapp,[app2]}]}.
---
lib/reltool/src/reltool_server.erl | 6 +-
lib/reltool/test/reltool_server_SUITE.erl | 345 ++++++++++++++++++++-
.../sort_apps/x-1.0/ebin/x.app | 7 +
.../sort_apps/y-1.0/ebin/y.app | 7 +
.../sort_apps/z-1.0/ebin/z.app | 8 +
5 files changed, 363 insertions(+), 10 deletions(-)
create mode 100644 lib/reltool/test/reltool_server_SUITE_data/sort_apps/x-1.0/ebin/x.app
create mode 100644 lib/reltool/test/reltool_server_SUITE_data/sort_apps/y-1.0/ebin/y.app
create mode 100644 lib/reltool/test/reltool_server_SUITE_data/sort_apps/z-1.0/ebin/z.app
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index 7dc2d21158..fcd1ad393e 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -1510,11 +1510,11 @@ decode(#rel{rel_apps = RelApps} = Rel, [RelApp | KeyVals], Status) ->
case RelApp of
Name when is_atom(Name) ->
{true, #rel_app{name = Name}};
- {Name, Type} when is_atom(Name) ->
- {is_type(Type), #rel_app{name = Name, app_type = Type}};
{Name, InclApps} when is_atom(Name), is_list(InclApps) ->
VI = lists:all(fun erlang:is_atom/1, InclApps),
{VI, #rel_app{name = Name, incl_apps = InclApps}};
+ {Name, Type} when is_atom(Name) ->
+ {is_type(Type), #rel_app{name = Name, app_type = Type}};
{Name, Type, InclApps} when is_atom(Name), is_list(InclApps) ->
VT = is_type(Type),
VI = lists:all(fun erlang:is_atom/1, InclApps),
@@ -1606,7 +1606,7 @@ check_app({RelName, AppName}, Apps, Status) ->
Status;
_ ->
Text = lists:concat(["Release ", RelName,
- " uses non included application ",
+ " uses non included application ",
AppName]),
reltool_utils:return_first_error(Status, Text)
end.
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index fc2d844d07..0aca242d4e 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -52,13 +52,32 @@ end_per_testcase(Func,Config) ->
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [start_server, set_config, get_config, create_release,
- create_script, create_target, create_embedded,
- create_standalone, create_old_target, eval_target_spec,
- otp_9135, otp_9229_exclude_app, otp_9229_exclude_mod,
- get_apps, get_mod, get_sys, set_app_and_undo, set_apps_and_undo,
- set_sys_and_undo, load_config_and_undo, reset_config_and_undo,
- gen_rel_files, save_config, dependencies].
+ [start_server,
+ set_config,
+ get_config,
+ create_release,
+ create_release_sort,
+ create_script,
+ create_script_sort,
+ create_target,
+ create_embedded,
+ create_standalone,
+ create_old_target,
+ eval_target_spec,
+ otp_9135,
+ otp_9229_exclude_app,
+ otp_9229_exclude_mod,
+ get_apps,
+ get_mod,
+ get_sys,
+ set_app_and_undo,
+ set_apps_and_undo,
+ set_sys_and_undo,
+ load_config_and_undo,
+ reset_config_and_undo,
+ gen_rel_files,
+ save_config,
+ dependencies].
groups() ->
[].
@@ -250,6 +269,121 @@ create_release(_Config) ->
?m({ok, Rel}, reltool:get_rel([{config, Config}], RelName)),
ok.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate releases and make sure order of applications specified in
+%% 'rel' parameter is preserved and that included applications are
+%% started before the including application.
+%% Circular dependencies shall also be detected and cause error.
+
+create_release_sort(_Config) -> {skip, "Multiple known problems - see OTP-9792"};
+create_release_sort(Config) ->
+ DataDir = ?config(data_dir,Config),
+ %% Configure the server
+ RelName1 = "MnesiaFirst",
+ RelName2 = "SaslFirst",
+ RelName3 = "Include-both",
+ RelName4 = "Include-only-app",
+ RelName5 = "Include-only-rel",
+ RelName6 = "Include-missing-app",
+ RelName7 = "Circular",
+ RelName8 = "Include-both-missing-app",
+ RelName9 = "Include-overwrite",
+ RelVsn = "1.0",
+ Sys =
+ {sys,
+ [
+ {lib_dirs, [filename:join(DataDir,"sort_apps")]},
+ {boot_rel, RelName1},
+ {rel, RelName1, RelVsn, [stdlib, kernel, mnesia, sasl]},
+ {rel, RelName2, RelVsn, [stdlib, kernel, sasl, mnesia]},
+ {rel, RelName3, RelVsn, [stdlib, kernel, {z,[tools]}, tools]},
+ {rel, RelName4, RelVsn, [stdlib, kernel, z, tools]},
+ {rel, RelName5, RelVsn, [stdlib, kernel, {sasl,[tools]}]},
+ {rel, RelName6, RelVsn, [stdlib, kernel, z]}, %z includes tools in .app
+ {rel, RelName7, RelVsn, [stdlib, kernel, mnesia, y, sasl, x]},
+ {rel, RelName8, RelVsn, [stdlib, kernel, {z,[tools]}]},
+ {rel, RelName9, RelVsn, [stdlib, kernel, {z,[]}]},
+ {incl_cond,exclude},
+ {mod_cond,app},
+ {app,kernel,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,mnesia,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,x,[{incl_cond,include}]},
+ {app,y,[{incl_cond,include}]},
+ {app,z,[{incl_cond,include}]},
+ {app,tools,[{mod_cond,app},{incl_cond,include}]}
+ ]},
+ %% Generate release
+
+ %% BUG: reltool reverses the list of applications after kernel and stdlib
+ ?msym({ok, {release, {RelName1, RelVsn},
+ {erts, _},
+ [{kernel, _},
+ {stdlib, _},
+ {mnesia, _},
+ {sasl, _}]}},
+ reltool:get_rel([{config, Sys}], RelName1)),
+
+ %% BUG: reltool reverses the list of applications after kernel and stdlib
+ ?msym({ok, {release, {RelName2, RelVsn},
+ {erts, _},
+ [{kernel, _},
+ {stdlib, _},
+ {sasl, _},
+ {mnesia, _}]}},
+ reltool:get_rel([{config, Sys}], RelName2)),
+
+ ?msym({ok, {release, {RelName3, RelVsn},
+ {erts, _},
+ [{kernel, _},
+ {stdlib, _},
+ {tools, _},
+ {z, _, [tools]}]}},
+ reltool:get_rel([{config, Sys}], RelName3)),
+
+ %% BUG: reltool does not honor included applications in .app files
+ %% unless they are also mentioned in the 'rel' specification in
+ %% the reltool config.
+ %% => order of tools and z does not become correct in rel (tools
+ %% should be first since it is included in z)
+ ?msym({ok, {release, {RelName4, RelVsn},
+ {erts, _},
+ [{kernel, _},
+ {stdlib, _},
+ {tools, _},
+ {z, _}]}},
+ reltool:get_rel([{config, Sys}], RelName4)),
+
+ ?m({error,"sasl: These applications are used by release "
+ "Include-only-rel but are missing as included_applications "
+ "in the app file: [tools]"},
+ reltool:get_rel([{config, Sys}], RelName5)),
+
+ %% BUG: reltool does not honor included applications in .app files
+ %% unless they are also mentioned in the 'rel' specification in
+ %% the reltool config.
+ %% => does not detect that tools (included in z) is missing
+ ?m({error, "Undefined applications: [tools]"},
+ reltool:get_rel([{config, Sys}], RelName6)),
+
+ ?m({error,"Circular dependencies: [x,y]"},
+ reltool:get_rel([{config, Sys}], RelName7)),
+
+ ?m({error,"Undefined applications: [tools]"},
+ reltool:get_rel([{config, Sys}], RelName8)),
+
+ %% BUG: Reltool looses the empty include list for z, which should
+ %% overwrite included_applications statement from the .app file.
+ ?msym({ok,{release,{RelName9,RelVsn},
+ {erts,_},
+ [{kernel,_},
+ {stdlib,_},
+ {z,_,[]}]}},
+ reltool:get_rel([{config, Sys}], RelName9)),
+
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate boot scripts
@@ -298,6 +432,203 @@ create_script(_Config) ->
?m(ok, reltool:stop(Pid)),
ok.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Test creation of .script with different sorting of applications and
+%% included applications.
+%% Test that result is equal to what systools produces
+create_script_sort(_Config) -> {skip, "Multiple known problems - see OTP-9792"};
+create_script_sort(Config) ->
+ DataDir = ?config(data_dir,Config),
+ %% Configure the server
+ RelName1 = "MnesiaFirst",
+ RelName2 = "SaslFirst",
+ RelName3 = "Include-both",
+ RelName4 = "Include-only-app",
+ RelName5 = "Include-only-rel",
+ RelName6 = "Include-missing-app",
+ RelName7 = "Circular",
+ RelName8 = "Include-both-missing-app",
+ RelName9 = "Include-overwrite",
+ RelVsn = "1.0",
+ LibDir = filename:join(DataDir,"sort_apps"),
+ Sys =
+ {sys,
+ [
+ {lib_dirs, [LibDir]},
+ {boot_rel, RelName1},
+ {rel, RelName1, RelVsn, [stdlib, kernel, mnesia, sasl]},
+ {rel, RelName2, RelVsn, [stdlib, kernel, sasl, mnesia]},
+ {rel, RelName3, RelVsn, [stdlib, kernel, {z,[tools]}, tools]},
+ {rel, RelName4, RelVsn, [stdlib, kernel, z, tools]},
+ {rel, RelName5, RelVsn, [stdlib, kernel, {sasl,[tools]}]},
+ {rel, RelName6, RelVsn, [stdlib, kernel, z]}, %z includes tools in .app
+ {rel, RelName7, RelVsn, [stdlib, kernel, mnesia, y, sasl, x]},
+ {rel, RelName8, RelVsn, [stdlib, kernel, {z,[tools]}]},
+ {rel, RelName9, RelVsn, [stdlib, kernel, {z,[]}]},
+ {incl_cond,exclude},
+ {mod_cond,app},
+ {app,kernel,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,mnesia,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,x,[{incl_cond,include}]},
+ {app,y,[{incl_cond,include}]},
+ {app,z,[{incl_cond,include}]},
+ {app,tools,[{mod_cond,app},{incl_cond,include}]}
+ ]},
+
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
+
+ %% Generate release files
+ application:load(sasl),
+ application:load(mnesia),
+ application:load(tools),
+ {ok,KernelVsn} = application:get_key(kernel,vsn),
+ {ok,StdlibVsn} = application:get_key(stdlib,vsn),
+ {ok,SaslVsn} = application:get_key(sasl,vsn),
+ {ok,MnesiaVsn} = application:get_key(mnesia,vsn),
+ {ok,ToolsVsn} = application:get_key(tools,vsn),
+ ErtsVsn = erlang:system_info(version),
+
+ Rel1 = {release, {RelName1,RelVsn}, {erts,ErtsVsn},
+ [{kernel,KernelVsn},
+ {stdlib,StdlibVsn},
+ {mnesia,MnesiaVsn},
+ {sasl,SaslVsn}]},
+ FullName1 = filename:join(?WORK_DIR,RelName1),
+ ?m(ok, file:write_file(FullName1 ++ ".rel", io_lib:format("~p.\n", [Rel1]))),
+ Rel2 = {release, {RelName2,RelVsn}, {erts,ErtsVsn},
+ [{kernel,KernelVsn},
+ {stdlib,StdlibVsn},
+ {sasl,SaslVsn},
+ {mnesia,MnesiaVsn}]},
+ FullName2 = filename:join(?WORK_DIR,RelName2),
+ ?m(ok, file:write_file(FullName2 ++ ".rel", io_lib:format("~p.\n", [Rel2]))),
+ Rel3 = {release, {RelName3,RelVsn}, {erts,ErtsVsn},
+ [{kernel,KernelVsn},
+ {stdlib,StdlibVsn},
+ {z,"1.0",[tools]},
+ {tools,ToolsVsn}]},
+ FullName3 = filename:join(?WORK_DIR,RelName3),
+ ?m(ok, file:write_file(FullName3 ++ ".rel", io_lib:format("~p.\n", [Rel3]))),
+ Rel4 = {release, {RelName4,RelVsn}, {erts,ErtsVsn},
+ [{kernel,KernelVsn},
+ {stdlib,StdlibVsn},
+ {z,"1.0"},
+ {tools,ToolsVsn}]},
+ FullName4 = filename:join(?WORK_DIR,RelName4),
+ ?m(ok, file:write_file(FullName4 ++ ".rel", io_lib:format("~p.\n", [Rel4]))),
+ Rel5 = {release, {RelName5,RelVsn}, {erts,ErtsVsn},
+ [{kernel,KernelVsn},
+ {stdlib,StdlibVsn},
+ {sasl,SaslVsn,[tools]},
+ {tools,ToolsVsn}]},
+ FullName5 = filename:join(?WORK_DIR,RelName5),
+ ?m(ok, file:write_file(FullName5 ++ ".rel", io_lib:format("~p.\n", [Rel5]))),
+ Rel6 = {release, {RelName6,RelVsn}, {erts,ErtsVsn},
+ [{kernel,KernelVsn},
+ {stdlib,StdlibVsn},
+ {z,"1.0"}]},
+ FullName6 = filename:join(?WORK_DIR,RelName6),
+ ?m(ok, file:write_file(FullName6 ++ ".rel", io_lib:format("~p.\n", [Rel6]))),
+ Rel7 = {release, {RelName7,RelVsn}, {erts,ErtsVsn},
+ [{kernel,KernelVsn},
+ {stdlib,StdlibVsn},
+ {mnesia,MnesiaVsn},
+ {y,"1.0"},
+ {sasl,SaslVsn},
+ {x,"1.0"}]},
+ FullName7 = filename:join(?WORK_DIR,RelName7),
+ ?m(ok, file:write_file(FullName7 ++ ".rel", io_lib:format("~p.\n", [Rel7]))),
+ Rel8 = {release, {RelName8,RelVsn}, {erts,ErtsVsn},
+ [{kernel,KernelVsn},
+ {stdlib,StdlibVsn},
+ {z,"1.0",[tools]}]},
+ FullName8 = filename:join(?WORK_DIR,RelName8),
+ ?m(ok, file:write_file(FullName8 ++ ".rel", io_lib:format("~p.\n", [Rel8]))),
+ Rel9 = {release, {RelName9,RelVsn}, {erts,ErtsVsn},
+ [{kernel,KernelVsn},
+ {stdlib,StdlibVsn},
+ {z,"1.0",[]}]},
+ FullName9 = filename:join(?WORK_DIR,RelName9),
+ ?m(ok, file:write_file(FullName9 ++ ".rel", io_lib:format("~p.\n", [Rel9]))),
+
+ %% Generate script files with systools and reltool and compare
+ ZPath = filename:join([LibDir,"*",ebin]),
+
+ %% BUG: reltool reverses the list of applications after kernel and stdlib
+ %% => mnesia and sasl are reverted
+ ?msym({ok,_,_}, systools_make_script(FullName1,ZPath)),
+ {ok, [SystoolsScript1]} = ?msym({ok,[_]}, file:consult(FullName1++".script")),
+ {ok, Script1} = ?msym({ok, _}, reltool:get_script(Pid, RelName1)),
+ ?m(equal, diff_script(SystoolsScript1, Script1)),
+
+ %% BUG: reltool reverses the list of applications after kernel and stdlib
+ %% => mnesia and sasl are reverted
+ ?msym({ok,_,_}, systools_make_script(FullName2,ZPath)),
+ {ok, [SystoolsScript2]} = ?msym({ok,[_]}, file:consult(FullName2++".script")),
+ {ok, Script2} = ?msym({ok, _}, reltool:get_script(Pid, RelName2)),
+ ?m(equal, diff_script(SystoolsScript2, Script2)),
+
+ %% BUG1: reltool loads all modules in the ebin dir of an application,
+ %% even if mod_cond is set to 'app'.
+ %% BUG2: reltool shall not start included applications!!
+ ?msym({ok,_,_}, systools_make_script(FullName3,ZPath)),
+ {ok, [SystoolsScript3]} = ?msym({ok,[_]}, file:consult(FullName3++".script")),
+ {ok, Script3} = ?msym({ok, _}, reltool:get_script(Pid, RelName3)),
+ ?m(equal, diff_script(SystoolsScript3, Script3)),
+
+ %% BUG1: reltool loads all modules in the ebin dir of an application,
+ %% even if mod_cond is set to 'app'.
+ %% BUG2: reltool does not honor included applications in .app files
+ %% unless they are also mentioned in the 'rel' specification in
+ %% the reltool config.
+ %% => faulty order of load instructions for tools and z. tools
+ %% should be first since it is included in z.
+ ?msym({ok,_,_}, systools_make_script(FullName4,ZPath)),
+ {ok, [SystoolsScript4]} = ?msym({ok,[_]}, file:consult(FullName4++".script")),
+ {ok, Script4} = ?msym({ok, _}, reltool:get_script(Pid, RelName4)),
+ ?m(equal, diff_script(SystoolsScript4, Script4)),
+
+ ?msym({error,_,[{error_reading,{sasl,{override_include,_}}}]},
+ systools_make_script(FullName5,ZPath)),
+ ?m({error,"sasl: These applications are used by release "
+ "Include-only-rel but are missing as included_applications "
+ "in the app file: [tools]"},
+ reltool:get_script(Pid, RelName5)),
+
+ %% BUG: reltool does not honor included applications in .app files
+ %% unless they are also mentioned in the 'rel' specification in
+ %% the reltool config.
+ %% => does not detect that tools (included in z) is missing
+ ?msym({error,_,{undefined_applications,_}},
+ systools_make_script(FullName6,ZPath)),
+ ?m({error, "Undefined applications: [tools]"},
+ reltool:get_script(Pid, RelName6)),
+
+ ?msym({error,_,{circular_dependencies,_}},
+ systools_make_script(FullName7,ZPath)),
+ ?m({error,"Circular dependencies: [x,y]"},
+ reltool:get_script(Pid, RelName7)),
+
+ ?msym({error,_,{undefined_applications,_}},
+ systools_make_script(FullName8,ZPath)),
+ ?m({error, "Undefined applications: [tools]"},
+ reltool:get_script(Pid, RelName8)),
+
+ ?msym({ok,_,_}, systools_make_script(FullName9,ZPath)),
+ {ok, [SystoolsScript9]} = ?msym({ok,[_]}, file:consult(FullName9++".script")),
+ {ok, Script9} = ?msym({ok, _}, reltool:get_script(Pid, RelName9)),
+ ?m(equal, diff_script(SystoolsScript9, Script9)),
+
+ %% Stop server
+ ?m(ok, reltool:stop(Pid)),
+ ok.
+
+
+systools_make_script(Name,Path) ->
+ systools:make_script(Name,[{path,[Path]},{outdir,?WORK_DIR},silent]).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate target system
diff --git a/lib/reltool/test/reltool_server_SUITE_data/sort_apps/x-1.0/ebin/x.app b/lib/reltool/test/reltool_server_SUITE_data/sort_apps/x-1.0/ebin/x.app
new file mode 100644
index 0000000000..5fa2a92969
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/sort_apps/x-1.0/ebin/x.app
@@ -0,0 +1,7 @@
+% -*-erlang-*-
+{application, x,
+ [{description, "Application in reltool sort app test - circular dependency"},
+ {vsn, "1.0"},
+ {modules,[]},
+ {registered, []},
+ {applications, [kernel, stdlib, y]}]}.
diff --git a/lib/reltool/test/reltool_server_SUITE_data/sort_apps/y-1.0/ebin/y.app b/lib/reltool/test/reltool_server_SUITE_data/sort_apps/y-1.0/ebin/y.app
new file mode 100644
index 0000000000..c4bc62f55f
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/sort_apps/y-1.0/ebin/y.app
@@ -0,0 +1,7 @@
+% -*-erlang-*-
+{application, y,
+ [{description, "Application in reltool sort app test - circular dependency"},
+ {vsn, "1.0"},
+ {modules,[]},
+ {registered, []},
+ {applications, [kernel, stdlib, x]}]}.
diff --git a/lib/reltool/test/reltool_server_SUITE_data/sort_apps/z-1.0/ebin/z.app b/lib/reltool/test/reltool_server_SUITE_data/sort_apps/z-1.0/ebin/z.app
new file mode 100644
index 0000000000..1622975bf6
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/sort_apps/z-1.0/ebin/z.app
@@ -0,0 +1,8 @@
+% -*-erlang-*-
+{application, z,
+ [{description, "Application in reltool sort app test - included applications"},
+ {vsn, "1.0"},
+ {modules,[]},
+ {registered, []},
+ {applications, [kernel, stdlib]},
+ {included_applications, [tools]}]}.
--
cgit v1.2.3
From e3bb31270b1cc43a72a2c3942f496e5c8f93155b Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Mon, 13 Feb 2012 16:57:51 +0100
Subject: [reltool] Add test cases for handling of escripts
OTP-9794
OTP-9968
The following test cases are added:
* create_standalone_beam
* create_standalone_app
* create_multiple_standalone
* load_config_escript_path
* load_config_same_escript_source
* load_config_same_escript_beam
* load_config_add_escript
Most of them are temporarily skipped since they re-produce known
problems that will be corrected in a later commit.
---
lib/reltool/test/reltool_server_SUITE.erl | 365 ++++++++++++++++++++-
.../test/reltool_server_SUITE_data/Makefile.src | 8 +-
.../escript/someapp-1.0/ebin/someapp.app | 6 +
.../escript/someapp-1.0/src/mymod.erl | 26 ++
4 files changed, 394 insertions(+), 11 deletions(-)
create mode 100644 lib/reltool/test/reltool_server_SUITE_data/escript/someapp-1.0/ebin/someapp.app
create mode 100644 lib/reltool/test/reltool_server_SUITE_data/escript/someapp-1.0/src/mymod.erl
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index 0aca242d4e..56c9cb5ed1 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -62,6 +62,9 @@ all() ->
create_target,
create_embedded,
create_standalone,
+ create_standalone_beam,
+ create_standalone_app,
+ create_multiple_standalone,
create_old_target,
eval_target_spec,
otp_9135,
@@ -74,6 +77,10 @@ all() ->
set_apps_and_undo,
set_sys_and_undo,
load_config_and_undo,
+ load_config_escript_path,
+ load_config_same_escript_source,
+ load_config_same_escript_beam,
+ load_config_add_escript,
reset_config_and_undo,
gen_rel_files,
save_config,
@@ -138,27 +145,34 @@ set_config(_Config) ->
%% Check that get_config returns the expected derivates and defaults
%% as specified
get_config(_Config) ->
+
+ KVsn = latest(kernel),
+ StdVsn = latest(stdlib),
+ SaslVsn = latest(sasl),
+
Sys = {sys,[{incl_cond, exclude},
{app,kernel,[{incl_cond,include}]},
- {app,sasl,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include},{vsn,SaslVsn}]},
{app,stdlib,[{incl_cond,include}]}]},
{ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
?m({ok, Sys}, reltool:get_config(Pid)),
?m({ok, Sys}, reltool:get_config(Pid,false,false)),
+ %% Include derived info
?msym({ok,{sys,[{incl_cond, exclude},
{erts,[]},
{app,kernel,[{incl_cond,include},{mod,_,[]}|_]},
- {app,sasl,[{incl_cond,include},{mod,_,[]}|_]},
+ {app,sasl,[{incl_cond,include},{vsn,SaslVsn},{mod,_,[]}|_]},
{app,stdlib,[{incl_cond,include},{mod,_,[]}|_]}]}},
reltool:get_config(Pid,false,true)),
+ %% Include defaults
?msym({ok,{sys,[{root_dir,_},
{lib_dirs,_},
{mod_cond,all},
{incl_cond,exclude},
{app,kernel,[{incl_cond,include},{vsn,undefined}]},
- {app,sasl,[{incl_cond,include},{vsn,undefined}]},
+ {app,sasl,[{incl_cond,include},{vsn,SaslVsn}]},
{app,stdlib,[{incl_cond,include},{vsn,undefined}]},
{boot_rel,"start_clean"},
{rel,"start_clean","1.0",[]},
@@ -178,16 +192,14 @@ get_config(_Config) ->
{debug_info,keep}]}},
reltool:get_config(Pid,true,false)),
- KVsn = latest(kernel),
- StdVsn = latest(stdlib),
-
+ %% Include both defaults and derived info
?msym({ok,{sys,[{root_dir,_},
{lib_dirs,_},
{mod_cond,all},
{incl_cond,exclude},
{erts,[]},
{app,kernel,[{incl_cond,include},{vsn,KVsn},{mod,_,[]}|_]},
- {app,sasl,[{incl_cond,include},{vsn,_},{mod,_,[]}|_]},
+ {app,sasl,[{incl_cond,include},{vsn,SaslVsn},{mod,_,[]}|_]},
{app,stdlib,[{incl_cond,include},{vsn,StdVsn},{mod,_,[]}|_]},
{boot_rel,"start_clean"},
{rel,"start_clean","1.0",[]},
@@ -720,21 +732,187 @@ create_standalone(_Config) ->
?m(ok, file:make_dir(TargetDir)),
ok = ?m(ok, reltool:create_target([{config, Config}], TargetDir)),
+ %% Start the target system and fetch root dir
BinDir = filename:join([TargetDir, "bin"]),
Erl = filename:join([BinDir, "erl"]),
{ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
RootDir = ?ignore(rpc:call(Node, code, root_dir, [])),
?msym(ok, stop_node(Node)),
+ %% Execute escript
Expected = iolist_to_binary(["Root dir: ", RootDir, "\n"
"Script args: [\"-arg1\",\"arg2\",\"arg3\"]\n",
"Smp: false\n",
"ExitCode:0"]),
io:format("Expected: ~s\n", [Expected]),
- ?m(Expected, run(BinDir, EscriptName ++ " -arg1 arg2 arg3")),
+ ?m(Expected, run(BinDir, EscriptName, "-arg1 arg2 arg3")),
ok.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate standalone system with inlined beam file
+
+create_standalone_beam(Config) ->
+ %% Read beam file
+ DataDir = ?config(data_dir,Config),
+ BeamFile = filename:join([DataDir,escript,"someapp-1.0",ebin,"mymod.beam"]),
+ {ok,BeamBin} = file:read_file(BeamFile),
+
+ %% Create the escript
+ EscriptName = "mymod.escript",
+ Escript = filename:join(?WORK_DIR,EscriptName),
+ ok = escript:create(Escript,[shebang,{beam,BeamBin}]),
+ ok = file:change_mode(Escript,8#00744),
+
+ %% Configure the server
+ Sys =
+ {sys,
+ [
+ {lib_dirs, []},
+ {escript, Escript, [{incl_cond, include}]},
+ {profile, standalone}
+ ]},
+
+ %% Generate target file
+ TargetDir = filename:join([?WORK_DIR, "target_standalone_beam"]),
+ ?m(ok, reltool_utils:recursive_delete(TargetDir)),
+ ?m(ok, file:make_dir(TargetDir)),
+ ok = ?m(ok, reltool:create_target([{config, Sys}], TargetDir)),
+
+ %% Start the target system and fetch root dir
+ BinDir = filename:join([TargetDir, "bin"]),
+ Erl = filename:join([BinDir, "erl"]),
+ {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
+ RootDir = ?ignore(rpc:call(Node, code, root_dir, [])),
+ ?msym(ok, stop_node(Node)),
+
+ %% Execute escript
+ Expected = iolist_to_binary(["Root dir: ", RootDir, "\n"
+ "Script args: [\"-arg1\",\"arg2\",\"arg3\"]\n",
+ "ExitCode:0"]),
+ io:format("Expected: ~s\n", [Expected]),
+ ?m(Expected, run(BinDir, EscriptName, "-arg1 arg2 arg3")),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate standalone system with inlined archived application
+
+%% BUG: see OTP-9792, 25)
+%% Problem related to change of #app.name from "*escript* someapp" to
+%% just "someapp", since there is a someapp.app in the
+%% archive. "someapp" does not have an incl_cond=include statement,
+%% and it is not derived so the it is not included in the target
+%% system.
+create_standalone_app(_Config) -> {skip, "Known bug: escript with inlined archive is not handled correctly by reltool"};
+create_standalone_app(Config) ->
+ %% Create archive
+ DataDir = ?config(data_dir,Config),
+ EscriptDir = filename:join(DataDir,escript),
+ {ok,{_Archive,Bin}} = zip:create("someapp-1.0.ez",["someapp-1.0"],
+ [memory,
+ {cwd,EscriptDir},
+ {compress,all},
+ {uncompress,[".beam",".app"]}]),
+
+ %% Create the escript
+ EscriptName = "someapp.escript",
+ Escript = filename:join(?WORK_DIR,EscriptName),
+ ok = escript:create(Escript,[shebang,
+ {emu_args,"-escript main mymod"},
+ {archive,Bin}]),
+ ok = file:change_mode(Escript,8#00744),
+
+ %% Configure the server
+ Sys =
+ {sys,
+ [
+ {lib_dirs, []},
+ {escript, Escript, [{incl_cond, include}]},
+ {profile, standalone}
+ ]},
+
+ %% Generate target file
+ TargetDir = filename:join([?WORK_DIR, "target_standalone_app"]),
+ ?m(ok, reltool_utils:recursive_delete(TargetDir)),
+ ?m(ok, file:make_dir(TargetDir)),
+ ok = ?m(ok, reltool:create_target([{config, Sys}], TargetDir)),
+
+ %% Start the target system and fetch root dir
+ BinDir = filename:join([TargetDir, "bin"]),
+ Erl = filename:join([BinDir, "erl"]),
+ {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
+ RootDir = ?ignore(rpc:call(Node, code, root_dir, [])),
+ ?msym(ok, stop_node(Node)),
+
+ %% Execute escript
+ Expected = iolist_to_binary(["Root dir: ", RootDir, "\n"
+ "Script args: [\"-arg1\",\"arg2\",\"arg3\"]\n",
+ "ExitCode:0"]),
+ io:format("Expected: ~s\n", [Expected]),
+ ?m(Expected, run(BinDir, EscriptName, "-arg1 arg2 arg3")),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate standalone system with multiple escripts
+
+create_multiple_standalone(Config) ->
+ %% First escript
+ ExDir = code:lib_dir(reltool, examples),
+ EscriptName1 = "display_args",
+ Escript1 = filename:join([ExDir, EscriptName1]),
+
+ %% Second escript
+ DataDir = ?config(data_dir,Config),
+ BeamFile = filename:join([DataDir,escript,"someapp-1.0",ebin,"mymod.beam"]),
+ {ok,BeamBin} = file:read_file(BeamFile),
+ EscriptName2 = "mymod.escript",
+ Escript2 = filename:join(?WORK_DIR,EscriptName2),
+ ok = escript:create(Escript2,[shebang,{beam,BeamBin}]),
+ ok = file:change_mode(Escript2,8#00744),
+
+ %% Configure server
+ Sys =
+ {sys,
+ [
+ {lib_dirs, []},
+ {escript, Escript1, [{incl_cond, include}]},
+ {escript, Escript2, [{incl_cond, include}]},
+ {profile, standalone}
+ ]},
+
+ %% Generate target system
+ TargetDir = filename:join([?WORK_DIR, "target_multiple_standalone"]),
+ ?m(ok, reltool_utils:recursive_delete(TargetDir)),
+ ?m(ok, file:make_dir(TargetDir)),
+ ok = ?m(ok, reltool:create_target([{config,Sys}], TargetDir)),
+
+ %% Start the target system and fetch root dir
+ BinDir = filename:join([TargetDir, "bin"]),
+ Erl = filename:join([BinDir, "erl"]),
+ {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
+ RootDir = ?ignore(rpc:call(Node, code, root_dir, [])),
+ ?msym(ok, stop_node(Node)),
+
+ %% Execute escript1
+ Expected1 = iolist_to_binary(["Root dir: ", RootDir, "\n"
+ "Script args: [\"-arg1\",\"arg2\",\"arg3\"]\n",
+ "Smp: false\n",
+ "ExitCode:0"]),
+ io:format("Expected1: ~s\n", [Expected1]),
+ ?m(Expected1, run(BinDir, EscriptName1, "-arg1 arg2 arg3")),
+
+
+ %% Execute escript2
+ Expected2 = iolist_to_binary(["Root dir: ", RootDir, "\n"
+ "Script args: [\"-arg1\",\"arg2\",\"arg3\"]\n",
+ "ExitCode:0"]),
+ io:format("Expected2: ~s\n", [Expected2]),
+ ?m(Expected2, run(BinDir, EscriptName2, "-arg1 arg2 arg3")),
+
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate old type of target system
@@ -1182,6 +1360,171 @@ load_config_and_undo(Config) ->
ok.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Load config with escript
+
+load_config_escript_path(_Config) -> {skip,"Known bug: loading config with escript at reltool start creates different #app record than loading same config with load_config"};
+load_config_escript_path(Config) ->
+ %% Create escript
+ DataDir = ?config(data_dir,Config),
+ BeamFile = filename:join([DataDir,escript,"someapp-1.0",ebin,"mymod.beam"]),
+ {ok,BeamBin} = file:read_file(BeamFile),
+ EscriptName = "mymod.escript",
+ Escript = filename:join(?WORK_DIR,EscriptName),
+ ok = escript:create(Escript,[shebang,{beam,BeamBin}]),
+ ok = file:change_mode(Escript,8#00744),
+
+ %% Start reltool_server with one escript in configuration
+ EscriptSys =
+ {sys,
+ [
+ {lib_dirs, []},
+ {escript, Escript, [{incl_cond, include}]},
+ {profile, standalone}
+ ]},
+
+ {ok, Pid1} = ?msym({ok, _}, reltool:start_server([{config, EscriptSys}])),
+ {ok,[#app{name='*escript* mymod'}=A]} =
+ ?msym({ok,[_]}, reltool_server:get_apps(Pid1,whitelist)),
+ ?m(ok, reltool:stop(Pid1)),
+
+
+ %% Do same again, but now start reltool first with simple config,
+ %% then add escript by loading new configuration and check that
+ %% #app is the same
+ SimpleSys =
+ {sys,
+ [
+ {lib_dirs, []}
+ ]},
+
+ {ok, Pid2} = ?msym({ok, _}, reltool:start_server([{config, SimpleSys}])),
+ ?m({ok,[]}, reltool_server:get_apps(Pid2,whitelist)),
+ ?m({ok,[]}, reltool_server:load_config(Pid2,EscriptSys)),
+ ?m({ok,[A]}, reltool_server:get_apps(Pid2,whitelist)),
+
+ ?m(ok, reltool:stop(Pid2)),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Load config with same (source) escript twice and check that the
+%% application information is not changed.
+
+load_config_same_escript_source(_Config) -> {skip,"Known bug: loading config with same escript (source) twice causes reltool to add same module twice in #app.mods"};
+load_config_same_escript_source(_Config) ->
+ %% Create escript
+ ExDir = code:lib_dir(reltool, examples),
+ EscriptName = "display_args",
+ Escript = filename:join([ExDir, EscriptName]),
+
+ %% Start reltool_server with one escript in configuration
+ Sys =
+ {sys,
+ [
+ {lib_dirs, []},
+ {escript, Escript, [{incl_cond, include}]},
+ {profile, standalone}
+ ]},
+
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
+ {ok,[#app{name='*escript* display_args'}=A]} =
+ ?msym({ok,[_]}, reltool_server:get_apps(Pid,whitelist)),
+
+ %% Load the same config again, then check that app is not changed
+ ?m({ok,[]}, reltool_server:load_config(Pid,Sys)),
+ ?m({ok,[A]}, reltool_server:get_apps(Pid,whitelist)),
+
+ ?m(ok, reltool:stop(Pid)),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Load config with same (beam) escript twice and check that the
+%% application information is not changed.
+
+load_config_same_escript_beam(_Config) -> {skip,"Known bug: loading config with same escript (with inlined beam) twice causes reltool to fail and say module is included by two different applications"};
+load_config_same_escript_beam(Config) ->
+ %% Create escript
+ DataDir = ?config(data_dir,Config),
+ BeamFile = filename:join([DataDir,escript,"someapp-1.0",ebin,"mymod.beam"]),
+ {ok,BeamBin} = file:read_file(BeamFile),
+ EscriptName = "mymod.escript",
+ Escript = filename:join(?WORK_DIR,EscriptName),
+ ok = escript:create(Escript,[shebang,{beam,BeamBin}]),
+ ok = file:change_mode(Escript,8#00744),
+
+ %% Start reltool_server with one escript in configuration
+ Sys =
+ {sys,
+ [
+ {lib_dirs, []},
+ {escript, Escript, [{incl_cond, include}]},
+ {profile, standalone}
+ ]},
+
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
+ {ok,[#app{name='*escript* mymod'}=A]} =
+ ?msym({ok,[_]}, reltool_server:get_apps(Pid,whitelist)),
+
+ %% Load the same config again, then check that app is not changed
+ ?m({ok,[]}, reltool_server:load_config(Pid,Sys)),
+ ?m({ok,[A]}, reltool_server:get_apps(Pid,whitelist)),
+
+ ?m(ok, reltool:stop(Pid)),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Load config with escript
+
+%% BUG: see OTP-9792, 25)
+load_config_add_escript(_Config) -> {skip,"Known bug: Can not load_config which in addition to an existing escript also adds another escript for which the name sorts before the existing one"};
+load_config_add_escript(Config) ->
+ %% First escript
+ ExDir = code:lib_dir(reltool, examples),
+ EscriptName1 = "display_args",
+ Escript1 = filename:join([ExDir, EscriptName1]),
+
+ %% Second escript
+ DataDir = ?config(data_dir,Config),
+ BeamFile = filename:join([DataDir,escript,"someapp-1.0",ebin,"mymod.beam"]),
+ {ok,BeamBin} = file:read_file(BeamFile),
+ EscriptName2 = "mymod.escript",
+ Escript2 = filename:join(?WORK_DIR,EscriptName2),
+ ok = escript:create(Escript2,[shebang,{beam,BeamBin}]),
+ ok = file:change_mode(Escript2,8#00744),
+
+ %% Start reltool_server with one escript in configuration
+ Sys1 =
+ {sys,
+ [
+ {lib_dirs, []},
+ {escript, Escript2, [{incl_cond, include}]},
+ {profile, standalone}
+ ]},
+
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
+
+ %% Add second escript by loading new configuration
+ Sys2 =
+ {sys,
+ [
+ {lib_dirs, []},
+ {escript, Escript1, [{incl_cond, include}]},
+ {escript, Escript2, [{incl_cond, include}]},
+ {profile, standalone}
+ ]},
+
+ {ok,[]} = ?m({ok,[]}, reltool_server:load_config(Pid,Sys2)),
+ {ok,[#app{name='*escript* display_args'},
+ #app{name='*escript* mymod'}]} =
+ ?msym({ok,[_,_]}, reltool_server:get_apps(Pid,whitelist)),
+
+ ?m(ok, reltool:stop(Pid)),
+
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
reset_config_and_undo(Config) ->
Sys1 = {sys,[{lib_dirs,[filename:join(datadir(Config),"faulty_app_file")]},
@@ -1654,14 +1997,16 @@ wait_for_process(Node, Name, N) when is_integer(N), N > 0 ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Run escript
-run(Dir, Cmd0) ->
+run(Dir, Script, Args) ->
+ Cmd0 = filename:rootname(Script) ++ " " ++ Args,
Cmd = case os:type() of
{win32,_} -> filename:nativename(Dir) ++ "\\" ++ Cmd0;
_ -> Cmd0
end,
do_run(Dir, Cmd).
-run(Dir, Opts, Cmd0) ->
+run(Dir, Opts, Script, Args) ->
+ Cmd0 = filename:rootname(Script) ++ " " ++ Args,
Cmd = case os:type() of
{win32,_} -> Opts ++ " " ++ filename:nativename(Dir) ++ "\\" ++ Cmd0;
_ -> Opts ++ " " ++ Dir ++ "/" ++ Cmd0
diff --git a/lib/reltool/test/reltool_server_SUITE_data/Makefile.src b/lib/reltool/test/reltool_server_SUITE_data/Makefile.src
index 35a239bfe2..8ab077d64b 100644
--- a/lib/reltool/test/reltool_server_SUITE_data/Makefile.src
+++ b/lib/reltool/test/reltool_server_SUITE_data/Makefile.src
@@ -14,8 +14,11 @@ DEPENDENCIES= \
dependencies/y-1.0/ebin/y2.@EMULATOR@ \
dependencies/z-1.0/ebin/z1.@EMULATOR@
+ESCRIPT= \
+ escript/someapp-1.0/ebin/mymod.@EMULATOR@
-all: $(OTP9229) $(DEPENDENCIES)
+
+all: $(OTP9229) $(DEPENDENCIES) $(ESCRIPT)
otp_9229/x-1.0/ebin/x.@EMULATOR@: otp_9229/x-1.0/src/x.erl
erlc $(EFLAGS) -ootp_9229/x-1.0/ebin otp_9229/x-1.0/src/x.erl
@@ -38,3 +41,6 @@ dependencies/y-1.0/ebin/y2.@EMULATOR@: dependencies/y-1.0/src/y2.erl
erlc $(EFLAGS) -odependencies/y-1.0/ebin dependencies/y-1.0/src/y2.erl
dependencies/z-1.0/ebin/z1.@EMULATOR@: dependencies/z-1.0/src/z1.erl
erlc $(EFLAGS) -odependencies/z-1.0/ebin dependencies/z-1.0/src/z1.erl
+
+escript/someapp-1.0/ebin/mymod.@EMULATOR@: escript/someapp-1.0/src/mymod.erl
+ erlc $(EFLAGS) -oescript/someapp-1.0/ebin escript/someapp-1.0/src/mymod.erl
diff --git a/lib/reltool/test/reltool_server_SUITE_data/escript/someapp-1.0/ebin/someapp.app b/lib/reltool/test/reltool_server_SUITE_data/escript/someapp-1.0/ebin/someapp.app
new file mode 100644
index 0000000000..ea2209941e
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/escript/someapp-1.0/ebin/someapp.app
@@ -0,0 +1,6 @@
+%% -*- erlang -*-
+{application, someapp,
+ [{description, "Some app for reltool test including archives in escripts"},
+ {vsn, "1.0"},
+ {modules, [someapp]},
+ {applications, [kernel, stdlib]}]}.
diff --git a/lib/reltool/test/reltool_server_SUITE_data/escript/someapp-1.0/src/mymod.erl b/lib/reltool/test/reltool_server_SUITE_data/escript/someapp-1.0/src/mymod.erl
new file mode 100644
index 0000000000..b6c71c666d
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/escript/someapp-1.0/src/mymod.erl
@@ -0,0 +1,26 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+%% AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(mymod).
+
+-export([main/1]).
+
+%%%-----------------------------------------------------------------
+%%% escript main function
+main(Args) ->
+ io:format("Root dir: ~s\n", [code:root_dir()]),
+ io:format("Script args: ~p\n", [Args]).
--
cgit v1.2.3
From 6f5e3e16019a3a4f9e9033d185b9c487967ad5fa Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Wed, 15 Feb 2012 16:36:27 +0100
Subject: [reltool] Update state and tables consistently for all types of
config changes
OTP-9794
OTP-9968
The main idea behind the data structure in reltool_server is that the
state shall reflect what is explicitly configured, and the tables
shall contain this configuration plus everything that is derived. In
some cases, however, this was not the complete truth:
* the application table was never read
* the module table was never updated on undo
* the state contained a lot more than what was explicitly configured
This commit re-writes major parts of the reltool_server for the sake
of unifying the way the state and tables are updated:
* The list of applications in the state now only contains those
applications and modules for which there are explicit settings in
the configuration (given at startup or changed from the GUI)
* When changing any bit of the configuration, the tables are always
emptied and every part is derived again from the configuration found
in the state
* All configuration changes now cause a re-read of the file system,
meaning that if something has changed in the file system it will be
reflected in the result of the configuration change. This is the
case even if no file system related configuration is changed
(e.g. root dir or lib dirs)
(*POSSIBLE INCOMPATIBILITY*)
* Requests for applications and modules from the GUI now always read
the tables, not the state
* When loading a new configuration file via the GUI, the old
configuration is completly scratched, and only the new is valid
(*POSSIBLE INCOMPATIBILITY*)
* The handling of escripts which include archives of applications is
changed to always produce one #app record for the escript in
addition to one for each inlined application. All modules are listed
as parts of the inlined application where it belongs and not as part
of the escript's #app record. This is a temporary solution which
will be modified and improved.
The following bugs are corrected by this commit:
* Loading a config which contains an escript via the GUI menu did not
produce the same #app record as when loading the same configuration
at reltool start. Paths, version and label could differ.
* Loading config with same escript (source) twice caused reltool to
add same module twice in #app.mods
* Loading config with same escript (inlined beam) twice caused reltool
to fail saying module is included by two different applications
* Loading config which in addition to an existing escript also adds
another escript for which the name sorts before the existing one
would cause reltool to fail saying "Application name clash"
---
lib/reltool/src/reltool_server.erl | 1177 +++++++++++++++--------------
lib/reltool/test/reltool_server_SUITE.erl | 37 +-
2 files changed, 613 insertions(+), 601 deletions(-)
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index fcd1ad393e..b6ffb9b134 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -138,12 +138,13 @@ do_init(Options) ->
%% process_flag(trap_exit, (S#state.common)#common.trap_exit),
proc_lib:init_ack(ParentPid,
{ok, self(), C, Sys#sys{apps = undefined}}),
- {S2, Status2} = refresh(S, true, Status),
- {S3, Status3} =
- analyse(S2#state{old_sys = S2#state.sys}, Status2),
+ {S2, Apps, Status2} = refresh(S, true, Status),
+ Status3 = analyse(S2, Apps, Status2),
case Status3 of
{ok, _Warnings} -> % BUGBUG: handle warnings
- loop(S3#state{status = Status3, old_status = {ok, []}});
+ loop(S2#state{old_sys = S2#state.sys,
+ status = Status3,
+ old_status = {ok, []}});
{error, Reason} ->
exit(Reason)
end.
@@ -152,40 +153,7 @@ parse_options(Opts) ->
AppTab = ets:new(reltool_apps, [public, ordered_set, {keypos, #app.name}]),
ModTab = ets:new(reltool_mods, [public, ordered_set, {keypos, #mod.name}]),
ModUsesTab = ets:new(reltool_mod_uses, [public, bag, {keypos, 1}]),
- Sys = #sys{root_dir = reltool_utils:root_dir(),
- lib_dirs = reltool_utils:erl_libs(),
- escripts = [],
- incl_cond = ?DEFAULT_INCL_COND,
- mod_cond = ?DEFAULT_MOD_COND,
- apps = ?DEFAULT_APPS,
- boot_rel = ?DEFAULT_REL_NAME,
- rels = reltool_utils:default_rels(),
- emu_name = ?DEFAULT_EMU_NAME,
- profile = ?DEFAULT_PROFILE,
- incl_sys_filters = dec_re(incl_sys_filters,
- ?DEFAULT_INCL_SYS_FILTERS,
- []),
- excl_sys_filters = dec_re(excl_sys_filters,
- ?DEFAULT_EXCL_SYS_FILTERS,
- []),
- incl_app_filters = dec_re(incl_app_filters,
- ?DEFAULT_INCL_APP_FILTERS,
- []),
- excl_app_filters = dec_re(excl_app_filters,
- ?DEFAULT_EXCL_APP_FILTERS,
- []),
- relocatable = ?DEFAULT_RELOCATABLE,
- rel_app_type = ?DEFAULT_REL_APP_TYPE,
- embedded_app_type = ?DEFAULT_EMBEDDED_APP_TYPE,
- app_file = ?DEFAULT_APP_FILE,
- incl_archive_filters = dec_re(incl_archive_filters,
- ?DEFAULT_INCL_ARCHIVE_FILTERS,
- []),
- excl_archive_filters = dec_re(excl_archive_filters,
- ?DEFAULT_EXCL_ARCHIVE_FILTERS,
- []),
- archive_opts = ?DEFAULT_ARCHIVE_OPTS,
- debug_info = ?DEFAULT_DEBUG_INFO},
+ Sys = default_sys(),
C2 = #common{sys_debug = [],
wx_debug = 0,
trap_exit = true,
@@ -195,6 +163,42 @@ parse_options(Opts) ->
S = #state{options = Opts},
parse_options(Opts, S, C2, Sys, {ok, []}).
+default_sys() ->
+ #sys{root_dir = reltool_utils:root_dir(),
+ lib_dirs = reltool_utils:erl_libs(),
+ escripts = [],
+ incl_cond = ?DEFAULT_INCL_COND,
+ mod_cond = ?DEFAULT_MOD_COND,
+ apps = ?DEFAULT_APPS,
+ boot_rel = ?DEFAULT_REL_NAME,
+ rels = reltool_utils:default_rels(),
+ emu_name = ?DEFAULT_EMU_NAME,
+ profile = ?DEFAULT_PROFILE,
+ incl_sys_filters = dec_re(incl_sys_filters,
+ ?DEFAULT_INCL_SYS_FILTERS,
+ []),
+ excl_sys_filters = dec_re(excl_sys_filters,
+ ?DEFAULT_EXCL_SYS_FILTERS,
+ []),
+ incl_app_filters = dec_re(incl_app_filters,
+ ?DEFAULT_INCL_APP_FILTERS,
+ []),
+ excl_app_filters = dec_re(excl_app_filters,
+ ?DEFAULT_EXCL_APP_FILTERS,
+ []),
+ relocatable = ?DEFAULT_RELOCATABLE,
+ rel_app_type = ?DEFAULT_REL_APP_TYPE,
+ embedded_app_type = ?DEFAULT_EMBEDDED_APP_TYPE,
+ app_file = ?DEFAULT_APP_FILE,
+ incl_archive_filters = dec_re(incl_archive_filters,
+ ?DEFAULT_INCL_ARCHIVE_FILTERS,
+ []),
+ excl_archive_filters = dec_re(excl_archive_filters,
+ ?DEFAULT_EXCL_ARCHIVE_FILTERS,
+ []),
+ archive_opts = ?DEFAULT_ARCHIVE_OPTS,
+ debug_info = ?DEFAULT_DEBUG_INFO}.
+
dec_re(Key, Regexps, Old) ->
reltool_utils:decode_regexps(Key, Regexps, Old).
@@ -252,19 +256,20 @@ loop(#state{common = C, sys = Sys} = S) ->
?MODULE:loop(S);
{call, ReplyTo, Ref, reset_config} ->
{S2, Status} = parse_options(S#state.options),
- S3 = shrink_sys(S2),
- {S4, Status2} = refresh(S3, true, Status),
- {S5, Status3} = analyse(S4#state{old_sys = S#state.sys}, Status2),
- S6 =
+ {S4, Apps, Status2} = refresh(S2, true, Status),
+ Status3 = analyse(S4, Apps, Status2),
+ S5 =
case Status3 of
{ok, _Warnings} ->
- S5#state{status = Status3, old_status = S#state.status};
+ S4#state{old_sys = Sys,
+ status = Status3,
+ old_status = S#state.status};
{error, _} ->
%% Keep old state
S
end,
reltool_utils:reply(ReplyTo, Ref, Status3),
- ?MODULE:loop(S6);
+ ?MODULE:loop(S5);
{call, ReplyTo, Ref, undo_config} ->
OldSys = S#state.old_sys,
S2 = S#state{sys = OldSys,
@@ -273,29 +278,29 @@ loop(#state{common = C, sys = Sys} = S) ->
%%! If so, consider if it is correct to use Force or not -
%%! since warnings from refresh_app will not re-appear here
%%! in undo if Force==false.
- Force =
- (OldSys#sys.root_dir =/= Sys#sys.root_dir) orelse
- (OldSys#sys.lib_dirs =/= Sys#sys.lib_dirs) orelse
- (OldSys#sys.escripts =/= Sys#sys.escripts),
-
- {S3, Status} = refresh(S2, Force, S#state.old_status),
- {S4, Status2} = analyse(S3, Status),
- S5 =
+ Force = true,
+% (OldSys#sys.root_dir =/= Sys#sys.root_dir) orelse
+% (OldSys#sys.lib_dirs =/= Sys#sys.lib_dirs) orelse
+% (OldSys#sys.escripts =/= Sys#sys.escripts),
+
+ {S3, Apps, Status} = refresh(S2, Force, S#state.old_status),
+ Status2 = analyse(S3, Apps, Status),
+ S4 =
case Status2 of
{ok, _Warnings} -> % BUGBUG: handle warnings
- S4#state{status = Status2, old_status = S#state.status};
+ S3#state{status = Status2, old_status = S#state.status};
{error, _} ->
%% Keep old state
S
end,
reltool_utils:reply(ReplyTo, Ref, Status2),
- ?MODULE:loop(S5);
+ ?MODULE:loop(S4);
{call, ReplyTo, Ref, {get_rel, RelName}} ->
Sys = S#state.sys,
Reply =
case lists:keysearch(RelName, #rel.name, Sys#sys.rels) of
{value, Rel} ->
- reltool_target:gen_rel(Rel, Sys);
+ reltool_target:gen_rel(Rel, sys_all_apps(C,Sys));
false ->
{error, "No such release: " ++ RelName}
end,
@@ -308,7 +313,8 @@ loop(#state{common = C, sys = Sys} = S) ->
{value, Rel} ->
PathFlag = true,
Vars = [],
- reltool_target:gen_script(Rel, Sys, PathFlag, Vars);
+ reltool_target:gen_script(Rel, sys_all_apps(C,Sys),
+ PathFlag, Vars);
false ->
{error, "No such release: " ++ RelName}
end,
@@ -326,99 +332,110 @@ loop(#state{common = C, sys = Sys} = S) ->
?MODULE:loop(S);
{call, ReplyTo, Ref, {get_app, AppName}} when is_atom(AppName) ->
Reply =
- case lists:keysearch(AppName, #app.name, Sys#sys.apps) of
- {value, App} ->
+ case ets:lookup(C#common.app_tab,AppName) of
+ [App] ->
{ok, App};
- false ->
+ [] ->
{error, "No such application: " ++
atom_to_list(AppName)}
end,
reltool_utils:reply(ReplyTo, Ref, Reply),
?MODULE:loop(S);
{call, ReplyTo, Ref, {set_app, App}} ->
- {S2, Status} = do_set_app(S, App, {ok, []}),
- {S3, Status2} = analyse(S2#state{old_sys=S#state.sys}, Status),
- {S4, Reply} =
- case Status2 of
+ {S2, Status} = do_set_apps(S, [App], {ok, []}),
+ {S3, Reply} =
+ case Status of
{ok, Warnings} ->
- App2 = ?KEYSEARCH(App#app.name,
- #app.name,
- (S3#state.sys)#sys.apps),
- {S3#state{status=Status2, old_status=S#state.status},
+ [App2] = ets:lookup(C#common.app_tab,App#app.name),
+ {S2#state{old_sys=Sys,
+ status=Status,
+ old_status=S#state.status},
{ok, App2, Warnings}};
{error, _} ->
%% Keep old state
- {S, Status2}
+ {S, Status}
end,
reltool_utils:reply(ReplyTo, Ref, Reply),
- ?MODULE:loop(S4);
+ ?MODULE:loop(S3);
{call, ReplyTo, Ref, {get_apps, Kind}} ->
AppNames =
case Kind of
whitelist ->
- [A ||
- A <- Sys#sys.apps,
- A#app.is_pre_included =:= true];
- blacklist ->
- [A ||
- A <- Sys#sys.apps,
- A#app.is_pre_included =:= false];
- source ->
- [A ||
- A <- Sys#sys.apps,
- A#app.is_included =/= true,
- A#app.is_pre_included =/= false];
+ %% Pre-included
+ ets:select(C#common.app_tab,
+ [{#app{is_pre_included=true,_='_'},
+ [],
+ ['$_']}]);
+ blacklist ->
+ %% Pre-excluded
+ ets:select(C#common.app_tab,
+ [{#app{is_pre_included=false,_='_'},
+ [],
+ ['$_']}]);
+ source ->
+ %% Not included and not pre-excluded
+ ets:select(C#common.app_tab,
+ [{#app{is_included='$1',
+ is_pre_included='$2',
+ _='_'},
+ [{'=/=','$1',true},
+ {'=/=','$2',false}],
+ ['$_']}]);
derived ->
- [A ||
- A <- Sys#sys.apps,
- A#app.is_included =:= true,
- A#app.is_pre_included =/= true]
+ %% Included, but not pre-included
+ ets:select(C#common.app_tab,
+ [{#app{is_included='$1',
+ is_pre_included='$2',
+ _='_'},
+ [{'=:=','$1',true},
+ {'=/=','$2',true}],
+ ['$_']}])
end,
reltool_utils:reply(ReplyTo, Ref, {ok, AppNames}),
?MODULE:loop(S);
{call, ReplyTo, Ref, {set_apps, Apps}} ->
- {S2, Status} =
- lists:foldl(fun(A, {X, Y}) -> do_set_app(X, A, Y) end,
- {S, {ok, []}},
- Apps),
- {S3, Status2} = analyse(S2#state{old_sys = S#state.sys}, Status),
- S4 =
- case Status2 of
+ {S2, Status} = do_set_apps(S, Apps, {ok, []}),
+ S3 =
+ case Status of
{ok, _Warnings} ->
- S3#state{status=Status2, old_status=S#state.status};
+ S2#state{old_sys = Sys,
+ status=Status,
+ old_status=S#state.status};
{error, _} ->
%% Keep old state
S
end,
- reltool_utils:reply(ReplyTo, Ref, Status2),
- ?MODULE:loop(S4);
+ reltool_utils:reply(ReplyTo, Ref, Status),
+ ?MODULE:loop(S3);
{call, ReplyTo, Ref, get_sys} ->
reltool_utils:reply(ReplyTo, Ref, {ok, Sys#sys{apps = undefined}}),
?MODULE:loop(S);
{call, ReplyTo, Ref, {set_sys, Sys2}} ->
S2 = S#state{sys = Sys2#sys{apps = Sys#sys.apps}},
- Force =
- (Sys2#sys.root_dir =/= Sys#sys.root_dir) orelse
- (Sys2#sys.lib_dirs =/= Sys#sys.lib_dirs) orelse
- (Sys2#sys.escripts =/= Sys#sys.escripts),
- {S3, Status} = refresh(S2, Force, {ok, []}),
- {S4, Status2} = analyse(S3#state{old_sys = S#state.sys}, Status),
- S5 =
+ Force = true,
+% (Sys2#sys.root_dir =/= Sys#sys.root_dir) orelse
+% (Sys2#sys.lib_dirs =/= Sys#sys.lib_dirs) orelse
+% (Sys2#sys.escripts =/= Sys#sys.escripts),
+ {S3, Apps, Status} = refresh(S2, Force, {ok, []}),
+ Status2 = analyse(S3, Apps, Status),
+ S4 =
case Status2 of
{ok, _Warnings} -> % BUGBUG: handle warnings
- S4#state{status = Status2, old_status = S#state.status};
+ S3#state{old_sys = Sys,
+ status = Status2,
+ old_status = S#state.status};
{error, _} ->
%% Keep old state
S
end,
reltool_utils:reply(ReplyTo, Ref, Status2),
- ?MODULE:loop(S5);
+ ?MODULE:loop(S4);
{call, ReplyTo, Ref, get_status} ->
reltool_utils:reply(ReplyTo, Ref, S#state.status),
?MODULE:loop(S);
{call, ReplyTo, Ref, {gen_rel_files, Dir}} ->
Status =
- case reltool_target:gen_rel_files(S#state.sys, Dir) of
+ case reltool_target:gen_rel_files(sys_all_apps(C,Sys), Dir) of
ok ->
{ok, []};
{error, Reason} ->
@@ -427,11 +444,11 @@ loop(#state{common = C, sys = Sys} = S) ->
reltool_utils:reply(ReplyTo, Ref, Status),
?MODULE:loop(S);
{call, ReplyTo, Ref, {gen_target, Dir}} ->
- Reply = reltool_target:gen_target(S#state.sys, Dir),
+ Reply = reltool_target:gen_target(sys_all_apps(C,Sys), Dir),
reltool_utils:reply(ReplyTo, Ref, Reply),
?MODULE:loop(S);
{call, ReplyTo, Ref, gen_spec} ->
- Reply = reltool_target:gen_spec(S#state.sys),
+ Reply = reltool_target:gen_spec(sys_all_apps(C,Sys)),
reltool_utils:reply(ReplyTo, Ref, Reply),
?MODULE:loop(S);
{'EXIT', Pid, Reason} when Pid =:= S#state.parent_pid ->
@@ -448,67 +465,141 @@ loop(#state{common = C, sys = Sys} = S) ->
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+do_set_apps(#state{sys = Sys} = S, ChangedApps, Status) ->
+
+ %% Create new list of configured applications
+ Sys2 = Sys#sys{apps = app_update_config(ChangedApps, Sys#sys.apps)},
+
+ %% Refresh and analyse
+ {S2, Apps, Status2} = refresh(S#state{sys = Sys2}, true, Status),
+ Status3 = analyse(S2, Apps, Status2),
+
+ {S2, Status3}.
+
+%% Re-create the #sys.apps list by
+%% 1) taking configurable fields from the changed #app records and
+%% create new default records
+%% 2) removing #app records if no configurable fields are set
+%% 3) keeping #app records that are not changed
+app_update_config([Config|Configs],SysApps) ->
+ NewSysApps =
+ case app_set_config_only(Config) of
+ {delete,Name} ->
+ lists:keydelete(Name,#app.name,SysApps);
+ New ->
+ lists:ukeymerge(#app.name,[New],SysApps)
+ end,
+ app_update_config(Configs,NewSysApps);
+app_update_config([],SysApps) ->
+ SysApps.
+
+app_set_config_only(#app{mods=ConfigMods} = Config) ->
+ app_set_config_only(mod_set_config_only(ConfigMods),Config).
+
+app_set_config_only([],#app{name = Name,
+ incl_cond = undefined,
+ mod_cond = undefined,
+ use_selected_vsn = undefined,
+ debug_info = undefined,
+ app_file = undefined,
+ app_type = undefined,
+ incl_app_filters = undefined,
+ excl_app_filters = undefined,
+ incl_archive_filters = undefined,
+ excl_archive_filters = undefined,
+ archive_opts = undefined}) ->
+ {delete,Name};
+app_set_config_only(Mods,#app{name = Name,
+ incl_cond = InclCond,
+ mod_cond = ModCond,
+ use_selected_vsn = UseSelectedVsn,
+ active_dir = ActiveDir,
+ debug_info = DebugInfo,
+ app_file = AppFile,
+ app_type = AppType,
+ incl_app_filters = InclAppFilters,
+ excl_app_filters = ExclAppFilters,
+ incl_archive_filters = InclArchiveFilters,
+ excl_archive_filters = ExclArchiveFilters,
+ archive_opts = ArchiveOpts,
+ vsn = Vsn}) ->
+ (default_app(Name))#app{incl_cond = InclCond,
+ mod_cond = ModCond,
+ use_selected_vsn = UseSelectedVsn,
+ active_dir = ActiveDir,
+ debug_info = DebugInfo,
+ app_file = AppFile,
+ app_type = AppType,
+ incl_app_filters = InclAppFilters,
+ excl_app_filters = ExclAppFilters,
+ incl_archive_filters = InclArchiveFilters,
+ excl_archive_filters = ExclArchiveFilters,
+ archive_opts = ArchiveOpts,
+ vsn = Vsn,
+ mods = Mods}.
+
+mod_set_config_only(ConfigMods) ->
+ [#mod{name = Name,
+ incl_cond = InclCond,
+ debug_info = DebugInfo} ||
+ #mod{name = Name,
+ incl_cond = InclCond,
+ debug_info = DebugInfo} <- ConfigMods,
+ (InclCond =/= undefined) orelse (DebugInfo =/= undefined)].
-do_set_app(#state{sys = Sys} = S, App, Status) ->
- AppName = App#app.name,
- {App2, Status2} = refresh_app(App, false, Status),
- Apps = Sys#sys.apps,
- Apps2 = lists:keystore(AppName, #app.name, Apps, App2),
- Escripts = [A#app.active_dir || A <- Apps2, A#app.is_escript],
- Sys2 = Sys#sys{apps = Apps2, escripts = Escripts},
- {S#state{sys = Sys2}, Status2}.
-
-analyse(#state{common = C,
- sys = #sys{apps = Apps0, rels = Rels} = Sys} = S,
- Status) ->
- Apps = lists:keydelete(?MISSING_APP_NAME, #app.name, Apps0),
+
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+analyse(#state{common=C, sys=Sys}, Apps, Status) ->
ets:delete_all_objects(C#common.app_tab),
ets:delete_all_objects(C#common.mod_tab),
ets:delete_all_objects(C#common.mod_used_by_tab),
- MissingApp = default_app(?MISSING_APP_NAME, "missing"),
- ets:insert(C#common.app_tab, MissingApp),
-
- {RevRelApps, Status2} = apps_in_rels(Rels, Apps, Status),
- RelApps2 = lists:reverse(RevRelApps),
- {Apps2, Status3} =
- lists:mapfoldl(fun(App, Acc) ->
- app_init_is_included(C, Sys, App, RelApps2, Acc)
- end,
- Status2,
- Apps),
- Apps3 =
- case app_propagate_is_included(C, Sys, Apps2, []) of
- [] ->
- Apps2;
- MissingMods ->
- %% io:format("Missing mods: ~p\n", [MissingMods]),
- MissingApp2 = MissingApp#app{label = ?MISSING_APP_TEXT,
- info = missing_app_info(""),
- mods = MissingMods,
- status = missing,
- uses_mods = []},
- [MissingApp2 | Apps2]
- end,
- app_propagate_is_used_by(C, Apps3),
- {Apps4,Status4} = app_recap_dependencies(C, Sys, Apps3, [], Status3),
- %% io:format("Missing app: ~p\n",
- %% [lists:keysearch(?MISSING_APP_NAME, #app.name, Apps4)]),
- Sys2 = Sys#sys{apps = Apps4},
-
- case verify_config(RelApps2, Sys2, Status4) of
- {ok, _Warnings} = Status5 ->
- {S#state{sys = Sys2}, Status5};
- {error, _} = Status5 ->
- {S, Status5}
- end.
+
+ %% Create a list of {RelName,AppName}, one element for each
+ %% AppName that needs to be included for the given release.
+ {RelApps, Status2} = apps_in_rels(Sys#sys.rels, Apps, Status),
+
+ %% Initiate is_pre_included and is_included for all applications
+ %% based on #sys.incl_cond, #app.incl_cond and if the application
+ %% is included in a release (rel spec - see apps_in_rels above).
+ %% Then initiate the same for each module, and check that there
+ %% are no duplicated module names (in different applications)
+ %% where we can not decide which one to use.
+ %% Write all #app to app_tab and all #mod to mod_tab.
+ Status3 = apps_init_is_included(C, Sys, Apps, RelApps, Status2),
+
+ %% For each module that has #mod.is_included==true, propagate
+ %% is_included to the modules it uses.
+ propagate_is_included(C, Sys),
+
+ %% Insert reverse dependencies - i.e. for each
+ %% #mod{name=Mod, uses_mods=[UsedMod]},
+ %% insert an entry {UsedMod,Mod} in mod_used_by_tab.
+ propagate_is_used_by(C),
+
+ %% Set the above reverse dependencies in #mod records
+ %% (used_by_mods) and accumulate in #app records.
+ %% Make sure #app.is_included is always true if some
+ %% #mod.is_included==true for at least one module in the app.
+ %% Set status=missing|ok for #app and #mod - indicates if module
+ %% (.beam file) is missing in file system.
+ Status4 = app_recap_dependencies(C, Status3),
+
+ %% Check that the boot_rel exists.
+ %% Check that all applications that are listed in a 'rel' spec are
+ %% also really included in the target release.
+ %% Check that all mandatory applications are included in all rels.
+ verify_config(C, Sys, RelApps, Status4).
apps_in_rels(Rels, Apps, Status) ->
- lists:foldl(fun(Rel, {RelApps, S}) ->
- {MoreRelApps, S2} = apps_in_rel(Rel, Apps, S),
- {MoreRelApps ++ RelApps, S2}
- end,
- {[], Status},
- Rels).
+ {AllRelApps, Status2} =
+ lists:foldl(fun(Rel, {RelApps, S}) ->
+ {MoreRelApps, S2} = apps_in_rel(Rel, Apps, S),
+ {MoreRelApps ++ RelApps, S2}
+ end,
+ {[], Status},
+ Rels),
+ {lists:reverse(AllRelApps), Status2}.
apps_in_rel(#rel{name = RelName, rel_apps = RelApps}, Apps, Status) ->
Mandatory = [{RelName, kernel}, {RelName, stdlib}],
@@ -540,6 +631,14 @@ more_apps_in_rels([{RelName, AppName} = RA | RelApps], Apps, Acc, Status) ->
more_apps_in_rels([], _Apps, Acc, Status) ->
{Acc, Status}.
+
+apps_init_is_included(C, Sys, Apps, RelApps, Status) ->
+ lists:foldl(fun(App, AccStatus) ->
+ app_init_is_included(C, Sys, App, RelApps, AccStatus)
+ end,
+ Status,
+ Apps).
+
app_init_is_included(C,
Sys,
#app{name = AppName, mods = Mods} = A,
@@ -587,8 +686,8 @@ app_init_is_included(C,
is_pre_included = IsPreIncl,
is_included = IsIncl,
rels = Rels},
- ets:insert(C#common.app_tab, A2),
- {A2, Status3}.
+ ets:insert(C#common.app_tab, A2), %%! Set mods to only mod names here????
+ Status3.
mod_init_is_included(C, M, ModCond, AppCond, Default, Status) ->
%% print(M#mod.name, hipe, "incl_cond -> ~p\n", [AppCond]),
@@ -676,55 +775,42 @@ false_to_undefined(Bool) ->
_ -> Bool
end.
-app_propagate_is_included(C, Sys, [#app{mods = Mods} = A | Apps], Acc) ->
- Acc2 = mod_propagate_is_included(C, Sys, A, Mods, Acc),
- app_propagate_is_included(C, Sys, Apps, Acc2);
-app_propagate_is_included(_C, _Sys, [], Acc) ->
- Acc.
-
-mod_propagate_is_included(C, Sys, A, [#mod{name = ModName} | Mods], Acc) ->
- Acc2 =
- case ets:lookup(C#common.mod_tab, ModName) of
- [M2] when M2#mod.app_name=:=A#app.name ->
- %% print(ModName, file, "Maybe Prop ~p -> ~p\n",
- %% [M2, M2#mod.is_included]),
- %% print(ModName, filename, "Maybe Prop ~p -> ~p\n",
- %% [M2, M2#mod.is_included]),
- case M2#mod.is_included of
- true ->
- %% Propagate include mark
- mod_mark_is_included(C,Sys,ModName,M2#mod.uses_mods,Acc);
- false ->
- Acc;
- undefined ->
- Acc
- end;
- [_] ->
- %% This module is currently used from a different application
- %% Ignore
- Acc
- end,
- mod_propagate_is_included(C, Sys, A, Mods, Acc2);
-mod_propagate_is_included(_C, _Sys, _A, [], Acc) ->
- Acc.
+%% Return the list for {ModName, UsesModNames} for all modules where
+%% #mod.is_included==true.
+get_all_mods_and_dependencies(C) ->
+ ets:select(C#common.mod_tab, [{#mod{name='$1',
+ uses_mods='$2',
+ is_included=true,
+ _='_'},
+ [],
+ [{{'$1','$2'}}]}]).
+
+propagate_is_included(C, Sys) ->
+ case lists:flatmap(
+ fun({ModName,UsesModNames}) ->
+ mod_mark_is_included(C,Sys,ModName,UsesModNames,[])
+ end,
+ get_all_mods_and_dependencies(C)) of
+ [] ->
+ ok;
+ MissingMods ->
+ MissingApp = default_app(?MISSING_APP_NAME, "missing"),
+ MissingApp2 = MissingApp#app{label = ?MISSING_APP_TEXT,
+ info = missing_app_info(""),
+ mods = MissingMods,
+ status = missing,
+ uses_mods = []},
+ ets:insert(C#common.app_tab, MissingApp2),
+ ok
+ end.
mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) ->
Acc3 =
case ets:lookup(C#common.mod_tab, ModName) of
[M] ->
- %% print(UsedByName, file, "Maybe Mark ~p -> ~p\n",
- %% [M, M#mod.is_included]),
- %% print(UsedByName, filename, "Maybe Mark ~p -> ~p\n",
- %% [M, M#mod.is_included]),
case M#mod.is_included of
- true ->
- %% Already marked
- Acc;
- false ->
- %% Already marked
- Acc;
undefined ->
- %% Mark and propagate
+ %% Not yet marked => mark and propagate
M2 =
case M#mod.incl_cond of
include ->
@@ -737,15 +823,9 @@ mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) ->
M#mod{is_included = true}
end,
ets:insert(C#common.mod_tab, M2),
- %% io:format("Propagate mod: ~p -> ~p (~p)\n",
- %% [UsedByName, ModName, M#mod.incl_cond]),
[A] = ets:lookup(C#common.app_tab, M2#mod.app_name),
Acc2 =
case A#app.is_included of
- true ->
- Acc;
- false ->
- Acc;
undefined ->
ModCond =
case A#app.mod_cond of
@@ -763,9 +843,6 @@ mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) ->
end
end,
Mods = lists:filter(Filter, A#app.mods),
- %% io:format("Propagate app: ~p ~p -> ~p\n",
- %% [UsedByName, A#app.name,
- %% [M3#mod.name || M3 <- Mods]]),
A2 = A#app{is_included = true},
ets:insert(C#common.app_tab, A2),
mod_mark_is_included(C,
@@ -773,53 +850,52 @@ mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) ->
ModName,
[M3#mod.name ||
M3 <- Mods],
- Acc)
+ Acc);
+ _ ->
+ %% Already marked true or false
+ Acc
end,
mod_mark_is_included(C,
Sys,
ModName,
M2#mod.uses_mods,
- Acc2)
+ Acc2);
+ _ ->
+ %% Already marked true or false
+ Acc
end;
[] ->
M = missing_mod(ModName, ?MISSING_APP_NAME),
M2 = M#mod{is_included = true},
ets:insert(C#common.mod_tab, M2),
- ets:insert(C#common.mod_used_by_tab, {UsedByName, ModName}),
[M2 | Acc]
end,
mod_mark_is_included(C, Sys, UsedByName, ModNames, Acc3);
mod_mark_is_included(_C, _Sys, _UsedByName, [], Acc) ->
Acc.
-app_propagate_is_used_by(C, [#app{mods = Mods, name = Name} | Apps]) ->
- case Name =:= ?MISSING_APP_NAME of
- true -> ok;
- false -> ok
- end,
- mod_propagate_is_used_by(C, Mods),
- app_propagate_is_used_by(C, Apps);
-app_propagate_is_used_by(_C, []) ->
- ok.
-
-mod_propagate_is_used_by(C, [#mod{name = ModName} | Mods]) ->
- [M] = ets:lookup(C#common.mod_tab, ModName),
- case M#mod.is_included of
- true ->
- [ets:insert(C#common.mod_used_by_tab, {UsedModName, ModName}) ||
- UsedModName <- M#mod.uses_mods];
- false ->
- ignore;
- undefined ->
- ignore
- end,
- mod_propagate_is_used_by(C, Mods);
-mod_propagate_is_used_by(_C, []) ->
- ok.
-
-app_recap_dependencies(C, Sys, [#app{mods = Mods, is_included = IsIncl} = A | Apps], Acc, Status) ->
+propagate_is_used_by(C) ->
+ lists:foreach(
+ fun({Mod,UsesMods}) ->
+ lists:foreach(
+ fun(UsedMod) ->
+ ets:insert(C#common.mod_used_by_tab,{UsedMod,Mod})
+ end,
+ UsesMods)
+ end,
+ get_all_mods_and_dependencies(C)).
+
+
+app_recap_dependencies(C, Status0) ->
+ ets:foldl(fun(App,Status) ->
+ app_recap_dependencies(C,App,Status)
+ end,
+ Status0,
+ C#common.app_tab).
+
+app_recap_dependencies(C, #app{mods = Mods, is_included = IsIncl} = A, Status) ->
{Mods2, IsIncl2, Status2} =
- mod_recap_dependencies(C, Sys, A, Mods, [], IsIncl, Status),
+ mod_recap_dependencies(C, A, Mods, [], IsIncl, Status),
AppStatus =
case lists:keymember(missing, #mod.status, Mods2) of
true -> missing;
@@ -844,11 +920,9 @@ app_recap_dependencies(C, Sys, [#app{mods = Mods, is_included = IsIncl} = A | Ap
used_by_apps = UsedByApps2,
is_included = IsIncl2},
ets:insert(C#common.app_tab,A2),
- app_recap_dependencies(C, Sys, Apps, [A2 | Acc], Status2);
-app_recap_dependencies(_C, _Sys, [], Acc, Status) ->
- {lists:reverse(Acc), Status}.
+ Status2.
-mod_recap_dependencies(C, Sys, A, [#mod{name = ModName}=M1 | Mods], Acc, IsIncl, Status) ->
+mod_recap_dependencies(C, A, [#mod{name = ModName}=M1 | Mods], Acc, IsIncl, Status) ->
case ets:lookup(C#common.mod_tab, ModName) of
[M2] when M2#mod.app_name=:=A#app.name ->
ModStatus = do_get_status(M2),
@@ -864,12 +938,12 @@ mod_recap_dependencies(C, Sys, A, [#mod{name = ModName}=M1 | Mods], Acc, IsIncl,
{IsIncl, M2#mod{status = ModStatus, used_by_mods = []}}
end,
ets:insert(C#common.mod_tab, M3),
- mod_recap_dependencies(C, Sys, A, Mods, [M3 | Acc], IsIncl2, Status);
- [_] when A#app.is_included==false; M1#mod.incl_cond==exclude ->
+ mod_recap_dependencies(C, A, Mods, [M3 | Acc], IsIncl2, Status);
+ [_] when A#app.is_included==false; M1#mod.incl_cond==exclude -> %!!! incl_cond could be read from #sys.app.mods
%% App is explicitely excluded so it is ok that the module
%% record does not exist for this module in this
%% application.
- mod_recap_dependencies(C, Sys, A, Mods, [M1 | Acc], IsIncl, Status);
+ mod_recap_dependencies(C, A, Mods, [M1 | Acc], IsIncl, Status);
[M2] ->
%% A module is potensially included by multiple
%% applications. This is not allowed!
@@ -879,9 +953,9 @@ mod_recap_dependencies(C, Sys, A, [#mod{name = ModName}=M1 | Mods], Acc, IsIncl,
" potentially included by two different applications: ",
A#app.name, " and ", M2#mod.app_name, "."]),
Status2 = reltool_utils:return_first_error(Status,Error),
- mod_recap_dependencies(C, Sys, A, Mods, [M1 | Acc], IsIncl, Status2)
+ mod_recap_dependencies(C, A, Mods, [M1 | Acc], IsIncl, Status2)
end;
-mod_recap_dependencies(_C, _Sys, _A, [], Acc, IsIncl, Status) ->
+mod_recap_dependencies(_C, _A, [], Acc, IsIncl, Status) ->
{lists:reverse(Acc), IsIncl, Status}.
do_get_status(M) ->
@@ -892,48 +966,53 @@ do_get_status(M) ->
ok
end.
-shrink_sys(#state{sys = #sys{apps = Apps} = Sys} = S) ->
- Apps2 = lists:zf(fun filter_app/1, Apps),
- S#state{sys = Sys#sys{apps = Apps2}}.
-
-filter_app(A) ->
- Mods = [M#mod{is_app_mod = undefined,
- is_ebin_mod = undefined,
- uses_mods = undefined,
- exists = false} ||
- M <- A#app.mods,
- M#mod.incl_cond =/= undefined],
- if
- A#app.is_escript ->
- {true, A#app{vsn = undefined,
- label = undefined,
- info = undefined,
- mods = [],
- uses_mods = undefined}};
- Mods =:= [],
- A#app.mod_cond =:= undefined,
- A#app.incl_cond =:= undefined,
- A#app.use_selected_vsn =:= undefined ->
- false;
+verify_config(C, #sys{boot_rel = BootRel, rels = Rels}, RelApps, Status) ->
+ case lists:keymember(BootRel, #rel.name, Rels) of
true ->
- {Dir, Dirs, OptVsn} =
- case A#app.use_selected_vsn of
- undefined ->
- {shrinked, [], undefined};
- false ->
- {shrinked, [], undefined};
- true ->
- {A#app.active_dir, [A#app.active_dir], A#app.vsn}
- end,
- {true, A#app{active_dir = Dir,
- sorted_dirs = Dirs,
- vsn = OptVsn,
- label = undefined,
- info = undefined,
- mods = Mods,
- uses_mods = undefined}}
+ Status2 = lists:foldl(fun(RA, Acc) ->
+ check_app(C, RA, Acc) end,
+ Status,
+ RelApps),
+ lists:foldl(fun(#rel{name = RelName}, Acc)->
+ check_rel(RelName, RelApps, Acc)
+ end,
+ Status2,
+ Rels);
+ false ->
+ Text = lists:concat(["Release ", BootRel,
+ " is mandatory (used as boot_rel)"]),
+ reltool_utils:return_first_error(Status, Text)
end.
+check_app(C, {RelName, AppName}, Status) ->
+ case ets:lookup(C#common.app_tab, AppName) of
+ [#app{is_pre_included=IsPreIncl, is_included=IsIncl}]
+ when IsPreIncl; IsIncl ->
+ Status;
+ _ ->
+ Text = lists:concat(["Release ", RelName,
+ " uses non included application ",
+ AppName]),
+ reltool_utils:return_first_error(Status, Text)
+ end.
+
+check_rel(RelName, RelApps, Status) ->
+ EnsureApp =
+ fun(AppName, Acc) ->
+ case lists:member({RelName, AppName}, RelApps) of
+ true ->
+ Acc;
+ false ->
+ Text = lists:concat(["Mandatory application ",
+ AppName,
+ " is not included in release ",
+ RelName]),
+ reltool_utils:return_first_error(Acc, Text)
+ end
+ end,
+ Mandatory = [kernel, stdlib],
+ lists:foldl(EnsureApp, Status, Mandatory).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
refresh_app(#app{name = AppName,
@@ -962,12 +1041,17 @@ refresh_app(#app{name = AppName,
AppName,
DefaultVsn,
Status),
+
+ %% And read all modules from ebin and create
+ %% #mod record with dependencies (uses_mods).
{AI, read_ebin_mods(Ebin, AppName), Status2};
true ->
{App#app.info, Mods, Status}
end,
- %% Add non-existing modules
+ %% Add non-existing modules - i.e. create default #mod
+ %% records for all modules that are listed in .app file
+ %% but do not exist in ebin.
AppInfoMods = AppInfo#app_info.modules,
AppModNames =
case AppInfo#app_info.mod of
@@ -981,11 +1065,19 @@ refresh_app(#app{name = AppName,
end,
MissingMods = add_missing_mods(AppName, EbinMods, AppModNames),
- %% Add optional user config for each module
+ %% Add optional user config for each module.
+ %% The #mod records that are already in the #app record at
+ %% this point do only contain user defined configuration
+ %% (set by parse_options/1). So here we merge with the
+ %% default records from above.
Mods2 = add_mod_config(MissingMods ++ EbinMods, Mods),
- %% Set app flag for each module in app file
+ %% Set app flag for each module in app file, i.e. the flag
+ %% which indicates if the module is listed in the .app
+ %% file or not. The start module also get the flag set to true.
Mods3 = set_mod_flags(Mods2, AppModNames),
+
+ %% Finally, set label and update the #app record
AppVsn = AppInfo#app_info.vsn,
AppLabel =
case AppVsn of
@@ -1196,12 +1288,54 @@ set_mod_flags(Mods, AppModNames) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
do_get_config(S, InclDef, InclDeriv) ->
- S2 =
+ AppTab = (S#state.common)#common.app_tab,
+ Sys =
case InclDeriv of
- false -> shrink_sys(S);
- true -> S
+ false ->
+ %% Only the apps that exist in #sys.apps shall be
+ %% included,and they shall be minimized
+ Apps = [shrink_app(App) ||
+ #app{name=Name} <- (S#state.sys)#sys.apps,
+ App <- ets:lookup(AppTab,Name)],
+ (S#state.sys)#sys{apps=Apps};
+ true ->
+ sys_all_apps(S#state.common,S#state.sys)
end,
- reltool_target:gen_config(S2#state.sys, InclDef).
+ reltool_target:gen_config(Sys, InclDef).
+
+shrink_app(A) ->
+ Mods = [M#mod{is_app_mod = undefined,
+ is_ebin_mod = undefined,
+ uses_mods = undefined,
+ exists = false} ||
+ M <- A#app.mods,
+ M#mod.incl_cond =/= undefined],
+ if
+ A#app.is_escript ->
+ A#app{vsn = undefined,
+ label = undefined,
+ info = undefined,
+ mods = [],
+ uses_mods = undefined};
+ true ->
+ {Dir, Dirs, OptVsn} =
+ case A#app.use_selected_vsn of
+ undefined ->
+ {shrinked, [], undefined};
+ false ->
+ {shrinked, [], undefined};
+ true ->
+ {A#app.active_dir, [A#app.active_dir], A#app.vsn}
+ end,
+ A#app{active_dir = Dir,
+ sorted_dirs = Dirs,
+ vsn = OptVsn,
+ label = undefined,
+ info = undefined,
+ mods = Mods,
+ uses_mods = undefined}
+ end.
+
do_save_config(S, Filename, InclDef, InclDeriv) ->
{ok, Config} = do_get_config(S, InclDef, InclDeriv),
@@ -1212,26 +1346,22 @@ do_save_config(S, Filename, InclDef, InclDeriv) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
do_load_config(S, SysConfig) ->
- OldSys = S#state.sys,
- S2 = shrink_sys(S),
- ShrinkedSys = S2#state.sys,
- {NewSys, Status} =
- read_config(ShrinkedSys#sys{apps = []}, SysConfig, {ok, []}),
+ {NewSys, Status} = read_config(default_sys(), SysConfig, {ok, []}),
case Status of
{ok, _Warnings} ->
- Force = false,
- {MergedSys, Status2} = merge_config(OldSys, NewSys, Force, Status),
- {S3, Status3} =
- analyse(S2#state{sys = MergedSys, old_sys = OldSys}, Status2),
- S4 =
+ {S2, Apps, Status2} = refresh(S#state{sys=NewSys}, true, Status),
+ Status3 = analyse(S2, Apps, Status2),
+ S3 =
case Status3 of
{ok, _Warnings2} ->
- S3#state{status = Status3, old_status = S#state.status};
+ S2#state{old_sys = S#state.sys,
+ status = Status3,
+ old_status = S#state.status};
{error, _} ->
%% Keep old state
S
end,
- {S4, Status3};
+ {S3, Status3};
{error, _} ->
%% Keep old state
{S, Status}
@@ -1298,17 +1428,12 @@ decode(#sys{apps = Apps} = Sys, [{app, Name, AppKeyVals} | SysKeyVals], Status)
{App2, Status2} = decode(App, AppKeyVals, Status),
decode(Sys#sys{apps = [App2 | Apps]}, SysKeyVals, Status2);
decode(#sys{apps = Apps, escripts = Escripts} = Sys,
- [{escript, File, AppKeyVals} | SysKeyVals], Status)
- when is_list(File), is_list(AppKeyVals) ->
- {Name, Label} = split_escript_name(File),
- App = default_app(Name, File),
- App2 = App#app{is_escript = true,
- label = Label,
- info = missing_app_info(""),
- active_dir = File,
- sorted_dirs = [File]},
- {App3, Status2} = decode(App2, AppKeyVals, Status),
- decode(Sys#sys{apps = [App3 | Apps], escripts = [File | Escripts]},
+ [{escript, File0, AppKeyVals} | SysKeyVals], Status)
+ when is_list(File0), is_list(AppKeyVals) ->
+ File = filename:absname(File0),
+ App = default_escript_app(File),
+ {App2, Status2} = decode(App, AppKeyVals, Status),
+ decode(Sys#sys{apps = [App2 | Apps], escripts = [File | Escripts]},
SysKeyVals,
Status2);
decode(#sys{rels = Rels} = Sys, [{rel, Name, Vsn, RelApps} | SysKeyVals],
@@ -1554,79 +1679,50 @@ split_escript_name(File) when is_list(File) ->
Label = filename:basename(File, ".escript"),
{list_to_atom("*escript* " ++ Label), Label}.
+default_escript_app(File) ->
+ {Name, Label} = split_escript_name(File),
+ App = default_app(Name, File),
+ App#app{is_escript = true,
+ label = Label,
+ info = missing_app_info("")}.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-refresh(#state{sys = Sys} = S, Force, Status) ->
- {Sys2, Status2} = merge_config(Sys, Sys#sys{apps = []}, Force, Status),
- {S#state{sys = Sys2}, Status2}.
-
-merge_config(OldSys, NewSys, Force, Status) ->
- RootDir = filename:absname(NewSys#sys.root_dir),
- LibDirs = [filename:absname(D) || D <- NewSys#sys.lib_dirs],
- Escripts = [filename:absname(E) || E <- NewSys#sys.escripts],
- {SourceDirs, Status2} =
- libs_to_dirs(RootDir, LibDirs, Status),
- MergedApps = merge_app_dirs(SourceDirs, NewSys#sys.apps, OldSys#sys.apps),
- {AllApps, Status3} =
- escripts_to_apps(Escripts, MergedApps, OldSys#sys.apps, Status2),
- {RefreshedApps, Status4} =
- refresh_apps(OldSys#sys.apps, AllApps, [], Force, Status3),
- {PatchedApps, Status5} =
- patch_erts_version(RootDir, RefreshedApps, Status4),
- Escripts2 = [A#app.active_dir || A <- PatchedApps, A#app.is_escript],
- NewSys2 = NewSys#sys{root_dir = RootDir,
- lib_dirs = LibDirs,
- escripts = Escripts2,
- apps = PatchedApps},
- {NewSys2, Status5}.
+%% Apps is a list of #app records - sorted on #app.name - containing
+%% only the apps that have specific configuration (e.g. in the config
+%% file)
+refresh(#state{sys=Sys} = S, Force, Status) ->
+ RootDir = filename:absname(Sys#sys.root_dir),
+ LibDirs = [filename:absname(D) || D <- Sys#sys.lib_dirs],
+ Escripts = [filename:absname(E) || E <- Sys#sys.escripts],
-verify_config(RelApps, #sys{boot_rel = BootRel, rels = Rels, apps = Apps}, Status) ->
- case lists:keymember(BootRel, #rel.name, Rels) of
- true ->
- Status2 = lists:foldl(fun(RA, Acc) ->
- check_app(RA, Apps, Acc) end,
- Status,
- RelApps),
- lists:foldl(fun(#rel{name = RelName}, Acc)->
- check_rel(RelName, RelApps, Acc)
- end,
- Status2,
- Rels);
- false ->
- Text = lists:concat(["Release ", BootRel,
- " is mandatory (used as boot_rel)"]),
- reltool_utils:return_first_error(Status, Text)
- end.
+ %% Read all lib dirs and return sorted [{AppName,Dir}]
+ {SourceDirs, Status2} = libs_to_dirs(RootDir, LibDirs, Status),
-check_app({RelName, AppName}, Apps, Status) ->
- case lists:keysearch(AppName, #app.name, Apps) of
- {value, App} when App#app.is_pre_included ->
- Status;
- {value, App} when App#app.is_included ->
- Status;
- _ ->
- Text = lists:concat(["Release ", RelName,
- " uses non included application ",
- AppName]),
- reltool_utils:return_first_error(Status, Text)
- end.
+ %% Create #app records for all apps in SourceDirs, and merge with
+ %% list of apps from config.
+ MergedApps = merge_app_dirs(SourceDirs, Sys#sys.apps),
-check_rel(RelName, RelApps, Status) ->
- EnsureApp =
- fun(AppName, Acc) ->
- case lists:member({RelName, AppName}, RelApps) of
- true ->
- Acc;
- false ->
- Text = lists:concat(["Mandatory application ",
- AppName,
- " is not included in release ",
- RelName]),
- reltool_utils:return_first_error(Acc, Text)
- end
- end,
- Mandatory = [kernel, stdlib],
- lists:foldl(EnsureApp, Status, Mandatory).
+ %% For each escript, find all related files and convert to #app
+ %% and #mod records
+ {AllApps, Status3} = escripts_to_apps(Escripts, MergedApps, Status2),
+
+ %% Make sure correct version of each application is used according
+ %% to the user configuration.
+ %% Then find all modules and their dependencies and set user
+ %% configuration per module if it exists.
+ {RefreshedApps, Status4} = refresh_apps(Sys#sys.apps, AllApps, [],
+ Force, Status3),
+
+ %% Make sure erts exists in app list and has a version (or warn)
+ {PatchedApps, Status5} = patch_erts_version(RootDir, RefreshedApps, Status4),
+
+ %% Update #sys and return
+ Escripts2 = [A#app.active_dir || A <- PatchedApps, A#app.is_escript],
+ Sys2 = Sys#sys{root_dir = RootDir,
+ lib_dirs = LibDirs,
+ escripts = Escripts2},
+ {S#state{sys=Sys2}, PatchedApps, Status5}.
patch_erts_version(RootDir, Apps, Status) ->
AppName = erts,
@@ -1717,7 +1813,7 @@ app_dirs2([Lib | Libs], Acc, Status) ->
app_dirs2([], Acc, Status) ->
{lists:sort(lists:append(Acc)), Status}.
-escripts_to_apps([Escript | Escripts], Apps, OldApps, Status) ->
+escripts_to_apps([Escript | Escripts], Apps, Status) ->
{EscriptAppName, _Label} = split_escript_name(Escript),
Ext = code:objfile_extension(),
Fun = fun(FullName, _GetInfo, GetBin, {FileAcc, StatusAcc}) ->
@@ -1780,92 +1876,67 @@ escripts_to_apps([Escript | Escripts], Apps, OldApps, Status) ->
end,
case reltool_utils:escript_foldl(Fun, {[], Status}, Escript) of
{ok, {Files, Status2}} ->
+ EscriptApp =
+ case lists:keyfind(EscriptAppName,#app.name,Apps) of
+ false -> default_escript_app(Escript);
+ EA -> EA
+ end,
{Apps2, Status3} =
- files_to_apps(Escript,
- lists:sort(Files),
- Apps,
- Apps,
- OldApps,
- Status2),
- escripts_to_apps(Escripts, Apps2, OldApps, Status3);
+ escript_files_to_apps(Escript,
+ lists:sort(Files),
+ [EscriptApp],
+ Apps,
+ Status2),
+ escripts_to_apps(Escripts, Apps2, Status3);
{error, Reason} ->
Text = lists:flatten(io_lib:format("~p", [Reason])),
{[], reltool_utils:return_first_error(Status,
"Illegal escript " ++
Escript ++ ": " ++ Text)}
end;
-escripts_to_apps([], Apps, _OldApps, Status) ->
+escripts_to_apps([], Apps, Status) ->
{Apps, Status}.
%% Assume that all files for an app are in consecutive order
%% Assume the app info is before the mods
-files_to_apps(Escript,
- [{AppName, Type, Dir, ModOrInfo} | Files] = AllFiles,
- Acc,
- Apps,
- OldApps,
- Status) ->
- case Type of
- mod ->
- case Acc of
- [] ->
- Info = missing_app_info(""),
- {NewApp, Status2} =
- merge_escript_app(AppName,
- Dir,
- Info,
- [ModOrInfo],
- Apps,
- OldApps,
- Status),
- files_to_apps(Escript,
- AllFiles,
- [NewApp | Acc],
- Apps,
- OldApps, Status2);
- [App | Acc2] when App#app.name =:= ModOrInfo#mod.app_name ->
- App2 = App#app{mods = [ModOrInfo | App#app.mods]},
- files_to_apps(Escript,
- Files,
- [App2 | Acc2],
- Apps,
- OldApps,
- Status);
- [App | Acc2] ->
- PrevApp = App#app{mods = lists:keysort(#mod.name,
- App#app.mods)},
- Info = missing_app_info(""),
- {NewApp, Status2} =
- merge_escript_app(AppName,
- Dir,
- Info,
- [ModOrInfo],
- Apps,
- OldApps,
- Status),
- files_to_apps(Escript,
- Files,
- [NewApp, PrevApp | Acc2],
- Apps,
- OldApps,
- Status2)
- end;
- app ->
- {App, Status2} =
- merge_escript_app(AppName, Dir, ModOrInfo, [], Apps, OldApps,
- Status),
- files_to_apps(Escript, Files, [App | Acc], Apps, OldApps, Status2)
- end;
-files_to_apps(_Escript, [], Acc, _Apps, _OldApps, Status) ->
- {lists:keysort(#app.name, Acc), Status}.
-
-merge_escript_app(AppName, Dir, Info, Mods, Apps, OldApps, Status) ->
- App1 = case lists:keyfind(AppName, #app.name, OldApps) of
- #app{} = App ->
- App;
- false ->
- default_app(AppName, Dir)
- end,
+escript_files_to_apps(Escript,
+ [{AppName, Type, Dir, ModOrInfo} | Files],
+ Acc,
+ Apps,
+ Status) ->
+ {NewAcc,Status3} =
+ case Type of
+ mod ->
+ case Acc of
+ [App | Acc2] when App#app.name =:= ModOrInfo#mod.app_name ->
+ Mods = lists:ukeymerge(#mod.name,
+ [ModOrInfo],
+ App#app.mods),
+ {[App#app{mods = Mods} | Acc2], Status};
+ Acc ->
+ {NewApp, Status2} = init_escript_app(AppName,
+ Dir,
+ missing_app_info(""),
+ [ModOrInfo],
+ Apps,
+ Status),
+ {[NewApp | Acc], Status2}
+ end;
+ app ->
+ {App, Status2} = init_escript_app(AppName,
+ Dir,
+ ModOrInfo,
+ [],
+ Apps,
+ Status),
+ {[App | Acc], Status2}
+ end,
+ escript_files_to_apps(Escript, Files, NewAcc, Apps, Status3);
+escript_files_to_apps(_Escript, [], Acc, Apps, Status) ->
+ {lists:ukeymerge(#app.name, Acc, Apps), Status}.
+
+init_escript_app(AppName, Dir, Info, Mods, Apps, Status) ->
+ App1 = default_app(AppName, Dir),
App2 = App1#app{is_escript = true,
label = filename:basename(Dir, ".escript"),
info = Info,
@@ -1882,54 +1953,30 @@ merge_escript_app(AppName, Dir, Info, Mods, Apps, OldApps, Status) ->
{App2, Status}
end.
-merge_app_dirs([{Name, Dir} | Rest], [App | Apps], OldApps)
- when App#app.name =:= Name ->
- %% Add new dir to app
- App2 = App#app{sorted_dirs = [Dir | App#app.sorted_dirs]},
- merge_app_dirs(Rest, [App2 | Apps], OldApps);
-merge_app_dirs([{Name, Dir} | Rest], Apps, OldApps) ->
- %% Initate app
- Apps2 = sort_app_dirs(Apps),
- Apps4 =
+merge_app_dirs([{Name, Dir} | Rest], Apps) ->
+ App =
case lists:keyfind(Name, #app.name, Apps) of
false ->
- case lists:keyfind(Name, #app.name, OldApps) of
- false ->
- App = default_app(Name, Dir),
- [App | Apps2];
- #app{active_dir = Dir} = OldApp ->
- [OldApp | Apps2];
- OldApp ->
- App =
- case filter_app(OldApp) of
- {true, NewApp} ->
- NewApp#app{active_dir = Dir,
- sorted_dirs = [Dir]};
- false ->
- default_app(Name, Dir)
- end,
- [App | Apps2]
- end;
+ default_app(Name, Dir);
OldApp ->
- Apps3 = lists:keydelete(Name, #app.name, Apps2),
- App = OldApp#app{sorted_dirs = [Dir | OldApp#app.sorted_dirs]},
- [App | Apps3]
+ SortedDirs = lists:umerge(fun reltool_utils:app_dir_test/2,
+ [Dir], OldApp#app.sorted_dirs),
+ OldApp#app{sorted_dirs = SortedDirs}
end,
- merge_app_dirs(Rest, Apps4, OldApps);
-merge_app_dirs([], Apps, _OldApps) ->
- Apps2 = sort_app_dirs(Apps),
- lists:reverse(Apps2).
-
-sort_app_dirs([#app{sorted_dirs = Dirs} = App | Acc]) ->
- SortedDirs = lists:sort(fun reltool_utils:app_dir_test/2, Dirs),
- case SortedDirs of
- [ActiveDir | _] -> ok;
- [] -> ActiveDir = undefined
- end,
- [App#app{active_dir = ActiveDir, sorted_dirs = SortedDirs} | Acc];
-sort_app_dirs([]) ->
+ Apps2 = lists:ukeymerge(#app.name, [App], Apps),
+ merge_app_dirs(Rest, Apps2);
+merge_app_dirs([], Apps) ->
+ set_active_dirs(Apps).
+
+%% First dir, i.e. the one with highest version, is set to active dir
+set_active_dirs([#app{sorted_dirs = [ActiveDir|_]} = App | Apps]) ->
+ [App#app{active_dir = ActiveDir} | set_active_dirs(Apps)];
+set_active_dirs([#app{sorted_dirs = []} = App | Apps]) ->
+ [App#app{active_dir = undefined} | set_active_dirs(Apps)];
+set_active_dirs([]) ->
[].
+
default_app(Name, Dir) ->
App = default_app(Name),
App#app{active_dir = Dir,
@@ -1938,82 +1985,44 @@ default_app(Name, Dir) ->
default_app(Name) ->
#app{name = Name,
is_escript = false,
- use_selected_vsn = undefined,
- active_dir = undefined,
sorted_dirs = [],
- vsn = undefined,
- label = undefined,
- info = undefined,
mods = [],
-
- mod_cond = undefined,
- incl_cond = undefined,
-
- status = missing,
- uses_mods = undefined,
- is_pre_included = undefined,
- is_included = undefined,
- rels = undefined}.
-
-%% Assume that the application are sorted
-refresh_apps([Old | OldApps], [New | NewApps], Acc, Force, Status)
- when New#app.name =:= Old#app.name ->
- {Info, ActiveDir, Status2} = ensure_app_info(New, Status),
- OptLabel =
- case Info#app_info.vsn =:= New#app.vsn of
- true -> New#app.label;
- false -> undefined % Cause refresh
- end,
- {Refreshed, Status3} =
- refresh_app(New#app{label = OptLabel,
- active_dir = ActiveDir,
- vsn = Info#app_info.vsn,
- info = Info},
- Force,
- Status2),
- refresh_apps(OldApps, NewApps, [Refreshed | Acc], Force, Status3);
-refresh_apps([Old | OldApps], [New | NewApps], Acc, Force, Status)
- when New#app.name < Old#app.name ->
- %% No old app version exists. Use new as is.
- %% BUGBUG: Issue warning if the active_dir is not defined
- {New2, Status2} = refresh_app(New, Force, Status),
- refresh_apps([Old | OldApps], NewApps, [New2 | Acc], Force, Status2);
-refresh_apps([Old | OldApps], [New | NewApps], Acc, Force, Status)
- when New#app.name > Old#app.name ->
- %% No new version. Remove the old.
- Status2 =
- case Old#app.name =:= ?MISSING_APP_NAME of
- true ->
- Status;
- false ->
- Warning =
- lists:concat([Old#app.name,
- ": The source dirs does not ",
- "contain the application anymore."]),
- reltool_utils:add_warning(Status, Warning)
- end,
- refresh_apps(OldApps, [New | NewApps], Acc, Force, Status2);
-refresh_apps([], [New | NewApps], Acc, Force, Status) ->
- %% No old app version exists. Use new as is.
- {New2, Status2} = refresh_app(New, Force, Status),
- refresh_apps([], NewApps, [New2 | Acc], Force, Status2);
-refresh_apps([Old | OldApps], [], Acc, Force, Status) ->
- %% No new version. Remove the old.
- Status2 =
- case Old#app.name =:= ?MISSING_APP_NAME of
- true ->
- Status;
- false ->
- Warning =
- lists:concat([Old#app.name,
- ": The source dirs does not "
- "contain the application anymore."]),
- reltool_utils:add_warning(Status, Warning)
- end,
- refresh_apps(OldApps, [], Acc, Force, Status2);
-refresh_apps([], [], Acc, _Force, Status) ->
+ status = missing}.
+
+
+
+refresh_apps(ConfigApps, [New | NewApps], Acc, Force, Status) ->
+ {New2, Status3} =
+ case lists:keymember(New#app.name,#app.name,ConfigApps) of
+ true ->
+ %% There is user defined config for this application, make
+ %% sure that the application exists and that correct
+ %% version is used. Set active directory.
+ {Info, ActiveDir, Status2} = ensure_app_info(New, Status),
+ OptLabel =
+ case Info#app_info.vsn =:= New#app.vsn of
+ true -> New#app.label;
+ false -> undefined % Cause refresh
+ end,
+ refresh_app(New#app{label = OptLabel,
+ active_dir = ActiveDir,
+ vsn = Info#app_info.vsn,
+ info = Info},
+ Force,
+ Status2);
+ false ->
+ %% There is no user defined config for this
+ %% application. This means that the app is found in the
+ %% lib dirs, and that the highest version shall be
+ %% used. I.e. the active_dir and vsn are already correct
+ %% from merge_app_dirs.
+ refresh_app(New, Force, Status)
+ end,
+ refresh_apps(ConfigApps, NewApps, [New2 | Acc], Force, Status3);
+refresh_apps(_ConfigApps, [], Acc, _Force, Status) ->
{lists:reverse(Acc), Status}.
+
ensure_app_info(#app{is_escript = true, active_dir = Dir, info = Info},
Status) ->
{Info, Dir, Status};
@@ -2092,6 +2101,12 @@ get_base(Name, Dir) ->
filename:basename(Dir)
end.
+sys_all_apps(C,Sys) ->
+ Sys#sys{apps = all_apps(C)}.
+
+all_apps(C) ->
+ ets:match_object(C#common.app_tab,'_').
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% sys callbacks
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index 56c9cb5ed1..f2b63f78f0 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -1192,8 +1192,10 @@ set_app_and_undo(Config) ->
ExclCover = Cover#mod{incl_cond=exclude},
Mods = Tools#app.mods,
Tools1 = Tools#app{mods = lists:keyreplace(cover,#mod.name,Mods,ExclCover)},
- {ok,ToolsNoCover,[]} = ?msym({ok,_,[]}, reltool_server:set_app(Pid,Tools1)),
- ?m({ok,[]}, reltool_server:get_status(Pid)),
+ {ok,ToolsNoCover,["a: Cannot parse app file"++_|_]} =
+ ?msym({ok,_,["a: Cannot parse app file"++_|_]},
+ reltool_server:set_app(Pid,Tools1)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]}, reltool_server:get_status(Pid)),
%% Check that the module is no longer included
?m({ok,ToolsNoCover}, reltool_server:get_app(Pid,tools)),
@@ -1201,17 +1203,16 @@ set_app_and_undo(Config) ->
reltool_server:get_mod(Pid,cover)),
%% Undo
- %%! warning can come twice here... :(
?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:undo_config(Pid)),
?m({ok,Tools}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover}, reltool_server:get_mod(Pid,cover)),
?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
%% Undo again, to check that it toggles
- ?m({ok,[]}, reltool_server:undo_config(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]}, reltool_server:undo_config(Pid)),
?m({ok,ToolsNoCover}, reltool_server:get_app(Pid,tools)),
?m({ok,NoIncludeCover}, reltool_server:get_mod(Pid,cover)),
- ?m({ok,[]}, reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]}, reltool_server:get_status(Pid)),
?m(ok, reltool:stop(Pid)),
ok.
@@ -1238,8 +1239,9 @@ set_apps_and_undo(Config) ->
%% Exclude one application with set_apps
ExclTools = Tools#app{incl_cond=exclude},
- ?m({ok,[]}, reltool_server:set_apps(Pid,[ExclTools])),
- ?m({ok,[]}, reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]},
+ reltool_server:set_apps(Pid,[ExclTools])),
+ ?msym({ok,["a: Cannot parse app file"++_|_]}, reltool_server:get_status(Pid)),
%% Check that the app and its modules (one of them) are no longer included
{ok,NoTools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
@@ -1249,17 +1251,16 @@ set_apps_and_undo(Config) ->
reltool_server:get_mod(Pid,cover)),
%% Undo
- %%! warning can come twice here... :(
?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:undo_config(Pid)),
?m({ok,Tools}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover}, reltool_server:get_mod(Pid,cover)),
?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
%% Undo again, to check that it toggles
- ?m({ok,[]}, reltool_server:undo_config(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]}, reltool_server:undo_config(Pid)),
?m({ok,NoTools}, reltool_server:get_app(Pid,tools)),
?m({ok,NoIncludeCover}, reltool_server:get_mod(Pid,cover)),
- ?m({ok,[]}, reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]}, reltool_server:get_status(Pid)),
?m(ok, reltool:stop(Pid)),
ok.
@@ -1327,7 +1328,7 @@ load_config_and_undo(Config) ->
{app,sasl,[{incl_cond,include}]},
{app,stdlib,[{incl_cond,include}]},
{app,tools,[{incl_cond,derived}]}]},
- ?msym({ok,["a: Cannot parse app file"++_]},
+ ?msym({ok,["a: Cannot parse app file"++_|_]},
reltool_server:load_config(Pid,Sys2)),
%%% OTP-0702, 15) ?m({ok, Sys2}, reltool:get_config(Pid)),
%%% Note that {incl_cond,exclude} is removed compared to Sys1 -
@@ -1363,7 +1364,6 @@ load_config_and_undo(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Load config with escript
-load_config_escript_path(_Config) -> {skip,"Known bug: loading config with escript at reltool start creates different #app record than loading same config with load_config"};
load_config_escript_path(Config) ->
%% Create escript
DataDir = ?config(data_dir,Config),
@@ -1411,7 +1411,6 @@ load_config_escript_path(Config) ->
%% Load config with same (source) escript twice and check that the
%% application information is not changed.
-load_config_same_escript_source(_Config) -> {skip,"Known bug: loading config with same escript (source) twice causes reltool to add same module twice in #app.mods"};
load_config_same_escript_source(_Config) ->
%% Create escript
ExDir = code:lib_dir(reltool, examples),
@@ -1428,12 +1427,14 @@ load_config_same_escript_source(_Config) ->
]},
{ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
- {ok,[#app{name='*escript* display_args'}=A]} =
- ?msym({ok,[_]}, reltool_server:get_apps(Pid,whitelist)),
+% {ok,[#app{name='*escript* display_args'}]} =
+ ?msym({ok,[#app{name='*escript* display_args',mods=[_]}]},
+ reltool_server:get_apps(Pid,whitelist)),
%% Load the same config again, then check that app is not changed
?m({ok,[]}, reltool_server:load_config(Pid,Sys)),
- ?m({ok,[A]}, reltool_server:get_apps(Pid,whitelist)),
+ ?msym({ok,[#app{name='*escript* display_args',mods=[_]}]},
+ reltool_server:get_apps(Pid,whitelist)),
?m(ok, reltool:stop(Pid)),
@@ -1443,7 +1444,6 @@ load_config_same_escript_source(_Config) ->
%% Load config with same (beam) escript twice and check that the
%% application information is not changed.
-load_config_same_escript_beam(_Config) -> {skip,"Known bug: loading config with same escript (with inlined beam) twice causes reltool to fail and say module is included by two different applications"};
load_config_same_escript_beam(Config) ->
%% Create escript
DataDir = ?config(data_dir,Config),
@@ -1478,8 +1478,6 @@ load_config_same_escript_beam(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Load config with escript
-%% BUG: see OTP-9792, 25)
-load_config_add_escript(_Config) -> {skip,"Known bug: Can not load_config which in addition to an existing escript also adds another escript for which the name sorts before the existing one"};
load_config_add_escript(Config) ->
%% First escript
ExDir = code:lib_dir(reltool, examples),
@@ -1566,7 +1564,6 @@ reset_config_and_undo(Config) ->
reltool_server:get_mod(Pid,cover)),
%% Reset
- %%! warning can come twice here... :(
?msym({ok,["a: Cannot parse app file"++_|_]},
reltool_server:reset_config(Pid)),
?m({ok,Tools1}, reltool_server:get_app(Pid,tools)),
--
cgit v1.2.3
From 0bc47607cad0c9ad475a7c0a8e7aa5633d00ceb5 Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Thu, 16 Feb 2012 14:21:19 +0100
Subject: [reltool] Fix badmatch when starting GUI
OTP-9792
Start of reltool GUI sometimes crashes with a badmatch in
reltool_sys_win:do_init/1 because the #sys record fetched with
reltool_server:get_sys/1 differs from the #sys record returned from
reltool_server:start_link/1. This has been
corrected. reltool_server:start_link/1 no longer retuns the #sys
record.
---
lib/reltool/src/reltool.erl | 4 ++--
lib/reltool/src/reltool_server.erl | 5 ++---
lib/reltool/src/reltool_sys_win.erl | 2 +-
3 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/lib/reltool/src/reltool.erl b/lib/reltool/src/reltool.erl
index 54eb1ca9e1..a2b1c9468c 100644
--- a/lib/reltool/src/reltool.erl
+++ b/lib/reltool/src/reltool.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -66,7 +66,7 @@ start_link(Options) when is_list(Options) ->
-spec start_server(options()) -> {ok, server_pid()} | {error, reason()}.
start_server(Options) ->
case reltool_server:start_link(Options) of
- {ok, ServerPid, _Common, _Sys} ->
+ {ok, ServerPid, _Common} ->
{ok, ServerPid};
{error, Reason} ->
{error, lists:flatten(io_lib:format("~p", [Reason]))}
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index b6ffb9b134..da15d91581 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -133,11 +133,10 @@ init(Options) ->
do_init(Options) ->
{S, Status} = parse_options(Options),
- #state{parent_pid = ParentPid, common = C, sys = Sys} = S,
+ #state{parent_pid = ParentPid, common = C} = S,
%% process_flag(trap_exit, (S#state.common)#common.trap_exit),
- proc_lib:init_ack(ParentPid,
- {ok, self(), C, Sys#sys{apps = undefined}}),
+ proc_lib:init_ack(ParentPid, {ok, self(), C}),
{S2, Apps, Status2} = refresh(S, true, Status),
Status3 = analyse(S2, Apps, Status2),
case Status3 of
diff --git a/lib/reltool/src/reltool_sys_win.erl b/lib/reltool/src/reltool_sys_win.erl
index f29a95af38..c49641d6a3 100644
--- a/lib/reltool/src/reltool_sys_win.erl
+++ b/lib/reltool/src/reltool_sys_win.erl
@@ -135,7 +135,7 @@ init(Options) ->
do_init([{safe_config, Safe}, {parent, Parent} | Options]) ->
case reltool_server:start_link(Options) of
- {ok, ServerPid, C, Sys} ->
+ {ok, ServerPid, C} ->
process_flag(trap_exit, C#common.trap_exit),
wx:new(),
wx:debug(C#common.wx_debug),
--
cgit v1.2.3
From a5240467ac0b5428063360fc4a3d67ab9ffa1413 Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Thu, 16 Feb 2012 14:58:57 +0100
Subject: [reltool] Link together escript with inlined application
OTP-9968
Make sure that inlined applications in an escript is included/excluded
as the escript itself, and forbid explicit configuration of the
inlined application.
---
lib/reltool/src/reltool.hrl | 3 +-
lib/reltool/src/reltool_mod_win.erl | 6 +-
lib/reltool/src/reltool_server.erl | 113 +++++++++++++++++++----------
lib/reltool/src/reltool_target.erl | 8 +--
lib/reltool/test/reltool_server_SUITE.erl | 116 ++++++++++++++++++++++++++++--
5 files changed, 193 insertions(+), 53 deletions(-)
diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl
index 8e80c80e10..0a90c42ce2 100644
--- a/lib/reltool/src/reltool.hrl
+++ b/lib/reltool/src/reltool.hrl
@@ -45,6 +45,7 @@
-type profile() :: development | embedded | standalone.
-type relocatable() :: boolean().
-type escript_file() :: file().
+-type escript_app_name() :: app_name().
-type mod_name() :: atom().
-type app_name() :: atom().
-type app_vsn() :: string(). % e.g. "4.7"
@@ -170,7 +171,7 @@
-record(app,
{ %% Static info
name :: app_name(),
- is_escript :: boolean(),
+ is_escript :: boolean() | {inlined, escript_app_name()},
use_selected_vsn :: boolean() | undefined,
active_dir :: dir(),
sorted_dirs :: [dir()],
diff --git a/lib/reltool/src/reltool_mod_win.erl b/lib/reltool/src/reltool_mod_win.erl
index e1c2fa5100..8cf175547b 100644
--- a/lib/reltool/src/reltool_mod_win.erl
+++ b/lib/reltool/src/reltool_mod_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -314,8 +314,8 @@ do_create_code_page(#state{xref_pid = Xref, mod = M} = S, PageName) ->
{ok, App} = reltool_server:get_app(Xref, M#mod.app_name),
ErlBin =
case App#app.is_escript of
- true -> find_escript_bin(App, M);
- false -> find_regular_bin(App, M)
+ false -> find_regular_bin(App, M);
+ _ -> find_escript_bin(App, M)
end,
load_code(Editor, ErlBin),
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index da15d91581..f5abaf0957 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -467,20 +467,30 @@ loop(#state{common = C, sys = Sys} = S) ->
do_set_apps(#state{sys = Sys} = S, ChangedApps, Status) ->
%% Create new list of configured applications
- Sys2 = Sys#sys{apps = app_update_config(ChangedApps, Sys#sys.apps)},
+ {SysApps,Status2} = app_update_config(ChangedApps, Sys#sys.apps, Status),
+ Sys2 = Sys#sys{apps = SysApps},
- %% Refresh and analyse
- {S2, Apps, Status2} = refresh(S#state{sys = Sys2}, true, Status),
- Status3 = analyse(S2, Apps, Status2),
+ %% Refresh from filesystem and analyse dependencies
+ {S2, Apps, Status3} = refresh(S#state{sys = Sys2}, true, Status2),
+ Status4 = analyse(S2, Apps, Status3),
- {S2, Status3}.
+ {S2, Status4}.
%% Re-create the #sys.apps list by
%% 1) taking configurable fields from the changed #app records and
%% create new default records
%% 2) removing #app records if no configurable fields are set
%% 3) keeping #app records that are not changed
-app_update_config([Config|Configs],SysApps) ->
+app_update_config([#app{name=Name,is_escript={inlined,Escript}}|Configs],
+ SysApps,Status) ->
+ Text =
+ lists:flatten(
+ io_lib:format("Application ~p is inlined in ~p. Can not change "
+ "configuration for an inlined application.",
+ [Name,Escript])),
+ Status2 = reltool_utils:return_first_error(Status, Text),
+ app_update_config(Configs,SysApps,Status2);
+app_update_config([Config|Configs],SysApps,Status) ->
NewSysApps =
case app_set_config_only(Config) of
{delete,Name} ->
@@ -488,9 +498,9 @@ app_update_config([Config|Configs],SysApps) ->
New ->
lists:ukeymerge(#app.name,[New],SysApps)
end,
- app_update_config(Configs,NewSysApps);
-app_update_config([],SysApps) ->
- SysApps.
+ app_update_config(Configs,NewSysApps,Status);
+app_update_config([],SysApps,Status) ->
+ {SysApps,Status}.
app_set_config_only(#app{mods=ConfigMods} = Config) ->
app_set_config_only(mod_set_config_only(ConfigMods),Config).
@@ -506,13 +516,13 @@ app_set_config_only([],#app{name = Name,
excl_app_filters = undefined,
incl_archive_filters = undefined,
excl_archive_filters = undefined,
- archive_opts = undefined}) ->
+ archive_opts = undefined,
+ is_escript = false})->
{delete,Name};
app_set_config_only(Mods,#app{name = Name,
incl_cond = InclCond,
mod_cond = ModCond,
use_selected_vsn = UseSelectedVsn,
- active_dir = ActiveDir,
debug_info = DebugInfo,
app_file = AppFile,
app_type = AppType,
@@ -521,21 +531,38 @@ app_set_config_only(Mods,#app{name = Name,
incl_archive_filters = InclArchiveFilters,
excl_archive_filters = ExclArchiveFilters,
archive_opts = ArchiveOpts,
- vsn = Vsn}) ->
- (default_app(Name))#app{incl_cond = InclCond,
- mod_cond = ModCond,
- use_selected_vsn = UseSelectedVsn,
- active_dir = ActiveDir,
- debug_info = DebugInfo,
- app_file = AppFile,
- app_type = AppType,
- incl_app_filters = InclAppFilters,
- excl_app_filters = ExclAppFilters,
- incl_archive_filters = InclArchiveFilters,
- excl_archive_filters = ExclArchiveFilters,
- archive_opts = ArchiveOpts,
- vsn = Vsn,
- mods = Mods}.
+ vsn = Vsn,
+ is_escript = IsEscript,
+ label = Label,
+ info = Info,
+ active_dir = ActiveDir,
+ sorted_dirs = SortedDirs}) ->
+ App = (default_app(Name))#app{incl_cond = InclCond,
+ mod_cond = ModCond,
+ use_selected_vsn = UseSelectedVsn,
+ debug_info = DebugInfo,
+ app_file = AppFile,
+ app_type = AppType,
+ incl_app_filters = InclAppFilters,
+ excl_app_filters = ExclAppFilters,
+ incl_archive_filters = InclArchiveFilters,
+ excl_archive_filters = ExclArchiveFilters,
+ archive_opts = ArchiveOpts,
+ vsn = Vsn,
+ mods = Mods},
+
+ %% Some fields shall only be set if it is an escript, e.g. label
+ %% must never be set for any other applications since that will
+ %% prevent refreshing.
+ if IsEscript ->
+ App#app{is_escript = IsEscript,
+ active_dir = ActiveDir,
+ sorted_dirs = SortedDirs,
+ label = Label,
+ info = Info};
+ true ->
+ App
+ end.
mod_set_config_only(ConfigMods) ->
[#mod{name = Name,
@@ -1044,7 +1071,7 @@ refresh_app(#app{name = AppName,
%% And read all modules from ebin and create
%% #mod record with dependencies (uses_mods).
{AI, read_ebin_mods(Ebin, AppName), Status2};
- true ->
+ _ ->
{App#app.info, Mods, Status}
end,
@@ -1316,7 +1343,7 @@ shrink_app(A) ->
info = undefined,
mods = [],
uses_mods = undefined};
- true ->
+ true ->
{Dir, Dirs, OptVsn} =
case A#app.use_selected_vsn of
undefined ->
@@ -1881,7 +1908,7 @@ escripts_to_apps([Escript | Escripts], Apps, Status) ->
EA -> EA
end,
{Apps2, Status3} =
- escript_files_to_apps(Escript,
+ escript_files_to_apps(EscriptAppName,
lists:sort(Files),
[EscriptApp],
Apps,
@@ -1898,7 +1925,7 @@ escripts_to_apps([], Apps, Status) ->
%% Assume that all files for an app are in consecutive order
%% Assume the app info is before the mods
-escript_files_to_apps(Escript,
+escript_files_to_apps(EscriptAppName,
[{AppName, Type, Dir, ModOrInfo} | Files],
Acc,
Apps,
@@ -1914,6 +1941,7 @@ escript_files_to_apps(Escript,
{[App#app{mods = Mods} | Acc2], Status};
Acc ->
{NewApp, Status2} = init_escript_app(AppName,
+ EscriptAppName,
Dir,
missing_app_info(""),
[ModOrInfo],
@@ -1923,6 +1951,7 @@ escript_files_to_apps(Escript,
end;
app ->
{App, Status2} = init_escript_app(AppName,
+ EscriptAppName,
Dir,
ModOrInfo,
[],
@@ -1930,18 +1959,24 @@ escript_files_to_apps(Escript,
Status),
{[App | Acc], Status2}
end,
- escript_files_to_apps(Escript, Files, NewAcc, Apps, Status3);
-escript_files_to_apps(_Escript, [], Acc, Apps, Status) ->
- {lists:ukeymerge(#app.name, Acc, Apps), Status}.
+ escript_files_to_apps(EscriptAppName, Files, NewAcc, Apps, Status3);
+escript_files_to_apps(_EscriptAppName, [], Acc, Apps, Status) ->
+ {lists:ukeymerge(#app.name, lists:reverse(Acc), Apps), Status}.
-init_escript_app(AppName, Dir, Info, Mods, Apps, Status) ->
+init_escript_app(AppName, EscriptAppName, Dir, Info, Mods, Apps, Status) ->
App1 = default_app(AppName, Dir),
- App2 = App1#app{is_escript = true,
+ IsEscript =
+ if AppName=:=EscriptAppName -> true;
+ true -> {inlined, EscriptAppName}
+ end,
+ InclCond = (lists:keyfind(EscriptAppName,#app.name,Apps))#app.incl_cond,
+ App2 = App1#app{is_escript = IsEscript,
label = filename:basename(Dir, ".escript"),
info = Info,
mods = Mods,
active_dir = Dir,
- sorted_dirs = [Dir]},
+ sorted_dirs = [Dir],
+ incl_cond = InclCond},% inlined apps inherit incl from escript
case lists:keymember(AppName, #app.name, Apps) of
true ->
Error = lists:concat([AppName, ": Application name clash. ",
@@ -2022,8 +2057,10 @@ refresh_apps(_ConfigApps, [], Acc, _Force, Status) ->
{lists:reverse(Acc), Status}.
-ensure_app_info(#app{is_escript = true, active_dir = Dir, info = Info},
- Status) ->
+ensure_app_info(#app{is_escript = IsEscript, active_dir = Dir, info = Info},
+ Status)
+ when IsEscript=/=false ->
+ %% Escript or application which is inlined in an escript
{Info, Dir, Status};
ensure_app_info(#app{name = Name, sorted_dirs = []}, Status) ->
Error = lists:concat([Name, ": Missing application directory."]),
diff --git a/lib/reltool/src/reltool_target.erl b/lib/reltool/src/reltool_target.erl
index 0fcf89a360..40d1009733 100644
--- a/lib/reltool/src/reltool_target.erl
+++ b/lib/reltool/src/reltool_target.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -101,7 +101,7 @@ do_gen_config(#sys{root_dir = RootDir,
|| A <- Apps,
A#app.name =/= ?MISSING_APP_NAME,
A#app.name =/= erts,
- not A#app.is_escript],
+ A#app.is_escript =/= true],
EscriptItems = [{escript,
A#app.active_dir,
emit(incl_cond, A#app.incl_cond, undefined, InclDefs)}
@@ -895,7 +895,7 @@ spec_escripts(#sys{apps = Apps}, ErtsBin, BinFiles) ->
if
Name =:= ?MISSING_APP_NAME ->
false;
- not IsEscript ->
+ IsEscript =/= true ->
false;
IsIncl; IsPre ->
{true, do_spec_escript(File, ErtsBin, BinFiles)};
@@ -957,7 +957,7 @@ spec_lib_files(#sys{apps = Apps} = Sys) ->
if
Name =:= ?MISSING_APP_NAME ->
false;
- IsEscript ->
+ IsEscript =/= false ->
false;
IsIncl; IsPre ->
true;
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index f2b63f78f0..e279be82a8 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -64,6 +64,7 @@ all() ->
create_standalone,
create_standalone_beam,
create_standalone_app,
+ create_standalone_app_clash,
create_multiple_standalone,
create_old_target,
eval_target_spec,
@@ -75,6 +76,7 @@ all() ->
get_sys,
set_app_and_undo,
set_apps_and_undo,
+ set_apps_inlined,
set_sys_and_undo,
load_config_and_undo,
load_config_escript_path,
@@ -798,13 +800,6 @@ create_standalone_beam(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate standalone system with inlined archived application
-%% BUG: see OTP-9792, 25)
-%% Problem related to change of #app.name from "*escript* someapp" to
-%% just "someapp", since there is a someapp.app in the
-%% archive. "someapp" does not have an incl_cond=include statement,
-%% and it is not derived so the it is not included in the target
-%% system.
-create_standalone_app(_Config) -> {skip, "Known bug: escript with inlined archive is not handled correctly by reltool"};
create_standalone_app(Config) ->
%% Create archive
DataDir = ?config(data_dir,Config),
@@ -854,6 +849,43 @@ create_standalone_app(Config) ->
ok.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate standalone system with inlined archived application
+%% Check that the inlined app can not be explicitly configured
+
+create_standalone_app_clash(Config) ->
+ %% Create archive
+ DataDir = ?config(data_dir,Config),
+ EscriptDir = filename:join(DataDir,escript),
+ {ok,{_Archive,Bin}} = zip:create("someapp-1.0.ez",["someapp-1.0"],
+ [memory,
+ {cwd,EscriptDir},
+ {compress,all},
+ {uncompress,[".beam",".app"]}]),
+
+ %% Create the escript
+ EscriptName = "someapp.escript",
+ Escript = filename:join(?WORK_DIR,EscriptName),
+ ok = escript:create(Escript,[shebang,
+ {emu_args,"-escript main mymod"},
+ {archive,Bin}]),
+ ok = file:change_mode(Escript,8#00744),
+
+ %% Configure the server
+ Sys =
+ {sys,
+ [
+ {lib_dirs, []},
+ {escript, Escript, [{incl_cond, include}]},
+ {profile, standalone},
+ {app, someapp, [{incl_cond,include}]}
+ ]},
+
+ ?msym({error,"someapp: Application name clash. Escript "++_},
+ reltool:get_target_spec([{config,Sys}])),
+
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate standalone system with multiple escripts
@@ -1266,6 +1298,76 @@ set_apps_and_undo(Config) ->
ok.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Test that escript can be configured, but not its inlined applications
+set_apps_inlined(Config) ->
+ %% Create archive
+ DataDir = ?config(data_dir,Config),
+ EscriptDir = filename:join(DataDir,escript),
+ {ok,{_Archive,Bin}} = zip:create("someapp-1.0.ez",["someapp-1.0"],
+ [memory,
+ {cwd,EscriptDir},
+ {compress,all},
+ {uncompress,[".beam",".app"]}]),
+
+ %% Create the escript
+ EscriptName = "someapp.escript",
+ Escript = filename:join(?WORK_DIR,EscriptName),
+ ok = escript:create(Escript,[shebang,
+ {emu_args,"-escript main mymod"},
+ {archive,Bin}]),
+ ok = file:change_mode(Escript,8#00744),
+
+ %% Configure the server
+ Sys = {sys,[{incl_cond, exclude},
+ {escript,Escript,[]},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]}]},
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
+ ?msym({ok,[]},reltool_server:get_status(Pid)),
+
+ %% Get app and mod
+ {ok,EApp} = ?msym({ok,_}, reltool_server:get_app(Pid,'*escript* someapp')),
+ {ok,Someapp} = ?msym({ok,_}, reltool_server:get_app(Pid,someapp)),
+ ?m(undefined, EApp#app.incl_cond),
+ ?m(undefined, Someapp#app.incl_cond),
+ ?m(false, Someapp#app.is_included),
+ ?m(false, Someapp#app.is_pre_included),
+
+ %% Include escript
+ EApp1 = EApp#app{incl_cond=include},
+ ?m({ok,[]}, reltool_server:set_apps(Pid,[EApp1])),
+ ExpectedEApp = EApp1#app{is_included=true,is_pre_included=true},
+ ?m({ok,ExpectedEApp}, reltool_server:get_app(Pid,'*escript* someapp')),
+ {ok,Someapp1} = ?msym({ok,_}, reltool_server:get_app(Pid,someapp)),
+ ?m(include, Someapp1#app.incl_cond),
+ ?m(true, Someapp1#app.is_included),
+ ?m(true, Someapp1#app.is_pre_included),
+
+ %% Check that inlined app can not be configured
+ Someapp2 = Someapp1#app{incl_cond=exclude},
+ ?msym({error,
+ "Application someapp is inlined in '*escript* someapp'. "
+ "Can not change configuration for an inlined application."},
+ reltool_server:set_apps(Pid,[Someapp2])),
+ ?m({ok,Someapp1}, reltool_server:get_app(Pid,someapp)),
+
+ %% Exclude escript
+ {ok,EApp2} = ?msym({ok,_}, reltool_server:get_app(Pid,'*escript* someapp')),
+ EApp3 = EApp2#app{incl_cond=exclude},
+ ?m({ok,[]}, reltool_server:set_apps(Pid,[EApp3])),
+ ExpectedEApp3 = EApp3#app{is_included=false,is_pre_included=false},
+ ?m({ok,ExpectedEApp3}, reltool_server:get_app(Pid,'*escript* someapp')),
+ {ok,Someapp3} = ?msym({ok,_}, reltool_server:get_app(Pid,someapp)),
+ ?m(exclude, Someapp3#app.incl_cond),
+ ?m(false, Someapp3#app.is_included),
+ ?m(false, Someapp3#app.is_pre_included),
+
+ ?m(ok, reltool:stop(Pid)),
+ ok.
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
set_sys_and_undo(Config) ->
Sys1 = {sys,[{incl_cond, exclude},
--
cgit v1.2.3
From c714eff72c1bd15f8831cffe7256f3dfd8faf806 Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Thu, 23 Feb 2012 11:26:27 +0100
Subject: [reltool] Fix rollback and undo
OTP-9794
Backup old configuration before starting re-configuration so rollback
is possible if configuration fails.
Store last configuration including derivates so undo does no longer
need to refresh and analyse everything from disk.
---
lib/reltool/src/reltool.hrl | 4 +-
lib/reltool/src/reltool_server.erl | 266 ++++++++++++++----------------
lib/reltool/src/reltool_sys_win.erl | 23 +--
lib/reltool/test/reltool_server_SUITE.erl | 60 +++++--
4 files changed, 181 insertions(+), 172 deletions(-)
diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl
index 0a90c42ce2..781c3f6d2c 100644
--- a/lib/reltool/src/reltool.hrl
+++ b/lib/reltool/src/reltool.hrl
@@ -130,7 +130,9 @@
trap_exit :: boolean(),
app_tab :: ets:tab(),
mod_tab :: ets:tab(),
- mod_used_by_tab :: ets:tab()
+ mod_used_by_tab :: ets:tab(),
+ old_app_tab :: ets:tab(),
+ old_mod_tab :: ets:tab()
}).
-record(mod,
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index f5abaf0957..e9b26b26da 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -132,33 +132,32 @@ init(Options) ->
end.
do_init(Options) ->
- {S, Status} = parse_options(Options),
- #state{parent_pid = ParentPid, common = C} = S,
-
- %% process_flag(trap_exit, (S#state.common)#common.trap_exit),
- proc_lib:init_ack(ParentPid, {ok, self(), C}),
- {S2, Apps, Status2} = refresh(S, true, Status),
- Status3 = analyse(S2, Apps, Status2),
- case Status3 of
- {ok, _Warnings} -> % BUGBUG: handle warnings
- loop(S2#state{old_sys = S2#state.sys,
- status = Status3,
- old_status = {ok, []}});
- {error, Reason} ->
- exit(Reason)
- end.
-
-parse_options(Opts) ->
AppTab = ets:new(reltool_apps, [public, ordered_set, {keypos, #app.name}]),
ModTab = ets:new(reltool_mods, [public, ordered_set, {keypos, #mod.name}]),
+ OldAppTab = ets:new(reltool_apps, [public, ordered_set, {keypos, #app.name}]),
+ OldModTab = ets:new(reltool_mods, [public, ordered_set, {keypos, #mod.name}]),
ModUsesTab = ets:new(reltool_mod_uses, [public, bag, {keypos, 1}]),
+ InitialC = #common{app_tab = AppTab,
+ mod_tab = ModTab,
+ old_app_tab = OldAppTab,
+ old_mod_tab = OldModTab,
+ mod_used_by_tab = ModUsesTab},
+
+ {S, Status} = parse_options(InitialC, Options),
+ %%! Check status before returning ok?
+
+ proc_lib:init_ack(S#state.parent_pid, {ok, self(), S#state.common}),
+
+ %% This will do exit if it fails
+ {S2, _Status2} = refresh_and_analyse_no_rollback(S, Status),
+ %%! what to do about warnings?
+ loop(S2).
+
+parse_options(C, Opts) ->
Sys = default_sys(),
- C2 = #common{sys_debug = [],
- wx_debug = 0,
- trap_exit = true,
- app_tab = AppTab,
- mod_tab = ModTab,
- mod_used_by_tab = ModUsesTab},
+ C2 = C#common{sys_debug = [],
+ wx_debug = 0,
+ trap_exit = true},
S = #state{options = Opts},
parse_options(Opts, S, C2, Sys, {ok, []}).
@@ -246,54 +245,31 @@ loop(#state{common = C, sys = Sys} = S) ->
reltool_utils:reply(ReplyTo, Ref, Reply),
?MODULE:loop(S);
{call, ReplyTo, Ref, {load_config, SysConfig}} ->
- {S2, Reply} = do_load_config(S, SysConfig),
- reltool_utils:reply(ReplyTo, Ref, Reply),
- ?MODULE:loop(S2);
+ {S2, Status} = do_load_config(S, SysConfig),
+ {S3, Status2} = refresh_and_analyse(S, S2, Status),
+ reltool_utils:reply(ReplyTo, Ref, Status2),
+ ?MODULE:loop(S3);
{call, ReplyTo, Ref, {save_config, Filename, InclDef, InclDeriv}} ->
Reply = do_save_config(S, Filename, InclDef, InclDeriv),
reltool_utils:reply(ReplyTo, Ref, Reply),
?MODULE:loop(S);
{call, ReplyTo, Ref, reset_config} ->
- {S2, Status} = parse_options(S#state.options),
- {S4, Apps, Status2} = refresh(S2, true, Status),
- Status3 = analyse(S4, Apps, Status2),
- S5 =
- case Status3 of
- {ok, _Warnings} ->
- S4#state{old_sys = Sys,
- status = Status3,
- old_status = S#state.status};
- {error, _} ->
- %% Keep old state
- S
- end,
- reltool_utils:reply(ReplyTo, Ref, Status3),
- ?MODULE:loop(S5);
- {call, ReplyTo, Ref, undo_config} ->
- OldSys = S#state.old_sys,
- S2 = S#state{sys = OldSys,
- old_sys = Sys},
- %%! Possibly skip old_status here, since we do all job again!
- %%! If so, consider if it is correct to use Force or not -
- %%! since warnings from refresh_app will not re-appear here
- %%! in undo if Force==false.
- Force = true,
-% (OldSys#sys.root_dir =/= Sys#sys.root_dir) orelse
-% (OldSys#sys.lib_dirs =/= Sys#sys.lib_dirs) orelse
-% (OldSys#sys.escripts =/= Sys#sys.escripts),
-
- {S3, Apps, Status} = refresh(S2, Force, S#state.old_status),
- Status2 = analyse(S3, Apps, Status),
- S4 =
- case Status2 of
- {ok, _Warnings} -> % BUGBUG: handle warnings
- S3#state{status = Status2, old_status = S#state.status};
- {error, _} ->
- %% Keep old state
- S
- end,
+ {S2, Status} = parse_options(C, S#state.options),
+ {S3, Status2} = refresh_and_analyse(S, S2, Status),
reltool_utils:reply(ReplyTo, Ref, Status2),
- ?MODULE:loop(S4);
+ ?MODULE:loop(S3);
+ {call, ReplyTo, Ref, undo_config} ->
+ C2 = C#common{app_tab = C#common.old_app_tab,
+ old_app_tab = C#common.app_tab,
+ mod_tab = C#common.old_mod_tab,
+ old_mod_tab = C#common.mod_tab},
+ S2 = S#state{common = C2,
+ sys = S#state.old_sys,
+ old_sys = Sys,
+ status = S#state.old_status,
+ old_status = S#state.status},
+ reltool_utils:reply(ReplyTo, Ref, ok),
+ ?MODULE:loop(S2);
{call, ReplyTo, Ref, {get_rel, RelName}} ->
Sys = S#state.sys,
Reply =
@@ -341,18 +317,15 @@ loop(#state{common = C, sys = Sys} = S) ->
reltool_utils:reply(ReplyTo, Ref, Reply),
?MODULE:loop(S);
{call, ReplyTo, Ref, {set_app, App}} ->
- {S2, Status} = do_set_apps(S, [App], {ok, []}),
- {S3, Reply} =
- case Status of
+ {S2, Status} = do_set_apps(S, [App]),
+ {S3, Status2} = refresh_and_analyse(S, S2, Status),
+ Reply =
+ case Status2 of
{ok, Warnings} ->
[App2] = ets:lookup(C#common.app_tab,App#app.name),
- {S2#state{old_sys=Sys,
- status=Status,
- old_status=S#state.status},
- {ok, App2, Warnings}};
+ {ok, App2, Warnings};
{error, _} ->
- %% Keep old state
- {S, Status}
+ Status2
end,
reltool_utils:reply(ReplyTo, Ref, Reply),
?MODULE:loop(S3);
@@ -393,42 +366,18 @@ loop(#state{common = C, sys = Sys} = S) ->
reltool_utils:reply(ReplyTo, Ref, {ok, AppNames}),
?MODULE:loop(S);
{call, ReplyTo, Ref, {set_apps, Apps}} ->
- {S2, Status} = do_set_apps(S, Apps, {ok, []}),
- S3 =
- case Status of
- {ok, _Warnings} ->
- S2#state{old_sys = Sys,
- status=Status,
- old_status=S#state.status};
- {error, _} ->
- %% Keep old state
- S
- end,
- reltool_utils:reply(ReplyTo, Ref, Status),
+ {S2, Status} = do_set_apps(S, Apps),
+ {S3, Status2} = refresh_and_analyse(S, S2, Status),
+ reltool_utils:reply(ReplyTo, Ref, Status2),
?MODULE:loop(S3);
{call, ReplyTo, Ref, get_sys} ->
reltool_utils:reply(ReplyTo, Ref, {ok, Sys#sys{apps = undefined}}),
?MODULE:loop(S);
{call, ReplyTo, Ref, {set_sys, Sys2}} ->
- S2 = S#state{sys = Sys2#sys{apps = Sys#sys.apps}},
- Force = true,
-% (Sys2#sys.root_dir =/= Sys#sys.root_dir) orelse
-% (Sys2#sys.lib_dirs =/= Sys#sys.lib_dirs) orelse
-% (Sys2#sys.escripts =/= Sys#sys.escripts),
- {S3, Apps, Status} = refresh(S2, Force, {ok, []}),
- Status2 = analyse(S3, Apps, Status),
- S4 =
- case Status2 of
- {ok, _Warnings} -> % BUGBUG: handle warnings
- S3#state{old_sys = Sys,
- status = Status2,
- old_status = S#state.status};
- {error, _} ->
- %% Keep old state
- S
- end,
- reltool_utils:reply(ReplyTo, Ref, Status2),
- ?MODULE:loop(S4);
+ S2 = S#state{sys = Sys2#sys{apps = Sys#sys.apps}},
+ {S3, Status} = refresh_and_analyse(S, S2, {ok,[]}),
+ reltool_utils:reply(ReplyTo, Ref, Status),
+ ?MODULE:loop(S3);
{call, ReplyTo, Ref, get_status} ->
reltool_utils:reply(ReplyTo, Ref, S#state.status),
?MODULE:loop(S);
@@ -463,18 +412,12 @@ loop(#state{common = C, sys = Sys} = S) ->
?MODULE:loop(S)
end.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-do_set_apps(#state{sys = Sys} = S, ChangedApps, Status) ->
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+do_set_apps(#state{sys = Sys} = S, ChangedApps) ->
%% Create new list of configured applications
- {SysApps,Status2} = app_update_config(ChangedApps, Sys#sys.apps, Status),
- Sys2 = Sys#sys{apps = SysApps},
-
- %% Refresh from filesystem and analyse dependencies
- {S2, Apps, Status3} = refresh(S#state{sys = Sys2}, true, Status2),
- Status4 = analyse(S2, Apps, Status3),
-
- {S2, Status4}.
+ {SysApps,Status} = app_update_config(ChangedApps, Sys#sys.apps, {ok,[]}),
+ {S#state{sys = Sys#sys{apps = SysApps}}, Status}.
%% Re-create the #sys.apps list by
%% 1) taking configurable fields from the changed #app records and
@@ -577,10 +520,6 @@ mod_set_config_only(ConfigMods) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
analyse(#state{common=C, sys=Sys}, Apps, Status) ->
- ets:delete_all_objects(C#common.app_tab),
- ets:delete_all_objects(C#common.mod_tab),
- ets:delete_all_objects(C#common.mod_used_by_tab),
-
%% Create a list of {RelName,AppName}, one element for each
%% AppName that needs to be included for the given release.
{RelApps, Status2} = apps_in_rels(Sys#sys.rels, Apps, Status),
@@ -1373,25 +1312,7 @@ do_save_config(S, Filename, InclDef, InclDeriv) ->
do_load_config(S, SysConfig) ->
{NewSys, Status} = read_config(default_sys(), SysConfig, {ok, []}),
- case Status of
- {ok, _Warnings} ->
- {S2, Apps, Status2} = refresh(S#state{sys=NewSys}, true, Status),
- Status3 = analyse(S2, Apps, Status2),
- S3 =
- case Status3 of
- {ok, _Warnings2} ->
- S2#state{old_sys = S#state.sys,
- status = Status3,
- old_status = S#state.status};
- {error, _} ->
- %% Keep old state
- S
- end,
- {S3, Status3};
- {error, _} ->
- %% Keep old state
- {S, Status}
- end.
+ {S#state{sys = NewSys}, Status}.
read_config(OldSys, Filename, Status) when is_list(Filename) ->
case file:consult(Filename) of
@@ -1717,7 +1638,7 @@ default_escript_app(File) ->
%% Apps is a list of #app records - sorted on #app.name - containing
%% only the apps that have specific configuration (e.g. in the config
%% file)
-refresh(#state{sys=Sys} = S, Force, Status) ->
+refresh(#state{sys=Sys} = S, Status) ->
RootDir = filename:absname(Sys#sys.root_dir),
LibDirs = [filename:absname(D) || D <- Sys#sys.lib_dirs],
Escripts = [filename:absname(E) || E <- Sys#sys.escripts],
@@ -1738,7 +1659,7 @@ refresh(#state{sys=Sys} = S, Force, Status) ->
%% Then find all modules and their dependencies and set user
%% configuration per module if it exists.
{RefreshedApps, Status4} = refresh_apps(Sys#sys.apps, AllApps, [],
- Force, Status3),
+ true, Status3),
%% Make sure erts exists in app list and has a version (or warn)
{PatchedApps, Status5} = patch_erts_version(RootDir, RefreshedApps, Status4),
@@ -2143,6 +2064,71 @@ sys_all_apps(C,Sys) ->
all_apps(C) ->
ets:match_object(C#common.app_tab,'_').
+refresh_and_analyse_no_rollback(#state{common=C} = S, {ok,_} = Status) ->
+ case refresh(S, Status) of
+ {S2, Apps, {ok, _}=Status2} ->
+ case analyse(S2, Apps, Status2) of
+ {ok, _} = Status3 ->
+ %% Set old_xxx is equal to xxx
+ FakeBackup = {ets:tab2list(C#common.app_tab),
+ ets:tab2list(C#common.mod_tab)},
+ save_old(S2, S2, FakeBackup, Status3);
+ {error,Reason} ->
+ exit(Reason)
+ end;
+ {_,_,{error,Reason}} ->
+ exit(Reason)
+ end;
+refresh_and_analyse_no_rollback(_,{error,Reason}) ->
+ exit(Reason).
+
+refresh_and_analyse(OldS, S, {ok,_}=Status) ->
+ case refresh(S, Status) of
+ {S2, Apps, {ok,_}=Status2} ->
+ %% Analyse will write to app_tab and mod_tab, so we first
+ %% backup these tables and clear them
+ Backup = backup(OldS),
+ case analyse(S2, Apps, Status2) of
+ {ok, _} = Status3 ->
+ save_old(OldS, S2, Backup, Status3);
+ Status3 ->
+ restore(Backup,OldS),
+ {OldS,Status3}
+ end;
+ {_, _, Status2} ->
+ {OldS, Status2}
+ end;
+refresh_and_analyse(OldS, _S, Status) ->
+ {OldS,Status}.
+
+
+backup(#state{common=C}) ->
+ Apps = ets:tab2list(C#common.app_tab),
+ Mods = ets:tab2list(C#common.mod_tab),
+ ets:delete_all_objects(C#common.app_tab),
+ ets:delete_all_objects(C#common.mod_tab),
+ ets:delete_all_objects(C#common.mod_used_by_tab), %tmp tab, no backup needed
+ {Apps,Mods}.
+
+restore({Apps,Mods}, #state{common=C}) ->
+ insert_all(C#common.app_tab,Apps),
+ insert_all(C#common.mod_tab,Mods).
+
+save_old(#state{status=OldStatus,sys=OldSys},#state{common=C}=NewS,
+ {OldApps,OldMods},NewStatus) ->
+ ets:delete_all_objects(C#common.old_app_tab),
+ ets:delete_all_objects(C#common.old_mod_tab),
+ insert_all(C#common.old_app_tab,OldApps),
+ insert_all(C#common.old_mod_tab,OldMods),
+ {NewS#state{old_sys=OldSys,
+ old_status=OldStatus,
+ status=NewStatus},
+ NewStatus}.
+
+insert_all(Tab,Items) ->
+ lists:foreach(fun(Item) -> ets:insert(Tab,Item) end, Items).
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% sys callbacks
diff --git a/lib/reltool/src/reltool_sys_win.erl b/lib/reltool/src/reltool_sys_win.erl
index c49641d6a3..1638acb145 100644
--- a/lib/reltool/src/reltool_sys_win.erl
+++ b/lib/reltool/src/reltool_sys_win.erl
@@ -1290,15 +1290,7 @@ reset_config(#state{status_bar = Bar} = S) ->
undo_config(#state{status_bar = Bar} = S) ->
wxStatusBar:setStatusText(Bar, "Processing libraries..."),
- case reltool_server:undo_config(S#state.server_pid) of
- {ok, []} ->
- ok;
- {ok, Warnings} ->
- Msg = lists:flatten([[W, $\n] || W <- Warnings]),
- display_message(Msg, ?wxICON_WARNING);
- {error, Reason} ->
- display_message(Reason, ?wxICON_ERROR)
- end,
+ ok = reltool_server:undo_config(S#state.server_pid),
refresh(S).
load_config(#state{status_bar = Bar, config_file = OldFile} = S) ->
@@ -1452,17 +1444,8 @@ undo_dialog(S, Warnings) ->
?wxID_OK ->
true;
?wxID_CANCEL ->
- case reltool_server:undo_config(S#state.server_pid) of
- {ok, _} ->
- false;
- {error, Reason} ->
- Msg = "FATAL - undo failed:\n\n" ++
- Reason ++
- "\n\nTerminating...",
- display_message(Msg, ?wxICON_ERROR),
- io:format("~p(~p): ~s\n", [?MODULE, ?LINE, Reason]),
- exit(Reason)
- end
+ ok = reltool_server:undo_config(S#state.server_pid),
+ false
end.
display_message(Message, Icon) ->
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index e279be82a8..2588c0829f 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -79,6 +79,7 @@ all() ->
set_apps_inlined,
set_sys_and_undo,
load_config_and_undo,
+ load_config_fail,
load_config_escript_path,
load_config_same_escript_source,
load_config_same_escript_beam,
@@ -1235,13 +1236,13 @@ set_app_and_undo(Config) ->
reltool_server:get_mod(Pid,cover)),
%% Undo
- ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:undo_config(Pid)),
+ ?m(ok, reltool_server:undo_config(Pid)),
?m({ok,Tools}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover}, reltool_server:get_mod(Pid,cover)),
- ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_|_]}, reltool_server:get_status(Pid)),
%% Undo again, to check that it toggles
- ?msym({ok,["a: Cannot parse app file"++_|_]}, reltool_server:undo_config(Pid)),
+ ?msym(ok, reltool_server:undo_config(Pid)),
?m({ok,ToolsNoCover}, reltool_server:get_app(Pid,tools)),
?m({ok,NoIncludeCover}, reltool_server:get_mod(Pid,cover)),
?msym({ok,["a: Cannot parse app file"++_|_]}, reltool_server:get_status(Pid)),
@@ -1283,13 +1284,13 @@ set_apps_and_undo(Config) ->
reltool_server:get_mod(Pid,cover)),
%% Undo
- ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:undo_config(Pid)),
+ ?m(ok, reltool_server:undo_config(Pid)),
?m({ok,Tools}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover}, reltool_server:get_mod(Pid,cover)),
?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
%% Undo again, to check that it toggles
- ?msym({ok,["a: Cannot parse app file"++_|_]}, reltool_server:undo_config(Pid)),
+ ?m(ok, reltool_server:undo_config(Pid)),
?m({ok,NoTools}, reltool_server:get_app(Pid,tools)),
?m({ok,NoIncludeCover}, reltool_server:get_mod(Pid,cover)),
?msym({ok,["a: Cannot parse app file"++_|_]}, reltool_server:get_status(Pid)),
@@ -1391,12 +1392,12 @@ set_sys_and_undo(Config) ->
?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
%% Undo
- ?m({ok,[]}, reltool_server:undo_config(Pid)),
+ ?m(ok, reltool_server:undo_config(Pid)),
?m({ok,SysRec}, reltool_server:get_sys(Pid)),
?m({ok,[]}, reltool_server:get_status(Pid)),
%% Undo again, to check that it toggles
- ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:undo_config(Pid)),
+ ?m(ok,reltool_server:undo_config(Pid)),
?m({ok,NewSysRec}, reltool_server:get_sys(Pid)),
?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
@@ -1448,13 +1449,13 @@ load_config_and_undo(Config) ->
reltool_server:get_mod(Pid,cover)),
%% Undo
- ?m({ok,[]}, reltool_server:undo_config(Pid)),
+ ?m(ok, reltool_server:undo_config(Pid)),
?m({ok,Tools1}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover1}, reltool_server:get_mod(Pid,cover)),
?m({ok,[]}, reltool_server:get_status(Pid)),
%% Undo again, to check that it toggles
- ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:undo_config(Pid)),
+ ?m(ok, reltool_server:undo_config(Pid)),
?m({ok,Tools2}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover2}, reltool_server:get_mod(Pid,cover)),
?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
@@ -1463,6 +1464,43 @@ load_config_and_undo(Config) ->
ok.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Test that load_config is properly rolled back if it fails
+load_config_fail(_Config) ->
+ Sys1 = {sys,[{incl_cond, exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,tools,[{incl_cond,include}]}]},
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
+ ?m({ok, Sys1}, reltool:get_config(Pid)),
+ ?m({ok,[]}, reltool_server:get_status(Pid)),
+
+ %% Get app and mod
+ {ok,Tools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
+
+ %% Try to load a config with a faulty rel statement (includes a
+ %% non-existing application)
+ Sys2 = {sys,[{incl_cond, exclude},
+ {boot_rel, "faulty_rel"},
+ {rel, "faulty_rel", "1.0", [kernel, sasl, stdlib, xxx]},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]}]},
+ ?msym({error,"Release faulty_rel uses non existing application xxx"},
+ reltool_server:load_config(Pid,Sys2)),
+
+ %% Check that a rollback is done to the old configuration
+ ?m({ok, Sys1}, reltool:get_config(Pid,false,false)),
+
+ %% and that tools is not changed (i.e. that the new configuration
+ %% is not applied)
+ ?m({ok,Tools}, reltool_server:get_app(Pid,tools)),
+
+ ?m(ok, reltool:stop(Pid)),
+ ok.
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Load config with escript
@@ -1673,13 +1711,13 @@ reset_config_and_undo(Config) ->
?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
%% Undo
- ?m({ok,[]}, reltool_server:undo_config(Pid)),
+ ?m(ok, reltool_server:undo_config(Pid)),
?m({ok,Tools2}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover2}, reltool_server:get_mod(Pid,cover)),
?m({ok,[]}, reltool_server:get_status(Pid)),
%% Undo again, to check that it toggles
- ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:undo_config(Pid)),
+ ?m(ok, reltool_server:undo_config(Pid)),
?m({ok,Tools1}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover1}, reltool_server:get_mod(Pid,cover)),
?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
--
cgit v1.2.3
From 537773c0e6969cb89f92aec0244ba29b07ec66ea Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Fri, 24 Feb 2012 15:52:34 +0100
Subject: [reltool] Improve error handling
OTP-9794
Stopping configuration (throw/catch) at first error instead of
continuing through all steps and then returning the error at the
end.
Start of reltool_server will no longer succeed if the configuration
causes an error.
reltool:get_status can only return {error,Reason} in the case where
the reltool_server has terminated. In all other cases it will return
{ok,Warnings}.
Bug fix in this commit:
* warnings are no longer duplicated in pop-up or return from reltool_server
---
lib/reltool/src/reltool.erl | 6 +-
lib/reltool/src/reltool_server.erl | 673 ++++++++++++------------------
lib/reltool/src/reltool_sys_win.erl | 73 ++--
lib/reltool/src/reltool_utils.erl | 35 +-
lib/reltool/test/reltool_server_SUITE.erl | 44 +-
5 files changed, 334 insertions(+), 497 deletions(-)
diff --git a/lib/reltool/src/reltool.erl b/lib/reltool/src/reltool.erl
index a2b1c9468c..2bdf222aa0 100644
--- a/lib/reltool/src/reltool.erl
+++ b/lib/reltool/src/reltool.erl
@@ -59,17 +59,17 @@ start_link(Options) when is_list(Options) ->
{ok, _WinPid} = OK ->
OK;
{error, Reason} ->
- {error, lists:flatten(io_lib:format("~p", [Reason]))}
+ {error, Reason}
end.
%% Start server process with options
-spec start_server(options()) -> {ok, server_pid()} | {error, reason()}.
start_server(Options) ->
case reltool_server:start_link(Options) of
- {ok, ServerPid, _Common} ->
+ {ok, ServerPid, _Common, _Sys} ->
{ok, ServerPid};
{error, Reason} ->
- {error, lists:flatten(io_lib:format("~p", [Reason]))}
+ {error, Reason}
end.
%% Start server process with options
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index e9b26b26da..4c22898559 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -123,10 +123,12 @@ gen_spec(Pid) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Server
-init(Options) ->
+init([{parent,Parent}|_] = Options) ->
try
do_init(Options)
catch
+ throw:{error,Reason} ->
+ proc_lib:init_ack(Parent,{error,Reason});
error:Reason ->
exit({Reason, erlang:get_stacktrace()})
end.
@@ -143,15 +145,16 @@ do_init(Options) ->
old_mod_tab = OldModTab,
mod_used_by_tab = ModUsesTab},
- {S, Status} = parse_options(InitialC, Options),
- %%! Check status before returning ok?
-
- proc_lib:init_ack(S#state.parent_pid, {ok, self(), S#state.common}),
-
- %% This will do exit if it fails
- {S2, _Status2} = refresh_and_analyse_no_rollback(S, Status),
- %%! what to do about warnings?
- loop(S2).
+ S = parse_options(InitialC, Options),
+ {S2, Apps, Status2} = refresh(S),
+ Status3 = analyse(S2, Apps, Status2),
+ %% Set old_xxx equal to xxx to allow undo=nop
+ FakeBackup = {ets:tab2list((S2#state.common)#common.app_tab),
+ ets:tab2list((S2#state.common)#common.mod_tab)},
+ S3 = save_old(S2, S2, FakeBackup, Status3),
+ #state{parent_pid = Parent, sys=Sys, common=C} = S3,
+ proc_lib:init_ack(Parent, {ok, self(), C, Sys#sys{apps=undefined}}),
+ loop(S3).
parse_options(C, Opts) ->
Sys = default_sys(),
@@ -159,7 +162,7 @@ parse_options(C, Opts) ->
wx_debug = 0,
trap_exit = true},
S = #state{options = Opts},
- parse_options(Opts, S, C2, Sys, {ok, []}).
+ parse_options(Opts, S, C2, Sys).
default_sys() ->
#sys{root_dir = reltool_utils:root_dir(),
@@ -200,36 +203,29 @@ default_sys() ->
dec_re(Key, Regexps, Old) ->
reltool_utils:decode_regexps(Key, Regexps, Old).
-parse_options([{Key, Val} | KeyVals], S, C, Sys, Status) ->
+parse_options([{Key, Val} | KeyVals], S, C, Sys) ->
case Key of
parent ->
- parse_options(KeyVals, S#state{parent_pid = Val}, C, Sys, Status);
+ parse_options(KeyVals, S#state{parent_pid = Val}, C, Sys);
sys_debug ->
- parse_options(KeyVals, S, C#common{sys_debug = Val}, Sys, Status);
+ parse_options(KeyVals, S, C#common{sys_debug = Val}, Sys);
wx_debug ->
- parse_options(KeyVals, S, C#common{wx_debug = Val}, Sys, Status);
+ parse_options(KeyVals, S, C#common{wx_debug = Val}, Sys);
trap_exit ->
- parse_options(KeyVals, S, C#common{trap_exit = Val}, Sys, Status);
+ parse_options(KeyVals, S, C#common{trap_exit = Val}, Sys);
config ->
- {Sys2, Status2} = read_config(Sys, Val, Status),
- parse_options(KeyVals, S, C, Sys2, Status2);
+ Sys2 = read_config(Sys, Val),
+ parse_options(KeyVals, S, C, Sys2);
sys ->
- {Sys2, Status2} = read_config(Sys, {sys, Val}, Status),
- parse_options(KeyVals, S, C, Sys2, Status2);
+ Sys2 = read_config(Sys, {sys, Val}),
+ parse_options(KeyVals, S, C, Sys2);
_ ->
- Text = lists:flatten(io_lib:format("~p", [{Key, Val}])),
- Status2 =
- reltool_utils:return_first_error(Status,
- "Illegal option: " ++ Text),
- parse_options(KeyVals, S, C, Sys, Status2)
+ reltool_utils:throw_error("Illegal option: ~p", [{Key, Val}])
end;
-parse_options([], S, C, Sys, Status) ->
- {S#state{common = C, sys = Sys}, Status};
-parse_options(KeyVals, S, C, Sys, Status) ->
- Text = lists:flatten(io_lib:format("~p", [KeyVals])),
- Status2 = reltool_utils:return_first_error(Status,
- "Illegal options: " ++ Text),
- {S#state{common = C, sys = Sys}, Status2}.
+parse_options([], S, C, Sys) ->
+ S#state{common = C, sys = Sys};
+parse_options(KeyVals, _S, _C, _Sys) ->
+ reltool_utils:throw_error("Illegal option: ~p", [KeyVals]).
loop(#state{common = C, sys = Sys} = S) ->
receive
@@ -245,8 +241,8 @@ loop(#state{common = C, sys = Sys} = S) ->
reltool_utils:reply(ReplyTo, Ref, Reply),
?MODULE:loop(S);
{call, ReplyTo, Ref, {load_config, SysConfig}} ->
- {S2, Status} = do_load_config(S, SysConfig),
- {S3, Status2} = refresh_and_analyse(S, S2, Status),
+ Fun = fun() -> do_load_config(S, SysConfig) end,
+ {S3, Status2} = config_and_refresh(S, Fun),
reltool_utils:reply(ReplyTo, Ref, Status2),
?MODULE:loop(S3);
{call, ReplyTo, Ref, {save_config, Filename, InclDef, InclDeriv}} ->
@@ -254,8 +250,8 @@ loop(#state{common = C, sys = Sys} = S) ->
reltool_utils:reply(ReplyTo, Ref, Reply),
?MODULE:loop(S);
{call, ReplyTo, Ref, reset_config} ->
- {S2, Status} = parse_options(C, S#state.options),
- {S3, Status2} = refresh_and_analyse(S, S2, Status),
+ Fun = fun() -> parse_options(C, S#state.options) end,
+ {S3, Status2} = config_and_refresh(S, Fun),
reltool_utils:reply(ReplyTo, Ref, Status2),
?MODULE:loop(S3);
{call, ReplyTo, Ref, undo_config} ->
@@ -317,8 +313,8 @@ loop(#state{common = C, sys = Sys} = S) ->
reltool_utils:reply(ReplyTo, Ref, Reply),
?MODULE:loop(S);
{call, ReplyTo, Ref, {set_app, App}} ->
- {S2, Status} = do_set_apps(S, [App]),
- {S3, Status2} = refresh_and_analyse(S, S2, Status),
+ Fun = fun() -> do_set_apps(S, [App]) end,
+ {S3, Status2} = config_and_refresh(S, Fun),
Reply =
case Status2 of
{ok, Warnings} ->
@@ -366,16 +362,16 @@ loop(#state{common = C, sys = Sys} = S) ->
reltool_utils:reply(ReplyTo, Ref, {ok, AppNames}),
?MODULE:loop(S);
{call, ReplyTo, Ref, {set_apps, Apps}} ->
- {S2, Status} = do_set_apps(S, Apps),
- {S3, Status2} = refresh_and_analyse(S, S2, Status),
+ Fun = fun() -> do_set_apps(S, Apps) end,
+ {S3, Status2} = config_and_refresh(S, Fun),
reltool_utils:reply(ReplyTo, Ref, Status2),
?MODULE:loop(S3);
{call, ReplyTo, Ref, get_sys} ->
reltool_utils:reply(ReplyTo, Ref, {ok, Sys#sys{apps = undefined}}),
?MODULE:loop(S);
{call, ReplyTo, Ref, {set_sys, Sys2}} ->
- S2 = S#state{sys = Sys2#sys{apps = Sys#sys.apps}},
- {S3, Status} = refresh_and_analyse(S, S2, {ok,[]}),
+ Fun = fun() -> S#state{sys = Sys2#sys{apps = Sys#sys.apps}} end,
+ {S3, Status} = config_and_refresh(S, Fun),
reltool_utils:reply(ReplyTo, Ref, Status),
?MODULE:loop(S3);
{call, ReplyTo, Ref, get_status} ->
@@ -416,24 +412,19 @@ loop(#state{common = C, sys = Sys} = S) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
do_set_apps(#state{sys = Sys} = S, ChangedApps) ->
%% Create new list of configured applications
- {SysApps,Status} = app_update_config(ChangedApps, Sys#sys.apps, {ok,[]}),
- {S#state{sys = Sys#sys{apps = SysApps}}, Status}.
+ SysApps = app_update_config(ChangedApps, Sys#sys.apps),
+ S#state{sys = Sys#sys{apps = SysApps}}.
%% Re-create the #sys.apps list by
%% 1) taking configurable fields from the changed #app records and
%% create new default records
%% 2) removing #app records if no configurable fields are set
%% 3) keeping #app records that are not changed
-app_update_config([#app{name=Name,is_escript={inlined,Escript}}|Configs],
- SysApps,Status) ->
- Text =
- lists:flatten(
- io_lib:format("Application ~p is inlined in ~p. Can not change "
- "configuration for an inlined application.",
- [Name,Escript])),
- Status2 = reltool_utils:return_first_error(Status, Text),
- app_update_config(Configs,SysApps,Status2);
-app_update_config([Config|Configs],SysApps,Status) ->
+app_update_config([#app{name=Name,is_escript={inlined,Escript}}|_],_SysApps) ->
+ reltool_utils:throw_error("Application ~p is inlined in ~p. Can not change "
+ "configuration for an inlined application.",
+ [Name,Escript]);
+app_update_config([Config|Configs],SysApps) ->
NewSysApps =
case app_set_config_only(Config) of
{delete,Name} ->
@@ -441,9 +432,9 @@ app_update_config([Config|Configs],SysApps,Status) ->
New ->
lists:ukeymerge(#app.name,[New],SysApps)
end,
- app_update_config(Configs,NewSysApps,Status);
-app_update_config([],SysApps,Status) ->
- {SysApps,Status}.
+ app_update_config(Configs,NewSysApps);
+app_update_config([],SysApps) ->
+ SysApps.
app_set_config_only(#app{mods=ConfigMods} = Config) ->
app_set_config_only(mod_set_config_only(ConfigMods),Config).
@@ -522,7 +513,7 @@ mod_set_config_only(ConfigMods) ->
analyse(#state{common=C, sys=Sys}, Apps, Status) ->
%% Create a list of {RelName,AppName}, one element for each
%% AppName that needs to be included for the given release.
- {RelApps, Status2} = apps_in_rels(Sys#sys.rels, Apps, Status),
+ RelApps = apps_in_rels(Sys#sys.rels, Apps),
%% Initiate is_pre_included and is_included for all applications
%% based on #sys.incl_cond, #app.incl_cond and if the application
@@ -531,7 +522,7 @@ analyse(#state{common=C, sys=Sys}, Apps, Status) ->
%% are no duplicated module names (in different applications)
%% where we can not decide which one to use.
%% Write all #app to app_tab and all #mod to mod_tab.
- Status3 = apps_init_is_included(C, Sys, Apps, RelApps, Status2),
+ Status2 = apps_init_is_included(C, Sys, Apps, RelApps, Status),
%% For each module that has #mod.is_included==true, propagate
%% is_included to the modules it uses.
@@ -548,53 +539,50 @@ analyse(#state{common=C, sys=Sys}, Apps, Status) ->
%% #mod.is_included==true for at least one module in the app.
%% Set status=missing|ok for #app and #mod - indicates if module
%% (.beam file) is missing in file system.
- Status4 = app_recap_dependencies(C, Status3),
+ app_recap_dependencies(C),
%% Check that the boot_rel exists.
%% Check that all applications that are listed in a 'rel' spec are
%% also really included in the target release.
%% Check that all mandatory applications are included in all rels.
- verify_config(C, Sys, RelApps, Status4).
+ verify_config(C, Sys, RelApps, Status2).
-apps_in_rels(Rels, Apps, Status) ->
- {AllRelApps, Status2} =
- lists:foldl(fun(Rel, {RelApps, S}) ->
- {MoreRelApps, S2} = apps_in_rel(Rel, Apps, S),
- {MoreRelApps ++ RelApps, S2}
+apps_in_rels(Rels, Apps) ->
+ AllRelApps =
+ lists:foldl(fun(Rel, RelApps) ->
+ MoreRelApps = apps_in_rel(Rel, Apps),
+ MoreRelApps ++ RelApps
end,
- {[], Status},
+ [],
Rels),
- {lists:reverse(AllRelApps), Status2}.
+ lists:reverse(AllRelApps).
-apps_in_rel(#rel{name = RelName, rel_apps = RelApps}, Apps, Status) ->
+apps_in_rel(#rel{name = RelName, rel_apps = RelApps}, Apps) ->
Mandatory = [{RelName, kernel}, {RelName, stdlib}],
Other = [{RelName, AppName} ||
RA <- RelApps,
AppName <- [RA#rel_app.name | RA#rel_app.incl_apps],
not lists:keymember(AppName, 2, Mandatory)],
- more_apps_in_rels(Mandatory ++ Other, Apps, [], Status).
+ more_apps_in_rels(Mandatory ++ Other, Apps, []).
-more_apps_in_rels([{RelName, AppName} = RA | RelApps], Apps, Acc, Status) ->
+more_apps_in_rels([{RelName, AppName} = RA | RelApps], Apps, Acc) ->
case lists:member(RA, Acc) of
true ->
- more_apps_in_rels(RelApps, Apps, Acc, Status);
+ 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],
- {Acc2, Status2} =
- more_apps_in_rels(Extra, Apps, [RA | Acc], Status),
- more_apps_in_rels(RelApps, Apps, Acc2, Status2);
+ Acc2 = more_apps_in_rels(Extra, Apps, [RA | Acc]),
+ more_apps_in_rels(RelApps, Apps, Acc2);
false ->
- Text = lists:concat(["Release ", RelName,
- " uses non existing application ",
- AppName]),
- Status2 = reltool_utils:return_first_error(Status, Text),
- more_apps_in_rels(RelApps, Apps, Acc, Status2)
+ reltool_utils:throw_error(
+ "Release ~p uses non existing application ~p",
+ [RelName,AppName])
end
end;
-more_apps_in_rels([], _Apps, Acc, Status) ->
- {Acc, Status}.
+more_apps_in_rels([], _Apps, Acc) ->
+ Acc.
apps_init_is_included(C, Sys, Apps, RelApps, Status) ->
@@ -627,11 +615,9 @@ app_init_is_included(C,
{exclude, []} ->
{undefined, false, false, Status};
{exclude, [RelName | _]} -> % App is included in at least one rel
- Text = lists:concat(["Application ", AppName, " is used "
- "in release ", RelName, " and cannot "
- "be excluded"]),
- TmpStatus = reltool_utils:return_first_error(Status, Text),
- {undefined, false, false, TmpStatus};
+ reltool_utils:throw_error(
+ "Application ~p is used in release ~p and cannot be excluded",
+ [AppName,RelName]);
{derived, []} ->
{undefined, undefined, undefined, Status};
{derived, [_ | _]} -> % App is included in at least one rel
@@ -651,7 +637,7 @@ app_init_is_included(C,
is_pre_included = IsPreIncl,
is_included = IsIncl,
rels = Rels},
- ets:insert(C#common.app_tab, A2), %%! Set mods to only mod names here????
+ ets:insert(C#common.app_tab, A2),
Status3.
mod_init_is_included(C, M, ModCond, AppCond, Default, Status) ->
@@ -716,15 +702,10 @@ mod_init_is_included(C, M, ModCond, AppCond, Default, Status) ->
%% Don't insert in mod_tab - using Existing
reltool_utils:add_warning(Status,Warning);
{_,_} ->
- Error =
- lists:concat(
- ["Module ",M#mod.name,
- " potentially included by ",
- "two different applications: ",
- Existing#mod.app_name, " and ",
- M#mod.app_name, "."]),
- %% Don't insert in mod_tab - using Existing
- reltool_utils:return_first_error(Status,Error)
+ reltool_utils:throw_error(
+ "Module ~p potentially included by two different "
+ "applications: ~p and ~p.",
+ [M#mod.name,Existing#mod.app_name,M#mod.app_name])
end;
[] ->
ets:insert(C#common.mod_tab, M2),
@@ -851,16 +832,12 @@ propagate_is_used_by(C) ->
get_all_mods_and_dependencies(C)).
-app_recap_dependencies(C, Status0) ->
- ets:foldl(fun(App,Status) ->
- app_recap_dependencies(C,App,Status)
- end,
- Status0,
- C#common.app_tab).
+app_recap_dependencies(C) ->
+ ets:foldl(fun(App,_) -> app_recap_dependencies(C,App) end,
+ ok, C#common.app_tab).
-app_recap_dependencies(C, #app{mods = Mods, is_included = IsIncl} = A, Status) ->
- {Mods2, IsIncl2, Status2} =
- mod_recap_dependencies(C, A, Mods, [], IsIncl, Status),
+app_recap_dependencies(C, #app{mods = Mods, is_included = IsIncl} = A) ->
+ {Mods2, IsIncl2} = mod_recap_dependencies(C, A, Mods, [], IsIncl),
AppStatus =
case lists:keymember(missing, #mod.status, Mods2) of
true -> missing;
@@ -885,9 +862,9 @@ app_recap_dependencies(C, #app{mods = Mods, is_included = IsIncl} = A, Status) -
used_by_apps = UsedByApps2,
is_included = IsIncl2},
ets:insert(C#common.app_tab,A2),
- Status2.
+ ok.
-mod_recap_dependencies(C, A, [#mod{name = ModName}=M1 | Mods], Acc, IsIncl, Status) ->
+mod_recap_dependencies(C, A, [#mod{name = ModName}=M1 | Mods], Acc, IsIncl) ->
case ets:lookup(C#common.mod_tab, ModName) of
[M2] when M2#mod.app_name=:=A#app.name ->
ModStatus = do_get_status(M2),
@@ -903,25 +880,21 @@ mod_recap_dependencies(C, A, [#mod{name = ModName}=M1 | Mods], Acc, IsIncl, Stat
{IsIncl, M2#mod{status = ModStatus, used_by_mods = []}}
end,
ets:insert(C#common.mod_tab, M3),
- mod_recap_dependencies(C, A, Mods, [M3 | Acc], IsIncl2, Status);
- [_] when A#app.is_included==false; M1#mod.incl_cond==exclude -> %!!! incl_cond could be read from #sys.app.mods
+ mod_recap_dependencies(C, A, Mods, [M3 | Acc], IsIncl2);
+ [_] when A#app.is_included==false; M1#mod.incl_cond==exclude ->
%% App is explicitely excluded so it is ok that the module
%% record does not exist for this module in this
%% application.
- mod_recap_dependencies(C, A, Mods, [M1 | Acc], IsIncl, Status);
+ mod_recap_dependencies(C, A, Mods, [M1 | Acc], IsIncl);
[M2] ->
%% A module is potensially included by multiple
%% applications. This is not allowed!
- Error =
- lists:concat(
- ["Module ",ModName,
- " potentially included by two different applications: ",
- A#app.name, " and ", M2#mod.app_name, "."]),
- Status2 = reltool_utils:return_first_error(Status,Error),
- mod_recap_dependencies(C, A, Mods, [M1 | Acc], IsIncl, Status2)
+ reltool_utils:throw_error(
+ "Module ~p potentially included by two different applications: "
+ "~p and ~p", [ModName,A#app.name, " and ", M2#mod.app_name, "."])
end;
-mod_recap_dependencies(_C, _A, [], Acc, IsIncl, Status) ->
- {lists:reverse(Acc), IsIncl, Status}.
+mod_recap_dependencies(_C, _A, [], Acc, IsIncl) ->
+ {lists:reverse(Acc), IsIncl}.
do_get_status(M) ->
if
@@ -944,9 +917,8 @@ verify_config(C, #sys{boot_rel = BootRel, rels = Rels}, RelApps, Status) ->
Status2,
Rels);
false ->
- Text = lists:concat(["Release ", BootRel,
- " is mandatory (used as boot_rel)"]),
- reltool_utils:return_first_error(Status, Text)
+ reltool_utils:throw_error(
+ "Release ~p is mandatory (used as boot_rel)",[BootRel])
end.
check_app(C, {RelName, AppName}, Status) ->
@@ -955,10 +927,8 @@ check_app(C, {RelName, AppName}, Status) ->
when IsPreIncl; IsIncl ->
Status;
_ ->
- Text = lists:concat(["Release ", RelName,
- " uses non included application ",
- AppName]),
- reltool_utils:return_first_error(Status, Text)
+ reltool_utils:throw_error(
+ "Release ~p uses non included application ~p",[RelName,AppName])
end.
check_rel(RelName, RelApps, Status) ->
@@ -968,11 +938,9 @@ check_rel(RelName, RelApps, Status) ->
true ->
Acc;
false ->
- Text = lists:concat(["Mandatory application ",
- AppName,
- " is not included in release ",
- RelName]),
- reltool_utils:return_first_error(Acc, Text)
+ reltool_utils:throw_error(
+ "Mandatory application ~p is not included in "
+ "release ~p", [AppName,RelName])
end
end,
Mandatory = [kernel, stdlib],
@@ -1033,7 +1001,7 @@ refresh_app(#app{name = AppName,
%% Add optional user config for each module.
%% The #mod records that are already in the #app record at
%% this point do only contain user defined configuration
- %% (set by parse_options/1). So here we merge with the
+ %% (set by parse_options/2). So here we merge with the
%% default records from above.
Mods2 = add_mod_config(MissingMods ++ EbinMods, Mods),
@@ -1311,105 +1279,83 @@ do_save_config(S, Filename, InclDef, InclDeriv) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
do_load_config(S, SysConfig) ->
- {NewSys, Status} = read_config(default_sys(), SysConfig, {ok, []}),
- {S#state{sys = NewSys}, Status}.
+ S#state{sys = read_config(default_sys(), SysConfig)}.
-read_config(OldSys, Filename, Status) when is_list(Filename) ->
+read_config(OldSys, Filename) when is_list(Filename) ->
case file:consult(Filename) of
{ok, [SysConfig | _]} ->
- read_config(OldSys, SysConfig, Status);
+ read_config(OldSys, SysConfig);
{ok, Content} ->
- Text = lists:flatten(io_lib:format("~p", [Content])),
- {OldSys,
- reltool_utils:return_first_error(Status,
- "Illegal file content: " ++
- Text)};
+ reltool_utils:throw_error("Illegal file content: ~p",[Content]);
{error, Reason} ->
- Text = file:format_error(Reason),
- {OldSys,
- reltool_utils:return_first_error(Status,
- "Illegal config file " ++
- Filename ++ ": " ++ Text)}
+ reltool_utils:throw_error("Illegal config file ~p: ~s",
+ [Filename,file:format_error(Reason)])
end;
-read_config(OldSys, {sys, KeyVals}, Status) ->
- {NewSys, Status2} =
- decode(OldSys#sys{apps = [], rels = []}, KeyVals, Status),
- case Status2 of
- {ok, _Warnings} -> % BUGBUG: handle warnings
- Apps = [A#app{mods = lists:sort(A#app.mods)} ||
- A <- NewSys#sys.apps],
- case NewSys#sys.rels of
- [] -> Rels = reltool_utils:default_rels();
- Rels -> ok
- end,
- NewSys2 = NewSys#sys{apps = lists:sort(Apps),
- rels = lists:sort(Rels)},
- case lists:keymember(NewSys2#sys.boot_rel,
- #rel.name,
- NewSys2#sys.rels) of
- true ->
- {NewSys2, Status2};
- false ->
- Text2 = lists:concat(["Release " ++ NewSys2#sys.boot_rel,
- " is mandatory (used as boot_rel)"]),
- {OldSys, reltool_utils:return_first_error(Status2, Text2)}
- end;
- {error, _} ->
- %% Keep old state
- {OldSys, Status2}
+read_config(OldSys, {sys, KeyVals}) ->
+ NewSys = decode(OldSys#sys{apps = [], rels = []}, KeyVals),
+ Apps = [A#app{mods = lists:sort(A#app.mods)} || A <- NewSys#sys.apps],
+ Rels =
+ case NewSys#sys.rels of
+ [] -> reltool_utils:default_rels();
+ Rs -> Rs
+ end,
+ NewSys2 = NewSys#sys{apps = lists:sort(Apps),
+ rels = lists:sort(Rels)},
+ case lists:keymember(NewSys2#sys.boot_rel, #rel.name, NewSys2#sys.rels) of
+ true ->
+ NewSys2;
+ false ->
+ reltool_utils:throw_error(
+ "Release ~p is mandatory (used as boot_rel)",
+ [NewSys2#sys.boot_rel])
end;
-read_config(OldSys, BadConfig, Status) ->
- Text = lists:flatten(io_lib:format("~p", [BadConfig])),
- {OldSys,
- reltool_utils:return_first_error(Status, "Illegal content: " ++ Text)}.
+read_config(_OldSys, BadConfig) ->
+ reltool_utils:throw_error("Illegal content: ~p", [BadConfig]).
-decode(#sys{apps = Apps} = Sys, [{erts = Name, AppKeyVals} | SysKeyVals],
- Status)
+decode(#sys{apps = Apps} = Sys, [{erts = Name, AppKeyVals} | SysKeyVals])
when is_atom(Name), is_list(AppKeyVals) ->
App = default_app(Name),
- {App2, Status2} = decode(App, AppKeyVals, Status),
- decode(Sys#sys{apps = [App2 | Apps]}, SysKeyVals, Status2);
-decode(#sys{apps = Apps} = Sys, [{app, Name, AppKeyVals} | SysKeyVals], Status)
+ App2= decode(App, AppKeyVals),
+ decode(Sys#sys{apps = [App2 | Apps]}, SysKeyVals);
+decode(#sys{apps = Apps} = Sys, [{app, Name, AppKeyVals} | SysKeyVals])
when is_atom(Name), is_list(AppKeyVals) ->
App = default_app(Name),
- {App2, Status2} = decode(App, AppKeyVals, Status),
- decode(Sys#sys{apps = [App2 | Apps]}, SysKeyVals, Status2);
+ App2 = decode(App, AppKeyVals),
+ decode(Sys#sys{apps = [App2 | Apps]}, SysKeyVals);
decode(#sys{apps = Apps, escripts = Escripts} = Sys,
- [{escript, File0, AppKeyVals} | SysKeyVals], Status)
+ [{escript, File0, AppKeyVals} | SysKeyVals])
when is_list(File0), is_list(AppKeyVals) ->
File = filename:absname(File0),
App = default_escript_app(File),
- {App2, Status2} = decode(App, AppKeyVals, Status),
+ App2 = decode(App, AppKeyVals),
decode(Sys#sys{apps = [App2 | Apps], escripts = [File | Escripts]},
- SysKeyVals,
- Status2);
-decode(#sys{rels = Rels} = Sys, [{rel, Name, Vsn, RelApps} | SysKeyVals],
- Status)
+ SysKeyVals);
+decode(#sys{rels = Rels} = Sys, [{rel, Name, Vsn, RelApps} | SysKeyVals])
when is_list(Name), is_list(Vsn), is_list(RelApps) ->
Rel = #rel{name = Name, vsn = Vsn, rel_apps = []},
- {Rel2, Status2} = decode(Rel, RelApps, Status),
- decode(Sys#sys{rels = [Rel2 | Rels]}, SysKeyVals, Status2);
-decode(#sys{} = Sys, [{Key, Val} | KeyVals], Status) ->
- {Sys3, Status3} =
+ Rel2 = decode(Rel, RelApps),
+ decode(Sys#sys{rels = [Rel2 | Rels]}, SysKeyVals);
+decode(#sys{} = Sys, [{Key, Val} | KeyVals]) ->
+ Sys3 =
case Key of
root_dir when is_list(Val) ->
- {Sys#sys{root_dir = Val}, Status};
+ Sys#sys{root_dir = Val};
lib_dirs when is_list(Val) ->
- {Sys#sys{lib_dirs = Val}, Status};
+ Sys#sys{lib_dirs = Val};
mod_cond when Val =:= all;
Val =:= app;
Val =:= ebin;
Val =:= derived;
Val =:= none ->
- {Sys#sys{mod_cond = Val}, Status};
+ Sys#sys{mod_cond = Val};
incl_cond when Val =:= include;
Val =:= exclude;
Val =:= derived ->
- {Sys#sys{incl_cond = Val}, Status};
+ Sys#sys{incl_cond = Val};
boot_rel when is_list(Val) ->
- {Sys#sys{boot_rel = Val}, Status};
+ Sys#sys{boot_rel = Val};
emu_name when is_list(Val) ->
- {Sys#sys{emu_name = Val}, Status};
+ Sys#sys{emu_name = Val};
profile when Val =:= development;
Val =:= embedded;
Val =:= standalone ->
@@ -1418,166 +1364,126 @@ decode(#sys{} = Sys, [{Key, Val} | KeyVals], Status) ->
InclApp = reltool_utils:choose_default(incl_app_filters, Val, false),
ExclApp = reltool_utils:choose_default(excl_app_filters, Val, false),
AppType = reltool_utils:choose_default(embedded_app_type, Val, false),
- {Sys#sys{profile = Val,
- incl_sys_filters = dec_re(incl_sys_filters,
- InclSys,
- Sys#sys.incl_sys_filters),
- excl_sys_filters = dec_re(excl_sys_filters,
- ExclSys,
- Sys#sys.excl_sys_filters),
- incl_app_filters = dec_re(incl_app_filters,
- InclApp,
- Sys#sys.incl_app_filters),
- excl_app_filters = dec_re(excl_app_filters,
- ExclApp,
- Sys#sys.excl_app_filters),
- embedded_app_type = AppType},
- Status};
+ Sys#sys{profile = Val,
+ incl_sys_filters = dec_re(incl_sys_filters,
+ InclSys,
+ Sys#sys.incl_sys_filters),
+ excl_sys_filters = dec_re(excl_sys_filters,
+ ExclSys,
+ Sys#sys.excl_sys_filters),
+ incl_app_filters = dec_re(incl_app_filters,
+ InclApp,
+ Sys#sys.incl_app_filters),
+ excl_app_filters = dec_re(excl_app_filters,
+ ExclApp,
+ Sys#sys.excl_app_filters),
+ embedded_app_type = AppType};
incl_sys_filters ->
- {Sys#sys{incl_sys_filters =
- dec_re(Key,
- Val,
- Sys#sys.incl_sys_filters)},
- Status};
+ Sys#sys{incl_sys_filters =
+ dec_re(Key, Val, Sys#sys.incl_sys_filters)};
excl_sys_filters ->
- {Sys#sys{excl_sys_filters =
- dec_re(Key,
- Val,
- Sys#sys.excl_sys_filters)},
- Status};
+ Sys#sys{excl_sys_filters =
+ dec_re(Key, Val, Sys#sys.excl_sys_filters)};
incl_app_filters ->
- {Sys#sys{incl_app_filters =
- dec_re(Key,
- Val,
- Sys#sys.incl_app_filters)},
- Status};
+ Sys#sys{incl_app_filters =
+ dec_re(Key, Val, Sys#sys.incl_app_filters)};
excl_app_filters ->
- {Sys#sys{excl_app_filters =
- dec_re(Key,
- Val,
- Sys#sys.excl_app_filters)},
- Status};
+ Sys#sys{excl_app_filters =
+ dec_re(Key, Val, Sys#sys.excl_app_filters)};
incl_archive_filters ->
- {Sys#sys{incl_archive_filters =
- dec_re(Key,
- Val,
- Sys#sys.incl_archive_filters)},
- Status};
+ Sys#sys{incl_archive_filters =
+ dec_re(Key, Val, Sys#sys.incl_archive_filters)};
excl_archive_filters ->
- {Sys#sys{excl_archive_filters =
- dec_re(Key,
- Val,
- Sys#sys.excl_archive_filters)},
- Status};
+ Sys#sys{excl_archive_filters =
+ dec_re(Key, Val, Sys#sys.excl_archive_filters)};
archive_opts when is_list(Val) ->
- {Sys#sys{archive_opts = Val}, Status};
+ Sys#sys{archive_opts = Val};
relocatable when Val =:= true; Val =:= false ->
- {Sys#sys{relocatable = Val}, Status};
+ Sys#sys{relocatable = Val};
rel_app_type when Val =:= permanent;
Val =:= transient;
Val =:= temporary;
Val =:= load;
Val =:= none ->
- {Sys#sys{rel_app_type = Val}, Status};
+ Sys#sys{rel_app_type = Val};
embedded_app_type when Val =:= permanent;
Val =:= transient;
Val =:= temporary;
Val =:= load;
Val =:= none;
Val =:= undefined ->
- {Sys#sys{embedded_app_type = Val}, Status};
+ Sys#sys{embedded_app_type = Val};
app_file when Val =:= keep; Val =:= strip; Val =:= all ->
- {Sys#sys{app_file = Val}, Status};
+ Sys#sys{app_file = Val};
debug_info when Val =:= keep; Val =:= strip ->
- {Sys#sys{debug_info = Val}, Status};
+ Sys#sys{debug_info = Val};
_ ->
- Text = lists:flatten(io_lib:format("~p", [{Key, Val}])),
- {Sys, reltool_utils:return_first_error(Status,
- "Illegal option: " ++
- Text)}
+ reltool_utils:throw_error("Illegal option: ~p", [{Key, Val}])
end,
- decode(Sys3, KeyVals, Status3);
-decode(#app{} = App, [{Key, Val} | KeyVals], Status) ->
- {App2, Status2} =
+ decode(Sys3, KeyVals);
+decode(#app{} = App, [{Key, Val} | KeyVals]) ->
+ App2 =
case Key of
mod_cond when Val =:= all;
Val =:= app;
Val =:= ebin;
Val =:= derived;
Val =:= none ->
- {App#app{mod_cond = Val}, Status};
+ App#app{mod_cond = Val};
incl_cond when Val =:= include;
Val =:= exclude;
Val =:= derived ->
- {App#app{incl_cond = Val}, Status};
+ App#app{incl_cond = Val};
debug_info when Val =:= keep;
Val =:= strip ->
- {App#app{debug_info = Val}, Status};
+ App#app{debug_info = Val};
app_file when Val =:= keep;
Val =:= strip;
Val =:= all ->
- {App#app{app_file = Val}, Status};
+ App#app{app_file = Val};
app_type when Val =:= permanent;
Val =:= transient;
Val =:= temporary;
Val =:= load;
Val =:= none;
Val =:= undefined ->
- {App#app{app_type = Val}, Status};
+ App#app{app_type = Val};
incl_app_filters ->
- {App#app{incl_app_filters =
- dec_re(Key,
- Val,
- App#app.incl_app_filters)},
- Status};
+ App#app{incl_app_filters =
+ dec_re(Key, Val, App#app.incl_app_filters)};
excl_app_filters ->
- {App#app{excl_app_filters =
- dec_re(Key,
- Val,
- App#app.excl_app_filters)},
- Status};
+ App#app{excl_app_filters =
+ dec_re(Key, Val, App#app.excl_app_filters)};
incl_archive_filters ->
- {App#app{incl_archive_filters =
- dec_re(Key,
- Val,
- App#app.incl_archive_filters)},
- Status};
+ App#app{incl_archive_filters =
+ dec_re(Key, Val, App#app.incl_archive_filters)};
excl_archive_filters ->
- {App#app{excl_archive_filters =
- dec_re(Key,
- Val,
- App#app.excl_archive_filters)},
- Status};
+ App#app{excl_archive_filters =
+ dec_re(Key, Val, App#app.excl_archive_filters)};
archive_opts when is_list(Val) ->
- {App#app{archive_opts = Val}, Status};
+ App#app{archive_opts = Val};
vsn when is_list(Val) ->
- {App#app{use_selected_vsn = true, vsn = Val}, Status};
+ App#app{use_selected_vsn = true, vsn = Val};
_ ->
- Text = lists:flatten(io_lib:format("~p", [{Key, Val}])),
- {App, reltool_utils:return_first_error(Status,
- "Illegal option: " ++ Text)}
+ reltool_utils:throw_error("Illegal option: ~p", [{Key, Val}])
end,
- decode(App2, KeyVals, Status2);
-decode(#app{mods = Mods} = App, [{mod, Name, ModKeyVals} | AppKeyVals],
- Status) ->
- {Mod, Status2} = decode(#mod{name = Name}, ModKeyVals, Status),
- decode(App#app{mods = [Mod | Mods]}, AppKeyVals, Status2);
-decode(#mod{} = Mod, [{Key, Val} | KeyVals], Status) ->
- {Mod2, Status2} =
+ decode(App2, KeyVals);
+decode(#app{mods = Mods} = App, [{mod, Name, ModKeyVals} | AppKeyVals]) ->
+ Mod = decode(#mod{name = Name}, ModKeyVals),
+ decode(App#app{mods = [Mod | Mods]}, AppKeyVals);
+decode(#mod{} = Mod, [{Key, Val} | KeyVals]) ->
+ Mod2 =
case Key of
incl_cond when Val =:= include; Val =:= exclude; Val =:= derived ->
- {Mod#mod{incl_cond = Val}, Status};
+ Mod#mod{incl_cond = Val};
debug_info when Val =:= keep; Val =:= strip ->
- {Mod#mod{debug_info = Val}, Status};
+ Mod#mod{debug_info = Val};
_ ->
- Text = lists:flatten(io_lib:format("~p", [{Key, Val}])),
- {Mod,
- reltool_utils:return_first_error(Status,
- "Illegal option: " ++ Text)}
+ reltool_utils:throw_error("Illegal option: ~p", [{Key, Val}])
end,
- decode(Mod2, KeyVals, Status2);
-decode(#rel{rel_apps = RelApps} = Rel, [RelApp | KeyVals], Status) ->
+ decode(Mod2, KeyVals);
+decode(#rel{rel_apps = RelApps} = Rel, [RelApp | KeyVals]) ->
{ValidTypesAssigned, RA} =
case RelApp of
Name when is_atom(Name) ->
@@ -1597,19 +1503,14 @@ decode(#rel{rel_apps = RelApps} = Rel, [RelApp | KeyVals], Status) ->
end,
case ValidTypesAssigned of
true ->
- decode(Rel#rel{rel_apps = RelApps ++ [RA]}, KeyVals, Status);
+ decode(Rel#rel{rel_apps = RelApps ++ [RA]}, KeyVals);
false ->
- Text = lists:flatten(io_lib:format("~p", [RelApp])),
- Status2 =
- reltool_utils:return_first_error(Status,
- "Illegal option: " ++ Text),
- decode(Rel, KeyVals, Status2)
+ reltool_utils:throw_error("Illegal option: ~p", [RelApp])
end;
-decode(Acc, [], Status) ->
- {Acc, Status};
-decode(Acc, KeyVal, Status) ->
- Text = lists:flatten(io_lib:format("~p", [KeyVal])),
- {Acc, reltool_utils:return_first_error(Status, "Illegal option: " ++ Text)}.
+decode(Acc, []) ->
+ Acc;
+decode(_Acc, KeyVal) ->
+ reltool_utils:throw_error("Illegal option: ~p", [KeyVal]).
is_type(Type) ->
case Type of
@@ -1638,13 +1539,13 @@ default_escript_app(File) ->
%% Apps is a list of #app records - sorted on #app.name - containing
%% only the apps that have specific configuration (e.g. in the config
%% file)
-refresh(#state{sys=Sys} = S, Status) ->
+refresh(#state{sys=Sys} = S) ->
RootDir = filename:absname(Sys#sys.root_dir),
LibDirs = [filename:absname(D) || D <- Sys#sys.lib_dirs],
Escripts = [filename:absname(E) || E <- Sys#sys.escripts],
%% Read all lib dirs and return sorted [{AppName,Dir}]
- {SourceDirs, Status2} = libs_to_dirs(RootDir, LibDirs, Status),
+ SourceDirs = libs_to_dirs(RootDir, LibDirs),
%% Create #app records for all apps in SourceDirs, and merge with
%% list of apps from config.
@@ -1652,24 +1553,24 @@ refresh(#state{sys=Sys} = S, Status) ->
%% For each escript, find all related files and convert to #app
%% and #mod records
- {AllApps, Status3} = escripts_to_apps(Escripts, MergedApps, Status2),
+ {AllApps, Status2} = escripts_to_apps(Escripts, MergedApps, {ok,[]}),
%% Make sure correct version of each application is used according
%% to the user configuration.
%% Then find all modules and their dependencies and set user
%% configuration per module if it exists.
- {RefreshedApps, Status4} = refresh_apps(Sys#sys.apps, AllApps, [],
- true, Status3),
+ {RefreshedApps, Status3} = refresh_apps(Sys#sys.apps, AllApps, [],
+ true, Status2),
%% Make sure erts exists in app list and has a version (or warn)
- {PatchedApps, Status5} = patch_erts_version(RootDir, RefreshedApps, Status4),
+ {PatchedApps, Status4} = patch_erts_version(RootDir, RefreshedApps, Status3),
%% Update #sys and return
Escripts2 = [A#app.active_dir || A <- PatchedApps, A#app.is_escript],
Sys2 = Sys#sys{root_dir = RootDir,
lib_dirs = LibDirs,
escripts = Escripts2},
- {S#state{sys=Sys2}, PatchedApps, Status5}.
+ {S#state{sys=Sys2}, PatchedApps, Status4}.
patch_erts_version(RootDir, Apps, Status) ->
AppName = erts,
@@ -1689,12 +1590,11 @@ patch_erts_version(RootDir, Apps, Status) ->
{Apps, Status}
end;
false ->
- Text = "erts cannot be found in the root directory " ++ RootDir,
- Status2 = reltool_utils:return_first_error(Status, Text),
- {Apps, Status2}
+ reltool_utils:throw_error(
+ "erts cannot be found in the root directory ~p", [RootDir])
end.
-libs_to_dirs(RootDir, LibDirs, Status) ->
+libs_to_dirs(RootDir, LibDirs) ->
case file:list_dir(RootDir) of
{ok, RootFiles} ->
RootLibDir = filename:join([RootDir, "lib"]),
@@ -1716,21 +1616,16 @@ libs_to_dirs(RootDir, LibDirs, Status) ->
end,
ErtsFiles = [{erts, Fun(F)} || F <- RootFiles,
lists:prefix("erts", F)],
- app_dirs2(AllLibDirs, [ErtsFiles], Status);
+ app_dirs2(AllLibDirs, [ErtsFiles]);
[Duplicate | _] ->
- {[],
- reltool_utils:return_first_error(Status,
- "Duplicate library: " ++
- Duplicate)}
+ reltool_utils:throw_error("Duplicate library: ~p",[Duplicate])
end;
{error, Reason} ->
- Text = file:format_error(Reason),
- {[], reltool_utils:return_first_error(Status,
- "Missing root library " ++
- RootDir ++ ": " ++ Text)}
+ reltool_utils:throw_error("Missing root library ~p: ~s",
+ [RootDir,file:format_error(Reason)])
end.
-app_dirs2([Lib | Libs], Acc, Status) ->
+app_dirs2([Lib | Libs], Acc) ->
case file:list_dir(Lib) of
{ok, Files} ->
Filter =
@@ -1750,15 +1645,13 @@ app_dirs2([Lib | Libs], Acc, Status) ->
end
end,
Files2 = lists:zf(Filter, Files),
- app_dirs2(Libs, [Files2 | Acc], Status);
+ app_dirs2(Libs, [Files2 | Acc]);
{error, Reason} ->
- Text = file:format_error(Reason),
- {[], reltool_utils:return_first_error(Status,
- "Illegal library " ++
- Lib ++ ": " ++ Text)}
+ reltool_utils:throw_error("Illegal library ~p: ~s",
+ [Lib, file:format_error(Reason)])
end;
-app_dirs2([], Acc, Status) ->
- {lists:sort(lists:append(Acc)), Status}.
+app_dirs2([], Acc) ->
+ lists:sort(lists:append(Acc)).
escripts_to_apps([Escript | Escripts], Apps, Status) ->
{EscriptAppName, _Label} = split_escript_name(Escript),
@@ -1836,10 +1729,7 @@ escripts_to_apps([Escript | Escripts], Apps, Status) ->
Status2),
escripts_to_apps(Escripts, Apps2, Status3);
{error, Reason} ->
- Text = lists:flatten(io_lib:format("~p", [Reason])),
- {[], reltool_utils:return_first_error(Status,
- "Illegal escript " ++
- Escript ++ ": " ++ Text)}
+ reltool_utils:throw_error("Illegal escript ~p: ~p", [Escript,Reason])
end;
escripts_to_apps([], Apps, Status) ->
{Apps, Status}.
@@ -1900,10 +1790,9 @@ init_escript_app(AppName, EscriptAppName, Dir, Info, Mods, Apps, Status) ->
incl_cond = InclCond},% inlined apps inherit incl from escript
case lists:keymember(AppName, #app.name, Apps) of
true ->
- Error = lists:concat([AppName, ": Application name clash. ",
- "Escript ", Dir," contains application ",
- AppName, "."]),
- {App2, reltool_utils:return_first_error(Status, Error)};
+ reltool_utils:throw_error(
+ "~p: Application name clash. Escript ~p contains application ~p.",
+ [AppName,Dir,AppName]);
false ->
{App2, Status}
end.
@@ -1983,10 +1872,8 @@ ensure_app_info(#app{is_escript = IsEscript, active_dir = Dir, info = Info},
when IsEscript=/=false ->
%% Escript or application which is inlined in an escript
{Info, Dir, Status};
-ensure_app_info(#app{name = Name, sorted_dirs = []}, Status) ->
- Error = lists:concat([Name, ": Missing application directory."]),
- Status2 = reltool_utils:return_first_error(Status, Error),
- {missing_app_info(""), undefined, Status2};
+ensure_app_info(#app{name = Name, sorted_dirs = []}, _Status) ->
+ reltool_utils:throw_error("~p: : Missing application directory.",[Name]);
ensure_app_info(#app{name = Name,
vsn = Vsn,
sorted_dirs = Dirs,
@@ -2008,11 +1895,10 @@ ensure_app_info(#app{name = Name,
%% No redundant info
Status2;
[BadVsn | _] ->
- Error2 =
- lists:concat([Name, ": Application version clash. ",
- "Multiple directories contains version \"",
- BadVsn, "\"."]),
- reltool_utils:return_first_error(Status2, Error2)
+ reltool_utils:throw_error(
+ "~p: Application version clash. "
+ "Multiple directories contains version ~p.",
+ [Name,BadVsn])
end,
FirstInfo = hd(AllInfo),
FirstDir = hd(Dirs),
@@ -2026,13 +1912,9 @@ ensure_app_info(#app{name = Name,
{Info, VsnDir} ->
{Info, VsnDir, Status3};
false ->
- Error3 =
- lists:concat([Name,
- ": No application directory contains ",
- "selected version \"",
- Vsn, "\"."]),
- Status4 = reltool_utils:return_first_error(Status3, Error3),
- {FirstInfo, FirstDir, Status4}
+ reltool_utils:throw_error(
+ "~p: No application directory contains selected version ~p",
+ [Name,Vsn])
end
end;
ensure_app_info(#app{active_dir = Dir, info = Info}, Status) ->
@@ -2064,42 +1946,24 @@ sys_all_apps(C,Sys) ->
all_apps(C) ->
ets:match_object(C#common.app_tab,'_').
-refresh_and_analyse_no_rollback(#state{common=C} = S, {ok,_} = Status) ->
- case refresh(S, Status) of
- {S2, Apps, {ok, _}=Status2} ->
- case analyse(S2, Apps, Status2) of
- {ok, _} = Status3 ->
- %% Set old_xxx is equal to xxx
- FakeBackup = {ets:tab2list(C#common.app_tab),
- ets:tab2list(C#common.mod_tab)},
- save_old(S2, S2, FakeBackup, Status3);
- {error,Reason} ->
- exit(Reason)
- end;
- {_,_,{error,Reason}} ->
- exit(Reason)
- end;
-refresh_and_analyse_no_rollback(_,{error,Reason}) ->
- exit(Reason).
-
-refresh_and_analyse(OldS, S, {ok,_}=Status) ->
- case refresh(S, Status) of
- {S2, Apps, {ok,_}=Status2} ->
- %% Analyse will write to app_tab and mod_tab, so we first
- %% backup these tables and clear them
- Backup = backup(OldS),
- case analyse(S2, Apps, Status2) of
- {ok, _} = Status3 ->
- save_old(OldS, S2, Backup, Status3);
- Status3 ->
- restore(Backup,OldS),
- {OldS,Status3}
- end;
- {_, _, Status2} ->
- {OldS, Status2}
- end;
-refresh_and_analyse(OldS, _S, Status) ->
- {OldS,Status}.
+config_and_refresh(OldS, Fun) ->
+ try
+ S = Fun(),
+ {S2, Apps, Status2} = refresh(S),
+ %% Analyse will write to app_tab and mod_tab, so we first
+ %% backup these tables and clear them
+ Backup = backup(OldS),
+ try
+ Status3 = analyse(S2, Apps, Status2),
+ S3 = save_old(OldS, S2, Backup, Status3),
+ {S3, Status3}
+ catch throw:{error,_} = Error1 ->
+ restore(Backup,OldS),
+ throw(Error1)
+ end
+ catch throw:{error,_} = Error2 ->
+ {OldS, Error2}
+ end.
backup(#state{common=C}) ->
@@ -2120,10 +1984,9 @@ save_old(#state{status=OldStatus,sys=OldSys},#state{common=C}=NewS,
ets:delete_all_objects(C#common.old_mod_tab),
insert_all(C#common.old_app_tab,OldApps),
insert_all(C#common.old_mod_tab,OldMods),
- {NewS#state{old_sys=OldSys,
+ NewS#state{old_sys=OldSys,
old_status=OldStatus,
- status=NewStatus},
- NewStatus}.
+ status=NewStatus}.
insert_all(Tab,Items) ->
lists:foreach(fun(Item) -> ets:insert(Tab,Item) end, Items).
diff --git a/lib/reltool/src/reltool_sys_win.erl b/lib/reltool/src/reltool_sys_win.erl
index 1638acb145..c75b302770 100644
--- a/lib/reltool/src/reltool_sys_win.erl
+++ b/lib/reltool/src/reltool_sys_win.erl
@@ -135,54 +135,49 @@ init(Options) ->
do_init([{safe_config, Safe}, {parent, Parent} | Options]) ->
case reltool_server:start_link(Options) of
- {ok, ServerPid, C} ->
+ {ok, ServerPid, C, Sys} ->
process_flag(trap_exit, C#common.trap_exit),
wx:new(),
wx:debug(C#common.wx_debug),
%% wx_misc:beginBusyCursor(),
- case reltool_server:get_status(ServerPid) of
- {ok, Warnings} ->
- exit_dialog(Warnings),
- {ok, Sys} = reltool_server:get_sys(ServerPid),
- S = #state{parent_pid = Parent,
- server_pid = ServerPid,
- common = C,
- config_file = filename:absname("config.reltool"),
- target_dir = filename:absname("reltool_target_dir"),
- app_wins = [],
- sys = Sys,
- fgraph_wins = []},
- S2 = create_window(S),
- S5 = wx:batch(fun() ->
- Title = atom_to_list(?APPLICATION),
- wxFrame:setTitle(S2#state.frame,
- Title),
- %% wxFrame:setMinSize(Frame,
- %% {?WIN_WIDTH, ?WIN_HEIGHT}),
- wxStatusBar:setStatusText(
- S2#state.status_bar,
- "Done."),
- S3 = redraw_apps(S2),
- S4 = redraw_libs(S3),
- redraw_config_page(S4)
- end),
- %% wx_misc:endBusyCursor(),
- %% wxFrame:destroy(Frame),
- proc_lib:init_ack(S#state.parent_pid, {ok, self()}),
- loop(S5);
- {error, Reason} ->
- restart_server_safe_config(Safe,Parent,Reason)
- end;
+ {ok, Warnings} = reltool_server:get_status(ServerPid),
+ exit_dialog(Warnings),
+ S = #state{parent_pid = Parent,
+ server_pid = ServerPid,
+ common = C,
+ config_file = filename:absname("config.reltool"),
+ target_dir = filename:absname("reltool_target_dir"),
+ app_wins = [],
+ sys = Sys,
+ fgraph_wins = []},
+ S2 = create_window(S),
+ S5 = wx:batch(fun() ->
+ Title = atom_to_list(?APPLICATION),
+ wxFrame:setTitle(S2#state.frame,
+ Title),
+ %% wxFrame:setMinSize(Frame,
+ %% {?WIN_WIDTH, ?WIN_HEIGHT}),
+ wxStatusBar:setStatusText(
+ S2#state.status_bar,
+ "Done."),
+ S3 = redraw_apps(S2),
+ S4 = redraw_libs(S3),
+ redraw_config_page(S4)
+ end),
+ %% wx_misc:endBusyCursor(),
+ %% wxFrame:destroy(Frame),
+ proc_lib:init_ack(S#state.parent_pid, {ok, self()}),
+ loop(S5);
{error, Reason} ->
- io:format("~p(~p): ~p\n", [?MODULE, ?LINE, Reason]),
- exit(Reason)
+ restart_server_safe_config(Safe,Parent,Reason)
end.
-restart_server_safe_config(true,_Parent,Reason) ->
+restart_server_safe_config(true,Parent,Reason) ->
io:format("~p(~p): ~p\n", [?MODULE, ?LINE, Reason]),
- exit(Reason);
+ proc_lib:init_ack(Parent, {error,Reason});
restart_server_safe_config(false,Parent,Reason) ->
+ wx:new(),
Strings =
[{?wxBLACK,"Could not start reltool server:\n\n"},
{?wxRED,Reason++"\n\n"},
@@ -197,7 +192,7 @@ restart_server_safe_config(false,Parent,Reason) ->
do_init([{safe_config,true},{parent,Parent},?safe_config]);
?wxID_CANCEL ->
io:format("~p(~p): ~p\n", [?MODULE, ?LINE, Reason]),
- exit(Reason)
+ proc_lib:init_ack(Parent,{error,Reason})
end.
exit_dialog([]) ->
diff --git a/lib/reltool/src/reltool_utils.erl b/lib/reltool/src/reltool_utils.erl
index 39d057d994..a9107355c7 100644
--- a/lib/reltool/src/reltool_utils.erl
+++ b/lib/reltool/src/reltool_utils.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -30,7 +30,7 @@
get_item/1, get_items/1, get_selected_items/3,
select_items/3, select_item/2,
- safe_keysearch/5, print/4, return_first_error/2, add_warning/2,
+ safe_keysearch/5, print/4, add_warning/2,
create_dir/1, list_dir/1, read_file_info/1,
write_file_info/2, read_file/1, write_file/2,
@@ -392,31 +392,12 @@ print(X, X, Format, Args) ->
print(_, _, _, _) ->
ok.
-%% -define(SAFE(M,F,A), safe(M, F, A, ?MODULE, ?LINE)).
-%%
-%% safe(M, F, A, Mod, Line) ->
-%% case catch apply(M, F, A) of
-%% {'EXIT', Reason} ->
-%% io:format("~p(~p): ~p:~p~p -> ~p\n", [Mod, Line, M, F, A, Reason]),
-%% timer:sleep(infinity);
-%% Res ->
-%% Res
-%% end.
-
-return_first_error(Status, NewError) when is_list(NewError) ->
- case Status of
- {ok, _Warnings} ->
- {error, NewError};
- {error, OldError} ->
- {error, OldError}
- end.
-
-add_warning(Status, Warning) ->
- case Status of
- {ok, Warnings} ->
- {ok, [Warning | Warnings]};
- {error, Error} ->
- {error, Error}
+add_warning({ok,Warnings}, Warning) ->
+ case lists:member(Warning,Warnings) of
+ true ->
+ {ok,Warnings};
+ false ->
+ {ok,[Warning|Warnings]}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index 2588c0829f..5526df5f52 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -883,8 +883,7 @@ create_standalone_app_clash(Config) ->
]},
?msym({error,"someapp: Application name clash. Escript "++_},
- reltool:get_target_spec([{config,Sys}])),
-
+ reltool:start_server([{config,Sys}])),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1214,7 +1213,7 @@ set_app_and_undo(Config) ->
{app,tools,[{incl_cond,include}]}]},
{ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
?m({ok, Sys}, reltool:get_config(Pid)),
- ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
%% Get app and mod
{ok,Tools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
@@ -1228,7 +1227,7 @@ set_app_and_undo(Config) ->
{ok,ToolsNoCover,["a: Cannot parse app file"++_|_]} =
?msym({ok,_,["a: Cannot parse app file"++_|_]},
reltool_server:set_app(Pid,Tools1)),
- ?msym({ok,["a: Cannot parse app file"++_|_]}, reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_]}, reltool_server:get_status(Pid)),
%% Check that the module is no longer included
?m({ok,ToolsNoCover}, reltool_server:get_app(Pid,tools)),
@@ -1239,13 +1238,13 @@ set_app_and_undo(Config) ->
?m(ok, reltool_server:undo_config(Pid)),
?m({ok,Tools}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover}, reltool_server:get_mod(Pid,cover)),
- ?msym({ok,["a: Cannot parse app file"++_|_]}, reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_]}, reltool_server:get_status(Pid)),
%% Undo again, to check that it toggles
?msym(ok, reltool_server:undo_config(Pid)),
?m({ok,ToolsNoCover}, reltool_server:get_app(Pid,tools)),
?m({ok,NoIncludeCover}, reltool_server:get_mod(Pid,cover)),
- ?msym({ok,["a: Cannot parse app file"++_|_]}, reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_]}, reltool_server:get_status(Pid)),
?m(ok, reltool:stop(Pid)),
ok.
@@ -1261,7 +1260,7 @@ set_apps_and_undo(Config) ->
{app,tools,[{incl_cond,include}]}]},
{ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
?m({ok, Sys}, reltool:get_config(Pid)),
- ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
%% Get app and mod
{ok,Tools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
@@ -1272,9 +1271,9 @@ set_apps_and_undo(Config) ->
%% Exclude one application with set_apps
ExclTools = Tools#app{incl_cond=exclude},
- ?msym({ok,["a: Cannot parse app file"++_|_]},
+ ?msym({ok,["a: Cannot parse app file"++_]},
reltool_server:set_apps(Pid,[ExclTools])),
- ?msym({ok,["a: Cannot parse app file"++_|_]}, reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_]}, reltool_server:get_status(Pid)),
%% Check that the app and its modules (one of them) are no longer included
{ok,NoTools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
@@ -1287,13 +1286,13 @@ set_apps_and_undo(Config) ->
?m(ok, reltool_server:undo_config(Pid)),
?m({ok,Tools}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover}, reltool_server:get_mod(Pid,cover)),
- ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
%% Undo again, to check that it toggles
?m(ok, reltool_server:undo_config(Pid)),
?m({ok,NoTools}, reltool_server:get_app(Pid,tools)),
?m({ok,NoIncludeCover}, reltool_server:get_mod(Pid,cover)),
- ?msym({ok,["a: Cannot parse app file"++_|_]}, reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_]}, reltool_server:get_status(Pid)),
?m(ok, reltool:stop(Pid)),
ok.
@@ -1386,10 +1385,10 @@ set_sys_and_undo(Config) ->
NewLib = filename:join(datadir(Config),"faulty_app_file"),
NewLibDirs = [NewLib | SysRec#sys.lib_dirs],
NewSysRec = SysRec#sys{lib_dirs=NewLibDirs},
- ?msym({ok,["a: Cannot parse app file"++_|_]},
+ ?msym({ok,["a: Cannot parse app file"++_]},
reltool_server:set_sys(Pid, NewSysRec)),
?m({ok,NewSysRec}, reltool_server:get_sys(Pid)),
- ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
%% Undo
?m(ok, reltool_server:undo_config(Pid)),
@@ -1399,7 +1398,7 @@ set_sys_and_undo(Config) ->
%% Undo again, to check that it toggles
?m(ok,reltool_server:undo_config(Pid)),
?m({ok,NewSysRec}, reltool_server:get_sys(Pid)),
- ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
?m(ok, reltool:stop(Pid)),
ok.
@@ -1431,12 +1430,12 @@ load_config_and_undo(Config) ->
{app,sasl,[{incl_cond,include}]},
{app,stdlib,[{incl_cond,include}]},
{app,tools,[{incl_cond,derived}]}]},
- ?msym({ok,["a: Cannot parse app file"++_|_]},
+ ?msym({ok,["a: Cannot parse app file"++_]},
reltool_server:load_config(Pid,Sys2)),
%%% OTP-0702, 15) ?m({ok, Sys2}, reltool:get_config(Pid)),
%%% Note that {incl_cond,exclude} is removed compared to Sys1 -
%%% config is merged, not overwritten - is this correct???
- ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
%% Check that tools is included (since it is used by sasl) but not
%% pre-included (neither included or excluded => undefined)
@@ -1458,7 +1457,7 @@ load_config_and_undo(Config) ->
?m(ok, reltool_server:undo_config(Pid)),
?m({ok,Tools2}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover2}, reltool_server:get_mod(Pid,cover)),
- ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
?m(ok, reltool:stop(Pid)),
ok.
@@ -1487,7 +1486,7 @@ load_config_fail(_Config) ->
{app,kernel,[{incl_cond,include}]},
{app,sasl,[{incl_cond,include}]},
{app,stdlib,[{incl_cond,include}]}]},
- ?msym({error,"Release faulty_rel uses non existing application xxx"},
+ ?msym({error,"Release \"faulty_rel\" uses non existing application xxx"},
reltool_server:load_config(Pid,Sys2)),
%% Check that a rollback is done to the old configuration
@@ -1674,7 +1673,7 @@ reset_config_and_undo(Config) ->
{app,tools,[{incl_cond,include}]}]},
{ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
?m({ok, Sys1}, reltool:get_config(Pid)),
- ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
%% Get app and mod
{ok,Tools1} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
@@ -1704,11 +1703,10 @@ reset_config_and_undo(Config) ->
reltool_server:get_mod(Pid,cover)),
%% Reset
- ?msym({ok,["a: Cannot parse app file"++_|_]},
- reltool_server:reset_config(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:reset_config(Pid)),
?m({ok,Tools1}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover1}, reltool_server:get_mod(Pid,cover)),
- ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
%% Undo
?m(ok, reltool_server:undo_config(Pid)),
@@ -1720,7 +1718,7 @@ reset_config_and_undo(Config) ->
?m(ok, reltool_server:undo_config(Pid)),
?m({ok,Tools1}, reltool_server:get_app(Pid,tools)),
?m({ok,Cover1}, reltool_server:get_mod(Pid,cover)),
- ?msym({ok,["a: Cannot parse app file"++_|_]},reltool_server:get_status(Pid)),
+ ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
?m(ok, reltool:stop(Pid)),
ok.
--
cgit v1.2.3
From 70b56b16177703c4721f9afbb0329b181af1de3e Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Wed, 29 Feb 2012 11:18:08 +0100
Subject: [reltool] Unset ERL_FLAGS when running escript from
reltool_server_SUITE
OTP-9794
Some escript tests in reltool_server_SUITE failed if ERL_FLAGS was set
to enable smp. The reason is that the test expected smp_support to be
false, since the argument "-smp disable" is stated in the %%!-line of
the escript. However, ERL_FLAGS will override the arguments in the
escript so the result could not be truested.
---
lib/reltool/test/reltool_server_SUITE.erl | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index 5526df5f52..c1d568f019 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -2150,7 +2150,9 @@ run(Dir, Opts, Script, Args) ->
do_run(Dir, Cmd) ->
io:format("Run: ~p\n", [Cmd]),
- Env = [{"PATH",Dir++":"++os:getenv("PATH")}],
+ Env = [{"PATH",Dir++":"++os:getenv("PATH")},
+ {"ERL_FLAGS",""}, % Make sure no flags are set that can override
+ {"ERL_ZFLAGS",""}], % any of the flags set in the escript.
Port = open_port({spawn,Cmd}, [exit_status,eof,in,{env,Env}]),
Res = get_data(Port, []),
receive
--
cgit v1.2.3
From a3a7c3590f549c609749cff16da7d00af2c114d3 Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Wed, 29 Feb 2012 15:27:34 +0100
Subject: [reltool] Cleanup test code
OTP-9794
Remove some unused code from reltool test.
---
lib/reltool/test/reltool_server_SUITE.erl | 20 +-----------------
lib/reltool/test/reltool_test_lib.erl | 6 +-----
lib/reltool/test/reltool_test_lib.hrl | 34 +------------------------------
3 files changed, 3 insertions(+), 57 deletions(-)
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index c1d568f019..4b0511afaf 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -104,8 +104,6 @@ end_per_group(_GroupName, Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Start a server process and check that it does not crash
-start_server(TestInfo) when is_atom(TestInfo) ->
- reltool_test_lib:tc_info(TestInfo);
start_server(_Config) ->
{ok, Pid} = ?msym({ok, _}, reltool:start_server([])),
Libs = lists:sort(erl_libs()),
@@ -121,8 +119,6 @@ start_server(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Start a server process and check that it does not crash
-set_config(TestInfo) when is_atom(TestInfo) ->
- reltool_test_lib:tc_info(TestInfo);
set_config(_Config) ->
Libs = lists:sort(erl_libs()),
Default =
@@ -229,8 +225,6 @@ get_config(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% OTP-9135, test that app_file option can be set to all | keep | strip
-otp_9135(TestInfo) when is_atom(TestInfo) ->
- reltool_test_lib:tc_info(TestInfo);
otp_9135(_Config) ->
Libs = lists:sort(erl_libs()),
StrippedDefaultSys =
@@ -260,8 +254,6 @@ otp_9135(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate releases
-create_release(TestInfo) when is_atom(TestInfo) ->
- reltool_test_lib:tc_info(TestInfo);
create_release(_Config) ->
%% Configure the server
RelName = "Just testing...",
@@ -402,8 +394,6 @@ create_release_sort(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate boot scripts
-create_script(TestInfo) when is_atom(TestInfo) ->
- reltool_test_lib:tc_info(TestInfo);
create_script(_Config) ->
%% Configure the server
RelName = "Just testing",
@@ -647,8 +637,6 @@ systools_make_script(Name,Path) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate target system
-create_target(TestInfo) when is_atom(TestInfo) ->
- reltool_test_lib:tc_info(TestInfo);
create_target(_Config) ->
%% Configure the server
RelName1 = "Just testing",
@@ -681,8 +669,6 @@ create_target(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate embedded target system
-create_embedded(TestInfo) when is_atom(TestInfo) ->
- reltool_test_lib:tc_info(TestInfo);
create_embedded(_Config) ->
%% Configure the server
RelName1 = "Just testing",
@@ -714,8 +700,6 @@ create_embedded(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate standalone system
-create_standalone(TestInfo) when is_atom(TestInfo) ->
- reltool_test_lib:tc_info(TestInfo);
create_standalone(_Config) ->
%% Configure the server
ExDir = code:lib_dir(reltool, examples),
@@ -948,10 +932,8 @@ create_multiple_standalone(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate old type of target system
-create_old_target(TestInfo) when is_atom(TestInfo) ->
- reltool_test_lib:tc_info(TestInfo);
+create_old_target(_Config) -> {skip, "Old style of target"};
create_old_target(_Config) ->
- ?skip("Old style of target", []),
%% Configure the server
RelName1 = "Just testing",
diff --git a/lib/reltool/test/reltool_test_lib.erl b/lib/reltool/test/reltool_test_lib.erl
index b8bcbcd009..61f783190c 100644
--- a/lib/reltool/test/reltool_test_lib.erl
+++ b/lib/reltool/test/reltool_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -138,10 +138,6 @@ end_per_testcase(_Func, Config) when is_list(Config) ->
reset_kill_timer(Config),
Config.
-%% Backwards compatible with test_server
-tc_info(suite) -> [];
-tc_info(doc) -> "".
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Use ?log(Format, Args) as wrapper
diff --git a/lib/reltool/test/reltool_test_lib.hrl b/lib/reltool/test/reltool_test_lib.hrl
index b592ebb2f0..0dfc08b81c 100644
--- a/lib/reltool/test/reltool_test_lib.hrl
+++ b/lib/reltool/test/reltool_test_lib.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -18,20 +18,10 @@
-include_lib("wx/include/wx.hrl").
--define(flat_format(Format,Args), lists:flatten(io_lib:format(Format,Args))).
-define(log(Format,Args), reltool_test_lib:log(Format,Args,?FILE,?LINE)).
--define(warning(Format,Args), ?log("\n " ++ Format,Args)).
-define(error(Format,Args), reltool_test_lib:error(Format,Args,?FILE,?LINE)).
-define(verbose(Format,Args), reltool_test_lib:verbose(Format,Args,?FILE,?LINE)).
--define(fatal(Format,Args),
- ?error(Format, Args),
- exit({test_case_fatal, Format, Args, ?FILE, ?LINE})).
-
--define(skip(Format,Args),
- ?warning(Format, Args),
- exit({skipped, ?flat_format(Format, Args)})).
-
-define(ignore(Expr),
fun() ->
AcTuAlReS = (catch (Expr)),
@@ -68,25 +58,3 @@
AcTuAlReS
end
end()).
-
--define(m_receive(ExpectedMsg),
- ?m(ExpectedMsg,reltool_test_lib:pick_msg())).
-
--define(m_multi_receive(ExpectedMsgs),
- fun() ->
- TmPeXpCtEdMsGs = lists:sort(ExpectedMsgs),
- AcTuAlReS =
- lists:sort(lists:map(fun(_) ->
- reltool_test_lib:pick_msg()
- end, TmPeXpCtEdMsGs)),
- case AcTuAlReS of
- TmPeXpCtEdMsGs ->
- ?verbose("ok: ~p\n",[AcTuAlReS]),
- AcTuAlReS;
- _ ->
- reltool_test_lib:error("Not matching actual result was:\n ~p \nExpected ~p\n",
- [AcTuAlReS, ExpectedMsgs],
- ?FILE, ?LINE),
- AcTuAlReS
- end
- end()).
--
cgit v1.2.3
From 2be5415d4a5d024c223d340381ef74e3697fc7ea Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Wed, 29 Feb 2012 16:30:13 +0100
Subject: [reltool] Display warnings continously in GUI
OTP-9967
All active warnings are now displayed in a specific warning list at
the bottom of the sys windows. Warnings do no longer cause popup
dialogs during configuration.
The reason for this is to avoid the same warning to pop up many
times. This would happen since each configuration change now causes a
fresh reading of the file system - and thus each warning would be
detected each time the configuration was changed.
reltool_manual_gui_SUITE is updated to test the new functionality.
---
lib/reltool/src/reltool_sys_win.erl | 207 +++++++++++++++++++++-----
lib/reltool/src/reltool_utils.erl | 12 +-
lib/reltool/test/reltool_manual_gui_SUITE.erl | 48 ++++--
3 files changed, 215 insertions(+), 52 deletions(-)
diff --git a/lib/reltool/src/reltool_sys_win.erl b/lib/reltool/src/reltool_sys_win.erl
index c75b302770..29a01b63d8 100644
--- a/lib/reltool/src/reltool_sys_win.erl
+++ b/lib/reltool/src/reltool_sys_win.erl
@@ -56,7 +56,9 @@
derived,
fgraph_wins,
app_box,
- mod_box
+ mod_box,
+ warning_list,
+ warning_wins
}).
-define(WIN_WIDTH, 800).
@@ -88,6 +90,10 @@
-define(blacklist, "Excluded").
-define(derived, "Derived").
+-define(WARNING_COL, 0).
+-define(DEFAULT_WARNING_TIP, "Warnings are listed in this window").
+-define(WARNING_POPUP_SIZE, {400,150}).
+
-define(safe_config,{sys,[{incl_cond,exclude},
{app,kernel,[{incl_cond,include}]},
{app,stdlib,[{incl_cond,include}]},
@@ -150,7 +156,8 @@ do_init([{safe_config, Safe}, {parent, Parent} | Options]) ->
target_dir = filename:absname("reltool_target_dir"),
app_wins = [],
sys = Sys,
- fgraph_wins = []},
+ fgraph_wins = [],
+ warning_wins = []},
S2 = create_window(S),
S5 = wx:batch(fun() ->
Title = atom_to_list(?APPLICATION),
@@ -235,10 +242,18 @@ loop(S) ->
lists:keydelete(ObjRef, #fgraph_win.frame, FWs),
?MODULE:loop(S#state{fgraph_wins = FWs2});
false ->
- error_logger:format("~p~p got unexpected "
- "message:\n\t~p\n",
- [?MODULE, self(), Msg]),
- ?MODULE:loop(S)
+ WWs = S#state.warning_wins,
+ case lists:member(ObjRef, WWs) of
+ true ->
+ wxFrame:destroy(ObjRef),
+ WWs2 = lists:delete(ObjRef, WWs),
+ ?MODULE:loop(S#state{warning_wins = WWs2});
+ false ->
+ error_logger:format("~p~p got unexpected "
+ "message:\n\t~p\n",
+ [?MODULE, self(), Msg]),
+ ?MODULE:loop(S)
+ end
end
end;
#wx{id = ?CLOSE_ITEM,
@@ -292,8 +307,8 @@ handle_child_exit({'EXIT', Pid, _Reason} = Exit, FWs, AWs) ->
msg_warning(Exit, application_window),
{FWs, lists:keydelete(Pid, #app_win.pid, AWs)};
false ->
- msg_warning(Exit, unknown),
- {FWs, AWs}
+ msg_warning(Exit, unknown),
+ {FWs, AWs}
end
end.
@@ -335,8 +350,12 @@ create_window(S) ->
fun create_main_release_page/1,
fun create_config_page/1
]),
+
+ S4 = create_warning_list(S3),
+
Sizer = wxBoxSizer:new(?wxVERTICAL),
wxSizer:add(Sizer, Book, [{flag, ?wxEXPAND}, {proportion, 1}]),
+ wxSizer:add(Sizer, S4#state.warning_list, [{flag, ?wxEXPAND}]),
wxPanel:setSizer(Panel, Sizer),
wxSizer:fit(Sizer, Frame),
@@ -344,7 +363,7 @@ create_window(S) ->
wxFrame:connect(Frame, close_window),
wxFrame:show(Frame),
- S3.
+ S4.
create_menubar(Frame) ->
MenuBar = wxMenuBar:new(),
@@ -637,6 +656,48 @@ redraw_config_page(#state{sys = Sys, app_box = AppBox, mod_box = ModBox} = S) ->
wxRadioBox:setSelection(ModBox, ModChoice),
S.
+create_warning_list(#state{panel = Panel} = S) ->
+ ListCtrl = wxListCtrl:new(Panel,
+ [{style,
+ ?wxLC_REPORT bor
+ ?wxLC_HRULES bor
+ ?wxVSCROLL},
+ {size, {?WIN_WIDTH,80}}]),
+ reltool_utils:assign_image_list(ListCtrl),
+ wxListCtrl:insertColumn(ListCtrl, ?WARNING_COL, "Warnings",
+ [{format,?wxLIST_FORMAT_LEFT}]),
+ wxListCtrl:setToolTip(ListCtrl, ?DEFAULT_WARNING_TIP),
+ wxEvtHandler:connect(ListCtrl, size,
+ [{skip, true}, {userData, warnings}]),
+ wxEvtHandler:connect(ListCtrl, command_list_item_activated,
+ [{userData, warnings}]),
+ wxEvtHandler:connect(ListCtrl, motion, [{userData, warnings}]),
+ wxEvtHandler:connect(ListCtrl, enter_window),
+ S#state{warning_list=ListCtrl}.
+
+redraw_warnings(S) ->
+ {ok,Warnings} = reltool_server:get_status(S#state.server_pid),
+ redraw_warnings(S#state.warning_list,Warnings),
+ length(Warnings).
+
+redraw_warnings(ListCtrl, []) ->
+ wxListCtrl:deleteAllItems(ListCtrl),
+ ok;
+redraw_warnings(ListCtrl, Warnings) ->
+ wxListCtrl:deleteAllItems(ListCtrl),
+ Show = fun(Warning, Row) ->
+ wxListCtrl:insertItem(ListCtrl, Row, ""),
+ wxListCtrl:setItem(ListCtrl,
+ Row,
+ ?WARNING_COL,
+ Warning,
+ [{imageId, ?WARN_IMAGE}]),
+ Row + 1
+ end,
+ wx:foldl(Show, 0, Warnings),
+ ok.
+
+
create_main_release_page(#state{book = Book} = S) ->
Panel = wxPanel:new(Book, []),
RelBook = wxNotebook:new(Panel, ?wxID_ANY, []),
@@ -778,6 +839,9 @@ escript_popup(S, File, Tree, Item) ->
handle_event(S, #wx{id = Id, obj= ObjRef, userData = UserData, event = Event} = _Wx) ->
%% io:format("wx: ~p\n", [Wx]),
case Event of
+ _ when UserData =:= warnings;
+ is_tuple(UserData), element(1,UserData)=:=warning ->
+ handle_warning_event(S, ObjRef, UserData, Event);
#wxSize{type = size, size = {W, _H}} when UserData =:= app_list_ctrl ->
wxListCtrl:setColumnWidth(ObjRef, ?APPS_APP_COL, W),
S;
@@ -855,6 +919,78 @@ handle_event(S, #wx{id = Id, obj= ObjRef, userData = UserData, event = Event} =
end
end.
+handle_warning_event(S, ObjRef, _, #wxSize{type = size}) ->
+ {Total, _} = wxWindow:getClientSize(ObjRef),
+ SBSize = scroll_size(ObjRef),
+ wxListCtrl:setColumnWidth(ObjRef, ?WARNING_COL, Total-SBSize),
+ S;
+handle_warning_event(S, ObjRef, _, #wxMouse{type = motion, x=X, y=Y}) ->
+ Pos = reltool_utils:wait_for_stop_motion(ObjRef, {X,Y}),
+ Index = wxListCtrl:findItem(ObjRef,-1,Pos,0),
+ Tip =
+ case wxListCtrl:getItemText(ObjRef,Index) of
+ "" ->
+ ?DEFAULT_WARNING_TIP;
+ Text ->
+ "WARNING:\n" ++ Text
+ end,
+ wxListCtrl:setToolTip(ObjRef, Tip),
+ S;
+handle_warning_event(S, ObjRef, _, #wxList{type = command_list_item_activated,
+ itemIndex = Pos}) ->
+ Text = wxListCtrl:getItemText(ObjRef, Pos),
+ S#state{warning_wins = [display_warning(S,Text) | S#state.warning_wins]};
+handle_warning_event(S, _ObjRef, {warning,Frame},
+ #wxCommand{type = command_button_clicked}) ->
+ wxFrame:destroy(Frame),
+ S#state{warning_wins = lists:delete(Frame,S#state.warning_wins)}.
+
+
+display_warning(S,Warning) ->
+ Pos = warning_popup_position(S,?WARNING_POPUP_SIZE),
+ Frame = wxFrame:new(wx:null(), ?wxID_ANY, "Warning",[{pos,Pos}]),
+ Panel = wxPanel:new(Frame, []),
+ TextStyle = ?wxTE_READONLY bor ?wxTE_WORDWRAP bor ?wxTE_MULTILINE,
+ Text = wxTextCtrl:new(Panel, ?wxID_ANY, [{value, Warning},
+ {style, TextStyle},
+ {size, ?WARNING_POPUP_SIZE}]),
+ Color = wxWindow:getBackgroundColour(Frame),
+ wxTextCtrl:setBackgroundColour(Text,Color),
+ Attr = wxTextAttr:new(),
+ wxTextAttr:setLeftIndent(Attr,10),
+ wxTextAttr:setRightIndent(Attr,10),
+ true = wxTextCtrl:setDefaultStyle(Text, Attr),
+ wxTextAttr:destroy(Attr),
+ Sizer = wxBoxSizer:new(?wxVERTICAL),
+ wxSizer:add(Sizer, Text, [{border, 2},
+ {flag, ?wxEXPAND bor ?wxALL},
+ {proportion, 1}]),
+
+ Close = wxButton:new(Panel, ?wxID_ANY, [{label, "Close"}]),
+ wxButton:setToolTip(Close, "Close window."),
+ wxButton:connect(Close, command_button_clicked, [{userData,{warning,Frame}}]),
+ wxSizer:add(Sizer, Close, [{flag, ?wxALIGN_CENTER_HORIZONTAL}]),
+
+ wxPanel:setSizer(Panel, Sizer),
+ wxSizer:fit(Sizer, Frame),
+ wxSizer:setSizeHints(Sizer, Frame),
+ wxFrame:connect(Frame, close_window),
+
+ wxFrame:show(Frame),
+ Frame.
+
+warning_popup_position(#state{frame=MF,warning_list=WL},{WFW,WFH}) ->
+ {MFX,MFY} = wxWindow:getPosition(MF),
+ {MFW,MFH} = wxWindow:getSize(MF),
+ {_WLW,WLH} = wxWindow:getSize(WL),
+
+ %% Position the popup in the middle of the main frame, above the
+ %% warning list, and with a small offset from the exact middle...
+ Offset = 50,
+ X = MFX + (MFW-WFW) div 2 - Offset,
+ Y = MFY + (MFH-WLH-WFH) div 2 - Offset,
+ {X,Y}.
+
handle_popup_event(S, _Type, 0, _ObjRef, _UserData, _Str) ->
S#state{popup_menu = undefined};
handle_popup_event(#state{popup_menu = #root_popup{dir = OldDir,
@@ -1079,11 +1215,8 @@ handle_app_button(#state{server_pid = ServerPid, app_wins = AppWins} = S,
Action) ->
NewApps = [move_app(S, Item, Action) || Item <- Items],
case reltool_server:set_apps(ServerPid, NewApps) of
- {ok, []} ->
+ {ok, _Warnings} ->
ok;
- {ok, Warnings} ->
- Msg = lists:flatten([[W, $\n] || W <- Warnings]),
- display_message(Msg, ?wxICON_WARNING);
{error, Reason} ->
display_message(Reason, ?wxICON_ERROR)
end,
@@ -1122,21 +1255,17 @@ move_app(S, {_ItemNo, AppBase}, Action) ->
do_set_app(#state{server_pid = ServerPid, app_wins = AppWins} = S, NewApp) ->
Result = reltool_server:set_app(ServerPid, NewApp),
- [ok = reltool_app_win:refresh(AW#app_win.pid) || AW <- AppWins],
- S2 = redraw_apps(S),
ReturnApp =
case Result of
- {ok, AnalysedApp, []} ->
- AnalysedApp;
- {ok, AnalysedApp, Warnings} ->
- Msg = lists:flatten([[W, $\n] || W <- Warnings]),
- display_message(Msg, ?wxICON_WARNING),
+ {ok, AnalysedApp, _Warnings} ->
AnalysedApp;
{error, Reason} ->
display_message(Reason, ?wxICON_ERROR),
{ok,OldApp} = reltool_server:get_app(ServerPid, NewApp#app.name),
OldApp
end,
+ [ok = reltool_app_win:refresh(AW#app_win.pid) || AW <- AppWins],
+ S2 = redraw_apps(S),
{ok, ReturnApp, S2}.
redraw_apps(#state{server_pid = ServerPid,
@@ -1159,8 +1288,14 @@ redraw_apps(#state{server_pid = ServerPid,
WhiteN = redraw_apps(WhiteApps, WhiteCtrl, ?TICK_IMAGE, ?ERR_IMAGE),
redraw_apps(BlackApps2, BlackCtrl, ?CROSS_IMAGE, ?WARN_IMAGE),
DerivedN = redraw_apps(DerivedApps, DerivedCtrl, ?TICK_IMAGE, ?ERR_IMAGE),
+
+ WarningsN = redraw_warnings(S),
+ WarningText = if WarningsN==1 -> "warning";
+ true -> "warnings"
+ end,
Status = lists:concat([WhiteN, " whitelisted modules and ",
- DerivedN, " derived modules."]),
+ DerivedN, " derived modules, ",
+ WarningsN, " ", WarningText, "."]),
wxStatusBar:setStatusText(S#state.status_bar, Status),
S.
@@ -1375,8 +1510,8 @@ check_and_refresh(S, Status) ->
case Status of
ok ->
true;
- {ok, Warnings} ->
- undo_dialog(S, Warnings);
+ {ok, _Warnings} ->
+ true;
{error, Reason} when is_list(Reason) ->
display_message(Reason, ?wxICON_ERROR),
false;
@@ -1430,19 +1565,6 @@ question_dialog(Question, Details) ->
wxDialog:destroy(Dialog),
Answer.
-undo_dialog(_S, []) ->
- true;
-undo_dialog(S, Warnings) ->
- Question = "Do you want to perform the update despite these warnings?",
- Details = lists:flatten([[W, $\n] || W <- Warnings]),
- case question_dialog(Question, Details) of
- ?wxID_OK ->
- true;
- ?wxID_CANCEL ->
- ok = reltool_server:undo_config(S#state.server_pid),
- false
- end.
-
display_message(Message, Icon) ->
Dialog = wxMessageDialog:new(wx:null(),
Message,
@@ -1486,6 +1608,19 @@ add_text(_,_,[]) ->
ok.
+scroll_size(ObjRef) ->
+ case os:type() of
+ {win32, nt} -> 0;
+ {unix, darwin} ->
+ %% I can't figure out is there is a visible scrollbar
+ %% Always make room for it
+ wxSystemSettings:getMetric(?wxSYS_VSCROLL_X);
+ _ ->
+ case wxWindow:hasScrollbar(ObjRef, ?wxVERTICAL) of
+ true -> wxSystemSettings:getMetric(?wxSYS_VSCROLL_X);
+ false -> 0
+ end
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/reltool/src/reltool_utils.erl b/lib/reltool/src/reltool_utils.erl
index a9107355c7..2d766224d9 100644
--- a/lib/reltool/src/reltool_utils.erl
+++ b/lib/reltool/src/reltool_utils.erl
@@ -23,7 +23,7 @@
split_app_name/1, prim_consult/1,
default_rels/0, choose_default/3,
- assign_image_list/1, get_latest_resize/1,
+ assign_image_list/1, get_latest_resize/1, wait_for_stop_motion/2,
mod_conds/0, list_to_mod_cond/1, mod_cond_to_index/1,
incl_conds/0, list_to_incl_cond/1, incl_cond_to_index/1, elem_to_index/2,
app_dir_test/2, split_app_dir/1,
@@ -191,6 +191,16 @@ get_latest_resize(#wx{obj = ObjRef, event = #wxSize{}} = Wx) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+wait_for_stop_motion(ObjRef, {_,_}=Pos) ->
+ receive
+ #wx{obj = ObjRef, event = #wxMouse{type = motion, x=X, y=Y}} ->
+ wait_for_stop_motion(ObjRef, {X,Y})
+ after 100 ->
+ Pos
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
mod_conds() ->
["all (ebin + app file)", "ebin + derived", "app file + derived", "derived", "none"].
diff --git a/lib/reltool/test/reltool_manual_gui_SUITE.erl b/lib/reltool/test/reltool_manual_gui_SUITE.erl
index c6b1d56988..1ebee9fae1 100644
--- a/lib/reltool/test/reltool_manual_gui_SUITE.erl
+++ b/lib/reltool/test/reltool_manual_gui_SUITE.erl
@@ -67,37 +67,49 @@ config(Config) ->
SimpleConfigFile = create_simple_config(PrivDir),
WarningConfigFile = create_warning_config(PrivDir,DataDir),
- break("there are no modules in the 'Included' and 'Excluded' columns",
+ break("there are no modules in the 'Included' and 'Excluded' columns, "
+ "and now warnings are displayed",
{"load configuration ~p",[SimpleConfigFile]}),
break("kernel, stdlib and sasl are included and all other are excluded",
"undo"),
break("we are back to default - no included and no excluded applications",
"undo again"),
break("kernel, stdlib and sasl are included and all other are excluded",
- {"load configuration ~p, but click 'cancel' in the warning dialog",
+ {"load configuration ~p",
[WarningConfigFile]}),
- break("no change is done",
- "load same configuration again and this time click 'ok' in the dialog"),
- break("application a is added in the 'Included' column",
+ break("a warning is displayed in the warning list",
+ "undo"),
+ break("no warning is displayed in the warning list",
+ "load same configuration again"),
+ break("application a is added in the 'Included' column and "
+ "one warning is displayed",
"reset configuration"),
- break("we are back to default - no included and no excluded applications",
+ break("we are back to default - no included and no excluded applications, "
+ "and no warnings",
"undo"),
- break("a warning dialog is displayed, with only an ok button",
- "click ok"),
- break("a, kernel, stdlib and sasl are included and all other are excluded",
+ break("a, kernel, stdlib and sasl are included and all other are excluded. "
+ "One warning should now exist through the rest of this test case",
+ "double click the warning"),
+ break("a popup window occurs displaying the warning text",
+ "close it with the 'Close' button"),
+ break("it disappears",
+ "open it again"),
+ break("the warning text can be marked, copied and pasted",
+ "close the popup with the close box on the top frame"),
+ break("it disappears",
"select application a from 'Included' column and click red cross to "
"exclude it"),
break("application a is moved to 'Excluded' column",
"select application tools from 'Excluded' column and click green V to "
"include it"),
break("application tools is moved to 'Included' column",
- "select application runtime-tools from 'Excluded' column and click "
+ "select application runtime_tools from 'Excluded' column and click "
"green V to include it"),
- break("application runtime-tools is moved to 'Included' column",
+ break("application runtime_tools is moved to 'Included' column",
"undo"),
ExplicitConfig = filename:join(PrivDir,"explicit.config"),
- break("application runtime-tools is moved back to 'Excluded' column",
+ break("application runtime_tools is moved back to 'Excluded' column",
{"save configuration as 'explicit' to ~p",[ExplicitConfig]}),
ExpectedExplicitConfig =
{sys,[{lib_dirs,[filename:join(DataDir,"faulty_app_file")]},
@@ -113,7 +125,7 @@ config(Config) ->
"Now go to the 'Libraries' tab and change the root directory to "
"some invalid directory."),
break("an error dialog occurs saying that there is no lib dir",
- {"add library directory ~p, and click 'ok' in warning dialog",
+ {"add library directory ~p",
[filename:join(DataDir,"dependencies")]}),
break("applications x, y and z are added to the 'Excluded' column in "
"'Applications' tab",
@@ -121,7 +133,7 @@ config(Config) ->
"to 'derived'"),
break("a is excluded, kernel, stdlib, sasl and tools are included and "
"x, y and z are available in the 'Applications' tab",
- "undo, and click ok in the warning dialog"),
+ "undo"),
break("all non included application are moved to the 'Excluded' column "
"and that 'Application inclusion policy' under 'System settings' "
"tab is set back to 'exclude'",
@@ -218,7 +230,13 @@ break(Check,Do) ->
break(CheckStr,DoStr).
break(Str) ->
- test_server:break(Str).
+ Count =
+ case get(count) of
+ undefined -> 1;
+ C -> C
+ end,
+ put(count,Count+1),
+ test_server:break("Step " ++ integer_to_list(Count) ++ ":\n" ++ Str).
check_config(Expected,File) ->
{ok,[Config]} = file:consult(File),
--
cgit v1.2.3
From 3f42375bbfc1657963f1d3aa7688f2ab67f31c1b Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Thu, 8 Mar 2012 11:03:02 +0100
Subject: [reltool] Move tables out of common record
OTP-9794
This is a minor change, in order to keep tables private to
reltool_server.
---
lib/reltool/src/reltool.hrl | 7 +-
lib/reltool/src/reltool_server.erl | 273 ++++++++++++++++++-------------------
2 files changed, 134 insertions(+), 146 deletions(-)
diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl
index 781c3f6d2c..d3eefb7ff0 100644
--- a/lib/reltool/src/reltool.hrl
+++ b/lib/reltool/src/reltool.hrl
@@ -127,12 +127,7 @@
{
sys_debug :: term(),
wx_debug :: term(),
- trap_exit :: boolean(),
- app_tab :: ets:tab(),
- mod_tab :: ets:tab(),
- mod_used_by_tab :: ets:tab(),
- old_app_tab :: ets:tab(),
- old_mod_tab :: ets:tab()
+ trap_exit :: boolean()
}).
-record(mod,
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index 4c22898559..90fc6a8c28 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -51,7 +51,12 @@
sys,
old_sys,
status,
- old_status}).
+ old_status,
+ app_tab,
+ old_app_tab,
+ mod_tab,
+ old_mod_tab,
+ mod_used_by_tab}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Client
@@ -134,35 +139,34 @@ init([{parent,Parent}|_] = Options) ->
end.
do_init(Options) ->
- AppTab = ets:new(reltool_apps, [public, ordered_set, {keypos, #app.name}]),
- ModTab = ets:new(reltool_mods, [public, ordered_set, {keypos, #mod.name}]),
- OldAppTab = ets:new(reltool_apps, [public, ordered_set, {keypos, #app.name}]),
- OldModTab = ets:new(reltool_mods, [public, ordered_set, {keypos, #mod.name}]),
+ AppTab = ets:new(reltool_apps1, [public, ordered_set, {keypos,#app.name}]),
+ OldAppTab = ets:new(reltool_apps2, [public, ordered_set, {keypos,#app.name}]),
+ ModTab = ets:new(reltool_mods1, [public, ordered_set, {keypos,#mod.name}]),
+ OldModTab = ets:new(reltool_mods2, [public, ordered_set, {keypos,#mod.name}]),
ModUsesTab = ets:new(reltool_mod_uses, [public, bag, {keypos, 1}]),
- InitialC = #common{app_tab = AppTab,
- mod_tab = ModTab,
- old_app_tab = OldAppTab,
- old_mod_tab = OldModTab,
- mod_used_by_tab = ModUsesTab},
-
- S = parse_options(InitialC, Options),
- {S2, Apps, Status2} = refresh(S),
- Status3 = analyse(S2, Apps, Status2),
+ S = #state{options = Options,
+ app_tab = AppTab,
+ old_app_tab = OldAppTab,
+ mod_tab = ModTab,
+ old_mod_tab = OldModTab,
+ mod_used_by_tab = ModUsesTab},
+
+ S2 = parse_options(S),
+ {S3, Apps, Status2} = refresh(S2),
+ Status3 = analyse(S3, Apps, Status2),
%% Set old_xxx equal to xxx to allow undo=nop
- FakeBackup = {ets:tab2list((S2#state.common)#common.app_tab),
- ets:tab2list((S2#state.common)#common.mod_tab)},
- S3 = save_old(S2, S2, FakeBackup, Status3),
- #state{parent_pid = Parent, sys=Sys, common=C} = S3,
+ FakeBackup = {ets:tab2list(S3#state.app_tab),ets:tab2list(S3#state.mod_tab)},
+ S4 = save_old(S3, S3, FakeBackup, Status3),
+ #state{parent_pid = Parent, sys=Sys, common=C} = S4,
proc_lib:init_ack(Parent, {ok, self(), C, Sys#sys{apps=undefined}}),
- loop(S3).
+ loop(S4).
-parse_options(C, Opts) ->
+parse_options(S) ->
Sys = default_sys(),
- C2 = C#common{sys_debug = [],
- wx_debug = 0,
- trap_exit = true},
- S = #state{options = Opts},
- parse_options(Opts, S, C2, Sys).
+ C = #common{sys_debug = [],
+ wx_debug = 0,
+ trap_exit = true},
+ parse_options(S#state.options, S, C, Sys).
default_sys() ->
#sys{root_dir = reltool_utils:root_dir(),
@@ -227,14 +231,14 @@ parse_options([], S, C, Sys) ->
parse_options(KeyVals, _S, _C, _Sys) ->
reltool_utils:throw_error("Illegal option: ~p", [KeyVals]).
-loop(#state{common = C, sys = Sys} = S) ->
+loop(#state{sys = Sys} = S) ->
receive
{system, From, Msg} ->
sys:handle_system_msg(Msg,
From,
S#state.parent_pid,
?MODULE,
- C#common.sys_debug,
+ (S#state.common)#common.sys_debug,
S);
{call, ReplyTo, Ref, {get_config, InclDef, InclDeriv}} ->
Reply = do_get_config(S, InclDef, InclDeriv),
@@ -250,41 +254,38 @@ loop(#state{common = C, sys = Sys} = S) ->
reltool_utils:reply(ReplyTo, Ref, Reply),
?MODULE:loop(S);
{call, ReplyTo, Ref, reset_config} ->
- Fun = fun() -> parse_options(C, S#state.options) end,
+ Fun = fun() -> parse_options(S) end,
{S3, Status2} = config_and_refresh(S, Fun),
reltool_utils:reply(ReplyTo, Ref, Status2),
?MODULE:loop(S3);
{call, ReplyTo, Ref, undo_config} ->
- C2 = C#common{app_tab = C#common.old_app_tab,
- old_app_tab = C#common.app_tab,
- mod_tab = C#common.old_mod_tab,
- old_mod_tab = C#common.mod_tab},
- S2 = S#state{common = C2,
- sys = S#state.old_sys,
+ S2 = S#state{sys = S#state.old_sys,
old_sys = Sys,
status = S#state.old_status,
- old_status = S#state.status},
+ old_status = S#state.status,
+ app_tab = S#state.old_app_tab,
+ old_app_tab = S#state.app_tab,
+ mod_tab = S#state.old_mod_tab,
+ old_mod_tab = S#state.mod_tab},
reltool_utils:reply(ReplyTo, Ref, ok),
?MODULE:loop(S2);
{call, ReplyTo, Ref, {get_rel, RelName}} ->
- Sys = S#state.sys,
Reply =
case lists:keysearch(RelName, #rel.name, Sys#sys.rels) of
{value, Rel} ->
- reltool_target:gen_rel(Rel, sys_all_apps(C,Sys));
+ reltool_target:gen_rel(Rel, sys_all_apps(S));
false ->
{error, "No such release: " ++ RelName}
end,
reltool_utils:reply(ReplyTo, Ref, Reply),
?MODULE:loop(S);
{call, ReplyTo, Ref, {get_script, RelName}} ->
- Sys = S#state.sys,
Reply =
case lists:keysearch(RelName, #rel.name, Sys#sys.rels) of
{value, Rel} ->
PathFlag = true,
Vars = [],
- reltool_target:gen_script(Rel, sys_all_apps(C,Sys),
+ reltool_target:gen_script(Rel, sys_all_apps(S),
PathFlag, Vars);
false ->
{error, "No such release: " ++ RelName}
@@ -293,7 +294,7 @@ loop(#state{common = C, sys = Sys} = S) ->
?MODULE:loop(S);
{call, ReplyTo, Ref, {get_mod, ModName}} ->
Reply =
- case ets:lookup(C#common.mod_tab, ModName) of
+ case ets:lookup(S#state.mod_tab, ModName) of
[M] ->
{ok, M};
[] ->
@@ -303,7 +304,7 @@ loop(#state{common = C, sys = Sys} = S) ->
?MODULE:loop(S);
{call, ReplyTo, Ref, {get_app, AppName}} when is_atom(AppName) ->
Reply =
- case ets:lookup(C#common.app_tab,AppName) of
+ case ets:lookup(S#state.app_tab,AppName) of
[App] ->
{ok, App};
[] ->
@@ -318,7 +319,7 @@ loop(#state{common = C, sys = Sys} = S) ->
Reply =
case Status2 of
{ok, Warnings} ->
- [App2] = ets:lookup(C#common.app_tab,App#app.name),
+ [App2] = ets:lookup(S3#state.app_tab,App#app.name),
{ok, App2, Warnings};
{error, _} ->
Status2
@@ -330,19 +331,19 @@ loop(#state{common = C, sys = Sys} = S) ->
case Kind of
whitelist ->
%% Pre-included
- ets:select(C#common.app_tab,
+ ets:select(S#state.app_tab,
[{#app{is_pre_included=true,_='_'},
[],
['$_']}]);
blacklist ->
%% Pre-excluded
- ets:select(C#common.app_tab,
+ ets:select(S#state.app_tab,
[{#app{is_pre_included=false,_='_'},
[],
['$_']}]);
source ->
%% Not included and not pre-excluded
- ets:select(C#common.app_tab,
+ ets:select(S#state.app_tab,
[{#app{is_included='$1',
is_pre_included='$2',
_='_'},
@@ -351,7 +352,7 @@ loop(#state{common = C, sys = Sys} = S) ->
['$_']}]);
derived ->
%% Included, but not pre-included
- ets:select(C#common.app_tab,
+ ets:select(S#state.app_tab,
[{#app{is_included='$1',
is_pre_included='$2',
_='_'},
@@ -379,7 +380,7 @@ loop(#state{common = C, sys = Sys} = S) ->
?MODULE:loop(S);
{call, ReplyTo, Ref, {gen_rel_files, Dir}} ->
Status =
- case reltool_target:gen_rel_files(sys_all_apps(C,Sys), Dir) of
+ case reltool_target:gen_rel_files(sys_all_apps(S), Dir) of
ok ->
{ok, []};
{error, Reason} ->
@@ -388,11 +389,11 @@ loop(#state{common = C, sys = Sys} = S) ->
reltool_utils:reply(ReplyTo, Ref, Status),
?MODULE:loop(S);
{call, ReplyTo, Ref, {gen_target, Dir}} ->
- Reply = reltool_target:gen_target(sys_all_apps(C,Sys), Dir),
+ Reply = reltool_target:gen_target(sys_all_apps(S), Dir),
reltool_utils:reply(ReplyTo, Ref, Reply),
?MODULE:loop(S);
{call, ReplyTo, Ref, gen_spec} ->
- Reply = reltool_target:gen_spec(sys_all_apps(C,Sys)),
+ Reply = reltool_target:gen_spec(sys_all_apps(S)),
reltool_utils:reply(ReplyTo, Ref, Reply),
?MODULE:loop(S);
{'EXIT', Pid, Reason} when Pid =:= S#state.parent_pid ->
@@ -510,7 +511,7 @@ mod_set_config_only(ConfigMods) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-analyse(#state{common=C, sys=Sys}, Apps, Status) ->
+analyse(#state{sys=Sys} = S, Apps, Status) ->
%% Create a list of {RelName,AppName}, one element for each
%% AppName that needs to be included for the given release.
RelApps = apps_in_rels(Sys#sys.rels, Apps),
@@ -522,16 +523,16 @@ analyse(#state{common=C, sys=Sys}, Apps, Status) ->
%% are no duplicated module names (in different applications)
%% where we can not decide which one to use.
%% Write all #app to app_tab and all #mod to mod_tab.
- Status2 = apps_init_is_included(C, Sys, Apps, RelApps, Status),
+ Status2 = apps_init_is_included(S, Apps, RelApps, Status),
%% For each module that has #mod.is_included==true, propagate
%% is_included to the modules it uses.
- propagate_is_included(C, Sys),
+ propagate_is_included(S),
%% Insert reverse dependencies - i.e. for each
%% #mod{name=Mod, uses_mods=[UsedMod]},
%% insert an entry {UsedMod,Mod} in mod_used_by_tab.
- propagate_is_used_by(C),
+ propagate_is_used_by(S),
%% Set the above reverse dependencies in #mod records
%% (used_by_mods) and accumulate in #app records.
@@ -539,13 +540,13 @@ analyse(#state{common=C, sys=Sys}, Apps, Status) ->
%% #mod.is_included==true for at least one module in the app.
%% Set status=missing|ok for #app and #mod - indicates if module
%% (.beam file) is missing in file system.
- app_recap_dependencies(C),
+ app_recap_dependencies(S),
%% Check that the boot_rel exists.
%% Check that all applications that are listed in a 'rel' spec are
%% also really included in the target release.
%% Check that all mandatory applications are included in all rels.
- verify_config(C, Sys, RelApps, Status2).
+ verify_config(S, RelApps, Status2).
apps_in_rels(Rels, Apps) ->
AllRelApps =
@@ -585,15 +586,14 @@ more_apps_in_rels([], _Apps, Acc) ->
Acc.
-apps_init_is_included(C, Sys, Apps, RelApps, Status) ->
+apps_init_is_included(S, Apps, RelApps, Status) ->
lists:foldl(fun(App, AccStatus) ->
- app_init_is_included(C, Sys, App, RelApps, AccStatus)
+ app_init_is_included(S, App, RelApps, AccStatus)
end,
Status,
Apps).
-app_init_is_included(C,
- Sys,
+app_init_is_included(#state{app_tab = AppTab, mod_tab = ModTab, sys=Sys},
#app{name = AppName, mods = Mods} = A,
RelApps,
Status) ->
@@ -624,7 +624,7 @@ app_init_is_included(C,
{true, undefined, true, Status}
end,
{Mods2,Status3} = lists:mapfoldl(fun(Mod,Acc) ->
- mod_init_is_included(C,
+ mod_init_is_included(ModTab,
Mod,
ModCond,
AppCond,
@@ -637,10 +637,10 @@ app_init_is_included(C,
is_pre_included = IsPreIncl,
is_included = IsIncl,
rels = Rels},
- ets:insert(C#common.app_tab, A2),
+ ets:insert(AppTab, A2),
Status3.
-mod_init_is_included(C, M, ModCond, AppCond, Default, Status) ->
+mod_init_is_included(ModTab, M, ModCond, AppCond, Default, Status) ->
%% print(M#mod.name, hipe, "incl_cond -> ~p\n", [AppCond]),
IsIncl =
case AppCond of
@@ -677,7 +677,7 @@ mod_init_is_included(C, M, ModCond, AppCond, Default, Status) ->
M2 = M#mod{is_pre_included = IsIncl, is_included = IsIncl},
Status2 =
- case ets:lookup(C#common.mod_tab,M#mod.name) of
+ case ets:lookup(ModTab,M#mod.name) of
[Existing] ->
case {Existing#mod.is_included,IsIncl} of
{false,_} ->
@@ -688,7 +688,7 @@ mod_init_is_included(C, M, ModCond, AppCond, Default, Status) ->
" and ", M#mod.app_name,
". Using module from application ",
M#mod.app_name, "."]),
- ets:insert(C#common.mod_tab, M2),
+ ets:insert(ModTab, M2),
reltool_utils:add_warning(Status,Warning);
{_,false} ->
Warning =
@@ -699,7 +699,7 @@ mod_init_is_included(C, M, ModCond, AppCond, Default, Status) ->
". Using module from application ",
Existing#mod.app_name, "."]),
- %% Don't insert in mod_tab - using Existing
+ %% Don't insert in ModTab - using Existing
reltool_utils:add_warning(Status,Warning);
{_,_} ->
reltool_utils:throw_error(
@@ -708,7 +708,7 @@ mod_init_is_included(C, M, ModCond, AppCond, Default, Status) ->
[M#mod.name,Existing#mod.app_name,M#mod.app_name])
end;
[] ->
- ets:insert(C#common.mod_tab, M2),
+ ets:insert(ModTab, M2),
Status
end,
@@ -723,20 +723,20 @@ false_to_undefined(Bool) ->
%% Return the list for {ModName, UsesModNames} for all modules where
%% #mod.is_included==true.
-get_all_mods_and_dependencies(C) ->
- ets:select(C#common.mod_tab, [{#mod{name='$1',
- uses_mods='$2',
- is_included=true,
- _='_'},
- [],
- [{{'$1','$2'}}]}]).
-
-propagate_is_included(C, Sys) ->
+get_all_mods_and_dependencies(S) ->
+ ets:select(S#state.mod_tab, [{#mod{name='$1',
+ uses_mods='$2',
+ is_included=true,
+ _='_'},
+ [],
+ [{{'$1','$2'}}]}]).
+
+propagate_is_included(S) ->
case lists:flatmap(
fun({ModName,UsesModNames}) ->
- mod_mark_is_included(C,Sys,ModName,UsesModNames,[])
+ mod_mark_is_included(S,ModName,UsesModNames,[])
end,
- get_all_mods_and_dependencies(C)) of
+ get_all_mods_and_dependencies(S)) of
[] ->
ok;
MissingMods ->
@@ -746,13 +746,14 @@ propagate_is_included(C, Sys) ->
mods = MissingMods,
status = missing,
uses_mods = []},
- ets:insert(C#common.app_tab, MissingApp2),
+ ets:insert(S#state.app_tab, MissingApp2),
ok
end.
-mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) ->
+mod_mark_is_included(#state{app_tab=AppTab, mod_tab=ModTab, sys=Sys} = S,
+ UsedByName, [ModName | ModNames], Acc) ->
Acc3 =
- case ets:lookup(C#common.mod_tab, ModName) of
+ case ets:lookup(ModTab, ModName) of
[M] ->
case M#mod.is_included of
undefined ->
@@ -768,8 +769,8 @@ mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) ->
undefined ->
M#mod{is_included = true}
end,
- ets:insert(C#common.mod_tab, M2),
- [A] = ets:lookup(C#common.app_tab, M2#mod.app_name),
+ ets:insert(ModTab, M2),
+ [A] = ets:lookup(AppTab, M2#mod.app_name),
Acc2 =
case A#app.is_included of
undefined ->
@@ -790,9 +791,8 @@ mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) ->
end,
Mods = lists:filter(Filter, A#app.mods),
A2 = A#app{is_included = true},
- ets:insert(C#common.app_tab, A2),
- mod_mark_is_included(C,
- Sys,
+ ets:insert(AppTab, A2),
+ mod_mark_is_included(S,
ModName,
[M3#mod.name ||
M3 <- Mods],
@@ -801,11 +801,7 @@ mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) ->
%% Already marked true or false
Acc
end,
- mod_mark_is_included(C,
- Sys,
- ModName,
- M2#mod.uses_mods,
- Acc2);
+ mod_mark_is_included(S, ModName, M2#mod.uses_mods, Acc2);
_ ->
%% Already marked true or false
Acc
@@ -813,31 +809,31 @@ mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) ->
[] ->
M = missing_mod(ModName, ?MISSING_APP_NAME),
M2 = M#mod{is_included = true},
- ets:insert(C#common.mod_tab, M2),
+ ets:insert(ModTab, M2),
[M2 | Acc]
end,
- mod_mark_is_included(C, Sys, UsedByName, ModNames, Acc3);
-mod_mark_is_included(_C, _Sys, _UsedByName, [], Acc) ->
+ mod_mark_is_included(S, UsedByName, ModNames, Acc3);
+mod_mark_is_included(_S, _UsedByName, [], Acc) ->
Acc.
-propagate_is_used_by(C) ->
+propagate_is_used_by(S) ->
lists:foreach(
fun({Mod,UsesMods}) ->
lists:foreach(
fun(UsedMod) ->
- ets:insert(C#common.mod_used_by_tab,{UsedMod,Mod})
+ ets:insert(S#state.mod_used_by_tab,{UsedMod,Mod})
end,
UsesMods)
end,
- get_all_mods_and_dependencies(C)).
+ get_all_mods_and_dependencies(S)).
-app_recap_dependencies(C) ->
- ets:foldl(fun(App,_) -> app_recap_dependencies(C,App) end,
- ok, C#common.app_tab).
+app_recap_dependencies(S) ->
+ ets:foldl(fun(App,_) -> app_recap_dependencies(S,App) end,
+ ok, S#state.app_tab).
-app_recap_dependencies(C, #app{mods = Mods, is_included = IsIncl} = A) ->
- {Mods2, IsIncl2} = mod_recap_dependencies(C, A, Mods, [], IsIncl),
+app_recap_dependencies(S, #app{mods = Mods, is_included = IsIncl} = A) ->
+ {Mods2, IsIncl2} = mod_recap_dependencies(S, A, Mods, [], IsIncl),
AppStatus =
case lists:keymember(missing, #mod.status, Mods2) of
true -> missing;
@@ -846,12 +842,12 @@ app_recap_dependencies(C, #app{mods = Mods, is_included = IsIncl} = A) ->
UsesMods = [M#mod.uses_mods || M <- Mods2, M#mod.is_included =:= true],
UsesMods2 = lists:usort(lists:flatten(UsesMods)),
UsesApps = [M#mod.app_name || ModName <- UsesMods2,
- M <- ets:lookup(C#common.mod_tab, ModName)],
+ M <- ets:lookup(S#state.mod_tab, ModName)],
UsesApps2 = lists:usort(UsesApps),
UsedByMods = [M#mod.used_by_mods || M <- Mods2, M#mod.is_included =:= true],
UsedByMods2 = lists:usort(lists:flatten(UsedByMods)),
UsedByApps = [M#mod.app_name || ModName <- UsedByMods2,
- M <- ets:lookup(C#common.mod_tab, ModName)],
+ M <- ets:lookup(S#state.mod_tab, ModName)],
UsedByApps2 = lists:usort(UsedByApps),
A2 = A#app{mods = Mods2,
@@ -861,11 +857,11 @@ app_recap_dependencies(C, #app{mods = Mods, is_included = IsIncl} = A) ->
uses_apps = UsesApps2,
used_by_apps = UsedByApps2,
is_included = IsIncl2},
- ets:insert(C#common.app_tab,A2),
+ ets:insert(S#state.app_tab,A2),
ok.
-mod_recap_dependencies(C, A, [#mod{name = ModName}=M1 | Mods], Acc, IsIncl) ->
- case ets:lookup(C#common.mod_tab, ModName) of
+mod_recap_dependencies(S, A, [#mod{name = ModName}=M1 | Mods], Acc, IsIncl) ->
+ case ets:lookup(S#state.mod_tab, ModName) of
[M2] when M2#mod.app_name=:=A#app.name ->
ModStatus = do_get_status(M2),
%% print(M2#mod.name, hipe, "status -> ~p\n", [ModStatus]),
@@ -873,19 +869,19 @@ mod_recap_dependencies(C, A, [#mod{name = ModName}=M1 | Mods], Acc, IsIncl) ->
case M2#mod.is_included of
true ->
UsedByMods =
- [N || {_, N} <- ets:lookup(C#common.mod_used_by_tab,
+ [N || {_, N} <- ets:lookup(S#state.mod_used_by_tab,
ModName)],
{true, M2#mod{status = ModStatus, used_by_mods = UsedByMods}};
_ ->
{IsIncl, M2#mod{status = ModStatus, used_by_mods = []}}
end,
- ets:insert(C#common.mod_tab, M3),
- mod_recap_dependencies(C, A, Mods, [M3 | Acc], IsIncl2);
+ ets:insert(S#state.mod_tab, M3),
+ mod_recap_dependencies(S, A, Mods, [M3 | Acc], IsIncl2);
[_] when A#app.is_included==false; M1#mod.incl_cond==exclude ->
%% App is explicitely excluded so it is ok that the module
%% record does not exist for this module in this
%% application.
- mod_recap_dependencies(C, A, Mods, [M1 | Acc], IsIncl);
+ mod_recap_dependencies(S, A, Mods, [M1 | Acc], IsIncl);
[M2] ->
%% A module is potensially included by multiple
%% applications. This is not allowed!
@@ -893,7 +889,7 @@ mod_recap_dependencies(C, A, [#mod{name = ModName}=M1 | Mods], Acc, IsIncl) ->
"Module ~p potentially included by two different applications: "
"~p and ~p", [ModName,A#app.name, " and ", M2#mod.app_name, "."])
end;
-mod_recap_dependencies(_C, _A, [], Acc, IsIncl) ->
+mod_recap_dependencies(_S, _A, [], Acc, IsIncl) ->
{lists:reverse(Acc), IsIncl}.
do_get_status(M) ->
@@ -904,11 +900,12 @@ do_get_status(M) ->
ok
end.
-verify_config(C, #sys{boot_rel = BootRel, rels = Rels}, RelApps, Status) ->
+verify_config(#state{app_tab=AppTab, sys=#sys{boot_rel = BootRel, rels = Rels}},
+ RelApps, Status) ->
case lists:keymember(BootRel, #rel.name, Rels) of
true ->
Status2 = lists:foldl(fun(RA, Acc) ->
- check_app(C, RA, Acc) end,
+ check_app(AppTab, RA, Acc) end,
Status,
RelApps),
lists:foldl(fun(#rel{name = RelName}, Acc)->
@@ -921,8 +918,8 @@ verify_config(C, #sys{boot_rel = BootRel, rels = Rels}, RelApps, Status) ->
"Release ~p is mandatory (used as boot_rel)",[BootRel])
end.
-check_app(C, {RelName, AppName}, Status) ->
- case ets:lookup(C#common.app_tab, AppName) of
+check_app(AppTab, {RelName, AppName}, Status) ->
+ case ets:lookup(AppTab, AppName) of
[#app{is_pre_included=IsPreIncl, is_included=IsIncl}]
when IsPreIncl; IsIncl ->
Status;
@@ -1001,7 +998,7 @@ refresh_app(#app{name = AppName,
%% Add optional user config for each module.
%% The #mod records that are already in the #app record at
%% this point do only contain user defined configuration
- %% (set by parse_options/2). So here we merge with the
+ %% (set by parse_options/4). So here we merge with the
%% default records from above.
Mods2 = add_mod_config(MissingMods ++ EbinMods, Mods),
@@ -1221,7 +1218,7 @@ set_mod_flags(Mods, AppModNames) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
do_get_config(S, InclDef, InclDeriv) ->
- AppTab = (S#state.common)#common.app_tab,
+ AppTab = S#state.app_tab,
Sys =
case InclDeriv of
false ->
@@ -1232,7 +1229,7 @@ do_get_config(S, InclDef, InclDeriv) ->
App <- ets:lookup(AppTab,Name)],
(S#state.sys)#sys{apps=Apps};
true ->
- sys_all_apps(S#state.common,S#state.sys)
+ sys_all_apps(S)
end,
reltool_target:gen_config(Sys, InclDef).
@@ -1940,11 +1937,8 @@ get_base(Name, Dir) ->
filename:basename(Dir)
end.
-sys_all_apps(C,Sys) ->
- Sys#sys{apps = all_apps(C)}.
-
-all_apps(C) ->
- ets:match_object(C#common.app_tab,'_').
+sys_all_apps(#state{app_tab=AppTab, sys=Sys}) ->
+ Sys#sys{apps = ets:match_object(AppTab,'_')}.
config_and_refresh(OldS, Fun) ->
try
@@ -1966,27 +1960,26 @@ config_and_refresh(OldS, Fun) ->
end.
-backup(#state{common=C}) ->
- Apps = ets:tab2list(C#common.app_tab),
- Mods = ets:tab2list(C#common.mod_tab),
- ets:delete_all_objects(C#common.app_tab),
- ets:delete_all_objects(C#common.mod_tab),
- ets:delete_all_objects(C#common.mod_used_by_tab), %tmp tab, no backup needed
+backup(S) ->
+ Apps = ets:tab2list(S#state.app_tab),
+ Mods = ets:tab2list(S#state.mod_tab),
+ ets:delete_all_objects(S#state.app_tab),
+ ets:delete_all_objects(S#state.mod_tab),
+ ets:delete_all_objects(S#state.mod_used_by_tab), %tmp tab, no backup needed
{Apps,Mods}.
-restore({Apps,Mods}, #state{common=C}) ->
- insert_all(C#common.app_tab,Apps),
- insert_all(C#common.mod_tab,Mods).
+restore({Apps,Mods}, S) ->
+ insert_all(S#state.app_tab,Apps),
+ insert_all(S#state.mod_tab,Mods).
-save_old(#state{status=OldStatus,sys=OldSys},#state{common=C}=NewS,
- {OldApps,OldMods},NewStatus) ->
- ets:delete_all_objects(C#common.old_app_tab),
- ets:delete_all_objects(C#common.old_mod_tab),
- insert_all(C#common.old_app_tab,OldApps),
- insert_all(C#common.old_mod_tab,OldMods),
+save_old(#state{status=OldStatus,sys=OldSys},NewS,{OldApps,OldMods},NewStatus) ->
+ ets:delete_all_objects(NewS#state.old_app_tab),
+ ets:delete_all_objects(NewS#state.old_mod_tab),
+ insert_all(NewS#state.old_app_tab,OldApps),
+ insert_all(NewS#state.old_mod_tab,OldMods),
NewS#state{old_sys=OldSys,
- old_status=OldStatus,
- status=NewStatus}.
+ old_status=OldStatus,
+ status=NewStatus}.
insert_all(Tab,Items) ->
lists:foreach(fun(Item) -> ets:insert(Tab,Item) end, Items).
--
cgit v1.2.3
From 048c28bc6c75964c3ee7930f5a1aecae92843c88 Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Mon, 12 Mar 2012 12:35:05 +0100
Subject: [reltool] Fix type spec and doc for app() and mod()
OTP-9792
Also correct documentation of reltool:install/2: first argument is
RelName, not Server.
---
lib/reltool/doc/src/reltool.xml | 11 +++++------
lib/reltool/src/reltool.hrl | 2 +-
2 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/lib/reltool/doc/src/reltool.xml b/lib/reltool/doc/src/reltool.xml
index 60e886e8f5..696ab52e63 100644
--- a/lib/reltool/doc/src/reltool.xml
+++ b/lib/reltool/doc/src/reltool.xml
@@ -5,7 +5,7 @@
2009
- 2011
+ 2012
Ericsson AB, All Rights Reserved
@@ -433,7 +433,7 @@ sys() = {root_dir, root_dir()}
| {excl_archive_filters, excl_archive_filters()}
| {archive_opts, [archive_opt()]}
app() = {vsn, app_vsn()}
- | {mod, mod_name(), mod()}
+ | {mod, mod_name(), [mod()]}
| {mod_cond, mod_cond()}
| {incl_cond, incl_cond()}
| {debug_info, debug_info()}
@@ -445,8 +445,7 @@ app() = {vsn, app_vsn()}
| {incl_archive_filters, incl_archive_filters()}
| {excl_archive_filters, excl_archive_filters()}
| {archive_opts, [archive_opt()]}
-mod() = {vsn, app_vsn()}
- | {incl_cond, incl_cond()}
+mod() = {incl_cond, incl_cond()}
| {debug_info, debug_info()}
rel_app() = app_name()
| {app_name(), app_type()}
@@ -664,10 +663,10 @@ target_spec() = [target_spec()]
- install(Server, TargetDir) -> ok | {error, Reason}
+ install(RelName, TargetDir) -> ok | {error, Reason}
Install a target system
- Server = server()
+ RelName = rel_name()
TargetDir = target_dir()
Reason = reason()
diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl
index d3eefb7ff0..fc0078715a 100644
--- a/lib/reltool/src/reltool.hrl
+++ b/lib/reltool/src/reltool.hrl
@@ -63,7 +63,7 @@
-type mod() :: {incl_cond, incl_cond()}
| {debug_info, debug_info()}.
-type app() :: {vsn, app_vsn()}
- | {mod, mod_name(), mod()}
+ | {mod, mod_name(), [mod()]}
| {mod_cond, mod_cond()}
| {incl_cond, incl_cond()}
| {app_file, app_file()}
--
cgit v1.2.3
From 50bc03bf5cc4b55644d164819d8c58bef966e278 Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Mon, 12 Mar 2012 17:21:33 +0100
Subject: [reltool] Always return warnings as flat strings
OTP-9794
---
lib/reltool/src/reltool_server.erl | 63 ++++++++++++++++++--------------------
lib/reltool/src/reltool_utils.erl | 5 +--
2 files changed, 32 insertions(+), 36 deletions(-)
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index 90fc6a8c28..d43be82cbd 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -681,26 +681,21 @@ mod_init_is_included(ModTab, M, ModCond, AppCond, Default, Status) ->
[Existing] ->
case {Existing#mod.is_included,IsIncl} of
{false,_} ->
- Warning =
- lists:concat(
- ["Module ",M#mod.name,
- " exists in applications ", Existing#mod.app_name,
- " and ", M#mod.app_name,
- ". Using module from application ",
- M#mod.app_name, "."]),
ets:insert(ModTab, M2),
- reltool_utils:add_warning(Status,Warning);
+ reltool_utils:add_warning(
+ "Module ~p exists in applications ~p and ~p. "
+ "Using module from application ~p.",
+ [M#mod.name, Existing#mod.app_name,
+ M#mod.app_name, M#mod.app_name],
+ Status);
{_,false} ->
- Warning =
- lists:concat(
- ["Module ",M#mod.name,
- " exists in applications ", Existing#mod.app_name,
- " and ", M#mod.app_name,
- ". Using module from application ",
- Existing#mod.app_name, "."]),
-
%% Don't insert in ModTab - using Existing
- reltool_utils:add_warning(Status,Warning);
+ reltool_utils:add_warning(
+ "Module ~p exists in applications ~p and ~p. "
+ "Using module from application ~p.",
+ [M#mod.name, Existing#mod.app_name,
+ M#mod.app_name,Existing#mod.app_name],
+ Status);
{_,_} ->
reltool_utils:throw_error(
"Module ~p potentially included by two different "
@@ -1035,22 +1030,21 @@ read_app_info(AppFileOrBin, AppFile, AppName, DefaultVsn, Status) ->
AI = #app_info{vsn = DefaultVsn},
parse_app_info(AppFile, Info, AI, Status);
{ok, _BadApp} ->
- Text = lists:concat([AppName,
- ": Illegal contents in app file ", AppFile,
- ", application tuple with arity 3 expected."]),
{missing_app_info(DefaultVsn),
- reltool_utils:add_warning(Status, Text)};
+ reltool_utils:add_warning("~p: Illegal contents in app file ~p, "
+ "application tuple with arity 3 expected.",
+ [AppName,AppFile],
+ Status)};
{error, Text} when Text =:= EnoentText ->
- Text2 = lists:concat([AppName,
- ": Missing app file ", AppFile, "."]),
{missing_app_info(DefaultVsn),
- reltool_utils:add_warning(Status, Text2)};
+ reltool_utils:add_warning("~p: Missing app file ~p.",
+ [AppName,AppFile],
+ Status)};
{error, Text} ->
- Text2 = lists:concat([AppName,
- ": Cannot parse app file ",
- AppFile, " (", Text, ")."]),
{missing_app_info(DefaultVsn),
- reltool_utils:add_warning(Status, Text2)}
+ reltool_utils:add_warning("~p: Cannot parse app file ~p (~p).",
+ [AppName,AppFile,Text],
+ Status)}
end.
parse_app_info(File, [{Key, Val} | KeyVals], AI, Status) ->
@@ -1084,10 +1078,11 @@ parse_app_info(File, [{Key, Val} | KeyVals], AI, Status) ->
parse_app_info(File, KeyVals, AI#app_info{start_phases = Val},
Status);
_ ->
- String = lists:concat(["Unexpected item ",
- Key, "in app file ", File]),
- parse_app_info(File, KeyVals, AI,
- reltool_utils:add_warning(Status, String))
+ Status2 =
+ reltool_utils:add_warning("Unexpected item ~p in app file ~p.",
+ [Key,File],
+ Status),
+ parse_app_info(File, KeyVals, AI, Status2)
end;
parse_app_info(_, [], AI, Status) ->
{AI, Status}.
@@ -1581,8 +1576,8 @@ patch_erts_version(RootDir, Apps, Status) ->
Apps2 = lists:keystore(AppName, #app.name, Apps, Erts2),
{Apps2, Status};
Vsn =:= "" ->
- {Apps, reltool_utils:add_warning(Status,
- "erts has no version")};
+ {Apps, reltool_utils:add_warning("erts has no version",[],
+ Status)};
true ->
{Apps, Status}
end;
diff --git a/lib/reltool/src/reltool_utils.erl b/lib/reltool/src/reltool_utils.erl
index 2d766224d9..9cf9bd1418 100644
--- a/lib/reltool/src/reltool_utils.erl
+++ b/lib/reltool/src/reltool_utils.erl
@@ -30,7 +30,7 @@
get_item/1, get_items/1, get_selected_items/3,
select_items/3, select_item/2,
- safe_keysearch/5, print/4, add_warning/2,
+ safe_keysearch/5, print/4, add_warning/3,
create_dir/1, list_dir/1, read_file_info/1,
write_file_info/2, read_file/1, write_file/2,
@@ -402,7 +402,8 @@ print(X, X, Format, Args) ->
print(_, _, _, _) ->
ok.
-add_warning({ok,Warnings}, Warning) ->
+add_warning(Format, Args, {ok,Warnings}) ->
+ Warning = lists:flatten(io_lib:format(Format,Args)),
case lists:member(Warning,Warnings) of
true ->
{ok,Warnings};
--
cgit v1.2.3
From dac94945228322ffb9f8dd8495789c0cd64442a3 Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Mon, 12 Mar 2012 17:34:15 +0100
Subject: [reltool] Just warn if same module occurs twice in .app file
OTP-9792
Earlier this would cause an error with reason
"Module xxx potentially included by two different applications: yyy and yyy."
This is now changed so it will only be a warning saying that the
module is duplicated in the .app file.
---
lib/reltool/src/reltool_server.erl | 40 +++++++++++++++-------
lib/reltool/test/reltool_server_SUITE.erl | 40 +++++++++++++++++++---
.../dupl_mod/a-1.0/ebin/a.app | 7 ++++
3 files changed, 70 insertions(+), 17 deletions(-)
create mode 100644 lib/reltool/test/reltool_server_SUITE_data/dupl_mod/a-1.0/ebin/a.app
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index d43be82cbd..29df619955 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -977,18 +977,32 @@ refresh_app(#app{name = AppName,
%% Add non-existing modules - i.e. create default #mod
%% records for all modules that are listed in .app file
%% but do not exist in ebin.
- AppInfoMods = AppInfo#app_info.modules,
- AppModNames =
- case AppInfo#app_info.mod of
- {StartModName, _} ->
- case lists:member(StartModName, AppInfoMods) of
- true -> AppInfoMods;
- false -> [StartModName | AppInfoMods]
- end;
- undefined ->
- AppInfoMods
- end,
- MissingMods = add_missing_mods(AppName, EbinMods, AppModNames),
+ AppInfoMods = lists:usort(AppInfo#app_info.modules),
+ Status4 =
+ case AppInfo#app_info.modules -- AppInfoMods of
+ [] ->
+ Status3;
+ DuplicatedMods ->
+ lists:foldl(
+ fun(M,S) ->
+ reltool_utils:add_warning(
+ "Module ~p duplicated in app file for "
+ "application ~p.", [M, AppName], S)
+ end,
+ Status3,
+ DuplicatedMods)
+ end,
+ AppModNames =
+ case AppInfo#app_info.mod of
+ {StartModName, _} ->
+ case lists:member(StartModName, AppInfoMods) of
+ true -> AppInfoMods;
+ false -> [StartModName | AppInfoMods]
+ end;
+ undefined ->
+ AppInfoMods
+ end,
+ MissingMods = add_missing_mods(AppName, EbinMods, AppModNames),
%% Add optional user config for each module.
%% The #mod records that are already in the #app record at
@@ -1013,7 +1027,7 @@ refresh_app(#app{name = AppName,
label = AppLabel,
info = AppInfo,
mods = lists:keysort(#mod.name, Mods3)},
- {App2, Status3};
+ {App2, Status4};
true ->
{App, Status}
end.
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index 4b0511afaf..57b04251d4 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -69,8 +69,9 @@ all() ->
create_old_target,
eval_target_spec,
otp_9135,
- otp_9229_exclude_app,
- otp_9229_exclude_mod,
+ otp_9229_dupl_mod_exclude_app,
+ otp_9229_dupl_mod_exclude_mod,
+ dupl_mod_in_app_file,
get_apps,
get_mod,
get_sys,
@@ -1002,7 +1003,7 @@ eval_target_spec(_Config) ->
%% exists in two applications.
%% Include on app, exclude the other
-otp_9229_exclude_app(Config) ->
+otp_9229_dupl_mod_exclude_app(Config) ->
DataDir = ?config(data_dir,Config),
LibDir = filename:join(DataDir,"otp_9229"),
@@ -1049,7 +1050,7 @@ otp_9229_exclude_app(Config) ->
ok.
%% Include both apps, but exclude common module from one app
-otp_9229_exclude_mod(Config) ->
+otp_9229_dupl_mod_exclude_mod(Config) ->
DataDir = ?config(data_dir,Config),
LibDir = filename:join(DataDir,"otp_9229"),
@@ -1102,6 +1103,37 @@ otp_9229_exclude_mod(Config) ->
ok.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Test that if a module is duplicated in a .app file, then a warning
+%% is produced, but target can still be created.
+dupl_mod_in_app_file(Config) ->
+ DataDir = ?config(data_dir,Config),
+ LibDir = filename:join(DataDir,"dupl_mod"),
+
+ %% Configure the server
+ Sys =
+ {sys,
+ [
+ {lib_dirs, [LibDir]},
+ {incl_cond,exclude},
+ {app,a,[{incl_cond,include}]},
+ {app,kernel,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]}
+ ]},
+
+ %% Generate target file
+ TargetDir = filename:join([?WORK_DIR, "target_dupl_mod_in_app_file"]),
+ ?m(ok, reltool_utils:recursive_delete(TargetDir)),
+ ?m(ok, file:make_dir(TargetDir)),
+ ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Sys}])]),
+ ?m({ok,["Module a duplicated in app file for application a."]},
+ reltool:get_status([{config, Sys}])),
+
+ %%! test that only one module installed (in spec)
+
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Test the interface used by the GUI:
%% get_app
diff --git a/lib/reltool/test/reltool_server_SUITE_data/dupl_mod/a-1.0/ebin/a.app b/lib/reltool/test/reltool_server_SUITE_data/dupl_mod/a-1.0/ebin/a.app
new file mode 100644
index 0000000000..fada34847a
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/dupl_mod/a-1.0/ebin/a.app
@@ -0,0 +1,7 @@
+% -*-erlang-*-
+{application, a,
+ [{description, "Application with duplicated module name in .app file"},
+ {vsn, "1.0"},
+ {modules, [a,a]},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.
--
cgit v1.2.3
From ba3e53ef71cc127d4df9c53f9f401645814e3fb7 Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Thu, 15 Mar 2012 11:52:41 +0100
Subject: [reltool] Fix problems with sorting of applications
OTP-9792
The following problems have been solved:
* reltool_target:do_merge_apps - in recursive calls to this function,
the accumulator was reverted each time causing the order of
applications listed after kernel and stdlib in the rel specification
in the configuration to sometimes be messed up.
* There are several ways to specify wich applications to include in an
application:
1) in the .app file for the including applications
2a) in the .rel file, when listing applications
2b) in the rel specification in the reltool configuration
2a (systools) and 2b (reltool) should have the same effect and
overwrite 1.
According to the documentation of systools (sasl), the default value
in 2a is an empty list. This should mean that if included
applications are not mentioned in the .rel file, then any included
application listed in the .app file will be disregarded. This is NOT
the way systools actually works. The implementation sets the default
for the .rel file to the same list as in the .app file.
Reltool earlier implemented 2b as described in the systools
documentation. However, after some discussion we decided to change
this so that reltool handles 2b in the same way as systools handles
2a since this seems more intuitive. The sasl documentation will be
altered accordingly (internal ref OTP-9980).
* If the rel specification in the reltool configuration explicitly
specified included applications to be an empty list, and the .app
file had a non-empty list, then the empty list from the rel
specification was discarded. This has been corrected so the rel
specification now, if set, always overwrites the value of
included_applications in the .app file.
* reltool would earlier add load instructions in the script/boot files
for ALL modules in the ebin directory of an application even if
mod_cond was set to app (include only modules listed in the .app
file). This has been corrected - now only modules with
#mod.is_included==true are loaded.
* reltool would earlier add start instructions in the script/boot file
for included applications. This has been corrected - included
applications shall only be loaded since the including application is
responsible for starting them.
---
lib/reltool/src/reltool.hrl | 2 +-
lib/reltool/src/reltool_server.erl | 30 +++++--
lib/reltool/src/reltool_target.erl | 72 +++++++++-------
lib/reltool/src/reltool_utils.erl | 8 +-
lib/reltool/test/reltool_server_SUITE.erl | 95 ++++++++++++----------
.../sort_apps/z-1.0/ebin/z.app | 4 +-
6 files changed, 121 insertions(+), 90 deletions(-)
diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl
index fc0078715a..4e5c5b2849 100644
--- a/lib/reltool/src/reltool.hrl
+++ b/lib/reltool/src/reltool.hrl
@@ -206,7 +206,7 @@
{
name :: app_name(),
app_type :: app_type() | undefined,
- incl_apps = [] :: [incl_app()]
+ incl_apps :: [incl_app()] | undefined
}).
-record(rel,
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index 29df619955..c99180a613 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -560,10 +560,30 @@ apps_in_rels(Rels, Apps) ->
apps_in_rel(#rel{name = RelName, rel_apps = RelApps}, Apps) ->
Mandatory = [{RelName, kernel}, {RelName, stdlib}],
- Other = [{RelName, AppName} ||
- RA <- RelApps,
- AppName <- [RA#rel_app.name | RA#rel_app.incl_apps],
- not lists:keymember(AppName, 2, Mandatory)],
+ Other =
+ [{RelName, AppName} ||
+ RA <- RelApps,
+ AppName <- [RA#rel_app.name |
+ %% 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 ~p uses non existing "
+ "application ~p",
+ [RelName,RA#rel_app.name])
+ end;
+ IA ->
+ IA
+ end],
+ not lists:keymember(AppName, 2, Mandatory)],
more_apps_in_rels(Mandatory ++ Other, Apps, []).
more_apps_in_rels([{RelName, AppName} = RA | RelApps], Apps, Acc) ->
@@ -1505,7 +1525,7 @@ decode(#rel{rel_apps = RelApps} = Rel, [RelApp | KeyVals]) ->
{VT andalso VI,
#rel_app{name = Name, app_type = Type, incl_apps = InclApps}};
_ ->
- {false, #rel_app{incl_apps = []}}
+ {false, #rel_app{}}
end,
case ValidTypesAssigned of
true ->
diff --git a/lib/reltool/src/reltool_target.erl b/lib/reltool/src/reltool_target.erl
index 40d1009733..3d83a77d99 100644
--- a/lib/reltool/src/reltool_target.erl
+++ b/lib/reltool/src/reltool_target.erl
@@ -208,10 +208,10 @@ do_gen_config(#rel_app{name = Name,
incl_apps = InclApps},
_InclDefs) ->
case {Type, InclApps} of
- {undefined, []} -> Name;
- {undefined, _} -> {Name, InclApps};
- {_, []} -> {Name, Type};
- {_, _} -> {Name, Type, InclApps}
+ {undefined, undefined} -> Name;
+ {undefined, _} -> {Name, InclApps};
+ {_, undefined} -> {Name, Type};
+ {_, _} -> {Name, Type, InclApps}
end;
do_gen_config({Tag, Val}, InclDefs) ->
emit(Tag, Val, undefined, InclDefs);
@@ -279,7 +279,7 @@ gen_rel(Rel, Sys) ->
{error, Text}
end.
-do_gen_rel(#rel{name = RelName, vsn = RelVsn},
+do_gen_rel(#rel{name = RelName, vsn = RelVsn, rel_apps = RelApps},
#sys{apps = Apps},
MergedApps) ->
ErtsName = erts,
@@ -288,7 +288,7 @@ do_gen_rel(#rel{name = RelName, vsn = RelVsn},
{release,
{RelName, RelVsn},
{ErtsName, Erts#app.vsn},
- [strip_rel_info(App) || App <- MergedApps]};
+ [strip_rel_info(App, RelApps) || App <- MergedApps]};
false ->
reltool_utils:throw_error("Mandatory application ~p is "
"not included",
@@ -298,13 +298,17 @@ do_gen_rel(#rel{name = RelName, vsn = RelVsn},
strip_rel_info(#app{name = Name,
vsn = Vsn,
app_type = Type,
- info = #app_info{incl_apps = InclApps}})
- when Type =/= undefined ->
- case {Type, InclApps} of
- {permanent, []} -> {Name, Vsn};
- {permanent, _} -> {Name, Vsn, InclApps};
- {_, []} -> {Name, Vsn, Type};
- {_, _} -> {Name, Vsn, Type, InclApps}
+ info = #app_info{incl_apps = AppInclApps}},
+ RelApps) when Type =/= undefined ->
+ RelInclApps = case lists:keyfind(Name,#rel_app.name,RelApps) of
+ #rel_app{incl_apps = RIA} when RIA =/= undefined -> RIA;
+ _ -> undefined
+ end,
+ case {Type, RelInclApps} of
+ {permanent, undefined} -> {Name, Vsn};
+ {permanent, _} -> {Name, Vsn, AppInclApps};
+ {_, undefined} -> {Name, Vsn, Type};
+ {_, _} -> {Name, Vsn, Type, AppInclApps}
end.
merge_apps(#rel{name = RelName,
@@ -323,7 +327,7 @@ merge_apps(#rel{name = RelName,
A#app.name =/= ?MISSING_APP_NAME,
not lists:keymember(A#app.name, #app.name, MergedApps2)],
MergedApps3 = do_merge_apps(RelName, Embedded, Apps, EmbAppType, MergedApps2),
- sort_apps(MergedApps3).
+ sort_apps(lists:reverse(MergedApps3)).
do_merge_apps(RelName, [#rel_app{name = Name} = RA | RelApps], Apps, RelAppType, Acc) ->
case is_already_merged(Name, RelApps, Acc) of
@@ -341,25 +345,18 @@ do_merge_apps(RelName, [Name | RelApps], Apps, RelAppType, Acc) ->
true ->
do_merge_apps(RelName, RelApps, Apps, RelAppType, Acc);
false ->
- RelApp = init_rel_app(Name, Apps),
+ RelApp = #rel_app{name = Name},
do_merge_apps(RelName, [RelApp | RelApps], Apps, RelAppType, Acc)
end;
do_merge_apps(_RelName, [], _Apps, _RelAppType, Acc) ->
- lists:reverse(Acc).
-
-init_rel_app(Name, Apps) ->
- {value, App} = lists:keysearch(Name, #app.name, Apps),
- Info = App#app.info,
- #rel_app{name = Name,
- app_type = undefined,
- incl_apps = Info#app_info.incl_apps}.
+ Acc.
merge_app(RelName,
- #rel_app{name = Name,
- app_type = Type,
- incl_apps = InclApps},
- RelAppType,
- App) ->
+ #rel_app{name = Name,
+ app_type = Type,
+ incl_apps = InclApps0},
+ RelAppType,
+ App) ->
Type2 =
case {Type, App#app.app_type} of
{undefined, undefined} -> RelAppType;
@@ -367,6 +364,11 @@ merge_app(RelName,
{_, _} -> Type
end,
Info = App#app.info,
+ InclApps =
+ case InclApps0 of
+ undefined -> Info#app_info.incl_apps;
+ _ -> InclApps0
+ end,
case InclApps -- Info#app_info.incl_apps of
[] ->
App#app{app_type = Type2, info = Info#app_info{incl_apps = InclApps}};
@@ -421,7 +423,10 @@ do_gen_script(#rel{name = RelName, vsn = RelVsn},
Mandatory = mandatory_modules(),
Early = Mandatory ++ Preloaded,
{value, KernelApp} = lists:keysearch(kernel, #app.name, MergedApps),
- InclApps = [I || #app{info = #app_info{incl_apps = I}} <- MergedApps],
+ InclApps = lists:flatmap(fun(#app{info = #app_info{incl_apps = I}}) ->
+ I
+ end,
+ MergedApps),
%% Create the script
DeepList =
@@ -471,7 +476,7 @@ load_app_mods(#app{mods = Mods} = App, Mand, PathFlag, Variables) ->
Path = cr_path(App, PathFlag, Variables),
PartNames =
lists:sort([{packages:split(M),M} ||
- #mod{name = M} <- Mods,
+ #mod{name = M, is_included=true} <- Mods,
not lists:member(M, Mand)]),
SplitMods =
lists:foldl(
@@ -513,7 +518,12 @@ sort_apps([#app{name = Name, info = Info} = App | Apps],
Circular,
Visited) ->
{Uses, Apps1, NotFnd1} =
- find_all(Name, Info#app_info.applications, Apps, Visited, [], []),
+ find_all(Name,
+ lists:reverse(Info#app_info.applications),
+ Apps,
+ Visited,
+ [],
+ []),
{Incs, Apps2, NotFnd2} =
find_all(Name,
lists:reverse(Info#app_info.incl_apps),
diff --git a/lib/reltool/src/reltool_utils.erl b/lib/reltool/src/reltool_utils.erl
index 9cf9bd1418..3e50324011 100644
--- a/lib/reltool/src/reltool_utils.erl
+++ b/lib/reltool/src/reltool_utils.erl
@@ -126,18 +126,14 @@ prim_parse(Tokens, Acc) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
default_rels() ->
- %%Kernel = #rel_app{name = kernel, incl_apps = []},
- %%Stdlib = #rel_app{name = stdlib, incl_apps = []},
- Sasl = #rel_app{name = sasl, incl_apps = []},
+ %% kernel and stdlib are added automatically in every release
[
#rel{name = ?DEFAULT_REL_NAME,
vsn = "1.0",
rel_apps = []},
- %%rel_apps = [Kernel, Stdlib]},
#rel{name = "start_sasl",
vsn = "1.0",
- rel_apps = [Sasl]}
- %%rel_apps = [Kernel, Sasl, Stdlib]}
+ rel_apps = [#rel_app{name = sasl}]}
].
choose_default(Tag, Profile, InclDefs)
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index 57b04251d4..122880fca9 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -283,7 +283,7 @@ create_release(_Config) ->
%% started before the including application.
%% Circular dependencies shall also be detected and cause error.
-create_release_sort(_Config) -> {skip, "Multiple known problems - see OTP-9792"};
+create_release_sort(_Config) -> {skip, "Two bugs related to sorting"};
create_release_sort(Config) ->
DataDir = ?config(data_dir,Config),
%% Configure the server
@@ -296,7 +296,11 @@ create_release_sort(Config) ->
RelName7 = "Circular",
RelName8 = "Include-both-missing-app",
RelName9 = "Include-overwrite",
+ RelName10= "Uses-order-as-rel",
RelVsn = "1.0",
+ %% Application z (.app file):
+ %% includes [tools, mnesia]
+ %% uses [kernel, stdlib, sasl, inets]
Sys =
{sys,
[
@@ -304,19 +308,21 @@ create_release_sort(Config) ->
{boot_rel, RelName1},
{rel, RelName1, RelVsn, [stdlib, kernel, mnesia, sasl]},
{rel, RelName2, RelVsn, [stdlib, kernel, sasl, mnesia]},
- {rel, RelName3, RelVsn, [stdlib, kernel, {z,[tools]}, tools]},
- {rel, RelName4, RelVsn, [stdlib, kernel, z, tools]},
+ {rel, RelName3, RelVsn, [stdlib, kernel, {z,[tools]}, tools, mnesia]},
+ {rel, RelName4, RelVsn, [stdlib, kernel, z, mnesia, tools]},
{rel, RelName5, RelVsn, [stdlib, kernel, {sasl,[tools]}]},
- {rel, RelName6, RelVsn, [stdlib, kernel, z]}, %z includes tools in .app
+ {rel, RelName6, RelVsn, [stdlib, kernel, z]},
{rel, RelName7, RelVsn, [stdlib, kernel, mnesia, y, sasl, x]},
{rel, RelName8, RelVsn, [stdlib, kernel, {z,[tools]}]},
{rel, RelName9, RelVsn, [stdlib, kernel, {z,[]}]},
+ {rel, RelName10, RelVsn, [stdlib, kernel, {z,[]}, inets, sasl]},
{incl_cond,exclude},
{mod_cond,app},
{app,kernel,[{incl_cond,include}]},
{app,stdlib,[{incl_cond,include}]},
{app,mnesia,[{incl_cond,include}]},
{app,sasl,[{incl_cond,include}]},
+ {app,inets,[{incl_cond,include}]},
{app,x,[{incl_cond,include}]},
{app,y,[{incl_cond,include}]},
{app,z,[{incl_cond,include}]},
@@ -324,7 +330,6 @@ create_release_sort(Config) ->
]},
%% Generate release
- %% BUG: reltool reverses the list of applications after kernel and stdlib
?msym({ok, {release, {RelName1, RelVsn},
{erts, _},
[{kernel, _},
@@ -333,7 +338,6 @@ create_release_sort(Config) ->
{sasl, _}]}},
reltool:get_rel([{config, Sys}], RelName1)),
- %% BUG: reltool reverses the list of applications after kernel and stdlib
?msym({ok, {release, {RelName2, RelVsn},
{erts, _},
[{kernel, _},
@@ -346,19 +350,21 @@ create_release_sort(Config) ->
{erts, _},
[{kernel, _},
{stdlib, _},
+ {sasl, _},
+ {inets, _},
{tools, _},
- {z, _, [tools]}]}},
+ {z, _, [tools]},
+ {mnesia, _}]}},
reltool:get_rel([{config, Sys}], RelName3)),
- %% BUG: reltool does not honor included applications in .app files
- %% unless they are also mentioned in the 'rel' specification in
- %% the reltool config.
- %% => order of tools and z does not become correct in rel (tools
- %% should be first since it is included in z)
+ %%! BUG: same as OTP-4121, but for reltool???? Or revert tools and mnesia
?msym({ok, {release, {RelName4, RelVsn},
{erts, _},
[{kernel, _},
{stdlib, _},
+ {sasl, _},
+ {inets, _},
+ {mnesia, _},
{tools, _},
{z, _}]}},
reltool:get_rel([{config, Sys}], RelName4)),
@@ -368,11 +374,7 @@ create_release_sort(Config) ->
"in the app file: [tools]"},
reltool:get_rel([{config, Sys}], RelName5)),
- %% BUG: reltool does not honor included applications in .app files
- %% unless they are also mentioned in the 'rel' specification in
- %% the reltool config.
- %% => does not detect that tools (included in z) is missing
- ?m({error, "Undefined applications: [tools]"},
+ ?m({error, "Undefined applications: [tools,mnesia]"},
reltool:get_rel([{config, Sys}], RelName6)),
?m({error,"Circular dependencies: [x,y]"},
@@ -381,15 +383,25 @@ create_release_sort(Config) ->
?m({error,"Undefined applications: [tools]"},
reltool:get_rel([{config, Sys}], RelName8)),
- %% BUG: Reltool looses the empty include list for z, which should
- %% overwrite included_applications statement from the .app file.
?msym({ok,{release,{RelName9,RelVsn},
{erts,_},
[{kernel,_},
{stdlib,_},
+ {sasl, _},
+ {inets, _},
{z,_,[]}]}},
reltool:get_rel([{config, Sys}], RelName9)),
+ %%! BUG: same as OTP-9984, but for reltool???? Or revert inets and sasl?
+ ?msym({ok,{release,{RelName10,RelVsn},
+ {erts,_},
+ [{kernel,_},
+ {stdlib,_},
+ {inets, _},
+ {sasl, _},
+ {z,_,[]}]}},
+ reltool:get_rel([{config, Sys}], RelName10)),
+
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -442,7 +454,7 @@ create_script(_Config) ->
%% Test creation of .script with different sorting of applications and
%% included applications.
%% Test that result is equal to what systools produces
-create_script_sort(_Config) -> {skip, "Multiple known problems - see OTP-9792"};
+create_script_sort(_Config) -> {skip, "OTP-9984 - stdlib sort problem"};
create_script_sort(Config) ->
DataDir = ?config(data_dir,Config),
%% Configure the server
@@ -464,10 +476,10 @@ create_script_sort(Config) ->
{boot_rel, RelName1},
{rel, RelName1, RelVsn, [stdlib, kernel, mnesia, sasl]},
{rel, RelName2, RelVsn, [stdlib, kernel, sasl, mnesia]},
- {rel, RelName3, RelVsn, [stdlib, kernel, {z,[tools]}, tools]},
- {rel, RelName4, RelVsn, [stdlib, kernel, z, tools]},
+ {rel, RelName3, RelVsn, [stdlib, kernel, {z,[tools]}, tools, mnesia]},
+ {rel, RelName4, RelVsn, [stdlib, kernel, z, mnesia, tools]},
{rel, RelName5, RelVsn, [stdlib, kernel, {sasl,[tools]}]},
- {rel, RelName6, RelVsn, [stdlib, kernel, z]}, %z includes tools in .app
+ {rel, RelName6, RelVsn, [stdlib, kernel, z]},
{rel, RelName7, RelVsn, [stdlib, kernel, mnesia, y, sasl, x]},
{rel, RelName8, RelVsn, [stdlib, kernel, {z,[tools]}]},
{rel, RelName9, RelVsn, [stdlib, kernel, {z,[]}]},
@@ -477,6 +489,7 @@ create_script_sort(Config) ->
{app,stdlib,[{incl_cond,include}]},
{app,mnesia,[{incl_cond,include}]},
{app,sasl,[{incl_cond,include}]},
+ {app,inets,[{incl_cond,include}]},
{app,x,[{incl_cond,include}]},
{app,y,[{incl_cond,include}]},
{app,z,[{incl_cond,include}]},
@@ -487,11 +500,13 @@ create_script_sort(Config) ->
%% Generate release files
application:load(sasl),
+ application:load(inets),
application:load(mnesia),
application:load(tools),
{ok,KernelVsn} = application:get_key(kernel,vsn),
{ok,StdlibVsn} = application:get_key(stdlib,vsn),
{ok,SaslVsn} = application:get_key(sasl,vsn),
+ {ok,InetsVsn} = application:get_key(inets,vsn),
{ok,MnesiaVsn} = application:get_key(mnesia,vsn),
{ok,ToolsVsn} = application:get_key(tools,vsn),
ErtsVsn = erlang:system_info(version),
@@ -514,14 +529,20 @@ create_script_sort(Config) ->
[{kernel,KernelVsn},
{stdlib,StdlibVsn},
{z,"1.0",[tools]},
- {tools,ToolsVsn}]},
+ {tools,ToolsVsn},
+ {mnesia,MnesiaVsn},
+ {sasl,SaslVsn},
+ {inets,InetsVsn}]},
FullName3 = filename:join(?WORK_DIR,RelName3),
?m(ok, file:write_file(FullName3 ++ ".rel", io_lib:format("~p.\n", [Rel3]))),
Rel4 = {release, {RelName4,RelVsn}, {erts,ErtsVsn},
[{kernel,KernelVsn},
{stdlib,StdlibVsn},
{z,"1.0"},
- {tools,ToolsVsn}]},
+ {tools,ToolsVsn},
+ {mnesia,MnesiaVsn},
+ {sasl,SaslVsn},
+ {inets,InetsVsn}]},
FullName4 = filename:join(?WORK_DIR,RelName4),
?m(ok, file:write_file(FullName4 ++ ".rel", io_lib:format("~p.\n", [Rel4]))),
Rel5 = {release, {RelName5,RelVsn}, {erts,ErtsVsn},
@@ -555,42 +576,30 @@ create_script_sort(Config) ->
Rel9 = {release, {RelName9,RelVsn}, {erts,ErtsVsn},
[{kernel,KernelVsn},
{stdlib,StdlibVsn},
- {z,"1.0",[]}]},
+ {z,"1.0",[]},
+ {sasl,SaslVsn},
+ {inets,InetsVsn}]},
FullName9 = filename:join(?WORK_DIR,RelName9),
?m(ok, file:write_file(FullName9 ++ ".rel", io_lib:format("~p.\n", [Rel9]))),
%% Generate script files with systools and reltool and compare
ZPath = filename:join([LibDir,"*",ebin]),
- %% BUG: reltool reverses the list of applications after kernel and stdlib
- %% => mnesia and sasl are reverted
?msym({ok,_,_}, systools_make_script(FullName1,ZPath)),
{ok, [SystoolsScript1]} = ?msym({ok,[_]}, file:consult(FullName1++".script")),
{ok, Script1} = ?msym({ok, _}, reltool:get_script(Pid, RelName1)),
?m(equal, diff_script(SystoolsScript1, Script1)),
- %% BUG: reltool reverses the list of applications after kernel and stdlib
- %% => mnesia and sasl are reverted
?msym({ok,_,_}, systools_make_script(FullName2,ZPath)),
{ok, [SystoolsScript2]} = ?msym({ok,[_]}, file:consult(FullName2++".script")),
{ok, Script2} = ?msym({ok, _}, reltool:get_script(Pid, RelName2)),
?m(equal, diff_script(SystoolsScript2, Script2)),
- %% BUG1: reltool loads all modules in the ebin dir of an application,
- %% even if mod_cond is set to 'app'.
- %% BUG2: reltool shall not start included applications!!
?msym({ok,_,_}, systools_make_script(FullName3,ZPath)),
{ok, [SystoolsScript3]} = ?msym({ok,[_]}, file:consult(FullName3++".script")),
{ok, Script3} = ?msym({ok, _}, reltool:get_script(Pid, RelName3)),
?m(equal, diff_script(SystoolsScript3, Script3)),
- %% BUG1: reltool loads all modules in the ebin dir of an application,
- %% even if mod_cond is set to 'app'.
- %% BUG2: reltool does not honor included applications in .app files
- %% unless they are also mentioned in the 'rel' specification in
- %% the reltool config.
- %% => faulty order of load instructions for tools and z. tools
- %% should be first since it is included in z.
?msym({ok,_,_}, systools_make_script(FullName4,ZPath)),
{ok, [SystoolsScript4]} = ?msym({ok,[_]}, file:consult(FullName4++".script")),
{ok, Script4} = ?msym({ok, _}, reltool:get_script(Pid, RelName4)),
@@ -603,13 +612,9 @@ create_script_sort(Config) ->
"in the app file: [tools]"},
reltool:get_script(Pid, RelName5)),
- %% BUG: reltool does not honor included applications in .app files
- %% unless they are also mentioned in the 'rel' specification in
- %% the reltool config.
- %% => does not detect that tools (included in z) is missing
?msym({error,_,{undefined_applications,_}},
systools_make_script(FullName6,ZPath)),
- ?m({error, "Undefined applications: [tools]"},
+ ?m({error, "Undefined applications: [tools,mnesia]"},
reltool:get_script(Pid, RelName6)),
?msym({error,_,{circular_dependencies,_}},
diff --git a/lib/reltool/test/reltool_server_SUITE_data/sort_apps/z-1.0/ebin/z.app b/lib/reltool/test/reltool_server_SUITE_data/sort_apps/z-1.0/ebin/z.app
index 1622975bf6..8608bc554b 100644
--- a/lib/reltool/test/reltool_server_SUITE_data/sort_apps/z-1.0/ebin/z.app
+++ b/lib/reltool/test/reltool_server_SUITE_data/sort_apps/z-1.0/ebin/z.app
@@ -4,5 +4,5 @@
{vsn, "1.0"},
{modules,[]},
{registered, []},
- {applications, [kernel, stdlib]},
- {included_applications, [tools]}]}.
+ {applications, [kernel, stdlib, sasl, inets]},
+ {included_applications, [tools, mnesia]}]}.
--
cgit v1.2.3
From f294d207da75e950bc533cb9d7d9148390c1001a Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Fri, 16 Mar 2012 09:57:13 +0100
Subject: [sasl] Doc that included applications in .rel defaults to same as in
.app
OTP-9980
Sasl documentation earlier said that the InclApps parameters in a .rel
file defaults to the empty list. This is not correct. It defaults to
the same value as specified in the .app file.
---
lib/sasl/doc/src/rel.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/sasl/doc/src/rel.xml b/lib/sasl/doc/src/rel.xml
index 470adf3c03..68ef90330f 100644
--- a/lib/sasl/doc/src/rel.xml
+++ b/lib/sasl/doc/src/rel.xml
@@ -5,7 +5,7 @@
--
cgit v1.2.3
From 8233c6e1787fa8e81f0301f10aea82c695cd322a Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Fri, 16 Mar 2012 14:34:30 +0100
Subject: [sasl] Sort applications used by other applications correctly in
.script
OTP-9984
Applications that are listed in {applications,Apps} in the app file
were not sorted correctly in the script file. They were loaded/started
in the reverse order of how they were listed in the .app file.
This is corrected so they are now sorted (internally between each
other) in the same way as they are listed in the .rel file.
---
lib/sasl/src/systools_make.erl | 60 +++++++++++-------
lib/sasl/test/systools_SUITE.erl | 133 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 166 insertions(+), 27 deletions(-)
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index 12ba2a5476..3c1002e4a6 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -375,7 +375,7 @@ get_release1(File, Path, ModTestP, Machine) ->
{ok, Release, Warnings1} = read_release(File, Path),
{ok, Appls0} = collect_applications(Release, Path),
{ok, Appls1} = check_applications(Appls0),
- {ok, Appls2} = sort_included_applications(Appls1, Release), % OTP-4121
+ {ok, Appls2} = sort_used_and_incl_appls(Appls1, Release), % OTP-4121, OTP-9984
{ok, Warnings2} = check_modules(Appls2, Path, ModTestP, Machine),
{ok, Appls} = sort_appls(Appls2),
{ok, Release, Appls, Warnings1 ++ Warnings2}.
@@ -842,34 +842,45 @@ undefined_applications(Appls) ->
filter(fun(X) -> not member(X, Defined) end, Uses).
%%______________________________________________________________________
-%% sort_included_applications(Applications, Release) -> Applications
+%% sort_used_and_incl_appls(Applications, Release) -> Applications
%% Applications = [{{Name,Vsn},#application}]
%% Release = #release{}
%%
-%% Check that included applications are given in the same order as in
-%% the release resource file (.rel). Otherwise load instructions in
-%% the boot script, and consequently release upgrade instructions in
-%% relup, may end up in the wrong order.
+%% OTP-4121, OTP-9984
+%% Check that used and included applications are given in the same
+%% order as in the release resource file (.rel). Otherwise load and
+%% start instructions in the boot script, and consequently release
+%% upgrade instructions in relup, may end up in the wrong order.
-sort_included_applications(Applications, Release) when is_tuple(Release) ->
+sort_used_and_incl_appls(Applications, Release) when is_tuple(Release) ->
{ok,
- sort_included_applications(Applications, Release#release.applications)};
-
-sort_included_applications([{Tuple,Appl}|Appls], OrderedAppls) ->
- case Appl#application.includes of
- Incls when length(Incls)>1 ->
- IndexedIncls = find_pos(Incls, OrderedAppls),
- SortedIndexedIncls = lists:keysort(1, IndexedIncls),
- Incls2 = lists:map(fun({_Index,Name}) -> Name end,
- SortedIndexedIncls),
- Appl2 = Appl#application{includes=Incls2},
- [{Tuple,Appl2}|sort_included_applications(Appls, OrderedAppls)];
- _Incls ->
- [{Tuple,Appl}|sort_included_applications(Appls, OrderedAppls)]
- end;
-sort_included_applications([], _OrderedAppls) ->
+ sort_used_and_incl_appls(Applications, Release#release.applications)};
+
+sort_used_and_incl_appls([{Tuple,Appl}|Appls], OrderedAppls) ->
+ Incls2 =
+ case Appl#application.includes of
+ Incls when length(Incls)>1 ->
+ sort_appl_list(Incls, OrderedAppls);
+ Incls ->
+ Incls
+ end,
+ Uses2 =
+ case Appl#application.uses of
+ Uses when length(Uses)>1 ->
+ sort_appl_list(Uses, OrderedAppls);
+ Uses ->
+ Uses
+ end,
+ Appl2 = Appl#application{includes=Incls2, uses=Uses2},
+ [{Tuple,Appl2}|sort_used_and_incl_appls(Appls, OrderedAppls)];
+sort_used_and_incl_appls([], _OrderedAppls) ->
[].
+sort_appl_list(List, Order) ->
+ IndexedList = find_pos(List, Order),
+ SortedIndexedList = lists:keysort(1, IndexedList),
+ lists:map(fun({_Index,Name}) -> Name end, SortedIndexedList).
+
find_pos([Name|Incs], OrderedAppls) ->
[find_pos(1, Name, OrderedAppls)|find_pos(Incs, OrderedAppls)];
find_pos([], _OrderedAppls) ->
@@ -1253,7 +1264,8 @@ sort_appls(Appls) -> {ok, sort_appls(Appls, [], [], [])}.
sort_appls([{N, A}|T], Missing, Circular, Visited) ->
{Name,_Vsn} = N,
- {Uses, T1, NotFnd1} = find_all(Name, A#application.uses, T, Visited, [], []),
+ {Uses, T1, NotFnd1} = find_all(Name, lists:reverse(A#application.uses),
+ T, Visited, [], []),
{Incs, T2, NotFnd2} = find_all(Name, lists:reverse(A#application.includes),
T1, Visited, [], []),
Missing1 = NotFnd1 ++ NotFnd2 ++ Missing,
diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl
index 4cf7364d74..72b3eb8954 100644
--- a/lib/sasl/test/systools_SUITE.erl
+++ b/lib/sasl/test/systools_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -45,7 +45,7 @@
abnormal_script/1, src_tests_script/1, crazy_script/1,
included_script/1, included_override_script/1,
included_fail_script/1, included_bug_script/1, exref_script/1,
- otp_3065_circular_dependenies/1]).
+ otp_3065_circular_dependenies/1, included_and_used_sort_script/1]).
-export([tar_options/1, normal_tar/1, no_mod_vsn_tar/1, system_files_tar/1,
system_files_tar/2, invalid_system_files_tar/1,
invalid_system_files_tar/2, variable_tar/1,
@@ -80,7 +80,7 @@ groups() ->
no_sasl_script, src_tests_script, crazy_script,
included_script, included_override_script,
included_fail_script, included_bug_script, exref_script,
- otp_3065_circular_dependenies]},
+ otp_3065_circular_dependenies, included_and_used_sort_script]},
{tar, [],
[tar_options, normal_tar, no_mod_vsn_tar, system_files_tar,
invalid_system_files_tar, variable_tar,
@@ -600,6 +600,24 @@ otp_3065_circular_dependenies(Config) when is_list(Config) ->
ok = file:set_cwd(OldDir),
ok.
+%% Test sorting of included applications and used applications
+included_and_used_sort_script(Config) when is_list(Config) ->
+ {ok, OldDir} = file:get_cwd(),
+ {LatestDir1, LatestName1} = create_include_files(sort_apps, Config),
+ ok = file:set_cwd(LatestDir1),
+ ok = systools:make_script(LatestName1),
+ ok = check_include_script(LatestName1,
+ [t20,t19,t18,t17,t16,t15,t14],[t20,t19,t18,t14]),
+
+ {LatestDir2, LatestName2} = create_include_files(sort_apps_rev, Config),
+ ok = file:set_cwd(LatestDir2),
+ ok = systools:make_script(LatestName2),
+ ok = check_include_script(LatestName2,
+ [t18,t19,t20,t15,t16,t17,t14],[t18,t19,t20,t14]),
+
+ ok = file:set_cwd(OldDir),
+ ok.
+
%% make_script: Check that make_script exref option works.
exref_script(Config) when is_list(Config) ->
@@ -2301,8 +2319,53 @@ create_include_files(otp_3065_circular_dependenies, Config) ->
" {chAts, \"1.0\"}, {aa12, \"1.0\"}, \n"
" {chTraffic, \"1.0\"}]}.\n",
file:write_file(Name ++ ".rel", list_to_binary(Rel)),
+ {filename:dirname(Name), filename:basename(Name)};
+
+create_include_files(sort_apps, Config) ->
+ PrivDir = ?privdir,
+ Name = fname(PrivDir, sort_apps),
+ create_sort_apps(PrivDir),
+
+ Apps = application_controller:which_applications(),
+ {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps),
+ {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps),
+
+ Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\n"
+ " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \""
+ ++ StdlibVer ++ "\"},\n"
+ " {t14, \"1.0\"}, \n"
+ " {t20, \"1.0\"}, \n"
+ " {t19, \"1.0\"}, \n"
+ " {t18, \"1.0\"}, \n"
+ " {t17, \"1.0\"}, \n"
+ " {t16, \"1.0\"}, \n"
+ " {t15, \"1.0\"}]}.\n",
+ file:write_file(Name ++ ".rel", list_to_binary(Rel)),
+ {filename:dirname(Name), filename:basename(Name)};
+
+create_include_files(sort_apps_rev, Config) ->
+ PrivDir = ?privdir,
+ Name = fname(PrivDir, sort_apps_rev),
+ create_sort_apps(PrivDir),
+
+ Apps = application_controller:which_applications(),
+ {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps),
+ {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps),
+
+ Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\n"
+ " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \""
+ ++ StdlibVer ++ "\"},\n"
+ " {t14, \"1.0\"}, \n"
+ " {t18, \"1.0\"}, \n"
+ " {t19, \"1.0\"}, \n"
+ " {t20, \"1.0\"}, \n"
+ " {t15, \"1.0\"}, \n"
+ " {t16, \"1.0\"}, \n"
+ " {t17, \"1.0\"}]}.\n",
+ file:write_file(Name ++ ".rel", list_to_binary(Rel)),
{filename:dirname(Name), filename:basename(Name)}.
+
create_apps(Dir) ->
T1 = "{application, t1,\n"
" [{vsn, \"1.0\"},\n"
@@ -2451,6 +2514,70 @@ create_apps_3065(Dir) ->
" {registered, []}]}.\n",
file:write_file(fname(Dir, 'aa12.app'), list_to_binary(T13)).
+create_sort_apps(Dir) ->
+ T14 = "{application, t14,\n"
+ " [{vsn, \"1.0\"},\n"
+ " {description, \"test\"},\n"
+ " {modules, []},\n"
+ " {applications, [t18,t20,t19]},\n"
+ " {included_applications, [t15,t17,t16]},\n"
+ " {registered, []}]}.\n",
+ file:write_file(fname(Dir, 't14.app'), list_to_binary(T14)),
+
+ T15 = "{application, t15,\n"
+ " [{vsn, \"1.0\"},\n"
+ " {description, \"test\"},\n"
+ " {modules, []},\n"
+ " {applications, []},\n"
+ " {included_applications, []},\n"
+ " {registered, []}]}.\n",
+ file:write_file(fname(Dir, 't15.app'), list_to_binary(T15)),
+
+ T16 = "{application, t16,\n"
+ " [{vsn, \"1.0\"},\n"
+ " {description, \"test\"},\n"
+ " {modules, []},\n"
+ " {applications, []},\n"
+ " {included_applications, []},\n"
+ " {registered, []}]}.\n",
+ file:write_file(fname(Dir, 't16.app'), list_to_binary(T16)),
+
+ T17 = "{application, t17,\n"
+ " [{vsn, \"1.0\"},\n"
+ " {description, \"test\"},\n"
+ " {modules, []},\n"
+ " {applications, []},\n"
+ " {included_applications, []},\n"
+ " {registered, []}]}.\n",
+ file:write_file(fname(Dir, 't17.app'), list_to_binary(T17)),
+
+ T18 = "{application, t18,\n"
+ " [{vsn, \"1.0\"},\n"
+ " {description, \"test\"},\n"
+ " {modules, []},\n"
+ " {applications, []},\n"
+ " {included_applications, []},\n"
+ " {registered, []}]}.\n",
+ file:write_file(fname(Dir, 't18.app'), list_to_binary(T18)),
+
+ T19 = "{application, t19,\n"
+ " [{vsn, \"1.0\"},\n"
+ " {description, \"test\"},\n"
+ " {modules, []},\n"
+ " {applications, []},\n"
+ " {included_applications, []},\n"
+ " {registered, []}]}.\n",
+ file:write_file(fname(Dir, 't19.app'), list_to_binary(T19)),
+
+ T20 = "{application, t20,\n"
+ " [{vsn, \"1.0\"},\n"
+ " {description, \"test\"},\n"
+ " {modules, []},\n"
+ " {applications, []},\n"
+ " {included_applications, []},\n"
+ " {registered, []}]}.\n",
+ file:write_file(fname(Dir, 't20.app'), list_to_binary(T20)).
+
fname(N) ->
filename:join(N).
--
cgit v1.2.3
From 20ef6a7d381b37d7c620f303a981a3a8b4e227a8 Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Mon, 19 Mar 2012 09:06:38 +0100
Subject: [reltool] Remove skip statement for test that failed due to stdlib
error
The stdlib error has been corrected in a previous commit so the
failing test (reltool_server_SUITE:create_script_sort) can be
un-skipped.
---
lib/reltool/test/reltool_server_SUITE.erl | 1 -
1 file changed, 1 deletion(-)
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index 122880fca9..4e24a2fb55 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -454,7 +454,6 @@ create_script(_Config) ->
%% Test creation of .script with different sorting of applications and
%% included applications.
%% Test that result is equal to what systools produces
-create_script_sort(_Config) -> {skip, "OTP-9984 - stdlib sort problem"};
create_script_sort(Config) ->
DataDir = ?config(data_dir,Config),
%% Configure the server
--
cgit v1.2.3
From 844afaf366ad7a4f668a60e896d0ae3b9e5d850b Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Mon, 19 Mar 2012 15:54:30 +0100
Subject: [reltool] Fix GUI problems on Windows
The new warning list did not work on Windows. It could not display
tooltips for each warning and the popup window would always disappear
behind the main system window.
Also, column width did not occur well initially in list controls.
---
lib/reltool/src/reltool_app_win.erl | 4 +-
lib/reltool/src/reltool_sys_win.erl | 83 +++++++++++++++++----------
lib/reltool/src/reltool_utils.erl | 21 +++++++
lib/reltool/test/reltool_manual_gui_SUITE.erl | 13 +++--
4 files changed, 82 insertions(+), 39 deletions(-)
diff --git a/lib/reltool/src/reltool_app_win.erl b/lib/reltool/src/reltool_app_win.erl
index 70bd72b258..eddb37ea11 100644
--- a/lib/reltool/src/reltool_app_win.erl
+++ b/lib/reltool/src/reltool_app_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -271,8 +271,8 @@ create_apps_list_ctrl(Panel, Sizer, Text) ->
ListItem = wxListItem:new(),
wxListItem:setAlign(ListItem, ?wxLIST_FORMAT_LEFT),
wxListItem:setText(ListItem, Text),
+ wxListItem:setWidth(ListItem, reltool_utils:get_column_width(ListCtrl)),
wxListCtrl:insertColumn(ListCtrl, ?APPS_APP_COL, ListItem),
- %% wxListCtrl:setColumnWidth(ListCtrl, ?APPS_APP_COL, ?APPS_APP_COL_WIDTH),
wxListItem:destroy(ListItem),
wxSizer:add(Sizer, ListCtrl,
diff --git a/lib/reltool/src/reltool_sys_win.erl b/lib/reltool/src/reltool_sys_win.erl
index 29a01b63d8..912a47ec39 100644
--- a/lib/reltool/src/reltool_sys_win.erl
+++ b/lib/reltool/src/reltool_sys_win.erl
@@ -458,6 +458,7 @@ create_app_list_ctrl(Panel, OuterSz, Title, Tick, Cross) ->
ListItem = wxListItem:new(),
wxListItem:setAlign(ListItem, ?wxLIST_FORMAT_LEFT),
wxListItem:setText(ListItem, Title),
+ wxListItem:setWidth(ListItem, reltool_utils:get_column_width(ListCtrl)),
wxListCtrl:insertColumn(ListCtrl, ?APPS_APP_COL, ListItem),
wxListItem:destroy(ListItem),
@@ -665,7 +666,8 @@ create_warning_list(#state{panel = Panel} = S) ->
{size, {?WIN_WIDTH,80}}]),
reltool_utils:assign_image_list(ListCtrl),
wxListCtrl:insertColumn(ListCtrl, ?WARNING_COL, "Warnings",
- [{format,?wxLIST_FORMAT_LEFT}]),
+ [{format,?wxLIST_FORMAT_LEFT},
+ {width,reltool_utils:get_column_width(ListCtrl)}]),
wxListCtrl:setToolTip(ListCtrl, ?DEFAULT_WARNING_TIP),
wxEvtHandler:connect(ListCtrl, size,
[{skip, true}, {userData, warnings}]),
@@ -907,7 +909,9 @@ handle_event(S, #wx{id = Id, obj= ObjRef, userData = UserData, event = Event} =
when S#state.popup_menu =/= undefined ->
handle_popup_event(S, Type, Id, ObjRef, UserData, Str);
#wxMouse{type = enter_window} ->
- wxWindow:setFocus(ObjRef),
+ %% The following is commented out because it raises the
+ %% main system window on top of popup windows.
+ %% wxWindow:setFocus(ObjRef),
S;
_ ->
case wxNotebook:getPageText(S#state.book,
@@ -920,21 +924,12 @@ handle_event(S, #wx{id = Id, obj= ObjRef, userData = UserData, event = Event} =
end.
handle_warning_event(S, ObjRef, _, #wxSize{type = size}) ->
- {Total, _} = wxWindow:getClientSize(ObjRef),
- SBSize = scroll_size(ObjRef),
- wxListCtrl:setColumnWidth(ObjRef, ?WARNING_COL, Total-SBSize),
+ ColumnWidth = reltool_utils:get_column_width(ObjRef),
+ wxListCtrl:setColumnWidth(ObjRef, ?WARNING_COL, ColumnWidth),
S;
handle_warning_event(S, ObjRef, _, #wxMouse{type = motion, x=X, y=Y}) ->
Pos = reltool_utils:wait_for_stop_motion(ObjRef, {X,Y}),
- Index = wxListCtrl:findItem(ObjRef,-1,Pos,0),
- Tip =
- case wxListCtrl:getItemText(ObjRef,Index) of
- "" ->
- ?DEFAULT_WARNING_TIP;
- Text ->
- "WARNING:\n" ++ Text
- end,
- wxListCtrl:setToolTip(ObjRef, Tip),
+ warning_list_set_tool_tip(os:type(),ObjRef,Pos),
S;
handle_warning_event(S, ObjRef, _, #wxList{type = command_list_item_activated,
itemIndex = Pos}) ->
@@ -945,6 +940,49 @@ handle_warning_event(S, _ObjRef, {warning,Frame},
wxFrame:destroy(Frame),
S#state{warning_wins = lists:delete(Frame,S#state.warning_wins)}.
+warning_list_set_tool_tip({win32,_},ListCtrl,{_X,Y}) ->
+ case win_find_item(ListCtrl,Y,0) of
+ -1 ->
+ wxListCtrl:setToolTip(ListCtrl,?DEFAULT_WARNING_TIP);
+ _Index ->
+ %% The following is commented out because there seems to
+ %% be an utomatic tooltip under Windows that shows the
+ %% expanded list item in case it is truncated because it
+ %% is too long for column width.
+ %% Tip =
+ %% case wxListCtrl:getItemText(ListCtrl,Index) of
+ %% "" ->
+ %% ?DEFAULT_WARNING_TIP;
+ %% Text ->
+ %% "WARNING:\n" ++ Text
+ %% end,
+ %% wxListCtrl:setToolTip(ListCtrl,Tip),
+ ok
+ end;
+warning_list_set_tool_tip(_,ListCtrl,Pos) ->
+ case wxListCtrl:findItem(ListCtrl,-1,Pos,0) of
+ Index when Index >= 0 ->
+ Tip =
+ case wxListCtrl:getItemText(ListCtrl,Index) of
+ "" ->
+ ?DEFAULT_WARNING_TIP;
+ Text ->
+ "WARNING:\n" ++ Text
+ end,
+ wxListCtrl:setToolTip(ListCtrl, Tip);
+ _ ->
+ ok
+ end.
+
+win_find_item(ListCtrl,YPos,Index) ->
+ case wxListCtrl:getItemRect(ListCtrl,Index) of
+ {true,{_,Y,_,H}} when YPos>=Y, YPos=
+ Index;
+ {true,_} ->
+ win_find_item(ListCtrl,YPos,Index+1);
+ {false,_} ->
+ -1
+ end.
display_warning(S,Warning) ->
Pos = warning_popup_position(S,?WARNING_POPUP_SIZE),
@@ -954,8 +992,6 @@ display_warning(S,Warning) ->
Text = wxTextCtrl:new(Panel, ?wxID_ANY, [{value, Warning},
{style, TextStyle},
{size, ?WARNING_POPUP_SIZE}]),
- Color = wxWindow:getBackgroundColour(Frame),
- wxTextCtrl:setBackgroundColour(Text,Color),
Attr = wxTextAttr:new(),
wxTextAttr:setLeftIndent(Attr,10),
wxTextAttr:setRightIndent(Attr,10),
@@ -1608,21 +1644,6 @@ add_text(_,_,[]) ->
ok.
-scroll_size(ObjRef) ->
- case os:type() of
- {win32, nt} -> 0;
- {unix, darwin} ->
- %% I can't figure out is there is a visible scrollbar
- %% Always make room for it
- wxSystemSettings:getMetric(?wxSYS_VSCROLL_X);
- _ ->
- case wxWindow:hasScrollbar(ObjRef, ?wxVERTICAL) of
- true -> wxSystemSettings:getMetric(?wxSYS_VSCROLL_X);
- false -> 0
- end
- end.
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% sys callbacks
diff --git a/lib/reltool/src/reltool_utils.erl b/lib/reltool/src/reltool_utils.erl
index 3e50324011..b0def45213 100644
--- a/lib/reltool/src/reltool_utils.erl
+++ b/lib/reltool/src/reltool_utils.erl
@@ -29,6 +29,7 @@
app_dir_test/2, split_app_dir/1,
get_item/1, get_items/1, get_selected_items/3,
select_items/3, select_item/2,
+ get_column_width/1,
safe_keysearch/5, print/4, add_warning/3,
@@ -383,6 +384,26 @@ select_item(ListCtrl, [{ItemNo, Text} | Items]) ->
select_item(_ListCtrl, []) ->
ok.
+get_column_width(ListCtrl) ->
+ wx:batch(fun() ->
+ {Total, _} = wxWindow:getClientSize(ListCtrl),
+ Total - scroll_size(ListCtrl)
+ end).
+
+scroll_size(ObjRef) ->
+ case os:type() of
+ {win32, nt} -> 0;
+ {unix, darwin} ->
+ %% I can't figure out is there is a visible scrollbar
+ %% Always make room for it
+ wxSystemSettings:getMetric(?wxSYS_VSCROLL_X);
+ _ ->
+ case wxWindow:hasScrollbar(ObjRef, ?wxVERTICAL) of
+ true -> wxSystemSettings:getMetric(?wxSYS_VSCROLL_X);
+ false -> 0
+ end
+ end.
+
safe_keysearch(Key, Pos, List, Mod, Line) ->
case lists:keysearch(Key, Pos, List) of
false ->
diff --git a/lib/reltool/test/reltool_manual_gui_SUITE.erl b/lib/reltool/test/reltool_manual_gui_SUITE.erl
index 1ebee9fae1..0dcc5cbf15 100644
--- a/lib/reltool/test/reltool_manual_gui_SUITE.erl
+++ b/lib/reltool/test/reltool_manual_gui_SUITE.erl
@@ -97,14 +97,14 @@ config(Config) ->
break("the warning text can be marked, copied and pasted",
"close the popup with the close box on the top frame"),
break("it disappears",
- "select application a from 'Included' column and click red cross to "
- "exclude it"),
+ "select application a from 'Included' column and click 'cross'-button "
+ "with to exclude it"),
break("application a is moved to 'Excluded' column",
- "select application tools from 'Excluded' column and click green V to "
- "include it"),
+ "select application tools from 'Excluded' column and click "
+ "'tick'-button to include it"),
break("application tools is moved to 'Included' column",
"select application runtime_tools from 'Excluded' column and click "
- "green V to include it"),
+ "'tick'-button to include it"),
break("application runtime_tools is moved to 'Included' column",
"undo"),
@@ -171,7 +171,8 @@ config(Config) ->
{ok,ServerPid} = reltool:get_server(SysPid),
unlink(SysPid),
break("the system window is still alive",
- "terminate reltool by hitting 'Ctrl-q' when system window is active"),
+ "terminate reltool by hitting 'Ctrl-q' (linux) or clicking the "
+ "close box on the top fram when system window is active"),
false = erlang:is_process_alive(SysPid),
false = erlang:is_process_alive(ServerPid),
--
cgit v1.2.3
From e67e94c20f16a102da93a40cfe4edf7885a602d8 Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Tue, 20 Mar 2012 11:33:18 +0100
Subject: [reltool] Update status bar for all config changes and for generate
target
OTP-9792
For some configuration changes and during generation of target system,
there was no indication in the status bar that reltool was
working. This has been corrected - it now says "Processing
libraries...".
---
lib/reltool/src/reltool_sys_win.erl | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/lib/reltool/src/reltool_sys_win.erl b/lib/reltool/src/reltool_sys_win.erl
index 912a47ec39..0c0b295db1 100644
--- a/lib/reltool/src/reltool_sys_win.erl
+++ b/lib/reltool/src/reltool_sys_win.erl
@@ -1246,9 +1246,12 @@ handle_app_event(S, Event, ObjRef, UserData) ->
[?MODULE, self(), ObjRef, UserData, Event]),
S.
-handle_app_button(#state{server_pid = ServerPid, app_wins = AppWins} = S,
+handle_app_button(#state{server_pid = ServerPid,
+ status_bar = Bar,
+ app_wins = AppWins} = S,
Items,
Action) ->
+ wxStatusBar:setStatusText(Bar, "Processing libraries..."),
NewApps = [move_app(S, Item, Action) || Item <- Items],
case reltool_server:set_apps(ServerPid, NewApps) of
{ok, _Warnings} ->
@@ -1289,7 +1292,10 @@ move_app(S, {_ItemNo, AppBase}, Action) ->
end,
OldApp#app{incl_cond = AppCond}.
-do_set_app(#state{server_pid = ServerPid, app_wins = AppWins} = S, NewApp) ->
+do_set_app(#state{server_pid = ServerPid,
+ status_bar = Bar,
+ app_wins = AppWins} = S, NewApp) ->
+ wxStatusBar:setStatusText(Bar, "Processing libraries..."),
Result = reltool_server:set_app(ServerPid, NewApp),
ReturnApp =
case Result of
@@ -1489,26 +1495,28 @@ save_config(#state{config_file = OldFile} = S, InclDefaults, InclDerivates) ->
S
end.
-gen_rel_files(#state{target_dir = OldDir} = S) ->
+gen_rel_files(#state{status_bar = Bar, target_dir = OldDir} = S) ->
Style = ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT,
case select_dir(S#state.frame,
"Select a directory to generate rel, script and boot files to",
OldDir,
Style) of
{ok, NewDir} ->
+ wxStatusBar:setStatusText(Bar, "Processing libraries..."),
Status = reltool_server:gen_rel_files(S#state.server_pid, NewDir),
check_and_refresh(S, Status);
cancel ->
S
end.
-gen_target(#state{target_dir = OldDir} = S) ->
+gen_target(#state{status_bar = Bar, target_dir = OldDir} = S) ->
Style = ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT,
case select_dir(S#state.frame,
"Select a directory to generate a target system to",
OldDir,
Style) of
{ok, NewDir} ->
+ wxStatusBar:setStatusText(Bar, "Processing libraries..."),
Status = reltool_server:gen_target(S#state.server_pid, NewDir),
check_and_refresh(S#state{target_dir = NewDir}, Status);
cancel ->
--
cgit v1.2.3
From e855e8326a6ce589991da9cafc2590f306d035c3 Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Tue, 20 Mar 2012 11:47:48 +0100
Subject: [reltool] Improve title of dependency colum
OTP-9792
The colum listing modules that uses the current application or module
did earlier have the title "Modules used by others". This is now
changed to "Modules using this".
---
lib/reltool/src/reltool_app_win.erl | 2 +-
lib/reltool/src/reltool_mod_win.erl | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/reltool/src/reltool_app_win.erl b/lib/reltool/src/reltool_app_win.erl
index eddb37ea11..e0acfab7aa 100644
--- a/lib/reltool/src/reltool_app_win.erl
+++ b/lib/reltool/src/reltool_app_win.erl
@@ -292,7 +292,7 @@ create_deps_page(S, Derived) ->
UsedByCtrl = create_mods_list_ctrl(Panel,
Main,
- "Modules used by others",
+ "Modules using this",
" and their applications",
undefined,
undefined),
diff --git a/lib/reltool/src/reltool_mod_win.erl b/lib/reltool/src/reltool_mod_win.erl
index 8cf175547b..899423bb6d 100644
--- a/lib/reltool/src/reltool_mod_win.erl
+++ b/lib/reltool/src/reltool_mod_win.erl
@@ -215,7 +215,7 @@ create_deps_page(S) ->
UsedByCtrl = create_mods_list_ctrl(Panel,
Main,
- "Modules used by others",
+ "Modules using this",
" and their applications"),
wxSizer:add(Main,
wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]),
--
cgit v1.2.3