📄 cover_web.erl
字号:
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id$%% -module(cover_web).-author('marting@erix.ericsson.se').-behaviour(gen_server).%%Export of configuration function-export([configData/0]).%% External exports-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).-export([start_link/0,start/0,stop/0]).-export([menu_frame/2,nodes_frame/2,import_frame/2, compile_frame/2,result_frame/2]).-export([list_dir/2,compile/2,add_node/2,remove_node/2,result/2, calls/2,coverage/2,import/2]).-record(state,{dir}).-include_lib("kernel/include/file.hrl").%% Timeouts-define(DEFAULT_TIME,10000).-define(MAX_COMPILE_TIME,60000).-define(MAX_ANALYSE_TIME,30000).%% Colors-define(INFO_BG_COLOR,"#C0C0EA").%%%----------------------------------------------------------------------%%% API - called from erlang shell%%%----------------------------------------------------------------------%% Start webtool and webcover from erlang shellstart() -> webtool:start(), webtool:start_tools([],"app=webcover"), ok.%% Stop webtool and webcover from erlang shellstop() -> webtool:stop_tools([],"app=webcover"), webtool:stop().%%%----------------------------------------------------------------------%%% API - called from webtool%%%----------------------------------------------------------------------start_link() -> gen_server:start_link({local, webcover_server},cover_web, [], []).nodes_frame(Env,Input)-> call({nodes_frame,Env,Input}).add_node(Env,Input)-> call({add_node,Env,Input}).remove_node(Env,Input)-> call({remove_node,Env,Input}).compile_frame(Env,Input)-> call({compile_frame,Env,Input}).list_dir(Env,Input) -> call({list_dir,Env,Input}).compile(Env,Input)-> call({compile,Env,Input},?MAX_COMPILE_TIME).result_frame(Env,Input)-> call({result_frame,Env,Input}).result(Env,Input) -> call({result,Env,Input},?MAX_ANALYSE_TIME).calls(Env,Input) -> call({calls,Env,Input}).coverage(Env,Input) -> call({coverage,Env,Input}).import_frame(Env,Input)-> call({import_frame,Env,Input}).import(Env,Input)-> call({import,Env,Input}).menu_frame(Env,Input)-> call({menu_frame,Env,Input}).call(Msg) -> call(Msg,?DEFAULT_TIME).call(Msg,Time) -> gen_server:call(webcover_server,Msg,Time). configData()-> {webcover,[{web_data,{"WebCover","/webcover"}}, {alias,{"/webcover",code:priv_dir(tools)}}, {alias,{erl_alias,"/webcover/erl",[cover_web]}}, {start,{child,{{local,webcover_server}, {cover_web,start_link,[]}, permanent,100,worker,[cover_web]}}} ]}.%%%----------------------------------------------------------------------%%% Callback functions from gen_server%%%----------------------------------------------------------------------%%----------------------------------------------------------------------%% Func: init/1%% Returns: {ok, State} |%% {ok, State, Timeout} |%% ignore |%% {stop, Reason}%%----------------------------------------------------------------------init([]) -> cover:start(), CS = whereis(cover_server), link(CS), GL = spawn_link(fun group_leader_proc/0), group_leader(GL,CS), %% Must trap exists in order to have terminate/2 executed when %% crashing because of a linked process crash. process_flag(trap_exit,true), {ok,Cwd} = file:get_cwd(), {ok, #state{dir=Cwd}}.group_leader_proc() -> register(cover_group_leader_proc,self()), group_leader_loop([]).group_leader_loop(Warnings) -> receive {io_request,From,ReplyAs,{put_chars,io_lib,Func,[Format,Args]}} -> Msg = (catch io_lib:Func(Format,Args)), From ! {io_reply,ReplyAs,ok}, case lists:member(Msg,Warnings) of true -> group_leader_loop(Warnings); false -> group_leader_loop([Msg|Warnings]) end; IoReq when element(1,IoReq)=:= io_request -> group_leader() ! IoReq, group_leader_loop(Warnings); {From,get_warnings} -> Warnings1 = receive {io_request,From,ReplyAs, {put_chars,io_lib,Func,[Format,Args]}} -> Msg = (catch io_lib:Func(Format,Args)), From ! {io_reply,ReplyAs,ok}, case lists:member(Msg,Warnings) of true -> Warnings; false -> [Msg|Warnings] end after 0 -> Warnings end, From ! {warnings,Warnings1}, group_leader_loop([]) end.%%----------------------------------------------------------------------%% Func: handle_call/3%% Returns: {reply, Reply, State} |%% {reply, Reply, State, Timeout} |%% {noreply, State} |%% {noreply, State, Timeout} |%% {stop, Reason, Reply, State} | (terminate/2 is called)%% {stop, Reason, State} (terminate/2 is called)%%----------------------------------------------------------------------handle_call({nodes_frame,_Env,_Input},_From,State)-> {reply,nodes_frame1(),State};handle_call({add_node,_Env,Input},_From,State)-> {reply,do_add_node(Input),State};handle_call({remove_node,_Env,Input},_From,State)-> {reply,do_remove_node(Input),State};handle_call({compile_frame,_Env,_Input},_From,State)-> {reply,compile_frame1(State#state.dir),State};handle_call({list_dir,_Env,Input},_From,State)-> Dir = get_input_data(Input,"path"), case filelib:is_dir(Dir) of true -> {reply,compile_frame1(Dir),State#state{dir=Dir}}; false -> Err = Dir ++ " is not a directory", {reply,compile_frame1(State#state.dir,Err),State} end;handle_call({compile,_Env,Input},_From,State)-> {reply,do_compile(Input,State#state.dir),State};handle_call({result_frame,_Env,_Input},_From,State)-> {reply,result_frame1(),State};handle_call({result,_Env,Input},_From,State)-> {reply,handle_result(Input),State};handle_call({calls,_Env,Input},_From,State)-> {reply,call_page(Input),State};handle_call({coverage,_Env,Input},_From,State)-> {reply,coverage_page(Input),State};handle_call({import_frame,_Env,_Input},_From,State)-> {ok,Cwd} = file:get_cwd(), {reply,import_frame1(Cwd),State};handle_call({import,_Env,Input},_From,State)-> {reply,do_import(Input),State};handle_call({menu_frame,_Env,_Input},_From,State)-> {reply,menu_frame1(),State};handle_call(_Request, _From, State) -> Reply = bad_request, {reply, Reply, State}.%%----------------------------------------------------------------------%% Func: handle_cast/2%% Returns: {noreply, State} |%% {noreply, State, Timeout} |%% {stop, Reason, State} (terminate/2 is called)%%----------------------------------------------------------------------handle_cast(_Msg, State) -> {noreply, State}.%%----------------------------------------------------------------------%% Func: handle_info/2%% Returns: {noreply, State} |%% {noreply, State, Timeout} |%% {stop, Reason, State} (terminate/2 is called)%%----------------------------------------------------------------------handle_info({'EXIT',_Pid,Reason}, State) -> {stop, Reason, State}.%%----------------------------------------------------------------------%% Func: terminate/2%% Purpose: Shutdown the server%% Returns: any (ignored by gen_server)%%----------------------------------------------------------------------terminate(_Reason, _State) -> cover:stop(), ok.%%--------------------------------------------------------------------%% Func: code_change/3%% Purpose: Convert process state when code is changed%% Returns: {ok, NewState}%%--------------------------------------------------------------------code_change(_OldVsn, State, _Extra) -> {ok, State}.%%%----------------------------------------------------------------------%%% Internal functions%%%----------------------------------------------------------------------%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% The functions that creates the whole pages by collecting all the %%%% neccessary data for each page. These functions are the public %%%% interface. %%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%----------------------------------------------------------------------%% Returns the page to the left frame%%----------------------------------------------------------------------menu_frame1()-> [header(),html_header(""),menu_body(),html_end()].%%----------------------------------------------------------------------%% Creates the page where the user can add and remove nodes%%----------------------------------------------------------------------nodes_frame1()-> nodes_frame1([]).nodes_frame1(Err)-> [header(),html_header("Add/remove nodes"),nodes_body(Err),html_end()].%%----------------------------------------------------------------------%% Creates the page where the user can cover compile modules%%----------------------------------------------------------------------compile_frame1(Dir)-> compile_frame1(Dir,[]).compile_frame1(Dir,Err) -> [header(),html_header("Cover compile"),compile_body(Dir,Err),html_end()].%%----------------------------------------------------------------------%% Creates the page where the user can handle results%%----------------------------------------------------------------------result_frame1()-> result_frame1([]).result_frame1(Err) -> [header(),html_header("Show cover results"),result_body(Err),html_end()].%%----------------------------------------------------------------------%%The beginning of the page that clear the cover information on a cover%%compiled module%%----------------------------------------------------------------------call_page(Input)-> [header(),html_header("Code coverage"),call_result(Input),html_end()].coverage_page(Input)-> [header(),html_header("Code coverage"),coverage_result(Input),html_end()].%%----------------------------------------------------------------------%% Creates the page where the user an import files%%----------------------------------------------------------------------import_frame1(Dir) -> import_frame1(Dir,"").import_frame1(Dir,Err) -> [header(),html_header("Import coverdata"),import_body(Dir,Err),html_end()]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% The functions that build the body of the menu frame %%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%menu_body() -> Nodes = cover:which_nodes(), Modules = cover:modules(), Imported = cover:imported(), ["<A HREF=\"./nodes_frame\" TARGET=\"main\">Nodes</A><BR>\n", "<A HREF=\"./compile_frame\" TARGET=\"main\">Compile</A><BR>\n", "<A HREF=\"./import_frame\" TARGET=\"main\">Import</A><BR>\n", "<A HREF=\"./result_frame\" TARGET=\"main\">Result</A>\n", "<P><B>Nodes:</B>\n", "<UL>\n", lists:map(fun(N) -> "<LI>"++atom_to_list(N)++"</LI>\n" end,[node()|Nodes]), "</UL>\n", "<P><B>Compiled modules:</B>\n", "<UL>\n", lists:map(fun(M) -> "<LI>"++atom_to_list(M)++"</LI>\n" end,Modules), "</UL>\n", "<P><B>Imported files:</B>\n", "<UL>\n", "<FONT SIZE=-1>\n", lists:map(fun(F) -> Short = filename:basename(F), "<LI TITLE=\""++F++"\">"++Short++"</LI>\n" end,Imported), "</FONT>\n", "</UL>\n"].%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% The functions that build the body of the nodes frame %%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%nodes_body(Err) -> CN = cover:which_nodes(), Fun = fun(N) -> NStr = atom_to_list(N), ["<OPTION VALUE=",NStr, " onClick=\"node.value=selected_node.value\">",NStr, "</OPTION>\n"] end, AllNodes = lists:append(lists:map(Fun,nodes()--CN)), CoverNodes = lists:append(lists:map(Fun,CN)), [reload_menu_script(Err), "<H1 ALIGN=center>Nodes</H1>\n", "<TABLE BORDER=0 WIDTH=600 ALIGN=center>\n", "<TR><TD BGCOLOR=",?INFO_BG_COLOR," COLSPAN=2>\n", "<P>You can run cover over several nodes simultaneously. Coverage data\n", "from all involved nodes will be merged during analysis.\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -