diff options
73 files changed, 915 insertions, 1213 deletions
diff --git a/erts/include/internal/ethread.h b/erts/include/internal/ethread.h index 142c26c0ca..e1885c627a 100644 --- a/erts/include/internal/ethread.h +++ b/erts/include/internal/ethread.h @@ -355,10 +355,8 @@ extern ethr_runtime_t ethr_runtime__; # include "sparc64/ethread.h" # endif # endif -#if 0 # include "gcc/ethread.h" # include "libatomic_ops/ethread.h" -#endif # endif # elif defined(ETHR_HAVE_LIBATOMIC_OPS) # include "libatomic_ops/ethread.h" diff --git a/erts/test/otp_SUITE.erl b/erts/test/otp_SUITE.erl index 5f28f22606..b7ceb0a3fd 100644 --- a/erts/test/otp_SUITE.erl +++ b/erts/test/otp_SUITE.erl @@ -84,13 +84,14 @@ undefined_functions(Config) when is_list(Config) -> "ExcludedFrom = ~p:_/_," "Undef - Undef | ExcludedFrom", [UndefS,ExcludeFrom]), - ?line {ok,Undef0} = xref:q(Server, lists:flatten(Q)), - ?line Undef1 = hipe_filter(Undef0), - ?line Undef2 = ssl_crypto_filter(Undef1), - ?line Undef3 = edoc_filter(Undef2), + {ok,Undef0} = xref:q(Server, lists:flatten(Q)), + Undef1 = hipe_filter(Undef0), + Undef2 = ssl_crypto_filter(Undef1), + Undef3 = edoc_filter(Undef2), Undef4 = eunit_filter(Undef3), Undef5 = dialyzer_filter(Undef4), - Undef = wx_filter(Undef5), + Undef6 = wx_filter(Undef5), + Undef = gs_filter(Undef6), case Undef of [] -> ok; @@ -202,6 +203,16 @@ wx_filter(Undef) -> _ -> Undef end. +gs_filter(Undef) -> + case code:lib_dir(gs) of + {error,bad_name} -> + filter(fun({_,{gs,_,_}}) -> false; + ({_,{gse,_,_}}) -> false; + ({_,{tool_utils,_,_}}) -> false; + (_) -> true + end, Undef); + _ -> Undef + end. deprecated_not_in_obsolete(Config) when is_list(Config) -> ?line Server = ?config(xref_server, Config), diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml index 64eeb4af92..abe8cb2041 100644 --- a/lib/common_test/doc/src/notes.xml +++ b/lib/common_test/doc/src/notes.xml @@ -32,6 +32,22 @@ <file>notes.xml</file> </header> +<section><title>Common_Test 1.6.2.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The interactive mode (ct_run -shell) would not start + properly. This error has been fixed.</p> + <p> + Own Id: OTP-10414</p> + </item> + </list> + </section> + +</section> + <section><title>Common_Test 1.6.2</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl index 49b51c9207..5014309c0f 100644 --- a/lib/common_test/src/ct.erl +++ b/lib/common_test/src/ct.erl @@ -274,7 +274,8 @@ step(TestDir,Suite,Case,Opts) -> %%% <c>> ct_telnet:cmd(unix_telnet, "ls .").</c><br/> %%% <c>{ok,["ls","file1 ...",...]}</c></p> start_interactive() -> - ct_util:start(interactive). + ct_util:start(interactive), + ok. %%%----------------------------------------------------------------- %%% @spec stop_interactive() -> ok @@ -282,7 +283,8 @@ start_interactive() -> %%% @doc Exit the interactive mode. %%% @see start_interactive/0 stop_interactive() -> - ct_util:stop(normal). + ct_util:stop(normal), + ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% MISC INTERFACE diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index 4d47731239..bec3368869 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -1529,6 +1529,12 @@ report(What,Data) -> end; tests_done -> ok; + severe_error -> + ct_event:sync_notify(#event{name=What, + node=node(), + data=Data}), + ct_util:set_testdata({What,Data}), + ok; tc_start -> %% Data = {{Suite,Func},LogFileName} ct_event:sync_notify(#event{name=tc_logfile, diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index d80d216f9e..4a6a3cdcac 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -211,6 +211,8 @@ analyze_test_result([Result|Rs], Args) -> end; analyze_test_result([], _) -> ?EXIT_STATUS_TEST_SUCCESSFUL; +analyze_test_result(interactive_mode, _) -> + interactive_mode; analyze_test_result(Unknown, _) -> io:format("\nTest run failed! Reason:\n~p\n\n\n",[Unknown]), ?EXIT_STATUS_TEST_RUN_FAILED. @@ -218,17 +220,22 @@ analyze_test_result(Unknown, _) -> finish(Tracing, ExitStatus, Args) -> stop_trace(Tracing), timer:sleep(1000), - %% 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]) + 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]) + end end. script_start1(Parent, Args) -> @@ -635,6 +642,7 @@ script_start4(#opts{label = Label, profile = Profile, verbosity = Verbosity, enable_builtin_hooks = EnableBuiltinHooks, logdir = LogDir, testspecs = Specs}, _Args) -> + %% label - used by ct_logs application:set_env(common_test, test_label, Label), @@ -655,7 +663,7 @@ script_start4(#opts{label = Label, profile = Profile, ct_util:set_testdata({logopts, LogOpts}), log_ts_names(Specs), io:nl(), - ok; + interactive_mode; Error -> Error end; @@ -2184,6 +2192,15 @@ do_run_test(Tests, Skip, Opts) -> end, CleanUp), [code:del_path(Dir) || Dir <- AddedToPath], + %% If a severe error has occurred in the test_server, + %% we will generate an exception here. + case ct_util:get_testdata(severe_error) of + undefined -> ok; + SevereError -> + ct_logs:log("SEVERE ERROR", "~p\n", [SevereError]), + exit(SevereError) + end, + case ct_util:get_testdata(stats) of Stats = {_Ok,_Failed,{_UserSkipped,_AutoSkipped}} -> Stats; @@ -2776,6 +2793,8 @@ opts2args(EnvStartOpts) -> [{exit_status,[atom_to_list(ExitStatusOpt)]}]; ({halt_with,{HaltM,HaltF}}) -> [{halt_with,[atom_to_list(HaltM),atom_to_list(HaltF)]}]; + ({interactive_mode,true}) -> + [{shell,[]}]; ({config,CfgFiles}) -> [{ct_config,[CfgFiles]}]; ({userconfig,{CBM,CfgStr=[X|_]}}) when is_integer(X) -> diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile index 7628ada61a..3526ef4421 100644 --- a/lib/common_test/test/Makefile +++ b/lib/common_test/test/Makefile @@ -50,7 +50,9 @@ MODULES= \ ct_netconfc_SUITE \ ct_basic_html_SUITE \ ct_auto_compile_SUITE \ - ct_verbosity_SUITE + ct_verbosity_SUITE \ + ct_shell_SUITE \ + ct_system_error_SUITE ERL_FILES= $(MODULES:%=%.erl) diff --git a/lib/common_test/test/ct_shell_SUITE.erl b/lib/common_test/test/ct_shell_SUITE.erl new file mode 100644 index 0000000000..4b8c43d800 --- /dev/null +++ b/lib/common_test/test/ct_shell_SUITE.erl @@ -0,0 +1,133 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2012. 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% +%% + +%%%------------------------------------------------------------------- +%%% File: ct_shell_SUITE +%%% +%%% Description: +%%% Test that the interactive mode starts properly +%%% +%%% The suites used for the test are located in the data directory. +%%%------------------------------------------------------------------- +-module(ct_shell_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + +-define(eh, ct_test_support_eh). + +%%-------------------------------------------------------------------- +%% TEST SERVER CALLBACK FUNCTIONS +%%-------------------------------------------------------------------- + +init_per_suite(Config) -> + Config1 = ct_test_support:init_per_suite(Config), + Config1. + +end_per_suite(Config) -> + ct_test_support:end_per_suite(Config). + +init_per_testcase(TestCase, Config) -> + ct_test_support:init_per_testcase(TestCase, Config). + +end_per_testcase(TestCase, Config) -> + ct_test_support:end_per_testcase(TestCase, Config). + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [start_interactive]. + +%%-------------------------------------------------------------------- +%% TEST CASES +%%-------------------------------------------------------------------- + +%%%----------------------------------------------------------------- +%%% +start_interactive(Config) -> + DataDir = ?config(data_dir, Config), + CfgFile = filename:join(DataDir, "cfgdata"), + + {Opts,ERPid} = setup([{interactive_mode,true},{config,CfgFile}], + Config), + CTNode = proplists:get_value(ct_node, Config), + Level = proplists:get_value(trace_level, Config), + test_server:format(Level, "Saving start opts on ~p: ~p~n", + [CTNode, Opts]), + rpc:call(CTNode, application, set_env, + [common_test, run_test_start_opts, Opts]), + test_server:format(Level, "Calling ct_run:script_start() on ~p~n", + [CTNode]), + + interactive_mode = rpc:call(CTNode, ct_run, script_start, []), + + ok = rpc:call(CTNode, ct, require, [key1]), + value1 = rpc:call(CTNode, ct, get_config, [key1]), + ok = rpc:call(CTNode, ct, require, [x,key2]), + value2 = rpc:call(CTNode, ct, get_config, [x]), + + ok = rpc:call(CTNode, ct, stop_interactive, []), + + case rpc:call(CTNode, erlang, whereis, [ct_util_server]) of + undefined -> + ok; + _ -> + test_server:format(Level, + "ct_util_server not stopped on ~p yet, waiting 5 s...~n", + [CTNode]), + timer:sleep(5000), + undefined = rpc:call(CTNode, erlang, whereis, [ct_util_server]) + end, + Events = ct_test_support:get_events(ERPid, Config), + + ct_test_support:log_events(start_interactive, + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), + TestEvents = test_events(start_interactive), + ok = ct_test_support:verify_events(TestEvents, Events, Config). + +%%%----------------------------------------------------------------- +%%% HELP FUNCTIONS +%%%----------------------------------------------------------------- + +setup(Test, Config) -> + Opts0 = ct_test_support:get_opts(Config), + Level = ?config(trace_level, Config), + EvHArgs = [{cbm,ct_test_support},{trace_level,Level}], + Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}}|Test], + ERPid = ct_test_support:start_event_receiver(Config), + {Opts,ERPid}. + +reformat(Events, EH) -> + ct_test_support:reformat(Events, EH). + +%%%----------------------------------------------------------------- +%%% TEST EVENTS +%%%----------------------------------------------------------------- + +test_events(start_interactive) -> + [ + {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]} + ]. diff --git a/lib/common_test/test/ct_shell_SUITE_data/cfgdata b/lib/common_test/test/ct_shell_SUITE_data/cfgdata new file mode 100644 index 0000000000..23a40ad21a --- /dev/null +++ b/lib/common_test/test/ct_shell_SUITE_data/cfgdata @@ -0,0 +1,2 @@ +{key1,value1}. +{key2,value2}. diff --git a/lib/common_test/test/ct_system_error_SUITE.erl b/lib/common_test/test/ct_system_error_SUITE.erl new file mode 100644 index 0000000000..f00f470c33 --- /dev/null +++ b/lib/common_test/test/ct_system_error_SUITE.erl @@ -0,0 +1,132 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. 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% +%% + +%%%------------------------------------------------------------------- +%%% File: ct_system_error_SUITE +%%% +%%% Description: +%%% +%%% Test that severe system errors (such as failure to write logs) are +%%% noticed and handled. +%%%------------------------------------------------------------------- +-module(ct_system_error_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + +-define(eh, ct_test_support_eh). + +%%-------------------------------------------------------------------- +%% TEST SERVER CALLBACK FUNCTIONS +%%-------------------------------------------------------------------- + +%%-------------------------------------------------------------------- +%% Description: Since Common Test starts another Test Server +%% instance, the tests need to be performed on a separate node (or +%% there will be clashes with logging processes etc). +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + Config1 = ct_test_support:init_per_suite(Config), + Config1. + +end_per_suite(Config) -> + ct_test_support:end_per_suite(Config). + +init_per_testcase(TestCase, Config) -> + ct_test_support:init_per_testcase(TestCase, Config). + +end_per_testcase(TestCase, Config) -> + ct_test_support:end_per_testcase(TestCase, Config). + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [ + test_server_failing_logs + ]. + +%%-------------------------------------------------------------------- +%% TEST CASES +%%-------------------------------------------------------------------- + +%%%----------------------------------------------------------------- +%%% +test_server_failing_logs(Config) -> + TC = test_server_failing_logs, + DataDir = ?config(data_dir, Config), + Suite = filename:join(DataDir, "a_SUITE"), + {Opts,ERPid} = setup([{suite,Suite},{label,TC}], Config), + crash_test_server(Config), + {error,{cannot_create_log_dir,__}} = ct_test_support:run(Opts, Config), + Events = ct_test_support:get_events(ERPid, Config), + ct_test_support:log_events(TC, + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), + + TestEvents = events_to_check(TC), + ok = ct_test_support:verify_events(TestEvents, Events, Config). + +crash_test_server(Config) -> + DataDir = ?config(data_dir, Config), + Root = ?config(priv_dir, Config), + [$@|Host] = lists:dropwhile(fun(C) -> + C =/= $@ + end, atom_to_list(node())), + Format = filename:join(Root, + "ct_run.ct@" ++ Host ++ + ".~4..0w-~2..0w-~2..0w_" + "~2..0w.~2..0w.~2..0w"), + [C2,C1|_] = lists:reverse(filename:split(DataDir)), + LogDir = C1 ++ "." ++ C2 ++ ".a_SUITE.logs", + T = calendar:datetime_to_gregorian_seconds(calendar:local_time()), + [begin + {{Y,Mon,D},{H,Min,S}} = + calendar:gregorian_seconds_to_datetime(T+Offset), + Dir0 = io_lib:format(Format, [Y,Mon,D,H,Min,S]), + Dir = lists:flatten(Dir0), + file:make_dir(Dir), + File = filename:join(Dir, LogDir), + file:write_file(File, "anything goes\n") + end || Offset <- lists:seq(0, 20)], + ok. + +%%%----------------------------------------------------------------- +%%% HELP FUNCTIONS +%%%----------------------------------------------------------------- + +setup(Test, Config) -> + Opts0 = ct_test_support:get_opts(Config), + Level = ?config(trace_level, Config), + EvHArgs = [{cbm,ct_test_support},{trace_level,Level}], + Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}}|Test], + ERPid = ct_test_support:start_event_receiver(Config), + {Opts,ERPid}. + +reformat(Events, EH) -> + ct_test_support:reformat(Events, EH). + +%%%----------------------------------------------------------------- +%%% TEST EVENTS +%%%----------------------------------------------------------------- + +events_to_check(_Test) -> + [{?eh,severe_error,{cannot_create_log_dir,{'_','_'}}}]. diff --git a/lib/common_test/test/ct_system_error_SUITE_data/a_SUITE.erl b/lib/common_test/test/ct_system_error_SUITE_data/a_SUITE.erl new file mode 100644 index 0000000000..c6e3ddfd5d --- /dev/null +++ b/lib/common_test/test/ct_system_error_SUITE_data/a_SUITE.erl @@ -0,0 +1,122 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. 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(a_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). + +%%-------------------------------------------------------------------- +%% @spec suite() -> Info +%% Info = [tuple()] +%% @end +%%-------------------------------------------------------------------- +suite() -> + [{timetrap,{seconds,10}}]. + +%%-------------------------------------------------------------------- +%% @spec init_per_suite(Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% Config0 = Config1 = [tuple()] +%% Reason = term() +%% @end +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + Config. + +%%-------------------------------------------------------------------- +%% @spec end_per_suite(Config0) -> void() | {save_config,Config1} +%% Config0 = Config1 = [tuple()] +%% @end +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + ok. + +%%-------------------------------------------------------------------- +%% @spec init_per_group(GroupName, Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% GroupName = atom() +%% Config0 = Config1 = [tuple()] +%% Reason = term() +%% @end +%%-------------------------------------------------------------------- +init_per_group(_GroupName, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% @spec end_per_group(GroupName, Config0) -> +%% void() | {save_config,Config1} +%% GroupName = atom() +%% Config0 = Config1 = [tuple()] +%% @end +%%-------------------------------------------------------------------- +end_per_group(_GroupName, _Config) -> + ok. + +%%-------------------------------------------------------------------- +%% @spec init_per_testcase(TestCase, Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% TestCase = atom() +%% Config0 = Config1 = [tuple()] +%% Reason = term() +%% @end +%%-------------------------------------------------------------------- +init_per_testcase(_TestCase, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% @spec end_per_testcase(TestCase, Config0) -> +%% void() | {save_config,Config1} | {fail,Reason} +%% TestCase = atom() +%% Config0 = Config1 = [tuple()] +%% Reason = term() +%% @end +%%-------------------------------------------------------------------- +end_per_testcase(_TestCase, _Config) -> + ok. + +%%-------------------------------------------------------------------- +%% @spec groups() -> [Group] +%% Group = {GroupName,Properties,GroupsAndTestCases} +%% GroupName = atom() +%% Properties = [parallel | sequence | Shuffle | {RepeatType,N}] +%% GroupsAndTestCases = [Group | {group,GroupName} | TestCase] +%% TestCase = atom() +%% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}} +%% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | +%% repeat_until_any_ok | repeat_until_any_fail +%% N = integer() | forever +%% @end +%%-------------------------------------------------------------------- +groups() -> + []. + +%%-------------------------------------------------------------------- +%% @spec all() -> GroupsAndTestCases | {skip,Reason} +%% GroupsAndTestCases = [{group,GroupName} | TestCase] +%% GroupName = atom() +%% TestCase = atom() +%% Reason = term() +%% @end +%%-------------------------------------------------------------------- +all() -> + [tc1]. + +tc1(_C) -> + ok. diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk index 877aa775fd..5c9fdfc47e 100644 --- a/lib/common_test/vsn.mk +++ b/lib/common_test/vsn.mk @@ -1 +1 @@ -COMMON_TEST_VSN = 1.6.2 +COMMON_TEST_VSN = 1.6.2.1 diff --git a/lib/kernel/doc/src/global.xml b/lib/kernel/doc/src/global.xml index 304a9b1d88..9c50049503 100644 --- a/lib/kernel/doc/src/global.xml +++ b/lib/kernel/doc/src/global.xml @@ -163,7 +163,8 @@ <fsummary>Globally register a name for a pid</fsummary> <type name="method"/> <type_desc name="method">{<c>Module</c>, <c>Function</c>} - is also allowed + is currently also allowed for backward compatibility, but its use is + deprecated </type_desc> <desc> <p>Globally associates the name <c><anno>Name</anno></c> with a pid, that is, @@ -180,6 +181,15 @@ unregistered. This function is called once for each name clash.</p> + <warning> + <p>If you plan to change code without restarting your system, + you must use an external fun (<c>fun Module:Function/Arity</c>) + as the <c><anno>Resolve</anno></c> function; if you use a + local fun you can never replace the code for the module that + the fun belongs to. + </p> + </warning> + <p>There are three pre-defined resolve functions: <c>random_exit_name/3</c>, <c>random_notify_name/3</c>, and <c>notify_all_name/3</c>. If no <c><anno>Resolve</anno></c> function is diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl index c299fb085c..9b7c4aa7b8 100644 --- a/lib/kernel/src/application.erl +++ b/lib/kernel/src/application.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. 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 @@ -37,8 +37,7 @@ -type application_opt() :: {'description', Description :: string()} | {'vsn', Vsn :: string()} | {'id', Id :: string()} - | {'modules', [(Module :: module()) | - {Module :: module(), Version :: term()}]} + | {'modules', [Module :: module()]} | {'registered', Names :: [Name :: atom()]} | {'applications', [Application :: atom()]} | {'included_applications', [Application :: atom()]} diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl index ebfe84463a..68cd26ec10 100644 --- a/lib/kernel/src/application_controller.erl +++ b/lib/kernel/src/application_controller.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. 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 @@ -162,7 +162,7 @@ %% appl_opt() = {description, string()} | %% {vsn, string()} | %% {id, string()}, | -%% {modules, [Module|{Module,Vsn}]} | +%% {modules, [Module]} | %% {registered, [atom()]} | %% {applications, [atom()]} | %% {included_applications, [atom()]} | @@ -172,7 +172,6 @@ %% {maxP, integer()|infinity} | %% {mod, {Module, term()}} %% Module = atom() -%% Vsn = term() %% Purpose: Starts the application_controller. This process starts all %% application masters for the applications. %% The kernel application is the only application that is @@ -446,7 +445,7 @@ get_application_module(Module) -> get_application_module(Module, AppModules). get_application_module(Module, [[AppName, Modules]|AppModules]) -> - case in_modules(Module, Modules) of + case lists:member(Module, Modules) of true -> {ok, AppName}; false -> @@ -455,16 +454,6 @@ get_application_module(Module, [[AppName, Modules]|AppModules]) -> get_application_module(_Module, []) -> undefined. -%% 'modules' key in .app is a list of Module or {Module,Vsn} -in_modules(Module, [Module|_Modules]) -> - true; -in_modules(Module, [{Module, _Vsn}|_Modules]) -> - true; -in_modules(Module, [_Module|Modules]) -> - in_modules(Module, Modules); -in_modules(_Module, []) -> - false. - permit_application(ApplName, Flag) -> gen_server:call(?AC, {permit_application, ApplName, Flag}, diff --git a/lib/kernel/src/global.erl b/lib/kernel/src/global.erl index 36cb713ee1..b24a9d5eac 100644 --- a/lib/kernel/src/global.erl +++ b/lib/kernel/src/global.erl @@ -232,7 +232,8 @@ register_name(Name, Pid) when is_pid(Pid) -> Name :: term(), Pid :: pid(), Resolve :: method(). -register_name(Name, Pid, Method) when is_pid(Pid) -> +register_name(Name, Pid, Method0) when is_pid(Pid) -> + Method = allow_tuple_fun(Method0), Fun = fun(Nodes) -> case (where(Name) =:= undefined) andalso check_dupname(Name, Pid) of true -> @@ -290,7 +291,8 @@ re_register_name(Name, Pid) when is_pid(Pid) -> Name :: term(), Pid :: pid(), Resolve :: method(). -re_register_name(Name, Pid, Method) when is_pid(Pid) -> +re_register_name(Name, Pid, Method0) when is_pid(Pid) -> + Method = allow_tuple_fun(Method0), Fun = fun(Nodes) -> gen_server:multi_call(Nodes, global_name_server, @@ -2218,3 +2220,9 @@ intersection(_, []) -> []; intersection(L1, L2) -> L1 -- (L1 -- L2). + +%% Support legacy tuple funs as resolve functions. +allow_tuple_fun({M, F}) when is_atom(M), is_atom(F) -> + fun M:F/3; +allow_tuple_fun(Fun) when is_function(Fun, 3) -> + Fun. diff --git a/lib/public_key/asn1/OTP-PKIX.asn1 b/lib/public_key/asn1/OTP-PKIX.asn1 index e94a77a3e7..4f20208bce 100644 --- a/lib/public_key/asn1/OTP-PKIX.asn1 +++ b/lib/public_key/asn1/OTP-PKIX.asn1 @@ -119,6 +119,7 @@ IMPORTS md2WithRSAEncryption, md5WithRSAEncryption, sha1WithRSAEncryption, + sha224WithRSAEncryption, sha256WithRSAEncryption, sha384WithRSAEncryption, sha512WithRSAEncryption @@ -317,6 +318,7 @@ PublicKeyAlgorithm ::= SEQUENCE { SupportedSignatureAlgorithms SIGNATURE-ALGORITHM-CLASS ::= { dsa-with-sha1 | md2-with-rsa-encryption | md5-with-rsa-encryption | sha1-with-rsa-encryption | + sha224-with-rsa-encryption | sha256-with-rsa-encryption | sha384-with-rsa-encryption | sha512-with-rsa-encryption | @@ -365,6 +367,10 @@ SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= { ID sha1WithRSAEncryption TYPE NULL } + sha224-with-rsa-encryption SIGNATURE-ALGORITHM-CLASS ::= { + ID sha224WithRSAEncryption + TYPE NULL } + sha256-with-rsa-encryption SIGNATURE-ALGORITHM-CLASS ::= { ID sha256WithRSAEncryption TYPE NULL } diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl index b76e32a2a0..f9e2025479 100644 --- a/lib/public_key/src/pubkey_cert.erl +++ b/lib/public_key/src/pubkey_cert.erl @@ -376,8 +376,12 @@ encoded_tbs_cert(Cert) -> digest_type(?sha1WithRSAEncryption) -> sha; +digest_type(?sha224WithRSAEncryption) -> + sha224; digest_type(?sha256WithRSAEncryption) -> sha256; +digest_type(?sha384WithRSAEncryption) -> + sha384; digest_type(?sha512WithRSAEncryption) -> sha512; digest_type(?md5WithRSAEncryption) -> diff --git a/lib/public_key/src/pubkey_ssh.erl b/lib/public_key/src/pubkey_ssh.erl index f0c94e29a5..008ea96dd3 100644 --- a/lib/public_key/src/pubkey_ssh.erl +++ b/lib/public_key/src/pubkey_ssh.erl @@ -47,7 +47,7 @@ decode(Bin, public_key)-> rfc4716_decode(Bin) end; decode(Bin, rfc4716_public_key) -> - rfc4716_decode(Bin); + rfc4716_decode(Bin); decode(Bin, Type) -> openssh_decode(Bin, Type). @@ -58,7 +58,7 @@ decode(Bin, Type) -> %% Description: Encodes a list of ssh file entries. %%-------------------------------------------------------------------- encode(Entries, Type) -> - erlang:iolist_to_binary(lists:map(fun({Key, Attributes}) -> + iolist_to_binary(lists:map(fun({Key, Attributes}) -> do_encode(Type, Key, Attributes) end, Entries)). @@ -106,7 +106,7 @@ rfc4716_decode_line(Line, Lines, Acc) -> _ -> {Body, Rest} = join_entry([Line | Lines], []), {lists:reverse(Acc), rfc4716_pubkey_decode(base64:mime_decode(Body)), Rest} - end. + end. join_entry([<<"---- END SSH2 PUBLIC KEY ----", _/binary>>| Lines], Entry) -> {lists:reverse(Entry), Lines}; @@ -115,16 +115,16 @@ join_entry([Line | Lines], Entry) -> rfc4716_pubkey_decode(<<?UINT32(Len), Type:Len/binary, - ?UINT32(SizeE), E:SizeE/binary, - ?UINT32(SizeN), N:SizeN/binary>>) when Type == <<"ssh-rsa">> -> + ?UINT32(SizeE), E:SizeE/binary, + ?UINT32(SizeN), N:SizeN/binary>>) when Type == <<"ssh-rsa">> -> #'RSAPublicKey'{modulus = erlint(SizeN, N), publicExponent = erlint(SizeE, E)}; rfc4716_pubkey_decode(<<?UINT32(Len), Type:Len/binary, - ?UINT32(SizeP), P:SizeP/binary, - ?UINT32(SizeQ), Q:SizeQ/binary, - ?UINT32(SizeG), G:SizeG/binary, - ?UINT32(SizeY), Y:SizeY/binary>>) when Type == <<"ssh-dss">> -> + ?UINT32(SizeP), P:SizeP/binary, + ?UINT32(SizeQ), Q:SizeQ/binary, + ?UINT32(SizeG), G:SizeG/binary, + ?UINT32(SizeY), Y:SizeY/binary>>) when Type == <<"ssh-dss">> -> {erlint(SizeY, Y), #'Dss-Parms'{p = erlint(SizeP, P), q = erlint(SizeQ, Q), @@ -143,94 +143,63 @@ do_openssh_decode(FileType, [<<>> | Lines], Acc) -> do_openssh_decode(FileType,[<<"#", _/binary>> | Lines], Acc) -> do_openssh_decode(FileType, Lines, Acc); do_openssh_decode(auth_keys = FileType, [Line | Lines], Acc) -> - Split = binary:split(Line, <<" ">>, [global]), - case mend_split(Split, []) of - %% ssh2 - [KeyType, Base64Enc, Comment] -> + case decode_auth_keys(Line) of + {ssh2, {options, [Options, KeyType, Base64Enc| Comment]}} -> do_openssh_decode(FileType, Lines, - [{openssh_pubkey_decode(KeyType, Base64Enc), - [{comment, string_decode(Comment)}]} | Acc]); - %% ssh1 - [Options, Bits, Exponent, Modulus, Comment] -> + [{openssh_pubkey_decode(KeyType, Base64Enc), + decode_comment(Comment) ++ [{options, comma_list_decode(Options)}]} | Acc]); + {ssh2, {no_options, [KeyType, Base64Enc| Comment]}} -> + do_openssh_decode(FileType, Lines, + [{openssh_pubkey_decode(KeyType, Base64Enc), + decode_comment(Comment)} | Acc]); + {ssh1, {options, [Options, Bits, Exponent, Modulus | Comment]}} -> do_openssh_decode(FileType, Lines, [{ssh1_rsa_pubkey_decode(Modulus, Exponent), - [{comment, string_decode(Comment)}, - {options, comma_list_decode(Options)}, - {bits, integer_decode(Bits)}]} | Acc]); - [A, B, C, D] -> - ssh_2_or_1(FileType, Lines, Acc, A,B,C,D) + decode_comment(Comment) ++ [{options, comma_list_decode(Options)}, + {bits, integer_decode(Bits)}] + } | Acc]); + {ssh1, {no_options, [Bits, Exponent, Modulus | Comment]}} -> + do_openssh_decode(FileType, Lines, + [{ssh1_rsa_pubkey_decode(Modulus, Exponent), + decode_comment(Comment) ++ [{bits, integer_decode(Bits)}] + } | Acc]) end; do_openssh_decode(known_hosts = FileType, [Line | Lines], Acc) -> - Split = binary:split(Line, <<" ">>, [global]), - case mend_split(Split, []) of - %% ssh 2 - [HostNames, KeyType, Base64Enc] -> + case decode_known_hosts(Line) of + {ssh2, [HostNames, KeyType, Base64Enc| Comment]} -> do_openssh_decode(FileType, Lines, - [{openssh_pubkey_decode(KeyType, Base64Enc), - [{hostnames, comma_list_decode(HostNames)}]}| Acc]); - [A, B, C, D] -> - ssh_2_or_1(FileType, Lines, Acc, A, B, C, D); - %% ssh 1 - [HostNames, Bits, Exponent, Modulus, Comment] -> + [{openssh_pubkey_decode(KeyType, Base64Enc), + decode_comment(Comment) ++ + [{hostnames, comma_list_decode(HostNames)}]}| Acc]); + {ssh1, [HostNames, Bits, Exponent, Modulus | Comment]} -> do_openssh_decode(FileType, Lines, - [{ssh1_rsa_pubkey_decode(Modulus, Exponent), - [{comment, string_decode(Comment)}, - {hostnames, comma_list_decode(HostNames)}, - {bits, integer_decode(Bits)}]} | Acc]) - end; + [{ssh1_rsa_pubkey_decode(Modulus, Exponent), + decode_comment(Comment) ++ + [{hostnames, comma_list_decode(HostNames)}, + {bits, integer_decode(Bits)}]} + | Acc]) + end; do_openssh_decode(openssh_public_key = FileType, [Line | Lines], Acc) -> - Split = binary:split(Line, <<" ">>, [global]), - case mend_split(Split, []) of - [KeyType, Base64Enc, Comment0] when KeyType == <<"ssh-rsa">>; - KeyType == <<"ssh-dss">> -> - Comment = string:strip(binary_to_list(Comment0), right, $\n), + case split_n(2, Line, []) of + [KeyType, Base64Enc] when KeyType == <<"ssh-rsa">>; + KeyType == <<"ssh-dss">> -> + do_openssh_decode(FileType, Lines, + [{openssh_pubkey_decode(KeyType, Base64Enc), + []} | Acc]); + [KeyType, Base64Enc | Comment0] when KeyType == <<"ssh-rsa">>; + KeyType == <<"ssh-dss">> -> + Comment = string:strip(string_decode(iolist_to_binary(Comment0)), right, $\n), do_openssh_decode(FileType, Lines, [{openssh_pubkey_decode(KeyType, Base64Enc), [{comment, Comment}]} | Acc]) end. -ssh_2_or_1(known_hosts = FileType, Lines, Acc, A, B, C, D) -> - try integer_decode(B) of - Int -> - file_type_decode_ssh1(FileType, Lines, Acc, A, Int, C,D) - catch - error:badarg -> - file_type_decode_ssh2(FileType, Lines, Acc, A,B,C,D) - end; -ssh_2_or_1(auth_keys = FileType, Lines, Acc, A, B, C, D) -> - try integer_decode(A) of - Int -> - file_type_decode_ssh1(FileType, Lines, Acc, Int, B, C,D) - catch - error:badarg -> - file_type_decode_ssh2(FileType, Lines, Acc, A,B,C,D) - end. - -file_type_decode_ssh1(known_hosts = FileType, Lines, Acc, HostNames, Bits, Exponent, Modulus) -> - do_openssh_decode(FileType, Lines, - [{ssh1_rsa_pubkey_decode(Modulus, Exponent), - [{comment, []}, - {hostnames, comma_list_decode(HostNames)}, - {bits, Bits}]} | Acc]); -file_type_decode_ssh1(auth_keys = FileType, Lines, Acc, Bits, Exponent, Modulus, Comment) -> - do_openssh_decode(FileType, Lines, - [{ssh1_rsa_pubkey_decode(Modulus, Exponent), - [{comment, string_decode(Comment)}, - {bits, Bits}]} | Acc]). - -file_type_decode_ssh2(known_hosts = FileType, Lines, Acc, HostNames, KeyType, Base64Enc, Comment) -> - do_openssh_decode(FileType, Lines, - [{openssh_pubkey_decode(KeyType, Base64Enc), - [{comment, string_decode(Comment)}, - {hostnames, comma_list_decode(HostNames)}]} | Acc]); -file_type_decode_ssh2(auth_keys = FileType, Lines, Acc, Options, KeyType, Base64Enc, Comment) -> - do_openssh_decode(FileType, Lines, - [{openssh_pubkey_decode(KeyType, Base64Enc), - [{comment, string_decode(Comment)}, - {options, comma_list_decode(Options)}]} - | Acc]). +decode_comment([]) -> + []; +decode_comment(Comment) -> + [{comment, string_decode(iolist_to_binary(Comment))}]. openssh_pubkey_decode(<<"ssh-rsa">>, Base64Enc) -> <<?UINT32(StrLen), _:StrLen/binary, @@ -267,7 +236,7 @@ integer_decode(BinStr) -> list_to_integer(binary_to_list(BinStr)). string_decode(BinStr) -> - binary_to_list(BinStr). + unicode_decode(BinStr). unicode_decode(BinStr) -> unicode:characters_to_list(BinStr). @@ -285,11 +254,11 @@ do_encode(Type, Key, Attributes) -> openssh_encode(Type, Key, Attributes). rfc4716_encode(Key, [],[]) -> - erlang:iolist_to_binary([begin_marker(),"\n", + iolist_to_binary([begin_marker(),"\n", split_lines(base64:encode(ssh2_pubkey_encode(Key))), "\n", end_marker(), "\n"]); rfc4716_encode(Key, [], [_|_] = Acc) -> - erlang:iolist_to_binary([begin_marker(), "\n", + iolist_to_binary([begin_marker(), "\n", lists:reverse(Acc), split_lines(base64:encode(ssh2_pubkey_encode(Key))), "\n", end_marker(), "\n"]); @@ -319,9 +288,9 @@ rfc4716_encode_value(Value) -> end. openssh_encode(openssh_public_key, Key, Attributes) -> - Comment = proplists:get_value(comment, Attributes), + Comment = proplists:get_value(comment, Attributes, ""), Enc = base64:encode(ssh2_pubkey_encode(Key)), - erlang:iolist_to_binary([key_type(Key), " ", Enc, " ", Comment, "\n"]); + iolist_to_binary([key_type(Key), " ", Enc, " ", Comment, "\n"]); openssh_encode(auth_keys, Key, Attributes) -> Comment = proplists:get_value(comment, Attributes, ""), @@ -345,30 +314,30 @@ openssh_encode(known_hosts, Key, Attributes) -> end. openssh_ssh2_auth_keys_encode(undefined, Key, Comment) -> - erlang:iolist_to_binary([key_type(Key)," ", base64:encode(ssh2_pubkey_encode(Key)), line_end(Comment)]); + iolist_to_binary([key_type(Key)," ", base64:encode(ssh2_pubkey_encode(Key)), line_end(Comment)]); openssh_ssh2_auth_keys_encode(Options, Key, Comment) -> - erlang:iolist_to_binary([comma_list_encode(Options, []), " ", + iolist_to_binary([comma_list_encode(Options, []), " ", key_type(Key)," ", base64:encode(ssh2_pubkey_encode(Key)), line_end(Comment)]). openssh_ssh1_auth_keys_encode(undefined, Bits, #'RSAPublicKey'{modulus = N, publicExponent = E}, Comment) -> - erlang:iolist_to_binary([integer_to_list(Bits), " ", integer_to_list(E), " ", integer_to_list(N), + iolist_to_binary([integer_to_list(Bits), " ", integer_to_list(E), " ", integer_to_list(N), line_end(Comment)]); openssh_ssh1_auth_keys_encode(Options, Bits, #'RSAPublicKey'{modulus = N, publicExponent = E}, Comment) -> - erlang:iolist_to_binary([comma_list_encode(Options, []), " ", integer_to_list(Bits), + iolist_to_binary([comma_list_encode(Options, []), " ", integer_to_list(Bits), " ", integer_to_list(E), " ", integer_to_list(N), line_end(Comment)]). openssh_ssh2_know_hosts_encode(Hostnames, Key, Comment) -> - erlang:iolist_to_binary([comma_list_encode(Hostnames, []), " ", + iolist_to_binary([comma_list_encode(Hostnames, []), " ", key_type(Key)," ", base64:encode(ssh2_pubkey_encode(Key)), line_end(Comment)]). openssh_ssh1_known_hosts_encode(Hostnames, Bits, - #'RSAPublicKey'{modulus = N, publicExponent = E}, - Comment) -> - erlang:iolist_to_binary([comma_list_encode(Hostnames, [])," ", integer_to_list(Bits)," ", + #'RSAPublicKey'{modulus = N, publicExponent = E}, + Comment) -> + iolist_to_binary([comma_list_encode(Hostnames, [])," ", integer_to_list(Bits)," ", integer_to_list(E)," ", integer_to_list(N), line_end(Comment)]). line_end("") -> @@ -411,24 +380,6 @@ ssh2_pubkey_encode({Y, #'Dss-Parms'{p = P, q = Q, g = G}}) -> GBin/binary, YBin/binary>>. -mend_split([Part1, Part2 | Rest] = List, Acc) -> - case option_end(Part1, Part2) of - true -> - lists:reverse(Acc) ++ List; - false -> - case length(binary:matches(Part1, <<"\"">>)) of - N when N rem 2 == 0 -> - mend_split(Rest, [Part1 | Acc]); - _ -> - mend_split([<<Part1/binary, Part2/binary>> | Rest], Acc) - end - end. - -option_end(Part1, Part2) -> - (is_key_field(Part1) orelse is_bits_field(Part1)) - orelse - (is_key_field(Part2) orelse is_bits_field(Part2)). - is_key_field(<<"ssh-dss">>) -> true; is_key_field(<<"ssh-rsa">>) -> @@ -456,3 +407,72 @@ split_lines(<<Text:?ENCODED_LINE_LENGTH/binary, Rest/binary>>) -> [Text, $\n | split_lines(Rest)]; split_lines(Bin) -> [Bin]. + +decode_auth_keys(Line) -> + [First, Rest] = binary:split(Line, <<" ">>, []), + case is_key_field(First) of + true -> + {ssh2, decode_auth_keys_ssh2(First, Rest)}; + false -> + case is_bits_field(First) of + true -> + {ssh1, decode_auth_keys_ssh1(First, Rest)}; + false -> + decode_auth_keys(First, Rest) + end + end. + +decode_auth_keys(First, Line) -> + [Second, Rest] = binary:split(Line, <<" ">>, []), + case is_key_field(Second) of + true -> + {ssh2, decode_auth_keys_ssh2(First, Second, Rest)}; + false -> + case is_bits_field(Second) of + true -> + {ssh1, decode_auth_keys_ssh1(First, Second, Rest)}; + false -> + decode_auth_keys(<<First/binary, Second/binary>>, Rest) + end + end. + +decode_auth_keys_ssh2(KeyType, Rest) -> + {no_options, [KeyType | split_n(1, Rest, [])]}. + +decode_auth_keys_ssh2(Options, Next, Rest) -> + {options, [Options, Next | split_n(1, Rest, [])]}. + +decode_auth_keys_ssh1(Options, Next, Rest) -> + {options, [Options, Next | split_n(2, Rest, [])]}. + +decode_auth_keys_ssh1(First, Rest) -> + {no_options, [First | split_n(2, Rest, [])]}. + +decode_known_hosts(Line) -> + [First, Rest] = binary:split(Line, <<" ">>, []), + [Second, Rest1] = binary:split(Rest, <<" ">>, []), + + case is_bits_field(Second) of + true -> + {ssh1, decode_known_hosts_ssh1(First, Second, Rest1)}; + false -> + {ssh2, decode_known_hosts_ssh2(First, Second, Rest1)} + end. + +decode_known_hosts_ssh1(Hostnames, Bits, Rest) -> + [Hostnames, Bits | split_n(2, Rest, [])]. + +decode_known_hosts_ssh2(Hostnames, KeyType, Rest) -> + [Hostnames, KeyType | split_n(1, Rest, [])]. + +split_n(0, <<>>, Acc) -> + lists:reverse(Acc); +split_n(0, Bin, Acc) -> + lists:reverse([Bin | Acc]); +split_n(N, Bin, Acc) -> + case binary:split(Bin, <<" ">>, []) of + [First, Rest] -> + split_n(N-1, Rest, [First | Acc]); + [Last] -> + split_n(0, <<>>, [Last | Acc]) + end. diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index 6a879867e1..f2f30dad6e 100644 --- a/lib/public_key/test/public_key_SUITE.erl +++ b/lib/public_key/test/public_key_SUITE.erl @@ -405,9 +405,20 @@ ssh_known_hosts(Config) when is_list(Config) -> Datadir = ?config(data_dir, Config), {ok, SshKnownHosts} = file:read_file(filename:join(Datadir, "known_hosts")), - [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2}] = Decoded = + [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2}, + {#'RSAPublicKey'{}, Attributes3}, {#'RSAPublicKey'{}, Attributes4}] = Decoded = public_key:ssh_decode(SshKnownHosts, known_hosts), + Comment1 = undefined, + Comment2 = "[email protected]", + Comment3 = "Comment with whitespaces", + Comment4 = "[email protected] Comment with whitespaces", + + Comment1 = proplists:get_value(comment, Attributes1, undefined), + Comment2 = proplists:get_value(comment, Attributes2), + Comment3 = proplists:get_value(comment, Attributes3), + Comment4 = proplists:get_value(comment, Attributes4), + Value1 = proplists:get_value(hostnames, Attributes1, undefined), Value2 = proplists:get_value(hostnames, Attributes2, undefined), true = (Value1 =/= undefined) and (Value2 =/= undefined), @@ -425,13 +436,16 @@ ssh1_known_hosts(Config) when is_list(Config) -> Datadir = ?config(data_dir, Config), {ok, SshKnownHosts} = file:read_file(filename:join(Datadir, "ssh1_known_hosts")), - [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2}] = Decoded = - public_key:ssh_decode(SshKnownHosts, known_hosts), + [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2},{#'RSAPublicKey'{}, Attributes3}] + = Decoded = public_key:ssh_decode(SshKnownHosts, known_hosts), Value1 = proplists:get_value(hostnames, Attributes1, undefined), Value2 = proplists:get_value(hostnames, Attributes2, undefined), true = (Value1 =/= undefined) and (Value2 =/= undefined), + Comment ="dhopson@VMUbuntu-DSH comment with whitespaces", + Comment = proplists:get_value(comment, Attributes3), + Encoded = public_key:ssh_encode(Decoded, known_hosts), Decoded = public_key:ssh_decode(Encoded, known_hosts). @@ -444,12 +458,22 @@ ssh_auth_keys(Config) when is_list(Config) -> Datadir = ?config(data_dir, Config), {ok, SshAuthKeys} = file:read_file(filename:join(Datadir, "auth_keys")), - [{#'RSAPublicKey'{}, Attributes1}, {{_, #'Dss-Parms'{}}, _Attributes2}] = Decoded = + [{#'RSAPublicKey'{}, Attributes1}, {{_, #'Dss-Parms'{}}, Attributes2}, + {#'RSAPublicKey'{}, Attributes3}, {{_, #'Dss-Parms'{}}, Attributes4} + ] = Decoded = public_key:ssh_decode(SshAuthKeys, auth_keys), Value1 = proplists:get_value(options, Attributes1, undefined), true = Value1 =/= undefined, + Comment1 = Comment2 = "dhopson@VMUbuntu-DSH", + Comment3 = Comment4 ="dhopson@VMUbuntu-DSH comment with whitespaces", + + Comment1 = proplists:get_value(comment, Attributes1), + Comment2 = proplists:get_value(comment, Attributes2), + Comment3 = proplists:get_value(comment, Attributes3), + Comment4 = proplists:get_value(comment, Attributes4), + Encoded = public_key:ssh_encode(Decoded, auth_keys), Decoded = public_key:ssh_decode(Encoded, auth_keys). @@ -462,13 +486,24 @@ ssh1_auth_keys(Config) when is_list(Config) -> Datadir = ?config(data_dir, Config), {ok, SshAuthKeys} = file:read_file(filename:join(Datadir, "ssh1_auth_keys")), - [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2}] = Decoded = + [{#'RSAPublicKey'{}, Attributes1}, + {#'RSAPublicKey'{}, Attributes2}, {#'RSAPublicKey'{}, Attributes3}, + {#'RSAPublicKey'{}, Attributes4}, {#'RSAPublicKey'{}, Attributes5}] = Decoded = public_key:ssh_decode(SshAuthKeys, auth_keys), - Value1 = proplists:get_value(bits, Attributes1, undefined), - Value2 = proplists:get_value(bits, Attributes2, undefined), + Value1 = proplists:get_value(bits, Attributes2, undefined), + Value2 = proplists:get_value(bits, Attributes3, undefined), true = (Value1 =/= undefined) and (Value2 =/= undefined), + Comment2 = Comment3 = "dhopson@VMUbuntu-DSH", + Comment4 = Comment5 ="dhopson@VMUbuntu-DSH comment with whitespaces", + + undefined = proplists:get_value(comment, Attributes1, undefined), + Comment2 = proplists:get_value(comment, Attributes2), + Comment3 = proplists:get_value(comment, Attributes3), + Comment4 = proplists:get_value(comment, Attributes4), + Comment5 = proplists:get_value(comment, Attributes5), + Encoded = public_key:ssh_encode(Decoded, auth_keys), Decoded = public_key:ssh_decode(Encoded, auth_keys). diff --git a/lib/public_key/test/public_key_SUITE_data/auth_keys b/lib/public_key/test/public_key_SUITE_data/auth_keys index 0c4b47edde..8be7357a06 100644 --- a/lib/public_key/test/public_key_SUITE_data/auth_keys +++ b/lib/public_key/test/public_key_SUITE_data/auth_keys @@ -1,3 +1,7 @@ command="dump /home",no-pty,no-port-forwarding ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAwrr66r8n6B8Y0zMF3dOpXEapIQD9DiYQ6D6/zwor9o39jSkHNiMMER/GETBbzP83LOcekm02aRjo55ArO7gPPVvCXbrirJu9pkm4AC4BBre5xSLS7soyzwbigFruM8G63jSXqpHqJ/ooi168sKMC2b0Ncsi+JlTfNYlDXJVLKEeZgZOInQyMmtisaDTUQWTIv1snAizf4iIYENuAkGYGNCL77u5Y5VOu5eQipvFajTnps9QvUx/zdSFYn9e2sulWM3Bxc/S4IJ67JWHVRpfJxGi3hinRBH8WQdXuUwdJJTiJHKPyYrrM7Q6Xq4TOMFtcRuLDC6u3BXM1L0gBvHPNOnD5l2Lp5EjUkQ9CBf2j4A4gfH+iWQZyk08esAG/iwArAVxkl368+dkbMWOXL8BN4x5zYgdzoeypQZZ2RKH780MCTSo4WQ19DP8pw+9q3bSFC9H3xYAxrKAJNWjeTUJOTrTe+mWXXU770gYyQTxa2ycnYrlZucn1S3vsvn6eq7NZZ8NRbyv1n15Ocg+nHK4fuKOrwPhU3NbKQwtjb0Wsxx1gAmQqIOLTpAdsrAauPxC7TPYA5qQVCphvimKuhQM/1gMV225JrnjspVlthCzuFYUjXOKC3wxz6FFEtwnXu3uC5bVVkmkNadJmD21gD23yk4BraGXVYpRMIB+X+OTUUI8= dhopson@VMUbuntu-DSH ssh-dss AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbETW6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdHYI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5cvwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGfJ0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAAvioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACBAN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HSn24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV dhopson@VMUbuntu-DSH + +command="dump /home",no-pty,no-port-forwarding ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAwrr66r8n6B8Y0zMF3dOpXEapIQD9DiYQ6D6/zwor9o39jSkHNiMMER/GETBbzP83LOcekm02aRjo55ArO7gPPVvCXbrirJu9pkm4AC4BBre5xSLS7soyzwbigFruM8G63jSXqpHqJ/ooi168sKMC2b0Ncsi+JlTfNYlDXJVLKEeZgZOInQyMmtisaDTUQWTIv1snAizf4iIYENuAkGYGNCL77u5Y5VOu5eQipvFajTnps9QvUx/zdSFYn9e2sulWM3Bxc/S4IJ67JWHVRpfJxGi3hinRBH8WQdXuUwdJJTiJHKPyYrrM7Q6Xq4TOMFtcRuLDC6u3BXM1L0gBvHPNOnD5l2Lp5EjUkQ9CBf2j4A4gfH+iWQZyk08esAG/iwArAVxkl368+dkbMWOXL8BN4x5zYgdzoeypQZZ2RKH780MCTSo4WQ19DP8pw+9q3bSFC9H3xYAxrKAJNWjeTUJOTrTe+mWXXU770gYyQTxa2ycnYrlZucn1S3vsvn6eq7NZZ8NRbyv1n15Ocg+nHK4fuKOrwPhU3NbKQwtjb0Wsxx1gAmQqIOLTpAdsrAauPxC7TPYA5qQVCphvimKuhQM/1gMV225JrnjspVlthCzuFYUjXOKC3wxz6FFEtwnXu3uC5bVVkmkNadJmD21gD23yk4BraGXVYpRMIB+X+OTUUI8= dhopson@VMUbuntu-DSH comment with whitespaces + +ssh-dss AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbETW6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdHYI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5cvwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGfJ0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAAvioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACBAN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HSn24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV dhopson@VMUbuntu-DSH comment with whitespaces diff --git a/lib/public_key/test/public_key_SUITE_data/known_hosts b/lib/public_key/test/public_key_SUITE_data/known_hosts index 30fc3b1fe8..3c3af68178 100644 --- a/lib/public_key/test/public_key_SUITE_data/known_hosts +++ b/lib/public_key/test/public_key_SUITE_data/known_hosts @@ -1,3 +1,8 @@ hostname.domain.com,192.168.0.1 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1XY18+zA8VNK2YkzygOkMqUxHSTfxT1Xxx8CgDZgcQH8HUhPssW5ttvG8nKetlPQZAVk1C4WkWS1y5b3ekBhZTIxocp9Joc6V1+f2EOfO2mSLRwB16RGrdw6q7msrBXTC/dl+hF45kMMzVNzqxnSMVOa0sEPK2zK6Sg3Vi9fCSM= |1|BWO5qDxk/cFH0wa05JLdHn+j6xQ=|rXQvIxh5cDD3C43k5DPDamawVNA= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1XY18+zA8VNK2YkzygOkMqUxHSTfxT1Xxx8CgDZgcQH8HUhPssW5ttvG8nKetlPQZAVk1C4WkWS1y5b3ekBhZTIxocp9Joc6V1+f2EOfO2mSLRwB16RGrdw6q7msrBXTC/dl+hF45kMMzVNzqxnSMVOa0sEPK2zK6Sg3Vi9fCSM= [email protected] + +hostname.domain.com,192.168.0.1 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1XY18+zA8VNK2YkzygOkMqUxHSTfxT1Xxx8CgDZgcQH8HUhPssW5ttvG8nKetlPQZAVk1C4WkWS1y5b3ekBhZTIxocp9Joc6V1+f2EOfO2mSLRwB16RGrdw6q7msrBXTC/dl+hF45kMMzVNzqxnSMVOa0sEPK2zK6Sg3Vi9fCSM= Comment with whitespaces + +|1|BWO5qDxk/cFH0wa05JLdHn+j6xQ=|rXQvIxh5cDD3C43k5DPDamawVNA= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1XY18+zA8VNK2YkzygOkMqUxHSTfxT1Xxx8CgDZgcQH8HUhPssW5ttvG8nKetlPQZAVk1C4WkWS1y5b3ekBhZTIxocp9Joc6V1+f2EOfO2mSLRwB16RGrdw6q7msrBXTC/dl+hF45kMMzVNzqxnSMVOa0sEPK2zK6Sg3Vi9fCSM= [email protected] Comment with whitespaces + diff --git a/lib/public_key/test/public_key_SUITE_data/ssh1_auth_keys b/lib/public_key/test/public_key_SUITE_data/ssh1_auth_keys index c91f4e4679..ac3d61b4c7 100644 --- a/lib/public_key/test/public_key_SUITE_data/ssh1_auth_keys +++ b/lib/public_key/test/public_key_SUITE_data/ssh1_auth_keys @@ -1,3 +1,9 @@ +1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 + 1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 dhopson@VMUbuntu-DSH command="dump /home",no-pty,no-port-forwarding 1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 dhopson@VMUbuntu-DSH + +1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 dhopson@VMUbuntu-DSH comment with whitespaces + +command="dump /home",no-pty,no-port-forwarding 1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 dhopson@VMUbuntu-DSH comment with whitespaces diff --git a/lib/public_key/test/public_key_SUITE_data/ssh1_known_hosts b/lib/public_key/test/public_key_SUITE_data/ssh1_known_hosts index ec668fe05b..835b16ab67 100644 --- a/lib/public_key/test/public_key_SUITE_data/ssh1_known_hosts +++ b/lib/public_key/test/public_key_SUITE_data/ssh1_known_hosts @@ -1,2 +1,3 @@ hostname.domain.com,192.168.0.1 1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 dhopson@VMUbuntu-DSH hostname2.domain.com,192.168.0.2 1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 +hostname3.domain.com,192.168.0.3 1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 dhopson@VMUbuntu-DSH comment with whitespaces diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl index 61e660e918..e8b28998c1 100644 --- a/lib/sasl/src/systools_make.erl +++ b/lib/sasl/src/systools_make.erl @@ -673,7 +673,7 @@ check_item({_,{registered,Regs}},I) -> _ -> throw({bad_param, I}) end; check_item({_,{modules,Mods}},I) -> - case mod_list_p(Mods) of + case a_list_p(Mods) of true -> Mods; _ -> throw({bad_param, I}) end; @@ -900,11 +900,10 @@ find_pos(N, Name, [_OtherAppl|OrderedAppls]) -> check_modules(Appls, Path, TestP, Machine) -> %% first check that all the module names are unique - %% Make a list M1 = [{Mod,Vsn,App,AppVsn,Dir}] - %% where Vsn = '$$ignore$$' | Specified - M1 = [{Mod,Vsn,App,Appv,A#application.dir} || - {{App,Appv},A} <- Appls, - {Mod,Vsn} <- get_mod_vsn(A#application.modules)], + %% Make a list M1 = [{Mod,App,Dir}] + M1 = [{Mod,App,A#application.dir} || + {{App,_Appv},A} <- Appls, + Mod <- A#application.modules], case duplicates(M1) of [] -> case check_mods(M1, Appls, Path, TestP, Machine) of @@ -918,16 +917,8 @@ check_modules(Appls, Path, TestP, Machine) -> throw({error, {duplicate_modules, Dups}}) end. -get_mod_vsn([{Mod,Vsn}|Mods]) -> - [{Mod,Vsn}|get_mod_vsn(Mods)]; -get_mod_vsn([Mod|Mods]) -> - [{Mod,'$$ignore$$'}|get_mod_vsn(Mods)]; -get_mod_vsn([]) -> - []. - %%______________________________________________________________________ -%% Check that all modules exists and that the specified version -%% corresponds to the version in the module's source code. +%% Check that all modules exists. %% Use the module extension of the running machine as extension for %% the checked modules. @@ -952,7 +943,7 @@ check_src(Modules, Appls, Path, true, Machine) -> Ext = objfile_extension(Machine), IncPath = create_include_path(Appls, Path), append(map(fun(ModT) -> - {Mod,_Vsn,App,_,Dir} = ModT, + {Mod,App,Dir} = ModT, case check_mod(Mod,App,Dir,Ext,IncPath) of ok -> []; @@ -1421,10 +1412,7 @@ create_mandatory_path(Appls, PathFlag, Variables) -> %% Load all modules, except those in Mandatory_modules. load_appl_mods([{{Name,Vsn},A}|Appls], Mand, PathFlag, Variables) -> - Mods = map(fun({Mod,_}) -> Mod; - (Mod) -> Mod - end, - A#application.modules), + Mods = A#application.modules, load_commands(filter(fun(Mod) -> not member(Mod, Mand) end, Mods), cr_path(Name, Vsn, A, PathFlag, Variables)) ++ load_appl_mods(Appls, Mand, PathFlag, Variables); @@ -1784,9 +1772,7 @@ add_appl(Name, Vsn, App, Tar, Variables, Flags, Var) -> add_to_tar(Tar, filename:join(AppDir, Name ++ ".app"), filename:join(BinDir, Name ++ ".app")), - add_modules(map(fun({Mod,_}) -> to_list(Mod); - (Mod) -> to_list(Mod) - end, + add_modules(map(fun(Mod) -> to_list(Mod) end, App#application.modules), Tar, AppDir, @@ -2026,14 +2012,6 @@ t_list_p([{A,_}|T]) when is_atom(A) -> t_list_p(T); t_list_p([]) -> true; t_list_p(_) -> false. -% check if a term is a list of atoms or two-tuples with the first -% element as an atom. - -mod_list_p([{A,_}|T]) when is_atom(A) -> mod_list_p(T); -mod_list_p([A|T]) when is_atom(A) -> mod_list_p(T); -mod_list_p([]) -> true; -mod_list_p(_) -> false. - % check if a term is a list of atoms. a_list_p([A|T]) when is_atom(A) -> a_list_p(T); diff --git a/lib/sasl/src/systools_rc.erl b/lib/sasl/src/systools_rc.erl index c16f6aa845..cf5cca7cb3 100644 --- a/lib/sasl/src/systools_rc.erl +++ b/lib/sasl/src/systools_rc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. 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 @@ -326,8 +326,7 @@ translate_application_instrs(Script, Appls, PreAppls) -> fun({add_application, Appl, Type}) -> case lists:keysearch(Appl, #application.name, Appls) of {value, Application} -> - Mods = - remove_vsn(Application#application.modules), + Mods = Application#application.modules, ApplyL = case Type of none -> []; load -> [{apply, {application, load, [Appl]}}]; @@ -349,9 +348,11 @@ translate_application_instrs(Script, Appls, PreAppls) -> end, case lists:keysearch(Appl, #application.name, PreAppls) of {value, RemApplication} -> - Mods = remove_vsn(RemApplication#application.modules), + Mods = RemApplication#application.modules, + [{apply, {application, stop, [Appl]}}] ++ - [{remove, {M, brutal_purge, brutal_purge}} || M <- Mods] ++ + [{remove, {M, brutal_purge, brutal_purge}} + || M <- Mods] ++ [{purge, Mods}, {apply, {application, unload, [Appl]}}]; false -> @@ -360,16 +361,14 @@ translate_application_instrs(Script, Appls, PreAppls) -> ({restart_application, Appl}) -> case lists:keysearch(Appl, #application.name, PreAppls) of {value, PreApplication} -> - PreMods = - remove_vsn(PreApplication#application.modules), - + PreMods = PreApplication#application.modules, case lists:keysearch(Appl, #application.name, Appls) of {value, PostApplication} -> - PostMods = - remove_vsn(PostApplication#application.modules), - + PostMods = PostApplication#application.modules, + [{apply, {application, stop, [Appl]}}] ++ - [{remove, {M, brutal_purge, brutal_purge}} || M <- PreMods] ++ + [{remove, {M, brutal_purge, brutal_purge}} + || M <- PreMods] ++ [{purge, PreMods}] ++ [{add_module, M, []} || M <- PostMods] ++ [{apply, {application, start, @@ -385,11 +384,6 @@ translate_application_instrs(Script, Appls, PreAppls) -> end, Script), lists:flatten(L). -remove_vsn(Mods) -> - lists:map(fun({Mod, _Vsn}) -> Mod; - (Mod) -> Mod - end, Mods). - %%----------------------------------------------------------------- %% Translates add_module into load_module (high-level transformation) %%----------------------------------------------------------------- @@ -654,15 +648,9 @@ translate_dep_to_low(Mode, Instructions, Appls) -> end. get_lib(Mod, [#application{name = Name, vsn = Vsn, modules = Modules} | T]) -> - %% Module = {Mod, Vsn} | Mod - case lists:keysearch(Mod, 1, Modules) of - {value, _} -> - {Name, Vsn}; - false -> - case lists:member(Mod, Modules) of - true -> {Name, Vsn}; - false -> get_lib(Mod, T) - end + case lists:member(Mod, Modules) of + true -> {Name, Vsn}; + false -> get_lib(Mod, T) end; get_lib(Mod, []) -> throw({error, {no_such_module, Mod}}). diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl index a8e3cc3d88..87a755031c 100644 --- a/lib/sasl/test/release_handler_SUITE.erl +++ b/lib/sasl/test/release_handler_SUITE.erl @@ -1206,12 +1206,25 @@ otp_9395_rm_many_mods(cleanup,_Conf) -> stop_node(node_name(otp_9395_rm_many_mods)). otp_9864(Conf) -> + case os:type() of + {win32,_} -> + {skip,"Testing handling of symlinks - skipped on windows"}; + _ -> + do_otp_9864(Conf) + end. +do_otp_9864(Conf) -> %% Set some paths PrivDir = priv_dir(Conf), Dir = filename:join(PrivDir,"otp_9864"), RelDir = filename:join(?config(data_dir, Conf), "app1_app2"), - LibDir1 = filename:join(RelDir, "lib1"), - LibDir2 = filename:join(RelDir, "lib2"), + + %% Copy libs to priv_dir because remove_release will remove some + %% of these again, and we don't want to remove anything from + %% data_dir + copy_tree(Conf,filename:join(RelDir, "lib1"),Dir), + copy_tree(Conf,filename:join(RelDir, "lib2"),Dir), + LibDir1 = filename:join(Dir, "lib1"), + LibDir2 = filename:join(Dir, "lib2"), %% Create the releases Rel1 = create_and_install_fake_first_release(Dir, @@ -1229,10 +1242,6 @@ otp_9864(Conf) -> {ok, Node} = t_start_node(otp_9864, Rel1, filename:join(Rel1Dir,"sys.config")), %% Unpack rel2 (make sure it does not work if an AppDir is bad) - LibDir3 = filename:join(RelDir, "lib3"), - {error, {no_such_directory, _}} = - rpc:call(Node, release_handler, set_unpacked, - [Rel2++".rel", [{app1,"2.0",LibDir2}, {app2,"1.0",LibDir3}]]), {ok, RelVsn2} = rpc:call(Node, release_handler, set_unpacked, [Rel2++".rel", [{app1,"2.0",LibDir2}, {app2,"1.0",LibDir2}]]), @@ -1243,22 +1252,27 @@ otp_9864(Conf) -> ok = rpc:call(Node, release_handler, install_file, [RelVsn2, filename:join(Rel2Dir, "sys.config")]), - %% Install RelVsn2 without {update_paths, true} option + %% Install RelVsn2 {ok, RelVsn1, []} = rpc:call(Node, release_handler, install_release, [RelVsn2]), - %% Install RelVsn1 again + %% Create a symlink inside release 2 + Releases2Dir = filename:join([Dir,"releases","2"]), + Link = filename:join(Releases2Dir,"foo_symlink_dir"), + file:make_symlink(Releases2Dir,Link), + + %% Back down to RelVsn1 {ok, RelVsn1, []} = rpc:call(Node, release_handler, install_release, [RelVsn1]), - TempRel2Dir = filename:join(Dir,"releases/2"), - file:make_symlink(TempRel2Dir, filename:join(TempRel2Dir, "foo_symlink_dir")), - %% This will fail if symlinks are not handled ok = rpc:call(Node, release_handler, remove_release, [RelVsn2]), ok. +otp_9864(cleanup,_Conf) -> + stop_node(node_name(otp_9864)). + upgrade_supervisor(Conf) when is_list(Conf) -> %% Set some paths diff --git a/lib/sasl/test/release_handler_SUITE_data/Makefile.src b/lib/sasl/test/release_handler_SUITE_data/Makefile.src index 55d20aa8b6..b794aa0e6f 100644 --- a/lib/sasl/test/release_handler_SUITE_data/Makefile.src +++ b/lib/sasl/test/release_handler_SUITE_data/Makefile.src @@ -1,9 +1,5 @@ EFLAGS=+debug_info -P2B= \ - P2B/a-2.0/ebin/a.@EMULATOR@ \ - P2B/a-2.0/ebin/a_sup.@EMULATOR@ - LIB= \ lib/a-9.1/ebin/a.@EMULATOR@ \ lib/a-9.1/ebin/a_sup.@EMULATOR@ \ @@ -80,13 +76,7 @@ SUP= \ release_handler_timeouts/dummy-0.1/ebin/dummy_sup.@EMULATOR@ \ release_handler_timeouts/dummy-0.1/ebin/dummy_sup_2.@EMULATOR@ -all: $(P2B) $(LIB) $(APP) $(OTP2740) $(C) $(SUP) - -P2B/a-2.0/ebin/a.@EMULATOR@: P2B/a-2.0/src/a.erl - erlc $(EFLAGS) -oP2B/a-2.0/ebin P2B/a-2.0/src/a.erl -P2B/a-2.0/ebin/a_sup.@EMULATOR@: P2B/a-2.0/src/a_sup.erl - erlc $(EFLAGS) -oP2B/a-2.0/ebin P2B/a-2.0/src/a_sup.erl - +all: $(LIB) $(APP) $(OTP2740) $(C) $(SUP) lib/a-1.0/ebin/a.@EMULATOR@: lib/a-1.0/src/a.erl erlc $(EFLAGS) -olib/a-1.0/ebin lib/a-1.0/src/a.erl diff --git a/lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/ebin/a.app b/lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/ebin/a.app deleted file mode 100644 index 200cfcfe47..0000000000 --- a/lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/ebin/a.app +++ /dev/null @@ -1,8 +0,0 @@ -{application, a, - [{description, "A CXC 138 11"}, - {vsn, "2.0"}, - {modules, [{a, 1}, {a_sup,1}]}, - {registered, [a_sup]}, - {applications, [kernel, stdlib]}, - {env, [{key1, val1}]}, - {mod, {a_sup, []}}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/src/a.erl b/lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/src/a.erl deleted file mode 100644 index cfe38b55ce..0000000000 --- a/lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/src/a.erl +++ /dev/null @@ -1,47 +0,0 @@ -%% ``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(a). - - --behaviour(gen_server). - -%% External exports --export([start_link/0, a/0]). -%% Internal exports --export([init/1, handle_call/3, handle_info/2, terminate/2]). - -start_link() -> gen_server:start_link({local, aa}, a, [], []). - -a() -> gen_server:call(aa, a). - -%%----------------------------------------------------------------- -%% Callback functions from gen_server -%%----------------------------------------------------------------- -init([]) -> - process_flag(trap_exit, true), - {ok, state}. - -handle_call(a, _From, State) -> - X = application:get_all_env(a), - {reply, X, State}. - -handle_info(_, State) -> - {noreply, State}. - -terminate(_Reason, _State) -> - ok. diff --git a/lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/src/a_sup.erl b/lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/src/a_sup.erl deleted file mode 100644 index a141c1767b..0000000000 --- a/lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/src/a_sup.erl +++ /dev/null @@ -1,37 +0,0 @@ -%% ``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(a_sup). - - --behaviour(supervisor). - -%% External exports --export([start/2]). - -%% Internal exports --export([init/1]). - -start(_, _) -> - supervisor:start_link({local, a_sup}, a_sup, []). - -init([]) -> - SupFlags = {one_for_one, 4, 3600}, - Config = {a, - {a, start_link, []}, - permanent, 2000, worker, [a]}, - {ok, {SupFlags, [Config]}}. diff --git a/lib/sasl/test/release_handler_SUITE_data/c/c.app b/lib/sasl/test/release_handler_SUITE_data/c/c.app index 908a94cf2d..2f56196918 100644 --- a/lib/sasl/test/release_handler_SUITE_data/c/c.app +++ b/lib/sasl/test/release_handler_SUITE_data/c/c.app @@ -1,7 +1,7 @@ {application, c, [{description, "C CXC 138 11"}, {vsn, "1.0"}, - {modules, [b, {aa, 1}, {c_sup,1}]}, + {modules, [b, aa, c_sup]}, {registered, [cc,bb,c_sup]}, {applications, [kernel, stdlib]}, {env, [{key1, val1}]}, diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/ebin/a.app b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/ebin/a.app index e938137f67..7ae189a36a 100644 --- a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/ebin/a.app +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/ebin/a.app @@ -1,7 +1,7 @@ {application, a, [{description, "A CXC 138 11"}, {vsn, "1.0"}, - {modules, [{a, 1}, {a_sup,1}]}, + {modules, [a, a_sup]}, {registered, [a_sup]}, {applications, [kernel, stdlib]}, {env, [{key1, val1}]}, diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.app b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.app index 1c3053b2fa..f8ab31fab9 100644 --- a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.app +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.app @@ -1,7 +1,7 @@ {application, a, [{description, "A CXC 138 11"}, {vsn, "1.1"}, - {modules, [{a, 2}, {a_sup,1}]}, + {modules, [a, a_sup]}, {registered, [a_sup]}, {applications, [kernel, stdlib]}, {env, [{key1, val1}]}, diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/ebin/a.app b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/ebin/a.app index b38722f06d..2393af0493 100644 --- a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/ebin/a.app +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/ebin/a.app @@ -1,7 +1,7 @@ {application, a, [{description, "A CXC 138 11"}, {vsn, "1.2"}, - {modules, [{a, 2}, {a_sup,1}]}, + {modules, [a, a_sup]}, {registered, [a_sup]}, {applications, [kernel, stdlib]}, {env, [{key1, val1}]}, diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/b-1.0/ebin/b.app b/lib/sasl/test/release_handler_SUITE_data/lib/b-1.0/ebin/b.app index 00347b2754..e2eada00a4 100644 --- a/lib/sasl/test/release_handler_SUITE_data/lib/b-1.0/ebin/b.app +++ b/lib/sasl/test/release_handler_SUITE_data/lib/b-1.0/ebin/b.app @@ -2,6 +2,6 @@ {application, b, [{description, "B CXC 138 12"}, {vsn, "1.0"}, - {modules, [{b_server, 1},{b_lib, 1}]}, + {modules, [b_server,b_lib]}, {registered, [b_server]}, {applications, [kernel, stdlib]}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.app b/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.app index 73c8e42b32..e4f8369ae5 100644 --- a/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.app +++ b/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.app @@ -2,6 +2,6 @@ {application, b, [{description, "B CXC 138 12"}, {vsn, "2.0"}, - {modules, [{b_server, 1}]}, + {modules, [b_server]}, {registered, [b_server]}, {applications, [kernel, stdlib]}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/ebin/many_mods.app b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/ebin/many_mods.app index aa39adfffa..5c56c4cd74 100644 --- a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/ebin/many_mods.app +++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/ebin/many_mods.app @@ -2,16 +2,6 @@ {application, many_mods, [{description, "Application with many modules CXC 138 11"}, {vsn, "1.0"}, - {modules, [{m, 1}, - {m1,1}, - {m2,1}, - {m3,1}, - {m4,1}, - {m5,1}, - {m6,1}, - {m7,1}, - {m8,1}, - {m9,1}, - {m10,1}]}, + {modules, [m,m1,m2,m3,m4,m5,m6,m7,m8,m9,m10]}, {registered, []}, {applications, [kernel, stdlib]}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.app b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.app index 36c50caf2f..87fdfe8442 100644 --- a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.app +++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.app @@ -2,16 +2,6 @@ {application, many_mods, [{description, "Application with many modules CXC 138 11"}, {vsn, "1.1"}, - {modules, [{m, 1}, - {m1,1}, - {m2,1}, - {m3,1}, - {m4,1}, - {m5,1}, - {m6,1}, - {m7,1}, - {m8,1}, - {m9,1}, - {m10,1}]}, + {modules, [m,m1,m2,m3,m4,m5,m6,m7,m8,m9,m10]}, {registered, []}, {applications, [kernel, stdlib]}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.app b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.app index 98f6527750..aba906d667 100644 --- a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.app +++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.app @@ -2,6 +2,6 @@ {application, many_mods, [{description, "Application with many modules CXC 138 11"}, {vsn, "2.0"}, - {modules, [{m, 1}]}, + {modules, [m]}, {registered, []}, {applications, [kernel, stdlib]}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/ebin/db.app b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/ebin/db.app index d375768b99..0878b80cb5 100644 --- a/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/ebin/db.app +++ b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/ebin/db.app @@ -1,7 +1,7 @@ {application, db, [{description, "ERICSSON NR FOR DB"}, {vsn, "2.0"}, - {modules, [{db1, "1.0"}, {db2, "1.0"}]}, + {modules, [db1, db2]}, {registered, []}, {applications, []}, {env, []}, diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/ebin/fe.app index d3bd85cda6..33d44805bd 100644 --- a/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/ebin/fe.app +++ b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/ebin/fe.app @@ -1,7 +1,7 @@ {application, fe, [{description, "ERICSSON NR FOR FE"}, {vsn, "3.1"}, - {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {modules, [fe1, fe2, fe3]}, {registered, []}, {applications, []}, {env, []}, diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-2.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-2.1/ebin/fe.app index 3cb0b0c2cf..d7fae9e092 100644 --- a/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-2.1/ebin/fe.app +++ b/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-2.1/ebin/fe.app @@ -1,7 +1,7 @@ {application, fe, [{description, "ERICSSON NR FOR FE"}, {vsn, "2.1"}, - {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {modules, [fe1, fe2, fe3]}, {registered, []}, {applications, []}, {mod, {fe1, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-3.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-3.1/ebin/fe.app index 0696e2494c..682d40eb12 100644 --- a/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-3.1/ebin/fe.app +++ b/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-3.1/ebin/fe.app @@ -1,7 +1,7 @@ {application, fe, [{description, "ERICSSON NR FOR FE"}, {vsn, "3.1"}, - {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {modules, [fe1, fe2, fe3]}, {registered, []}, {applications, []}, {mod, {fe1, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/ebin/db.app b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/ebin/db.app index 191919f8d3..a1025c306a 100644 --- a/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/ebin/db.app +++ b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/ebin/db.app @@ -1,7 +1,7 @@ {application, db, [{description, "ERICSSON NR FOR DB"}, {vsn, "2.1"}, - {modules, [{db1, "1.0"}, {db2, "1.0"}]}, + {modules, [db1, db2]}, {registered, []}, {applications, []}, {env, []}, diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/ebin/fe.app index d3bd85cda6..33d44805bd 100644 --- a/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/ebin/fe.app +++ b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/ebin/fe.app @@ -1,7 +1,7 @@ {application, fe, [{description, "ERICSSON NR FOR FE"}, {vsn, "3.1"}, - {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {modules, [fe1, fe2, fe3]}, {registered, []}, {applications, []}, {env, []}, diff --git a/lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/ebin/db.app b/lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/ebin/db.app index 3e0ac3c3c9..28d0f80d34 100644 --- a/lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/ebin/db.app +++ b/lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/ebin/db.app @@ -1,7 +1,7 @@ {application, db, [{description, "ERICSSON NR FOR DB"}, {vsn, "2.1"}, - {modules, [{db1, "1.0"}, {db2, "1.0"}, {db3, "2.0"}]}, + {modules, [db1, db2, db3]}, {registered, []}, {applications, []}, {env, []}, diff --git a/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/ebin/db.app b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/ebin/db.app index 191919f8d3..a1025c306a 100644 --- a/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/ebin/db.app +++ b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/ebin/db.app @@ -1,7 +1,7 @@ {application, db, [{description, "ERICSSON NR FOR DB"}, {vsn, "2.1"}, - {modules, [{db1, "1.0"}, {db2, "1.0"}]}, + {modules, [db1, db2]}, {registered, []}, {applications, []}, {env, []}, diff --git a/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/ebin/fe.app index d3bd85cda6..33d44805bd 100644 --- a/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/ebin/fe.app +++ b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/ebin/fe.app @@ -1,7 +1,7 @@ {application, fe, [{description, "ERICSSON NR FOR FE"}, {vsn, "3.1"}, - {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {modules, [fe1, fe2, fe3]}, {registered, []}, {applications, []}, {env, []}, diff --git a/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-2.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-2.1/ebin/fe.app index 47ea248720..717d30cf45 100644 --- a/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-2.1/ebin/fe.app +++ b/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-2.1/ebin/fe.app @@ -1,7 +1,7 @@ {application, fe, [{description, "ERICSSON NR FOR FE"}, {vsn, "2.1"}, - {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {modules, [fe1, fe2, fe3]}, {registered, []}, {applications, []}, {env, []}, diff --git a/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-3.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-3.1/ebin/fe.app index 0696e2494c..682d40eb12 100644 --- a/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-3.1/ebin/fe.app +++ b/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-3.1/ebin/fe.app @@ -1,7 +1,7 @@ {application, fe, [{description, "ERICSSON NR FOR FE"}, {vsn, "3.1"}, - {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {modules, [fe1, fe2, fe3]}, {registered, []}, {applications, []}, {mod, {fe1, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-500.18.7/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-500.18.7/ebin/fe.app index 3a5c0ddd9b..77b97979cb 100644 --- a/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-500.18.7/ebin/fe.app +++ b/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-500.18.7/ebin/fe.app @@ -1,7 +1,7 @@ {application, fe, [{description, "ERICSSON NR FOR FE"}, {vsn, "500.18.7"}, - {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {modules, [fe1, fe2, fe3]}, {registered, []}, {applications, []}, {mod, {fe1, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.0/ebin/db.app b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.0/ebin/db.app index 22530ee335..3968ce3c32 100644 --- a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.0/ebin/db.app +++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.0/ebin/db.app @@ -1,7 +1,7 @@ {application, db, [{description, "ERICSSON NR FOR DB"}, {vsn, "1.0"}, - {modules, [{db1, "1.0"}, {db2, "1.0"}]}, + {modules, [db1, db2]}, {registered, []}, {applications, []}, {env, []}, diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.1/ebin/db.app b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.1/ebin/db.app index 7243a0a96a..0f0c926fbd 100644 --- a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.1/ebin/db.app +++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.1/ebin/db.app @@ -1,7 +1,7 @@ {application, db, [{description, "ERICSSON NR FOR DB"}, {vsn, "1.1"}, - {modules, [{db1, "1.0"}, {db2, "1.0"}]}, + {modules, [db1, db2]}, {registered, []}, {applications, []}, {env, []}, diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/ebin/db.app b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/ebin/db.app index 202d7f1234..6901d225e2 100644 --- a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/ebin/db.app +++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/ebin/db.app @@ -1,7 +1,7 @@ {application, db, [{description, "ERICSSON NR FOR DB"}, {vsn, "2.1"}, - {modules, [{db1, "1.0"}, {db2, "1.0"}]}, + {modules, [db1, db2]}, {registered, []}, {applications, []}, {mod, {db1, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1.1/ebin/fe.app index c7ba1dfe91..d963a7e7fa 100644 --- a/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1.1/ebin/fe.app +++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1.1/ebin/fe.app @@ -1,7 +1,7 @@ {application, fe, [{description, "ERICSSON NR FOR FE"}, {vsn, "2.1.1"}, - {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {modules, [fe1, fe2, fe3]}, {registered, []}, {applications, []}, {env, []}, diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1/ebin/fe.app index 47ea248720..717d30cf45 100644 --- a/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1/ebin/fe.app +++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1/ebin/fe.app @@ -1,7 +1,7 @@ {application, fe, [{description, "ERICSSON NR FOR FE"}, {vsn, "2.1"}, - {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {modules, [fe1, fe2, fe3]}, {registered, []}, {applications, []}, {env, []}, diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/ebin/fe.app index 0696e2494c..682d40eb12 100644 --- a/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/ebin/fe.app +++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/ebin/fe.app @@ -1,7 +1,7 @@ {application, fe, [{description, "ERICSSON NR FOR FE"}, {vsn, "3.1"}, - {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {modules, [fe1, fe2, fe3]}, {registered, []}, {applications, []}, {mod, {fe1, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1.1/ebin/fe.app index c7ba1dfe91..d963a7e7fa 100644 --- a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1.1/ebin/fe.app +++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1.1/ebin/fe.app @@ -1,7 +1,7 @@ {application, fe, [{description, "ERICSSON NR FOR FE"}, {vsn, "2.1.1"}, - {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {modules, [fe1, fe2, fe3]}, {registered, []}, {applications, []}, {env, []}, diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1/ebin/fe.app index 47ea248720..717d30cf45 100644 --- a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1/ebin/fe.app +++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1/ebin/fe.app @@ -1,7 +1,7 @@ {application, fe, [{description, "ERICSSON NR FOR FE"}, {vsn, "2.1"}, - {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {modules, [fe1, fe2, fe3]}, {registered, []}, {applications, []}, {env, []}, diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.app index 0696e2494c..682d40eb12 100644 --- a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.app +++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.app @@ -1,7 +1,7 @@ {application, fe, [{description, "ERICSSON NR FOR FE"}, {vsn, "3.1"}, - {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {modules, [fe1, fe2, fe3]}, {registered, []}, {applications, []}, {mod, {fe1, []}}]}. diff --git a/lib/sasl/test/systools_rc_SUITE.erl b/lib/sasl/test/systools_rc_SUITE.erl index bd4aa9e7a7..0cb6e63cf3 100644 --- a/lib/sasl/test/systools_rc_SUITE.erl +++ b/lib/sasl/test/systools_rc_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% Copyright Ericsson AB 2010-2012. 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 @@ -46,7 +46,7 @@ syntax_check(Config) when is_list(Config) -> [#application{name = test, description = "TEST", vsn = "0.1", - modules = [{foo,1},{bar,1},{baz,1},{old_mod,1}], + modules = [foo,bar,baz,old_mod], regs = [], mod = {sasl, []}}, #application{name = snmp, @@ -59,7 +59,7 @@ syntax_check(Config) when is_list(Config) -> [#application{name = test, description = "TEST", vsn = "1.0", - modules = [{foo,1},{bar,1},{baz,1},{new_mod,1}], + modules = [foo,bar,baz,new_mod], regs = [], mod = {sasl, []}}], S1 = [ @@ -128,8 +128,8 @@ translate(Config) when is_list(Config) -> [#application{name = test, description = "TEST", vsn = "1.0", - modules = [{foo,1},{bar,1},{baz,1}, - {x,1},{y,1},{z,1}], + modules = [foo,bar,baz, + x,y,z], regs = [], mod = {sasl, []}}], %% Simple translation (1) @@ -439,7 +439,7 @@ translate_app(Config) when is_list(Config) -> [#application{name = test, description = "TEST", vsn = "1.0", - modules = [{foo,1},{bar,1},{baz,1}], + modules = [foo,bar,baz], regs = [], mod = {sasl, []}}, #application{name = pelle, @@ -452,7 +452,7 @@ translate_app(Config) when is_list(Config) -> [#application{name = test, description = "TEST", vsn = "1.0", - modules = [{foo,1},{bar,1},{baz,1}], + modules = [foo,bar,baz], regs = [], mod = {sasl, []}}], %% Simple translation (1) @@ -492,13 +492,13 @@ translate_emulator_restarts(_Config) -> [#application{name = test, description = "TEST", vsn = "1.0", - modules = [{foo,1},{bar,1},{baz,1}], + modules = [foo,bar,baz], regs = [], mod = {sasl, []}}, #application{name = test, description = "TEST2", vsn = "1.0", - modules = [{x,1},{y,1},{z,1}], + modules = [x,y,z], regs = [], mod = {sasl, []}}], %% restart_new_emulator diff --git a/lib/stdlib/doc/src/filelib.xml b/lib/stdlib/doc/src/filelib.xml index f3079c7337..cec20aee8e 100644 --- a/lib/stdlib/doc/src/filelib.xml +++ b/lib/stdlib/doc/src/filelib.xml @@ -150,6 +150,11 @@ <p>Matches any number of characters up to the end of the filename, the next dot, or the next slash.</p> </item> + <tag>**</tag> + <item> + <p>Two adjacent <c>*</c>'s used as a single pattern will + match all files and zero or more directories and subdirectories.</p> + </item> <tag>[Character1,Character2,...]</tag> <item> <p>Matches any of the characters listed. Two characters @@ -192,6 +197,10 @@ <c>src</c> or <c>include</c> directories, use:</p> <code type="none"> filelib:wildcard("lib/*/{src,include}/*.{erl,hrl}") </code> + <p>To find all <c>.erl</c> or <c>.hrl</c> files in any + subdirectory, use:</p> + <code type="none"> + filelib:wildcard("lib/**/*.{erl,hrl}") </code> </desc> </func> <func> diff --git a/lib/stdlib/src/filelib.erl b/lib/stdlib/src/filelib.erl index fa4f92617c..318f3b87b8 100644 --- a/lib/stdlib/src/filelib.erl +++ b/lib/stdlib/src/filelib.erl @@ -132,6 +132,8 @@ do_wildcard_comp({compiled_wildcard,{exists,File}}, Mod) -> {ok,_} -> [File]; _ -> [] end; +do_wildcard_comp({compiled_wildcard,[cwd,Base|Rest]}, Mod) -> + do_wildcard_1([Base], Rest, Mod); do_wildcard_comp({compiled_wildcard,[Base|Rest]}, Mod) -> do_wildcard_1([Base], Rest, Mod). @@ -143,7 +145,11 @@ do_wildcard_comp({compiled_wildcard,{exists,File}}, Cwd, Mod) -> {ok,_} -> [File]; _ -> [] end; -do_wildcard_comp({compiled_wildcard,[current|Rest]}, Cwd0, Mod) -> +do_wildcard_comp({compiled_wildcard,[cwd|Rest0]}, Cwd0, Mod) -> + case Rest0 of + [current|Rest] -> ok; + Rest -> ok + end, {Cwd,PrefixLen} = case filename:join([Cwd0]) of Bin when is_binary(Bin) -> {Bin,byte_size(Bin)+1}; Other -> {Other,length(Other)+1} @@ -295,6 +301,8 @@ do_wildcard_2([File|Rest], Pattern, Result, Mod) -> do_wildcard_2([], _, Result, _Mod) -> Result. +do_wildcard_3(Base, [[double_star]|Rest], Result, Mod) -> + lists:sort(do_double_star(current, [Base], Rest, Result, Mod, true)); do_wildcard_3(Base, [Pattern|Rest], Result, Mod) -> case do_list_dir(Base, Mod) of {ok, Files0} -> @@ -328,6 +336,8 @@ wildcard_5([question|Rest1], [_|Rest2]) -> wildcard_5(Rest1, Rest2); wildcard_5([accept], _) -> true; +wildcard_5([double_star], _) -> + true; wildcard_5([star|Rest], File) -> do_star(Rest, File); wildcard_5([{one_of, Ordset}|Rest], [C|File]) -> @@ -348,6 +358,21 @@ wildcard_5([], [_|_]) -> wildcard_5([_|_], []) -> false. +do_double_star(Base, [H|T], Rest, Result, Mod, Root) -> + Full = join(Base, H), + Result1 = case do_list_dir(Full, Mod) of + {ok, Files} -> + do_double_star(Full, Files, Rest, Result, Mod, false); + _ -> Result + end, + Result2 = case Root andalso Rest == [] of + true -> Result1; + false -> do_wildcard_3(Full, Rest, Result1, Mod) + end, + do_double_star(Base, T, Rest, Result2, Mod, Root); +do_double_star(_Base, [], _Rest, Result, _Mod, _Root) -> + Result. + do_star(Pattern, [X|Rest]) -> case wildcard_5(Pattern, [X|Rest]) of true -> true; @@ -383,7 +408,10 @@ compile_wildcard_1(Pattern) -> [Root|Rest] = filename:split(Pattern), case filename:pathtype(Root) of relative -> - compile_wildcard_2([Root|Rest], current); + case compile_wildcard_2([Root|Rest], current) of + {exists,_}=Wc -> Wc; + [_|_]=Wc -> [cwd|Wc] + end; _ -> compile_wildcard_2(Rest, [Root]) end. @@ -416,6 +444,10 @@ compile_part([$}|Rest], true, Result) -> {ok, $}, lists:reverse(Result), Rest}; compile_part([$?|Rest], Upto, Result) -> compile_part(Rest, Upto, [question|Result]); +compile_part([$*,$*], Upto, Result) -> + compile_part([], Upto, [double_star|Result]); +compile_part([$*,$*|Rest], Upto, Result) -> + compile_part(Rest, Upto, [star|Result]); compile_part([$*], Upto, Result) -> compile_part([], Upto, [accept|Result]); compile_part([$*|Rest], Upto, Result) -> diff --git a/lib/stdlib/test/filelib_SUITE.erl b/lib/stdlib/test/filelib_SUITE.erl index 1de639a166..1fd7518519 100644 --- a/lib/stdlib/test/filelib_SUITE.erl +++ b/lib/stdlib/test/filelib_SUITE.erl @@ -176,9 +176,64 @@ do_wildcard_5(Dir, Wcf) -> %% Cleanup ?line del(Files), - ?line foreach(fun(D) -> ok = file:del_dir(filename:join(Dir, D)) end, Dirs). + ?line foreach(fun(D) -> ok = file:del_dir(filename:join(Dir, D)) end, Dirs), + do_wildcard_6(Dir, Wcf). + +do_wildcard_6(Dir, Wcf) -> + ok = file:make_dir(filename:join(Dir, "xbin")), + All = ["xbin/a.x","xbin/b.x","xbin/c.x"], + Files = mkfiles(All, Dir), + All = Wcf("xbin/*.x"), + All = Wcf("xbin/*"), + ["xbin"] = Wcf("*"), + All = Wcf("*/*"), + del(Files), + ok = file:del_dir(filename:join(Dir, "xbin")), + do_wildcard_7(Dir, Wcf). + +do_wildcard_7(Dir, Wcf) -> + Dirs = ["blurf","xa","yyy"], + SubDirs = ["blurf/nisse"], + foreach(fun(D) -> + ok = file:make_dir(filename:join(Dir, D)) + end, Dirs ++ SubDirs), + All = ["blurf/nisse/baz","xa/arne","xa/kalle","yyy/arne"], + Files = mkfiles(lists:reverse(All), Dir), + %% Test. + Listing = Wcf("**"), + ["blurf","blurf/nisse","blurf/nisse/baz", + "xa","xa/arne","xa/kalle","yyy","yyy/arne"] = Listing, + Listing = Wcf("**/*"), + ["xa/arne","yyy/arne"] = Wcf("**/arne"), + ["blurf/nisse"] = Wcf("**/nisse"), + [] = Wcf("mountain/**"), + + %% Cleanup + del(Files), + foreach(fun(D) -> + ok = file:del_dir(filename:join(Dir, D)) + end, SubDirs ++ Dirs), + do_wildcard_8(Dir, Wcf). + +do_wildcard_8(Dir, Wcf) -> + Dirs0 = ["blurf"], + Dirs1 = ["blurf/nisse"], + Dirs2 = ["blurf/nisse/a", "blurf/nisse/b"], + foreach(fun(D) -> + ok = file:make_dir(filename:join(Dir, D)) + end, Dirs0 ++ Dirs1 ++ Dirs2), + All = ["blurf/nisse/a/1.txt", "blurf/nisse/b/2.txt", "blurf/nisse/b/3.txt"], + Files = mkfiles(lists:reverse(All), Dir), + %% Test. + All = Wcf("**/blurf/**/*.txt"), + + %% Cleanup + del(Files), + foreach(fun(D) -> + ok = file:del_dir(filename:join(Dir, D)) + end, Dirs2 ++ Dirs1 ++ Dirs0). fold_files(Config) when is_list(Config) -> ?line Dir = filename:join(?config(priv_dir, Config), "fold_files"), diff --git a/lib/test_server/doc/src/ts.xml b/lib/test_server/doc/src/ts.xml index 7a356755ba..4a2c536e96 100644 --- a/lib/test_server/doc/src/ts.xml +++ b/lib/test_server/doc/src/ts.xml @@ -498,29 +498,6 @@ This option is mandatory for remote targets </desc> </func> <func> - <name>index() -> ok | {error, Reason}</name> - <fsummary>Updates local index page</fsummary> - <type> - <v>Reason = term()</v> - </type> - <desc> - <p>This function updates the local index page. This can be - useful if a previous test run was not completed and the index - is incomplete.</p> - </desc> - </func> - <func> - <name>clean() -> ok</name> - <name>clean(all) -> ok</name> - <fsummary>Cleans up the log directories created when running tests. </fsummary> - <desc> - <p>This function cleans up log directories created when - running test cases. <c>clean/0</c> cleans up all but the last - run of each application. <c>clean/1</c> cleans up all test - runs found.</p> - </desc> - </func> - <func> <name>estone() -> ok | {error, Reason}</name> <name>estone(Opts) -> ok</name> <fsummary>Runs the EStone test</fsummary> diff --git a/lib/test_server/src/Makefile b/lib/test_server/src/Makefile index ada9bac05a..bb0b4e55b8 100644 --- a/lib/test_server/src/Makefile +++ b/lib/test_server/src/Makefile @@ -49,7 +49,6 @@ MODULES= test_server_ctrl \ TS_MODULES= \ ts \ ts_run \ - ts_reports \ ts_lib \ ts_make \ ts_erl_config \ diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl index a38e2be98e..f7266e5632 100644 --- a/lib/test_server/src/test_server_ctrl.erl +++ b/lib/test_server/src/test_server_ctrl.erl @@ -1410,13 +1410,14 @@ init_tester(Mod, Func, Args, Dir, Name, {SumLev,MajLev,MinLev}, RejectIoReqs, StartedExtraTools = start_extra_tools(ExtraTools), {TimeMy,Result} = ts_tc(Mod, Func, Args), put(test_server_common_io_handler, undefined), - stop_extra_tools(StartedExtraTools), + catch stop_extra_tools(StartedExtraTools), case Result of {'EXIT',test_suites_done} -> print(25, "DONE, normal exit", []); {'EXIT',_Pid,Reason} -> print(1, "EXIT, reason ~p", [Reason]); {'EXIT',Reason} -> + report_severe_error(Reason), print(1, "EXIT, reason ~p", [Reason]); _Other -> print(25, "DONE", []) @@ -1440,6 +1441,9 @@ init_tester(Mod, Func, Args, Dir, Name, {SumLev,MajLev,MinLev}, RejectIoReqs, "</tfoot>\n", [Time,SuccessStr,OkN,FailedN,SkipStr,OkN+FailedN+SkippedN]). +report_severe_error(Reason) -> + test_server_sup:framework_call(report, [severe_error,Reason]). + %% timer:tc/3 ts_tc(M, F, A) -> Before = ?now, @@ -1873,7 +1877,7 @@ start_log_file() -> {error, eexist} -> ok; MkDirError -> - exit({cant_create_log_dir,{MkDirError,Dir}}) + log_file_error(MkDirError, Dir) end, TestDir = timestamp_filename_get(filename:join(Dir, "run.")), TestDir1 = @@ -1888,10 +1892,10 @@ start_log_file() -> ok -> TestDirX; MkDirError2 -> - exit({cant_create_log_dir,{MkDirError2,TestDirX}}) + log_file_error(MkDirError2, TestDirX) end; MkDirError2 -> - exit({cant_create_log_dir,{MkDirError2,TestDir}}) + log_file_error(MkDirError2, TestDir) end, ok = file:write_file(filename:join(Dir, ?last_file), TestDir1 ++ "\n"), ok = file:write_file(?last_file, TestDir1 ++ "\n"), @@ -1918,6 +1922,9 @@ start_log_file() -> test_server_sup:framework_call(report, [loginfo,LogInfo]), {ok,TestDir1}. +log_file_error(Error, Dir) -> + exit({cannot_create_log_dir,{Error,lists:flatten(Dir)}}). + make_html_link(LinkName, Target, Explanation) -> %% if possible use a relative reference to Target. TargetL = filename:split(Target), diff --git a/lib/test_server/src/ts.erl b/lib/test_server/src/ts.erl index a30f6c65fe..db16b6ecd2 100644 --- a/lib/test_server/src/ts.erl +++ b/lib/test_server/src/ts.erl @@ -25,9 +25,8 @@ -module(ts). -export([run/0, run/1, run/2, run/3, run/4, - clean/0, clean/1, tests/0, tests/1, - install/0, install/1, index/0, + install/0, install/1, bench/0, bench/1, bench/2, benchmarks/0, estone/0, estone/1, cross_cover_analyse/1, @@ -42,17 +41,11 @@ %%% %%% +-- ts_install --+------ ts_autoconf_win32 %%% | -%%% | -%%% | %%% ts ---+ +------ ts_erl_config %%% | | ts_lib -%%% | +------ ts_make -%%% | | -%%% +-- ts_run -----+ +%%% +-- ts_run -----+------ ts_make %%% | | ts_filelib %%% | +------ ts_make_erl -%%% | | -%%% | +------ ts_reports (indirectly) %%% | %%% +-- ts_benchmark %%% @@ -77,8 +70,6 @@ %%% and other platforms. %%% ts_make_erl A corrected version of the standar Erlang module %%% make (used for rebuilding test suites). -%%% ts_reports Generates index pages in HTML, providing a summary -%%% of the tests run. %%% ts_lib Miscellanous utility functions, each used by several %%% other modules. %%% ts_benchmark Supervises otp benchmarks and collects results. @@ -163,9 +154,6 @@ help(installed) -> " ts:tests() - Shows all available families of tests.\n", " ts:tests(Spec) - Shows all available test modules in Spec,\n", " i.e. ../Spec_test/*_SUITE.erl\n", - " ts:index() - Updates local index page.\n", - " ts:clean() - Cleans up all but the last tests run.\n", - " ts:clean(all) - Cleans up all test runs found.\n", " ts:estone() - Run estone_SUITE in kernel application with\n" " no run options\n", " ts:estone(Opts) - Run estone_SUITE in kernel application with\n" @@ -201,33 +189,6 @@ install() -> install(Options) when is_list(Options) -> ts_install:install(install_local,Options). -%% Updates the local index page. - -index() -> - check_and_run(fun(_Vars) -> ts_reports:make_index(), ok end). - -%% -%% clean(all) -%% Deletes all logfiles. -%% -clean(all) -> - delete_files(filelib:wildcard("*" ++ ?logdir_ext)). - -%% clean/0 -%% -%% Cleans up run logfiles, all but the last run. -clean() -> - clean1(filelib:wildcard("*" ++ ?logdir_ext)). - -clean1([Dir|Dirs]) -> - List0 = filelib:wildcard(filename:join(Dir, "run.*")), - case lists:reverse(lists:sort(List0)) of - [] -> ok; - [_Last|Rest] -> delete_files(Rest) - end, - clean1(Dirs); -clean1([]) -> ok. - %% run/0 %% Runs all specs found by ts:tests(), if any, or returns %% {error, no_tests_available}. (batch) @@ -579,32 +540,6 @@ run_test(File, Args, Options) -> run_test(File, Args, Options, Vars) -> ts_run:run(File, Args, Options, Vars). - -delete_files([]) -> ok; -delete_files([Item|Rest]) -> - case file:delete(Item) of - ok -> - delete_files(Rest); - {error,eperm} -> - file:change_mode(Item, 8#777), - delete_files(filelib:wildcard(filename:join(Item, "*"))), - file:del_dir(Item), - ok; - {error,eacces} -> - %% We'll see about that! - file:change_mode(Item, 8#777), - case file:delete(Item) of - ok -> ok; - {error,_} -> - erlang:yield(), - file:change_mode(Item, 8#777), - file:delete(Item), - ok - end; - {error,_} -> ok - end, - delete_files(Rest). - %% This module provides some convenient shortcuts to running %% the test server from within a started Erlang shell. diff --git a/lib/test_server/src/ts_lib.erl b/lib/test_server/src/ts_lib.erl index 3dce19ed65..d9a699ca9f 100644 --- a/lib/test_server/src/ts_lib.erl +++ b/lib/test_server/src/ts_lib.erl @@ -25,9 +25,8 @@ -compile({no_auto_import,[error/1]}). -export([error/1, var/2, erlang_type/0, erlang_type/1, - initial_capital/1, interesting_logs/1, - specs/1, suites/2, last_test/1, - force_write_file/2, force_delete/1, + initial_capital/1, + specs/1, suites/2, subst_file/3, subst/2, print_data/1, make_non_erlang/2, maybe_atom_to_list/1, progress/4 @@ -91,21 +90,6 @@ initial_capital([C|Rest]) when $a =< C, C =< $z -> initial_capital(String) -> String. -%% Returns a list of the "interesting logs" in a directory, -%% i.e. those that correspond to spec files. - -interesting_logs(Dir) -> - Logs = filelib:wildcard(filename:join(Dir, [$*|?logdir_ext])), - Interesting = - case specs(Dir) of - [] -> - Logs; - Specs0 -> - Specs = ordsets:from_list(Specs0), - [L || L <- Logs, ordsets:is_element(filename_to_atom(L), Specs)] - end, - sort_tests(Interesting). - specs(Dir) -> Specs = filelib:wildcard(filename:join([filename:dirname(Dir), "*_test", "*.{dyn,}spec"])), @@ -165,42 +149,6 @@ suite_order(mnesia) -> 44; suite_order(system) -> 999; %% IMPORTANT: system SHOULD always be last! suite_order(_) -> 200. -last_test(Dir) -> - last_test(filelib:wildcard(filename:join(Dir, "run.[1-2]*")), false). - -last_test([Run|Rest], false) -> - last_test(Rest, Run); -last_test([Run|Rest], Latest) when Run > Latest -> - last_test(Rest, Run); -last_test([_|Rest], Latest) -> - last_test(Rest, Latest); -last_test([], Latest) -> - Latest. - -%% Do the utmost to ensure that the file is written, by deleting or -%% renaming an old file with the same name. - -force_write_file(Name, Contents) -> - force_delete(Name), - file:write_file(Name, Contents). - -force_delete(Name) -> - case file:delete(Name) of - {error, eacces} -> - force_rename(Name, Name ++ ".old.", 0); - Other -> - Other - end. - -force_rename(From, To, Number) -> - Dest = [To|integer_to_list(Number)], - case file:read_file_info(Dest) of - {ok, _} -> - force_rename(From, To, Number+1); - {error, _} -> - file:rename(From, Dest) - end. - %% Substitute all occurrences of @var@ in the In file, using %% the list of variables in Vars, producing the output file Out. %% Returns: ok | {error, Reason} diff --git a/lib/test_server/src/ts_reports.erl b/lib/test_server/src/ts_reports.erl deleted file mode 100644 index f981a77ae4..0000000000 --- a/lib/test_server/src/ts_reports.erl +++ /dev/null @@ -1,545 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-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% -%% - -%%% Purpose : Produces reports in HTML from the outcome of test suite runs. - --module(ts_reports). - --export([make_index/0, make_master_index/2, make_progress_index/2]). --export([count_cases/1, year/0, current_time/0]). - --include_lib("kernel/include/file.hrl"). --include("ts.hrl"). - --compile({no_auto_import,[error/1]}). - --import(filename, [basename/1, rootname/1]). --import(ts_lib, [error/1]). - - -%% Make master index page which points out index pages for all platforms. - -make_master_index(Dir, Vars) -> - IndexName = filename:join(Dir, "index.html"), - {ok, Index0} = make_master_index1(directories(Dir), master_header(Vars)), - Index = [Index0|master_footer()], - io:put_chars("Updating " ++ IndexName ++ "... "), - ok = ts_lib:force_write_file(IndexName, Index), - io:put_chars("done\n"). - -make_master_index1([Dir|Rest], Result) -> - NewResult = - case catch read_variables(Dir) of - {'EXIT',{{bad_installation,Reason},_}} -> - io:put_chars("Failed to read " ++ filename:join(Dir,?variables)++ - ": " ++ Reason ++ " - Ignoring this directory\n"), - Result; - Vars -> - Platform = ts_lib:var(platform_label, Vars), - case make_index(Dir, Vars, false) of - {ok, Summary} -> - make_master_index(Platform, Dir, Summary, Result); - {error, _} -> - Result - end - end, - make_master_index1(Rest, NewResult); -make_master_index1([], Result) -> - {ok, Result}. - -make_progress_index(Dir, Vars) -> - IndexName = filename:join(Dir, "index.html"), - io:put_chars("Updating " ++ IndexName ++ "... "), - Index0=progress_header(Vars), - ts_lib:force_delete(IndexName), - Dirs=find_progress_runs(Dir), - Index1=[Index0|make_progress_links(Dirs, [])], - IndexF=[Index1|progress_footer()], - ok = ts_lib:force_write_file(IndexName, IndexF), - io:put_chars("done\n"). - -find_progress_runs(Dir) -> - case file:list_dir(Dir) of - {ok, Dirs0} -> - Dirs1= [filename:join(Dir,X) || X <- Dirs0, - filelib:is_dir(filename:join(Dir,X))], - lists:sort(Dirs1); - _ -> - [] - end. - -name_from_vars(Dir, Platform) -> - VarFile=filename:join([Dir, Platform, "variables"]), - case file:consult(VarFile) of - {ok, Vars} -> - ts_lib:var(platform_id, Vars); - _Other -> - Platform - end. - -make_progress_links([], Acc) -> - Acc; -make_progress_links([RDir|Rest], Acc) -> - Dir=filename:basename(RDir), - Platforms=[filename:basename(X) || - X <- find_progress_runs(RDir)], - PlatformLinks=["<A HREF=\""++filename:join([Dir,X,"index.html"]) - ++"\">"++name_from_vars(RDir, X)++"</A><BR>" || - X <- Platforms], - LinkName=Dir++"/index.html", - Link = - [ - "<TR valign=top>\n", - "<TD><A HREF=\"", LinkName, "\">", Dir, "</A></TD>", "\n", - "<TD>", PlatformLinks, "</TD>", "\n" - ], - make_progress_links(Rest, [Link|Acc]). - -read_variables(Dir) -> - case file:consult(filename:join(Dir, ?variables)) of - {ok, Vars} -> Vars; - {error, Reason} -> - erlang:error({bad_installation,file:format_error(Reason)}, [Dir]) - end. - -make_master_index(Platform, Dirname, {Succ, Fail, UserSkip,AutoSkip}, Result) -> - Link = filename:join(filename:basename(Dirname), "index.html"), - FailStr = - if Fail > 0 -> - ["<FONT color=\"red\">", - integer_to_list(Fail),"</FONT>"]; - true -> - integer_to_list(Fail) - end, - AutoSkipStr = - if AutoSkip > 0 -> - ["<FONT color=\"brown\">", - integer_to_list(AutoSkip),"</FONT>"]; - true -> integer_to_list(AutoSkip) - end, - [Result, - "<TR valign=top>\n", - "<TD><A HREF=\"", Link, "\">", Platform, "</A></TD>", "\n", - make_row(integer_to_list(Succ), false), - make_row(FailStr, false), - make_row(integer_to_list(UserSkip), false), - make_row(AutoSkipStr, false), - "</TR>\n"]. - -%% Make index page which points out individual test suites for a single platform. - -make_index() -> - {ok, Pwd} = file:get_cwd(), - Vars = read_variables(Pwd), - make_index(Pwd, Vars, true). - -make_index(Dir, Vars, IncludeLast) -> - IndexName = filename:absname("index.html", Dir), - io:put_chars("Updating " ++ IndexName ++ "... "), - case catch make_index1(Dir, IndexName, Vars, IncludeLast) of - {'EXIT', Reason} -> - io:put_chars("CRASHED!\n"), - io:format("~p~n", [Reason]), - {error, Reason}; - {error, Reason} -> - io:put_chars("FAILED\n"), - io:format("~p~n", [Reason]), - {error, Reason}; - {ok, Summary} -> - io:put_chars("done\n"), - {ok, Summary}; - Err -> - io:format("Unknown internal error. Please report.\n(Err: ~p, ID: 1)", - [Err]), - {error, Err} - end. - -make_index1(Dir, IndexName, Vars, IncludeLast) -> - Logs0 = ts_lib:interesting_logs(Dir), - Logs = - case IncludeLast of - true -> add_last_name(Logs0); - false -> Logs0 - end, - {ok, {Index0, Summary}} = make_index(Logs, header(Vars), 0, 0, 0, 0, 0), - Index = [Index0|footer()], - case ts_lib:force_write_file(IndexName, Index) of - ok -> - {ok, Summary}; - {error, Reason} -> - error({index_write_error, Reason}) - end. - -make_index([Name|Rest], Result, TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt) -> - case ts_lib:last_test(Name) of - false -> - %% Silently skip. - make_index(Rest, Result, TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt); - Last -> - case count_cases(Last) of - {Succ, Fail, USkip, ASkip} -> - Cov = - case file:read_file(filename:join(Last,?cover_total)) of - {ok,Bin} -> - TotCoverage = binary_to_term(Bin), - io_lib:format("~w %",[TotCoverage]); - _error -> - "" - end, - Link = filename:join(basename(Name), basename(Last)), - JustTheName = rootname(basename(Name)), - NotBuilt = not_built(JustTheName), - NewResult = [Result, make_index1(JustTheName, - Link, Succ, Fail, USkip, ASkip, - NotBuilt, Cov, false)], - make_index(Rest, NewResult, TotSucc+Succ, TotFail+Fail, - UserSkip+USkip, AutoSkip+ASkip, TotNotBuilt+NotBuilt); - error -> - make_index(Rest, Result, TotSucc, TotFail, UserSkip, AutoSkip, - TotNotBuilt) - end - end; -make_index([], Result, TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt) -> - {ok, {[Result|make_index1("Total", no_link, - TotSucc, TotFail, UserSkip, AutoSkip, - TotNotBuilt, "", true)], - {TotSucc, TotFail, UserSkip, AutoSkip}}}. - -make_index1(SuiteName, Link, Success, Fail, UserSkip, AutoSkip, NotBuilt, Coverage, Bold) -> - Name = test_suite_name(SuiteName), - FailStr = - if Fail > 0 -> - ["<FONT color=\"red\">", - integer_to_list(Fail),"</FONT>"]; - true -> - integer_to_list(Fail) - end, - AutoSkipStr = - if AutoSkip > 0 -> - ["<FONT color=\"brown\">", - integer_to_list(AutoSkip),"</FONT>"]; - true -> integer_to_list(AutoSkip) - end, - ["<TR valign=top>\n", - "<TD>", - case Link of - no_link -> - ["<B>", Name|"</B>"]; - _Other -> - CrashDumpName = SuiteName ++ "_erl_crash.dump", - CrashDumpLink = - case filelib:is_file(CrashDumpName) of - true -> - [" <A HREF=\"", CrashDumpName, - "\">(CrashDump)</A>"]; - false -> - "" - end, - LogFile = filename:join(Link, ?suitelog_name ++ ".html"), - ["<A HREF=\"", LogFile, "\">", Name, "</A>\n", CrashDumpLink, - "</TD>\n"] - end, - make_row(integer_to_list(Success), Bold), - make_row(FailStr, Bold), - make_row(integer_to_list(UserSkip), Bold), - make_row(AutoSkipStr, Bold), - make_row(integer_to_list(NotBuilt), Bold), - make_row(Coverage, Bold), - "</TR>\n"]. - -make_row(Row, true) -> - ["<TD ALIGN=right><B>", Row|"</B></TD>"]; -make_row(Row, false) -> - ["<TD ALIGN=right>", Row|"</TD>"]. - -not_built(BaseName) -> - Dir = filename:join("..", BaseName++"_test"), - Erl = length(filelib:wildcard(filename:join(Dir,"*_SUITE.erl"))), - Beam = length(filelib:wildcard(filename:join(Dir,"*_SUITE.beam"))), - Erl-Beam. - - -%% Add the log file directory for the very last test run (according to -%% last_name). - -add_last_name(Logs) -> - case file:read_file("last_name") of - {ok, Bin} -> - Name = filename:dirname(lib:nonl(binary_to_list(Bin))), - case lists:member(Name, Logs) of - true -> Logs; - false -> [Name|Logs] - end; - _ -> - Logs - end. - -term_to_text(Term) -> - lists:flatten(io_lib:format("~p.\n", [Term])). - -test_suite_name(Name) -> - ts_lib:initial_capital(Name) ++ " suite". - -directories(Dir) -> - {ok, Files} = file:list_dir(Dir), - [filename:join(Dir, X) || X <- Files, - filelib:is_dir(filename:join(Dir, X))]. - - -%%% Headers and footers. - -header(Vars) -> - Platform = ts_lib:var(platform_id, Vars), - ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n" - "<!-- autogenerated by '"++atom_to_list(?MODULE)++"'. -->\n" - "<HTML>\n", - "<HEAD>\n", - "<TITLE>Test Results for ", Platform, "</TITLE>\n", - "</HEAD>\n", - - body_tag(), - - "<!-- ---- DOCUMENT TITLE ---- -->\n", - - "<CENTER>\n", - "<H1>Test Results for ", Platform, "</H1>\n", - "</CENTER>\n", - - "<!-- ---- CONTENT ---- -->\n", - "<CENTER>\n", - - "<TABLE border=3 cellpadding=5>\n", - "<th><B>Family</B></th>\n", - "<th>Successful</th>\n", - "<th>Failed</th>\n", - "<th>User Skipped</th>\n" - "<th>Auto Skipped</th>\n" - "<th>Missing Suites</th>\n" - "<th>Coverage</th>\n" - "\n"]. - -footer() -> - ["</TABLE>\n" - "</CENTER>\n" - "<P><CENTER>\n" - "<HR>\n" - "<P><FONT SIZE=-1>\n" - "Copyright © ", year(), - " <A HREF=\"http://erlang.ericsson.se\">Open Telecom Platform</A><BR>\n" - "Updated: <!date>", current_time(), "<!/date><BR>\n" - "</FONT>\n" - "</CENTER>\n" - "</body>\n" - "</HTML>\n"]. - -progress_header(Vars) -> - Release = ts_lib:var(erl_release, Vars), - ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n" - "<!-- autogenerated by '"++atom_to_list(?MODULE)++"'. -->\n" - "<HTML>\n", - "<HEAD>\n", - "<TITLE>", Release, " Progress Test Results</TITLE>\n", - "</HEAD>\n", - - body_tag(), - - "<!-- ---- DOCUMENT TITLE ---- -->\n", - - "<CENTER>\n", - "<H1>", Release, " Progress Test Results</H1>\n", - "<TABLE border=3 cellpadding=5>\n", - "<th><b>Test Run</b></th><th>Platforms</th>\n"]. - -progress_footer() -> - ["</TABLE>\n", - "</CENTER>\n", - "<P><CENTER>\n", - "<HR>\n", - "<P><FONT SIZE=-1>\n", - "Copyright © ", year(), - " <A HREF=\"http://erlang.ericsson.se\">Open Telecom Platform</A><BR>\n", - "Updated: <!date>", current_time(), "<!/date><BR>\n", - "</FONT>\n", - "</CENTER>\n", - "</body>\n", - "</HTML>\n"]. - -master_header(Vars) -> - Release = ts_lib:var(erl_release, Vars), - Vsn = erlang:system_info(version), - ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n" - "<!-- autogenerated by '"++atom_to_list(?MODULE)++"'. -->\n" - "<HTML>\n", - "<HEAD>\n", - "<TITLE>", Release, " Test Results (", Vsn, ")</TITLE>\n", - "</HEAD>\n", - - body_tag(), - - "<!-- ---- DOCUMENT TITLE ---- -->\n", - - "<CENTER>\n", - "<H1>", Release, " Test Results (", Vsn, ")</H1>\n", - "</CENTER>\n", - - "<!-- ---- CONTENT ---- -->\n", - - "<CENTER>\n", - - "<TABLE border=3 cellpadding=5>\n", - "<th><b>Platform</b></th>\n", - "<th>Successful</th>\n", - "<th>Failed</th>\n", - "<th>User Skipped</th>\n" - "<th>Auto Skipped</th>\n" - "\n"]. - -master_footer() -> - ["</TABLE>\n", - "</CENTER>\n", - "<P><CENTER>\n", - "<HR>\n", - "<P><FONT SIZE=-1>\n", - "Copyright © ", year(), - " <A HREF=\"http://erlang.ericsson.se\">Open Telecom Platform</A><BR>\n", - "Updated: <!date>", current_time(), "<!/date><BR>\n", - "</FONT>\n", - "</CENTER>\n", - "</body>\n", - "</HTML>\n"]. - -body_tag() -> - "<body bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\"" - "vlink=\"#800080\" alink=\"#FF0000\">". - -year() -> - {Y, _, _} = date(), - integer_to_list(Y). - -current_time() -> - {{Y, Mon, D}, {H, Min, S}} = calendar:local_time(), - Weekday = weekday(calendar:day_of_the_week(Y, Mon, D)), - lists:flatten(io_lib:format("~s ~s ~p ~2.2.0w:~2.2.0w:~2.2.0w ~w", - [Weekday, month(Mon), D, H, Min, S, Y])). - -weekday(1) -> "Mon"; -weekday(2) -> "Tue"; -weekday(3) -> "Wed"; -weekday(4) -> "Thu"; -weekday(5) -> "Fri"; -weekday(6) -> "Sat"; -weekday(7) -> "Sun". - -month(1) -> "Jan"; -month(2) -> "Feb"; -month(3) -> "Mar"; -month(4) -> "Apr"; -month(5) -> "May"; -month(6) -> "Jun"; -month(7) -> "Jul"; -month(8) -> "Aug"; -month(9) -> "Sep"; -month(10) -> "Oct"; -month(11) -> "Nov"; -month(12) -> "Dec". - -%% Count test cases in the given directory (a directory of the type -%% run.1997-08-04_09.58.52). - -count_cases(Dir) -> - SumFile = filename:join(Dir, ?run_summary), - case read_summary(SumFile, [summary]) of - {ok, [{Succ,Fail,Skip}]} -> - {Succ,Fail,Skip,0}; - {ok, [Summary]} -> - Summary; - {error, _} -> - LogFile = filename:join(Dir, ?suitelog_name), - case file:read_file(LogFile) of - {ok, Bin} -> - Summary = count_cases1(binary_to_list(Bin), {0, 0, 0, 0}), - write_summary(SumFile, Summary), - Summary; - {error, _Reason} -> - io:format("\nFailed to read ~p (skipped)\n", [LogFile]), - error - end - end. - -write_summary(Name, Summary) -> - File = [term_to_text({summary, Summary})], - ts_lib:force_write_file(Name, File). - -% XXX: This function doesn't do what the writer expect. It can't handle -% the case if there are several different keys and I had to add a special -% case for the empty file. The caller also expect just one tuple as -% a result so this function is written way to general for no reason. -% But it works sort of. /kgb - -read_summary(Name, Keys) -> - case file:consult(Name) of - {ok, []} -> - {error, "Empty summary file"}; - {ok, Terms} -> - {ok, lists:map(fun(Key) -> {value, {_, Value}} = - lists:keysearch(Key, 1, Terms), - Value end, - Keys)}; - {error, Reason} -> - {error, Reason} - end. - -count_cases1("=failed" ++ Rest, {Success, _Fail, UserSkip,AutoSkip}) -> - {NextLine, Count} = get_number(Rest), - count_cases1(NextLine, {Success, Count, UserSkip,AutoSkip}); -count_cases1("=successful" ++ Rest, {_Success, Fail, UserSkip,AutoSkip}) -> - {NextLine, Count} = get_number(Rest), - count_cases1(NextLine, {Count, Fail, UserSkip,AutoSkip}); -count_cases1("=skipped" ++ Rest, {Success, Fail, _UserSkip,AutoSkip}) -> - {NextLine, Count} = get_number(Rest), - count_cases1(NextLine, {Success, Fail, Count,AutoSkip}); -count_cases1("=user_skipped" ++ Rest, {Success, Fail, _UserSkip,AutoSkip}) -> - {NextLine, Count} = get_number(Rest), - count_cases1(NextLine, {Success, Fail, Count,AutoSkip}); -count_cases1("=auto_skipped" ++ Rest, {Success, Fail, UserSkip,_AutoSkip}) -> - {NextLine, Count} = get_number(Rest), - count_cases1(NextLine, {Success, Fail, UserSkip,Count}); -count_cases1([], Counters) -> - Counters; -count_cases1(Other, Counters) -> - count_cases1(skip_to_nl(Other), Counters). - -get_number([$\s|Rest]) -> - get_number(Rest); -get_number([Digit|Rest]) when $0 =< Digit, Digit =< $9 -> - get_number(Rest, Digit-$0). - -get_number([Digit|Rest], Acc) when $0 =< Digit, Digit =< $9 -> - get_number(Rest, Acc*10+Digit-$0); -get_number([$\n|Rest], Acc) -> - {Rest, Acc}; -get_number([_|Rest], Acc) -> - get_number(Rest, Acc). - -skip_to_nl([$\n|Rest]) -> - Rest; -skip_to_nl([_|Rest]) -> - skip_to_nl(Rest); -skip_to_nl([]) -> - []. diff --git a/lib/test_server/src/ts_run.erl b/lib/test_server/src/ts_run.erl index e108a22839..f4d5b3e3b1 100644 --- a/lib/test_server/src/ts_run.erl +++ b/lib/test_server/src/ts_run.erl @@ -21,7 +21,7 @@ -module(ts_run). --export([run/4]). +-export([run/4,ct_run_test/2]). -define(DEFAULT_MAKE_TIMETRAP_MINUTES, 60). -define(DEFAULT_UNMAKE_TIMETRAP_MINUTES, 15). @@ -87,6 +87,24 @@ execute([Hook|Rest], Vars0, Spec0, St0) -> execute([], Vars, Spec, St) -> {ok, Vars, Spec, St}. +%% Wrapper to run tests using ct:run_test/1 and handle any errors. + +ct_run_test(Dir, CommonTestArgs) -> + try + ok = file:set_cwd(Dir), + case ct:run_test(CommonTestArgs) of + {_,_,_} -> + ok; + {error,Error} -> + io:format("ERROR: ~P\n", [Error,20]); + Other -> + io:format("~P\n", [Other,20]) + end + catch + _:Crash -> + io:format("CRASH: ~P\n", [Crash,20]) + end. + %% %% Deletes File from Files when File is on the form .../<SUITE>_data/<file> %% when all of <SUITE> has been skipped in Spec, i.e. there @@ -230,8 +248,7 @@ make_command(Vars, Spec, State) -> " -boot start_sasl -sasl errlog_type error", " -pz \"",Cwd,"\"", " -ct_test_vars ",TestVars, - " -eval \"file:set_cwd(\\\"",TestDir,"\\\")\" " - " -eval \"ct:run_test(", + " -eval \"ts_run:ct_run_test(\\\"",TestDir,"\\\", ", backslashify(lists:flatten(State#state.test_server_args)),")\"" " ", ExtraArgs], diff --git a/lib/test_server/src/ts_selftest.erl b/lib/test_server/src/ts_selftest.erl deleted file mode 100644 index 655aa4bab3..0000000000 --- a/lib/test_server/src/ts_selftest.erl +++ /dev/null @@ -1,120 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. 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(ts_selftest). --export([selftest/0]). - -selftest() -> - case node() of - nonode@nohost -> - io:format("Sorry, you have to start this node distributed.~n"), - exit({error, node_not_distributed}); - _ -> - ok - end, - case catch ts:tests(test_server) of - {'EXIT', _} -> - io:format("Test Server self test not availiable."); - Other -> - selftest1() - end. - -selftest1() -> - % Batch starts - io:format("Selftest #1: Whole spec, batch mode:~n"), - io:format("------------------------------------~n"), - ts:run(test_server, [batch]), - ok=check_result(1, "test_server.logs", 2), - - io:format("Selftest #2: One module, batch mode:~n"), - io:format("------------------------------------~n"), - ts:run(test_server, test_server_SUITE, [batch]), - ok=check_result(2, "test_server_SUITE.logs", 2), - - io:format("Selftest #3: One testcase, batch mode:~n"), - io:format("--------------------------------------~n"), - ts:run(test_server, test_server_SUITE, msgs, [batch]), - ok=check_result(3, "test_server_SUITE.logs", 0), - - % Interactive starts - io:format("Selftest #4: Whole spec, interactive mode:~n"), - io:format("------------------------------------------~n"), - ts:run(test_server), - kill_test_server(), - ok=check_result(4, "test_server.logs", 2), - - io:format("Selftest #5: One module, interactive mode:~n"), - io:format("------------------------------------------~n"), - ts:run(test_server, test_server_SUITE), - kill_test_server(), - ok=check_result(5, "test_server_SUITE.logs", 2), - - io:format("Selftest #6: One testcase, interactive mode:~n"), - io:format("--------------------------------------------~n"), - ts:run(test_server, test_server_SUITE, msgs), - kill_test_server(), - ok=check_result(6, "test_server_SUITE.logs", 0), - - ok. - -check_result(Test, TDir, ExpSkip) -> - Dir=ts_lib:last_test(TDir), - {Total, Failed, Skipped}=ts_reports:count_cases(Dir), - io:format("Selftest #~p:",[Test]), - case {Total, Failed, Skipped} of - {_, 0, ExpSkip} -> % 2 test cases should be skipped. - io:format("All ok.~n~n"), - ok; - {_, _, _} -> - io:format("Not completely successful.~n~n"), - error - end. - - -%% Wait for test server to get started. -kill_test_server() -> - Node=list_to_atom("test_server@"++atom_to_list(hostname())), - net_adm:ping(Node), - case whereis(test_server_ctrl) of - undefined -> - kill_test_server(); - Pid -> - kill_test_server(0, Pid) - end. - -%% Wait for test server to finish. -kill_test_server(30, Pid) -> - exit(self(), test_server_is_dead); -kill_test_server(Num, Pid) -> - case whereis(test_server_ctrl) of - undefined -> - slave:stop(node(Pid)); - Pid -> - receive - after - 1000 -> - kill_test_server(Num+1, Pid) - end - end. - - -hostname() -> - list_to_atom(from($@, atom_to_list(node()))). -from(H, [H | T]) -> T; -from(H, [_ | T]) -> from(H, T); -from(H, []) -> []. |