26
1
mirror of https://github.com/processone/ejabberd.git synced 2024-12-28 17:38:54 +01:00

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

SVN Revision: 2109
This commit is contained in:
Badlop 2009-05-27 17:29:43 +00:00
parent dc613df3b1
commit a1fe76fb5b
2 changed files with 145 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 ++
[?XMLATTR('type', Type),
?XMLATTR('name', Name),
?XMLATTR('value', Value)])).
process(["doc", LocalFile], _Request) ->
DocPath = case os:getenv("EJABBERD_DOC_PATH") of
@ -149,6 +155,12 @@ make_xhtml(Els, Host, Node, Lang) ->
#xmlel{ns = ?NS_XHTML, name = 'meta', attrs = [
?XMLATTR('http-equiv', <<"Content-Type">>),
?XMLATTR('content', <<"text/html; charset=utf-8">>)]},
#xmlel{ns = ?NS_XHTML, name = 'script',
%% This children is to ensure exmpp puts: <script ...></script>
children = [?C(".")],
attrs = [
?XMLATTR('src', Base ++ "additions.js"),
?XMLATTR('type', <<"text/javascript">>)]},
#xmlel{ns = ?NS_XHTML, name = 'link', attrs = [
?XMLATTR('href', Base ++ "favicon.ico"),
?XMLATTR('type', <<"image/x-icon">>),
@ -190,6 +202,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),
"
@ -525,6 +555,10 @@ h3 {
padding-left: 10px;
}
#content ul.noliststyle > li {
list-style-type: none;
}
#content li.big {
font-size: 10pt;
}
@ -646,6 +680,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,
@ -1953,9 +1990,32 @@ 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),
%% If we want checkboxes selected by default:
%%?XA("input", [{"checked", ""},
%% {"type", "checkbox"},
%% {"name", "selected"},
%% {"value", BeamString}]),
?C(BeamString)])
end,
UpdatedBeams),
SelectButtons =
[?BR,
?INPUTATTRS(<<"button">>, <<"selectall">>,
<<"Select All">>,
[?XMLATTR('onClick', <<"selectAll()">>)]),
?C(" "),
?INPUTATTRS(<<"button">>, <<"unselectall">>,
<<"Unselect All">>,
[?XMLATTR('onClick', <<"unSelectAll()">>)])],
%%?XE("ul", BeamsLis)
?XAE('ul', [?XMLATTR('class', <<"noliststyle">>)],
BeamsLis ++ SelectButtons)
end,
FmtScript = ?XC('pre', io_lib:format("~p", [Script])),
FmtLowLevelScript = ?XC('pre', io_lib:format("~p", [LowLevelScript])),
@ -1972,6 +2032,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")
])
];
@ -2294,7 +2355,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} ->