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').
%% API
-export([update/0, update_info/0]).
-export([update/0, update/1, update_info/0]).
-include("ejabberd.hrl").
%%====================================================================
%% API
%%====================================================================
%% Update all the modified modules
update() ->
case update_info() of
{ok, Dir, _UpdatedBeams, _Script, LowLevelScript, _Check} ->
@ -48,48 +50,91 @@ update() ->
{error, Reason}
end.
update_info() ->
Dir = filename:dirname(code:which(ejabberd)),
case file:list_dir(Dir) of
{ok, Files} ->
Beams = [list_to_atom(filename:rootname(FN)) ||
FN <- Files, lists:suffix(".beam", FN)],
UpdatedBeams =
lists:filter(
fun(Module) ->
{ok, {Module, NewVsn}} =
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,
%% Update only the specified modules
update(ModulesToUpdate) ->
case update_info() of
{ok, Dir, UpdatedBeamsAll, _Script, _LowLevelScript, _Check} ->
UpdatedBeamsNow =
[A || A <- UpdatedBeamsAll, B <- ModulesToUpdate, A == B],
{_, LowLevelScript, _} = build_script(Dir, UpdatedBeamsNow),
Eval =
release_handler_1:eval_script(
LowLevelScript, [],
[{ejabberd, "", filename:join(Dir, "..")}]),
?INFO_MSG("check: ~p~n", [Check]),
{ok, Dir, UpdatedBeams, Script, LowLevelScript, Check};
?INFO_MSG("eval: ~p~n", [Eval]),
Eval;
{error, Reason} ->
{error, Reason}
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
%%--------------------------------------------------------------------
%% 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,
{name, %% Name of the application, atom().
type = permanent, %% Application start type, atom().

View File

@ -39,6 +39,12 @@
-include("ejabberd_http.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) ->
DocPath = case os:getenv("EJABBERD_DOC_PATH") of
@ -145,6 +151,8 @@ make_xhtml(Els, Host, Node, Lang) ->
[?XCT("title", "ejabberd Web Admin"),
{xmlelement, "meta", [{"http-equiv", "Content-Type"},
{"content", "text/html; charset=utf-8"}], []},
{xmlelement, "script", [{"src", Base ++ "/additions.js"},
{"type", "text/javascript"}], [?C(" ")]},
{xmlelement, "link", [{"href", Base ++ "favicon.ico"},
{"type", "image/x-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(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) ->
Base = get_base_path(Host, cluster),
"
@ -519,6 +545,10 @@ h3 {
padding-left: 10px;
}
#content ul.nolistyle>li {
list-style-type: none;
}
#content li.big {
font-size: 10pt;
}
@ -640,6 +670,9 @@ process_admin(_Host, #request{path = ["logo.png"]}) ->
process_admin(_Host, #request{path = ["logo-fill.png"]}) ->
{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,
#request{path = ["acls-raw"],
q = Query,
@ -1927,9 +1960,28 @@ get_node(global, Node, ["update"], Query, Lang) ->
[] ->
?CT("None");
_ ->
?XE("ul",
[?LI([?C(atom_to_list(Beam))]) ||
Beam <- UpdatedBeams])
BeamsLis =
lists:map(
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,
FmtScript = ?XC("pre", io_lib:format("~p", [Script])),
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", "Low level update script"), FmtLowLevelScript,
?XCT("h3", "Script check"), ?XC("pre", atom_to_list(Check)),
?BR,
?INPUTT("submit", "update", "Update")
])
];
@ -2268,7 +2321,9 @@ node_modules_parse_query(Host, Node, Modules, Query) ->
node_update_parse_query(Node, Query) ->
case lists:keysearch("update", 1, Query) of
{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;
{error, Error} ->