diff options
Diffstat (limited to 'lib/reltool/src')
-rw-r--r-- | lib/reltool/src/reltool_server.erl | 189 | ||||
-rw-r--r-- | lib/reltool/src/reltool_sys_win.erl | 159 |
2 files changed, 249 insertions, 99 deletions
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl index 9743289ca6..692baea0a4 100644 --- a/lib/reltool/src/reltool_server.erl +++ b/lib/reltool/src/reltool_server.erl @@ -465,16 +465,16 @@ analyse(#state{common = C, [MissingApp2 | Apps2] end, app_propagate_is_used_by(C, Apps3), - Apps4 = read_apps(C, Sys, 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, Status3) of - {ok, _Warnings} = Status4 -> - {S#state{sys = Sys2}, Status4}; - {error, _} = Status4 -> - {S, Status4} + case verify_config(RelApps2, Sys2, Status4) of + {ok, _Warnings} = Status5 -> + {S#state{sys = Sys2}, Status5}; + {error, _} = Status5 -> + {S, Status5} end. apps_in_rels(Rels, Apps, Status) -> @@ -548,21 +548,24 @@ app_init_is_included(C, {derived, [_ | _]} -> % App is included in at least one rel {true, undefined, true, Status} end, - A2 = A#app{is_pre_included = IsPreIncl, + {Mods2,Status3} = lists:mapfoldl(fun(Mod,Acc) -> + mod_init_is_included(C, + Mod, + ModCond, + AppCond, + Default, + Acc) + end, + Status2, + Mods), + A2 = A#app{mods = Mods2, + is_pre_included = IsPreIncl, is_included = IsIncl, rels = Rels}, ets:insert(C#common.app_tab, A2), - lists:foreach(fun(Mod) -> - mod_init_is_included(C, - Mod, - ModCond, - AppCond, - Default) - end, - Mods), - {A2, Status2}. - -mod_init_is_included(C, M, ModCond, AppCond, Default) -> + {A2, Status3}. + +mod_init_is_included(C, M, ModCond, AppCond, Default, Status) -> %% print(M#mod.name, hipe, "incl_cond -> ~p\n", [AppCond]), IsIncl = case AppCond of @@ -595,9 +598,52 @@ mod_init_is_included(C, M, ModCond, AppCond, Default) -> Default end end, + M2 = M#mod{is_pre_included = IsIncl, is_included = IsIncl}, + + Status2 = + case ets:lookup(C#common.mod_tab,M#mod.name) of + [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(C#common.mod_tab, M2), + reltool_utils:add_warning(Status,Warning); + {_,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 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) + end; + [] -> + ets:insert(C#common.mod_tab, M2), + Status + end, + %% print(M#mod.name, hipe, "~p -> ~p\n", [M2, IsIncl]), - ets:insert(C#common.mod_tab, M2). + {M2,Status2}. false_to_undefined(Bool) -> case Bool of @@ -612,21 +658,27 @@ app_propagate_is_included(_C, _Sys, [], Acc) -> Acc. mod_propagate_is_included(C, Sys, A, [#mod{name = ModName} | Mods], Acc) -> - [M2] = ets:lookup(C#common.mod_tab, ModName), - %% 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]), Acc2 = - 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, + 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. @@ -740,9 +792,10 @@ mod_propagate_is_used_by(C, [#mod{name = ModName} | Mods]) -> mod_propagate_is_used_by(_C, []) -> ok. -read_apps(C, Sys, [#app{mods = Mods, is_included = IsIncl} = A | Apps], Acc) -> - {Mods2, IsIncl2} = read_apps(C, Sys, A, Mods, [], IsIncl), - Status = +app_recap_dependencies(C, Sys, [#app{mods = Mods, is_included = IsIncl} = A | Apps], Acc, Status) -> + {Mods2, IsIncl2, Status2} = + mod_recap_dependencies(C, Sys, A, Mods, [], IsIncl, Status), + AppStatus = case lists:keymember(missing, #mod.status, Mods2) of true -> missing; false -> ok @@ -759,34 +812,52 @@ read_apps(C, Sys, [#app{mods = Mods, is_included = IsIncl} = A | Apps], Acc) -> UsedByApps2 = lists:usort(UsedByApps), A2 = A#app{mods = Mods2, - status = Status, + status = AppStatus, uses_mods = UsesMods2, used_by_mods = UsedByMods2, uses_apps = UsesApps2, used_by_apps = UsedByApps2, is_included = IsIncl2}, - read_apps(C, Sys, Apps, [A2 | Acc]); -read_apps(_C, _Sys, [], Acc) -> - lists:reverse(Acc). - -read_apps(C, Sys, A, [#mod{name = ModName} | Mods], Acc, IsIncl) -> - [M2] = ets:lookup(C#common.mod_tab, ModName), - Status = do_get_status(M2), - %% print(M2#mod.name, hipe, "status -> ~p\n", [Status]), - {IsIncl2, M3} = - case M2#mod.is_included of - true -> - UsedByMods = - [N || {_, N} <- ets:lookup(C#common.mod_used_by_tab, - ModName)], - {true, M2#mod{status = Status, used_by_mods = UsedByMods}}; - _ -> - {IsIncl, M2#mod{status = Status, used_by_mods = []}} - end, - ets:insert(C#common.mod_tab, M3), - read_apps(C, Sys, A, Mods, [M3 | Acc], IsIncl2); -read_apps(_C, _Sys, _A, [], Acc, IsIncl) -> - {lists:reverse(Acc), IsIncl}. + 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}. + +mod_recap_dependencies(C, Sys, 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), + %% print(M2#mod.name, hipe, "status -> ~p\n", [ModStatus]), + {IsIncl2, M3} = + case M2#mod.is_included of + true -> + UsedByMods = + [N || {_, N} <- ets:lookup(C#common.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, Sys, A, Mods, [M3 | Acc], IsIncl2, Status); + [_] 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, Sys, A, Mods, [M1 | Acc], IsIncl, Status); + [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, Sys, A, Mods, [M1 | Acc], IsIncl, Status2) + end; +mod_recap_dependencies(_C, _Sys, _A, [], Acc, IsIncl, Status) -> + {lists:reverse(Acc), IsIncl, Status}. do_get_status(M) -> if diff --git a/lib/reltool/src/reltool_sys_win.erl b/lib/reltool/src/reltool_sys_win.erl index dbb8e32aa2..8b0f64eb45 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-2010. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. 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 @@ -54,7 +54,9 @@ whitelist, blacklist, derived, - fgraph_wins + fgraph_wins, + app_box, + mod_box }). -define(WIN_WIDTH, 800). @@ -86,6 +88,11 @@ -define(blacklist, "Excluded"). -define(derived, "Derived"). +-define(safe_config,{sys,[{incl_cond,exclude}, + {app,kernel,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}]}). + -record(root_data, {dir}). -record(lib_data, {dir, tree, item}). -record(escript_data, {file, tree, item}). @@ -102,7 +109,7 @@ start_link(Opts) -> proc_lib:start_link(?MODULE, init, - [[{parent, self()} | Opts]], + [[{safe_config, false}, {parent, self()} | Opts]], infinity, []). @@ -126,53 +133,73 @@ init(Options) -> exit({Reason, erlang:get_stacktrace()}) end. -do_init([{parent, Parent} | Options]) -> +do_init([{safe_config, Safe}, {parent, Parent} | Options]) -> case reltool_server:start_link(Options) of {ok, ServerPid, C, Sys} -> process_flag(trap_exit, C#common.trap_exit), - 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 = []}, wx:new(), wx:debug(C#common.wx_debug), - S2 = create_window(S), %% wx_misc:beginBusyCursor(), case reltool_server:get_status(ServerPid) of {ok, Warnings} -> exit_dialog(Warnings), - {ok, Sys2} = reltool_server:get_sys(ServerPid), - S3 = S2#state{sys = Sys2}, + {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(S3#state.frame, + wxFrame:setTitle(S2#state.frame, Title), %% wxFrame:setMinSize(Frame, %% {?WIN_WIDTH, ?WIN_HEIGHT}), wxStatusBar:setStatusText( - S3#state.status_bar, + S2#state.status_bar, "Done."), - S4 = redraw_apps(S3), - redraw_libs(S4) + 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; {error, Reason} -> io:format("~p(~p): <ERROR> ~p\n", [?MODULE, ?LINE, Reason]), exit(Reason) end. +restart_server_safe_config(true,_Parent,Reason) -> + io:format("~p(~p): <ERROR> ~p\n", [?MODULE, ?LINE, Reason]), + exit(Reason); +restart_server_safe_config(false,Parent,Reason) -> + Strings = + [{?wxBLACK,"Could not start reltool server:\n\n"}, + {?wxRED,Reason++"\n\n"}, + {?wxBLACK, + io_lib:format( + "Resetting the configuration to:~n~n ~p~n~n" + "Do you want to continue with this configuration?", + [?safe_config])}], + + case question_dialog_2("Reltool server start error", Strings) of + ?wxID_OK -> + do_init([{safe_config,true},{parent,Parent},?safe_config]); + ?wxID_CANCEL -> + io:format("~p(~p): <ERROR> ~p\n", [?MODULE, ?LINE, Reason]), + exit(Reason) + end. + exit_dialog([]) -> ok; exit_dialog(Warnings) -> @@ -606,6 +633,13 @@ create_config_page(#state{sys = Sys, book = Book} = S) -> {proportion, 1}]), wxPanel:setSizer(Panel, Sizer), wxNotebook:addPage(Book, Panel, ?SYS_PAGE, []), + S#state{app_box = AppBox, mod_box = ModBox}. + +redraw_config_page(#state{sys = Sys, app_box = AppBox, mod_box = ModBox} = S) -> + AppChoice = reltool_utils:incl_cond_to_index(Sys#sys.incl_cond), + wxRadioBox:setSelection(AppBox, AppChoice), + ModChoice = reltool_utils:mod_cond_to_index(Sys#sys.mod_cond), + wxRadioBox:setSelection(ModBox, ModChoice), S. create_main_release_page(#state{book = Book} = S) -> @@ -640,15 +674,15 @@ create_main_release_page(#state{book = Book} = S) -> add_release_page(Book, #rel{name = RelName, rel_apps = RelApps}) -> Panel = wxPanel:new(Book, []), Sizer = wxBoxSizer:new(?wxHORIZONTAL), - RelBox = wxRadioBox:new(Panel, - ?wxID_ANY, - "Applications included in the release " ++ RelName, - ?wxDefaultPosition, - ?wxDefaultSize, - [atom_to_list(RA#rel_app.name) || RA <- RelApps], - []), - %% wxRadioBox:setSelection(RelBox, 2), % mandatory - wxEvtHandler:connect(RelBox, command_radiobox_selected, + AppNames = [kernel, stdlib | + [RA#rel_app.name || RA <- RelApps] -- [kernel, stdlib]], + RelBox = wxListBox:new( + Panel,?wxID_ANY, + [{pos,?wxDefaultPosition}, + {size,?wxDefaultSize}, + {choices,[[atom_to_list(AppName)] || AppName <- AppNames]}, + {style,?wxLB_EXTENDED}]), + wxEvtHandler:connect(RelBox, command_listbox_selected, [{userData, {config_rel_cond, RelName}}]), RelToolTip = "Choose which applications that shall " "be included in the release resource file.", @@ -1092,17 +1126,23 @@ move_app(S, {_ItemNo, AppBase}, Action) -> OldApp#app{incl_cond = AppCond}. do_set_app(#state{server_pid = ServerPid, app_wins = AppWins} = S, NewApp) -> - {ok, AnalysedApp, Warnings} = reltool_server:set_app(ServerPid, NewApp), + Result = reltool_server:set_app(ServerPid, NewApp), [ok = reltool_app_win:refresh(AW#app_win.pid) || AW <- AppWins], S2 = redraw_apps(S), - case Warnings of - [] -> - ignore; - _ -> - Msg = lists:flatten([[W, $\n] || W <- Warnings]), - display_message(Msg, ?wxICON_WARNING) - end, - {ok, AnalysedApp, S2}. + ReturnApp = + case Result of + {ok, AnalysedApp, []} -> + AnalysedApp; + {ok, AnalysedApp, Warnings} -> + Msg = lists:flatten([[W, $\n] || W <- Warnings]), + display_message(Msg, ?wxICON_WARNING), + AnalysedApp; + {error, Reason} -> + display_message(Reason, ?wxICON_ERROR), + {ok,OldApp} = reltool_server:get_app(ServerPid, NewApp#app.name), + OldApp + end, + {ok, ReturnApp, S2}. redraw_apps(#state{server_pid = ServerPid, source = SourceCtrl, @@ -1357,7 +1397,8 @@ refresh(S) -> [ok = reltool_app_win:refresh(AW#app_win.pid) || AW <- S#state.app_wins], S2 = S#state{sys = Sys}, S3 = redraw_libs(S2), - redraw_apps(S3). + S4 = redraw_apps(S3), + redraw_config_page(S4). question_dialog(Question, Details) -> %% Parent = S#state.frame, @@ -1414,6 +1455,44 @@ display_message(Message, Icon) -> wxMessageDialog:showModal(Dialog), wxMessageDialog:destroy(Dialog). +%% Strings = [{Color,String}] +question_dialog_2(DialogLabel, Strings) -> + %% Parent = S#state.frame, + Parent = wx:typeCast(wx:null(), wxWindow), + %% [{style, ?wxYES_NO bor ?wxICON_ERROR bor ?wx}]), + DialogStyle = ?wxRESIZE_BORDER bor ?wxCAPTION bor ?wxSYSTEM_MENU bor + ?wxMINIMIZE_BOX bor ?wxMAXIMIZE_BOX bor ?wxCLOSE_BOX, + Dialog = wxDialog:new(Parent, ?wxID_ANY, DialogLabel, + [{style, DialogStyle}]), + Color = wxWindow:getBackgroundColour(Dialog), + TextStyle = ?wxTE_READONLY bor ?wxTE_MULTILINE bor ?wxHSCROLL, + Text = wxTextCtrl:new(Dialog, ?wxID_ANY, + [{size, {600, 400}}, {style, TextStyle}]), + wxWindow:setBackgroundColour(Text, Color), + TextAttr = wxTextAttr:new(), + add_text(Text,TextAttr,Strings), + Sizer = wxBoxSizer:new(?wxVERTICAL), + wxSizer:add(Sizer, Text, [{border, 2}, {flag, ?wxEXPAND}, {proportion, 1}]), + ButtSizer = wxDialog:createStdDialogButtonSizer(Dialog, ?wxOK bor ?wxCANCEL), + wxSizer:add(Sizer, ButtSizer, [{border, 2}, {flag, ?wxEXPAND}]), + wxPanel:setSizer(Dialog, Sizer), + wxSizer:fit(Sizer, Dialog), + wxSizer:setSizeHints(Sizer, Dialog), + Answer = wxDialog:showModal(Dialog), + wxDialog:destroy(Dialog), + Answer. + +add_text(Text,Attr,[{Color,String}|Strings]) -> + wxTextAttr:setTextColour(Attr, Color), + wxTextCtrl:setDefaultStyle(Text, Attr), + wxTextCtrl:appendText(Text, String), + add_text(Text,Attr,Strings); +add_text(_,_,[]) -> + ok. + + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% sys callbacks |