]> granicus.if.org Git - ejabberd/commitdiff
Support to select what modules to update. Split large function in smaller ones.
authorBadlop <badlop@process-one.net>
Wed, 27 May 2009 17:28:55 +0000 (17:28 +0000)
committerBadlop <badlop@process-one.net>
Wed, 27 May 2009 17:28:55 +0000 (17:28 +0000)
SVN Revision: 2107

src/ejabberd_update.erl
src/web/ejabberd_web_admin.erl

index 7d5ae36c95dbd27a79fbfd0084ff4a96b86a58e8..de233355889a6e0d7beb3700bf0d3ea1c9baf010 100644 (file)
 -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 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("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} ->
-           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,
-                 [{ejabberd, "", filename:join(Dir, "..")}]),
-           ?INFO_MSG("check: ~p~n", [Check]),
-           {ok, Dir, UpdatedBeams, Script, LowLevelScript, Check};
+           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().
index 0b74a7ee09bf2bc2d717454c6cb1d8897ce363b9..50f9499e953f1e8460594923f82b9efd4906a3dd 100644 (file)
 -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} ->