mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-30 17:43:57 +01:00
Support to select what modules to update. Split large function in smaller ones.
SVN Revision: 2109
This commit is contained in:
parent
dc613df3b1
commit
a1fe76fb5b
@ -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().
|
||||||
|
@ -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 ++
|
||||||
|
[?XMLATTR('type', Type),
|
||||||
|
?XMLATTR('name', Name),
|
||||||
|
?XMLATTR('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
|
||||||
@ -149,6 +155,12 @@ make_xhtml(Els, Host, Node, Lang) ->
|
|||||||
#xmlel{ns = ?NS_XHTML, name = 'meta', attrs = [
|
#xmlel{ns = ?NS_XHTML, name = 'meta', attrs = [
|
||||||
?XMLATTR('http-equiv', <<"Content-Type">>),
|
?XMLATTR('http-equiv', <<"Content-Type">>),
|
||||||
?XMLATTR('content', <<"text/html; charset=utf-8">>)]},
|
?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 = [
|
#xmlel{ns = ?NS_XHTML, name = 'link', attrs = [
|
||||||
?XMLATTR('href', Base ++ "favicon.ico"),
|
?XMLATTR('href', Base ++ "favicon.ico"),
|
||||||
?XMLATTR('type', <<"image/x-icon">>),
|
?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(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),
|
||||||
"
|
"
|
||||||
@ -525,6 +555,10 @@ h3 {
|
|||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#content ul.noliststyle > li {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
#content li.big {
|
#content li.big {
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
}
|
}
|
||||||
@ -646,6 +680,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,
|
||||||
@ -1953,9 +1990,32 @@ 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),
|
||||||
|
%% 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,
|
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])),
|
||||||
@ -1972,6 +2032,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")
|
||||||
])
|
])
|
||||||
];
|
];
|
||||||
@ -2294,7 +2355,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} ->
|
||||||
|
Loading…
Reference in New Issue
Block a user