aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSiri Hansen <[email protected]>2012-02-24 15:52:34 +0100
committerSiri Hansen <[email protected]>2012-03-19 09:48:54 +0100
commit537773c0e6969cb89f92aec0244ba29b07ec66ea (patch)
treee9b0cb88965ddad387bc6e7a154bc067538dbacb
parentc714eff72c1bd15f8831cffe7256f3dfd8faf806 (diff)
downloadotp-537773c0e6969cb89f92aec0244ba29b07ec66ea.tar.gz
otp-537773c0e6969cb89f92aec0244ba29b07ec66ea.tar.bz2
otp-537773c0e6969cb89f92aec0244ba29b07ec66ea.zip
[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
-rw-r--r--lib/reltool/src/reltool.erl6
-rw-r--r--lib/reltool/src/reltool_server.erl673
-rw-r--r--lib/reltool/src/reltool_sys_win.erl73
-rw-r--r--lib/reltool/src/reltool_utils.erl35
-rw-r--r--lib/reltool/test/reltool_server_SUITE.erl44
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): <ERROR> ~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): <ERROR> ~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): <ERROR> ~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.