Support to select what modules to update. Split large function in smaller ones.

SVN Revision: 2107
This commit is contained in:
Badlop 2009-05-27 17:28:55 +00:00
parent 7f5cce8196
commit 4094482a9f
2 changed files with 137 additions and 37 deletions

View File

@ -28,13 +28,15 @@
-author('alexey@process-one.net'). -author('alexey@process-one.net').
%% API %% API
-export([update/0, update_info/0]). -export([update/0, update/1, update_info/0]).
-include("ejabberd.hrl"). -include("ejabberd.hrl").
%%==================================================================== %%====================================================================
%% API %% API
%%==================================================================== %%====================================================================
%% Update all the modified modules
update() -> update() ->
case update_info() of case update_info() of
{ok, Dir, _UpdatedBeams, _Script, LowLevelScript, _Check} -> {ok, Dir, _UpdatedBeams, _Script, LowLevelScript, _Check} ->
@ -48,48 +50,91 @@ update() ->
{error, Reason} {error, Reason}
end. end.
update_info() -> %% Update only the specified modules
Dir = filename:dirname(code:which(ejabberd)), update(ModulesToUpdate) ->
case file:list_dir(Dir) of case update_info() of
{ok, Files} -> {ok, Dir, UpdatedBeamsAll, _Script, _LowLevelScript, _Check} ->
Beams = [list_to_atom(filename:rootname(FN)) || UpdatedBeamsNow =
FN <- Files, lists:suffix(".beam", FN)], [A || A <- UpdatedBeamsAll, B <- ModulesToUpdate, A == B],
UpdatedBeams = {_, LowLevelScript, _} = build_script(Dir, UpdatedBeamsNow),
lists:filter( Eval =
fun(Module) -> release_handler_1:eval_script(
{ok, {Module, NewVsn}} = LowLevelScript, [],
beam_lib:version(code:which(Module)),
case code:is_loaded(Module) of
{file, _} ->
Attrs = Module:module_info(attributes),
{value, {vsn, CurVsn}} =
lists:keysearch(vsn, 1, Attrs),
NewVsn /= CurVsn;
false ->
false
end
end, Beams),
?INFO_MSG("beam files: ~p~n", [UpdatedBeams]),
Script = make_script(UpdatedBeams),
?INFO_MSG("script: ~p~n", [Script]),
LowLevelScript = make_low_level_script(UpdatedBeams, Script),
?INFO_MSG("low level script: ~p~n", [LowLevelScript]),
Check =
release_handler_1:check_script(
LowLevelScript,
[{ejabberd, "", filename:join(Dir, "..")}]), [{ejabberd, "", filename:join(Dir, "..")}]),
?INFO_MSG("check: ~p~n", [Check]), ?INFO_MSG("eval: ~p~n", [Eval]),
{ok, Dir, UpdatedBeams, Script, LowLevelScript, Check}; Eval;
{error, Reason} -> {error, Reason} ->
{error, Reason} {error, Reason}
end. end.
%% Get information about the modified modules
update_info() ->
Dir = filename:dirname(code:which(ejabberd)),
case file:list_dir(Dir) of
{ok, Files} ->
update_info(Dir, Files);
{error, Reason} ->
{error, Reason}
end.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%%% Internal functions %%% Internal functions
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% From systools.hrl update_info(Dir, Files) ->
Beams = lists:sort(get_beams(Files)),
UpdatedBeams = get_updated_beams(Beams),
?INFO_MSG("beam files: ~p~n", [UpdatedBeams]),
{Script, LowLevelScript, Check} = build_script(Dir, UpdatedBeams),
{ok, Dir, UpdatedBeams, Script, LowLevelScript, Check}.
get_beams(Files) ->
[list_to_atom(filename:rootname(FN))
|| FN <- Files, lists:suffix(".beam", FN)].
%% Return only the beams that have different version
get_updated_beams(Beams) ->
lists:filter(
fun(Module) ->
NewVsn = get_new_version(Module),
case code:is_loaded(Module) of
{file, _} ->
CurVsn = get_current_version(Module),
(NewVsn /= CurVsn
andalso NewVsn /= unknown_version);
false ->
false
end
end, Beams).
get_new_version(Module) ->
Path = code:which(Module),
VersionRes = beam_lib:version(Path),
case VersionRes of
{ok, {Module, NewVsn}} -> NewVsn;
%% If a m1.erl has -module("m2"):
_ -> unknown_version
end.
get_current_version(Module) ->
Attrs = Module:module_info(attributes),
{value, {vsn, CurVsn}} = lists:keysearch(vsn, 1, Attrs),
CurVsn.
%% @spec(Dir::string(), UpdatedBeams::[atom()]) -> {Script,LowLevelScript,Check}
build_script(Dir, UpdatedBeams) ->
Script = make_script(UpdatedBeams),
?INFO_MSG("script: ~p~n", [Script]),
LowLevelScript = make_low_level_script(UpdatedBeams, Script),
?INFO_MSG("low level script: ~p~n", [LowLevelScript]),
Check =
release_handler_1:check_script(
LowLevelScript,
[{ejabberd, "", filename:join(Dir, "..")}]),
?INFO_MSG("check: ~p~n", [Check]),
{Script, LowLevelScript, Check}.
%% Copied from Erlang/OTP file: lib/sasl/src/systools.hrl
-record(application, -record(application,
{name, %% Name of the application, atom(). {name, %% Name of the application, atom().
type = permanent, %% Application start type, atom(). type = permanent, %% Application start type, atom().

View File

@ -39,6 +39,12 @@
-include("ejabberd_http.hrl"). -include("ejabberd_http.hrl").
-include("ejabberd_web_admin.hrl"). -include("ejabberd_web_admin.hrl").
-define(INPUTATTRS(Type, Name, Value, Attrs),
?XA("input", Attrs ++
[{"type", Type},
{"name", Name},
{"value", Value}])).
process(["doc", LocalFile], _Request) -> process(["doc", LocalFile], _Request) ->
DocPath = case os:getenv("EJABBERD_DOC_PATH") of DocPath = case os:getenv("EJABBERD_DOC_PATH") of
@ -145,6 +151,8 @@ make_xhtml(Els, Host, Node, Lang) ->
[?XCT("title", "ejabberd Web Admin"), [?XCT("title", "ejabberd Web Admin"),
{xmlelement, "meta", [{"http-equiv", "Content-Type"}, {xmlelement, "meta", [{"http-equiv", "Content-Type"},
{"content", "text/html; charset=utf-8"}], []}, {"content", "text/html; charset=utf-8"}], []},
{xmlelement, "script", [{"src", Base ++ "/additions.js"},
{"type", "text/javascript"}], [?C(" ")]},
{xmlelement, "link", [{"href", Base ++ "favicon.ico"}, {xmlelement, "link", [{"href", Base ++ "favicon.ico"},
{"type", "image/x-icon"}, {"type", "image/x-icon"},
{"rel", "shortcut icon"}], []}, {"rel", "shortcut icon"}], []},
@ -184,6 +192,24 @@ get_base_path(Host, cluster) -> "/admin/server/" ++ Host ++ "/";
get_base_path(global, Node) -> "/admin/node/" ++ atom_to_list(Node) ++ "/"; get_base_path(global, Node) -> "/admin/node/" ++ atom_to_list(Node) ++ "/";
get_base_path(Host, Node) -> "/admin/server/" ++ Host ++ "/node/" ++ atom_to_list(Node) ++ "/". get_base_path(Host, Node) -> "/admin/server/" ++ Host ++ "/node/" ++ atom_to_list(Node) ++ "/".
additions_js() ->
"
function selectAll() {
for(i=0;i<document.forms[0].elements.length;i++)
{ var e = document.forms[0].elements[i];
if(e.type == 'checkbox')
{ e.checked = true; }
}
}
function unSelectAll() {
for(i=0;i<document.forms[0].elements.length;i++)
{ var e = document.forms[0].elements[i];
if(e.type == 'checkbox')
{ e.checked = false; }
}
}
".
css(Host) -> css(Host) ->
Base = get_base_path(Host, cluster), Base = get_base_path(Host, cluster),
" "
@ -519,6 +545,10 @@ h3 {
padding-left: 10px; padding-left: 10px;
} }
#content ul.nolistyle>li {
list-style-type: none;
}
#content li.big { #content li.big {
font-size: 10pt; font-size: 10pt;
} }
@ -640,6 +670,9 @@ process_admin(_Host, #request{path = ["logo.png"]}) ->
process_admin(_Host, #request{path = ["logo-fill.png"]}) -> process_admin(_Host, #request{path = ["logo-fill.png"]}) ->
{200, [{"Content-Type", "image/png"}, last_modified(), cache_control_public()], logo_fill()}; {200, [{"Content-Type", "image/png"}, last_modified(), cache_control_public()], logo_fill()};
process_admin(_Host, #request{path = ["additions.js"]}) ->
{200, [{"Content-Type", "text/javascript"}, last_modified(), cache_control_public()], additions_js()};
process_admin(Host, process_admin(Host,
#request{path = ["acls-raw"], #request{path = ["acls-raw"],
q = Query, q = Query,
@ -1927,9 +1960,28 @@ get_node(global, Node, ["update"], Query, Lang) ->
[] -> [] ->
?CT("None"); ?CT("None");
_ -> _ ->
?XE("ul", BeamsLis =
[?LI([?C(atom_to_list(Beam))]) || lists:map(
Beam <- UpdatedBeams]) fun(Beam) ->
BeamString = atom_to_list(Beam),
?LI([
?INPUT("checkbox", "selected", BeamString),
%%?XA("input", [{"checked", ""}, %% Selected by default
%% {"type", "checkbox"},
%% {"name", "selected"},
%% {"value", BeamString}]),
?C(BeamString)])
end,
UpdatedBeams),
SelectButtons =
[?BR,
?INPUTATTRS("button", "selectall", "Select All",
[{"onClick", "selectAll()"}]),
?C(" "),
?INPUTATTRS("button", "unselectall", "Unselect All",
[{"onClick", "unSelectAll()"}])],
%%?XE("ul", BeamsLis)
?XAE("ul", [{"class", "nolistyle"}], BeamsLis ++ SelectButtons)
end, end,
FmtScript = ?XC("pre", io_lib:format("~p", [Script])), FmtScript = ?XC("pre", io_lib:format("~p", [Script])),
FmtLowLevelScript = ?XC("pre", io_lib:format("~p", [LowLevelScript])), FmtLowLevelScript = ?XC("pre", io_lib:format("~p", [LowLevelScript])),
@ -1946,6 +1998,7 @@ get_node(global, Node, ["update"], Query, Lang) ->
?XCT("h3", "Update script"), FmtScript, ?XCT("h3", "Update script"), FmtScript,
?XCT("h3", "Low level update script"), FmtLowLevelScript, ?XCT("h3", "Low level update script"), FmtLowLevelScript,
?XCT("h3", "Script check"), ?XC("pre", atom_to_list(Check)), ?XCT("h3", "Script check"), ?XC("pre", atom_to_list(Check)),
?BR,
?INPUTT("submit", "update", "Update") ?INPUTT("submit", "update", "Update")
]) ])
]; ];
@ -2268,7 +2321,9 @@ node_modules_parse_query(Host, Node, Modules, Query) ->
node_update_parse_query(Node, Query) -> node_update_parse_query(Node, Query) ->
case lists:keysearch("update", 1, Query) of case lists:keysearch("update", 1, Query) of
{value, _} -> {value, _} ->
case rpc:call(Node, ejabberd_update, update, []) of ModulesToUpdateStrings = proplists:get_all_values("selected",Query),
ModulesToUpdate = [list_to_atom(M) || M <- ModulesToUpdateStrings],
case rpc:call(Node, ejabberd_update, update, [ModulesToUpdate]) of
{ok, _} -> {ok, _} ->
ok; ok;
{error, Error} -> {error, Error} ->