svn commit: r385668 - in head/lang: erlang erlang-java erlang-runtime17 erlang-runtime17/files erlang-wx erlang/files
Jimmy Olgeni
olgeni at FreeBSD.org
Thu May 7 20:34:31 UTC 2015
Author: olgeni
Date: Thu May 7 20:34:30 2015
New Revision: 385668
URL: https://svnweb.freebsd.org/changeset/ports/385668
Log:
Upgrade all Erlang 17 ports to 17.5.3.
Added:
head/lang/erlang-runtime17/files/patch-otp-17.5.3 (contents, props changed)
head/lang/erlang/files/patch-otp-17.5.3 (contents, props changed)
Modified:
head/lang/erlang-java/Makefile
head/lang/erlang-runtime17/Makefile
head/lang/erlang-wx/Makefile
head/lang/erlang/Makefile
Modified: head/lang/erlang-java/Makefile
==============================================================================
--- head/lang/erlang-java/Makefile Thu May 7 20:31:03 2015 (r385667)
+++ head/lang/erlang-java/Makefile Thu May 7 20:34:30 2015 (r385668)
@@ -1,7 +1,7 @@
# $FreeBSD$
PORTNAME= erlang
-PORTVERSION= 17.5.2
+PORTVERSION= 17.5.3
CATEGORIES= lang parallel java
MASTER_SITES= http://www.erlang.org/download/:erlangorg \
http://erlang.stacken.kth.se/download/:erlangorg \
@@ -25,8 +25,7 @@ OPTIONS_DEFINE= DOCS
ERL_RELEASE= 17.5
-USES= gmake
-USE_AUTOTOOLS= autoconf:env
+USES= autoreconf gmake
GNU_CONFIGURE= yes
LDFLAGS+= -L${LOCALBASE}/lib
Modified: head/lang/erlang-runtime17/Makefile
==============================================================================
--- head/lang/erlang-runtime17/Makefile Thu May 7 20:31:03 2015 (r385667)
+++ head/lang/erlang-runtime17/Makefile Thu May 7 20:34:30 2015 (r385668)
@@ -2,8 +2,7 @@
# $FreeBSD$
PORTNAME= erlang
-PORTVERSION= 17.5.2
-PORTREVISION= 2
+PORTVERSION= 17.5.3
CATEGORIES= lang parallel java
MASTER_SITES= http://www.erlang.org/download/:erlangorg \
http://erlang.stacken.kth.se/download/:erlangorg \
@@ -186,6 +185,10 @@ post-install:
${TAR} --unlink -xzpf ${DISTDIR}/${DIST_SUBDIR}/${ERLANG_DOCS} \
-C ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}
+ ${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/erts-6.4/* \
+ ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/erts-6.4.1
+ ${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/erts-6.4
+
${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/inets-5.10.6/* \
${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/inets-5.10.7
${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/inets-5.10.6
@@ -194,6 +197,22 @@ post-install:
${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/ssh-3.2.2
${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/ssh-3.2
+ ${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/common_test-1.10/* \
+ ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/common_test-1.10.1
+ ${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/common_test-1.10
+
+ ${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/diameter-1.9/* \
+ ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/diameter-1.9.1
+ ${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/diameter-1.9
+
+ ${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/snmp-5.1.1/* \
+ ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/snmp-5.1.2
+ ${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/snmp-5.1.1
+
+ ${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/test_server-3.8/* \
+ ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/test_server-3.8.1
+ ${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/test_server-3.8
+
${INSTALL_DATA} ${WRKSRC}/lib/dialyzer/doc/*.txt \
${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/dialyzer-*/doc/
.endif
Added: head/lang/erlang-runtime17/files/patch-otp-17.5.3
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/lang/erlang-runtime17/files/patch-otp-17.5.3 Thu May 7 20:34:30 2015 (r385668)
@@ -0,0 +1,3738 @@
+diff --git OTP_VERSION OTP_VERSION
+index 808ab16..f32d20d 100644
+--- OTP_VERSION
++++ OTP_VERSION
+@@ -1 +1 @@
+-17.5.2
++17.5.3
+diff --git erts/doc/src/notes.xml erts/doc/src/notes.xml
+index a2b4ae4..35e6e55 100644
+--- erts/doc/src/notes.xml
++++ erts/doc/src/notes.xml
+@@ -30,6 +30,22 @@
+ </header>
+ <p>This document describes the changes made to the ERTS application.</p>
+
++<section><title>Erts 6.4.1</title>
++
++ <section><title>Fixed Bugs and Malfunctions</title>
++ <list>
++ <item>
++ <p>
++ The VTS mode in Common Test has been modified to use a
++ private version of the Webtool application (ct_webtool).</p>
++ <p>
++ Own Id: OTP-12704 Aux Id: OTP-10922 </p>
++ </item>
++ </list>
++ </section>
++
++</section>
++
+ <section><title>Erts 6.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+diff --git erts/etc/common/ct_run.c erts/etc/common/ct_run.c
+index bb59b93..9e67b94 100644
+--- erts/etc/common/ct_run.c
++++ erts/etc/common/ct_run.c
+@@ -239,7 +239,7 @@ int main(int argc, char** argv)
+ */
+
+ if (ct_mode == VTS_MODE) {
+- PUSH4("-s", "webtool", "script_start", "vts");
++ PUSH4("-s", "ct_webtool", "script_start", "vts");
+ if (browser[0] != '\0') PUSH(browser);
+ PUSH3("-s", "ct_run", "script_start");
+ }
+diff --git erts/vsn.mk erts/vsn.mk
+index abc9c0b..9e5aa99 100644
+--- erts/vsn.mk
++++ erts/vsn.mk
+@@ -17,7 +17,7 @@
+ # %CopyrightEnd%
+ #
+
+-VSN = 6.4
++VSN = 6.4.1
+
+ # Port number 4365 in 4.2
+ # Port number 4366 in 4.3
+diff --git lib/common_test/doc/src/notes.xml lib/common_test/doc/src/notes.xml
+index 822ebf1..472e3b7 100644
+--- lib/common_test/doc/src/notes.xml
++++ lib/common_test/doc/src/notes.xml
+@@ -32,6 +32,66 @@
+ <file>notes.xml</file>
+ </header>
+
++<section><title>Common_Test 1.10.1</title>
++
++ <section><title>Fixed Bugs and Malfunctions</title>
++ <list>
++ <item>
++ <p>
++ A fault in the Common Test logger process, that caused
++ the application to crash when running on a long name
++ node, has been corrected.</p>
++ <p>
++ Own Id: OTP-12643</p>
++ </item>
++ <item>
++ <p>
++ A 'wait_for_prompt' option in ct_telnet:expect/3 has been
++ introduced which forces the function to not return until
++ a prompt string has been received, even if other expect
++ patterns have already been found.</p>
++ <p>
++ Own Id: OTP-12688 Aux Id: seq12818 </p>
++ </item>
++ <item>
++ <p>
++ If the last expression in a test case causes a timetrap
++ timeout, the stack trace is ignored and not printed to
++ the test case log file. This happens because the
++ {Suite,TestCase,Line} info is not available in the stack
++ trace in this scenario, due to tail call elimination.
++ Common Test has been modified to handle this situation by
++ inserting a {Suite,TestCase,last_expr} tuple in the
++ correct place and printing the stack trace as expected.</p>
++ <p>
++ Own Id: OTP-12697 Aux Id: seq12848 </p>
++ </item>
++ <item>
++ <p>
++ Fixed a buffer problem in ct_netconfc which could cause
++ that some messages where buffered forever.</p>
++ <p>
++ Own Id: OTP-12698 Aux Id: seq12844 </p>
++ </item>
++ <item>
++ <p>
++ The VTS mode in Common Test has been modified to use a
++ private version of the Webtool application (ct_webtool).</p>
++ <p>
++ Own Id: OTP-12704 Aux Id: OTP-10922 </p>
++ </item>
++ <item>
++ <p>
++ Add possibility to add user capabilities in
++ <c>ct_netconfc:hello/3</c>.</p>
++ <p>
++ Own Id: OTP-12707 Aux Id: seq12846 </p>
++ </item>
++ </list>
++ </section>
++
++</section>
++
+ <section><title>Common_Test 1.10</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+diff --git lib/common_test/src/Makefile lib/common_test/src/Makefile
+index 8d74546..449cba6 100644
+--- lib/common_test/src/Makefile
++++ lib/common_test/src/Makefile
+@@ -62,6 +62,8 @@ MODULES= \
+ ct_telnet_client \
+ ct_make \
+ vts \
++ ct_webtool \
++ ct_webtool_sup \
+ unix_telnet \
+ ct_config \
+ ct_config_plain \
+diff --git lib/common_test/src/ct_logs.erl lib/common_test/src/ct_logs.erl
+index dc118ed..fa55a97 100644
+--- lib/common_test/src/ct_logs.erl
++++ lib/common_test/src/ct_logs.erl
+@@ -1908,13 +1908,14 @@ sort_all_runs(Dirs) ->
+ sort_ct_runs(Dirs) ->
+ %% Directory naming: <Prefix>.NodeName.Date_Time[/...]
+ %% Sort on Date_Time string: "YYYY-MM-DD_HH.MM.SS"
+- lists:sort(fun(Dir1,Dir2) ->
+- [_Prefix,_Node1,DateHH1,MM1,SS1] =
+- string:tokens(filename:dirname(Dir1),[$.]),
+- [_Prefix,_Node2,DateHH2,MM2,SS2] =
+- string:tokens(filename:dirname(Dir2),[$.]),
+- {DateHH1,MM1,SS1} =< {DateHH2,MM2,SS2}
+- end, Dirs).
++ lists:sort(
++ fun(Dir1,Dir2) ->
++ [SS1,MM1,DateHH1 | _] =
++ lists:reverse(string:tokens(filename:dirname(Dir1),[$.])),
++ [SS2,MM2,DateHH2 | _] =
++ lists:reverse(string:tokens(filename:dirname(Dir2),[$.])),
++ {DateHH1,MM1,SS1} =< {DateHH2,MM2,SS2}
++ end, Dirs).
+
+ dir_diff_all_runs(Dirs, LogCache) ->
+ case LogCache#log_cache.all_runs of
+diff --git lib/common_test/src/ct_netconfc.erl lib/common_test/src/ct_netconfc.erl
+index 85fb1ea..80ffb51 100644
+--- lib/common_test/src/ct_netconfc.erl
++++ lib/common_test/src/ct_netconfc.erl
+@@ -172,6 +172,7 @@
+ only_open/2,
+ hello/1,
+ hello/2,
++ hello/3,
+ close_session/1,
+ close_session/2,
+ kill_session/2,
+@@ -456,23 +457,35 @@ only_open(KeyOrName, ExtraOpts) ->
+
+ %%----------------------------------------------------------------------
+ %% @spec hello(Client) -> Result
+-%% @equiv hello(Client, infinity)
++%% @equiv hello(Client, [], infinity)
+ hello(Client) ->
+- hello(Client,?DEFAULT_TIMEOUT).
++ hello(Client,[],?DEFAULT_TIMEOUT).
+
+ %%----------------------------------------------------------------------
+ -spec hello(Client,Timeout) -> Result when
+ Client :: handle(),
+ Timeout :: timeout(),
+ Result :: ok | {error,error_reason()}.
+-%% @doc Exchange `hello' messages with the server.
+-%%
+-%% Sends a `hello' message to the server and waits for the return.
+-%%
+-%% @end
+-%%----------------------------------------------------------------------
++%% @spec hello(Client, Timeout) -> Result
++%% @equiv hello(Client, [], Timeout)
+ hello(Client,Timeout) ->
+- call(Client, {hello, Timeout}).
++ hello(Client,[],Timeout).
++
++%%----------------------------------------------------------------------
++-spec hello(Client,Options,Timeout) -> Result when
++ Client :: handle(),
++ Options :: [{capability, [string()]}],
++ Timeout :: timeout(),
++ Result :: ok | {error,error_reason()}.
++%% @doc Exchange `hello' messages with the server.
++%%
++%% Adds optional capabilities and sends a `hello' message to the
++%% server and waits for the return.
++%% @end
++%%----------------------------------------------------------------------
++hello(Client,Options,Timeout) ->
++ call(Client, {hello, Options, Timeout}).
++
+
+ %%----------------------------------------------------------------------
+ %% @spec get_session_id(Client) -> Result
+@@ -1040,9 +1053,9 @@ terminate(_, #state{connection=Connection}) ->
+ ok.
+
+ %% @private
+-handle_msg({hello,Timeout}, From,
++handle_msg({hello, Options, Timeout}, From,
+ #state{connection=Connection,hello_status=HelloStatus} = State) ->
+- case do_send(Connection, client_hello()) of
++ case do_send(Connection, client_hello(Options)) of
+ ok ->
+ case HelloStatus of
+ undefined ->
+@@ -1118,7 +1131,9 @@ handle_msg({Ref,timeout},#state{pending=Pending} = State) ->
+ close_session -> stop;
+ _ -> noreply
+ end,
+- {R,State#state{pending=Pending1}}.
++ %% Halfhearted try to get in correct state, this matches
++ %% the implementation before this patch
++ {R,State#state{pending=Pending1, buff= <<>>}}.
+
+ %% @private
+ %% Called by ct_util_server to close registered connections before terminate.
+@@ -1222,10 +1237,14 @@ set_request_timer(T) ->
+
+
+ %%%-----------------------------------------------------------------
+-client_hello() ->
++client_hello(Options) when is_list(Options) ->
++ UserCaps = [{capability, UserCap} ||
++ {capability, UserCap} <- Options,
++ is_list(hd(UserCap))],
+ {hello, ?NETCONF_NAMESPACE_ATTR,
+ [{capabilities,
+- [{capability,[?NETCONF_BASE_CAP++?NETCONF_BASE_CAP_VSN]}]}]}.
++ [{capability,[?NETCONF_BASE_CAP++?NETCONF_BASE_CAP_VSN]}|
++ UserCaps]}]}.
+
+ %%%-----------------------------------------------------------------
+
+@@ -1308,72 +1327,54 @@ to_xml_doc(Simple) ->
+
+ %%%-----------------------------------------------------------------
+ %%% Parse and handle received XML data
+-handle_data(NewData,#state{connection=Connection,buff=Buff} = State) ->
++handle_data(NewData,#state{connection=Connection,buff=Buff0} = State0) ->
+ log(Connection,recv,NewData),
+- Data = <<Buff/binary,NewData/binary>>,
+- case xmerl_sax_parser:stream(<<>>,
+- [{continuation_fun,fun sax_cont/1},
+- {continuation_state,{Data,Connection,false}},
+- {event_fun,fun sax_event/3},
+- {event_state,[]}]) of
+- {ok, Simple, Rest} ->
+- decode(Simple,State#state{buff=Rest});
+- {fatal_error,_Loc,Reason,_EndTags,_EventState} ->
+- ?error(Connection#connection.name,[{parse_error,Reason},
+- {buffer,Buff},
+- {new_data,NewData}]),
+- case Reason of
+- {could_not_fetch_data,Msg} ->
+- handle_msg(Msg,State#state{buff = <<>>});
+- _Other ->
+- Pending1 =
+- case State#state.pending of
+- [] ->
+- [];
+- Pending ->
+- %% Assuming the first request gets the
+- %% first answer
+- P=#pending{tref=TRef,caller=Caller} =
+- lists:last(Pending),
+- _ = timer:cancel(TRef),
+- Reason1 = {failed_to_parse_received_data,Reason},
+- ct_gen_conn:return(Caller,{error,Reason1}),
+- lists:delete(P,Pending)
+- end,
+- {noreply,State#state{pending=Pending1,buff = <<>>}}
+- end
+- end.
+-
+-%%%-----------------------------------------------------------------
+-%%% Parsing of XML data
+-%% Contiuation function for the sax parser
+-sax_cont(done) ->
+- {<<>>,done};
+-sax_cont({Data,Connection,false}) ->
++ Data = append_wo_initial_nl(Buff0,NewData),
+ case binary:split(Data,[?END_TAG],[]) of
+- [All] ->
+- %% No end tag found. Remove what could be a part
+- %% of an end tag from the data and save for next
+- %% iteration
+- SafeSize = size(All)-5,
+- <<New:SafeSize/binary,Save:5/binary>> = All,
+- {New,{Save,Connection,true}};
+- [_Msg,_Rest]=Msgs ->
+- %% We have at least one full message. Any excess data will
+- %% be returned from xmerl_sax_parser:stream/2 in the Rest
+- %% parameter.
+- {list_to_binary(Msgs),done}
+- end;
+-sax_cont({Data,Connection,true}) ->
+- case ssh_receive_data() of
+- {ok,Bin} ->
+- log(Connection,recv,Bin),
+- sax_cont({<<Data/binary,Bin/binary>>,Connection,false});
+- {error,Reason} ->
+- throw({could_not_fetch_data,Reason})
++ [_NoEndTagFound] ->
++ {noreply, State0#state{buff=Data}};
++ [FirstMsg,Buff1] ->
++ SaxArgs = [{event_fun,fun sax_event/3}, {event_state,[]}],
++ case xmerl_sax_parser:stream(FirstMsg, SaxArgs) of
++ {ok, Simple, _Thrash} ->
++ case decode(Simple, State0#state{buff=Buff1}) of
++ {noreply, #state{buff=Buff} = State} when Buff =/= <<>> ->
++ %% Recurse if we have more data in buffer
++ handle_data(<<>>, State);
++ Other ->
++ Other
++ end;
++ {fatal_error,_Loc,Reason,_EndTags,_EventState} ->
++ ?error(Connection#connection.name,
++ [{parse_error,Reason},
++ {buffer, Buff0},
++ {new_data,NewData}]),
++ handle_error(Reason, State0#state{buff= <<>>})
++ end
+ end.
+
++%% xml does not accept a leading nl and some netconf server add a nl after
++%% each ?END_TAG, ignore them
++append_wo_initial_nl(<<>>,NewData) -> NewData;
++append_wo_initial_nl(<<"\n", Data/binary>>, NewData) ->
++ append_wo_initial_nl(Data, NewData);
++append_wo_initial_nl(Data, NewData) ->
++ <<Data/binary, NewData/binary>>.
+
++handle_error(Reason, State) ->
++ Pending1 = case State#state.pending of
++ [] -> [];
++ Pending ->
++ %% Assuming the first request gets the
++ %% first answer
++ P=#pending{tref=TRef,caller=Caller} =
++ lists:last(Pending),
++ _ = timer:cancel(TRef),
++ Reason1 = {failed_to_parse_received_data,Reason},
++ ct_gen_conn:return(Caller,{error,Reason1}),
++ lists:delete(P,Pending)
++ end,
++ {noreply, State#state{pending=Pending1}}.
+
+ %% Event function for the sax parser. It builds a simple XML structure.
+ %% Care is taken to keep namespace attributes and prefixes as in the original XML.
+@@ -1836,16 +1837,6 @@ get_tag([]) ->
+
+ %%%-----------------------------------------------------------------
+ %%% SSH stuff
+-ssh_receive_data() ->
+- receive
+- {ssh_cm, CM, {data, Ch, _Type, Data}} ->
+- ssh_connection:adjust_window(CM,Ch,size(Data)),
+- {ok, Data};
+- {ssh_cm, _CM, {Closed, _Ch}} = X when Closed == closed; Closed == eof ->
+- {error,X};
+- {_Ref,timeout} = X ->
+- {error,X}
+- end.
+
+ ssh_open(#options{host=Host,timeout=Timeout,port=Port,ssh=SshOpts,name=Name}) ->
+ case ssh:connect(Host, Port,
+diff --git lib/common_test/src/ct_run.erl lib/common_test/src/ct_run.erl
+index 4a12481..be547b4 100644
+--- lib/common_test/src/ct_run.erl
++++ lib/common_test/src/ct_run.erl
+@@ -225,18 +225,24 @@ finish(Tracing, ExitStatus, Args) ->
+ if ExitStatus == interactive_mode ->
+ interactive_mode;
+ true ->
+- %% it's possible to tell CT to finish execution with a call
+- %% to a different function than the normal halt/1 BIF
+- %% (meant to be used mainly for reading the CT exit status)
+- case get_start_opt(halt_with,
+- fun([HaltMod,HaltFunc]) ->
+- {list_to_atom(HaltMod),
+- list_to_atom(HaltFunc)} end,
+- Args) of
+- undefined ->
+- halt(ExitStatus);
+- {M,F} ->
+- apply(M, F, [ExitStatus])
++ case get_start_opt(vts, true, Args) of
++ true ->
++ %% VTS mode, don't halt the node
++ ok;
++ _ ->
++ %% it's possible to tell CT to finish execution with a call
++ %% to a different function than the normal halt/1 BIF
++ %% (meant to be used mainly for reading the CT exit status)
++ case get_start_opt(halt_with,
++ fun([HaltMod,HaltFunc]) ->
++ {list_to_atom(HaltMod),
++ list_to_atom(HaltFunc)} end,
++ Args) of
++ undefined ->
++ halt(ExitStatus);
++ {M,F} ->
++ apply(M, F, [ExitStatus])
++ end
+ end
+ end.
+
+@@ -244,7 +250,7 @@ script_start1(Parent, Args) ->
+ %% read general start flags
+ Label = get_start_opt(label, fun([Lbl]) -> Lbl end, Args),
+ Profile = get_start_opt(profile, fun([Prof]) -> Prof end, Args),
+- Vts = get_start_opt(vts, true, Args),
++ Vts = get_start_opt(vts, true, undefined, Args),
+ Shell = get_start_opt(shell, true, Args),
+ Cover = get_start_opt(cover, fun([CoverFile]) -> ?abs(CoverFile) end, Args),
+ CoverStop = get_start_opt(cover_stop,
+@@ -330,8 +336,8 @@ script_start1(Parent, Args) ->
+ Stylesheet = get_start_opt(stylesheet,
+ fun([SS]) -> ?abs(SS) end, Args),
+ %% basic_html - used by ct_logs
+- BasicHtml = case proplists:get_value(basic_html, Args) of
+- undefined ->
++ BasicHtml = case {Vts,proplists:get_value(basic_html, Args)} of
++ {undefined,undefined} ->
+ application:set_env(common_test, basic_html, false),
+ undefined;
+ _ ->
+@@ -364,9 +370,10 @@ script_start1(Parent, Args) ->
+ scale_timetraps = ScaleTT,
+ create_priv_dir = CreatePrivDir,
+ starter = script},
+-
++
+ %% check if log files should be refreshed or go on to run tests...
+ Result = run_or_refresh(Opts, Args),
++
+ %% send final results to starting process waiting in script_start/0
+ Parent ! {self(), Result}.
+
+@@ -757,21 +764,6 @@ script_start4(Opts = #opts{tests = Tests}, Args) ->
+ %%% @doc Print usage information for <code>ct_run</code>.
+ script_usage() ->
+ io:format("\n\nUsage:\n\n"),
+- io:format("Run tests in web based GUI:\n\n"
+- "\tct_run -vts [-browser Browser]"
+- "\n\t[-config ConfigFile1 ConfigFile2 .. ConfigFileN]"
+- "\n\t[-decrypt_key Key] | [-decrypt_file KeyFile]"
+- "\n\t[-dir TestDir1 TestDir2 .. TestDirN] |"
+- "\n\t[-suite Suite [-case Case]]"
+- "\n\t[-logopts LogOpt1 LogOpt2 .. LogOptN]"
+- "\n\t[-verbosity GenVLvl | [CategoryVLvl1 .. CategoryVLvlN]]"
+- "\n\t[-include InclDir1 InclDir2 .. InclDirN]"
+- "\n\t[-no_auto_compile]"
+- "\n\t[-abort_if_missing_suites]"
+- "\n\t[-multiply_timetraps N]"
+- "\n\t[-scale_timetraps]"
+- "\n\t[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]"
+- "\n\t[-basic_html]\n\n"),
+ io:format("Run tests from command line:\n\n"
+ "\tct_run [-dir TestDir1 TestDir2 .. TestDirN] |"
+ "\n\t[[-dir TestDir] -suite Suite1 Suite2 .. SuiteN"
+@@ -831,7 +823,22 @@ script_usage() ->
+ io:format("Run CT in interactive mode:\n\n"
+ "\tct_run -shell"
+ "\n\t[-config ConfigFile1 ConfigFile2 .. ConfigFileN]"
+- "\n\t[-decrypt_key Key] | [-decrypt_file KeyFile]\n\n").
++ "\n\t[-decrypt_key Key] | [-decrypt_file KeyFile]\n\n"),
++ io:format("Run tests in web based GUI:\n\n"
++ "\tct_run -vts [-browser Browser]"
++ "\n\t[-config ConfigFile1 ConfigFile2 .. ConfigFileN]"
++ "\n\t[-decrypt_key Key] | [-decrypt_file KeyFile]"
++ "\n\t[-dir TestDir1 TestDir2 .. TestDirN] |"
++ "\n\t[-suite Suite [-case Case]]"
++ "\n\t[-logopts LogOpt1 LogOpt2 .. LogOptN]"
++ "\n\t[-verbosity GenVLvl | [CategoryVLvl1 .. CategoryVLvlN]]"
++ "\n\t[-include InclDir1 InclDir2 .. InclDirN]"
++ "\n\t[-no_auto_compile]"
++ "\n\t[-abort_if_missing_suites]"
++ "\n\t[-multiply_timetraps N]"
++ "\n\t[-scale_timetraps]"
++ "\n\t[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]"
++ "\n\t[-basic_html]\n\n").
+
+ %%%-----------------------------------------------------------------
+ %%% @hidden
+diff --git lib/common_test/src/ct_telnet.erl lib/common_test/src/ct_telnet.erl
+index d906a26..844f537 100644
+--- lib/common_test/src/ct_telnet.erl
++++ lib/common_test/src/ct_telnet.erl
+@@ -486,7 +486,8 @@ expect(Connection,Patterns) ->
+ %%% Opts = [Opt]
+ %%% Opt = {idle_timeout,IdleTimeout} | {total_timeout,TotalTimeout} |
+ %%% repeat | {repeat,N} | sequence | {halt,HaltPatterns} |
+-%%% ignore_prompt | no_prompt_check
++%%% ignore_prompt | no_prompt_check | wait_for_prompt |
++%%% {wait_for_prompt,Prompt}
+ %%% IdleTimeout = infinity | integer()
+ %%% TotalTimeout = infinity | integer()
+ %%% N = integer()
+@@ -499,9 +500,9 @@ expect(Connection,Patterns) ->
+ %%%
+ %%% @doc Get data from telnet and wait for the expected pattern.
+ %%%
+-%%% <p><code>Pattern</code> can be a POSIX regular expression. If more
+-%%% than one pattern is given, the function returns when the first
+-%%% match is found.</p>
++%%% <p><code>Pattern</code> can be a POSIX regular expression. The function
++%%% returns as soon as a pattern has been successfully matched (at least one,
++%%% in the case of multiple patterns).</p>
+ %%%
+ %%% <p><code>RxMatch</code> is a list of matched strings. It looks
+ %%% like this: <code>[FullMatch, SubMatch1, SubMatch2, ...]</code>
+@@ -524,10 +525,13 @@ expect(Connection,Patterns) ->
+ %%% milliseconds, <code>{error,timeout}</code> is returned. The default
+ %%% value is <code>infinity</code> (i.e. no time limit).</p>
+ %%%
+-%%% <p>The function will always return when a prompt is found, unless
+-%%% any of the <code>ignore_prompt</code> or
+-%%% <code>no_prompt_check</code> options are used, in which case it
+-%%% will return when a match is found or after a timeout.</p>
++%%% <p>The function will return when a prompt is received, even if no
++%%% pattern has yet been matched. In this event,
++%%% <code>{error,{prompt,Prompt}}</code> is returned.
++%%% However, this behaviour may be modified with the
++%%% <code>ignore_prompt</code> or <code>no_prompt_check</code> option, which
++%%% tells <code>expect</code> to return only when a match is found or after a
++%%% timeout.</p>
+ %%%
+ %%% <p>If the <code>ignore_prompt</code> option is used,
+ %%% <code>ct_telnet</code> will ignore any prompt found. This option
+@@ -541,6 +545,13 @@ expect(Connection,Patterns) ->
+ %%% is useful if, for instance, the <code>Pattern</code> itself
+ %%% matches the prompt.</p>
+ %%%
++%%% <p>The <code>wait_for_prompt</code> option forces <code>ct_telnet</code>
++%%% to wait until the prompt string has been received before returning
++%%% (even if a pattern has already been matched). This is equal to calling:
++%%% <code>expect(Conn, Patterns++[{prompt,Prompt}], [sequence|Opts])</code>.
++%%% Note that <code>idle_timeout</code> and <code>total_timeout</code>
++%%% may abort the operation of waiting for prompt.</p>
++%%%
+ %%% <p>The <code>repeat</code> option indicates that the pattern(s)
+ %%% shall be matched multiple times. If <code>N</code> is given, the
+ %%% pattern(s) will be matched <code>N</code> times, and the function
+@@ -653,18 +664,21 @@ handle_msg({cmd,Cmd,Opts},State) ->
+ start_gen_log(heading(cmd,State#state.name)),
+ log(State,cmd,"Cmd: ~p",[Cmd]),
+
++ %% whatever is in the buffer from previous operations
++ %% will be ignored as we go ahead with this telnet cmd
++
+ debug_cont_gen_log("Throwing Buffer:",[]),
+ debug_log_lines(State#state.buffer),
+
+ case {State#state.type,State#state.prompt} of
+- {ts,_} ->
++ {ts,_} ->
+ silent_teln_expect(State#state.name,
+ State#state.teln_pid,
+ State#state.buffer,
+ prompt,
+ State#state.prx,
+ [{idle_timeout,2000}]);
+- {ip,false} ->
++ {ip,false} ->
+ silent_teln_expect(State#state.name,
+ State#state.teln_pid,
+ State#state.buffer,
+@@ -1029,10 +1043,12 @@ teln_expect(Name,Pid,Data,Pattern0,Prx,Opts) ->
+ end,
+
+ PromptCheck = get_prompt_check(Opts),
+- Seq = get_seq(Opts),
+- Pattern = convert_pattern(Pattern0,Seq),
+
+- {IdleTimeout,TotalTimeout} = get_timeouts(Opts),
++ {WaitForPrompt,Pattern1,Opts1} = wait_for_prompt(Pattern0,Opts),
++
++ Seq = get_seq(Opts1),
++ Pattern2 = convert_pattern(Pattern1,Seq),
++ {IdleTimeout,TotalTimeout} = get_timeouts(Opts1),
+
+ EO = #eo{teln_pid=Pid,
+ prx=Prx,
+@@ -1042,9 +1058,16 @@ teln_expect(Name,Pid,Data,Pattern0,Prx,Opts) ->
+ haltpatterns=HaltPatterns,
+ prompt_check=PromptCheck},
+
+- case get_repeat(Opts) of
++ case get_repeat(Opts1) of
+ false ->
+- case teln_expect1(Name,Pid,Data,Pattern,[],EO) of
++ case teln_expect1(Name,Pid,Data,Pattern2,[],EO) of
++ {ok,Matched,Rest} when WaitForPrompt ->
++ case lists:reverse(Matched) of
++ [{prompt,_},Matched1] ->
++ {ok,Matched1,Rest};
++ [{prompt,_}|Matched1] ->
++ {ok,lists:reverse(Matched1),Rest}
++ end;
+ {ok,Matched,Rest} ->
+ {ok,Matched,Rest};
+ {halt,Why,Rest} ->
+@@ -1054,7 +1077,7 @@ teln_expect(Name,Pid,Data,Pattern0,Prx,Opts) ->
+ end;
+ N ->
+ EO1 = EO#eo{repeat=N},
+- repeat_expect(Name,Pid,Data,Pattern,[],EO1)
++ repeat_expect(Name,Pid,Data,Pattern2,[],EO1)
+ end.
+
+ convert_pattern(Pattern,Seq)
+@@ -1118,6 +1141,40 @@ get_ignore_prompt(Opts) ->
+ get_prompt_check(Opts) ->
+ not lists:member(no_prompt_check,Opts).
+
++wait_for_prompt(Pattern, Opts) ->
++ case lists:member(wait_for_prompt, Opts) of
++ true ->
++ wait_for_prompt1(prompt, Pattern,
++ lists:delete(wait_for_prompt,Opts));
++ false ->
++ case proplists:get_value(wait_for_prompt, Opts) of
++ undefined ->
++ {false,Pattern,Opts};
++ PromptStr ->
++ wait_for_prompt1({prompt,PromptStr}, Pattern,
++ proplists:delete(wait_for_prompt,Opts))
++ end
++ end.
++
++wait_for_prompt1(Prompt, [Ch|_] = Pattern, Opts) when is_integer(Ch) ->
++ wait_for_prompt2(Prompt, [Pattern], Opts);
++wait_for_prompt1(Prompt, Pattern, Opts) when is_list(Pattern) ->
++ wait_for_prompt2(Prompt, Pattern, Opts);
++wait_for_prompt1(Prompt, Pattern, Opts) ->
++ wait_for_prompt2(Prompt, [Pattern], Opts).
++
++wait_for_prompt2(Prompt, Pattern, Opts) ->
++ Pattern1 = case lists:reverse(Pattern) of
++ [prompt|_] -> Pattern;
++ [{prompt,_}|_] -> Pattern;
++ _ -> Pattern ++ [Prompt]
++ end,
++ Opts1 = case lists:member(sequence, Opts) of
++ true -> Opts;
++ false -> [sequence|Opts]
++ end,
++ {true,Pattern1,Opts1}.
++
+ %% Repeat either single or sequence. All match results are accumulated
+ %% and returned when a halt condition is fulllfilled.
+ repeat_expect(_Name,_Pid,Rest,_Pattern,Acc,#eo{repeat=0}) ->
+@@ -1210,7 +1267,7 @@ get_data1(Pid) ->
+ %% 1) Single expect.
+ %% First the whole data chunk is searched for a prompt (to avoid doing
+ %% a regexp match for the prompt at each line).
+-%% If we are searching for anyting else, the datachunk is split into
++%% If we are searching for anything else, the datachunk is split into
+ %% lines and each line is matched against each pattern.
+
+ %% one_expect: split data chunk at prompts
+@@ -1227,7 +1284,7 @@ one_expect(Name,Pid,Data,Pattern,EO) ->
+ log(name_or_pid(Name,Pid),"PROMPT: ~ts",[PromptType]),
+ {match,{prompt,PromptType},Rest};
+ [{prompt,_OtherPromptType}] ->
+- %% Only searching for one specific prompt, not thisone
++ %% Only searching for one specific prompt, not this one
+ log_lines(Name,Pid,UptoPrompt),
+ {nomatch,Rest};
+ _ ->
+diff --git lib/common_test/src/ct_webtool.erl lib/common_test/src/ct_webtool.erl
+new file mode 100644
+index 0000000..b67a7c2
+--- /dev/null
++++ lib/common_test/src/ct_webtool.erl
+@@ -0,0 +1,1207 @@
++%%
++%% %CopyrightBegin%
++%%
++%% Copyright Ericsson AB 2001-2010. All Rights Reserved.
++%%
++%% 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 online 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.
++%%
++%% %CopyrightEnd%
++%%
++-module(ct_webtool).
++-behaviour(gen_server).
++
++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
++%% %%
++%% The general idea is: %%
++%% %%
++%% %%
++%% 1. Scan through the path for *.tool files and find all the web %%
++%% based tools. Query each tool for configuration data. %%
++%% 2. Add Alias for Erlscript and html for each tool to %%
++%% the webserver configuration data. %%
++%% 3. Start the webserver. %%
++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
++
++%% API functions
++-export([start/0, start/2, stop/0]).
++
++%% Starting Webtool from a shell script
++-export([script_start/0, script_start/1]).
++
++%% Web api
++-export([started_tools/2, toolbar/2, start_tools/2, stop_tools/2]).
++
++%% API against other tools
++-export([is_localhost/0]).
++
++%% Debug export s
++-export([get_tools1/1]).
++-export([debug/1, stop_debug/0, debug_app/1]).
++
++%% gen_server callbacks
++-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
++ terminate/2, code_change/3]).
++
++-include_lib("kernel/include/file.hrl").
++-include_lib("stdlib/include/ms_transform.hrl").
++
++-record(state,{priv_dir,app_data,supvis,web_data,started=[]}).
++
++-define(MAX_NUMBER_OF_WEBTOOLS,256).
++-define(DEFAULT_PORT,8888).% must be >1024 or the user must be root on unix
++-define(DEFAULT_ADDR,{127,0,0,1}).
++
++-define(WEBTOOL_ALIAS,{ct_webtool,[{alias,{erl_alias,"/ct_webtool",[ct_webtool]}}]}).
++-define(HEADER,"Pragma:no-cache\r\n Content-type: text/html\r\n\r\n").
++-define(HTML_HEADER,"<HTML>\r\n<HEAD>\r\n<TITLE>WebTool</TITLE>\r\n</HEAD>\r\n<BODY BGCOLOR=\"#FFFFFF\">\r\n").
++-define(HTML_HEADER_RELOAD,"<HTML>\r\n<HEAD>\r\n<TITLE>WebTool
++ </TITLE>\r\n</HEAD>\r\n
++ <BODY BGCOLOR=\"#FFFFFF\" onLoad=reloadCompiledList()>\r\n").
++
++-define(HTML_END,"</BODY></HTML>").
++
++-define(SEND_URL_TIMEOUT,5000).
++
++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
++%% %%
++%% For debugging only. %%
++%% %%
++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
++%% Start tracing with
++%% debug(Functions).
++%% Functions = local | global | FunctionList
++%% FunctionList = [Function]
++%% Function = {FunctionName,Arity} | FunctionName |
++%% {Module, FunctionName, Arity} | {Module,FunctionName}
++debug(F) ->
++ ttb:tracer(all,[{file,"webtool.trc"}]), % tracing all nodes
++ ttb:p(all,[call,timestamp]),
++ MS = [{'_',[],[{return_trace},{message,{caller}}]}],
++ tp(F,MS),
++ ttb:ctp(?MODULE,stop_debug), % don't want tracing of the stop_debug func
++ ok.
++tp(local,MS) -> % all functions
++ ttb:tpl(?MODULE,MS);
++tp(global,MS) -> % all exported functions
++ ttb:tp(?MODULE,MS);
++tp([{M,F,A}|T],MS) -> % Other module
++ ttb:tpl(M,F,A,MS),
++ tp(T,MS);
++tp([{M,F}|T],MS) when is_atom(F) -> % Other module
++ ttb:tpl(M,F,MS),
++ tp(T,MS);
++tp([{F,A}|T],MS) -> % function/arity
++ ttb:tpl(?MODULE,F,A,MS),
++ tp(T,MS);
++tp([F|T],MS) -> % function
++ ttb:tpl(?MODULE,F,MS),
++ tp(T,MS);
++tp([],_MS) ->
++ ok.
++stop_debug() ->
++ ttb:stop([format]).
++
++debug_app(Mod) ->
++ ttb:tracer(all,[{file,"webtool_app.trc"},{handler,{fun out/4,true}}]),
++ ttb:p(all,[call,timestamp]),
++ MS = [{'_',[],[{return_trace},{message,{caller}}]}],
++ ttb:tp(Mod,MS),
++ ok.
++
++out(_,{trace_ts,Pid,call,MFA={M,F,A},{W,_,_},TS},_,S)
++ when W==webtool;W==mod_esi->
++ io:format("~w: (~p)~ncall ~s~n", [TS,Pid,ffunc(MFA)]),
++ [{M,F,length(A)}|S];
++out(_,{trace_ts,Pid,return_from,MFA,R,TS},_,[MFA|S]) ->
++ io:format("~w: (~p)~nreturned from ~s -> ~p~n", [TS,Pid,ffunc(MFA),R]),
++ S;
++out(_,_,_,_) ->
++ ok.
++
++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
++%% %%
++%% Functions called via script. %%
++%% %%
++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
++script_start() ->
++ usage(),
++ halt().
++script_start([App]) ->
++ DefaultBrowser =
++ case os:type() of
++ {win32,_} -> iexplore;
++ _ -> firefox
++ end,
++ script_start([App,DefaultBrowser]);
++script_start([App,Browser]) ->
++ io:format("Starting webtool...\n"),
++ start(),
++ AvailableApps = get_applications(),
++ {OSType,_} = os:type(),
++ case lists:keysearch(App,1,AvailableApps) of
++ {value,{App,StartPage}} ->
++ io:format("Starting ~w...\n",[App]),
++ start_tools([],"app=" ++ atom_to_list(App)),
++ PortStr = integer_to_list(get_port()),
++ Url = case StartPage of
++ "/" ++ Page ->
++ "http://localhost:" ++ PortStr ++ "/" ++ Page;
++ _ ->
++ "http://localhost:" ++ PortStr ++ "/" ++ StartPage
++ end,
++ case Browser of
++ none ->
++ ok;
++ iexplore when OSType == win32->
++ io:format("Starting internet explorer...\n"),
++ {ok,R} = win32reg:open(""),
++ Key="\\local_machine\\SOFTWARE\\Microsoft\\IE Setup\\Setup",
++ win32reg:change_key(R,Key),
++ {ok,Val} = win32reg:value(R,"Path"),
++ IExplore=filename:join(win32reg:expand(Val),"iexplore.exe"),
++ os:cmd("\"" ++ IExplore ++ "\" " ++ Url);
++ _ when OSType == win32 ->
++ io:format("Starting ~w...\n",[Browser]),
++ os:cmd("\"" ++ atom_to_list(Browser) ++ "\" " ++ Url);
++ B when B==firefox; B==mozilla ->
++ io:format("Sending URL to ~w...",[Browser]),
++ BStr = atom_to_list(Browser),
++ SendCmd = BStr ++ " -raise -remote \'openUrl(" ++
++ Url ++ ")\'",
++ Port = open_port({spawn,SendCmd},[exit_status]),
++ receive
++ {Port,{exit_status,0}} ->
++ io:format("done\n"),
++ ok;
++ {Port,{exit_status,_Error}} ->
++ io:format(" not running, starting ~w...\n",
++ [Browser]),
++ os:cmd(BStr ++ " " ++ Url),
++ ok
++ after ?SEND_URL_TIMEOUT ->
++ io:format(" failed, starting ~w...\n",[Browser]),
++ erlang:port_close(Port),
++ os:cmd(BStr ++ " " ++ Url)
++ end;
++ _ ->
++ io:format("Starting ~w...\n",[Browser]),
++ os:cmd(atom_to_list(Browser) ++ " " ++ Url)
++ end,
++ ok;
++ false ->
++ stop(),
++ io:format("\n{error,{unknown_app,~p}}\n",[App]),
++ halt()
++ end.
++
++usage() ->
++ io:format("Starting webtool...\n"),
++ start(),
++ Apps = lists:map(fun({A,_}) -> A end,get_applications()),
++ io:format(
++ "\nUsage: start_webtool application [ browser ]\n"
++ "\nAvailable applications are: ~p\n"
++ "Default browser is \'iexplore\' (Internet Explorer) on Windows "
++ "or else \'firefox\'\n",
++ [Apps]),
++ stop().
++
++
++get_applications() ->
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-ports-all
mailing list