diff options
Diffstat (limited to 'lib')
207 files changed, 9710 insertions, 3182 deletions
diff --git a/lib/asn1/vsn.mk b/lib/asn1/vsn.mk index ae92fcb11b..04f4b22421 100644 --- a/lib/asn1/vsn.mk +++ b/lib/asn1/vsn.mk @@ -1,2 +1,2 @@ -#next version number to use is 1.6.15 | 1.7 | 2.0 -ASN1_VSN = 1.6.19 +#next version number to use is 2.0 +ASN1_VSN = 1.7 diff --git a/lib/common_test/doc/src/ct_hooks_chapter.xml b/lib/common_test/doc/src/ct_hooks_chapter.xml index 8505ee8469..c5b4fd0073 100644 --- a/lib/common_test/doc/src/ct_hooks_chapter.xml +++ b/lib/common_test/doc/src/ct_hooks_chapter.xml @@ -429,6 +429,16 @@ terminate(State) -> <seealso marker="sasl:sasl_app">SASL</seealso> events report using the normal SASL mechanisms. </cell> </row> + <row> + <cell>cth_surefire</cell> + <cell>no</cell> + <cell>Captures all test results and outputs them as surefire XML into + a file. The file which is created is by default called junit_report.xml. + The name can be by setting the path option for this hook. e.g. + <code>-ct_hooks cth_surefix [{path,"/tmp/report.xml"}]</code> + Surefire XML can forinstance be used by Jenkins to display test + results.</cell> + </row> </table> </section> diff --git a/lib/common_test/src/Makefile b/lib/common_test/src/Makefile index 125aa828fb..e9555de35a 100644 --- a/lib/common_test/src/Makefile +++ b/lib/common_test/src/Makefile @@ -69,7 +69,8 @@ MODULES= \ ct_slave \ ct_hooks\ ct_hooks_lock\ - cth_log_redirect + cth_log_redirect\ + cth_surefire TARGET_MODULES= $(MODULES:%=$(EBIN)/%) BEAM_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) diff --git a/lib/common_test/src/common_test.app.src b/lib/common_test/src/common_test.app.src index 7fba484b18..bdd48fbc6b 100644 --- a/lib/common_test/src/common_test.app.src +++ b/lib/common_test/src/common_test.app.src @@ -25,6 +25,8 @@ ct_framework, ct_ftp, ct_gen_conn, + ct_hooks, + ct_hooks_lock, ct_logs, ct_make, ct_master, @@ -45,7 +47,9 @@ ct_config, ct_config_plain, ct_config_xml, - ct_slave + ct_slave, + cth_log_redirect, + cth_surefire ]}, {registered, [ct_logs, ct_util_server, diff --git a/lib/common_test/src/cth_surefire.erl b/lib/common_test/src/cth_surefire.erl new file mode 100644 index 0000000000..c42f956b3a --- /dev/null +++ b/lib/common_test/src/cth_surefire.erl @@ -0,0 +1,199 @@ +%%% @doc Common Test Framework functions handling test specifications. +%%% +%%% <p>This module creates a junit report of the test run if plugged in +%%% as a suite_callback.</p> + +-module(cth_surefire). + +%% Suite Callbacks +-export([id/1, init/2]). + +-export([pre_init_per_suite/3]). +-export([post_init_per_suite/4]). +-export([pre_end_per_suite/3]). +-export([post_end_per_suite/4]). + +-export([pre_init_per_group/3]). +-export([post_init_per_group/4]). +-export([pre_end_per_group/3]). +-export([post_end_per_group/4]). + +-export([pre_init_per_testcase/3]). +-export([post_end_per_testcase/4]). + +-export([on_tc_fail/3]). +-export([on_tc_skip/3]). + +-export([terminate/1]). + +-record(state, { filepath, axis, properties, package, hostname, + curr_suite, curr_suite_ts, curr_group = [], curr_tc, + curr_log_dir, timer, tc_log, + test_cases = [], + test_suites = [] }). + +-record(testcase, { log, group, classname, name, time, failure, timestamp }). +-record(testsuite, { errors, failures, hostname, name, tests, + time, timestamp, id, package, + properties, testcases }). + +id(Opts) -> + filename:absname(proplists:get_value(path, Opts, "junit_report.xml")). + +init(Path, Opts) -> + {ok, Host} = inet:gethostname(), + #state{ filepath = Path, + hostname = proplists:get_value(hostname,Opts,Host), + package = proplists:get_value(package,Opts), + axis = proplists:get_value(axis,Opts,[]), + properties = proplists:get_value(properties,Opts,[]), + timer = now() }. + +pre_init_per_suite(Suite,Config,State) -> + {Config, init_tc(State#state{ curr_suite = Suite, curr_suite_ts = now() }, + Config) }. + +post_init_per_suite(_Suite,Config, Result, State) -> + {Result, end_tc(init_per_suite,Config,Result,State)}. + +pre_end_per_suite(_Suite,Config,State) -> {Config, init_tc(State, Config)}. + +post_end_per_suite(_Suite,Config,Result,State) -> + NewState = end_tc(end_per_suite,Config,Result,State), + TCs = NewState#state.test_cases, + Suite = get_suite(NewState, TCs), + {Result, State#state{ test_cases = [], + test_suites = [Suite | State#state.test_suites]}}. + +pre_init_per_group(Group,Config,State) -> + {Config, init_tc(State#state{ curr_group = [Group|State#state.curr_group]}, + Config)}. + +post_init_per_group(_Group,Config,Result,State) -> + {Result, end_tc(init_per_group,Config,Result,State)}. + +pre_end_per_group(_Group,Config,State) -> {Config, init_tc(State, Config)}. + +post_end_per_group(_Group,Config,Result,State) -> + NewState = end_tc(end_per_group, Config, Result, State), + {Result, NewState#state{ curr_group = tl(NewState#state.curr_group)}}. + +pre_init_per_testcase(_TC,Config,State) -> {Config, init_tc(State, Config)}. + +post_end_per_testcase(TC,Config,Result,State) -> + {Result, end_tc(TC,Config, Result,State)}. + +on_tc_fail(_TC, Res, State) -> + TCs = State#state.test_cases, + TC = hd(State#state.test_cases), + NewTC = TC#testcase{ failure = + {fail,lists:flatten(io_lib:format("~p",[Res]))} }, + State#state{ test_cases = [NewTC | tl(TCs)]}. + +on_tc_skip(_Tc, Res, State) -> + TCs = State#state.test_cases, + TC = hd(State#state.test_cases), + NewTC = TC#testcase{ + failure = + {skipped,lists:flatten(io_lib:format("~p",[Res]))} }, + State#state{ test_cases = [NewTC | tl(TCs)]}. + +init_tc(State, Config) -> + State#state{ timer = now(), + tc_log = proplists:get_value(tc_logfile, Config)}. + +end_tc(Func, Config, Res, State) when is_atom(Func) -> + end_tc(atom_to_list(Func), Config, Res, State); +end_tc(Name, _Config, _Res, State = #state{ curr_suite = Suite, + curr_group = Groups, + timer = TS, tc_log = Log } ) -> + ClassName = atom_to_list(Suite), + PGroup = string:join([ atom_to_list(Group)|| + Group <- lists:reverse(Groups)],"."), + TimeTakes = io_lib:format("~f",[timer:now_diff(now(),TS) / 1000000]), + State#state{ test_cases = [#testcase{ log = Log, + timestamp = now_to_string(TS), + classname = ClassName, + group = PGroup, + name = Name, + time = TimeTakes, + failure = passed }| State#state.test_cases]}. + +get_suite(State, TCs) -> + Total = length(TCs), + Succ = length(lists:filter(fun(#testcase{ failure = F }) -> + F == passed + end,TCs)), + Fail = Total - Succ, + TimeTaken = timer:now_diff(now(),State#state.curr_suite_ts) / 1000000, + #testsuite{ name = atom_to_list(State#state.curr_suite), + package = State#state.package, + time = io_lib:format("~f",[TimeTaken]), + timestamp = now_to_string(State#state.curr_suite_ts), + errors = Fail, tests = Total, testcases = lists:reverse(TCs) }. + +terminate(State) -> + {ok,D} = file:open(State#state.filepath,[write]), + io:format(D, "<?xml version=\"1.0\" encoding= \"UTF-8\" ?>", []), + io:format(D, to_xml(State), []), + catch file:sync(D), + catch file:close(D). + +to_xml(#testcase{ group = Group, classname = CL, log = L, name = N, time = T, timestamp = TS, failure = F}) -> + ["<testcase ", + [["group=\"",Group,"\""]||Group /= ""]," " + "name=\"",N,"\" " + "time=\"",T,"\" " + "timestamp=\"",TS,"\" " + "log=\"",L,"\">", + case F of + passed -> + []; + {skipped,Reason} -> + ["<skipped type=\"skip\" message=\"Test ",N," in ",CL, + " skipped!\">", sanitize(Reason),"</skipped>"]; + {fail,Reason} -> + ["<failure message=\"Test ",N," in ",CL," failed!\" type=\"crash\">", + sanitize(Reason),"</failure>"] + end,"</testcase>"]; +to_xml(#testsuite{ package = P, hostname = H, errors = E, time = Time, + timestamp = TS, tests = T, name = N, testcases = Cases }) -> + ["<testsuite ", + [["package=\"",P,"\" "]||P /= undefined], + [["hostname=\"",P,"\" "]||H /= undefined], + [["name=\"",N,"\" "]||N /= undefined], + [["time=\"",Time,"\" "]||Time /= undefined], + [["timestamp=\"",TS,"\" "]||TS /= undefined], + "errors=\"",integer_to_list(E),"\" " + "tests=\"",integer_to_list(T),"\">", + [to_xml(Case) || Case <- Cases], + "</testsuite>"]; +to_xml(#state{ test_suites = TestSuites, axis = Axis, properties = Props }) -> + ["<testsuites>",properties_to_xml(Axis,Props), + [to_xml(TestSuite) || TestSuite <- TestSuites],"</testsuites>"]. + +properties_to_xml(Axis,Props) -> + ["<properties>", + [["<property name=\"",Name,"\" axis=\"yes\" value=\"",Value,"\" />"] || {Name,Value} <- Axis], + [["<property name=\"",Name,"\" value=\"",Value,"\" />"] || {Name,Value} <- Props], + "</properties>" + ]. + +sanitize([$>|T]) -> + ">" ++ sanitize(T); +sanitize([$<|T]) -> + "<" ++ sanitize(T); +sanitize([$"|T]) -> + """ ++ sanitize(T); +sanitize([$'|T]) -> + "'" ++ sanitize(T); +sanitize([$&|T]) -> + "&" ++ sanitize(T); +sanitize([H|T]) -> + [H|sanitize(T)]; +sanitize([]) -> + []. + +now_to_string(Now) -> + {{YY,MM,DD},{HH,Mi,SS}} = calendar:now_to_local_time(Now), + io_lib:format("~p-~2..0B-~2..0BT~2..0B:~2..0B:~2..0B",[YY,MM,DD,HH,Mi,SS]). diff --git a/lib/debugger/src/dbg_iserver.erl b/lib/debugger/src/dbg_iserver.erl index 1bb73a43b9..31a856545f 100644 --- a/lib/debugger/src/dbg_iserver.erl +++ b/lib/debugger/src/dbg_iserver.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2011. All Rights Reserved. +%% Copyright Ericsson AB 1998-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 @@ -188,10 +188,7 @@ handle_call({new_break, Point, Options}, _From, State) -> handle_call(all_breaks, _From, State) -> {reply, State#state.breaks, State}; handle_call({all_breaks, Mod}, _From, State) -> - Reply = lists:filter(fun({{M,_L}, _Options}) -> - M =/= Mod - end, - State#state.breaks), + Reply = [Break || Break = {{M, _},_} <- State#state.breaks, M =:= Mod], {reply, Reply, State}; %% From Meta process diff --git a/lib/debugger/test/int_break_SUITE.erl b/lib/debugger/test/int_break_SUITE.erl index 159678a1f9..7bb0fc2018 100644 --- a/lib/debugger/test/int_break_SUITE.erl +++ b/lib/debugger/test/int_break_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-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 @@ -76,6 +76,9 @@ basic(Config) when list(Config) -> ?line S3 = [xxx,y] = ordsets1:add_element(y, S2), ?line ok = i:ib(ordsets1, union, 2), ?line [xxx,y,z] = ordsets1:union(S3, [z]), + All = [{{ordsets1,86}, _}, {{ordsets1,_},_}|_] = lists:sort(int:all_breaks()), + [] = lists:sort(int:all_breaks(foobar)), + All = lists:sort(int:all_breaks(ordsets1)), ok. cleanup(doc) -> "Make sure that the auto-attach flag is turned off."; diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 845df0ca61..0c2e846010 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2011. All Rights Reserved. +%% Copyright Ericsson AB 2003-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 @@ -241,6 +241,7 @@ type(erl_ddll, try_unload, 2, Xs) -> %%-- erlang ------------------------------------------------------------------- type(erlang, halt, 0, _) -> t_none(); type(erlang, halt, 1, _) -> t_none(); +type(erlang, halt, 2, _) -> t_none(); type(erlang, exit, 1, _) -> t_none(); %% Note that exit/2 sends an exit signal to another process. type(erlang, exit, 2, _) -> t_atom('true'); @@ -709,6 +710,27 @@ type(erlang, display_nl, 0, _) -> t_atom('true'); type(erlang, dist_exit, 3, Xs) -> strict(arg_types(erlang, dist_exit, 3), Xs, fun (_) -> t_atom('true') end); +type(erlang, dt_append_vm_tag_data, 1, Xs) -> + strict(arg_types(erlang, dt_append_vm_tag_data, 1), + Xs, + fun(_) -> t_iodata() end); +type(erlang, dt_get_tag, 0, _) -> + t_sup(t_binary(), t_atom('undefined')); +type(erlang, dt_get_tag_data, 0, _) -> + t_sup(t_binary(), t_atom('undefined')); +type(erlang, dt_prepend_vm_tag_data, 1, Xs) -> + strict(arg_types(erlang, dt_prepend_vm_tag_data, 1), + Xs, + fun(_) -> t_iodata() end); +type(erlang, dt_put_tag, 1, Xs) -> + strict(arg_types(erlang, dt_put_tag, 1), Xs, + fun(_) -> t_sup(t_binary(), t_atom('undefined')) end); +type(erlang, dt_restore_tag, 1, Xs) -> + strict(arg_types(erlang, dt_restore_tag, 1), Xs, fun(_) -> t_atom('true') end); +type(erlang, dt_spread_tag, 1, Xs) -> + strict(arg_types(erlang, dt_spread_tag, 1), Xs, + fun(_) -> t_sup(t_tuple([t_non_neg_integer(), t_sup(t_binary(), t_nil())]), + t_atom('true')) end); type(erlang, element, 2, Xs) -> strict(arg_types(erlang, element, 2), Xs, fun ([X1, X2]) -> @@ -3494,6 +3516,20 @@ arg_types(erlang, display_string, 1) -> [t_string()]; arg_types(erlang, dist_exit, 3) -> [t_pid(), t_dist_exit(), t_sup(t_pid(), t_port())]; +arg_types(erlang, dt_append_vm_tag_data, 1) -> + [t_iodata()]; +arg_types(erlang, dt_get_tag, 0) -> + []; +arg_types(erlang, dt_get_tag_data, 0) -> + []; +arg_types(erlang, dt_prepend_vm_tag_data, 1) -> + [t_iodata()]; +arg_types(erlang, dt_put_tag, 1) -> + [t_sup(t_binary(), t_atom('undefined'))]; +arg_types(erlang, dt_restore_tag, 1) -> + [t_sup(t_tuple([t_non_neg_integer(), t_sup(t_binary(), t_nil())]), t_atom('true'))]; +arg_types(erlang, dt_spread_tag, 1) -> + [t_boolean()]; arg_types(erlang, element, 2) -> [t_pos_fixnum(), t_tuple()]; arg_types(erlang, erase, 0) -> @@ -3553,7 +3589,10 @@ arg_types(erlang, group_leader, 2) -> arg_types(erlang, halt, 0) -> []; arg_types(erlang, halt, 1) -> - [t_sup(t_non_neg_fixnum(), t_string())]; + [t_sup([t_non_neg_fixnum(), t_atom('abort'), t_string()])]; +arg_types(erlang, halt, 2) -> + [t_sup([t_non_neg_fixnum(), t_atom('abort'), t_string()]), + t_list(t_tuple([t_atom('flush'), t_boolean()]))]; arg_types(erlang, hash, 2) -> [t_any(), t_integer()]; arg_types(erlang, hd, 1) -> diff --git a/lib/ic/test/c_client_erl_server_SUITE_data/Makefile.src b/lib/ic/test/c_client_erl_server_SUITE_data/Makefile.src index d5277eb256..53543a5bf0 100644 --- a/lib/ic/test/c_client_erl_server_SUITE_data/Makefile.src +++ b/lib/ic/test/c_client_erl_server_SUITE_data/Makefile.src @@ -122,24 +122,33 @@ EBINS = $(ERL_FILES:.erl=.@EMULATOR@) all: $(PGMS) $(EBINS) +$(GEN_ERL_FILES) $(GEN_HRL_FILES): c_erl_test.built_erl +$(GEN_C_FILES) $(GEN_H_FILES): c_erl_test.built_c +$(OBJS): $(GEN_C_FILES) $(GEN_H_FILES) +$(EBINS): $(GEN_ERL_FILES) $(GEN_HRL_FILES) + clean: -rm -f $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ - $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \ + c_erl_test.built_erl c_erl_test.built_c -del /F /Q $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ - $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \ + c_erl_test.built_erl c_erl_test.built_c $(PGMS): $(OBJS) $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) -$(GEN_C_FILES) $(GEN_H_FILES): c_erl_test.idl +c_erl_test.built_c: c_erl_test.idl $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,c_client}" c_erl_test.idl + echo done > c_erl_test.built_c -$(GEN_ERL_FILES) $(GEN_HRL_FILES): c_erl_test.idl +c_erl_test.built_erl: c_erl_test.idl $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" c_erl_test.idl + echo done > c_erl_test.built_erl -.c@obj@: +.c@obj@: $(CC) -c -o $*@obj@ $(CFLAGS) $< -.erl.@EMULATOR@: +.erl.@EMULATOR@: $(ERLC) -I $(IC_INCLUDE_PATH) $< diff --git a/lib/ic/test/c_client_erl_server_proto_SUITE_data/Makefile.src b/lib/ic/test/c_client_erl_server_proto_SUITE_data/Makefile.src index 8bc1a907a7..7d32ee4e87 100644 --- a/lib/ic/test/c_client_erl_server_proto_SUITE_data/Makefile.src +++ b/lib/ic/test/c_client_erl_server_proto_SUITE_data/Makefile.src @@ -122,25 +122,34 @@ EBINS = $(ERL_FILES:.erl=.@EMULATOR@) all: $(PGMS) $(EBINS) +$(GEN_ERL_FILES) $(GEN_HRL_FILES): c_erl_test.built_erl +$(GEN_C_FILES) $(GEN_H_FILES): c_erl_test.built_c +$(OBJS): $(GEN_C_FILES) $(GEN_H_FILES) +$(EBINS): $(GEN_ERL_FILES) $(GEN_HRL_FILES) + clean: -rm -f $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ - $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \ + c_erl_test.built_erl c_erl_test.built_c -del /F /Q $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ - $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \ + c_erl_test.built_erl c_erl_test.built_c $(PGMS): $(OBJS) $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) -$(GEN_C_FILES) $(GEN_H_FILES): c_erl_test.idl +c_erl_test.built_c: c_erl_test.idl $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,c_client}" \ "+{user_protocol,my}" c_erl_test.idl + echo done > c_erl_test.built_c -$(GEN_ERL_FILES) $(GEN_HRL_FILES): c_erl_test.idl +c_erl_test.built_erl: c_erl_test.idl $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" c_erl_test.idl + echo done > c_erl_test.built_erl -.c@obj@: +.c@obj@: $(CC) -c -o $*@obj@ $(CFLAGS) $< -.erl.@EMULATOR@: +.erl.@EMULATOR@: $(ERLC) -I $(IC_INCLUDE_PATH) $< diff --git a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/Makefile.src b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/Makefile.src index 2585341791..19c67734ca 100644 --- a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/Makefile.src +++ b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/Makefile.src @@ -122,25 +122,33 @@ EBINS = $(ERL_FILES:.erl=.@EMULATOR@) all: $(PGMS) $(EBINS) +$(GEN_ERL_FILES) $(GEN_HRL_FILES): c_erl_test.built_erl +$(GEN_C_FILES) $(GEN_H_FILES): c_erl_test.built_c +$(OBJS): $(GEN_C_FILES) $(GEN_H_FILES) +$(EBINS): $(GEN_ERL_FILES) $(GEN_HRL_FILES) + clean: -rm -f $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ - $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \ + c_erl_test.built_erl c_erl_test.built_c -del /F /Q $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ - $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \ + c_erl_test.built_erl c_erl_test.built_c $(PGMS): $(OBJS) $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) -$(GEN_C_FILES) $(GEN_H_FILES): c_erl_test.idl - $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,c_client}" \ - "+{user_protocol,my}" "+{c_timeout,{5000,5000}}" c_erl_test.idl +c_erl_test.built_c: c_erl_test.idl + $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,c_client}" c_erl_test.idl + echo done > c_erl_test.built_c -$(GEN_ERL_FILES) $(GEN_HRL_FILES): c_erl_test.idl +c_erl_test.built_erl: c_erl_test.idl $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" c_erl_test.idl + echo done > c_erl_test.built_erl -.c@obj@: +.c@obj@: $(CC) -c -o $*@obj@ $(CFLAGS) $< -.erl.@EMULATOR@: +.erl.@EMULATOR@: $(ERLC) -I $(IC_INCLUDE_PATH) $< diff --git a/lib/ic/test/erl_client_c_server_SUITE_data/Makefile.src b/lib/ic/test/erl_client_c_server_SUITE_data/Makefile.src index 50cf9d4445..ac53d0a657 100644 --- a/lib/ic/test/erl_client_c_server_SUITE_data/Makefile.src +++ b/lib/ic/test/erl_client_c_server_SUITE_data/Makefile.src @@ -122,25 +122,34 @@ EBINS = $(ERL_FILES:.erl=.@EMULATOR@) all: $(PGMS) $(EBINS) +$(GEN_ERL_FILES) $(GEN_HRL_FILES): c_erl_test.built_erl +$(GEN_C_FILES) $(GEN_H_FILES): c_erl_test.built_c +$(OBJS): $(GEN_C_FILES) $(GEN_H_FILES) +$(EBINS): $(GEN_ERL_FILES) $(GEN_HRL_FILES) + clean: -rm -f $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ - $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \ + c_erl_test.built_erl c_erl_test.built_c -del /F /Q $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ - $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \ + c_erl_test.built_erl c_erl_test.built_c $(PGMS): $(OBJS) $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) -$(GEN_C_FILES) $(GEN_H_FILES): erl_c_test.idl +c_erl_test.built_c: erl_c_test.idl $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,c_server}" \ "+{scoped_op_calls,true}" erl_c_test.idl + echo done > c_erl_test.built_c # If we have scoped operation calls for C, we must have that for # Erlang as well, if we use the m_i.erl file for calling the server. -$(GEN_ERL_FILES) $(GEN_HRL_FILES): erl_c_test.idl +c_erl_test.built_erl: erl_c_test.idl $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" \ "+{scoped_op_calls,true}" "+{timeout,true}" erl_c_test.idl + echo done > c_erl_test.built_erl .c@obj@: $(CC) -c -o $*@obj@ $(CFLAGS) $< diff --git a/lib/ic/test/erl_client_c_server_proto_SUITE_data/Makefile.src b/lib/ic/test/erl_client_c_server_proto_SUITE_data/Makefile.src index 6c7701ca50..d23de04944 100644 --- a/lib/ic/test/erl_client_c_server_proto_SUITE_data/Makefile.src +++ b/lib/ic/test/erl_client_c_server_proto_SUITE_data/Makefile.src @@ -122,25 +122,34 @@ EBINS = $(ERL_FILES:.erl=.@EMULATOR@) all: $(PGMS) $(EBINS) +$(GEN_ERL_FILES) $(GEN_HRL_FILES): c_erl_test.built_erl +$(GEN_C_FILES) $(GEN_H_FILES): c_erl_test.built_c +$(OBJS): $(GEN_C_FILES) $(GEN_H_FILES) +$(EBINS): $(GEN_ERL_FILES) $(GEN_HRL_FILES) + clean: -rm -f $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ - $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \ + c_erl_test.built_erl c_erl_test.built_c -del /F /Q $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ - $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \ + c_erl_test.built_erl c_erl_test.built_c $(PGMS): $(OBJS) $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) -$(GEN_C_FILES) $(GEN_H_FILES): erl_c_test.idl +c_erl_test.built_c: erl_c_test.idl $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,c_server}" \ "+{scoped_op_calls,true}" erl_c_test.idl + echo done > c_erl_test.built_c # If we have scoped operation calls for C, we must have that for # Erlang as well, if we use the m_i.erl file for calling the server. -$(GEN_ERL_FILES) $(GEN_HRL_FILES): erl_c_test.idl +c_erl_test.built_erl: erl_c_test.idl $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" \ "+{scoped_op_calls,true}" "+{timeout,true}" erl_c_test.idl + echo done > c_erl_test.built_erl .c@obj@: $(CC) -c -o $*@obj@ $(CFLAGS) $< diff --git a/lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src b/lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src index 5e190fe1a5..0d84a62270 100644 --- a/lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src +++ b/lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src @@ -69,20 +69,29 @@ EBINS = $(ERL_FILES:.erl=.@EMULATOR@) all: $(CLASS_FILES) $(EBINS) +$(GEN_ERL_FILES) $(GEN_HRL_FILES): java_erl_test.built_erl +$(GEN_JAVA_FILES): java_erl_test.built_java +$(CLASS_FILES): $(GEN_JAVA_FILES) +$(EBINS): $(GEN_ERL_FILES) $(GEN_HRL_FILES) + clean: -rm -f $(GEN_JAVA_FILES) $(CLASS_FILES) \ - $(GEN_ERL_FILES) $(GEN_HRL_FILES) $(EBINS) + $(GEN_ERL_FILES) $(GEN_HRL_FILES) $(EBINS) \ + java_erl_test.built_erl java_erl_test.built_java -del /F /Q $(GEN_JAVA_FILES) $(CLASS_FILES) \ - $(GEN_ERL_FILES) $(GEN_HRL_FILES) $(EBINS) + $(GEN_ERL_FILES) $(GEN_HRL_FILES) $(EBINS) \ + java_erl_test.built_erl java_erl_test.built_java -$(GEN_JAVA_FILES) : java_erl_test.idl +java_erl_test.built_java: java_erl_test.idl $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,java}" java_erl_test.idl + echo done > java_erl_test.built_java $(CLASS_FILES) : $(JAVA_FILES) $(JAVAC) -classpath $(CLASSPATH) $(JAVA_FILES) -$(GEN_ERL_FILES) $(GEN_HRL_FILES): java_erl_test.idl +java_erl_test.built_erl: java_erl_test.idl $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" java_erl_test.idl + echo done > java_erl_test.built_erl .erl.@EMULATOR@: $(ERLC) -I $(IC_INCLUDE_PATH) $< diff --git a/lib/inets/doc/src/Makefile b/lib/inets/doc/src/Makefile index 53d505b102..c4152a1d72 100644 --- a/lib/inets/doc/src/Makefile +++ b/lib/inets/doc/src/Makefile @@ -48,6 +48,7 @@ XML_REF3_FILES = \ inets.xml \ ftp.xml \ tftp.xml \ + http_uri.xml\ httpc.xml\ httpd.xml \ httpd_conf.xml \ diff --git a/lib/inets/doc/src/book.xml b/lib/inets/doc/src/book.xml index 7da0abd98f..51cbb2d963 100644 --- a/lib/inets/doc/src/book.xml +++ b/lib/inets/doc/src/book.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE book SYSTEM "book.dtd"> <book xmlns:xi="http://www.w3.org/2001/XInclude"> <header titlestyle="normal"> <copyright> - <year>1997</year><year>2009</year> + <year>1997</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/inets/doc/src/fascicules.xml b/lib/inets/doc/src/fascicules.xml index 101e745722..ea3b988882 100644 --- a/lib/inets/doc/src/fascicules.xml +++ b/lib/inets/doc/src/fascicules.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE fascicules SYSTEM "fascicules.dtd"> <fascicules> diff --git a/lib/inets/doc/src/ftp_client.xml b/lib/inets/doc/src/ftp_client.xml index 7f62a453a6..b44674d997 100644 --- a/lib/inets/doc/src/ftp_client.xml +++ b/lib/inets/doc/src/ftp_client.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> <header> <copyright> - <year>2004</year><year>2009</year> + <year>2004</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/inets/doc/src/http_uri.xml b/lib/inets/doc/src/http_uri.xml new file mode 100644 index 0000000000..bd31ae42d2 --- /dev/null +++ b/lib/inets/doc/src/http_uri.xml @@ -0,0 +1,160 @@ +<?xml version="1.0" encoding="iso-8859-1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2012</year><year>2012</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>http_uri</title> + <prepared></prepared> + <responsible></responsible> + <docno></docno> + <date></date> + <rev></rev> + </header> + + <module>http_uri</module> + <modulesummary>URI utility module</modulesummary> + + <description> + <p>This module provides utility functions for working with URIs, + according to RFC 3986. </p> + + </description> + + <section> + <title>COMMON DATA TYPES </title> + <p>Type definitions that are used more than once in + this module:</p> + <code type="none"><![CDATA[ +boolean() = true | false +string() = list of ASCII characters + ]]></code> + + </section> + + <section> + <title>URI DATA TYPES </title> + <p>Type definitions that are related to URI:</p> + <p>For more information about URI, see RFC 3986. </p> + + <code type="none"><![CDATA[ +uri() = string() - Syntax according to the URI definition in rfc 3986, ex: "http://www.erlang.org/" +user_info() = string() +scheme() = atom() - Example: http, https +host() = string() +port() = pos_integer() +path() = string() - Representing a file path or directory path +query() = string() + ]]></code> + + <marker id="scheme_defaults"></marker> + </section> + + <funcs> + <func> + <name>scheme_defaults() -> SchemeDefaults</name> + <fsummary>A list of scheme and their default ports</fsummary> + <type> + <v>SchemeDefaults = [{scheme(), default_scheme_port_number()}] </v> + <v>default_scheme_port_number() = pos_integer()</v> + </type> + <desc> + <p>This function provides a list of the scheme and their default + port numbers currently supported (by default) by this utility. </p> + + <marker id="parse"></marker> + </desc> + </func> + + <func> + <name>parse(URI) -> {ok, Result} | {error, Reason}</name> + <name>parse(URI, Options) -> {ok, Result} | {error, Reason}</name> + <fsummary>Parse an URI</fsummary> + <type> + <v>URI = uri() </v> + <v>Options = [Option] </v> + <v>Option = {ipv6_host_with_brackets, boolean()} | + {scheme_defaults, scheme_defaults()}]</v> + <v>Result = {Scheme, UserInfo, Host, Port, Path, Query}</v> + <v>UserInfo = user_info()</v> + <v>Host = host()</v> + <v>Port = pos_integer()</v> + <v>Path = path()</v> + <v>Query = query()</v> + <v>Reason = term() </v> + </type> + <desc> + <p>This function is used to parse an URI. If no scheme defaults + are provided, the value of + <seealso marker="#scheme_defaults">scheme_defaults</seealso> + function will be used. </p> + + <p>Note that when parsing an URI with an unknown scheme (that is, + a scheme not found in the scheme defaults) a port number must be + provided or else the parsing will fail. </p> + + <marker id="encode"></marker> + </desc> + </func> + + <func> + <name>encode(URI) -> HexEncodedURI</name> + + <fsummary>Hex encode an URI</fsummary> + <type> + <v>URI = uri()</v> + <v>HexEncodedURI = string() - Hex encoded uri</v> + </type> + + <desc> + <p>Hex encode an URI. </p> + + <marker id="decode"></marker> + </desc> + </func> + + <func> + <name>decode(HexEncodedURI) -> URI</name> + + <fsummary>Decode a hex encoded URI</fsummary> + <type> + <v>HexEncodedURI = string() - A possibly hex encoded uri</v> + <v>URI = uri()</v> + </type> + + <desc> + <p>Decode a possibly hex encoded URI. </p> + + </desc> + </func> + + </funcs> + +<!-- + <section> + <title>SEE ALSO</title> + <p>RFC 2616, <seealso marker="inets">inets(3)</seealso>, + <seealso marker="kernel:gen_tcp">gen_tcp(3)</seealso>, + <seealso marker="ssl:ssl">ssl(3)</seealso> + </p> + </section> +--> + +</erlref> diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml index 48a2089605..70c845bade 100644 --- a/lib/inets/doc/src/httpc.xml +++ b/lib/inets/doc/src/httpc.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2004</year><year>2011</year> + <year>2004</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -541,6 +541,35 @@ apply(Module, Function, [ReplyInfo | Args]) default value of the <c>max_sessions</c> option. </p> </note> + <marker id="get_options"></marker> + </desc> + </func> + + <func> + <name>get_options(OptionItems) -> {ok, Values} | {error, Reason}</name> + <name>get_options(OptionItems, Profile) -> {ok, Values} | {error, Reason}</name> + <fsummary>Gets the currently used options.</fsummary> + <type> + <v>OptionItems = all | [option_item()]</v> + <v>option_item() = proxy | + max_sessions | + keep_alive_timeout | + max_keep_alive_length | + pipeline_timeout | + max_pipeline_length | + cookies | + ipfamily | + ip | + port | + socket_opts | + verbose</v> + <v>Profile = profile() | pid() (when started <c>stand_alone</c>)</v> + <v>Values = [{option_item(), term()}]</v> + <v>Reason = term() </v> + </type> + <desc> + <p>Retrieves the options currently used by the client.</p> + <marker id="stream_next"></marker> </desc> </func> diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml index f88099a82e..7e21229fcf 100644 --- a/lib/inets/doc/src/httpd.xml +++ b/lib/inets/doc/src/httpd.xml @@ -55,14 +55,14 @@ <section> <title>ERLANG HTTP SERVER SERVICE START/STOP </title> <p>A web server can be configured to start when starting the inets - application or started dynamically in runtime by calling the - Inets application API <c>inets:start(httpd, ServiceConfig)</c>, or - <c>inets:start(httpd, ServiceConfig, How)</c>, - see <seealso marker="inets">inets(3)</seealso> Below follows a - description of the available configuration options, also called - properties.</p> - - <marker id="file_prop"></marker> + application or started dynamically in runtime by calling the + Inets application API <c>inets:start(httpd, ServiceConfig)</c>, or + <c>inets:start(httpd, ServiceConfig, How)</c>, + see <seealso marker="inets">inets(3)</seealso> Below follows a + description of the available configuration options, also called + properties.</p> + + <marker id="props_file"></marker> <p><em>File properties</em></p> <p>When the web server is started @@ -76,21 +76,25 @@ list.</p> <taglist> + <marker id="prop_proplist_file"></marker> <tag>{proplist_file, path()}</tag> <item> - If this property is defined inets will expect to find - all other properties defined in this file. Note that the - file must include all properties listed under mandatory - properties. </item> - <tag>{file, path()}</tag> + <p>If this property is defined inets will expect to find + all other properties defined in this file. Note that the + file must include all properties listed under mandatory + properties. </p> + </item> - <item> If this property is defined - inets will expect to find all other properties defined in this - file, that uses Apache like syntax. Note that the file must - include all properties listed under mandatory properties. The - Apache like syntax is the property, written as one word where - each new word begins with a capital, followed by a white-space - followed by the value followed by a new line. Ex: + <marker id="prop_file"></marker> + <tag>{file, path()}</tag> + <item> + <p>If this property is defined inets will expect to find all + other properties defined in this file, that uses Apache like + syntax. Note that the file must include all properties listed + under mandatory properties. The Apache like syntax is the property, + written as one word where each new word begins with a capital, + followed by a white-space followed by the value followed by a + new line. Ex: </p> <code> {server_root, "/urs/local/www"} -> ServerRoot /usr/local/www @@ -114,40 +118,51 @@ <p>The properties proplist_file and file are mutually exclusive.</p> </note> - <marker id="mand_prop"></marker> + <marker id="props_mand"></marker> <p><em>Mandatory properties</em></p> <taglist> + <marker id="prop_port"></marker> <tag>{port, integer()} </tag> <item> - The port that the HTTP server shall listen on. - If zero is specified as port, an arbitrary available port - will be picked and you can use the httpd:info/2 function to find - out which port was picked. </item> + <p>The port that the HTTP server shall listen on. + If zero is specified as port, an arbitrary available port + will be picked and you can use the httpd:info/2 function to find + out which port was picked. </p> + </item> + + <marker id="prop_server_name"></marker> <tag>{server_name, string()} </tag> <item> - The name of your server, normally a fully qualified domain - name. + <p>The name of your server, normally a fully qualified domain name. </p> </item> + + <marker id="prop_server_root"></marker> <tag>{server_root, path()} </tag> <item> - Defines the servers home directory where log files etc can + <p>Defines the servers home directory where log files etc can be stored. Relative paths specified in other properties refer - to this directory.</item> + to this directory. </p> + </item> + + <marker id="prop_doc_root"></marker> <tag>{document_root, path()}</tag> <item> Defines the top directory for the documents that - are available on the HTTP server.</item> + are available on the HTTP server. + </item> </taglist> - <marker id="comm_prop"></marker> + <marker id="props_comm"></marker> <p><em>Communication properties</em> </p> <taglist> + <marker id="prop_bind_address"></marker> <tag>{bind_address, ip_address() | hostname() | any} </tag> <item> - Defaults to <c>any</c>. Note that <c>any</c> is denoted <em>*</em> - in the apache like configuration file. + <p>Defaults to <c>any</c>. Note that <c>any</c> is denoted <em>*</em> + in the apache like configuration file. </p> </item> + <marker id="prop_socket_type"></marker> <tag>{socket_type, ip_comm | ssl | essl}</tag> <item> <p>When using ssl, there are currently only one alternative. @@ -156,6 +171,7 @@ <p>Defaults to <c>ip_comm</c>. </p> </item> + <marker id="prop_ipfamily"></marker> <tag>{ipfamily, inet | inet6 | inet6fb4}</tag> <item> <p>Defaults to <c>inet6fb4. </c> </p> @@ -165,74 +181,93 @@ </taglist> + <marker id="props_api_modules"></marker> <p><em>Erlang Web server API modules</em> </p> <taglist> + <marker id="prop_modules"></marker> <tag>{modules, [atom()]} </tag> <item> - Defines which modules the HTTP server will use to handle + <p>Defines which modules the HTTP server will use to handle requests. Defaults to: <c>[mod_alias, mod_auth, mod_esi, mod_actions, mod_cgi, mod_dir, mod_get, mod_head, mod_log, mod_disk_log] </c> Note that some mod-modules are dependent on others, so the order can not be entirely arbitrary. See the <seealso marker="http_server"> Inets Web server Modules in the - Users guide</seealso> for more information. + Users guide</seealso> for more information. </p> </item> - </taglist> + </taglist> - <marker id="limit_prop"></marker> + <marker id="props_limit"></marker> <p><em>Limit properties</em> </p> <taglist> + <marker id="prop_disable_chunked_encoding"></marker> <tag>{disable_chunked_transfer_encoding_send, boolean()}</tag> <item> - This property allows you to disable chunked + <p>This property allows you to disable chunked transfer-encoding when sending a response to a HTTP/1.1 - client, by default this is false.</item> + client, by default this is false. </p> + </item> + <marker id="prop_keep_alive"></marker> <tag>{keep_alive, boolean()}</tag> <item> - Instructs the server whether or not to use persistent + <p>Instructs the server whether or not to use persistent connections when the client claims to be HTTP/1.1 - compliant, default is true.</item> + compliant, default is true. </p> + </item> + <marker id="prop_keep_alive_timeout"></marker> <tag>{keep_alive_timeout, integer()}</tag> <item> - The number of seconds the server will wait for a + <p>The number of seconds the server will wait for a subsequent request from the client before closing the - connection. Default is 150.</item> + connection. Default is 150. </p> + </item> + <marker id="prop_max_body_size"></marker> <tag>{max_body_size, integer()}</tag> <item> - Limits the size of the message body of HTTP request. - By the default there is no limit.</item> + <p>Limits the size of the message body of HTTP request. + By the default there is no limit. </p> + </item> + <marker id="prop_max_clients"></marker> <tag>{max_clients, integer()}</tag> <item> - Limits the number of simultaneous requests that can be - supported. Defaults to 150. </item> + <p>Limits the number of simultaneous requests that can be + supported. Defaults to 150. </p> + </item> + <marker id="prop_max_header_size"></marker> <tag>{max_header_size, integer()}</tag> <item> - Limits the size of the message header of HTTP request. - Defaults to 10240. + <p>Limits the size of the message header of HTTP request. + Defaults to 10240. </p> </item> + <marker id="prop_max_uri"></marker> <tag>{max_uri, integer()}</tag> <item> - Limits the size of the HTTP request URI. By - default there is no limit.</item> + <p>Limits the size of the HTTP request URI. By + default there is no limit. </p> + </item> + <marker id="prop_max_keep_alive_req"></marker> <tag>{max_keep_alive_requests, integer()}</tag> - <item> The number of request that a client can do on one + <item> + <p>The number of request that a client can do on one connection. When the server has responded to the number of requests defined by max_keep_alive_requests the server close the connection. The server will close it even if there are queued - request. Defaults to no limit.</item> + request. Defaults to no limit. </p> + </item> </taglist> - <marker id="admin_prop"></marker> + <marker id="props_admin"></marker> <p><em>Administrative properties</em></p> <taglist> + <marker id="prop_mime_types"></marker> <tag>{mime_types, [{MimeType, Extension}] | path()}</tag> <item> <p>Where MimeType = string() and Extension = string(). @@ -250,19 +285,43 @@ text/plain asc txt <p>Defaults to [{"html","text/html"},{"htm","text/html"}]</p> </item> + <marker id="prop_mime_type"></marker> <tag>{mime_type, string()}</tag> - <item> - When the server is asked to provide a document type which + <p>When the server is asked to provide a document type which cannot be determined by the MIME Type Settings, the server will - use this default type. </item> + use this default type. </p> + </item> + <marker id="prop_server_admin"></marker> <tag>{server_admin, string()}</tag> <item> - ServerAdmin defines the email-address of the server + <p>ServerAdmin defines the email-address of the server administrator, to be included in any error messages returned by - the server.</item> + the server. </p> + </item> + <marker id="prop_server_tokens"></marker> + <tag>{server_tokens, prod|major|minor|minimal|os|full|{private, string()}}</tag> + <item> + <p>ServerTokens defines how the value of the server header + should look. </p> + <p>Example: Assuming the version of inets is 5.8.1, + here is what the server header string could look like for + the different values of server-tokens: </p> + <pre> +prod "inets" +major "inets/5" +minor "inets/5.8" +minimal "inets/5.8.1" +os "inets/5.8.1 (unix)" +full "inets/5.8.1 (unix/linux) OTP/R15B" +{private, "foo/bar"} "foo/bar" + </pre> + <p>By default, the value is as before, which is <c>minimal</c>. </p> + </item> + + <marker id="prop_log_format"></marker> <tag>{log_format, common | combined}</tag> <item> <p>Defines if access logs should be written according to the common @@ -307,8 +366,9 @@ bytes <p>This affects the access logs written by mod_log and mod_disk_log. </p> - </item> - + </item> + + <marker id="prop_elog_format"></marker> <tag>{error_log_format, pretty | compact}</tag> <item> <p>Defaults to pretty. If the error log is meant to be read @@ -330,63 +390,77 @@ bytes </taglist> - <marker id="ssl_prop"></marker> + <marker id="props_ssl"></marker> <p><em>ssl properties</em></p> <taglist> + <marker id="prop_ssl_ca_cert_file"></marker> <tag>{ssl_ca_certificate_file, path()}</tag> <item> - Used as cacertfile option in ssl:listen/2 see - <seealso marker="ssl:ssl">ssl(3)</seealso> </item> + <p>Used as cacertfile option in ssl:listen/2 see + <seealso marker="ssl:ssl">ssl(3)</seealso>. </p> + </item> + <marker id="prop_ssl_cert_file"></marker> <tag>{ssl_certificate_file, path()}</tag> <item> - Used as certfile option in ssl:listen/2 see - <seealso marker="ssl:ssl">ssl(3)</seealso> + <p>Used as certfile option in ssl:listen/2 see + <seealso marker="ssl:ssl">ssl(3)</seealso>. </p> </item> + <marker id="prop_ssl_ciphers"></marker> <tag>{ssl_ciphers, list()}</tag> <item> - Used as ciphers option in ssl:listen/2 see - <seealso marker="ssl:ssl">ssl(3)</seealso> + <p>Used as ciphers option in ssl:listen/2 see + <seealso marker="ssl:ssl">ssl(3)</seealso>. </p> </item> + <marker id="prop_ssl_verify_client"></marker> <tag>{ssl_verify_client, integer()}</tag> <item> - Used as verify option in ssl:listen/2 see - <seealso marker="ssl:ssl">ssl(3)</seealso> </item> + <p>Used as verify option in ssl:listen/2 see + <seealso marker="ssl:ssl">ssl(3)</seealso>. </p> + </item> + <marker id="prop_ssl_verify_depth"></marker> <tag>{ssl_verify_depth, integer()}</tag> <item> - Used as depth option in ssl:listen/2 see - <seealso marker="ssl:ssl">ssl(3)</seealso> </item> + <p>Used as depth option in ssl:listen/2 see + <seealso marker="ssl:ssl">ssl(3)</seealso>. </p> + </item> + <marker id="prop_ssl_passwd_callback_funct"></marker> <tag>{ssl_password_callback_function, atom()}</tag> <item> - Used together with ssl_password_callback_module + <p>Used together with ssl_password_callback_module to retrieve a value to use as password option to ssl:listen/2 - see <seealso marker="ssl:ssl">ssl(3)</seealso> + see <seealso marker="ssl:ssl">ssl(3)</seealso>. </p> </item> + <marker id="prop_ssl_passwd_callback_args"></marker> <tag>{ssl_password_callback_arguments, list()}</tag> <item> - Used together with ssl_password_callback_function to supply a + <p>Used together with ssl_password_callback_function to supply a list of arguments to the callback function. If not specified - the callback function will be assumed to have arity 0. </item> + the callback function will be assumed to have arity 0. </p> + </item> + <marker id="prop_ssl_passwd_callback_mod"></marker> <tag>{ssl_password_callback_module, atom()}</tag> <item> - Used together with ssl_password_callback_function + <p>Used together with ssl_password_callback_function to retrieve a value to use as password option to ssl:listen/2 - see <seealso marker="ssl:ssl">ssl(3)</seealso></item> + see <seealso marker="ssl:ssl">ssl(3)</seealso>. </p> + </item> </taglist> - <marker id="alias_prop"></marker> + <marker id="props_alias"></marker> <p><em>URL aliasing properties - requires mod_alias</em></p> <taglist> + <marker id="prop_alias"></marker> <tag>{alias, {Alias, RealName}}</tag> - - <item> Where Alias = string() and RealName = string(). + <item> + <p>Where Alias = string() and RealName = string(). The Alias property allows documents to be stored in the local file system instead of the document_root location. URLs with a path that begins with url-path is mapped to local files that begins with @@ -395,11 +469,13 @@ bytes <code>{alias, {"/image", "/ftp/pub/image"}</code> and an access to http://your.server.org/image/foo.gif would refer to - the file /ftp/pub/image/foo.gif.</item> + the file /ftp/pub/image/foo.gif. </p> + </item> - <tag>{re_write, {Re, Replacement}}</tag> - - <item> Where Re = string() and Replacement = string(). + <marker id="prop_re_write"></marker> + <tag>{re_write, {Re, Replacement}}</tag> + <item> + <p>Where Re = string() and Replacement = string(). The ReWrite property allows documents to be stored in the local file system instead of the document_root location. URLs are rewritten by re:replace/3 to produce a path in the local filesystem. @@ -419,13 +495,13 @@ bytes Beware of trailing space in Replacement that will be used. If you must have a space in Re use e.g the character encoding - <code>\040</code> see <seealso marker="stdlib:re">re(3)</seealso>. + <code>\040</code> see <seealso marker="stdlib:re">re(3)</seealso>. </p> </item> - <tag>{directory_index, [string()]}</tag> - + <marker id="prop_dir_idx"></marker> + <tag>{directory_index, [string()]}</tag> <item> - DirectoryIndex specifies a list of resources to look for + <p>DirectoryIndex specifies a list of resources to look for if a client requests a directory using a / at the end of the directory name. file depicts the name of a file in the directory. Several files may be given, in which case the server @@ -436,70 +512,79 @@ bytes and access to http://your.server.org/docs/ would return http://your.server.org/docs/index.html or http://your.server.org/docs/welcome.html if index.html do not - exist. + exist. </p> </item> </taglist> - <marker id="cgi_prop"></marker> + <marker id="props_cgi"></marker> <p><em>CGI properties - requires mod_cgi</em></p> <taglist> + <marker id="prop_script_alias"></marker> <tag>{script_alias, {Alias, RealName}}</tag> - <item> Where Alias = string() and RealName = string(). + <item> + <p>Where Alias = string() and RealName = string(). Has the same behavior as the Alias property, except that it also marks the target directory as containing CGI scripts. URLs with a path beginning with url-path are mapped to scripts beginning with directory-filename, for example: - <code> {script_alias, {"/cgi-bin/", "/web/cgi-bin/"}</code> + <code>{script_alias, {"/cgi-bin/", "/web/cgi-bin/"}</code> and an access to http://your.server.org/cgi-bin/foo would cause - the server to run the script /web/cgi-bin/foo. + the server to run the script /web/cgi-bin/foo. </p> </item> + <marker id="prop_script_re_write"></marker> <tag>{script_re_write, {Re, Replacement}}</tag> - <item> Where Re = string() and Replacement = string(). + <item> + <p>Where Re = string() and Replacement = string(). Has the same behavior as the ReWrite property, except that it also marks the target directory as containing CGI scripts. URLs with a path beginning with url-path are mapped to scripts beginning with directory-filename, for example: - <code> {script_re_write, {"^/cgi-bin/(\\d+)/", "/web/\\1/cgi-bin/"}</code> + <code>{script_re_write, {"^/cgi-bin/(\\d+)/", "/web/\\1/cgi-bin/"}</code> and an access to http://your.server.org/cgi-bin/17/foo would cause - the server to run the script /web/17/cgi-bin/foo. + the server to run the script /web/17/cgi-bin/foo. </p> </item> + <marker id="prop_script_nocache"></marker> <tag>{script_nocache, boolean()}</tag> - <item> - If ScriptNoCache is set to true the HTTP server will by + <p>If ScriptNoCache is set to true the HTTP server will by default add the header fields necessary to prevent proxies from caching the page. Generally this is something you want. Defaults - to false.</item> + to false. </p> + </item> + <marker id="prop_script_timeout"></marker> <tag>{script_timeout, integer()}</tag> - <item> - The time in seconds the web server will wait between each + <p>The time in seconds the web server will wait between each chunk of data from the script. If the CGI-script not delivers any data before the timeout the connection to the client will be - closed. Defaults to 15. </item> + closed. Defaults to 15. </p> + </item> + <marker id="prop_action"></marker> <tag>{action, {MimeType, CgiScript}} - requires mod_action</tag> - - <item>Where MimeType = string() and CgiScript = string(). + <item> + <p>Where MimeType = string() and CgiScript = string(). Action adds an action, which will activate a cgi-script whenever a file of a certain mime-type is requested. It propagates the URL and file path of the requested document using the standard CGI PATH_INFO and PATH_TRANSLATED environment variables. - <code> {action, {"text/plain", "/cgi-bin/log_and_deliver_text"} - </code> + + <code>{action, {"text/plain", "/cgi-bin/log_and_deliver_text"}</code> + </p> </item> + <marker id="prop_script"></marker> <tag>{script, {Method, CgiScript}} - requires mod_action</tag> - - <item>Where Method = string() and CgiScript = string(). + <item> + <p>Where Method = string() and CgiScript = string(). Script adds an action, which will activate a cgi-script whenever a file is requested using a certain HTTP method. The method is either GET or POST as defined in RFC 1945. It @@ -507,18 +592,19 @@ bytes the standard CGI PATH_INFO and PATH_TRANSLATED environment variables. - <code> {script, {"PUT", "/cgi-bin/put"} - </code> + <code>{script, {"PUT", "/cgi-bin/put"}</code> + </p> </item> </taglist> - <marker id="esi_prop"></marker> + <marker id="props_esi"></marker> <p><em>ESI properties - requires mod_esi</em></p> <taglist> - <tag>{erl_script_alias, {URLPath, [AllowedModule]}}</tag> - - <item>Where URLPath = string() and AllowedModule = atom(). + <marker id="prop_esi_alias"></marker> + <tag>{erl_script_alias, {URLPath, [AllowedModule]}}</tag> + <item> + <p>Where URLPath = string() and AllowedModule = atom(). erl_script_alias marks all URLs matching url-path as erl scheme scripts. A matching URL is mapped into a specific module and function. For example: @@ -531,140 +617,151 @@ bytes would refer to httpd_example:yahoo/3 or, if that did not exist, httpd_example:yahoo/2 and http://your.server.org/cgi-bin/example/other:yahoo would - not be allowed to execute. + not be allowed to execute. </p> </item> + <marker id="prop_esi_nocache"></marker> <tag>{erl_script_nocache, boolean()}</tag> - <item> - If erl_script_nocache is set to true the server will add + <p>If erl_script_nocache is set to true the server will add http header fields that prevents proxies from caching the page. This is generally a good idea for dynamic content, since - the content often vary between each request. Defaults to false. + the content often vary between each request. + Defaults to false. </p> </item> + <marker id="prop_esi_timeout"></marker> <tag>{erl_script_timeout, integer()}</tag> - <item> - If erl_script_timeout sets the time in seconds the server will + <p>If erl_script_timeout sets the time in seconds the server will wait between each chunk of data to be delivered through mod_esi:deliver/2. Defaults to 15. This is only relevant - for scripts that uses the erl scheme. + for scripts that uses the erl scheme. </p> </item> + <marker id="prop_esi_timeout"></marker> <tag>{eval_script_alias, {URLPath, [AllowedModule]}}</tag> - - <item>Where URLPath = string() and AllowedModule = atom(). + <item> + <p>Where URLPath = string() and AllowedModule = atom(). Same as erl_script_alias but for scripts - using the eval scheme. Note that this is only supported - for backwards compatibility. The eval scheme is deprecated.</item> + using the eval scheme. Note that this is only supported + for backwards compatibility. The eval scheme is deprecated. </p> + </item> </taglist> - <marker id="log_prop"></marker> + <marker id="props_log"></marker> <p><em>Log properties - requires mod_log</em></p> <taglist> + <marker id="prop_elog"></marker> <tag>{error_log, path()}</tag> - <item> - Defines the filename of the error log file to be used to log + <p>Defines the filename of the error log file to be used to log server errors. If the filename does not begin with a slash (/) - it is assumed to be relative to the server_root</item> + it is assumed to be relative to the server_root. </p> + </item> + <marker id="prop_slog"></marker> <tag>{security_log, path()}</tag> - <item> - Defines the filename of the access log file to be used to - log security events. If the filename does not begin with a slash - (/) it is assumed to be relative to the server_root. + <p>Defines the filename of the access log file to be used to + log security events. If the filename does not begin with a slash + (/) it is assumed to be relative to the server_root. </p> </item> + <marker id="prop_tlog"></marker> <tag>{transfer_log, path()}</tag> - <item> - Defines the filename of the access log file to be used to + <p>Defines the filename of the access log file to be used to log incoming requests. If the filename does not begin with a - slash (/) it is assumed to be relative to the server_root. + slash (/) it is assumed to be relative to the server_root. </p> </item> </taglist> - <marker id="dlog_prop"></marker> + <marker id="props_dlog"></marker> <p><em>Disk Log properties - requires mod_disk_log</em></p> <taglist> + <marker id="prop_dlog_format"></marker> <tag>{disk_log_format, internal | external}</tag> - <item> - Defines the file-format of the log files see disk_log for + <p>Defines the file-format of the log files see disk_log for more information. If the internal file-format is used, the logfile will be repaired after a crash. When a log file is repaired data might get lost. When the external file-format is used httpd will not start if the log file is broken. Defaults to - external. + external. </p> </item> + <marker id="prop_edlog"></marker> <tag>{error_disk_log, internal | external}</tag> - <item> - Defines the filename of the (disk_log(3)) error log file + <p>Defines the filename of the (disk_log(3)) error log file to be used to log server errors. If the filename does not begin - with a slash (/) it is assumed to be relative to the server_root. + with a slash (/) it is assumed to be relative to the server_root. </p> </item> + <marker id="prop_edlog_size"></marker> <tag>{error_disk_log_size, {MaxBytes, MaxFiles}}</tag> - - <item>Where MaxBytes = integer() and MaxFiles = integer(). + <item> + <p>Where MaxBytes = integer() and MaxFiles = integer(). Defines the properties of the (disk_log(3)) error log file. The disk_log(3) error log file is of type wrap log and max-bytes will be written to each file and max-files will be - used before the first file is truncated and reused. </item> + used before the first file is truncated and reused. </p> + </item> + <marker id="prop_sdlog"></marker> <tag>{security_disk_log, path()}</tag> - <item> - Defines the filename of the (disk_log(3)) access log file + <p>Defines the filename of the (disk_log(3)) access log file which logs incoming security events i.e authenticated requests. If the filename does not begin with a slash (/) it - is assumed to be relative to the server_root. + is assumed to be relative to the server_root. </p> </item> + <marker id="prop_sdlog_size"></marker> <tag>{security_disk_log_size, {MaxBytes, MaxFiles}}</tag> - - <item>Where MaxBytes = integer() and MaxFiles = integer(). + <item> + <p>Where MaxBytes = integer() and MaxFiles = integer(). Defines the properties of the disk_log(3) access log file. The disk_log(3) access log file is of type wrap log and max-bytes will be written to each file and max-files will be - used before the first file is truncated and reused.</item> + used before the first file is truncated and reused. </p> + </item> - <tag>{transfer_disk_log, path()}</tag> - + <marker id="prop_tdlog"></marker> + <tag>{transfer_disk_log, path()}</tag> <item> - Defines the filename of the (disk_log(3)) access log file + <p>Defines the filename of the (disk_log(3)) access log file which logs incoming requests. If the filename does not begin with a slash (/) it is assumed to be relative to the - server_root. + server_root. </p> </item> + <marker id="prop_tdlog_size"></marker> <tag>{transfer_disk_log_size, {MaxBytes, MaxFiles}}</tag> - - <item>Where MaxBytes = integer() and MaxFiles = integer(). + <item> + <p>Where MaxBytes = integer() and MaxFiles = integer(). Defines the properties of the disk_log(3) access log file. The disk_log(3) access log file is of type wrap log and max-bytes will be written to each file and max-files will be - used before the first file is truncated and reused.</item> + used before the first file is truncated and reused. </p> + </item> </taglist> - <marker id="auth_prop"></marker> + <marker id="props_auth"></marker> <p><em>Authentication properties - requires mod_auth</em></p> + <marker id="prop_dri"></marker> <p><em>{directory, {path(), [{property(), term()}]}}</em></p> - <marker id="dir_prop"></marker> + <marker id="props_dir"></marker> <p>Here follows the valid properties for directories </p> <taglist> + <marker id="prop_allow_from"></marker> <tag>{allow_from, all | [RegxpHostString]}</tag> - <item> - Defines a set of hosts which should be granted access to a + <p>Defines a set of hosts which should be granted access to a given directory. For example: @@ -672,34 +769,36 @@ bytes <code>{allow_from, ["123.34.56.11", "150.100.23"] </code> The host 123.34.56.11 and all machines on the 150.100.23 - subnet are allowed access.</item> + subnet are allowed access. </p> + </item> + <marker id="prop_deny_from"></marker> <tag>{deny_from, all | [RegxpHostString]}</tag> - <item> - Defines a set of hosts + <p>Defines a set of hosts which should be denied access to a given directory. For example: <code>{deny_from, ["123.34.56.11", "150.100.23"] </code> The host 123.34.56.11 and all machines on the 150.100.23 - subnet are not allowed access.</item> + subnet are not allowed access. </p> + </item> + <marker id="prop_auth_type"></marker> <tag>{auth_type, plain | dets | mnesia}</tag> - <item> - Sets the type of authentication database that is used for the + <p>Sets the type of authentication database that is used for the directory.The key difference between the different methods is that dynamic data can be saved when Mnesia and Dets is used. This property is called AuthDbType in the Apache like - configuration files. + configuration files. </p> </item> + <marker id="prop_auth_user_file"></marker> <tag>{auth_user_file, path()}</tag> - <item> - Sets the name of a file which contains the list of users and + <p>Sets the name of a file which contains the list of users and passwords for user authentication. filename can be either absolute or relative to the <c>server_root</c>. If using the plain storage method, this file is a plain text file, where @@ -717,12 +816,13 @@ bytes storage method. For security reasons, make sure that the <c>auth_user_file</c> is stored outside the document tree of the Web server. If it is placed in the directory which it protects, - clients will be able to download it. + clients will be able to download it. </p> </item> + <marker id="prop_auth_group_file"></marker> <tag>{auth_group_file, path()}</tag> - - <item> Sets the name of a file which contains the list of user + <item> + <p>Sets the name of a file which contains the list of user groups for user authentication. Filename can be either absolute or relative to the <c>server_root</c>. If you use the plain storage method, the group file is a plain text file, where @@ -738,93 +838,109 @@ bytes For security reasons, make sure that the <c>auth_group_file</c> is stored outside the document tree of the Web server. If it is placed in the directory which it protects, clients will be - able to download it.</item> + able to download it. </p> + </item> + <marker id="prop_auth_name"></marker> <tag>{auth_name, string()}</tag> - <item> - Sets the name of the authorization realm (auth-domain) for + <p>Sets the name of the authorization realm (auth-domain) for a directory. This string informs the client about which user - name and password to use. </item> + name and password to use. </p> + </item> + <marker id="prop_auth_access_passwd"></marker> <tag>{auth_access_password, string()}</tag> - - <item> If set to other than "NoPassword" the password is required + <item> + <p>If set to other than "NoPassword" the password is required for all API calls. If the password is set to "DummyPassword" the password must be changed before any other API calls. To secure the authenticating data the password must be changed after the web server is started since it otherwise is written in clear - text in the configuration file.</item> + text in the configuration file. </p> + </item> + <marker id="prop_req_user"></marker> <tag>{require_user, [string()]}</tag> <item> - Defines users which should be granted access to a given - directory using a secret password. + <p>Defines users which should be granted access to a given + directory using a secret password. </p> </item> + <marker id="prop_req_grp"></marker> <tag>{require_group, [string()]}</tag> <item> - Defines users which should be granted access to a given - directory using a secret password. + <p>Defines users which should be granted access to a given + directory using a secret password. </p> </item> </taglist> - <marker id="htaccess_prop"></marker> + <marker id="props_htaccess"></marker> <p><em>Htaccess authentication properties - requires mod_htaccess</em></p> <taglist> + <marker id="prop_access_files"></marker> <tag>{access_files, [path()]}</tag> - - <item> Specify which filenames that are used for + <item> + <p>Specify which filenames that are used for access-files. When a request comes every directory in the path to the requested asset will be searched after files with the names specified by this parameter. If such a file is found the file will be parsed and the restrictions specified in it will - be applied to the request. + be applied to the request. </p> </item> </taglist> - <marker id="sec_prop"></marker> + <marker id="props_sec"></marker> <p><em>Security properties - requires mod_security </em></p> + <marker id="prop_sec_dir"></marker> <p><em>{security_directory, {path(), [{property(), term()}]}</em></p> - <marker id="sdir_prop"></marker> - <p> Here follows the valid properties for security directories</p> + <marker id="props_sdir"></marker> + <p>Here follows the valid properties for security directories</p> <taglist> - <tag>{data_file, path()}</tag> - + <marker id="prop_data_file"></marker> + <tag>{data_file, path()}</tag> <item> - Name of the security data file. The filename can either + <p>Name of the security data file. The filename can either absolute or relative to the server_root. This file is used to - store persistent data for the mod_security module. </item> - - <tag>{max_retries, integer()}</tag> + store persistent data for the mod_security module. </p> + </item> - <item> Specifies the maximum number of tries to authenticate a + <marker id="prop_max_retries"></marker> + <tag>{max_retries, integer()}</tag> + <item> + <p>Specifies the maximum number of tries to authenticate a user has before the user is blocked out. If a user successfully authenticates when the user has been blocked, the user will receive a 403 (Forbidden) response from the server. If the user makes a failed attempt while blocked the server will return 401 (Unauthorized), for security - reasons. Defaults to 3 may also be set to infinity.</item> + reasons. + Defaults to 3 may also be set to infinity. </p> + </item> + <marker id="prop_block_time"></marker> <tag>{block_time, integer()}</tag> - - <item> Specifies the number of minutes a user is blocked. After + <item> + <p>Specifies the number of minutes a user is blocked. After this amount of time, he automatically regains access. - Defaults to 60</item> + Defaults to 60. </p> + </item> + <marker id="prop_fail_exp_time"></marker> <tag>{fail_expire_time, integer()}</tag> - <item> - Specifies the number of minutes a failed user authentication + <p>Specifies the number of minutes a failed user authentication is remembered. If a user authenticates after this amount of time, his previous failed authentications are - forgotten. Defaults to 30</item> + forgotten. + Defaults to 30. </p> + </item> + <marker id="prop_auth_timeout"></marker> <tag>{auth_timeout, integer()}</tag> - <item> Specifies the number of seconds a successful user authentication is remembered. After this time has passed, the @@ -835,6 +951,7 @@ bytes <funcs> <func> + <marker id="info1"></marker> <name>info(Pid) -></name> <name>info(Pid, Properties) -> [{Option, Value}]</name> <fsummary>Fetches information about the HTTP server</fsummary> @@ -858,6 +975,7 @@ bytes </func> <func> + <marker id="info2"></marker> <name>info(Address, Port) -> </name> <name>info(Address, Port, Properties) -> [{Option, Value}] </name> <fsummary>Fetches information about the HTTP server</fsummary> @@ -883,6 +1001,7 @@ bytes </func> <func> + <marker id="reload_config"></marker> <name>reload_config(Config, Mode) -> ok | {error, Reason}</name> <fsummary>Reloads the HTTP server configuration without restarting the server.</fsummary> @@ -1003,6 +1122,7 @@ bytes </section> <funcs> <func> + <marker id="module_do"></marker> <name>Module:do(ModData)-> {proceed, OldData} | {proceed, NewData} | {break, NewData} | done</name> <fsummary>Called for each request to the Web server.</fsummary> <type> @@ -1046,7 +1166,9 @@ bytes closing the connection.</p> </desc> </func> + <func> + <marker id="module_load"></marker> <name>Module:load(Line, AccIn)-> eof | ok | {ok, AccOut} | {ok, AccOut, {Option, Value}} | {ok, AccOut, [{Option, Value}]} | {error, Reason} </name> <fsummary>Load is used to convert a line in a Apache like config file to a <c>{Option, Value}</c> tuple.</fsummary> @@ -1068,7 +1190,9 @@ bytes </p> </desc> </func> + <func> + <marker id="module_store"></marker> <name>Module:store({Option, Value}, Config)-> {ok, {Option, NewValue}} | {error, Reason} </name> <fsummary></fsummary> <type> @@ -1092,6 +1216,7 @@ bytes </func> <func> + <marker id="module_remove"></marker> <name>Module:remove(ConfigDB) -> ok | {error, Reason} </name> <fsummary>Callback function that is called when the Web server is closed.</fsummary> <type> @@ -1112,6 +1237,7 @@ bytes </section> <funcs> <func> + <marker id="parse_query"></marker> <name>parse_query(QueryString) -> [{Key,Value}]</name> <fsummary>Parse incoming data to <c>erl </c>and <c>eval </c>scripts.</fsummary> <type> @@ -1120,7 +1246,6 @@ bytes <v>Value = string()</v> </type> <desc> - <marker id="parse_query"></marker> <p><c>parse_query/1</c> parses incoming data to <c>erl</c> and <c>eval</c> scripts (See <seealso marker="mod_esi">mod_esi(3)</seealso>) as defined in the standard URL format, that is '+' becomes 'space' and decoding of diff --git a/lib/inets/doc/src/httpd_conf.xml b/lib/inets/doc/src/httpd_conf.xml index a1ad76a8ae..fc34f14ec3 100644 --- a/lib/inets/doc/src/httpd_conf.xml +++ b/lib/inets/doc/src/httpd_conf.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> <header> <copyright> - <year>1997</year><year>2009</year> + <year>1997</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -33,11 +33,14 @@ Web server API programmer.</modulesummary> <description> <p>This module provides the Erlang Webserver API programmer with - utility functions for adding run-time configuration directives.</p> + utility functions for adding run-time configuration directives.</p> + + <marker id="check_enum"></marker> </description> + <funcs> <func> - <name>check_enum(EnumString,ValidEnumStrings) -> Result</name> + <name>check_enum(EnumString, ValidEnumStrings) -> Result</name> <fsummary>Check if string is a valid enumeration.</fsummary> <type> <v>EnumString = string()</v> @@ -47,10 +50,13 @@ <desc> <marker id="check_enum"></marker> <p><c>check_enum/2</c> checks if <c>EnumString</c> is a valid - enumeration of <c>ValidEnumStrings</c> in which case it is - returned as an atom.</p> + enumeration of <c>ValidEnumStrings</c> in which case it is + returned as an atom.</p> + + <marker id="clean"></marker> </desc> </func> + <func> <name>clean(String) -> Stripped</name> <fsummary>Remove leading and/or trailing white spaces.</fsummary> @@ -60,9 +66,12 @@ <desc> <marker id="clean"></marker> <p><c>clean/1</c> removes leading and/or trailing white spaces - from <c>String</c>.</p> + from <c>String</c>.</p> + + <marker id="custom_clean"></marker> </desc> </func> + <func> <name>custom_clean(String,Before,After) -> Stripped</name> <fsummary>Remove leading and/or trailing white spaces and custom characters.</fsummary> @@ -73,11 +82,14 @@ <desc> <marker id="custom_clean"></marker> <p><c>custom_clean/3</c> removes leading and/or trailing white - spaces and custom characters from <c>String</c>. <c>Before</c> - and <c>After</c> are regular expressions, as defined in - <c>regexp(3)</c>, describing the custom characters.</p> + spaces and custom characters from <c>String</c>. <c>Before</c> + and <c>After</c> are regular expressions, as defined in + <c>regexp(3)</c>, describing the custom characters.</p> + + <marker id="is_directory"></marker> </desc> </func> + <func> <name>is_directory(FilePath) -> Result</name> <fsummary>Check if a file path is a directory.</fsummary> @@ -91,13 +103,16 @@ <desc> <marker id="is_directory"></marker> <p><c>is_directory/1</c> checks if <c>FilePath</c> is a - directory in which case it is returned. Please read - <c>file(3)</c> for a description of <c>enoent</c>, - <c>eaccess</c> and <c>enotdir</c>. The definition of - the file info record can be found by including <c>file.hrl</c> - from the kernel application, see file(3).</p> + directory in which case it is returned. Please read + <c>file(3)</c> for a description of <c>enoent</c>, + <c>eaccess</c> and <c>enotdir</c>. The definition of + the file info record can be found by including <c>file.hrl</c> + from the kernel application, see file(3).</p> + + <marker id="is_file"></marker> </desc> </func> + <func> <name>is_file(FilePath) -> Result</name> <fsummary>Check if a file path is a regular file.</fsummary> @@ -111,13 +126,16 @@ <desc> <marker id="is_file"></marker> <p><c>is_file/1</c> checks if <c>FilePath</c> is a regular - file in which case it is returned. Read <c>file(3)</c> for a - description of <c>enoent</c>, <c>eaccess</c> and - <c>enotdir</c>. The definition of the file info record can be - found by including <c>file.hrl</c> from the kernel application, - see file(3).</p> + file in which case it is returned. Read <c>file(3)</c> for a + description of <c>enoent</c>, <c>eaccess</c> and + <c>enotdir</c>. The definition of the file info record can be + found by including <c>file.hrl</c> from the kernel application, + see file(3).</p> + + <marker id="make_integer"></marker> </desc> </func> + <func> <name>make_integer(String) -> Result</name> <fsummary>Return an integer representation of a string.</fsummary> diff --git a/lib/inets/doc/src/httpd_socket.xml b/lib/inets/doc/src/httpd_socket.xml index fba1a58d3a..58cd2ec575 100644 --- a/lib/inets/doc/src/httpd_socket.xml +++ b/lib/inets/doc/src/httpd_socket.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> <header> <copyright> - <year>1997</year><year>2009</year> + <year>1997</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -33,10 +33,13 @@ Web server API programmer.</modulesummary> <description> <p>This module provides the Erlang Web server API module programmer - with utility functions for generic sockets communication. The - appropriate communication mechanism is transparently used, that - is <c>ip_comm</c> or <c>ssl</c>.</p> + with utility functions for generic sockets communication. The + appropriate communication mechanism is transparently used, that + is <c>ip_comm</c> or <c>ssl</c>.</p> + + <marker id="deliver"></marker> </description> + <funcs> <func> <name>deliver(SocketType, Socket, Data) -> Result</name> @@ -50,11 +53,14 @@ <desc> <marker id="deliver"></marker> <p><c>deliver/3</c> sends the <c>Binary</c> over the - <c>Socket</c> using the specified <c>SocketType</c>. Socket - and SocketType should be the socket and the socket_type form - the mod record as defined in httpd.hrl</p> + <c>Socket</c> using the specified <c>SocketType</c>. Socket + and SocketType should be the socket and the socket_type form + the mod record as defined in httpd.hrl</p> + + <marker id="peername"></marker> </desc> </func> + <func> <name>peername(SocketType,Socket) -> {Port,IPAddress}</name> <fsummary>Return the port and IP-address of the remote socket.</fsummary> @@ -67,9 +73,12 @@ <desc> <marker id="peername"></marker> <p><c>peername/3</c> returns the <c>Port</c> and - <c>IPAddress</c> of the remote <c>Socket</c>. </p> + <c>IPAddress</c> of the remote <c>Socket</c>. </p> + + <marker id="resolve"></marker> </desc> </func> + <func> <name>resolve() -> HostName</name> <fsummary>Return the official name of the current host.</fsummary> @@ -79,7 +88,7 @@ <desc> <marker id="resolve"></marker> <p><c>resolve/0</c> returns the official <c>HostName</c> of - the current host. </p> + the current host. </p> </desc> </func> </funcs> diff --git a/lib/inets/doc/src/httpd_util.xml b/lib/inets/doc/src/httpd_util.xml index 6ac2b13c72..9f290084d2 100644 --- a/lib/inets/doc/src/httpd_util.xml +++ b/lib/inets/doc/src/httpd_util.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> <header> <copyright> - <year>1997</year><year>2010</year> + <year>1997</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/inets/doc/src/inets_services.xml b/lib/inets/doc/src/inets_services.xml index c274d67f19..e282050b12 100644 --- a/lib/inets/doc/src/inets_services.xml +++ b/lib/inets/doc/src/inets_services.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> <header> <copyright> - <year>1997</year><year>2009</year> + <year>1997</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/inets/doc/src/mod_alias.xml b/lib/inets/doc/src/mod_alias.xml index c783b99b23..265a1b8e76 100644 --- a/lib/inets/doc/src/mod_alias.xml +++ b/lib/inets/doc/src/mod_alias.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> <header> <copyright> - <year>1997</year><year>2009</year> + <year>1997</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -32,8 +32,11 @@ <modulesummary>URL aliasing.</modulesummary> <description> <p>Erlang Webserver Server internal API for handling of things - such as interaction data exported by the mod_alias module.</p> + such as interaction data exported by the mod_alias module.</p> + + <marker id="default_index"></marker> </description> + <funcs> <func> <name>default_index(ConfigDB, Path) -> NewPath</name> @@ -45,17 +48,20 @@ <desc> <marker id="default_index"></marker> <p>If <c>Path</c> is a directory, <c>default_index/2</c>, it starts - searching for resources or files that are specified in the config - directive DirectoryIndex. - If an appropriate resource or file is found, it is appended to - the end of <c>Path</c> and then returned. <c>Path</c> is - returned unaltered, if no appropriate - file is found, or if <c>Path</c> is not a directory. - <c>config_db()</c> is the server config file in ETS table format - as described in - <seealso marker="http_server">Inets Users Guide.</seealso>.</p> + searching for resources or files that are specified in the config + directive DirectoryIndex. + If an appropriate resource or file is found, it is appended to + the end of <c>Path</c> and then returned. <c>Path</c> is + returned unaltered, if no appropriate + file is found, or if <c>Path</c> is not a directory. + <c>config_db()</c> is the server config file in ETS table format + as described in + <seealso marker="http_server">Inets Users Guide.</seealso>.</p> + + <marker id="path"></marker> </desc> </func> + <func> <name>path(PathData, ConfigDB, RequestURI) -> Path</name> <fsummary>Return the actual file path to a URL.</fsummary> @@ -67,15 +73,19 @@ <desc> <marker id="path"></marker> <p><c>path/3</c> returns the actual file <c>Path</c> in the - <c>RequestURI</c> (See RFC 1945). If the interaction data - <c>{real_name,{Path,AfterPath}}</c> has been exported by - mod_alias; - <c>Path</c> is returned. If no interaction data has been - exported, ServerRoot is used to - generate a file <c>Path</c>. <c>config_db()</c> and - <c>interaction_data()</c> are as defined in <seealso marker="http_server">Inets Users Guide</seealso>.</p> + <c>RequestURI</c> (See RFC 1945). If the interaction data + <c>{real_name,{Path,AfterPath}}</c> has been exported by + mod_alias; + <c>Path</c> is returned. If no interaction data has been + exported, ServerRoot is used to + generate a file <c>Path</c>. <c>config_db()</c> and + <c>interaction_data()</c> are as defined in + <seealso marker="http_server">Inets Users Guide</seealso>.</p> + + <marker id="real_name"></marker> </desc> </func> + <func> <name>real_name(ConfigDB, RequestURI, Aliases) -> Ret</name> <fsummary>Expand a request uri using Alias config directives.</fsummary> @@ -89,18 +99,24 @@ <desc> <marker id="real_name"></marker> <p><c>real_name/3</c> traverses <c>Aliases</c>, typically - extracted from <c>ConfigDB</c>, and matches each - <c>FakeName</c> with <c>RequestURI</c>. If a match is found - <c>FakeName</c> is replaced with <c>RealName</c> in the - match. The resulting path is split into two parts, that - is <c>ShortPath</c> and <c>AfterPath</c> as defined in <seealso marker="httpd_util#split_path">httpd_util:split_path/1</seealso>. - <c>Path</c> is generated from <c>ShortPath</c>, that is - the result from <seealso marker="#default_index">default_index/2</seealso> with - <c>ShortPath</c> as an argument. - <c>config_db()</c> is the server config file in ETS table - format as described in <seealso marker="http_server">Inets User Guide.</seealso>. </p> + extracted from <c>ConfigDB</c>, and matches each + <c>FakeName</c> with <c>RequestURI</c>. If a match is found + <c>FakeName</c> is replaced with <c>RealName</c> in the + match. The resulting path is split into two parts, that + is <c>ShortPath</c> and <c>AfterPath</c> as defined in + <seealso marker="httpd_util#split_path">httpd_util:split_path/1</seealso>. + <c>Path</c> is generated from <c>ShortPath</c>, that is + the result from + <seealso marker="#default_index">default_index/2</seealso> with + <c>ShortPath</c> as an argument. + <c>config_db()</c> is the server config file in ETS table + format as described in + <seealso marker="http_server">Inets User Guide.</seealso>. </p> + + <marker id="real_script_name"></marker> </desc> </func> + <func> <name>real_script_name(ConfigDB,RequestURI,ScriptAliases) -> Ret</name> <fsummary>Expand a request uri using ScriptAlias config directives.</fsummary> @@ -114,15 +130,15 @@ <desc> <marker id="real_script_name"></marker> <p><c>real_name/3</c> traverses <c>ScriptAliases</c>, - typically extracted from <c>ConfigDB</c>, and matches each - <c>FakeName</c> with <c>RequestURI</c>. If a match is found - <c>FakeName</c> is replaced with <c>RealName</c> in the - match. If the resulting match is not an executable script - <c>not_a_script</c> is returned. If it is a script the - resulting script path is in two parts, that is - <c>ShortPath</c> and <c>AfterPath</c> as defined in <seealso marker="httpd_util#split_script_path">httpd_util:split_script_path/1</seealso>. - <c>config_db()</c> is the server config file in ETS table - format as described in <seealso marker="http_server">Inets Users Guide.</seealso>.</p> + typically extracted from <c>ConfigDB</c>, and matches each + <c>FakeName</c> with <c>RequestURI</c>. If a match is found + <c>FakeName</c> is replaced with <c>RealName</c> in the + match. If the resulting match is not an executable script + <c>not_a_script</c> is returned. If it is a script the + resulting script path is in two parts, that is + <c>ShortPath</c> and <c>AfterPath</c> as defined in <seealso marker="httpd_util#split_script_path">httpd_util:split_script_path/1</seealso>. + <c>config_db()</c> is the server config file in ETS table + format as described in <seealso marker="http_server">Inets Users Guide.</seealso>.</p> </desc> </func> </funcs> diff --git a/lib/inets/doc/src/mod_auth.xml b/lib/inets/doc/src/mod_auth.xml index 2134ebeeae..7801567862 100644 --- a/lib/inets/doc/src/mod_auth.xml +++ b/lib/inets/doc/src/mod_auth.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> @@ -32,8 +32,11 @@ <modulesummary>User authentication using text files, dets or mnesia database.</modulesummary> <description> <p>This module provides for basic user authentication using - textual files, dets databases as well as mnesia databases. </p> + textual files, dets databases as well as mnesia databases. </p> + + <marker id="add_user"></marker> </description> + <funcs> <func> <name>add_user(UserName, Options) -> true| {error, Reason}</name> @@ -55,12 +58,17 @@ <desc> <marker id="user_api"></marker> <marker id="add_user"></marker> - <p><c>add_user/2, add_user/5</c> and <c>add_user/6</c> adds a user to the user - database. If the operation is successful, this function returns - <c>true</c>. If an error occurs, <c>{error,Reason}</c> is returned. When <c>add_user/2</c> - is called the Password, UserData Port and Dir options is mandatory.</p> + <p><c>add_user/2, add_user/5</c> and <c>add_user/6</c> adds a + user to the user + database. If the operation is successful, this function returns + <c>true</c>. If an error occurs, <c>{error,Reason}</c> is returned. + When <c>add_user/2</c> is called the Password, + UserData Port and Dir options is mandatory.</p> + + <marker id="delete_user"></marker> </desc> </func> + <func> <name>delete_user(UserName,Options) -> true | {error, Reason}</name> <name>delete_user(UserName, Port, Dir) -> true | {error, Reason}</name> @@ -79,13 +87,16 @@ <desc> <marker id="delete_user"></marker> <p><c>delete_user/2, delete_user/3</c> and <c>delete_user/4</c> - deletes a user - from the user database. If the operation is successful, this - function returns <c>true</c>. If an error occurs, - <c>{error,Reason}</c> is returned. When <c>delete_user/2</c> is - called the Port and Dir options are mandatory.</p> + deletes a user from the user database. + If the operation is successful, this function returns <c>true</c>. + If an error occurs, <c>{error,Reason}</c> is returned. + When <c>delete_user/2</c> is called the Port and Dir options + are mandatory.</p> + + <marker id="get_user"></marker> </desc> </func> + <func> <name>get_user(UserName,Options) -> {ok, #httpd_user} |{error, Reason}</name> <name>get_user(UserName, Port, Dir) -> {ok, #httpd_user} | {error, Reason}</name> @@ -104,12 +115,15 @@ <desc> <marker id="get_user"></marker> <p><c>get_user/2, get_user/3</c> and <c>get_user/4</c> returns a - <c>httpd_user</c> record containing the userdata for a - specific user. If the user cannot be found, <c>{error, Reason}</c> - is returned. When <c>get_user/2</c> is called the Port and Dir - options are mandatory.</p> + <c>httpd_user</c> record containing the userdata for a + specific user. If the user cannot be found, <c>{error, Reason}</c> + is returned. When <c>get_user/2</c> is called the Port and Dir + options are mandatory.</p> + + <marker id="list_users"></marker> </desc> </func> + <func> <name>list_users(Options) -> {ok, Users} | {error, Reason}</name> <name>list_users(Port, Dir) -> {ok, Users} | {error, Reason}</name> @@ -127,12 +141,16 @@ </type> <desc> <marker id="list_users"></marker> - <p><c>list_users/1, list_users/2</c> and <c>list_users/3</c> returns a list - of users in the user database for a specific <c>Port/Dir</c>. - When <c>list_users/1</c> is called the Port and Dir - options are mandatory.</p> + <p><c>list_users/1, list_users/2</c> and <c>list_users/3</c> + returns a list + of users in the user database for a specific <c>Port/Dir</c>. + When <c>list_users/1</c> is called the Port and Dir + options are mandatory.</p> + + <marker id="add_group_member"></marker> </desc> </func> + <func> <name>add_group_member(GroupName, UserName, Options) -> true | {error, Reason}</name> <name>add_group_member(GroupName, UserName, Port, Dir) -> true | {error, Reason}</name> @@ -151,13 +169,18 @@ </type> <desc> <marker id="add_group_member"></marker> - <p><c>add_group_member/3, add_group_member/4</c> and <c>add_group_member/5</c> - adds a user to a group. If the group does not exist, it - is created and the user is added to the group. Upon successful - operation, this function returns <c>true</c>. When <c>add_group_members/3</c> - is called the Port and Dir options are mandatory.</p> + <p><c>add_group_member/3, add_group_member/4</c> and + <c>add_group_member/5</c> + adds a user to a group. If the group does not exist, it + is created and the user is added to the group. Upon successful + operation, this function returns <c>true</c>. + When <c>add_group_members/3</c> + is called the Port and Dir options are mandatory.</p> + + <marker id="delete_group_member"></marker> </desc> </func> + <func> <name>delete_group_member(GroupName, UserName, Options) -> true | {error, Reason}</name> <name>delete_group_member(GroupName, UserName, Port, Dir) -> true | {error, Reason}</name> @@ -176,13 +199,17 @@ </type> <desc> <marker id="delete_group_member"></marker> - <p><c>delete_group_member/3, delete_group_member/4</c> and <c>delete_group_member/5</c> deletes a user from a group. - If the group or the user does not exist, - this function returns an error, otherwise it returns <c>true</c>. - When <c>delete_group_member/3</c> is called the Port and Dir options - are mandatory.</p> + <p><c>delete_group_member/3, delete_group_member/4</c> and + <c>delete_group_member/5</c> deletes a user from a group. + If the group or the user does not exist, + this function returns an error, otherwise it returns <c>true</c>. + When <c>delete_group_member/3</c> is called the Port and Dir options + are mandatory.</p> + + <marker id="list_group_members"></marker> </desc> </func> + <func> <name>list_group_members(GroupName, Options) -> {ok, Users} | {error, Reason}</name> <name>list_group_members(GroupName, Port, Dir) -> {ok, Users} | {error, Reason}</name> @@ -201,13 +228,17 @@ </type> <desc> <marker id="list_group_members"></marker> - <p><c>list_group_members/2, list_group_members/3</c> and <c>list_group_members/4</c> - lists the members of a specified group. If the group does not - exist or there is an error, <c>{error, Reason}</c> is returned. - When <c>list_group_members/2</c> is called the Port and Dir options - are mandatory.</p> + <p><c>list_group_members/2, list_group_members/3</c> and + <c>list_group_members/4</c> + lists the members of a specified group. If the group does not + exist or there is an error, <c>{error, Reason}</c> is returned. + When <c>list_group_members/2</c> is called the Port and Dir options + are mandatory.</p> + + <marker id="list_groups"></marker> </desc> </func> + <func> <name>list_groups(Options) -> {ok, Groups} | {error, Reason}</name> <name>list_groups(Port, Dir) -> {ok, Groups} | {error, Reason}</name> @@ -225,12 +256,16 @@ </type> <desc> <marker id="list_groups"></marker> - <p><c>list_groups/1, list_groups/2</c> and <c>list_groups/3</c> lists all - the groups available. If there is an error, <c>{error, Reason}</c> - is returned. When <c>list_groups/1</c> is called the Port and Dir options - are mandatory.</p> + <p><c>list_groups/1, list_groups/2</c> and <c>list_groups/3</c> + lists all the groups available. + If there is an error, <c>{error, Reason}</c> is returned. + When <c>list_groups/1</c> is called the Port and Dir options + are mandatory.</p> + + <marker id="delete_group"></marker> </desc> </func> + <func> <name>delete_group(GroupName, Options) -> true | {error,Reason} <name>delete_group(GroupName, Port, Dir) -> true | {error, Reason}</name> <name>delete_group(GroupName, Address, Port, Dir) -> true | {error, Reason}</name> @@ -247,12 +282,16 @@ </type> <desc> <marker id="delete_group"></marker> - <p><c>delete_group/2, delete_group/3</c> and <c>delete_group/4</c> deletes the - group specified and returns <c>true</c>. If there is an error, - <c>{error, Reason}</c> is returned. When <c>delete_group/2</c> is called the - Port and Dir options are mandatory.</p> + <p><c>delete_group/2, delete_group/3</c> and <c>delete_group/4</c> + deletes the group specified and returns <c>true</c>. + If there is an error, <c>{error, Reason}</c> is returned. + When <c>delete_group/2</c> is called the + Port and Dir options are mandatory.</p> + + <marker id="update_password"></marker> </desc> </func> + <func> <name>update_password(Port, Dir, OldPassword, NewPassword, NewPassword) -> ok | {error, Reason}</name> <name>update_password(Address,Port, Dir, OldPassword, NewPassword, NewPassword) -> ok | {error, Reason}</name> @@ -268,10 +307,12 @@ </type> <desc> <marker id="update_password"></marker> - <p><c>update_password/5</c> and <c>update_password/6</c> Updates the AuthAccessPassword - for the specified directory. If NewPassword is equal to "NoPassword" no password is requires to - change authorisation data. If NewPassword is equal to "DummyPassword" no changes can be done - without changing the password first.</p> + <p><c>update_password/5</c> and <c>update_password/6</c> + Updates the AuthAccessPassword for the specified directory. + If NewPassword is equal to "NoPassword" no password is requires to + change authorisation data. + If NewPassword is equal to "DummyPassword" no changes can be done + without changing the password first.</p> </desc> </func> </funcs> diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index cfc58b8ddb..dfdeb4016c 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -33,6 +33,96 @@ </header> + <section><title>Inets 5.9</title> + + <section><title>Improvements and New Features</title> +<!-- + <p>-</p> +--> + + <list> + <item> + <p>[httpd] Make the server header configurable with new config + option + <seealso marker="httpd#prop_server_tokens">server_tokens</seealso>. + The value of the server header, which was previously hard-coded + (at compile time), is now possible to manipulate through the means + of the + <seealso marker="httpd#prop_server_tokens">server_tokens</seealso> + config option. </p> + <p>Own Id: OTP-9805</p> + </item> + + <item> + <p>Improve inets support for inets as an included application. </p> + <p><c>inets_app</c> calls <c>supervisor:start_link/3</c> directly + rather than calling the root supervisor function + <c>inets_sup:start_link/0</c>. + This precludes using included_applications to start inets without + having a wrapper function. </p> + <p>Jay Nelson</p> + <p>Own Id: OTP-9960</p> + </item> + + <item> + <p>[httpc] Add function for retrieving current options, + <seealso marker="httpc#get_options">get_options/1,2</seealso>. </p> + <p>Own Id: OTP-9979</p> + </item> + + <item> + <p>Utility module + <seealso marker="http_uri">http_uri</seealso> + now officially supported. </p> + <p>Also, the + <seealso marker="http_uri#parse">parse</seealso> + function has been extended with more + scheme support and a way to provide your own scheme info. </p> + <p>Own Id: OTP-9983</p> + <p>Aux Id: Seq 12022</p> + </item> + + </list> + + </section> + + <section><title>Fixed Bugs and Malfunctions</title> + <p>-</p> + +<!-- + <list> + <item> + <p>[httpd] Fix logging of content length in mod_log. </p> + <p>Garrett Smith</p> + <p>Own Id: OTP-9715</p> + </item> + + </list> +--> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + +<!-- + <list> + <item> + <p>[httpc|httpd] The old ssl implementation (based on OpenSSL), + has been deprecated. The config option that specified usage of + this version of the ssl app, <c>ossl</c>, has been removed. </p> + <p>Own Id: OTP-9522</p> + </item> + + </list> +--> + + </section> + + </section> <!-- 5.9 --> + + <section><title>Inets 5.8.1</title> <section><title>Improvements and New Features</title> <p>-</p> @@ -417,7 +507,7 @@ <p><c>ossl</c> will work for as long as the ssl application supports it. </p> <p>See the httpd - <seealso marker="httpd#comm_prop">socket_type</seealso> + <seealso marker="httpd#props_comm">socket_type</seealso> communication property or the httpc <seealso marker="httpc#request2">request/4,5</seealso> function for more info. </p> @@ -436,7 +526,7 @@ <list> <item> <p>[httpd] Wrong - <seealso marker="httpd#sec_prop">security property</seealso> + <seealso marker="httpd#props_sec">security property</seealso> names used in documentation. </p> <p><c>security_data_file</c> used instead of <c>data_file</c>. </p> <p><c>security_max_retries</c> used instead of <c>max_retries</c>. </p> @@ -620,7 +710,7 @@ the <c>essl</c> tag instead. </p> <p>See the <c>http_option</c> option in the <seealso marker="httpc#request2">request/4,5</seealso> or - the <seealso marker="httpd#comm_prop">socket-type</seealso> + the <seealso marker="httpd#props_comm">socket-type</seealso> section of the Communication properties chapter for more info, </p> <p>Own Id: OTP-7907</p> </item> @@ -637,9 +727,9 @@ <p>[httpd] - Improved mod_alias. Now able to do better URL rewrites. </p> <p>See - <seealso marker="httpd#alias_prop">URL aliasing properties</seealso> + <seealso marker="httpd#props_alias">URL aliasing properties</seealso> and the - <seealso marker="httpd#cgi_prop">CGI properties</seealso> + <seealso marker="httpd#props_cgi">CGI properties</seealso> section(s) for more info, </p> <p>Own Id: OTP-8573</p> </item> @@ -1225,7 +1315,7 @@ <p>Default is <c>inet6fb4</c> which emulates the behaviour of the previous version. </p> <p>See the - <seealso marker="httpd#comm_prop">Communication properties</seealso> + <seealso marker="httpd#props_comm">Communication properties</seealso> section for more info. </p> <p>Own Id: OTP-8069</p> <p>Aux Id: seq11086</p> diff --git a/lib/inets/doc/src/notes_history.xml b/lib/inets/doc/src/notes_history.xml index 151bec375e..bd59c1ba47 100644 --- a/lib/inets/doc/src/notes_history.xml +++ b/lib/inets/doc/src/notes_history.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> <header> <copyright> - <year>2004</year><year>2011</year> + <year>2004</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/inets/doc/src/part.xml b/lib/inets/doc/src/part.xml index 36955df6b3..3b6734a9b8 100644 --- a/lib/inets/doc/src/part.xml +++ b/lib/inets/doc/src/part.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE part SYSTEM "part.dtd"> <part xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>2004</year><year>2009</year> + <year>2004</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/inets/doc/src/part_notes.xml b/lib/inets/doc/src/part_notes.xml index 21f464318b..81b0dedbfa 100644 --- a/lib/inets/doc/src/part_notes.xml +++ b/lib/inets/doc/src/part_notes.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE part SYSTEM "part.dtd"> <part xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>2002</year><year>2009</year> + <year>2002</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/inets/doc/src/part_notes_history.xml b/lib/inets/doc/src/part_notes_history.xml index 3c1e6f5232..f714a6d2e3 100644 --- a/lib/inets/doc/src/part_notes_history.xml +++ b/lib/inets/doc/src/part_notes_history.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE part SYSTEM "part.dtd"> <part> <header> <copyright> - <year>2004</year><year>2009</year> + <year>2004</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/inets/doc/src/ref_man.xml b/lib/inets/doc/src/ref_man.xml index 45d5dfcd0e..e44829827c 100644 --- a/lib/inets/doc/src/ref_man.xml +++ b/lib/inets/doc/src/ref_man.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE application SYSTEM "application.dtd"> <application xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>1997</year><year>2010</year> + <year>1997</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -30,8 +30,8 @@ </header> <description> <p>Inets is a container for Internet clients and - servers. Currently a FTP client, a HTTP client and server, and - a tftp client and server has been incorporated in Inets.</p> + servers. Currently a FTP client, a HTTP client and server, and + a tftp client and server has been incorporated in Inets.</p> </description> <xi:include href="inets.xml"/> <xi:include href="ftp.xml"/> @@ -45,6 +45,7 @@ <xi:include href="mod_auth.xml"/> <xi:include href="mod_esi.xml"/> <xi:include href="mod_security.xml"/> + <xi:include href="http_uri.xml"/> </application> diff --git a/lib/inets/doc/src/tftp.xml b/lib/inets/doc/src/tftp.xml index 96d6ae0dd5..0b3e93a153 100644 --- a/lib/inets/doc/src/tftp.xml +++ b/lib/inets/doc/src/tftp.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> <header> <copyright> - <year>2006</year><year>2009</year> + <year>2006</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -218,6 +218,8 @@ <c>5</c> times when the timeout expires.</p> </item> </taglist> + + <marker id="start1"></marker> </section> <funcs> @@ -231,11 +233,14 @@ </type> <desc> <p>Starts a daemon process which listens for udp packets on a - port. When it receives a request for read or write it spawns - a temporary server process which handles the actual transfer - of the (virtual) file.</p> + port. When it receives a request for read or write it spawns + a temporary server process which handles the actual transfer + of the (virtual) file.</p> + + <marker id="read_file"></marker> </desc> </func> + <func> <name>read_file(RemoteFilename, LocalFilename, Options) -> {ok, LastCallbackState} | {error, Reason}</name> <fsummary>Read a (virtual) file from a TFTP server</fsummary> @@ -248,23 +253,26 @@ </type> <desc> <p>Reads a (virtual) file <c>RemoteFilename</c> from a TFTP - server.</p> - <p>If <c>LocalFilename</c> is the atom <c>binary</c>, - <c>tftp_binary</c> is used as callback module. It concatenates - all transferred blocks and returns them as one single binary - in <c>LastCallbackState</c>.</p> - <p>If <c>LocalFilename</c> is a string and there are no - registered callback modules, <c>tftp_file</c> is used as - callback module. It writes each transferred block to the file - named <c>LocalFilename</c> and returns the number of - transferred bytes in <c>LastCallbackState</c>.</p> - <p>If <c>LocalFilename</c> is a string and there are registered - callback modules, <c>LocalFilename</c> is tested against - the regexps of these and the callback module corresponding to - the first match is used, or an error tuple is returned if no - matching regexp is found.</p> + server.</p> + <p>If <c>LocalFilename</c> is the atom <c>binary</c>, + <c>tftp_binary</c> is used as callback module. It concatenates + all transferred blocks and returns them as one single binary + in <c>LastCallbackState</c>.</p> + <p>If <c>LocalFilename</c> is a string and there are no + registered callback modules, <c>tftp_file</c> is used as + callback module. It writes each transferred block to the file + named <c>LocalFilename</c> and returns the number of + transferred bytes in <c>LastCallbackState</c>.</p> + <p>If <c>LocalFilename</c> is a string and there are registered + callback modules, <c>LocalFilename</c> is tested against + the regexps of these and the callback module corresponding to + the first match is used, or an error tuple is returned if no + matching regexp is found.</p> </desc> + + <marker id="write_file"></marker> </func> + <func> <name>write_file(RemoteFilename, LocalFilename, Options) -> {ok, LastCallbackState} | {error, Reason}</name> <fsummary>Write a (virtual) file to a TFTP server</fsummary> @@ -288,10 +296,12 @@ block by block and returns the number of transferred bytes in <c>LastCallbackState</c>.</p> <p>If <c>LocalFilename</c> is a string and there are registered - callback modules, <c>LocalFilename</c> is tested against - the regexps of these and the callback module corresponding to - the first match is used, or an error tuple is returned if no - matching regexp is found.</p> + callback modules, <c>LocalFilename</c> is tested against + the regexps of these and the callback module corresponding to + the first match is used, or an error tuple is returned if no + matching regexp is found.</p> + + <marker id="info_daemons"></marker> </desc> </func> @@ -304,8 +314,9 @@ <v>Reason = term()</v> </type> <desc> - <p>Returns info about all TFTP daemon processes. - </p> + <p>Returns info about all TFTP daemon processes. </p> + + <marker id="info_servers"></marker> </desc> </func> @@ -318,8 +329,9 @@ <v>Reason = term()</v> </type> <desc> - <p>Returns info about all TFTP server processes. - </p> + <p>Returns info about all TFTP server processes. </p> + + <marker id="info_pid"></marker> </desc> </func> @@ -332,6 +344,8 @@ </type> <desc> <p>Returns info about a TFTP daemon, server or client process.</p> + + <marker id="change_config_daemons"></marker> </desc> </func> @@ -346,8 +360,9 @@ <v>Reason = term()</v> </type> <desc> - <p>Changes config for all TFTP daemon processes - </p> + <p>Changes config for all TFTP daemon processes. </p> + + <marker id="change_config_servers"></marker> </desc> </func> @@ -362,8 +377,9 @@ <v>Reason = term()</v> </type> <desc> - <p>Changes config for all TFTP server processes - </p> + <p>Changes config for all TFTP server processes. </p> + + <marker id="change_config_pid"></marker> </desc> </func> @@ -378,8 +394,11 @@ </type> <desc> <p>Changes config for a TFTP daemon, server or client process</p> + + <marker id="start2"></marker> </desc> </func> + <func> <name>start() -> ok | {error, Reason}</name> <fsummary>Start the Inets application</fsummary> @@ -442,8 +461,9 @@ by the already ongoing connection on the server side. By not setting up yet another connection, in parallel with the ongoing one, the server will - consumer lesser resources. - </p> + consumer lesser resources. </p> + + <marker id="prepare"></marker> </section> <funcs> @@ -468,17 +488,20 @@ <v>Text = string()</v> </type> <desc> - <p>Prepares to open a file on the client side.</p> - <p>No new options may be added, but the ones that are present in - <c>SuggestedOptions</c> may be omitted or replaced with new - values in <c>AcceptedOptions</c>.</p> - <p>Will be followed by a call to <c>open/4</c> before any - read/write access is performed. <c>AcceptedOptions</c> is - sent to the server which replies with those options that it - accepts. These will be forwarded to <c>open/4</c> as - <c>SuggestedOptions</c>.</p> + <p>Prepares to open a file on the client side.</p> + <p>No new options may be added, but the ones that are present in + <c>SuggestedOptions</c> may be omitted or replaced with new + values in <c>AcceptedOptions</c>.</p> + <p>Will be followed by a call to <c>open/4</c> before any + read/write access is performed. <c>AcceptedOptions</c> is + sent to the server which replies with those options that it + accepts. These will be forwarded to <c>open/4</c> as + <c>SuggestedOptions</c>.</p> + + <marker id="open"></marker> </desc> </func> + <func> <name>open(Peer, Access, Filename, Mode, SuggestedOptions, State) -> {ok, AcceptedOptions, NewState} | {error, {Code, Text}}</name> <fsummary>Open a file for read or write access</fsummary> @@ -503,14 +526,17 @@ <desc> <p>Opens a file for read or write access.</p> <p>On the client side where the <c>open/5</c> call has been - preceded by a call to <c>prepare/5</c>, all options must be - accepted or rejected.</p> - <p>On the server side, where there is no preceding - <c>prepare/5</c> call, no new options may be added, but - the ones that are present in <c>SuggestedOptions</c> may be - omitted or replaced with new values in <c>AcceptedOptions</c>.</p> + preceded by a call to <c>prepare/5</c>, all options must be + accepted or rejected.</p> + <p>On the server side, where there is no preceding + <c>prepare/5</c> call, no new options may be added, but + the ones that are present in <c>SuggestedOptions</c> may be + omitted or replaced with new values in <c>AcceptedOptions</c>.</p> + + <marker id="read"></marker> </desc> </func> + <func> <name>read(State) -> {more, Bin, NewState} | {last, Bin, FileSize} | {error, {Code, Text}}</name> <fsummary>Read a chunk from the file</fsummary> @@ -526,15 +552,18 @@ <desc> <p>Read a chunk from the file.</p> <p>The callback function is expected to close - the file when the last file chunk is - encountered. When an error is encountered - the callback function is expected to clean - up after the aborted file transfer, such as - closing open file descriptors etc. In both - cases there will be no more calls to any of - the callback functions.</p> + the file when the last file chunk is + encountered. When an error is encountered + the callback function is expected to clean + up after the aborted file transfer, such as + closing open file descriptors etc. In both + cases there will be no more calls to any of + the callback functions.</p> + + <marker id="write"></marker> </desc> </func> + <func> <name>write(Bin, State) -> {more, NewState} | {last, FileSize} | {error, {Code, Text}}</name> <fsummary>Write a chunk to the file</fsummary> @@ -550,15 +579,18 @@ <desc> <p>Write a chunk to the file.</p> <p>The callback function is expected to close - the file when the last file chunk is - encountered. When an error is encountered - the callback function is expected to clean - up after the aborted file transfer, such as - closing open file descriptors etc. In both - cases there will be no more calls to any of - the callback functions.</p> + the file when the last file chunk is + encountered. When an error is encountered + the callback function is expected to clean + up after the aborted file transfer, such as + closing open file descriptors etc. In both + cases there will be no more calls to any of + the callback functions.</p> + + <marker id="abort"></marker> </desc> </func> + <func> <name>abort(Code, Text, State) -> ok</name> <fsummary>Abort the file transfer</fsummary> @@ -572,14 +604,14 @@ <desc> <p>Invoked when the file transfer is aborted.</p> <p>The callback function is expected to clean - up its used resources after the aborted file - transfer, such as closing open file - descriptors etc. The function will not be - invoked if any of the other callback - functions returns an error, as it is - expected that they already have cleaned up - the necessary resources. It will however be - invoked if the functions fails (crashes).</p> + up its used resources after the aborted file + transfer, such as closing open file + descriptors etc. The function will not be + invoked if any of the other callback + functions returns an error, as it is + expected that they already have cleaned up + the necessary resources. It will however be + invoked if the functions fails (crashes).</p> </desc> </func> </funcs> @@ -589,7 +621,9 @@ <title>LOGGER FUNCTIONS</title> <p>A <c>tftp_logger</c> callback module should be implemented as a - <c>tftp_logger</c> behavior and export the functions listed below.</p> + <c>tftp_logger</c> behavior and export the functions listed below.</p> + + <marker id="error_msg"></marker> </section> <funcs> @@ -602,7 +636,10 @@ <v>Reason = term()</v> </type> <desc> - <p>Log an error message. See <c>error_logger:error_msg/2 for details.</c> </p> + <p>Log an error message. + See <c>error_logger:error_msg/2 for details.</c> </p> + + <marker id="warning_msg"></marker> </desc> </func> @@ -615,7 +652,10 @@ <v>Reason = term()</v> </type> <desc> - <p>Log a warning message. See <c>error_logger:warning_msg/2 for details.</c> </p> + <p>Log a warning message. + See <c>error_logger:warning_msg/2 for details.</c> </p> + + <marker id="info_msg"></marker> </desc> </func> @@ -628,7 +668,8 @@ <v>Reason = term()</v> </type> <desc> - <p>Log an info message. See <c>error_logger:info_msg/2 for details.</c> </p> + <p>Log an info message. + See <c>error_logger:info_msg/2 for details.</c> </p> </desc> </func> </funcs> diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl index ae87ceed93..0a30fe1e20 100644 --- a/lib/inets/src/http_client/httpc.erl +++ b/lib/inets/src/http_client/httpc.erl @@ -31,8 +31,10 @@ -export([ request/1, request/2, request/4, request/5, cancel_request/1, cancel_request/2, - set_option/2, set_option/3, + set_option/2, set_option/3, set_options/1, set_options/2, + get_option/1, get_option/2, + get_options/1, get_options/2, store_cookies/2, store_cookies/3, cookie_header/1, cookie_header/2, cookie_header/3, which_cookies/0, which_cookies/1, @@ -156,7 +158,7 @@ request(Method, {http_options, HTTPOptions}, {options, Options}, {profile, Profile}]), - case http_uri:parse(Url, Options) of + case uri_parse(Url, Options) of {error, Reason} -> {error, Reason}; {ok, ParsedUrl} -> @@ -177,7 +179,7 @@ request(Method, {http_options, HTTPOptions}, {options, Options}, {profile, Profile}]), - case http_uri:parse(Url, Options) of + case uri_parse(Url, Options) of {error, Reason} -> {error, Reason}; {ok, ParsedUrl} -> @@ -230,7 +232,7 @@ cancel_request(RequestId, Profile) set_options(Options) -> set_options(Options, default_profile()). set_options(Options, Profile) when is_atom(Profile) orelse is_pid(Profile) -> - ?hcrt("set cookies", [{options, Options}, {profile, Profile}]), + ?hcrt("set options", [{options, Options}, {profile, Profile}]), case validate_options(Options) of {ok, Opts} -> try @@ -253,6 +255,58 @@ set_option(Key, Value, Profile) -> %%-------------------------------------------------------------------------- +%% get_options(OptionItems) -> {ok, Values} | {error, Reason} +%% get_options(OptionItems, Profile) -> {ok, Values} | {error, Reason} +%% OptionItems - all | [option_item()] +%% option_item() - proxy | pipeline_timeout | max_pipeline_length | +%% keep_alive_timeout | max_keep_alive_length | +%% max_sessions | verbose | +%% cookies | ipfamily | ip | port | socket_opts +%% Profile - atom() +%% Values - [{option_item(), term()}] +%% Reason - term() +%% Description: Retrieves the current options. +%%------------------------------------------------------------------------- +get_options() -> + record_info(fields, options). + +get_options(Options) -> + get_options(Options, default_profile()). + +get_options(all = _Options, Profile) -> + get_options(get_options(), Profile); +get_options(Options, Profile) + when (is_list(Options) andalso + (is_atom(Profile) orelse is_pid(Profile))) -> + ?hcrt("get options", [{options, Options}, {profile, Profile}]), + case Options -- get_options() of + [] -> + try + begin + {ok, httpc_manager:get_options(Options, + profile_name(Profile))} + end + catch + exit:{noproc, _} -> + {error, inets_not_started} + end; + InvalidGetOptions -> + {error, {invalid_options, InvalidGetOptions}} + end. + +get_option(Key) -> + get_option(Key, default_profile()). + +get_option(Key, Profile) -> + case get_options([Key], Profile) of + {ok, [{Key, Value}]} -> + {ok, Value}; + Error -> + Error + end. + + +%%-------------------------------------------------------------------------- %% store_cookies(SetCookieHeaders, Url [, Profile]) -> ok | {error, reason} %% %% @@ -274,7 +328,7 @@ store_cookies(SetCookieHeaders, Url, Profile) %% Since the Address part is not actually used %% by the manager when storing cookies, we dont %% care about ipv6-host-with-brackets. - {ok, {_, _, Host, Port, Path, _}} = http_uri:parse(Url), + {ok, {_, _, Host, Port, Path, _}} = uri_parse(Url), Address = {Host, Port}, ProfileName = profile_name(Profile), Cookies = httpc_cookie:cookies(SetCookieHeaders, Path, Host), @@ -347,7 +401,7 @@ which_cookies(Profile) -> %% info() -> list() %% info(Profile) -> list() %% -%% Description: Debug function, retreive info about the profile +%% Description: Debug function, retrieve info about the profile %%------------------------------------------------------------------------- info() -> info(default_profile()). @@ -1144,6 +1198,22 @@ validate_headers(RequestHeaders, _, _) -> RequestHeaders. +%%-------------------------------------------------------------------------- +%% These functions is just simple wrappers to parse specifically HTTP URIs +%%-------------------------------------------------------------------------- + +scheme_defaults() -> + [{http, 80}, {https, 443}]. + +uri_parse(URI) -> + http_uri:parse(URI, [{scheme_defaults, scheme_defaults()}]). + +uri_parse(URI, Opts) -> + http_uri:parse(URI, [{scheme_defaults, scheme_defaults()} | Opts]). + + +%%-------------------------------------------------------------------------- + child_name2info(undefined) -> {error, no_such_service}; child_name2info(httpc_manager) -> diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl index bfe9b14ef6..b8c34bd99b 100644 --- a/lib/inets/src/http_client/httpc_handler.erl +++ b/lib/inets/src/http_client/httpc_handler.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2011. All Rights Reserved. +%% Copyright Ericsson AB 2002-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 @@ -851,14 +851,17 @@ connect(SocketType, ToAddress, case IpFamily of inet6fb4 -> Opts3 = [inet6 | Opts2], - case http_transport:connect(SocketType, ToAddress, Opts3, Timeout) of - {error, _Reason} = Error -> + case http_transport:connect(SocketType, + ToAddress, Opts3, Timeout) of + {error, Reason6} -> Opts4 = [inet | Opts2], case http_transport:connect(SocketType, ToAddress, Opts4, Timeout) of - {error, _} -> - %% Reply with the "original" error - Error; + {error, Reason4} -> + {error, {failed_connect, + [{to_address, ToAddress}, + {inet6, Opts3, Reason6}, + {inet, Opts4, Reason4}]}}; OK -> OK end; @@ -867,7 +870,13 @@ connect(SocketType, ToAddress, end; _ -> Opts3 = [IpFamily | Opts2], - http_transport:connect(SocketType, ToAddress, Opts3, Timeout) + case http_transport:connect(SocketType, ToAddress, Opts3, Timeout) of + {error, Reason} -> + {error, {failed_connect, [{to_address, ToAddress}, + {IpFamily, Opts3, Reason}]}}; + Else -> + Else + end end. connect_and_send_first_request(Address, Request, #state{options = Options} = State) -> diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl index 453081da21..b225b43214 100644 --- a/lib/inets/src/http_client/httpc_manager.erl +++ b/lib/inets/src/http_client/httpc_manager.erl @@ -37,6 +37,7 @@ update_session/4, delete_session/2, set_options/2, + get_options/2, store_cookies/3, which_cookies/1, which_cookies/2, which_cookies/3, reset_cookies/1, @@ -250,6 +251,21 @@ set_options(Options, ProfileName) -> %%-------------------------------------------------------------------- +%% Function: get_options(OptionItems, ProfileName) -> Values +%% +%% OptionItems = [OptionItem] +%% OptionItem = Any or all fields of the current #options{} record +%% Values = [{OptionItem, Value}] +%% Value = term() +%% +%% Description: Gets the specified options used by the client. +%%-------------------------------------------------------------------- + +get_options(Options, ProfileName) -> + call(ProfileName, {get_options, Options}). + + +%%-------------------------------------------------------------------- %% Function: store_cookies(Cookies, Address, ProfileName) -> ok %% %% Cookies = [Cookie] @@ -430,7 +446,7 @@ handle_call(which_cookies, _, #state{cookie_db = CookieDb} = State) -> handle_call({which_cookies, Url, Options}, _, #state{cookie_db = CookieDb} = State) -> ?hcrv("which cookies", [{url, Url}, {options, Options}]), - case http_uri:parse(Url, Options) of + case uri_parse(Url, Options) of {ok, {Scheme, _, Host, Port, Path, _}} -> CookieHeaders = httpc_cookie:header(CookieDb, Scheme, {Host, Port}, Path), @@ -439,6 +455,12 @@ handle_call({which_cookies, Url, Options}, _, {reply, ERROR, State} end; +handle_call({get_options, OptionItems}, _, #state{options = Options} = State) -> + ?hcrv("get options", [{option_items, OptionItems}]), + Reply = [{OptionItem, get_option(OptionItem, Options)} || OptionItem <- + OptionItems], + {reply, Reply, State}; + handle_call(info, _, State) -> ?hcrv("info", []), Info = get_manager_info(State), @@ -872,6 +894,19 @@ make_db_name(ProfileName, Post) -> list_to_atom(atom_to_list(ProfileName) ++ Post). +%%-------------------------------------------------------------------------- +%% These functions is just simple wrappers to parse specifically HTTP URIs +%%-------------------------------------------------------------------------- + +scheme_defaults() -> + [{http, 80}, {https, 443}]. + +uri_parse(URI, Opts) -> + http_uri:parse(URI, [{scheme_defaults, scheme_defaults()} | Opts]). + + +%%-------------------------------------------------------------------------- + call(ProfileName, Msg) -> Timeout = infinity, @@ -883,6 +918,31 @@ cast(ProfileName, Msg) -> gen_server:cast(ProfileName, Msg). +get_option(proxy, #options{proxy = Proxy}) -> + Proxy; +get_option(pipeline_timeout, #options{pipeline_timeout = Timeout}) -> + Timeout; +get_option(max_pipeline_length, #options{max_pipeline_length = Length}) -> + Length; +get_option(keep_alive_timeout, #options{keep_alive_timeout = Timeout}) -> + Timeout; +get_option(max_keep_alive_length, #options{max_keep_alive_length = Length}) -> + Length; +get_option(max_sessions, #options{max_sessions = MaxSessions}) -> + MaxSessions; +get_option(cookies, #options{cookies = Cookies}) -> + Cookies; +get_option(verbose, #options{verbose = Verbose}) -> + Verbose; +get_option(ipfamily, #options{ipfamily = IpFamily}) -> + IpFamily; +get_option(ip, #options{ip = IP}) -> + IP; +get_option(port, #options{port = Port}) -> + Port; +get_option(socket_opts, #options{socket_opts = SocketOpts}) -> + SocketOpts. + get_proxy(Opts, #options{proxy = Default}) -> proplists:get_value(proxy, Opts, Default). diff --git a/lib/inets/src/http_client/httpc_response.erl b/lib/inets/src/http_client/httpc_response.erl index 919115a23a..23924e355e 100644 --- a/lib/inets/src/http_client/httpc_response.erl +++ b/lib/inets/src/http_client/httpc_response.erl @@ -342,7 +342,7 @@ redirect(Response = {StatusLine, Headers, Body}, Request) -> RedirUrl -> UrlParseOpts = [{ipv6_host_with_brackets, Request#request.ipv6_host_with_brackets}], - case http_uri:parse(RedirUrl, UrlParseOpts) of + case uri_parse(RedirUrl, UrlParseOpts) of {error, no_scheme} when (Request#request.settings)#http_options.relaxed -> NewLocation = fix_relative_uri(Request, RedirUrl), @@ -437,3 +437,17 @@ format_response({StatusLine, Headers, Body}) -> end, {{StatusLine, http_response:header_list(Headers), NewBody}, Data}. +%%-------------------------------------------------------------------------- +%% These functions is just simple wrappers to parse specifically HTTP URIs +%%-------------------------------------------------------------------------- + +scheme_defaults() -> + [{http, 80}, {https, 443}]. + +uri_parse(URI, Opts) -> + http_uri:parse(URI, [{scheme_defaults, scheme_defaults()} | Opts]). + + +%%-------------------------------------------------------------------------- + + diff --git a/lib/inets/src/http_lib/http_uri.erl b/lib/inets/src/http_lib/http_uri.erl index 32c6305a79..5962001c3a 100644 --- a/lib/inets/src/http_lib/http_uri.erl +++ b/lib/inets/src/http_lib/http_uri.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2011. All Rights Reserved. +%% Copyright Ericsson AB 2006-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 @@ -17,39 +17,95 @@ %% %CopyrightEnd% %% %% -%% RFC 3986 +%% This is from chapter 3, Syntax Components, of RFC 3986: +%% +%% The generic URI syntax consists of a hierarchical sequence of +%% components referred to as the scheme, authority, path, query, and +%% fragment. +%% +%% URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] +%% +%% hier-part = "//" authority path-abempty +%% / path-absolute +%% / path-rootless +%% / path-empty +%% +%% The scheme and path components are required, though the path may be +%% empty (no characters). When authority is present, the path must +%% either be empty or begin with a slash ("/") character. When +%% authority is not present, the path cannot begin with two slash +%% characters ("//"). These restrictions result in five different ABNF +%% rules for a path (Section 3.3), only one of which will match any +%% given URI reference. +%% +%% The following are two example URIs and their component parts: +%% +%% foo://example.com:8042/over/there?name=ferret#nose +%% \_/ \______________/\_________/ \_________/ \__/ +%% | | | | | +%% scheme authority path query fragment +%% | _____________________|__ +%% / \ / \ +%% urn:example:animal:ferret:nose +%% +%% scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) +%% authority = [ userinfo "@" ] host [ ":" port ] +%% userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) +%% %% -module(http_uri). -export([parse/1, parse/2, + scheme_defaults/0, encode/1, decode/1]). +-export_type([scheme/0, default_scheme_port_number/0]). + %%%========================================================================= %%% API %%%========================================================================= + +-type scheme() :: atom(). +-type default_scheme_port_number() :: pos_integer(). + +-spec scheme_defaults() -> + [{scheme(), default_scheme_port_number()}]. + +scheme_defaults() -> + [{http, 80}, + {https, 443}, + {ftp, 21}, + {ssh, 22}, + {sftp, 22}, + {tftp, 69}]. + parse(AbsURI) -> parse(AbsURI, []). parse(AbsURI, Opts) -> - case parse_scheme(AbsURI) of + case parse_scheme(AbsURI, Opts) of {error, Reason} -> {error, Reason}; - {Scheme, Rest} -> - case (catch parse_uri_rest(Scheme, Rest, Opts)) of - {UserInfo, Host, Port, Path, Query} -> + {Scheme, DefaultPort, Rest} -> + case (catch parse_uri_rest(Scheme, DefaultPort, Rest, Opts)) of + {ok, {UserInfo, Host, Port, Path, Query}} -> {ok, {Scheme, UserInfo, Host, Port, Path, Query}}; + {error, Reason} -> + {error, {Reason, Scheme, AbsURI}}; _ -> - {error, {malformed_url, AbsURI}} + {error, {malformed_url, Scheme, AbsURI}} end end. +reserved() -> + sets:from_list([$;, $:, $@, $&, $=, $+, $,, $/, $?, + $#, $[, $], $<, $>, $\", ${, $}, $|, + $\\, $', $^, $%, $ ]). + encode(URI) -> - Reserved = sets:from_list([$;, $:, $@, $&, $=, $+, $,, $/, $?, - $#, $[, $], $<, $>, $\", ${, $}, $|, - $\\, $', $^, $%, $ ]), - %% lists:append(lists:map(fun(Char) -> uri_encode(Char, Reserved) end, URI)). + Reserved = reserved(), lists:append([uri_encode(Char, Reserved) || Char <- URI]). decode(String) -> @@ -67,20 +123,31 @@ do_decode([]) -> %%% Internal functions %%%======================================================================== -parse_scheme(AbsURI) -> +which_scheme_defaults(Opts) -> + Key = scheme_defaults, + case lists:keysearch(Key, 1, Opts) of + {value, {Key, SchemeDefaults}} -> + SchemeDefaults; + false -> + scheme_defaults() + end. + +parse_scheme(AbsURI, Opts) -> case split_uri(AbsURI, ":", {error, no_scheme}, 1, 1) of {error, no_scheme} -> {error, no_scheme}; - {StrScheme, Rest} -> - case list_to_atom(http_util:to_lower(StrScheme)) of - Scheme when (Scheme =:= http) orelse (Scheme =:= https) -> - {Scheme, Rest}; - Scheme -> - {error, {not_supported_scheme, Scheme}} + {SchemeStr, Rest} -> + Scheme = list_to_atom(http_util:to_lower(SchemeStr)), + SchemeDefaults = which_scheme_defaults(Opts), + case lists:keysearch(Scheme, 1, SchemeDefaults) of + {value, {Scheme, DefaultPort}} -> + {Scheme, DefaultPort, Rest}; + false -> + {Scheme, no_default_port, Rest} end end. -parse_uri_rest(Scheme, "//" ++ URIPart, Opts) -> +parse_uri_rest(Scheme, DefaultPort, "//" ++ URIPart, Opts) -> {Authority, PathQuery} = case split_uri(URIPart, "/", URIPart, 1, 0) of Split = {_, _} -> @@ -93,26 +160,25 @@ parse_uri_rest(Scheme, "//" ++ URIPart, Opts) -> {URIPart,""} end end, - {UserInfo, HostPort} = split_uri(Authority, "@", {"", Authority}, 1, 1), - {Host, Port} = parse_host_port(Scheme, HostPort, Opts), + {Host, Port} = parse_host_port(Scheme, DefaultPort, HostPort, Opts), {Path, Query} = parse_path_query(PathQuery), - {UserInfo, Host, Port, Path, Query}. + {ok, {UserInfo, Host, Port, Path, Query}}. parse_path_query(PathQuery) -> {Path, Query} = split_uri(PathQuery, "\\?", {PathQuery, ""}, 1, 0), {path(Path), Query}. -parse_host_port(Scheme,"[" ++ HostPort, Opts) -> %ipv6 - DefaultPort = default_port(Scheme), +%% In this version of the function, we no longer need +%% the Scheme argument, but just in case... +parse_host_port(_Scheme, DefaultPort, "[" ++ HostPort, Opts) -> %ipv6 {Host, ColonPort} = split_uri(HostPort, "\\]", {HostPort, ""}, 1, 1), Host2 = maybe_ipv6_host_with_brackets(Host, Opts), {_, Port} = split_uri(ColonPort, ":", {"", DefaultPort}, 0, 1), {Host2, int_port(Port)}; -parse_host_port(Scheme, HostPort, _Opts) -> - DefaultPort = default_port(Scheme), +parse_host_port(_Scheme, DefaultPort, HostPort, _Opts) -> {Host, Port} = split_uri(HostPort, ":", {HostPort, DefaultPort}, 1, 1), {Host, int_port(Port)}. @@ -133,15 +199,14 @@ maybe_ipv6_host_with_brackets(Host, Opts) -> Host end. -default_port(http) -> - 80; -default_port(https) -> - 443. int_port(Port) when is_integer(Port) -> Port; int_port(Port) when is_list(Port) -> - list_to_integer(Port). + list_to_integer(Port); +%% This is the case where no port was found and there was no default port +int_port(no_default_port) -> + throw({error, no_default_port}). path("") -> "/"; diff --git a/lib/inets/src/http_server/Makefile b/lib/inets/src/http_server/Makefile index 55cc68dede..c341a2cec7 100644 --- a/lib/inets/src/http_server/Makefile +++ b/lib/inets/src/http_server/Makefile @@ -88,6 +88,8 @@ ERL_FILES = $(MODULES:%=%.erl) TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) +INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' + # ---------------------------------------------------- # FLAGS diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl index 7646300409..b575d7331b 100644 --- a/lib/inets/src/http_server/httpd_conf.erl +++ b/lib/inets/src/http_server/httpd_conf.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-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 @@ -210,12 +210,32 @@ load("MaxBodySize " ++ MaxBodySize, []) -> {ok, Integer} -> {ok, [], {max_body_size,Integer}}; {error, _} -> - {error, ?NICE(clean(MaxBodySize)++ + {error, ?NICE(clean(MaxBodySize) ++ " is an invalid number of MaxBodySize")} end; load("ServerName " ++ ServerName, []) -> - {ok,[],{server_name,clean(ServerName)}}; + {ok,[], {server_name, clean(ServerName)}}; + +load("ServerTokens " ++ ServerTokens, []) -> + %% These are the valid *plain* server tokens: + %% sprod, major, minor, minimum, os, full + %% It can also be a "private" server token: private:<any string> + case string:tokens(ServerTokens, [$:]) of + ["private", Private] -> + {ok,[], {server_tokens, clean(Private)}}; + [TokStr] -> + Tok = list_to_atom(clean(TokStr)), + case lists:member(Tok, [prod, major, minor, minimum, os, full]) of + true -> + {ok,[], {server_tokens, Tok}}; + false -> + {error, ?NICE(clean(ServerTokens) ++ + " is an invalid ServerTokens")} + end; + _ -> + {error, ?NICE(clean(ServerTokens) ++ " is an invalid ServerTokens")} + end; load("SocketType " ++ SocketType, []) -> %% ssl is the same as HTTP_DEFAULT_SSL_KIND @@ -475,7 +495,7 @@ validate_properties(Properties) -> validate_properties2(Properties) -> case proplists:get_value(bind_address, Properties) of undefined -> - case proplists:get_value(sock_type, Properties, ip_comm) of + case proplists:get_value(sock_type, Properties, ip_comm) of ip_comm -> case proplists:get_value(ipfamily, Properties) of undefined -> @@ -537,6 +557,20 @@ validate_config_params([{server_name, Value} | Rest]) validate_config_params([{server_name, Value} | _]) -> throw({server_name, Value}); +validate_config_params([{server_tokens, Value} | Rest]) + when is_atom(Value) -> + case lists:member(Value, plain_server_tokens()) of + true -> + validate_config_params(Rest); + false -> + throw({server_tokens, Value}) + end; +validate_config_params([{server_tokens, {private, Value}} | Rest]) + when is_list(Value) -> + validate_config_params(Rest); +validate_config_params([{server_tokens, Value} | _]) -> + throw({server_tokens, Value}); + validate_config_params([{socket_type, Value} | Rest]) when (Value =:= ip_comm) orelse (Value =:= ssl) orelse @@ -737,9 +771,73 @@ store({log_format, LogFormat}, _ConfigList) store({log_format, LogFormat}, _ConfigList) when (LogFormat =:= compact) orelse (LogFormat =:= pretty) -> {ok, {log_format, LogFormat}}; +store({server_tokens, ServerTokens} = Entry, _ConfigList) -> + Server = server(ServerTokens), + {ok, [Entry, {server, Server}]}; store(ConfigListEntry, _ConfigList) -> {ok, ConfigListEntry}. + +%% The SERVER_SOFTWARE macro has the following structure: +%% <product>/<version> +%% Example: "inets/1.2.3" +%% So, with this example (on a linux machine, with OTP R15B), +%% this will result in: +%% prod: "inets" +%% major: "inets/1" +%% minor: "inets/1.2" +%% minimal: "inets/1.2.3" +%% os: "inets/1.2.3 (unix) +%% full: "inets/1.2.3 (unix/linux) OTP/R15B" +%% Note that the format of SERVER_SOFTWARE is that of 'minimal'. +%% Also, there will always be atleast two digits in a version: +%% Not just 1 but 1.0 +%% +%% We have already checked that the value is valid, +%% so there is no need to check enything here. +%% +server(prod = _ServerTokens) -> + [Prod|_Version] = string:tokens(?SERVER_SOFTWARE, [$/]), + Prod; +server(major = _ServerTokens) -> + [Prod|Version] = string:tokens(?SERVER_SOFTWARE, [$/]), + [Major|_] = string:tokens(Version, [$.]), + Prod ++ "/" ++ Major; +server(minor = _ServerTokens) -> + [Prod|Version] = string:tokens(?SERVER_SOFTWARE, [$/]), + [Major,Minor|_] = string:tokens(Version, [$.]), + Prod ++ "/" ++ Major ++ "." ++ Minor; +server(minimal = _ServerTokens) -> + %% This is the default + ?SERVER_SOFTWARE; +server(os = _ServerTokens) -> + OS = os_info(partial), + lists:flatten(io_lib:format("~s ~s", [?SERVER_SOFTWARE, OS])); +server(full = _ServerTokens) -> + OTPRelease = otp_release(), + OS = os_info(full), + lists:flatten( + io_lib:format("~s ~s OTP/~s", [?SERVER_SOFTWARE, OS, OTPRelease])); +server({private, Server} = _ServerTokens) when is_list(Server) -> + %% The user provide its own + Server; +server(_) -> + ?SERVER_SOFTWARE. + +os_info(Info) -> + case os:type() of + {OsFamily, _OsName} when Info =:= partial -> + lists:flatten(io_lib:format("(~w)", [OsFamily])); + {OsFamily, OsName} -> + lists:flatten(io_lib:format("(~w/~w)", [OsFamily, OsName])); + OsFamily -> + lists:flatten(io_lib:format("(~w)", [OsFamily])) + end. + +otp_release() -> + erlang:system_info(otp_release). + + %% Phase 3: Remove remove_all(ConfigDB) -> Modules = httpd_util:lookup(ConfigDB,modules,[]), @@ -1159,6 +1257,10 @@ ssl_ca_certificate_file(ConfigDB) -> [{cacertfile, File}] end. +plain_server_tokens() -> + [prod, major, minor, minimum, os, full]. + error_report(Where,M,F,Error) -> error_logger:error_report([{?MODULE, Where}, {apply, {M, F, []}}, Error]). + diff --git a/lib/inets/src/http_server/httpd_response.erl b/lib/inets/src/http_server/httpd_response.erl index dd7223876e..2dedb088e4 100644 --- a/lib/inets/src/http_server/httpd_response.erl +++ b/lib/inets/src/http_server/httpd_response.erl @@ -144,10 +144,14 @@ send_response(ModData, Header, Body) -> end end. -send_header(#mod{socket_type = Type, socket = Sock, - http_version = Ver, connection = Conn} = _ModData, +send_header(#mod{socket_type = Type, + socket = Sock, + http_version = Ver, + connection = Conn, + config_db = ConfigDb} = _ModData, StatusCode, KeyValueTupleHeaders) -> - Headers = create_header(lists:map(fun transform/1, KeyValueTupleHeaders)), + Headers = create_header(ConfigDb, + lists:map(fun transform/1, KeyValueTupleHeaders)), NewVer = case {Ver, StatusCode} of {[], _} -> %% May be implicit! @@ -275,13 +279,20 @@ cache_headers(#mod{config_db = Db}) -> [] end. -create_header(KeyValueTupleHeaders) -> - NewHeaders = add_default_headers([{"date", httpd_util:rfc1123_date()}, - {"content-type", "text/html"}, - {"server", ?SERVER_SOFTWARE}], - KeyValueTupleHeaders), +create_header(ConfigDb, KeyValueTupleHeaders) -> + Date = httpd_util:rfc1123_date(), + ContentType = "text/html", + Server = server(ConfigDb), + NewHeaders = add_default_headers([{"date", Date}, + {"content-type", ContentType}, + {"server", Server}], + KeyValueTupleHeaders), lists:map(fun fix_header/1, NewHeaders). + +server(ConfigDb) -> + httpd_util:lookup(ConfigDb, server, ?SERVER_SOFTWARE). + fix_header({Key0, Value}) -> %% make sure first letter is capital Words1 = string:tokens(Key0, "-"), diff --git a/lib/inets/src/http_server/httpd_script_env.erl b/lib/inets/src/http_server/httpd_script_env.erl index d3115150b0..a5613ba4a4 100644 --- a/lib/inets/src/http_server/httpd_script_env.erl +++ b/lib/inets/src/http_server/httpd_script_env.erl @@ -50,29 +50,44 @@ create_env(ScriptType, ModData, ScriptElements) -> %%%======================================================================== %%% Internal functions %%%======================================================================== + +which_server(#mod{config_db = ConfigDb}) -> + httpd_util:lookup(ConfigDb, server, ?SERVER_SOFTWARE). + +which_port(#mod{config_db = ConfigDb}) -> + httpd_util:lookup(ConfigDb, port, 80). + +which_peername(#mod{init_data = #init_data{peername = {_, RemoteAddr}}}) -> + RemoteAddr. + +which_resolve(#mod{init_data = #init_data{resolve = Resolve}}) -> + Resolve. + +which_method(#mod{method = Method}) -> + Method. + +which_request_uri(#mod{request_uri = RUri}) -> + RUri. + create_basic_elements(esi, ModData) -> - {_, RemoteAddr} = (ModData#mod.init_data)#init_data.peername, - [{server_software, ?SERVER_SOFTWARE}, - {server_name, (ModData#mod.init_data)#init_data.resolve}, - {gateway_interface,?GATEWAY_INTERFACE}, - {server_protocol, ?SERVER_PROTOCOL}, - {server_port, httpd_util:lookup(ModData#mod.config_db,port,80)}, - {request_method, ModData#mod.method}, - {remote_addr, RemoteAddr}, - {script_name, ModData#mod.request_uri}]; + [{server_software, which_server(ModData)}, + {server_name, which_resolve(ModData)}, + {gateway_interface, ?GATEWAY_INTERFACE}, + {server_protocol, ?SERVER_PROTOCOL}, + {server_port, which_port(ModData)}, + {request_method, which_method(ModData)}, + {remote_addr, which_peername(ModData)}, + {script_name, which_request_uri(ModData)}]; create_basic_elements(cgi, ModData) -> - {_, RemoteAddr} = (ModData#mod.init_data)#init_data.peername, - [{"SERVER_SOFTWARE",?SERVER_SOFTWARE}, - {"SERVER_NAME", (ModData#mod.init_data)#init_data.resolve}, - {"GATEWAY_INTERFACE",?GATEWAY_INTERFACE}, - {"SERVER_PROTOCOL",?SERVER_PROTOCOL}, - {"SERVER_PORT", - integer_to_list(httpd_util:lookup( - ModData#mod.config_db, port, 80))}, - {"REQUEST_METHOD", ModData#mod.method}, - {"REMOTE_ADDR", RemoteAddr}, - {"SCRIPT_NAME", ModData#mod.request_uri}]. + [{"SERVER_SOFTWARE", which_server(ModData)}, + {"SERVER_NAME", which_resolve(ModData)}, + {"GATEWAY_INTERFACE", ?GATEWAY_INTERFACE}, + {"SERVER_PROTOCOL", ?SERVER_PROTOCOL}, + {"SERVER_PORT", integer_to_list(which_port(ModData))}, + {"REQUEST_METHOD", which_method(ModData)}, + {"REMOTE_ADDR", which_peername(ModData)}, + {"SCRIPT_NAME", which_request_uri(ModData)}]. create_http_header_elements(ScriptType, Headers) -> create_http_header_elements(ScriptType, Headers, []). @@ -80,7 +95,7 @@ create_http_header_elements(ScriptType, Headers) -> create_http_header_elements(_, [], Acc) -> Acc; create_http_header_elements(ScriptType, [{Name, [Value | _] = Values } | - Headers], Acc) + Headers], Acc) when is_list(Value) -> NewName = lists:map(fun(X) -> if X == $- -> $_; true -> X end end, Name), Element = http_env_element(ScriptType, NewName, multi_value(Values)), diff --git a/lib/inets/src/http_server/httpd_sup.erl b/lib/inets/src/http_server/httpd_sup.erl index 264dc9f006..8f3e8f9500 100644 --- a/lib/inets/src/http_server/httpd_sup.erl +++ b/lib/inets/src/http_server/httpd_sup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-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,17 +162,30 @@ httpd_config([Value| _] = Config) when is_tuple(Value) -> httpd_child_spec([Value| _] = Config, AcceptTimeout, Debug) when is_tuple(Value) -> + ?hdrt("httpd_child_spec - entry", [{accept_timeout, AcceptTimeout}, + {debug, Debug}]), Address = proplists:get_value(bind_address, Config, any), Port = proplists:get_value(port, Config, 80), httpd_child_spec(Config, AcceptTimeout, Debug, Address, Port); -httpd_child_spec(ConfigFile, AcceptTimeout, Debug) -> +%% In this case the AcceptTimeout and Debug will only have default values... +httpd_child_spec(ConfigFile, AcceptTimeoutDef, DebugDef) -> + ?hdrt("httpd_child_spec - entry", [{config_file, ConfigFile}, + {accept_timeout_def, AcceptTimeoutDef}, + {debug_def, DebugDef}]), case httpd_conf:load(ConfigFile) of {ok, ConfigList} -> + ?hdrt("httpd_child_spec - loaded", [{config_list, ConfigList}]), case (catch httpd_conf:validate_properties(ConfigList)) of {ok, Config} -> + ?hdrt("httpd_child_spec - validated", [{config, Config}]), Address = proplists:get_value(bind_address, Config, any), Port = proplists:get_value(port, Config, 80), + AcceptTimeout = + proplists:get_value(accept_timeout, Config, + AcceptTimeoutDef), + Debug = + proplists:get_value(debug, Config, DebugDef), httpd_child_spec([{file, ConfigFile} | Config], AcceptTimeout, Debug, Address, Port); Error -> @@ -183,7 +196,7 @@ httpd_child_spec(ConfigFile, AcceptTimeout, Debug) -> end. httpd_child_spec(Config, AcceptTimeout, Debug, Addr, Port) -> - case Port == 0 orelse proplists:is_defined(fd, Config) of + case (Port =:= 0) orelse proplists:is_defined(fd, Config) of true -> httpd_child_spec_listen(Config, AcceptTimeout, Debug, Addr, Port); false -> diff --git a/lib/inets/src/http_server/mod_get.erl b/lib/inets/src/http_server/mod_get.erl index 5cb30e3d97..c58d1f3508 100644 --- a/lib/inets/src/http_server/mod_get.erl +++ b/lib/inets/src/http_server/mod_get.erl @@ -18,9 +18,16 @@ %% %% -module(mod_get). + -export([do/1]). + -include("httpd.hrl"). -include("httpd_internal.hrl"). +-include("inets_internal.hrl"). + +-define(VMODULE,"GET"). + + %% do do(Info) -> @@ -84,15 +91,16 @@ send_response(_Socket, _SocketType, Path, Info)-> file:close(FileDescriptor), {proceed,[{response,{already_sent,200, FileInfo#file_info.size}}, - {mime_type,MimeType}|Info#mod.data]}; + {mime_type,MimeType} | Info#mod.data]}; {error, Reason} -> + ?hdrt("send_response -> failed open file", + [{path, Path}, {reason, Reason}]), Status = httpd_file:handle_error(Reason, "open", Info, Path), - {proceed, - [{status, Status}| Info#mod.data]} + {proceed, [{status, Status} | Info#mod.data]} end. %% send - + send(#mod{socket = Socket, socket_type = SocketType} = Info, StatusCode, Headers, FileDescriptor) -> ?DEBUG("send -> send header",[]), diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile index d99e33b4ea..6da6a1d79f 100644 --- a/lib/inets/src/inets_app/Makefile +++ b/lib/inets/src/inets_app/Makefile @@ -46,7 +46,8 @@ MODULES = \ inets_service \ inets_app \ inets_sup \ - inets_regexp + inets_regexp \ + inets_trace INTERNAL_HRL_FILES = inets_internal.hrl EXTERNAL_HRL_FILES = ../../include/httpd.hrl \ diff --git a/lib/inets/src/inets_app/inets.app.src b/lib/inets/src/inets_app/inets.app.src index 1db7ed2c30..4aea2ef3d7 100644 --- a/lib/inets/src/inets_app/inets.app.src +++ b/lib/inets/src/inets_app/inets.app.src @@ -18,14 +18,15 @@ %% {application,inets, - [{description,"INETS CXC 138 49"}, - {vsn,"%VSN%"}, + [{description, "INETS CXC 138 49"}, + {vsn, "%VSN%"}, {modules,[ inets, inets_sup, inets_app, inets_service, inets_regexp, + inets_trace, %% FTP ftp, diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index e80cb2a23b..c7029f7b31 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -18,65 +18,115 @@ {"%VSN%", [ + {"5.8.1", + [ + {load_module, http_uri, soft_purge, soft_purge, []}, + {load_module, httpc_response, soft_purge, soft_purge, [http_uri]}, + + {load_module, httpc, soft_purge, soft_purge, + [http_uri, httpc_manager]}, + {update, httpc_manager, soft, soft_purge, soft_purge, [http_uri]}, + + {load_module, inets_app, soft_purge, soft_purge, [inets_sup]}, + {update, inets_sup, soft, soft_purge, soft_purge, []}, + + {load_module, httpd_conf, soft_purge, soft_purge, []}, + {load_module, httpd_response, soft_purge, soft_purge, []}, + {load_module, httpd_script_env, soft_purge, soft_purge, []}, + + {load_module, inets, soft_purge, soft_purge, [inets_trace]}, + {update, httpc_handler, soft, soft_purge, soft_purge, []}, + {update, httpd_sup, soft, soft_purge, soft_purge, []}, + {add_module, inets_trace} + ] + }, {"5.8", [ + {load_module, http_uri, soft_purge, soft_purge, []}, + {load_module, httpc_response, soft_purge, soft_purge, [http_uri]}, + + {load_module, httpc, soft_purge, soft_purge, + [http_uri, httpc_manager]}, + + {load_module, inets_app, soft_purge, soft_purge, [inets_sup]}, + {update, inets_sup, soft, soft_purge, soft_purge, []}, + + {load_module, inets, soft_purge, soft_purge, [inets_trace]}, + + {load_module, httpd_conf, soft_purge, soft_purge, []}, + {load_module, httpd_response, soft_purge, soft_purge, []}, + {load_module, httpd_script_env, soft_purge, soft_purge, []}, + {load_module, ftp, soft_purge, soft_purge, []}, {update, httpc_handler, {advanced, upgrade_from_pre_5_8_1}, soft_purge, soft_purge, []}, {update, httpc_manager, {advanced, upgrade_from_pre_5_8_1}, - soft_purge, soft_purge, [httpc_handler]} + soft_purge, soft_purge, [http_uri, httpc_handler]}, + {update, httpd_sup, soft, soft_purge, soft_purge, []}, + + {add_module, inets_trace} ] }, {"5.7.2", [ {restart_application, inets} ] - }, - {"5.7.1", - [ - {restart_application, inets} - ] - }, - {"5.7", + } + ], + [ + {"5.8.1", [ - {restart_application, inets} + {load_module, http_uri, soft_purge, soft_purge, []}, + {load_module, httpc_response, soft_purge, soft_purge, [http_uri]}, + + {load_module, httpc, soft_purge, soft_purge, + [http_uri, httpc_manager]}, + {update, httpc_manager, soft, soft_purge, soft_purge, [http_uri]}, + + {load_module, inets_app, soft_purge, soft_purge, [inets_sup]}, + {update, inets_sup, soft, soft_purge, soft_purge, []}, + + {load_module, httpd_conf, soft_purge, soft_purge, []}, + {load_module, httpd_response, soft_purge, soft_purge, []}, + {load_module, httpd_script_env, soft_purge, soft_purge, []}, + + {load_module, inets, soft_purge, soft_purge, []}, + {update, httpc_handler, soft, soft_purge, soft_purge, []}, + {update, httpd_sup, soft, soft_purge, soft_purge, []}, + {remove, {inets_trace, soft_purge, brutal_purge}} ] }, - {"5.6", - [ - {restart_application, inets} - ] - } - ], - [ {"5.8", [ + {load_module, http_uri, soft_purge, soft_purge, []}, + {load_module, httpc_response, soft_purge, soft_purge, [http_uri]}, + + {load_module, httpc, soft_purge, soft_purge, + [http_uri, httpc_manager]}, + + {load_module, inets_app, soft_purge, soft_purge, [inets_sup]}, + {update, inets_sup, soft, soft_purge, soft_purge, []}, + + {load_module, inets, soft_purge, soft_purge, []}, + + {load_module, httpd_conf, soft_purge, soft_purge, []}, + {load_module, httpd_response, soft_purge, soft_purge, []}, + {load_module, httpd_script_env, soft_purge, soft_purge, []}, + {load_module, ftp, soft_purge, soft_purge, []}, {update, httpc_handler, {advanced, upgrade_from_pre_5_8_1}, soft_purge, soft_purge, []}, {update, httpc_manager, {advanced, upgrade_from_pre_5_8_1}, - soft_purge, soft_purge, [httpc_handler]} + soft_purge, soft_purge, [http_uri, httpc_handler]}, + {update, httpd_sup, soft, soft_purge, soft_purge, []}, + + {remove, {inets_trace, soft_purge, brutal_purge}} ] }, {"5.7.2", [ {restart_application, inets} ] - }, - {"5.7.1", - [ - {restart_application, inets} - ] - }, - {"5.7", - [ - {restart_application, inets} - ] - }, - {"5.6", - [ - {restart_application, inets} - ] } ] }. diff --git a/lib/inets/src/inets_app/inets.erl b/lib/inets/src/inets_app/inets.erl index 054468e445..8e79f8d456 100644 --- a/lib/inets/src/inets_app/inets.erl +++ b/lib/inets/src/inets_app/inets.erl @@ -28,7 +28,7 @@ stop/0, stop/2, services/0, services_info/0, service_names/0]). --export([enable_trace/2, enable_trace/3, disable_trace/0, set_trace/1, +-export([enable_trace/2, enable_trace/3, disable_trace/0, set_trace/1, report_event/4]). -export([versions/0, print_version_info/0, print_version_info/1]). @@ -409,47 +409,8 @@ service_names() -> %% Severity withing Limit) will be written to stdout using io:format. %% %%----------------------------------------------------------------- -enable_trace(Level, Dest) -> - enable_trace(Level, Dest, all). - -enable_trace(Level, Dest, Service) -> - case valid_trace_service(Service) of - true -> - enable_trace2(Level, Dest, Service); - false -> - {error, {invalid_service, Service}} - end. - -enable_trace2(Level, File, Service) - when is_list(File) -> - case file:open(File, [write]) of - {ok, Fd} -> - HandleSpec = {fun handle_trace/2, {Service, Fd}}, - do_enable_trace(Level, process, HandleSpec); - Err -> - Err - end; -enable_trace2(Level, Port, _) when is_integer(Port) -> - do_enable_trace(Level, port, dbg:trace_port(ip, Port)); -enable_trace2(Level, io, Service) -> - HandleSpec = {fun handle_trace/2, {Service, standard_io}}, - do_enable_trace(Level, process, HandleSpec); -enable_trace2(Level, {Fun, _Data} = HandleSpec, _) when is_function(Fun) -> - do_enable_trace(Level, process, HandleSpec). - -do_enable_trace(Level, Type, HandleSpec) -> - case dbg:tracer(Type, HandleSpec) of - {ok, _} -> - set_trace(Level), - ok; - Error -> - Error - end. - -valid_trace_service(all) -> - true; -valid_trace_service(Service) -> - lists:member(Service, [httpc, httpd, ftpc, tftp]). +enable_trace(Level, Dest) -> inets_trace:enable(Level, Dest). +enable_trace(Level, Dest, Service) -> inets_trace:enable(Level, Dest, Service). %%----------------------------------------------------------------- @@ -458,12 +419,7 @@ valid_trace_service(Service) -> %% Description: %% This function is used to stop tracing. %%----------------------------------------------------------------- -disable_trace() -> - %% This is to make handle_trace/2 close the output file (if the - %% event gets there before dbg closes) - inets:report_event(100, "stop trace", stop_trace, [stop_trace]), - dbg:stop(). - +disable_trace() -> inets_trace:disable(). %%----------------------------------------------------------------- @@ -476,60 +432,7 @@ disable_trace() -> %% This function is used to change the trace level when tracing has %% already been started. %%----------------------------------------------------------------- -set_trace(Level) -> - set_trace(Level, all). - -set_trace(Level, Service) -> - Pat = make_pattern(?MODULE, Service, Level), - change_pattern(Pat). - -make_pattern(Mod, Service, Level) - when is_atom(Mod) andalso is_atom(Service) -> - case Level of - min -> - {Mod, Service, []}; - max -> - Head = ['$1', '_', '_', '_'], - Body = [], - Cond = [], - {Mod, Service, [{Head, Cond, Body}]}; - DetailLevel when is_integer(DetailLevel) -> - Head = ['$1', '_', '_', '_'], - Body = [], - Cond = [{ '=<', '$1', DetailLevel}], - {Mod, Service, [{Head, Cond, Body}]}; - _ -> - exit({bad_level, Level}) - end. - -change_pattern({Mod, Service, Pattern}) - when is_atom(Mod) andalso is_atom(Service) -> - MFA = {Mod, report_event, 4}, - case Pattern of - [] -> - try - error_to_exit(ctp, dbg:ctp(MFA)), - error_to_exit(p, dbg:p(all, clear)) - catch - exit:{Where, Reason} -> - {error, {Where, Reason}} - end; - List when is_list(List) -> - try - error_to_exit(ctp, dbg:ctp(MFA)), - error_to_exit(tp, dbg:tp(MFA, Pattern)), - error_to_exit(p, dbg:p(all, [call, timestamp])) - catch - exit:{Where, Reason} -> - {error, {Where, Reason}} - end - end, - ok. - -error_to_exit(_Where, {ok, _} = OK) -> - OK; -error_to_exit(Where, {error, Reason}) -> - exit({Where, Reason}). +set_trace(Level) -> inets_trace:set_level(Level). %%----------------------------------------------------------------- @@ -546,164 +449,8 @@ error_to_exit(Where, {error, Reason}) -> %% put trace on this function. %%----------------------------------------------------------------- -report_event(Severity, Label, Service, Content) - when (is_integer(Severity) andalso - (Severity >= 0) andalso (100 >= Severity)) andalso - is_list(Label) andalso - is_atom(Service) andalso - is_list(Content) -> - hopefully_traced. - - -%% ---------------------------------------------------------------------- -%% handle_trace(Event, Fd) -> Verbosity -%% -%% Parameters: -%% Event -> The trace event (only megaco 'trace_ts' events are printed) -%% Fd -> standard_io | file_descriptor() | trace_port() -%% -%% Description: -%% This function is used to "receive" and print the trace events. -%% Events are printed if: -%% - Verbosity is max -%% - Severity is =< Verbosity (e.g. Severity = 30, and Verbosity = 40) -%% Events are not printed if: -%% - Verbosity is min -%% - Severity is > Verbosity -%%----------------------------------------------------------------- - -handle_trace(_, closed_file = Fd) -> - Fd; -handle_trace({trace_ts, _Who, call, - {?MODULE, report_event, - [_Sev, "stop trace", stop_trace, [stop_trace]]}, - Timestamp}, - {_, standard_io} = Fd) -> - (catch io:format(standard_io, "stop trace at ~s~n", [format_timestamp(Timestamp)])), - Fd; -handle_trace({trace_ts, _Who, call, - {?MODULE, report_event, - [_Sev, "stop trace", stop_trace, [stop_trace]]}, - Timestamp}, - standard_io = Fd) -> - (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), - Fd; -handle_trace({trace_ts, _Who, call, - {?MODULE, report_event, - [_Sev, "stop trace", stop_trace, [stop_trace]]}, - Timestamp}, - {_Service, Fd}) -> - (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), - (catch file:close(Fd)), - closed_file; -handle_trace({trace_ts, _Who, call, - {?MODULE, report_event, - [_Sev, "stop trace", stop_trace, [stop_trace]]}, - Timestamp}, - Fd) -> - (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), - (catch file:close(Fd)), - closed_file; -handle_trace({trace_ts, Who, call, - {?MODULE, report_event, - [Sev, Label, Service, Content]}, Timestamp}, - Fd) -> - (catch print_inets_trace(Fd, Sev, Timestamp, Who, - Label, Service, Content)), - Fd; -handle_trace(Event, Fd) -> - (catch print_trace(Fd, Event)), - Fd. - - -print_inets_trace({Service, Fd}, - Sev, Timestamp, Who, Label, Service, Content) -> - do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content); -print_inets_trace({ServiceA, Fd}, - Sev, Timestamp, Who, Label, ServiceB, Content) - when (ServiceA =:= all) -> - do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, ServiceB, Content); -print_inets_trace({ServiceA, _Fd}, - _Sev, _Timestamp, _Who, _Label, ServiceB, _Content) - when ServiceA =/= ServiceB -> - ok; -print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) -> - do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content). - -do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) -> - Ts = format_timestamp(Timestamp), - io:format(Fd, "[inets ~w trace ~w ~w ~s] ~s " - "~n Content: ~p" - "~n", - [Service, Sev, Who, Ts, Label, Content]). - -print_trace({_, Fd}, Event) -> - do_print_trace(Fd, Event); -print_trace(Fd, Event) -> - do_print_trace(Fd, Event). - -do_print_trace(Fd, {trace, Who, What, Where}) -> - io:format(Fd, "[trace]" - "~n Who: ~p" - "~n What: ~p" - "~n Where: ~p" - "~n", [Who, What, Where]); - -do_print_trace(Fd, {trace, Who, What, Where, Extra}) -> - io:format(Fd, "[trace]" - "~n Who: ~p" - "~n What: ~p" - "~n Where: ~p" - "~n Extra: ~p" - "~n", [Who, What, Where, Extra]); - -do_print_trace(Fd, {trace_ts, Who, What, Where, When}) -> - Ts = format_timestamp(When), - io:format(Fd, "[trace ~s]" - "~n Who: ~p" - "~n What: ~p" - "~n Where: ~p" - "~n", [Ts, Who, What, Where]); - -do_print_trace(Fd, {trace_ts, Who, What, Where, Extra, When}) -> - Ts = format_timestamp(When), - io:format(Fd, "[trace ~s]" - "~n Who: ~p" - "~n What: ~p" - "~n Where: ~p" - "~n Extra: ~p" - "~n", [Ts, Who, What, Where, Extra]); - -do_print_trace(Fd, {seq_trace, What, Where}) -> - io:format(Fd, "[seq trace]" - "~n What: ~p" - "~n Where: ~p" - "~n", [What, Where]); - -do_print_trace(Fd, {seq_trace, What, Where, When}) -> - Ts = format_timestamp(When), - io:format(Fd, "[seq trace ~s]" - "~n What: ~p" - "~n Where: ~p" - "~n", [Ts, What, Where]); - -do_print_trace(Fd, {drop, Num}) -> - io:format(Fd, "[drop trace] ~p~n", [Num]); - -do_print_trace(Fd, Trace) -> - io:format(Fd, "[trace] " - "~n ~p" - "~n", [Trace]). - - -format_timestamp({_N1, _N2, N3} = Now) -> - {Date, Time} = calendar:now_to_datetime(Now), - {YYYY,MM,DD} = Date, - {Hour,Min,Sec} = Time, - FormatDate = - io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w", - [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]), - lists:flatten(FormatDate). +report_event(Severity, Label, Service, Content) -> + inets_trace:report_event(Severity, Label, Service, Content). %%-------------------------------------------------------------------- diff --git a/lib/inets/src/inets_app/inets.mk b/lib/inets/src/inets_app/inets.mk index 194b4ca2b1..d24cc0aea3 100644 --- a/lib/inets/src/inets_app/inets.mk +++ b/lib/inets/src/inets_app/inets.mk @@ -41,8 +41,6 @@ INETS_APP_VSN_COMPILE_FLAGS = \ +'{parse_transform,sys_pre_attributes}' \ +'{attribute,insert,app_vsn,$(APP_VSN)}' -INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' - INETS_ERL_COMPILE_FLAGS += \ -pa $(ERL_TOP)/lib/inets/ebin \ $(INETS_APP_VSN_COMPILE_FLAGS) diff --git a/lib/inets/src/inets_app/inets_app.erl b/lib/inets/src/inets_app/inets_app.erl index cae79a6767..77c39d85eb 100644 --- a/lib/inets/src/inets_app/inets_app.erl +++ b/lib/inets/src/inets_app/inets_app.erl @@ -24,7 +24,7 @@ -export([start/2, stop/1]). start(_Type, _State) -> - supervisor:start_link({local, inets_sup}, inets_sup, []). + inets_sup:start_link(). stop(_State) -> ok. diff --git a/lib/inets/src/inets_app/inets_internal.hrl b/lib/inets/src/inets_app/inets_internal.hrl index 55c3669e4a..e56af3b59d 100644 --- a/lib/inets/src/inets_app/inets_internal.hrl +++ b/lib/inets/src/inets_app/inets_internal.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. 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 @@ -24,8 +24,8 @@ %% Various trace macros -define(report(Severity, Label, Service, Content), - inets:report_event(Severity, Label, Service, - [{module, ?MODULE}, {line, ?LINE} | Content])). + inets_trace:report_event(Severity, Label, Service, + [{module, ?MODULE}, {line, ?LINE} | Content])). -define(report_important(Label, Service, Content), ?report(20, Label, Service, Content)). -define(report_verbose(Label, Service, Content), diff --git a/lib/inets/src/inets_app/inets_sup.erl b/lib/inets/src/inets_app/inets_sup.erl index 20d5ef343e..0382362778 100644 --- a/lib/inets/src/inets_app/inets_sup.erl +++ b/lib/inets/src/inets_app/inets_sup.erl @@ -25,9 +25,19 @@ -behaviour(supervisor). +%% External API +-export([start_link/0]). + +%% Supervisor callbacks -export([init/1]). %%%========================================================================= +%%% External functions +%%%========================================================================= +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +%%%========================================================================= %%% Supervisor callback %%%========================================================================= init([]) -> diff --git a/lib/inets/src/inets_app/inets_trace.erl b/lib/inets/src/inets_app/inets_trace.erl new file mode 100644 index 0000000000..8911f65897 --- /dev/null +++ b/lib/inets/src/inets_app/inets_trace.erl @@ -0,0 +1,357 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011-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% +%% +%% +%%---------------------------------------------------------------------- +%% Purpose: Module for debug trace functions of the inets application +%%---------------------------------------------------------------------- + +-module(inets_trace). + +%% API +-export([enable/2, enable/3, + disable/0, + set_level/1, set_level/2, + report_event/4]). + + +%%==================================================================== +%% API +%%==================================================================== + +%%----------------------------------------------------------------- +%% enable(Level, Destination) -> void() +%% enable(Level, Destination, Service) -> void() +%% +%% Parameters: +%% Level -> max | min | integer() +%% Destination -> File | Port | io | HandlerSpec +%% Service -> httpc | httpd | ftpc | tftp | all +%% File -> string() +%% Port -> integer() +%% Verbosity -> true | false +%% HandlerSpec = {function(), Data} +%% Data = term() +%% +%% Description: +%% This function is used to start tracing at level Level and send +%% the result either to the file File, the port Port or to a +%% trace handler. +%% Note that it starts a tracer server. +%% When Destination is the atom io (or the tuple {io, Verbosity}), +%% all (printable) inets trace events (trace_ts events which has +%% Severity withing Limit) will be written to stdout using io:format. +%% +%%----------------------------------------------------------------- +enable(Level, Dest) -> + enable(Level, Dest, all). + +enable(Level, Dest, Service) -> + case valid_trace_service(Service) of + true -> + enable2(Level, Dest, Service); + false -> + {error, {invalid_service, Service}} + end. + +enable2(Level, File, Service) + when is_list(File) -> + case file:open(File, [write]) of + {ok, Fd} -> + HandleSpec = {fun handle_trace/2, {Service, Fd}}, + do_enable(Level, process, HandleSpec); + Err -> + Err + end; +enable2(Level, Port, _) when is_integer(Port) -> + do_enable(Level, port, dbg:trace_port(ip, Port)); +enable2(Level, io, Service) -> + HandleSpec = {fun handle_trace/2, {Service, standard_io}}, + do_enable(Level, process, HandleSpec); +enable2(Level, {Fun, _Data} = HandleSpec, _) when is_function(Fun) -> + do_enable(Level, process, HandleSpec). + +do_enable(Level, Type, HandleSpec) -> + case dbg:tracer(Type, HandleSpec) of + {ok, _} -> + set_level(Level), + ok; + Error -> + Error + end. + +valid_trace_service(all) -> + true; +valid_trace_service(Service) -> + lists:member(Service, [httpc, httpd, ftpc, tftp]). + + +%%----------------------------------------------------------------- +%% disable() -> void() +%% +%% Description: +%% This function is used to stop tracing. +%%----------------------------------------------------------------- + +disable() -> + %% This is to make handle_trace/2 close the output file (if the + %% event gets there before dbg closes) + inets_trace:report_event(100, "stop trace", stop_trace, [stop_trace]), + dbg:stop(). + + + +%%----------------------------------------------------------------- +%% set_level(Level) -> void() +%% +%% Parameters: +%% Level -> max | min | integer() +%% +%% Description: +%% This function is used to change the trace level when tracing has +%% already been started. +%%----------------------------------------------------------------- +set_level(Level) -> + set_level(Level, all). + +set_level(Level, Service) -> + Pat = make_pattern(?MODULE, Service, Level), + change_pattern(Pat). + +make_pattern(Mod, Service, Level) + when is_atom(Mod) andalso is_atom(Service) -> + case Level of + min -> + {Mod, Service, []}; + max -> + Head = ['$1', '_', '_', '_'], + Body = [], + Cond = [], + {Mod, Service, [{Head, Cond, Body}]}; + DetailLevel when is_integer(DetailLevel) -> + Head = ['$1', '_', '_', '_'], + Body = [], + Cond = [{ '=<', '$1', DetailLevel}], + {Mod, Service, [{Head, Cond, Body}]}; + _ -> + exit({bad_level, Level}) + end. + +change_pattern({Mod, Service, Pattern}) + when is_atom(Mod) andalso is_atom(Service) -> + MFA = {Mod, report_event, 4}, + case Pattern of + [] -> + try + error_to_exit(ctp, dbg:ctp(MFA)), + error_to_exit(p, dbg:p(all, clear)) + catch + exit:{Where, Reason} -> + {error, {Where, Reason}} + end; + List when is_list(List) -> + try + error_to_exit(ctp, dbg:ctp(MFA)), + error_to_exit(tp, dbg:tp(MFA, Pattern)), + error_to_exit(p, dbg:p(all, [call, timestamp])) + catch + exit:{Where, Reason} -> + {error, {Where, Reason}} + end + end. + +error_to_exit(_Where, {ok, _} = OK) -> + OK; +error_to_exit(Where, {error, Reason}) -> + exit({Where, Reason}). + + +%%----------------------------------------------------------------- +%% report_event(Severity, Label, Service, Content) +%% +%% Parameters: +%% Severity -> 0 =< integer() =< 100 +%% Label -> string() +%% Service -> httpd | httpc | ftp | tftp +%% Content -> [{tag, term()}] +%% +%% Description: +%% This function is used to generate trace events, that is, +%% put trace on this function. +%%----------------------------------------------------------------- + +report_event(Severity, Label, Service, Content) + when (is_integer(Severity) andalso + (Severity >= 0) andalso (100 >= Severity)) andalso + is_list(Label) andalso + is_atom(Service) andalso + is_list(Content) -> + hopefully_traced. + + +%% ---------------------------------------------------------------------- +%% handle_trace(Event, Fd) -> Verbosity +%% +%% Parameters: +%% Event -> The trace event +%% Fd -> standard_io | file_descriptor() | trace_port() +%% +%% Description: +%% This function is used to "receive" and pretty print the trace events. +%% Events are printed if: +%% - Verbosity is max +%% - Severity is =< Verbosity (e.g. Severity = 30, and Verbosity = 40) +%% Events are not printed if: +%% - Verbosity is min +%% - Severity is > Verbosity +%%----------------------------------------------------------------- + +handle_trace(_, closed_file = Fd) -> + Fd; +handle_trace({trace_ts, _Who, call, + {?MODULE, report_event, + [_Sev, "stop trace", stop_trace, [stop_trace]]}, + Timestamp}, + {_, standard_io} = Fd) -> + (catch io:format(standard_io, "stop trace at ~s~n", [format_timestamp(Timestamp)])), + Fd; +handle_trace({trace_ts, _Who, call, + {?MODULE, report_event, + [_Sev, "stop trace", stop_trace, [stop_trace]]}, + Timestamp}, + standard_io = Fd) -> + (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), + Fd; +handle_trace({trace_ts, _Who, call, + {?MODULE, report_event, + [_Sev, "stop trace", stop_trace, [stop_trace]]}, + Timestamp}, + {_Service, Fd}) -> + (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), + (catch file:close(Fd)), + closed_file; +handle_trace({trace_ts, _Who, call, + {?MODULE, report_event, + [_Sev, "stop trace", stop_trace, [stop_trace]]}, + Timestamp}, + Fd) -> + (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), + (catch file:close(Fd)), + closed_file; +handle_trace({trace_ts, Who, call, + {?MODULE, report_event, + [Sev, Label, Service, Content]}, Timestamp}, + Fd) -> + (catch print_inets_trace(Fd, Sev, Timestamp, Who, + Label, Service, Content)), + Fd; +handle_trace(Event, Fd) -> + (catch print_trace(Fd, Event)), + Fd. + + +print_inets_trace({Service, Fd}, + Sev, Timestamp, Who, Label, Service, Content) -> + do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content); +print_inets_trace({ServiceA, Fd}, + Sev, Timestamp, Who, Label, ServiceB, Content) + when (ServiceA =:= all) -> + do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, ServiceB, Content); +print_inets_trace({ServiceA, _Fd}, + _Sev, _Timestamp, _Who, _Label, ServiceB, _Content) + when ServiceA =/= ServiceB -> + ok; +print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) -> + do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content). + +do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) -> + Ts = format_timestamp(Timestamp), + io:format(Fd, "[inets ~w trace ~w ~w ~s] ~s " + "~n Content: ~p" + "~n", + [Service, Sev, Who, Ts, Label, Content]). + +print_trace({_, Fd}, Event) -> + do_print_trace(Fd, Event); +print_trace(Fd, Event) -> + do_print_trace(Fd, Event). + +do_print_trace(Fd, {trace, Who, What, Where}) -> + io:format(Fd, "[trace]" + "~n Who: ~p" + "~n What: ~p" + "~n Where: ~p" + "~n", [Who, What, Where]); + +do_print_trace(Fd, {trace, Who, What, Where, Extra}) -> + io:format(Fd, "[trace]" + "~n Who: ~p" + "~n What: ~p" + "~n Where: ~p" + "~n Extra: ~p" + "~n", [Who, What, Where, Extra]); + +do_print_trace(Fd, {trace_ts, Who, What, Where, When}) -> + Ts = format_timestamp(When), + io:format(Fd, "[trace ~s]" + "~n Who: ~p" + "~n What: ~p" + "~n Where: ~p" + "~n", [Ts, Who, What, Where]); + +do_print_trace(Fd, {trace_ts, Who, What, Where, Extra, When}) -> + Ts = format_timestamp(When), + io:format(Fd, "[trace ~s]" + "~n Who: ~p" + "~n What: ~p" + "~n Where: ~p" + "~n Extra: ~p" + "~n", [Ts, Who, What, Where, Extra]); + +do_print_trace(Fd, {seq_trace, What, Where}) -> + io:format(Fd, "[seq trace]" + "~n What: ~p" + "~n Where: ~p" + "~n", [What, Where]); + +do_print_trace(Fd, {seq_trace, What, Where, When}) -> + Ts = format_timestamp(When), + io:format(Fd, "[seq trace ~s]" + "~n What: ~p" + "~n Where: ~p" + "~n", [Ts, What, Where]); + +do_print_trace(Fd, {drop, Num}) -> + io:format(Fd, "[drop trace] ~p~n", [Num]); + +do_print_trace(Fd, Trace) -> + io:format(Fd, "[trace] " + "~n ~p" + "~n", [Trace]). + + +format_timestamp({_N1, _N2, N3} = Now) -> + {Date, Time} = calendar:now_to_datetime(Now), + {YYYY,MM,DD} = Date, + {Hour,Min,Sec} = Time, + FormatDate = + io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w", + [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]), + lists:flatten(FormatDate). + + diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 881266b70a..a116edef77 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-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 @@ -146,6 +146,20 @@ groups() -> ]. +init_per_group(ipv6 = _GroupName, Config) -> + case inets_test_lib:has_ipv6_support() of + {ok, _} -> + Config; + _ -> + {skip, "Host does not support IPv6"} + end; +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + %%-------------------------------------------------------------------- %% Function: init_per_suite(Config) -> Config %% Config - [tuple()] @@ -156,6 +170,9 @@ groups() -> %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- init_per_suite(Config) -> + + ?PRINT_SYSTEM_INFO([]), + PrivDir = ?config(priv_dir, Config), DataDir = ?config(data_dir, Config), ServerRoot = filename:join(PrivDir, "server_root"), @@ -179,10 +196,11 @@ init_per_suite(Config) -> {ok, FileInfo} = file:read_file_info(Cgi), ok = file:write_file_info(Cgi, FileInfo#file_info{mode = 8#00755}), - [{server_root, ServerRoot}, - {doc_root, DocRoot}, - {local_port, ?IP_PORT}, - {local_ssl_port, ?SSL_PORT} | Config]. + [{has_ipv6_support, inets_test_lib:has_ipv6_support()}, + {server_root, ServerRoot}, + {doc_root, DocRoot}, + {local_port, ?IP_PORT}, + {local_ssl_port, ?SSL_PORT} | Config]. %%-------------------------------------------------------------------- @@ -198,6 +216,7 @@ end_per_suite(Config) -> application:stop(ssl), ok. + %%-------------------------------------------------------------------- %% Function: init_per_testcase(Case, Config) -> Config %% Case - atom() @@ -229,12 +248,12 @@ init_per_testcase(initial_server_connect = Case, Config) -> "~n ~p", [Case, App, ActualError]), SkipString = "Could not start " ++ atom_to_list(App), - {skip, SkipString}; + skip(SkipString); _:X -> SkipString = lists:flatten( io_lib:format("Failed starting apps: ~p", [X])), - {skip, SkipString} + skip(SkipString) end; init_per_testcase(Case, Config) -> @@ -244,6 +263,7 @@ init_per_testcase(Case, Timeout, Config) -> io:format(user, "~n~n*** INIT ~w:~w[~w] ***" "~n~n", [?MODULE, Case, Timeout]), + PrivDir = ?config(priv_dir, Config), application:stop(inets), Dog = test_server:timetrap(inets_test_lib:minutes(Timeout)), @@ -337,7 +357,8 @@ init_per_testcase(Case, Timeout, Config) -> inets:start(httpc, [{profile, Profile}, {data_dir, PrivDir}], stand_alone), - httpc:set_options([{ipfamily, inet6}], ProfilePid), + ok = httpc:set_options([{ipfamily, inet6}], + ProfilePid), tsp("httpc profile pid: ~p", [ProfilePid]), [{watchdog, Dog}, {profile, ProfilePid}| TmpConfig] catch @@ -346,27 +367,67 @@ init_per_testcase(Case, Timeout, Config) -> "~n ~p", [Case, App, ActualError]), SkipString = "Could not start " ++ atom_to_list(App), - {skip, SkipString}; + skip(SkipString); _:X -> SkipString = lists:flatten( io_lib:format("Failed starting apps: ~p", [X])), - {skip, SkipString} + skip(SkipString) end; _ -> + %% Try inet6fb4 on windows... + %% No need? Since it is set above? + + %% tsp("init_per_testcase -> allways try IPv6 on windows"), + %% ?RUN_ON_WINDOWS( + %% fun() -> + %% tsp("init_per_testcase:set_options_fun -> " + %% "set-option ipfamily to inet6fb4"), + %% Res = httpc:set_options([{ipfamily, inet6fb4}]), + %% tsp("init_per_testcase:set_options_fun -> " + %% "~n Res: ~p", [Res]), + %% Res + %% end), + TmpConfig2 = lists:keydelete(local_server, 1, TmpConfig), %% Will start inets + tsp("init_per_testcase -> try start server"), Server = start_http_server(PrivDir, IpConfFile), [{watchdog, Dog}, {local_server, Server} | TmpConfig2] end, + %% <IPv6> + %% Set default ipfamily to the same as the main server has by default + %% This makes the client try w/ ipv6 before falling back to ipv4, + %% as that is what the server is configured to do. + %% Note that this is required for the tests to run on *BSD w/ ipv6 enabled + %% as well as on Windows. The Linux behaviour of allowing ipv4 connects + %% to ipv6 sockets is not required or even encouraged. + + tsp("init_per_testcase -> Options before ipfamily set: ~n~p", + [httpc:get_options(all)]), + ok = httpc:set_options([{ipfamily, inet6fb4}]), + tsp("init_per_testcase -> Options after ipfamily set: ~n~p", + [httpc:get_options(all)]), + + %% Note that the IPv6 test case(s) *must* use inet6, + %% so this value will be overwritten (see "ipv6_" below). + %% </IPv6> + %% This will fail for the ipv6_ - cases (but that is ok) ProxyExceptions = ["localhost", ?IPV6_LOCAL_HOST], - httpc:set_options([{proxy, {{?PROXY, ?PROXY_PORT}, ProxyExceptions}}]), + tsp("init_per_testcase -> Options before proxy set: ~n~p", + [httpc:get_options(all)]), + ok = httpc:set_options([{proxy, {{?PROXY, ?PROXY_PORT}, ProxyExceptions}}]), + tsp("init_per_testcase -> Options after proxy set: ~n~p", + [httpc:get_options(all)]), inets:enable_trace(max, io, httpc), %% inets:enable_trace(max, io, all), %% snmp:set_trace([gen_tcp]), + tsp("init_per_testcase(~w) -> done when" + "~n NewConfig: ~p" + "~n~n", [Case, NewConfig]), NewConfig. @@ -405,6 +466,7 @@ end_per_testcase(http_save_to_file = Case, Config) -> end_per_testcase(Case, Config) -> io:format(user, "~n~n*** END ~w:~w ***~n~n", [?MODULE, Case]), + dbg:stop(), % ? case atom_to_list(Case) of "ipv6_" ++ _Rest -> tsp("end_per_testcase(~w) -> stop ssl", [Case]), @@ -449,29 +511,39 @@ http_options(doc) -> http_options(suite) -> []; http_options(Config) when is_list(Config) -> - {skip, "Not supported by httpd"}. + skip("Not supported by httpd"). http_head(doc) -> ["Test http head request against local server."]; http_head(suite) -> []; http_head(Config) when is_list(Config) -> - case ?config(local_server, Config) of - ok -> - Port = ?config(local_port, Config), - URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", - case httpc:request(head, {URL, []}, [], []) of - {ok, {{_,200,_}, [_ | _], []}} -> - ok; - {ok, WrongReply} -> - tsf({wrong_reply, WrongReply}); - Error -> - tsf({failed, Error}) - end; - _ -> - {skip, "Failed to start local http-server"} - end. + tsp("http_head -> entry with" + "~n Config: ~p", [Config]), + Method = head, + Port = ?config(local_port, Config), + URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", + Request = {URL, []}, + HttpOpts = [], + Opts = [], + VerifyResult = + fun({ok, {{_,200,_}, [_ | _], []}}) -> + ok; + ({ok, UnexpectedReply}) -> + tsp("http_head:verify_fun -> Unexpected Reply: " + "~n ~p", [UnexpectedReply]), + tsf({unexpected_reply, UnexpectedReply}); + ({error, Reason} = Error) -> + tsp("http_head:verify_fun -> Error reply: " + "~n Reason: ~p", [Reason]), + tsf({bad_reply, Error}) + end, + simple_request_and_verify(Config, + Method, Request, HttpOpts, Opts, VerifyResult). + + %%------------------------------------------------------------------------- + http_get(doc) -> ["Test http get request against local server"]; http_get(suite) -> @@ -488,7 +560,8 @@ http_get(Config) when is_list(Config) -> Request = {URL, []}, Timeout = timer:seconds(1), ConnTimeout = Timeout + timer:seconds(1), - HttpOptions1 = [{timeout, Timeout}, {connect_timeout, ConnTimeout}], + HttpOptions1 = [{timeout, Timeout}, + {connect_timeout, ConnTimeout}], Options1 = [], Body = case httpc:request(Method, Request, HttpOptions1, Options1) of @@ -516,14 +589,15 @@ http_get(Config) when is_list(Config) -> tsf({bad_reply, Error2}) end; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. %%------------------------------------------------------------------------- + http_post(doc) -> - ["Test http post request against local server. We do in this case" - " only care about the client side of the the post. The server" - " script will not actually use the post data."]; + ["Test http post request against local server. We do in this case " + "only care about the client side of the the post. The server " + "script will not actually use the post data."]; http_post(suite) -> []; http_post(Config) when is_list(Config) -> @@ -551,7 +625,7 @@ http_post(Config) when is_list(Config) -> httpc:request(post, {URL, [{"expect","100-continue"}], "text/plain", "foobar"}, [], []); _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. %%------------------------------------------------------------------------- @@ -597,7 +671,7 @@ http_post_streaming(Config) when is_list(Config) -> "text/plain", {BodyFun, 10}}, [], []); _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -621,7 +695,7 @@ http_emulate_lower_versions(Config) when is_list(Config) -> httpc:request(get, {URL, []}, [{version, "HTTP/1.1"}], []), inets_test_lib:check_body(Body2); _-> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -682,7 +756,7 @@ http_inets_pipe(Config) when is_list(Config) -> URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", test_pipeline(URL); _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -818,7 +892,7 @@ http_trace(Config) when is_list(Config) -> tsf({failed, Error}) end; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. %%------------------------------------------------------------------------- http_async(doc) -> @@ -853,7 +927,7 @@ http_async(Config) when is_list(Config) -> ok end; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. %%------------------------------------------------------------------------- @@ -874,7 +948,7 @@ http_save_to_file(Config) when is_list(Config) -> {ok, {{_,200,_}, [_ | _], Body}} = httpc:request(URL), Bin == Body; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -904,7 +978,7 @@ http_save_to_file_async(Config) when is_list(Config) -> {ok, {{_,200,_}, [_ | _], Body}} = httpc:request(URL), Bin == Body; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. %%------------------------------------------------------------------------- http_headers(doc) -> @@ -961,7 +1035,7 @@ http_headers(Config) when is_list(Config) -> ]}, [], []), ok; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. %%------------------------------------------------------------------------- @@ -1096,9 +1170,9 @@ ssl_head(SslTag, Config) -> {ok, {{_,200, _}, [_ | _], []}} = httpc:request(head, {URL, []}, [{ssl, SSLConfig}], []); {ok, _} -> - {skip, "local http-server not started"}; + skip("local http-server not started"); _ -> - {skip, "SSL not started"} + skip("SSL not started") end. @@ -1136,13 +1210,24 @@ ssl_get(SslTag, Config) when is_list(Config) -> "~n URL: ~p" "~n SslTag: ~p" "~n SSLOptions: ~p", [URL, SslTag, SSLOptions]), - {ok, {{_,200, _}, [_ | _], Body = [_ | _]}} = - httpc:request(get, {URL, []}, [{ssl, SSLConfig}], []), - inets_test_lib:check_body(Body); + case httpc:request(get, {URL, []}, [{ssl, SSLConfig}], []) of + {ok, {{_,200, _}, [_ | _], Body = [_ | _]}} -> + inets_test_lib:check_body(Body), + ok; + {ok, {StatusLine, Headers, _Body}} -> + tsp("ssl_get -> unexpected result: " + "~n StatusLine: ~p" + "~n Headers: ~p", [StatusLine, Headers]), + tsf({unexpected_response, StatusLine, Headers}); + {error, Reason} -> + tsp("ssl_get -> request failed: " + "~n Reason: ~p", [Reason]), + tsf({request_failed, Reason}) + end; {ok, _} -> - {skip, "local http-server not started"}; + skip("local http-server not started"); _ -> - {skip, "SSL not started"} + skip("SSL not started") end. @@ -1191,9 +1276,9 @@ ssl_trace(SslTag, Config) when is_list(Config) -> tsf({failed, Error}) end; {ok, _} -> - {skip, "local http-server not started"}; + skip("local http-server not started"); _ -> - {skip, "SSL not started"} + skip("SSL not started") end. @@ -1208,8 +1293,8 @@ http_redirect(Config) when is_list(Config) -> "~n Config: ~p", [Config]), case ?config(local_server, Config) of ok -> - tsp("http_redirect -> set ipfamily option to inet"), - ok = httpc:set_options([{ipfamily, inet}]), + %% tsp("http_redirect -> set ipfamily option to inet"), + %% ok = httpc:set_options([{ipfamily, inet}]), tsp("http_redirect -> start dummy server inet"), {DummyServerPid, Port} = dummy_server(ipv4), @@ -1312,7 +1397,7 @@ http_redirect(Config) when is_list(Config) -> ok; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -1449,7 +1534,7 @@ proxy_options(Config) when is_list(Config) -> tsf({unexpected_result, Unexpected}) end; Reason -> - {skip, Reason} + skip(Reason) end. @@ -1470,7 +1555,7 @@ proxy_head(Config) when is_list(Config) -> tsf({unexpected_result, Unexpected}) end; Reason -> - {skip, Reason} + skip(Reason) end. @@ -1489,7 +1574,7 @@ proxy_get(Config) when is_list(Config) -> tsf({unexpected_result, Unexpected}) end; Reason -> - {skip, Reason} + skip(Reason) end. %%------------------------------------------------------------------------- @@ -1530,12 +1615,13 @@ proxy_emulate_lower_versions(Config) when is_list(Config) -> end; Reason -> - {skip, Reason} + skip(Reason) end. pelv_get(Version) -> httpc:request(get, {?PROXY_URL, []}, [{version, Version}], []). + %%------------------------------------------------------------------------- proxy_trace(doc) -> ["Perform a TRACE request that goes through a proxy."]; @@ -1544,8 +1630,8 @@ proxy_trace(suite) -> proxy_trace(Config) when is_list(Config) -> %%{ok, {{_,200,_}, [_ | _], "TRACE " ++ _}} = %% httpc:request(trace, {?PROXY_URL, []}, [], []), - {skip, "HTTP TRACE is no longer allowed on the ?PROXY_URL server due " - "to security reasons"}. + skip("HTTP TRACE is no longer allowed on the ?PROXY_URL server due " + "to security reasons"). %%------------------------------------------------------------------------- @@ -1568,7 +1654,7 @@ proxy_post(Config) when is_list(Config) -> tsf({unexpected_result, Unexpected}) end; Reason -> - {skip, Reason} + skip(Reason) end. @@ -1593,7 +1679,7 @@ proxy_put(Config) when is_list(Config) -> tsf({unexpected_result, Unexpected}) end; Reason -> - {skip, Reason} + skip(Reason) end. @@ -1618,7 +1704,7 @@ proxy_delete(Config) when is_list(Config) -> tsf({unexpected_result, Unexpected}) end; Reason -> - {skip, Reason} + skip(Reason) end. @@ -1652,9 +1738,10 @@ proxy_headers(Config) when is_list(Config) -> ]}, [], []), ok; Reason -> - {skip, Reason} + skip(Reason) end. + %%------------------------------------------------------------------------- proxy_auth(doc) -> ["Test the code for sending of proxy authorization."]; @@ -1674,7 +1761,7 @@ proxy_auth(Config) when is_list(Config) -> tsf({unexpected_result, Unexpected}) end; Reason -> - {skip, Reason} + skip(Reason) end. @@ -1718,7 +1805,7 @@ proxy_page_does_not_exist(Config) when is_list(Config) -> httpc:request(get, {URL, []}, [], []), ok; Reason -> - {skip, Reason} + skip(Reason) end. @@ -1737,6 +1824,7 @@ proxy_https_not_supported(Config) when is_list(Config) -> tsf({unexpected_reason, Result}) end. + %%------------------------------------------------------------------------- http_stream(doc) -> @@ -1863,7 +1951,7 @@ proxy_stream(Config) when is_list(Config) -> Body == binary_to_list(StreamedBody); Reason -> - {skip, Reason} + skip(Reason) end. @@ -1886,7 +1974,7 @@ parse_url(Config) when is_list(Config) -> http_uri:parse("http://[2010:836B:4179::836B:4179]/foobar.html", [{foo, false}]), {error, - {malformed_url,"http://2010:836B:4179::836B:4179/foobar.html"}} = + {malformed_url, _, "http://2010:836B:4179::836B:4179/foobar.html"}} = http_uri:parse("http://2010:836B:4179::836B:4179/foobar.html"), %% ipv4 @@ -1902,8 +1990,8 @@ parse_url(Config) when is_list(Config) -> http_uri:parse("http://nisse:foobar@localhost:8888/foobar.html"), %% Scheme error - {error,no_scheme} = http_uri:parse("localhost/foobar.html"), - {error,{not_supported_scheme,localhost}} = + {error, no_scheme} = http_uri:parse("localhost/foobar.html"), + {error, {malformed_url, _, _}} = http_uri:parse("localhost:8888/foobar.html"), %% Query @@ -1966,7 +2054,7 @@ ipv6_essl(Config) when is_list(Config) -> ipv6(SocketType, Scheme, HTTPOptions, Extra, Config) -> %% Check if we are a IPv6 host - tsp("ipv6 -> verify ipv6 support", []), + tsp("ipv6 -> verify ipv6 support"), case inets_test_lib:has_ipv6_support(Config) of {ok, Addr} -> tsp("ipv6 -> ipv6 supported: ~p", [Addr]), @@ -1997,8 +2085,8 @@ ipv6(SocketType, Scheme, HTTPOptions, Extra, Config) -> end, ok; _ -> - tsp("ipv6 -> ipv6 not supported", []), - {skip, "Host does not support IPv6"} + tsp("ipv6 -> ipv6 not supported"), + skip("Host does not support IPv6") end. @@ -2355,7 +2443,7 @@ options(Config) when is_list(Config) -> = httpc:request(get, {URL, []}, [{timeout, infinity}], [{full_result, false}]); _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -2468,7 +2556,7 @@ proxy_not_modified_otp_6821(Config) when is_list(Config) -> undefined -> provocate_not_modified_bug(?PROXY_URL); Reason -> - {skip, Reason} + skip(Reason) end. @@ -2870,7 +2958,7 @@ otp_8106_pid(Config) when is_list(Config) -> ok; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -2890,7 +2978,7 @@ otp_8106_fun(Config) when is_list(Config) -> ok; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -2910,7 +2998,7 @@ otp_8106_mfa(Config) when is_list(Config) -> ok; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -3059,7 +3147,7 @@ otp_8352(Config) when is_list(Config) -> ok; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -3254,7 +3342,11 @@ create_config(FileName, ComType, Port, PrivDir, ServerRoot, DocRoot, " mod_include mod_dir mod_get mod_head" " mod_log mod_disk_log mod_trace", + %% BindAddress = "*|inet", % Force the use of IPv4 + BindAddress = "*", % This corresponds to using IpFamily inet6fb4 + HttpConfig = [ + cline(["BindAddress ", BindAddress]), cline(["Port ", integer_to_list(Port)]), cline(["ServerName ", "httpc_test"]), cline(["SocketType ", atom_to_list(ComType)]), @@ -3813,6 +3905,34 @@ pick_header(Headers, Name) -> Val end. + +%% ------------------------------------------------------------------------- + +simple_request_and_verify(Config, + Method, Request, HttpOpts, Opts, VerifyResult) + when (is_list(Config) andalso + is_atom(Method) andalso + is_list(HttpOpts) andalso + is_list(Opts) andalso + is_function(VerifyResult, 1)) -> + tsp("request_and_verify -> entry with" + "~n Method: ~p" + "~n Request: ~p" + "~n HttpOpts: ~p" + "~n Opts: ~p", [Method, Request, HttpOpts, Opts]), + case ?config(local_server, Config) of + ok -> + tsp("request_and_verify -> local-server running"), + Result = (catch httpc:request(Method, Request, HttpOpts, Opts)), + VerifyResult(Result); + _ -> + tsp("request_and_verify -> local-server *not* running - skip"), + hard_skip("Local http-server not running") + end. + + + + not_implemented_yet() -> exit(not_implemented_yet). @@ -3823,9 +3943,9 @@ p(F, A) -> io:format("~p ~w:" ++ F ++ "~n", [self(), ?MODULE | A]). tsp(F) -> - inets_test_lib:tsp(F). + inets_test_lib:tsp("[~w]" ++ F, [?MODULE]). tsp(F, A) -> - inets_test_lib:tsp(F, A). + inets_test_lib:tsp("[~w]" ++ F, [?MODULE|A]). tsf(Reason) -> test_server:fail(Reason). @@ -3864,6 +3984,8 @@ dummy_ssl_server_hang_loop(_) -> ok end. +hard_skip(Reason) -> + throw(skip(Reason)). skip(Reason) -> {skip, Reason}. diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index a4bb8f7159..41e4188e5f 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2011. All Rights Reserved. +%% Copyright Ericsson AB 2005-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 @@ -224,7 +224,8 @@ all() -> ]. groups() -> - [{ip, [], + [ + {ip, [], [ip_mod_alias, ip_mod_actions, ip_mod_security, ip_mod_auth, ip_mod_auth_api, ip_mod_auth_mnesia_api, ip_mod_htaccess, ip_mod_cgi, ip_mod_esi, ip_mod_get, @@ -293,6 +294,14 @@ groups() -> [ticket_5775, ticket_5865, ticket_5913, ticket_6003, ticket_7304]}]. + +init_per_group(ipv6 = _GroupName, Config) -> + case inets_test_lib:has_ipv6_support() of + {ok, _} -> + Config; + _ -> + {skip, "Host does not support IPv6"} + end; init_per_group(_GroupName, Config) -> Config. @@ -314,6 +323,8 @@ init_per_suite(Config) -> "~n Config: ~p" "~n", [Config]), + ?PRINT_SYSTEM_INFO([]), + PrivDir = ?config(priv_dir, Config), SuiteTopDir = filename:join(PrivDir, ?MODULE), case file:make_dir(SuiteTopDir) of @@ -325,10 +336,11 @@ init_per_suite(Config) -> throw({error, {failed_creating_suite_top_dir, Error}}) end, - [{suite_top_dir, SuiteTopDir}, - {node, node()}, - {host, inets_test_lib:hostname()}, - {address, getaddr()} | Config]. + [{has_ipv6_support, inets_test_lib:has_ipv6_support()}, + {suite_top_dir, SuiteTopDir}, + {node, node()}, + {host, inets_test_lib:hostname()}, + {address, getaddr()} | Config]. %%-------------------------------------------------------------------- @@ -363,10 +375,9 @@ init_per_testcase(Case, Config) -> init_per_testcase2(Case, Config) -> - io:format(user, "~w:init_per_testcase2(~w) -> entry with" - "~n Config: ~p" - "~n", [?MODULE, Case, Config]), - + tsp("init_per_testcase2 -> entry with" + "~n Config: ~p", [Config]), + IpNormal = integer_to_list(?IP_PORT) ++ ".conf", IpHtaccess = integer_to_list(?IP_PORT) ++ "htaccess.conf", SslNormal = integer_to_list(?SSL_PORT) ++ ".conf", @@ -375,39 +386,33 @@ init_per_testcase2(Case, Config) -> DataDir = ?config(data_dir, Config), SuiteTopDir = ?config(suite_top_dir, Config), - io:format(user, "~w:init_per_testcase2(~w) -> " - "~n SuiteDir: ~p" - "~n DataDir: ~p" - "~n", [?MODULE, Case, SuiteTopDir, DataDir]), + tsp("init_per_testcase2 -> " + "~n SuiteDir: ~p" + "~n DataDir: ~p", [SuiteTopDir, DataDir]), TcTopDir = filename:join(SuiteTopDir, Case), ?line ok = file:make_dir(TcTopDir), - io:format(user, "~w:init_per_testcase2(~w) -> " - "~n TcTopDir: ~p" - "~n", [?MODULE, Case, TcTopDir]), + tsp("init_per_testcase2 -> " + "~n TcTopDir: ~p", [TcTopDir]), DataSrc = filename:join([DataDir, "server_root"]), ServerRoot = filename:join([TcTopDir, "server_root"]), - io:format(user, "~w:init_per_testcase2(~w) -> " - "~n DataSrc: ~p" - "~n ServerRoot: ~p" - "~n", [?MODULE, Case, DataSrc, ServerRoot]), + tsp("init_per_testcase2 -> " + "~n DataSrc: ~p" + "~n ServerRoot: ~p", [DataSrc, ServerRoot]), ok = file:make_dir(ServerRoot), ok = file:make_dir(filename:join([TcTopDir, "logs"])), NewConfig = [{tc_top_dir, TcTopDir}, {server_root, ServerRoot} | Config], - io:format(user, "~w:init_per_testcase2(~w) -> " - "copy DataSrc to ServerRoot~n", - [?MODULE, Case]), + tsp("init_per_testcase2 -> copy DataSrc to ServerRoot"), inets_test_lib:copy_dirs(DataSrc, ServerRoot), - io:format(user, "~w:init_per_testcase2(~w) -> fix cgi~n", - [?MODULE, Case]), + tsp("init_per_testcase2 -> fix cgi"), EnvCGI = filename:join([ServerRoot, "cgi-bin", "printenv.sh"]), {ok, FileInfo} = file:read_file_info(EnvCGI), ok = file:write_file_info(EnvCGI, @@ -427,16 +432,14 @@ init_per_testcase2(Case, Config) -> FileInfo1#file_info{mode = 8#00755}), %% To be used by IP test cases - io:format(user, "~w:init_per_testcase2(~w) -> ip testcase setups~n", - [?MODULE, Case]), + tsp("init_per_testcase2 -> ip testcase setups"), create_config([{port, ?IP_PORT}, {sock_type, ip_comm} | NewConfig], normal_access, IpNormal), create_config([{port, ?IP_PORT}, {sock_type, ip_comm} | NewConfig], mod_htaccess, IpHtaccess), %% To be used by SSL test cases - io:format(user, "~w:init_per_testcase2(~w) -> ssl testcase setups~n", - [?MODULE, Case]), + tsp("init_per_testcase2 -> ssl testcase setups"), SocketType = case atom_to_list(Case) of [X, $s, $s, $l | _] -> @@ -460,8 +463,7 @@ init_per_testcase2(Case, Config) -> %% when you run the whole test suite due to shortcomings %% of the test server. - io:format(user, "~w:init_per_testcase2(~w) -> " - "maybe generate IPv6 config file(s)", [?MODULE, Case]), + tsp("init_per_testcase2 -> maybe generate IPv6 config file(s)"), NewConfig2 = case atom_to_list(Case) of "ipv6_" ++ _ -> @@ -502,15 +504,15 @@ init_per_testcase2(Case, Config) -> NewConfig end, - io:format(user, "~w:init_per_testcase2(~w) -> done~n", - [?MODULE, Case]), + tsp("init_per_testcase2 -> done when" + "~n NewConfig2: ~p", [NewConfig2]), NewConfig2. init_per_testcase3(Case, Config) -> - io:format(user, "~w:init_per_testcase3(~w) -> entry with" - "~n Config: ~p", [?MODULE, Case, Config]), + tsp("init_per_testcase3(~w) -> entry with" + "~n Config: ~p", [Case, Config]), %% %% Create a new fresh node to be used by the server in this test-case @@ -532,12 +534,10 @@ init_per_testcase3(Case, Config) -> %% Set trace level case lists:reverse(atom_to_list(Case)) of "tset_emit" ++ _Rest -> % test-cases ending with time_test - io:format(user, "~w:init_per_testcase3(~w) -> disabling trace", - [?MODULE, Case]), + tsp("init_per_testcase3(~w) -> disabling trace", [Case]), inets:disable_trace(); _ -> - io:format(user, "~w:init_per_testcase3(~w) -> enabling trace", - [?MODULE, Case]), + tsp("init_per_testcase3(~w) -> enabling trace", [Case]), %% TraceLevel = 70, TraceLevel = max, TraceDest = io, @@ -545,8 +545,7 @@ init_per_testcase3(Case, Config) -> end, %% Start initialization - io:format(user, "~w:init_per_testcase3(~w) -> start init", - [?MODULE, Case]), + tsp("init_per_testcase3(~w) -> start init", [Case]), Dog = test_server:timetrap(inets_test_lib:minutes(10)), @@ -627,26 +626,32 @@ init_per_testcase3(Case, Config) -> end end, - case CaseRest of - {skip, _} = Skip -> - Skip; - "mod_auth_" ++ _ -> - start_mnesia(?config(node, Config)), - [{watchdog, Dog} | NewConfig]; - "mod_htaccess" -> - ServerRoot = ?config(server_root, Config), - Path = filename:join([ServerRoot, "htdocs"]), - catch remove_htaccess(Path), - create_htaccess_data(Path, ?config(address, Config)), - [{watchdog, Dog} | NewConfig]; - "range" -> - ServerRoot = ?config(server_root, Config), - Path = filename:join([ServerRoot, "htdocs"]), - create_range_data(Path), - [{watchdog, Dog} | NewConfig]; - _ -> - [{watchdog, Dog} | NewConfig] - end. + InitRes = + case CaseRest of + {skip, _} = Skip -> + Skip; + "mod_auth_" ++ _ -> + start_mnesia(?config(node, Config)), + [{watchdog, Dog} | NewConfig]; + "mod_htaccess" -> + ServerRoot = ?config(server_root, Config), + Path = filename:join([ServerRoot, "htdocs"]), + catch remove_htaccess(Path), + create_htaccess_data(Path, ?config(address, Config)), + [{watchdog, Dog} | NewConfig]; + "range" -> + ServerRoot = ?config(server_root, Config), + Path = filename:join([ServerRoot, "htdocs"]), + create_range_data(Path), + [{watchdog, Dog} | NewConfig]; + _ -> + [{watchdog, Dog} | NewConfig] + end, + + tsp("init_per_testcase3(~w) -> done when" + "~n InitRes: ~p", [Case, InitRes]), + + InitRes. %%-------------------------------------------------------------------- @@ -664,16 +669,14 @@ end_per_testcase(Case, Config) -> ok. end_per_testcase2(Case, Config) -> - io:format(user, "~w:end_per_testcase2(~w) -> entry with" - "~n Config: ~p~n", - [?MODULE, Case, Config]), + tsp("end_per_testcase2(~w) -> entry with" + "~n Config: ~p", [Case, Config]), application:unset_env(inets, services), application:stop(inets), application:stop(ssl), application:stop(crypto), % used by the new ssl (essl test cases) cleanup_mnesia(), - io:format(user, "~w:end_per_testcase2(~w) -> done~n", - [?MODULE, Case]), + tsp("end_per_testcase2(~w) -> done", [Case]), ok. @@ -2354,32 +2357,33 @@ create_config(Config, Access, FileName) -> true -> [] end, - ModOrder = case Access of - mod_htaccess -> - "Modules mod_alias mod_htaccess mod_auth " - "mod_security " - "mod_responsecontrol mod_trace mod_esi " - "mod_actions mod_cgi mod_include mod_dir " - "mod_range mod_get " - "mod_head mod_log mod_disk_log"; - _ -> - "Modules mod_alias mod_auth mod_security " - "mod_responsecontrol mod_trace mod_esi " - "mod_actions mod_cgi mod_include mod_dir " + ModOrder = + case Access of + mod_htaccess -> + "Modules mod_alias mod_htaccess mod_auth " + "mod_security " + "mod_responsecontrol mod_trace mod_esi " + "mod_actions mod_cgi mod_include mod_dir " + "mod_range mod_get " + "mod_head mod_log mod_disk_log"; + _ -> + "Modules mod_alias mod_auth mod_security " + "mod_responsecontrol mod_trace mod_esi " + "mod_actions mod_cgi mod_include mod_dir " "mod_range mod_get " - "mod_head mod_log mod_disk_log" - end, + "mod_head mod_log mod_disk_log" + end, -%% The test suite currently does not handle an explicit BindAddress. -%% They assume any has been used, that is Addr is always set to undefined! + %% The test suite currently does not handle an explicit BindAddress. + %% They assume any has been used, that is Addr is always set to undefined! -%% {ok, Hostname} = inet:gethostname(), -%% {ok, Addr} = inet:getaddr(Hostname, inet6), -%% AddrStr = make_ipv6(Addr), -%% BindAddress = lists:flatten(io_lib:format("~s|inet6", [AddrStr])), + %% {ok, Hostname} = inet:gethostname(), + %% {ok, Addr} = inet:getaddr(Hostname, inet6), + %% AddrStr = make_ipv6(Addr), + %% BindAddress = lists:flatten(io_lib:format("~s|inet6", [AddrStr])), - %% BindAddress = "*|inet", - BindAddress = "*", + BindAddress = "*|inet", + %% BindAddress = "*", HttpConfig = [ cline(["Port ", integer_to_list(Port)]), @@ -2770,10 +2774,10 @@ create_ipv6_config(Config, FileName, Ipv6Address) -> ok = file:close(Fd). -%% tsp(F) -> -%% inets_test_lib:tsp(F). +tsp(F) -> + inets_test_lib:tsp("[~w]" ++ F, [?MODULE]). tsp(F, A) -> - inets_test_lib:tsp(F, A). + inets_test_lib:tsp("[~w]" ++ F, [?MODULE|A]). tsf(Reason) -> inets_test_lib:tsf(Reason). diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl index 4cd38f2ec4..7a476ea14a 100644 --- a/lib/inets/test/httpd_basic_SUITE.erl +++ b/lib/inets/test/httpd_basic_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-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 @@ -20,6 +20,8 @@ -module(httpd_basic_SUITE). -include_lib("common_test/include/ct.hrl"). +-include("inets_test_lib.hrl"). + %% Note: This directive should only be used in test suites. -compile(export_all). @@ -184,6 +186,15 @@ escaped_url_in_error_body(doc) -> escaped_url_in_error_body(suite) -> []; escaped_url_in_error_body(Config) when is_list(Config) -> + %% <CONDITIONAL-SKIP> + %% This skip is due to a problem on windows with long path's + %% If a path is too long file:open fails with, for example, eio. + %% Until that problem is fixed, we skip this case... + Skippable = [win32], + Condition = fun() -> ?OS_BASED_SKIP(Skippable) end, + ?NON_PC_TC_MAYBE_SKIP(Config, Condition), + %% </CONDITIONAL-SKIP> + tsp("escaped_url_in_error_body -> entry"), HttpdConf = ?config(httpd_conf, Config), {ok, Pid} = inets:start(httpd, [{port, 0} | HttpdConf]), @@ -192,6 +203,7 @@ escaped_url_in_error_body(Config) when is_list(Config) -> _Address = proplists:get_value(bind_address, Info), %% Request 1 + tss(1000), tsp("escaped_url_in_error_body -> request 1"), URL1 = ?URL_START ++ integer_to_list(Port), %% Make sure the server is ok, by making a request for a valid page @@ -202,11 +214,12 @@ escaped_url_in_error_body(Config) when is_list(Config) -> {ok, {200, _}} -> %% Don't care about the the body, just that we get a ok response ok; - {ok, UnexpectedOK1} -> - tsf({unexpected_ok_1, UnexpectedOK1}) + {ok, {StatusCode1, Body1}} -> + tsf({unexpected_ok_1, StatusCode1, Body1}) end, %% Request 2 + tss(1000), tsp("escaped_url_in_error_body -> request 2"), %% Make sure the server is ok, by making a request for a valid page case httpc:request(get, {URL1 ++ "/dummy.html", []}, @@ -216,11 +229,12 @@ escaped_url_in_error_body(Config) when is_list(Config) -> {ok, {200, _}} -> %% Don't care about the the body, just that we get a ok response ok; - {ok, UnexpectedOK2} -> - tsf({unexpected_ok_2, UnexpectedOK2}) + {ok, {StatusCode2, Body2}} -> + tsf({unexpected_ok_2, StatusCode2, Body2}) end, %% Request 3 + tss(1000), tsp("escaped_url_in_error_body -> request 3"), %% Ask for a non-existing page(1) Path = "/<b>this_is_bold<b>", @@ -238,10 +252,11 @@ escaped_url_in_error_body(Config) when is_list(Config) -> tsf({unexpected_path_3, HTMLEncodedPath, BadPath3}) end; {ok, UnexpectedOK3} -> - tsf({unexpected_ok_1, UnexpectedOK3}) + tsf({unexpected_ok_3, UnexpectedOK3}) end, %% Request 4 + tss(1000), tsp("escaped_url_in_error_body -> request 4"), %% Ask for a non-existing page(2) case httpc:request(get, {URL2, []}, @@ -253,11 +268,12 @@ escaped_url_in_error_body(Config) when is_list(Config) -> HTMLEncodedPath -> ok; BadPath4 -> - tsf({unexpected_path_2, HTMLEncodedPath, BadPath4}) + tsf({unexpected_path_4, HTMLEncodedPath, BadPath4}) end; {ok, UnexpectedOK4} -> tsf({unexpected_ok_4, UnexpectedOK4}) end, + tss(1000), tsp("escaped_url_in_error_body -> stop inets"), inets:stop(httpd, Pid), tsp("escaped_url_in_error_body -> done"), @@ -277,7 +293,12 @@ tsp(F, A) -> inets_test_lib:tsp(F, A). tsf(Reason) -> - test_server:fail(Reason). + inets_test_lib:tsf(Reason). + +tss(Time) -> + inets_test_lib:tss(Time). + + skip(Reason) -> diff --git a/lib/inets/test/httpd_mod.erl b/lib/inets/test/httpd_mod.erl index 5016cdb9e6..cb1214b7fb 100644 --- a/lib/inets/test/httpd_mod.erl +++ b/lib/inets/test/httpd_mod.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2011. All Rights Reserved. +%% Copyright Ericsson AB 2005-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 @@ -39,14 +39,10 @@ %% Test cases starts here. %%------------------------------------------------------------------------- alias(Type, Port, Host, Node) -> -%% io:format(user, "~w:alias -> entry with" -%% "~n Type: ~p" -%% "~n Port: ~p" -%% "~n Host: ~p" -%% "~n Node: ~p" -%% "~n", [?MODULE, Type, Port, Host, Node]), - - ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + %% This is very crude, but... + tsp("alias -> Has IPv6 support: ~p", [inets_test_lib:has_ipv6_support()]), + Opts = [], + ok = httpd_test_lib:verify_request(Type, Host, Port, Opts, Node, "GET /pics/icon.sheet.gif " "HTTP/1.0\r\n\r\n", [{statuscode, 200}, @@ -55,7 +51,7 @@ alias(Type, Port, Host, Node) -> {header, "Date"}, {version, "HTTP/1.0"}]), - ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + ok = httpd_test_lib:verify_request(Type, Host, Port, Opts, Node, "GET / HTTP/1.0\r\n\r\n", [{statuscode, 200}, {header, "Content-Type","text/html"}, @@ -63,7 +59,7 @@ alias(Type, Port, Host, Node) -> {header, "Date"}, {version, "HTTP/1.0"}]), - ok = httpd_test_lib:verify_request(Type,Host,Port,Node, + ok = httpd_test_lib:verify_request(Type, Host, Port, Opts, Node, "GET /misc/ HTTP/1.0\r\n\r\n", [{statuscode, 200}, {header, "Content-Type","text/html"}, @@ -71,8 +67,8 @@ alias(Type, Port, Host, Node) -> {header, "Date"}, {version, "HTTP/1.0"}]), - %% Check redirection if trailing slash is missing. - ok = httpd_test_lib:verify_request(Type,Host,Port,Node, + %% Check redirection if trailing slash is missing. + ok = httpd_test_lib:verify_request(Type, Host, Port, Opts, Node, "GET /misc HTTP/1.0\r\n\r\n", [{statuscode, 301}, {header, "Location"}, @@ -1032,9 +1028,10 @@ check_lists_members1(L1,L2) -> %% tsp(F) -> -%% tsp(F, []). -%% tsp(F, A) -> -%% test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]). +%% inets_test_lib:tsp(F). +tsp(F, A) -> + inets_test_lib:tsp(F, A). + tsf(Reason) -> test_server:fail(Reason). diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl index 2f5867559a..3e1213376d 100644 --- a/lib/inets/test/httpd_test_lib.erl +++ b/lib/inets/test/httpd_test_lib.erl @@ -79,19 +79,19 @@ %%-------------------------------------------------------------------- %% API %%------------------------------------------------------------------ + verify_request(SocketType, Host, Port, Node, RequestStr, Options) -> - verify_request(SocketType, Host, Port, Node, RequestStr, - Options, 30000). + verify_request(SocketType, Host, Port, Node, RequestStr, Options, 30000). + verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options) when is_list(TranspOpts) -> - verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, - Options, 30000); + verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, 30000); + verify_request(SocketType, Host, Port, Node, RequestStr, Options, TimeOut) when (is_integer(TimeOut) orelse (TimeOut =:= infinity)) -> - verify_request(SocketType, Host, Port, [], Node, RequestStr, - Options, TimeOut). -verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, - Options, TimeOut) -> + verify_request(SocketType, Host, Port, [], Node, RequestStr, Options, TimeOut). + +verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, TimeOut) -> tsp("verify_request -> entry with" "~n SocketType: ~p" "~n Host: ~p" @@ -101,7 +101,7 @@ verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, "~n Options: ~p" "~n TimeOut: ~p", [SocketType, Host, Port, TranspOpts, Node, Options, TimeOut]), - case (catch inets_test_lib:connect_bin(SocketType, Host, Port, TranspOpts)) of + try inets_test_lib:connect_bin(SocketType, Host, Port, TranspOpts) of {ok, Socket} -> tsp("verify_request -> connected - now send message"), SendRes = inets_test_lib:send(SocketType, Socket, RequestStr), @@ -117,25 +117,37 @@ verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, case request(State#state{request = RequestStr, socket = Socket}, TimeOut) of {error, Reason} -> - tsp("request failed: " + tsp("verify_request -> request failed: " "~n Reason: ~p", [Reason]), {error, Reason}; NewState -> - tsp("validate reply: " + tsp("verify_request -> validate reply: " "~n NewState: ~p", [NewState]), ValidateResult = validate(RequestStr, NewState, Options, Node, Port), - tsp("validation result: " + tsp("verify_request -> validation result: " "~n ~p", [ValidateResult]), inets_test_lib:close(SocketType, Socket), ValidateResult end; ConnectError -> - tsp("verify_request -> connect failed: " + tsp("verify_request -> connect error: " "~n ~p" "~n", [ConnectError]), - tsf({connect_failure, ConnectError}) + tsf({connect_error, ConnectError, + [SocketType, Host, Port, TranspOpts]}) + catch + T:E -> + tsp("verify_request -> connect failed: " + "~n E: ~p" + "~n T: ~p" + "~n", [E, T]), + tsf({connect_failure, + [{type, T}, + {error, E}, + {stacktrace, erlang:get_stacktrace()}, + {args, [SocketType, Host, Port, TranspOpts]}]}) end. request(#state{mfa = {Module, Function, Args}, diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl index bbed35e1f8..c94be796cd 100644 --- a/lib/inets/test/inets_test_lib.erl +++ b/lib/inets/test/inets_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2011. All Rights Reserved. +%% Copyright Ericsson AB 2001-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 @@ -31,42 +31,48 @@ send/3, close/2]). -export([copy_file/3, copy_files/2, copy_dirs/2, del_dirs/1]). -export([info/4, log/4, debug/4, print/4]). --export([tsp/1, tsp/2, tsf/1]). +-export([tsp/1, tsp/2, tsf/1, tss/1]). -export([check_body/1]). -export([millis/0, millis_diff/2, hours/1, minutes/1, seconds/1, sleep/1]). --export([oscmd/1, has_ipv6_support/1]). +-export([oscmd/1, has_ipv6_support/0, has_ipv6_support/1, print_system_info/1]). +-export([run_on_os/2, run_on_windows/1]). -export([ensure_started/1]). -export([non_pc_tc_maybe_skip/4, os_based_skip/1, skip/3, fail/3]). -export([flush/0]). -export([start_node/1, stop_node/1]). + %% -- Misc os command and stuff +has_ipv6_support() -> + tsp("has_ipv6_support -> no ipv6_hosts config"), + {ok, Hostname} = inet:gethostname(), + case inet:getaddrs(Hostname, inet6) of + {ok, [Addr|_]} when is_tuple(Addr) andalso + (element(1, Addr) =/= 0) -> + %% We actually need to test that the addr can be used, + %% this is done by attempting to create a (tcp) + %% listen socket + tsp("has_ipv6_support -> check Addr: ~p", [Addr]), + case (catch gen_tcp:listen(0, [inet6, {ip, Addr}])) of + {ok, LSock} -> + tsp("has_ipv6_support -> we are ipv6 host"), + gen_tcp:close(LSock), + {ok, Addr}; + _ -> + undefined + end; + _ -> + undefined + end. + has_ipv6_support(Config) -> case lists:keysearch(ipv6_hosts, 1, Config) of false -> %% Do a basic check to se if %% our own host has a working IPv6 address... - tsp("has_ipv6_support -> no ipv6_hosts config"), - {ok, Hostname} = inet:gethostname(), - case inet:getaddrs(Hostname, inet6) of - {ok, [Addr|_]} when is_tuple(Addr) andalso - (element(1, Addr) =/= 0) -> - %% We actually need to test that the addr can be used, - %% this is done by attempting to create a (tcp) - %% listen socket - tsp("has_ipv6_support -> check Addr: ~p", [Addr]), - case (catch gen_tcp:listen(0, [inet6, {ip, Addr}])) of - {ok, LSock} -> - tsp("has_ipv6_support -> we are ipv6 host"), - gen_tcp:close(LSock), - {ok, Addr}; - _ -> - undefined - end; - _ -> - undefined - end; + has_ipv6_support(); + {value, {_, Hosts}} when is_list(Hosts) -> %% Check if our host is in the list of *known* IPv6 hosts tsp("has_ipv6_support -> Hosts: ~p", [Hosts]), @@ -88,6 +94,49 @@ has_ipv6_support(Config) -> oscmd(Cmd) -> string:strip(os:cmd(Cmd), right, $\n). + +print_system_info([]) -> + do_print_system_info("System Info"); +print_system_info(Prefix) when is_list(Prefix) -> + NewPrefix = lists:flatten(io_lib:format("~s: System Info", [Prefix])), + do_print_system_info(NewPrefix). + +do_print_system_info(Prefix) -> + tsp("~s => " + "~n" + "~n OS Type: ~p" + "~n OS version: ~p" + "~n Sys Arch: ~p" + "~n CPU Topology: ~p" + "~n Num logical procs: ~p" + "~n SMP support: ~p" + "~n Num schedulers: ~p" + "~n Scheduler bindings: ~p" + "~n Wordsize: ~p" + "~n~n", [Prefix, + os:type(), os:version(), + erlang:system_info(system_architecture), + erlang:system_info(cpu_topology), + erlang:system_info(logical_processors), + erlang:system_info(smp_support), + erlang:system_info(schedulers), + erlang:system_info(scheduler_bindings), + erlang:system_info(wordsize)]), + ok. + + +run_on_windows(Fun) -> + run_on_os(windows, Fun). + +run_on_os(windows, Fun) -> + case os:type() of + {win32, _} -> + Fun(); + _ -> + ok + end. + + %% -- Misc node operation wrapper functions -- start_node(Name) -> @@ -156,6 +205,17 @@ do_ensure_started(App, Start) when is_function(Start) -> end. +ensure_loaded(App) -> + case application:load(App) of + ok -> + ok; + {error, {already_loaded,inets}} -> + ok; + Error -> + Error + end. + + %% ---------------------------------------------------------------- %% HTTPD starter functions @@ -165,8 +225,9 @@ start_http_server(Conf) -> start_http_server(Conf, ?HTTP_DEFAULT_SSL_KIND). start_http_server(Conf, essl = _SslTag) -> - tsp("start_http_server(essl) -> entry - try start crypto and public_key"), + tsp("start_http_server(essl) -> try start crypto"), application:start(crypto), + tsp("start_http_server(essl) -> try start public_key"), application:start(public_key), do_start_http_server(Conf); start_http_server(Conf, SslTag) -> @@ -177,23 +238,32 @@ do_start_http_server(Conf) -> tsp("do_start_http_server -> entry with" "~n Conf: ~p" "~n", [Conf]), - application:load(inets), - case application:set_env(inets, services, [{httpd, Conf}]) of + tsp("do_start_http_server -> load inets"), + case ensure_loaded(inets) of ok -> - tsp("start_http_server -> httpd conf stored in inets app env"), - case application:start(inets) of + tsp("do_start_http_server -> inets loaded - now set_env for httpd"), + case application:set_env(inets, services, [{httpd, Conf}]) of ok -> - tsp("start_http_server -> inets started"), - ok; - Error1 -> - tsp("<ERROR> Failed starting application: " - "~n Error1: ~p", [Error1]), - Error1 + tsp("do_start_http_server -> " + "httpd conf stored in inets app env"), + case (catch application:start(inets)) of + ok -> + tsp("do_start_http_server -> inets started"), + ok; + Error1 -> + tsp("<ERROR> Failed starting application: " + "~n Error1: ~p", [Error1]), + tsf({failed_starting_inets, Error1}) + end; + Error2 -> + tsp("<ERROR> Failed set application env: " + "~n Error: ~p", [Error2]), + tsf({failed_set_env, Error2}) end; - Error2 -> - tsp("<ERROR> Failed set application env: " - "~n Error: ~p", [Error2]), - Error2 + {error, Reason} -> + tsp("do_start_http_server -> failed loading inets" + "~n Reason: ~p", [Reason]), + tsf({failed_loading_inets, Reason}) end. start_http_server_ssl(FileName) -> @@ -213,6 +283,7 @@ do_start_http_server_ssl(FileName) -> catch do_start_http_server(FileName). + %% ---------------------------------------------------------------------- %% print functions %% @@ -257,20 +328,49 @@ copy_files(FromDir, ToDir) -> copy_dirs(FromDirRoot, ToDirRoot) -> - {ok, Files} = file:list_dir(FromDirRoot), - lists:foreach( - fun(FileOrDir) -> - %% Check if it's a directory or a file - case filelib:is_dir(filename:join(FromDirRoot, FileOrDir)) of - true -> - FromDir = filename:join([FromDirRoot, FileOrDir]), - ToDir = filename:join([ToDirRoot, FileOrDir]), - ok = file:make_dir(ToDir), - copy_dirs(FromDir, ToDir); - false -> - copy_file(FileOrDir, FromDirRoot, ToDirRoot) - end - end, Files). + case file:list_dir(FromDirRoot) of + {ok, Files} -> + lists:foreach( + fun(FileOrDir) -> + %% Check if it's a directory or a file + case filelib:is_dir(filename:join(FromDirRoot, + FileOrDir)) of + true -> + FromDir = filename:join([FromDirRoot, FileOrDir]), + ToDir = filename:join([ToDirRoot, FileOrDir]), + case file:make_dir(ToDir) of + ok -> + copy_dirs(FromDir, ToDir); + {error, Reason} -> + tsp("<ERROR> Failed creating directory: " + "~n ToDir: ~p" + "~n Reason: ~p" + "~nwhen" + "~n ToDirRoot: ~p" + "~n ToDirRoot file info: ~p", + [ToDir, + Reason, + ToDirRoot, + file:read_file_info(ToDirRoot)]), + tsf({failed_copy_dir, ToDir, Reason}) + end; + false -> + copy_file(FileOrDir, FromDirRoot, ToDirRoot) + end + end, Files); + {error, Reason} -> + tsp("<ERROR> Failed get directory file list: " + "~n FromDirRoot: ~p" + "~n Reason: ~p" + "~nwhen" + "~n FromDirRoot file info: ~p", + [FromDirRoot, + Reason, + file:read_file_info(FromDirRoot)]), + tsf({failed_list_dir, FromDirRoot, Reason}) + end. + + del_dirs(Dir) -> case file:list_dir(Dir) of @@ -394,56 +494,80 @@ connect_byte(ip_comm, Host, Port, Opts0) -> connect(ip_comm, Host, Port, Opts). -connect(ssl, Host, Port, Opts) -> +%% This always falls back on IPV4, but tries IPV6 first. +connect(Proto, Host, Port, Opts0) -> + Opts = Opts0 -- [inet, inet6], + connect(Proto, Host, Port, Opts ++ [inet6], inet6). + +connect(ssl, Host, Port, Opts, Type) -> tsp("connect(ssl) -> entry with" "~n Host: ~p" "~n Port: ~p" - "~n Opts: ~p", [Host, Port, Opts]), + "~n Opts: ~p" + "~n Type: ~p", [Host, Port, Opts, Type]), ssl:start(), - %% Does not support ipv6 in old ssl + %% We ignore this option for ssl... + %% ...maybe we should really treat this in the same way as ip_comm... case ssl:connect(Host, Port, Opts) of {ok, Socket} -> {ok, Socket}; + {error, Reason} when Type =:= inet6 -> + tsp("connect(ssl) -> failed connecting with inet6: " + "~n Reason: ~p" + "~n trying inet", [Reason]), + connect(ssl, Host, Port, Opts -- [inet6], inet); {error, Reason} -> - {error, Reason}; + tsp("connect(ssl) -> failed connecting: " + "~n Reason: ~p", [Reason]), + {error, Reason}; Error -> Error end; -connect(ip_comm, Host, Port, Opts) -> +connect(ip_comm, Host, Port, Opts, Type) -> tsp("connect(ip_comm) -> entry with" "~n Host: ~p" "~n Port: ~p" - "~n Opts: ~p", [Host, Port, Opts]), - case gen_tcp:connect(Host,Port, Opts) of + "~n Opts: ~p" + "~n Type: ~p", [Host, Port, Opts, Type]), + + case gen_tcp:connect(Host, Port, Opts) of {ok, Socket} -> tsp("connect success"), {ok, Socket}; - {error, nxdomain} -> - tsp("connect error nxdomain when opts: ~p", [Opts]), - connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); - {error, eafnosupport} -> - tsp("connect error eafnosupport when opts: ~p", [Opts]), - connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); - {error, econnreset} -> - tsp("connect error econnreset when opts: ~p", [Opts]), - connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); - {error, enetunreach} -> - tsp("connect error eafnosupport when opts: ~p", [Opts]), - connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); - {error, {enfile,_}} -> - tsp("connect error enfile when opts: ~p", [Opts]), - {error, enfile}; + + {error, nxdomain} when Type =:= inet6 -> + tsp("connect error nxdomain when" + "~n Opts: ~p", [Opts]), + connect(ip_comm, Host, Port, Opts -- [inet6], inet); + {error, eafnosupport} when Type =:= inet6 -> + tsp("connect error eafnosupport when" + "~n Opts: ~p", [Opts]), + connect(ip_comm, Host, Port, Opts -- [inet6], inet); + {error, econnreset} when Type =:= inet6 -> + tsp("connect error econnreset when" + "~n Opts: ~p", [Opts]), + connect(ip_comm, Host, Port, Opts -- [inet6], inet); + {error, enetunreach} when Type =:= inet6 -> + tsp("connect error eafnosupport when" + "~n Opts: ~p", [Opts]), + connect(ip_comm, Host, Port, Opts -- [inet6], inet); + {error, econnrefused} when Type =:= inet6 -> + tsp("connect error econnrefused when" + "~n Opts: ~p", [Opts]), + connect(ip_comm, Host, Port, Opts -- [inet6], inet); + Error -> - tsp("Unexpected error: " + tsp("connect(ip_conn) -> Fatal connect error: " "~n Error: ~p" "~nwhen" "~n Host: ~p" "~n Port: ~p" "~n Opts: ~p" - "~n", [Error, Host, Port, Opts]), + "~n Type: ~p" + "~n", [Error, Host, Port, Opts, Type]), Error end. - + send(ssl, Socket, Data) -> ssl:send(Socket, Data); @@ -509,12 +633,15 @@ tsp(F) -> tsp(F, []). tsp(F, A) -> Timestamp = formated_timestamp(), - test_server:format("*** ~s ~p ~p ~w:" ++ F ++ "~n", - [Timestamp, node(), self(), ?MODULE | A]). + test_server:format("*** ~s ~p ~p " ++ F ++ "~n", + [Timestamp, node(), self() | A]). tsf(Reason) -> test_server:fail(Reason). +tss(Time) -> + test_server:sleep(Time). + formated_timestamp() -> format_timestamp( os:timestamp() ). diff --git a/lib/inets/test/inets_test_lib.hrl b/lib/inets/test/inets_test_lib.hrl index c578398c55..6a86b1b764 100644 --- a/lib/inets/test/inets_test_lib.hrl +++ b/lib/inets/test/inets_test_lib.hrl @@ -50,6 +50,11 @@ -define(OSCMD(Cmd), inets_test_lib:oscmd(Cmd)). +-define(PRINT_SYSTEM_INFO(P), inets_test_lib:print_system_info(P)). + +-define(RUN_ON_OS(OS, FUN), inets_test_lib:run_on_os(OS, FUN)). +-define(RUN_ON_WINDOWS(FUN), inets_test_lib:run_on_windows(FUN)). + %% - Test case macros - diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk index 77eb43a7ed..488947c3a1 100644 --- a/lib/inets/vsn.mk +++ b/lib/inets/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% APPLICATION = inets -INETS_VSN = 5.8.1 +INETS_VSN = 5.9 PRE_VSN = APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)" diff --git a/lib/kernel/doc/src/app.xml b/lib/kernel/doc/src/app.xml index ff8a12fe97..1914844b37 100644 --- a/lib/kernel/doc/src/app.xml +++ b/lib/kernel/doc/src/app.xml @@ -4,7 +4,7 @@ <fileref> <header> <copyright> - <year>1997</year><year>2011</year> + <year>1997</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -75,7 +75,7 @@ MaxT int() infinity Names [Name] [] Apps [App] [] Env [{Par,Val}] [] -Start {Module,StartArgs} undefined +Start {Module,StartArgs} [] Phases [{Phase,PhaseArgs}] undefined Module = Name = App = Par = Phase = atom() Val = StartArgs = PhaseArgs = term()</code> diff --git a/lib/kernel/src/disk_log.erl b/lib/kernel/src/disk_log.erl index fb9415d440..f5f972c112 100644 --- a/lib/kernel/src/disk_log.erl +++ b/lib/kernel/src/disk_log.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-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 @@ -1034,10 +1034,9 @@ sync_loop(From, S) -> -define(MAX_LOOK_AHEAD, 64*1024). %% Inlined. -log_loop(S, Pids, _Bins, _Sync, _Sz) when S#state.cache_error =/= ok -> +log_loop(#state{cache_error = CE}=S, Pids, _Bins, _Sync, _Sz) when CE =/= ok -> loop(cache_error(S, Pids)); -log_loop(#state{messages = []}=S, Pids, Bins, Sync, Sz) - when Sz > ?MAX_LOOK_AHEAD -> +log_loop(#state{}=S, Pids, Bins, Sync, Sz) when Sz > ?MAX_LOOK_AHEAD -> loop(log_end(S, Pids, Bins, Sync)); log_loop(#state{messages = []}=S, Pids, Bins, Sync, Sz) -> receive @@ -1046,8 +1045,7 @@ log_loop(#state{messages = []}=S, Pids, Bins, Sync, Sz) -> after 0 -> loop(log_end(S, Pids, Bins, Sync)) end; -log_loop(S, Pids, Bins, Sync, Sz) -> - [M | Ms] = S#state.messages, +log_loop(#state{messages = [M | Ms]}=S, Pids, Bins, Sync, Sz) -> S1 = S#state{messages = Ms}, log_loop(M, Pids, Bins, Sync, Sz, S1, get(log)). diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index 4028dd4f0b..e2290f6a23 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -1416,7 +1416,11 @@ mode_list(_) -> %% Functions for communicating with the file server call(Command, Args) when is_list(Args) -> - gen_server:call(?FILE_SERVER, list_to_tuple([Command | Args]), infinity). + X = erlang:dt_spread_tag(true), + Y = gen_server:call(?FILE_SERVER, list_to_tuple([Command | Args]), + infinity), + erlang:dt_restore_tag(X), + Y. check_and_call(Command, Args) when is_list(Args) -> case check_args(Args) of diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl index 14da9c1a55..7311ad9fee 100644 --- a/lib/kernel/src/file_io_server.erl +++ b/lib/kernel/src/file_io_server.erl @@ -57,9 +57,11 @@ start_link(Owner, FileName, ModeList) do_start(Spawn, Owner, FileName, ModeList) -> Self = self(), Ref = make_ref(), + Utag = erlang:dt_spread_tag(true), Pid = erlang:Spawn( fun() -> + erlang:dt_restore_tag(Utag), %% process_flag(trap_exit, true), case parse_options(ModeList) of {ReadMode, UnicodeMode, Opts} -> @@ -84,6 +86,7 @@ do_start(Spawn, Owner, FileName, ModeList) -> exit(Reason1) end end), + erlang:dt_restore_tag(Utag), Mref = erlang:monitor(process, Pid), receive {Ref, {error, _Reason} = Error} -> diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index 99b0cd2ffb..4dfa92a755 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -1441,6 +1441,9 @@ filter_app("netconf",_) -> % Safe has the same kind of error in the .app file as ic filter_app("safe",_) -> false; +% Comte cannot be started in the "usual" way +filter_app("comte",_) -> + false; % OS_mon does not find it's port program when running cerl filter_app("os_mon",true) -> false; diff --git a/lib/observer/src/observer_perf_wx.erl b/lib/observer/src/observer_perf_wx.erl index 0de9785fb9..fa867e12f6 100644 --- a/lib/observer/src/observer_perf_wx.erl +++ b/lib/observer/src/observer_perf_wx.erl @@ -278,7 +278,7 @@ collect_data(?IO_W, {N, Q}) -> end. mem_types() -> - [total, processes, system, atom, binary, code, ets]. + [total, processes, atom, binary, code, ets]. lmax([]) -> 0; lmax(List) -> diff --git a/lib/public_key/src/public_key.appup.src b/lib/public_key/src/public_key.appup.src index 2945fb1213..aacd3b866d 100644 --- a/lib/public_key/src/public_key.appup.src +++ b/lib/public_key/src/public_key.appup.src @@ -1,16 +1,8 @@ %% -*- erlang -*- {"%VSN%", [ - {"0.13", [{restart_application, public_key}]}, - {"0.11", [{restart_application, public_key}]}, - {"0.10", [{restart_application, public_key}]}, - {"0.9", [{restart_application, public_key}]}, - {"0.8", [{restart_application, public_key}]} + {<<"0\\.*">>, [{restart_application, public_key}]} ], [ - {"0.13", [{restart_application, public_key}]}, - {"0.11", [{restart_application, public_key}]}, - {"0.10", [{restart_application, public_key}]}, - {"0.9", [{restart_application, public_key}]}, - {"0.8", [{restart_application, public_key}]} + {<<"0\\.*">>, [{restart_application, public_key}]} ]}. diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk index d8f811bf25..ab4ee8b0ff 100644 --- a/lib/public_key/vsn.mk +++ b/lib/public_key/vsn.mk @@ -1 +1 @@ -PUBLIC_KEY_VSN = 0.14 +PUBLIC_KEY_VSN = 0.15 diff --git a/lib/reltool/doc/src/reltool.xml b/lib/reltool/doc/src/reltool.xml index 60e886e8f5..696ab52e63 100644 --- a/lib/reltool/doc/src/reltool.xml +++ b/lib/reltool/doc/src/reltool.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2009</year> - <year>2011</year> + <year>2012</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -433,7 +433,7 @@ sys() = {root_dir, root_dir()} | {excl_archive_filters, excl_archive_filters()} | {archive_opts, [archive_opt()]} app() = {vsn, app_vsn()} - | {mod, mod_name(), mod()} + | {mod, mod_name(), [mod()]} | {mod_cond, mod_cond()} | {incl_cond, incl_cond()} | {debug_info, debug_info()} @@ -445,8 +445,7 @@ app() = {vsn, app_vsn()} | {incl_archive_filters, incl_archive_filters()} | {excl_archive_filters, excl_archive_filters()} | {archive_opts, [archive_opt()]} -mod() = {vsn, app_vsn()} - | {incl_cond, incl_cond()} +mod() = {incl_cond, incl_cond()} | {debug_info, debug_info()} rel_app() = app_name() | {app_name(), app_type()} @@ -664,10 +663,10 @@ target_spec() = [target_spec()] </func> <func> - <name>install(Server, TargetDir) -> ok | {error, Reason}</name> + <name>install(RelName, TargetDir) -> ok | {error, Reason}</name> <fsummary>Install a target system</fsummary> <type> - <v>Server = server()</v> + <v>RelName = rel_name()</v> <v>TargetDir = target_dir()</v> <v>Reason = reason()</v> </type> diff --git a/lib/reltool/src/reltool.erl b/lib/reltool/src/reltool.erl index 54eb1ca9e1..2bdf222aa0 100644 --- a/lib/reltool/src/reltool.erl +++ b/lib/reltool/src/reltool.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2011. All Rights Reserved. +%% Copyright Ericsson AB 2009-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 @@ -59,7 +59,7 @@ start_link(Options) when is_list(Options) -> {ok, _WinPid} = OK -> OK; {error, Reason} -> - {error, lists:flatten(io_lib:format("~p", [Reason]))} + {error, Reason} end. %% Start server process with options @@ -69,7 +69,7 @@ start_server(Options) -> {ok, ServerPid, _Common, _Sys} -> {ok, ServerPid}; {error, Reason} -> - {error, lists:flatten(io_lib:format("~p", [Reason]))} + {error, Reason} end. %% Start server process with options diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl index 93f47f6381..4e5c5b2849 100644 --- a/lib/reltool/src/reltool.hrl +++ b/lib/reltool/src/reltool.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2011. All Rights Reserved. +%% Copyright Ericsson AB 2009-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 @@ -45,6 +45,7 @@ -type profile() :: development | embedded | standalone. -type relocatable() :: boolean(). -type escript_file() :: file(). +-type escript_app_name() :: app_name(). -type mod_name() :: atom(). -type app_name() :: atom(). -type app_vsn() :: string(). % e.g. "4.7" @@ -62,7 +63,7 @@ -type mod() :: {incl_cond, incl_cond()} | {debug_info, debug_info()}. -type app() :: {vsn, app_vsn()} - | {mod, mod_name(), mod()} + | {mod, mod_name(), [mod()]} | {mod_cond, mod_cond()} | {incl_cond, incl_cond()} | {app_file, app_file()} @@ -126,10 +127,7 @@ { sys_debug :: term(), wx_debug :: term(), - trap_exit :: boolean(), - app_tab :: ets:tab(), - mod_tab :: ets:tab(), - mod_used_by_tab :: ets:tab() + trap_exit :: boolean() }). -record(mod, @@ -170,7 +168,7 @@ -record(app, { %% Static info name :: app_name(), - is_escript :: boolean(), + is_escript :: boolean() | {inlined, escript_app_name()}, use_selected_vsn :: boolean() | undefined, active_dir :: dir(), sorted_dirs :: [dir()], @@ -199,8 +197,8 @@ used_by_mods :: [mod_name()], uses_apps :: [app_name()], used_by_apps :: [app_name()], - is_pre_included :: boolean(), - is_included :: boolean(), + is_pre_included :: boolean() | undefined, + is_included :: boolean() | undefined, rels :: [rel_name()] }). @@ -208,7 +206,7 @@ { name :: app_name(), app_type :: app_type() | undefined, - incl_apps = [] :: [incl_app()] + incl_apps :: [incl_app()] | undefined }). -record(rel, diff --git a/lib/reltool/src/reltool_app_win.erl b/lib/reltool/src/reltool_app_win.erl index 70bd72b258..e0acfab7aa 100644 --- a/lib/reltool/src/reltool_app_win.erl +++ b/lib/reltool/src/reltool_app_win.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% Copyright Ericsson AB 2009-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 @@ -271,8 +271,8 @@ create_apps_list_ctrl(Panel, Sizer, Text) -> ListItem = wxListItem:new(), wxListItem:setAlign(ListItem, ?wxLIST_FORMAT_LEFT), wxListItem:setText(ListItem, Text), + wxListItem:setWidth(ListItem, reltool_utils:get_column_width(ListCtrl)), wxListCtrl:insertColumn(ListCtrl, ?APPS_APP_COL, ListItem), - %% wxListCtrl:setColumnWidth(ListCtrl, ?APPS_APP_COL, ?APPS_APP_COL_WIDTH), wxListItem:destroy(ListItem), wxSizer:add(Sizer, ListCtrl, @@ -292,7 +292,7 @@ create_deps_page(S, Derived) -> UsedByCtrl = create_mods_list_ctrl(Panel, Main, - "Modules used by others", + "Modules using this", " and their applications", undefined, undefined), diff --git a/lib/reltool/src/reltool_mod_win.erl b/lib/reltool/src/reltool_mod_win.erl index e1c2fa5100..899423bb6d 100644 --- a/lib/reltool/src/reltool_mod_win.erl +++ b/lib/reltool/src/reltool_mod_win.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2011. All Rights Reserved. +%% Copyright Ericsson AB 2009-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 @@ -215,7 +215,7 @@ create_deps_page(S) -> UsedByCtrl = create_mods_list_ctrl(Panel, Main, - "Modules used by others", + "Modules using this", " and their applications"), wxSizer:add(Main, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), @@ -314,8 +314,8 @@ do_create_code_page(#state{xref_pid = Xref, mod = M} = S, PageName) -> {ok, App} = reltool_server:get_app(Xref, M#mod.app_name), ErlBin = case App#app.is_escript of - true -> find_escript_bin(App, M); - false -> find_regular_bin(App, M) + false -> find_regular_bin(App, M); + _ -> find_escript_bin(App, M) end, load_code(Editor, ErlBin), diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl index 692baea0a4..c99180a613 100644 --- a/lib/reltool/src/reltool_server.erl +++ b/lib/reltool/src/reltool_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2011. All Rights Reserved. +%% Copyright Ericsson AB 2009-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 @@ -51,7 +51,12 @@ sys, old_sys, status, - old_status}). + old_status, + app_tab, + old_app_tab, + mod_tab, + old_mod_tab, + mod_used_by_tab}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Client @@ -123,174 +128,165 @@ gen_spec(Pid) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Server -init(Options) -> +init([{parent,Parent}|_] = Options) -> try do_init(Options) catch + throw:{error,Reason} -> + proc_lib:init_ack(Parent,{error,Reason}); error:Reason -> exit({Reason, erlang:get_stacktrace()}) end. do_init(Options) -> - {S, Status} = parse_options(Options), - #state{parent_pid = ParentPid, common = C, sys = Sys} = S, - - %% process_flag(trap_exit, (S#state.common)#common.trap_exit), - proc_lib:init_ack(ParentPid, - {ok, self(), C, Sys#sys{apps = undefined}}), - {S2, Status2} = refresh(S, true, Status), - {S3, Status3} = - analyse(S2#state{old_sys = S2#state.sys}, Status2), - case Status3 of - {ok, _Warnings} -> % BUGBUG: handle warnings - loop(S3#state{status = Status3, old_status = {ok, []}}); - {error, Reason} -> - exit(Reason) - end. - -parse_options(Opts) -> - AppTab = ets:new(reltool_apps, [public, ordered_set, {keypos, #app.name}]), - ModTab = ets:new(reltool_mods, [public, ordered_set, {keypos, #mod.name}]), + AppTab = ets:new(reltool_apps1, [public, ordered_set, {keypos,#app.name}]), + OldAppTab = ets:new(reltool_apps2, [public, ordered_set, {keypos,#app.name}]), + ModTab = ets:new(reltool_mods1, [public, ordered_set, {keypos,#mod.name}]), + OldModTab = ets:new(reltool_mods2, [public, ordered_set, {keypos,#mod.name}]), ModUsesTab = ets:new(reltool_mod_uses, [public, bag, {keypos, 1}]), - Sys = #sys{root_dir = reltool_utils:root_dir(), - lib_dirs = reltool_utils:erl_libs(), - escripts = [], - incl_cond = ?DEFAULT_INCL_COND, - mod_cond = ?DEFAULT_MOD_COND, - apps = ?DEFAULT_APPS, - boot_rel = ?DEFAULT_REL_NAME, - rels = reltool_utils:default_rels(), - emu_name = ?DEFAULT_EMU_NAME, - profile = ?DEFAULT_PROFILE, - incl_sys_filters = dec_re(incl_sys_filters, - ?DEFAULT_INCL_SYS_FILTERS, - []), - excl_sys_filters = dec_re(excl_sys_filters, - ?DEFAULT_EXCL_SYS_FILTERS, - []), - incl_app_filters = dec_re(incl_app_filters, - ?DEFAULT_INCL_APP_FILTERS, - []), - excl_app_filters = dec_re(excl_app_filters, - ?DEFAULT_EXCL_APP_FILTERS, - []), - relocatable = ?DEFAULT_RELOCATABLE, - rel_app_type = ?DEFAULT_REL_APP_TYPE, - embedded_app_type = ?DEFAULT_EMBEDDED_APP_TYPE, - app_file = ?DEFAULT_APP_FILE, - incl_archive_filters = dec_re(incl_archive_filters, - ?DEFAULT_INCL_ARCHIVE_FILTERS, - []), - excl_archive_filters = dec_re(excl_archive_filters, - ?DEFAULT_EXCL_ARCHIVE_FILTERS, - []), - archive_opts = ?DEFAULT_ARCHIVE_OPTS, - debug_info = ?DEFAULT_DEBUG_INFO}, - C2 = #common{sys_debug = [], - wx_debug = 0, - trap_exit = true, - app_tab = AppTab, - mod_tab = ModTab, - mod_used_by_tab = ModUsesTab}, - S = #state{options = Opts}, - parse_options(Opts, S, C2, Sys, {ok, []}). + S = #state{options = Options, + app_tab = AppTab, + old_app_tab = OldAppTab, + mod_tab = ModTab, + old_mod_tab = OldModTab, + mod_used_by_tab = ModUsesTab}, + + S2 = parse_options(S), + {S3, Apps, Status2} = refresh(S2), + Status3 = analyse(S3, Apps, Status2), + %% Set old_xxx equal to xxx to allow undo=nop + FakeBackup = {ets:tab2list(S3#state.app_tab),ets:tab2list(S3#state.mod_tab)}, + S4 = save_old(S3, S3, FakeBackup, Status3), + #state{parent_pid = Parent, sys=Sys, common=C} = S4, + proc_lib:init_ack(Parent, {ok, self(), C, Sys#sys{apps=undefined}}), + loop(S4). + +parse_options(S) -> + Sys = default_sys(), + C = #common{sys_debug = [], + wx_debug = 0, + trap_exit = true}, + parse_options(S#state.options, S, C, Sys). + +default_sys() -> + #sys{root_dir = reltool_utils:root_dir(), + lib_dirs = reltool_utils:erl_libs(), + escripts = [], + incl_cond = ?DEFAULT_INCL_COND, + mod_cond = ?DEFAULT_MOD_COND, + apps = ?DEFAULT_APPS, + boot_rel = ?DEFAULT_REL_NAME, + rels = reltool_utils:default_rels(), + emu_name = ?DEFAULT_EMU_NAME, + profile = ?DEFAULT_PROFILE, + incl_sys_filters = dec_re(incl_sys_filters, + ?DEFAULT_INCL_SYS_FILTERS, + []), + excl_sys_filters = dec_re(excl_sys_filters, + ?DEFAULT_EXCL_SYS_FILTERS, + []), + incl_app_filters = dec_re(incl_app_filters, + ?DEFAULT_INCL_APP_FILTERS, + []), + excl_app_filters = dec_re(excl_app_filters, + ?DEFAULT_EXCL_APP_FILTERS, + []), + relocatable = ?DEFAULT_RELOCATABLE, + rel_app_type = ?DEFAULT_REL_APP_TYPE, + embedded_app_type = ?DEFAULT_EMBEDDED_APP_TYPE, + app_file = ?DEFAULT_APP_FILE, + incl_archive_filters = dec_re(incl_archive_filters, + ?DEFAULT_INCL_ARCHIVE_FILTERS, + []), + excl_archive_filters = dec_re(excl_archive_filters, + ?DEFAULT_EXCL_ARCHIVE_FILTERS, + []), + archive_opts = ?DEFAULT_ARCHIVE_OPTS, + debug_info = ?DEFAULT_DEBUG_INFO}. dec_re(Key, Regexps, Old) -> reltool_utils:decode_regexps(Key, Regexps, Old). -parse_options([{Key, Val} | KeyVals], S, C, Sys, Status) -> +parse_options([{Key, Val} | KeyVals], S, C, Sys) -> case Key of parent -> - parse_options(KeyVals, S#state{parent_pid = Val}, C, Sys, Status); + parse_options(KeyVals, S#state{parent_pid = Val}, C, Sys); sys_debug -> - parse_options(KeyVals, S, C#common{sys_debug = Val}, Sys, Status); + parse_options(KeyVals, S, C#common{sys_debug = Val}, Sys); wx_debug -> - parse_options(KeyVals, S, C#common{wx_debug = Val}, Sys, Status); + parse_options(KeyVals, S, C#common{wx_debug = Val}, Sys); trap_exit -> - parse_options(KeyVals, S, C#common{trap_exit = Val}, Sys, Status); + parse_options(KeyVals, S, C#common{trap_exit = Val}, Sys); config -> - {Sys2, Status2} = read_config(Sys, Val, Status), - parse_options(KeyVals, S, C, Sys2, Status2); + Sys2 = read_config(Sys, Val), + parse_options(KeyVals, S, C, Sys2); sys -> - {Sys2, Status2} = read_config(Sys, {sys, Val}, Status), - parse_options(KeyVals, S, C, Sys2, Status2); + Sys2 = read_config(Sys, {sys, Val}), + parse_options(KeyVals, S, C, Sys2); _ -> - Text = lists:flatten(io_lib:format("~p", [{Key, Val}])), - Status2 = - reltool_utils:return_first_error(Status, - "Illegal option: " ++ Text), - parse_options(KeyVals, S, C, Sys, Status2) + reltool_utils:throw_error("Illegal option: ~p", [{Key, Val}]) end; -parse_options([], S, C, Sys, Status) -> - {S#state{common = C, sys = Sys}, Status}; -parse_options(KeyVals, S, C, Sys, Status) -> - Text = lists:flatten(io_lib:format("~p", [KeyVals])), - Status2 = reltool_utils:return_first_error(Status, - "Illegal options: " ++ Text), - {S#state{common = C, sys = Sys}, Status2}. - -loop(#state{common = C, sys = Sys} = S) -> +parse_options([], S, C, Sys) -> + S#state{common = C, sys = Sys}; +parse_options(KeyVals, _S, _C, _Sys) -> + reltool_utils:throw_error("Illegal option: ~p", [KeyVals]). + +loop(#state{sys = Sys} = S) -> receive {system, From, Msg} -> sys:handle_system_msg(Msg, From, S#state.parent_pid, ?MODULE, - C#common.sys_debug, + (S#state.common)#common.sys_debug, S); {call, ReplyTo, Ref, {get_config, InclDef, InclDeriv}} -> Reply = do_get_config(S, InclDef, InclDeriv), reltool_utils:reply(ReplyTo, Ref, Reply), ?MODULE:loop(S); {call, ReplyTo, Ref, {load_config, SysConfig}} -> - {S2, Reply} = do_load_config(S, SysConfig), - reltool_utils:reply(ReplyTo, Ref, Reply), - ?MODULE:loop(S2); + Fun = fun() -> do_load_config(S, SysConfig) end, + {S3, Status2} = config_and_refresh(S, Fun), + reltool_utils:reply(ReplyTo, Ref, Status2), + ?MODULE:loop(S3); {call, ReplyTo, Ref, {save_config, Filename, InclDef, InclDeriv}} -> Reply = do_save_config(S, Filename, InclDef, InclDeriv), reltool_utils:reply(ReplyTo, Ref, Reply), ?MODULE:loop(S); {call, ReplyTo, Ref, reset_config} -> - {S2, Status} = parse_options(S#state.options), - S3 = shrink_sys(S2), - {S4, Status2} = refresh(S3, true, Status), - {S5, Status3} = analyse(S4#state{old_sys = S4#state.sys}, Status2), - S6 = - case Status3 of - {ok, _Warnings} -> - S5#state{status = Status3, old_status = S#state.status}; - {error, _} -> - %% Keep old state - S - end, - reltool_utils:reply(ReplyTo, Ref, Status3), - ?MODULE:loop(S6); + Fun = fun() -> parse_options(S) end, + {S3, Status2} = config_and_refresh(S, Fun), + reltool_utils:reply(ReplyTo, Ref, Status2), + ?MODULE:loop(S3); {call, ReplyTo, Ref, undo_config} -> - reltool_utils:reply(ReplyTo, Ref, ok), S2 = S#state{sys = S#state.old_sys, - old_sys = S#state.sys, - status = S#state.old_status, - old_status = S#state.status}, + old_sys = Sys, + status = S#state.old_status, + old_status = S#state.status, + app_tab = S#state.old_app_tab, + old_app_tab = S#state.app_tab, + mod_tab = S#state.old_mod_tab, + old_mod_tab = S#state.mod_tab}, + reltool_utils:reply(ReplyTo, Ref, ok), ?MODULE:loop(S2); {call, ReplyTo, Ref, {get_rel, RelName}} -> - Sys = S#state.sys, Reply = case lists:keysearch(RelName, #rel.name, Sys#sys.rels) of {value, Rel} -> - reltool_target:gen_rel(Rel, Sys); + reltool_target:gen_rel(Rel, sys_all_apps(S)); false -> {error, "No such release: " ++ RelName} end, reltool_utils:reply(ReplyTo, Ref, Reply), ?MODULE:loop(S); {call, ReplyTo, Ref, {get_script, RelName}} -> - Sys = S#state.sys, Reply = case lists:keysearch(RelName, #rel.name, Sys#sys.rels) of {value, Rel} -> PathFlag = true, Vars = [], - reltool_target:gen_script(Rel, Sys, PathFlag, Vars); + reltool_target:gen_script(Rel, sys_all_apps(S), + PathFlag, Vars); false -> {error, "No such release: " ++ RelName} end, @@ -298,7 +294,7 @@ loop(#state{common = C, sys = Sys} = S) -> ?MODULE:loop(S); {call, ReplyTo, Ref, {get_mod, ModName}} -> Reply = - case ets:lookup(C#common.mod_tab, ModName) of + case ets:lookup(S#state.mod_tab, ModName) of [M] -> {ok, M}; [] -> @@ -308,92 +304,83 @@ loop(#state{common = C, sys = Sys} = S) -> ?MODULE:loop(S); {call, ReplyTo, Ref, {get_app, AppName}} when is_atom(AppName) -> Reply = - case lists:keysearch(AppName, #app.name, Sys#sys.apps) of - {value, App} -> + case ets:lookup(S#state.app_tab,AppName) of + [App] -> {ok, App}; - false -> + [] -> {error, "No such application: " ++ atom_to_list(AppName)} end, reltool_utils:reply(ReplyTo, Ref, Reply), ?MODULE:loop(S); {call, ReplyTo, Ref, {set_app, App}} -> - {S2, Status} = do_set_app(S, App, {ok, []}), - {S3, Status2} = analyse(S2, Status), - case Status2 of - {ok, Warnings} -> - App2 = ?KEYSEARCH(App#app.name, - #app.name, - (S3#state.sys)#sys.apps), - reltool_utils:reply(ReplyTo, Ref, {ok, App2, Warnings}), - ?MODULE:loop(S3); - {error, Reason} -> - %% Keep old state - reltool_utils:reply(ReplyTo, Ref, {error, Reason}), - ?MODULE:loop(S) - end; + Fun = fun() -> do_set_apps(S, [App]) end, + {S3, Status2} = config_and_refresh(S, Fun), + Reply = + case Status2 of + {ok, Warnings} -> + [App2] = ets:lookup(S3#state.app_tab,App#app.name), + {ok, App2, Warnings}; + {error, _} -> + Status2 + end, + reltool_utils:reply(ReplyTo, Ref, Reply), + ?MODULE:loop(S3); {call, ReplyTo, Ref, {get_apps, Kind}} -> AppNames = case Kind of whitelist -> - [A || - A <- Sys#sys.apps, - A#app.is_pre_included =:= true]; - blacklist -> - [A || - A <- Sys#sys.apps, - A#app.is_pre_included =:= false]; - source -> - [A || - A <- Sys#sys.apps, - A#app.is_included =/= true, - A#app.is_pre_included =/= false]; + %% Pre-included + ets:select(S#state.app_tab, + [{#app{is_pre_included=true,_='_'}, + [], + ['$_']}]); + blacklist -> + %% Pre-excluded + ets:select(S#state.app_tab, + [{#app{is_pre_included=false,_='_'}, + [], + ['$_']}]); + source -> + %% Not included and not pre-excluded + ets:select(S#state.app_tab, + [{#app{is_included='$1', + is_pre_included='$2', + _='_'}, + [{'=/=','$1',true}, + {'=/=','$2',false}], + ['$_']}]); derived -> - [A || - A <- Sys#sys.apps, - A#app.is_included =:= true, - A#app.is_pre_included =/= true] + %% Included, but not pre-included + ets:select(S#state.app_tab, + [{#app{is_included='$1', + is_pre_included='$2', + _='_'}, + [{'=:=','$1',true}, + {'=/=','$2',true}], + ['$_']}]) end, reltool_utils:reply(ReplyTo, Ref, {ok, AppNames}), ?MODULE:loop(S); {call, ReplyTo, Ref, {set_apps, Apps}} -> - {S2, Status} = - lists:foldl(fun(A, {X, Y}) -> do_set_app(X, A, Y) end, - {S, {ok, []}}, - Apps), - {S3, Status2} = analyse(S2, Status), + Fun = fun() -> do_set_apps(S, Apps) end, + {S3, Status2} = config_and_refresh(S, Fun), reltool_utils:reply(ReplyTo, Ref, Status2), - ?MODULE:loop(S3); + ?MODULE:loop(S3); {call, ReplyTo, Ref, get_sys} -> reltool_utils:reply(ReplyTo, Ref, {ok, Sys#sys{apps = undefined}}), ?MODULE:loop(S); {call, ReplyTo, Ref, {set_sys, Sys2}} -> - S2 = S#state{sys = Sys2#sys{apps = Sys#sys.apps}}, - Force = - (Sys2#sys.root_dir =/= Sys#sys.root_dir) orelse - (Sys2#sys.lib_dirs =/= Sys#sys.lib_dirs) orelse - (Sys2#sys.escripts =/= Sys#sys.escripts), - {S3, Status} = refresh(S2, Force, {ok, []}), - {S4, Status2} = - analyse(S3#state{old_sys = S#state.sys}, Status), - {S5, Status3} = - case Status2 of - {ok, _Warnings} -> % BUGBUG: handle warnings - {S4#state{status = Status2, - old_status = S#state.status}, - Status2}; - {error, _} -> - %% Keep old state - {S, Status2} - end, - reltool_utils:reply(ReplyTo, Ref, Status3), - ?MODULE:loop(S5); + Fun = fun() -> S#state{sys = Sys2#sys{apps = Sys#sys.apps}} end, + {S3, Status} = config_and_refresh(S, Fun), + reltool_utils:reply(ReplyTo, Ref, Status), + ?MODULE:loop(S3); {call, ReplyTo, Ref, get_status} -> reltool_utils:reply(ReplyTo, Ref, S#state.status), ?MODULE:loop(S); {call, ReplyTo, Ref, {gen_rel_files, Dir}} -> Status = - case reltool_target:gen_rel_files(S#state.sys, Dir) of + case reltool_target:gen_rel_files(sys_all_apps(S), Dir) of ok -> {ok, []}; {error, Reason} -> @@ -402,11 +389,11 @@ loop(#state{common = C, sys = Sys} = S) -> reltool_utils:reply(ReplyTo, Ref, Status), ?MODULE:loop(S); {call, ReplyTo, Ref, {gen_target, Dir}} -> - Reply = reltool_target:gen_target(S#state.sys, Dir), + Reply = reltool_target:gen_target(sys_all_apps(S), Dir), reltool_utils:reply(ReplyTo, Ref, Reply), ?MODULE:loop(S); {call, ReplyTo, Ref, gen_spec} -> - Reply = reltool_target:gen_spec(S#state.sys), + Reply = reltool_target:gen_spec(sys_all_apps(S)), reltool_utils:reply(ReplyTo, Ref, Reply), ?MODULE:loop(S); {'EXIT', Pid, Reason} when Pid =:= S#state.parent_pid -> @@ -422,101 +409,211 @@ loop(#state{common = C, sys = Sys} = S) -> ?MODULE:loop(S) end. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -do_set_app(#state{sys = Sys} = S, App, Status) -> - AppName = App#app.name, - {App2, Status2} = refresh_app(App, false, Status), - Apps = Sys#sys.apps, - Apps2 = lists:keystore(AppName, #app.name, Apps, App2), - Escripts = [A#app.active_dir || A <- Apps2, A#app.is_escript], - Sys2 = Sys#sys{apps = Apps2, escripts = Escripts}, - {S#state{sys = Sys2}, Status2}. - -analyse(#state{common = C, - sys = #sys{apps = Apps0, rels = Rels} = Sys} = S, - Status) -> - Apps = lists:keydelete(?MISSING_APP_NAME, #app.name, Apps0), - ets:delete_all_objects(C#common.app_tab), - ets:delete_all_objects(C#common.mod_tab), - ets:delete_all_objects(C#common.mod_used_by_tab), - MissingApp = default_app(?MISSING_APP_NAME, "missing"), - ets:insert(C#common.app_tab, MissingApp), - - {RevRelApps, Status2} = apps_in_rels(Rels, Apps, Status), - RelApps2 = lists:reverse(RevRelApps), - {Apps2, Status3} = - lists:mapfoldl(fun(App, Acc) -> - app_init_is_included(C, Sys, App, RelApps2, Acc) - end, - Status2, - Apps), - Apps3 = - case app_propagate_is_included(C, Sys, Apps2, []) of - [] -> - Apps2; - MissingMods -> - %% io:format("Missing mods: ~p\n", [MissingMods]), - MissingApp2 = MissingApp#app{label = ?MISSING_APP_TEXT, - info = missing_app_info(""), - mods = MissingMods, - status = missing, - uses_mods = []}, - [MissingApp2 | Apps2] - end, - app_propagate_is_used_by(C, Apps3), - {Apps4,Status4} = app_recap_dependencies(C, Sys, Apps3, [], Status3), - %% io:format("Missing app: ~p\n", - %% [lists:keysearch(?MISSING_APP_NAME, #app.name, Apps4)]), - Sys2 = Sys#sys{apps = Apps4}, - - case verify_config(RelApps2, Sys2, Status4) of - {ok, _Warnings} = Status5 -> - {S#state{sys = Sys2}, Status5}; - {error, _} = Status5 -> - {S, Status5} + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +do_set_apps(#state{sys = Sys} = S, ChangedApps) -> + %% Create new list of configured applications + SysApps = app_update_config(ChangedApps, Sys#sys.apps), + S#state{sys = Sys#sys{apps = SysApps}}. + +%% Re-create the #sys.apps list by +%% 1) taking configurable fields from the changed #app records and +%% create new default records +%% 2) removing #app records if no configurable fields are set +%% 3) keeping #app records that are not changed +app_update_config([#app{name=Name,is_escript={inlined,Escript}}|_],_SysApps) -> + reltool_utils:throw_error("Application ~p is inlined in ~p. Can not change " + "configuration for an inlined application.", + [Name,Escript]); +app_update_config([Config|Configs],SysApps) -> + NewSysApps = + case app_set_config_only(Config) of + {delete,Name} -> + lists:keydelete(Name,#app.name,SysApps); + New -> + lists:ukeymerge(#app.name,[New],SysApps) + end, + app_update_config(Configs,NewSysApps); +app_update_config([],SysApps) -> + SysApps. + +app_set_config_only(#app{mods=ConfigMods} = Config) -> + app_set_config_only(mod_set_config_only(ConfigMods),Config). + +app_set_config_only([],#app{name = Name, + incl_cond = undefined, + mod_cond = undefined, + use_selected_vsn = undefined, + debug_info = undefined, + app_file = undefined, + app_type = undefined, + incl_app_filters = undefined, + excl_app_filters = undefined, + incl_archive_filters = undefined, + excl_archive_filters = undefined, + archive_opts = undefined, + is_escript = false})-> + {delete,Name}; +app_set_config_only(Mods,#app{name = Name, + incl_cond = InclCond, + mod_cond = ModCond, + use_selected_vsn = UseSelectedVsn, + debug_info = DebugInfo, + app_file = AppFile, + app_type = AppType, + incl_app_filters = InclAppFilters, + excl_app_filters = ExclAppFilters, + incl_archive_filters = InclArchiveFilters, + excl_archive_filters = ExclArchiveFilters, + archive_opts = ArchiveOpts, + vsn = Vsn, + is_escript = IsEscript, + label = Label, + info = Info, + active_dir = ActiveDir, + sorted_dirs = SortedDirs}) -> + App = (default_app(Name))#app{incl_cond = InclCond, + mod_cond = ModCond, + use_selected_vsn = UseSelectedVsn, + debug_info = DebugInfo, + app_file = AppFile, + app_type = AppType, + incl_app_filters = InclAppFilters, + excl_app_filters = ExclAppFilters, + incl_archive_filters = InclArchiveFilters, + excl_archive_filters = ExclArchiveFilters, + archive_opts = ArchiveOpts, + vsn = Vsn, + mods = Mods}, + + %% Some fields shall only be set if it is an escript, e.g. label + %% must never be set for any other applications since that will + %% prevent refreshing. + if IsEscript -> + App#app{is_escript = IsEscript, + active_dir = ActiveDir, + sorted_dirs = SortedDirs, + label = Label, + info = Info}; + true -> + App end. -apps_in_rels(Rels, Apps, Status) -> - lists:foldl(fun(Rel, {RelApps, S}) -> - {MoreRelApps, S2} = apps_in_rel(Rel, Apps, S), - {MoreRelApps ++ RelApps, S2} - end, - {[], Status}, - Rels). +mod_set_config_only(ConfigMods) -> + [#mod{name = Name, + incl_cond = InclCond, + debug_info = DebugInfo} || + #mod{name = Name, + incl_cond = InclCond, + debug_info = DebugInfo} <- ConfigMods, + (InclCond =/= undefined) orelse (DebugInfo =/= undefined)]. -apps_in_rel(#rel{name = RelName, rel_apps = RelApps}, Apps, Status) -> - Mandatory = [{RelName, kernel}, {RelName, stdlib}], - Other = [{RelName, AppName} || - RA <- RelApps, - AppName <- [RA#rel_app.name | RA#rel_app.incl_apps], - not lists:keymember(AppName, 2, Mandatory)], - more_apps_in_rels(Mandatory ++ Other, Apps, [], Status). -more_apps_in_rels([{RelName, AppName} = RA | RelApps], Apps, Acc, Status) -> + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +analyse(#state{sys=Sys} = S, Apps, Status) -> + %% Create a list of {RelName,AppName}, one element for each + %% AppName that needs to be included for the given release. + RelApps = apps_in_rels(Sys#sys.rels, Apps), + + %% Initiate is_pre_included and is_included for all applications + %% based on #sys.incl_cond, #app.incl_cond and if the application + %% is included in a release (rel spec - see apps_in_rels above). + %% Then initiate the same for each module, and check that there + %% are no duplicated module names (in different applications) + %% where we can not decide which one to use. + %% Write all #app to app_tab and all #mod to mod_tab. + Status2 = apps_init_is_included(S, Apps, RelApps, Status), + + %% For each module that has #mod.is_included==true, propagate + %% is_included to the modules it uses. + propagate_is_included(S), + + %% Insert reverse dependencies - i.e. for each + %% #mod{name=Mod, uses_mods=[UsedMod]}, + %% insert an entry {UsedMod,Mod} in mod_used_by_tab. + propagate_is_used_by(S), + + %% Set the above reverse dependencies in #mod records + %% (used_by_mods) and accumulate in #app records. + %% Make sure #app.is_included is always true if some + %% #mod.is_included==true for at least one module in the app. + %% Set status=missing|ok for #app and #mod - indicates if module + %% (.beam file) is missing in file system. + app_recap_dependencies(S), + + %% Check that the boot_rel exists. + %% Check that all applications that are listed in a 'rel' spec are + %% also really included in the target release. + %% Check that all mandatory applications are included in all rels. + verify_config(S, RelApps, Status2). + +apps_in_rels(Rels, Apps) -> + AllRelApps = + lists:foldl(fun(Rel, RelApps) -> + MoreRelApps = apps_in_rel(Rel, Apps), + MoreRelApps ++ RelApps + end, + [], + Rels), + lists:reverse(AllRelApps). + +apps_in_rel(#rel{name = RelName, rel_apps = RelApps}, Apps) -> + Mandatory = [{RelName, kernel}, {RelName, stdlib}], + Other = + [{RelName, AppName} || + RA <- RelApps, + AppName <- [RA#rel_app.name | + %% Included applications in rel shall overwrite included + %% applications in .app. I.e. included applications in + %% .app shall only be used if it is not defined in rel. + case RA#rel_app.incl_apps of + undefined -> + case lists:keyfind(RA#rel_app.name, + #app.name, + Apps) of + #app{info = #app_info{incl_apps = IA}} -> + IA; + false -> + reltool_utils:throw_error( + "Release ~p uses non existing " + "application ~p", + [RelName,RA#rel_app.name]) + end; + IA -> + IA + end], + not lists:keymember(AppName, 2, Mandatory)], + more_apps_in_rels(Mandatory ++ Other, Apps, []). + +more_apps_in_rels([{RelName, AppName} = RA | RelApps], Apps, Acc) -> case lists:member(RA, Acc) of true -> - more_apps_in_rels(RelApps, Apps, Acc, Status); + more_apps_in_rels(RelApps, Apps, Acc); false -> case lists:keyfind(AppName, #app.name, Apps) of #app{info = #app_info{applications = InfoApps}} -> Extra = [{RelName, N} || N <- InfoApps], - {Acc2, Status2} = - more_apps_in_rels(Extra, Apps, [RA | Acc], Status), - more_apps_in_rels(RelApps, Apps, Acc2, Status2); + Acc2 = more_apps_in_rels(Extra, Apps, [RA | Acc]), + more_apps_in_rels(RelApps, Apps, Acc2); false -> - Text = lists:concat(["Release ", RelName, - " uses non existing application ", - AppName]), - Status2 = reltool_utils:return_first_error(Status, Text), - more_apps_in_rels(RelApps, Apps, Acc, Status2) + reltool_utils:throw_error( + "Release ~p uses non existing application ~p", + [RelName,AppName]) end end; -more_apps_in_rels([], _Apps, Acc, Status) -> - {Acc, Status}. +more_apps_in_rels([], _Apps, Acc) -> + Acc. + + +apps_init_is_included(S, Apps, RelApps, Status) -> + lists:foldl(fun(App, AccStatus) -> + app_init_is_included(S, App, RelApps, AccStatus) + end, + Status, + Apps). -app_init_is_included(C, - Sys, +app_init_is_included(#state{app_tab = AppTab, mod_tab = ModTab, sys=Sys}, #app{name = AppName, mods = Mods} = A, RelApps, Status) -> @@ -538,18 +635,16 @@ app_init_is_included(C, {exclude, []} -> {undefined, false, false, Status}; {exclude, [RelName | _]} -> % App is included in at least one rel - Text = lists:concat(["Application ", AppName, " is used " - "in release ", RelName, " and cannot " - "be excluded"]), - TmpStatus = reltool_utils:return_first_error(Status, Text), - {undefined, false, false, TmpStatus}; + reltool_utils:throw_error( + "Application ~p is used in release ~p and cannot be excluded", + [AppName,RelName]); {derived, []} -> {undefined, undefined, undefined, Status}; {derived, [_ | _]} -> % App is included in at least one rel {true, undefined, true, Status} end, {Mods2,Status3} = lists:mapfoldl(fun(Mod,Acc) -> - mod_init_is_included(C, + mod_init_is_included(ModTab, Mod, ModCond, AppCond, @@ -562,10 +657,10 @@ app_init_is_included(C, is_pre_included = IsPreIncl, is_included = IsIncl, rels = Rels}, - ets:insert(C#common.app_tab, A2), - {A2, Status3}. + ets:insert(AppTab, A2), + Status3. -mod_init_is_included(C, M, ModCond, AppCond, Default, Status) -> +mod_init_is_included(ModTab, M, ModCond, AppCond, Default, Status) -> %% print(M#mod.name, hipe, "incl_cond -> ~p\n", [AppCond]), IsIncl = case AppCond of @@ -602,43 +697,33 @@ mod_init_is_included(C, M, ModCond, AppCond, Default, Status) -> M2 = M#mod{is_pre_included = IsIncl, is_included = IsIncl}, Status2 = - case ets:lookup(C#common.mod_tab,M#mod.name) of + case ets:lookup(ModTab,M#mod.name) of [Existing] -> case {Existing#mod.is_included,IsIncl} of {false,_} -> - Warning = - lists:concat( - ["Module ",M#mod.name, - " exists in applications ", Existing#mod.app_name, - " and ", M#mod.app_name, - ". Using module from application ", - M#mod.app_name, "."]), - ets:insert(C#common.mod_tab, M2), - reltool_utils:add_warning(Status,Warning); + ets:insert(ModTab, M2), + reltool_utils:add_warning( + "Module ~p exists in applications ~p and ~p. " + "Using module from application ~p.", + [M#mod.name, Existing#mod.app_name, + M#mod.app_name, M#mod.app_name], + Status); {_,false} -> - Warning = - lists:concat( - ["Module ",M#mod.name, - " exists in applications ", Existing#mod.app_name, - " and ", M#mod.app_name, - ". Using module from application ", - Existing#mod.app_name, "."]), - - %% Don't insert in mod_tab - using Existing - reltool_utils:add_warning(Status,Warning); + %% Don't insert in ModTab - using Existing + reltool_utils:add_warning( + "Module ~p exists in applications ~p and ~p. " + "Using module from application ~p.", + [M#mod.name, Existing#mod.app_name, + M#mod.app_name,Existing#mod.app_name], + Status); {_,_} -> - Error = - lists:concat( - ["Module ",M#mod.name, - " potentially included by ", - "two different applications: ", - Existing#mod.app_name, " and ", - M#mod.app_name, "."]), - %% Don't insert in mod_tab - using Existing - reltool_utils:return_first_error(Status,Error) + reltool_utils:throw_error( + "Module ~p potentially included by two different " + "applications: ~p and ~p.", + [M#mod.name,Existing#mod.app_name,M#mod.app_name]) end; [] -> - ets:insert(C#common.mod_tab, M2), + ets:insert(ModTab, M2), Status end, @@ -651,55 +736,43 @@ false_to_undefined(Bool) -> _ -> Bool end. -app_propagate_is_included(C, Sys, [#app{mods = Mods} = A | Apps], Acc) -> - Acc2 = mod_propagate_is_included(C, Sys, A, Mods, Acc), - app_propagate_is_included(C, Sys, Apps, Acc2); -app_propagate_is_included(_C, _Sys, [], Acc) -> - Acc. - -mod_propagate_is_included(C, Sys, A, [#mod{name = ModName} | Mods], Acc) -> - Acc2 = - case ets:lookup(C#common.mod_tab, ModName) of - [M2] when M2#mod.app_name=:=A#app.name -> - %% print(ModName, file, "Maybe Prop ~p -> ~p\n", - %% [M2, M2#mod.is_included]), - %% print(ModName, filename, "Maybe Prop ~p -> ~p\n", - %% [M2, M2#mod.is_included]), - case M2#mod.is_included of - true -> - %% Propagate include mark - mod_mark_is_included(C,Sys,ModName,M2#mod.uses_mods,Acc); - false -> - Acc; - undefined -> - Acc - end; - [_] -> - %% This module is currently used from a different application - %% Ignore - Acc - end, - mod_propagate_is_included(C, Sys, A, Mods, Acc2); -mod_propagate_is_included(_C, _Sys, _A, [], Acc) -> - Acc. +%% Return the list for {ModName, UsesModNames} for all modules where +%% #mod.is_included==true. +get_all_mods_and_dependencies(S) -> + ets:select(S#state.mod_tab, [{#mod{name='$1', + uses_mods='$2', + is_included=true, + _='_'}, + [], + [{{'$1','$2'}}]}]). + +propagate_is_included(S) -> + case lists:flatmap( + fun({ModName,UsesModNames}) -> + mod_mark_is_included(S,ModName,UsesModNames,[]) + end, + get_all_mods_and_dependencies(S)) of + [] -> + ok; + MissingMods -> + MissingApp = default_app(?MISSING_APP_NAME, "missing"), + MissingApp2 = MissingApp#app{label = ?MISSING_APP_TEXT, + info = missing_app_info(""), + mods = MissingMods, + status = missing, + uses_mods = []}, + ets:insert(S#state.app_tab, MissingApp2), + ok + end. -mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) -> +mod_mark_is_included(#state{app_tab=AppTab, mod_tab=ModTab, sys=Sys} = S, + UsedByName, [ModName | ModNames], Acc) -> Acc3 = - case ets:lookup(C#common.mod_tab, ModName) of + case ets:lookup(ModTab, ModName) of [M] -> - %% print(UsedByName, file, "Maybe Mark ~p -> ~p\n", - %% [M, M#mod.is_included]), - %% print(UsedByName, filename, "Maybe Mark ~p -> ~p\n", - %% [M, M#mod.is_included]), case M#mod.is_included of - true -> - %% Already marked - Acc; - false -> - %% Already marked - Acc; undefined -> - %% Mark and propagate + %% Not yet marked => mark and propagate M2 = case M#mod.incl_cond of include -> @@ -711,16 +784,10 @@ mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) -> undefined -> M#mod{is_included = true} end, - ets:insert(C#common.mod_tab, M2), - %% io:format("Propagate mod: ~p -> ~p (~p)\n", - %% [UsedByName, ModName, M#mod.incl_cond]), - [A] = ets:lookup(C#common.app_tab, M2#mod.app_name), + ets:insert(ModTab, M2), + [A] = ets:lookup(AppTab, M2#mod.app_name), Acc2 = case A#app.is_included of - true -> - Acc; - false -> - Acc; undefined -> ModCond = case A#app.mod_cond of @@ -738,63 +805,50 @@ mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) -> end end, Mods = lists:filter(Filter, A#app.mods), - %% io:format("Propagate app: ~p ~p -> ~p\n", - %% [UsedByName, A#app.name, - %% [M3#mod.name || M3 <- Mods]]), A2 = A#app{is_included = true}, - ets:insert(C#common.app_tab, A2), - mod_mark_is_included(C, - Sys, + ets:insert(AppTab, A2), + mod_mark_is_included(S, ModName, [M3#mod.name || M3 <- Mods], - Acc) + Acc); + _ -> + %% Already marked true or false + Acc end, - mod_mark_is_included(C, - Sys, - ModName, - M2#mod.uses_mods, - Acc2) + mod_mark_is_included(S, ModName, M2#mod.uses_mods, Acc2); + _ -> + %% Already marked true or false + Acc end; [] -> M = missing_mod(ModName, ?MISSING_APP_NAME), M2 = M#mod{is_included = true}, - ets:insert(C#common.mod_tab, M2), - ets:insert(C#common.mod_used_by_tab, {UsedByName, ModName}), + ets:insert(ModTab, M2), [M2 | Acc] end, - mod_mark_is_included(C, Sys, UsedByName, ModNames, Acc3); -mod_mark_is_included(_C, _Sys, _UsedByName, [], Acc) -> + mod_mark_is_included(S, UsedByName, ModNames, Acc3); +mod_mark_is_included(_S, _UsedByName, [], Acc) -> Acc. -app_propagate_is_used_by(C, [#app{mods = Mods, name = Name} | Apps]) -> - case Name =:= ?MISSING_APP_NAME of - true -> ok; - false -> ok - end, - mod_propagate_is_used_by(C, Mods), - app_propagate_is_used_by(C, Apps); -app_propagate_is_used_by(_C, []) -> - ok. +propagate_is_used_by(S) -> + lists:foreach( + fun({Mod,UsesMods}) -> + lists:foreach( + fun(UsedMod) -> + ets:insert(S#state.mod_used_by_tab,{UsedMod,Mod}) + end, + UsesMods) + end, + get_all_mods_and_dependencies(S)). -mod_propagate_is_used_by(C, [#mod{name = ModName} | Mods]) -> - [M] = ets:lookup(C#common.mod_tab, ModName), - case M#mod.is_included of - true -> - [ets:insert(C#common.mod_used_by_tab, {UsedModName, ModName}) || - UsedModName <- M#mod.uses_mods]; - false -> - ignore; - undefined -> - ignore - end, - mod_propagate_is_used_by(C, Mods); -mod_propagate_is_used_by(_C, []) -> - ok. -app_recap_dependencies(C, Sys, [#app{mods = Mods, is_included = IsIncl} = A | Apps], Acc, Status) -> - {Mods2, IsIncl2, Status2} = - mod_recap_dependencies(C, Sys, A, Mods, [], IsIncl, Status), +app_recap_dependencies(S) -> + ets:foldl(fun(App,_) -> app_recap_dependencies(S,App) end, + ok, S#state.app_tab). + +app_recap_dependencies(S, #app{mods = Mods, is_included = IsIncl} = A) -> + {Mods2, IsIncl2} = mod_recap_dependencies(S, A, Mods, [], IsIncl), AppStatus = case lists:keymember(missing, #mod.status, Mods2) of true -> missing; @@ -803,12 +857,12 @@ app_recap_dependencies(C, Sys, [#app{mods = Mods, is_included = IsIncl} = A | Ap UsesMods = [M#mod.uses_mods || M <- Mods2, M#mod.is_included =:= true], UsesMods2 = lists:usort(lists:flatten(UsesMods)), UsesApps = [M#mod.app_name || ModName <- UsesMods2, - M <- ets:lookup(C#common.mod_tab, ModName)], + M <- ets:lookup(S#state.mod_tab, ModName)], UsesApps2 = lists:usort(UsesApps), UsedByMods = [M#mod.used_by_mods || M <- Mods2, M#mod.is_included =:= true], UsedByMods2 = lists:usort(lists:flatten(UsedByMods)), UsedByApps = [M#mod.app_name || ModName <- UsedByMods2, - M <- ets:lookup(C#common.mod_tab, ModName)], + M <- ets:lookup(S#state.mod_tab, ModName)], UsedByApps2 = lists:usort(UsedByApps), A2 = A#app{mods = Mods2, @@ -818,13 +872,11 @@ app_recap_dependencies(C, Sys, [#app{mods = Mods, is_included = IsIncl} = A | Ap uses_apps = UsesApps2, used_by_apps = UsedByApps2, is_included = IsIncl2}, - ets:insert(C#common.app_tab,A2), - app_recap_dependencies(C, Sys, Apps, [A2 | Acc], Status2); -app_recap_dependencies(_C, _Sys, [], Acc, Status) -> - {lists:reverse(Acc), Status}. + ets:insert(S#state.app_tab,A2), + ok. -mod_recap_dependencies(C, Sys, A, [#mod{name = ModName}=M1 | Mods], Acc, IsIncl, Status) -> - case ets:lookup(C#common.mod_tab, ModName) of +mod_recap_dependencies(S, A, [#mod{name = ModName}=M1 | Mods], Acc, IsIncl) -> + case ets:lookup(S#state.mod_tab, ModName) of [M2] when M2#mod.app_name=:=A#app.name -> ModStatus = do_get_status(M2), %% print(M2#mod.name, hipe, "status -> ~p\n", [ModStatus]), @@ -832,32 +884,28 @@ mod_recap_dependencies(C, Sys, A, [#mod{name = ModName}=M1 | Mods], Acc, IsIncl, case M2#mod.is_included of true -> UsedByMods = - [N || {_, N} <- ets:lookup(C#common.mod_used_by_tab, + [N || {_, N} <- ets:lookup(S#state.mod_used_by_tab, ModName)], {true, M2#mod{status = ModStatus, used_by_mods = UsedByMods}}; _ -> {IsIncl, M2#mod{status = ModStatus, used_by_mods = []}} end, - ets:insert(C#common.mod_tab, M3), - mod_recap_dependencies(C, Sys, A, Mods, [M3 | Acc], IsIncl2, Status); + ets:insert(S#state.mod_tab, M3), + mod_recap_dependencies(S, A, Mods, [M3 | Acc], IsIncl2); [_] when A#app.is_included==false; M1#mod.incl_cond==exclude -> %% App is explicitely excluded so it is ok that the module %% record does not exist for this module in this %% application. - mod_recap_dependencies(C, Sys, A, Mods, [M1 | Acc], IsIncl, Status); + mod_recap_dependencies(S, A, Mods, [M1 | Acc], IsIncl); [M2] -> %% A module is potensially included by multiple %% applications. This is not allowed! - Error = - lists:concat( - ["Module ",ModName, - " potentially included by two different applications: ", - A#app.name, " and ", M2#mod.app_name, "."]), - Status2 = reltool_utils:return_first_error(Status,Error), - mod_recap_dependencies(C, Sys, A, Mods, [M1 | Acc], IsIncl, Status2) + reltool_utils:throw_error( + "Module ~p potentially included by two different applications: " + "~p and ~p", [ModName,A#app.name, " and ", M2#mod.app_name, "."]) end; -mod_recap_dependencies(_C, _Sys, _A, [], Acc, IsIncl, Status) -> - {lists:reverse(Acc), IsIncl, Status}. +mod_recap_dependencies(_S, _A, [], Acc, IsIncl) -> + {lists:reverse(Acc), IsIncl}. do_get_status(M) -> if @@ -867,48 +915,49 @@ do_get_status(M) -> ok end. -shrink_sys(#state{sys = #sys{apps = Apps} = Sys} = S) -> - Apps2 = lists:zf(fun filter_app/1, Apps), - S#state{sys = Sys#sys{apps = Apps2}}. - -filter_app(A) -> - Mods = [M#mod{is_app_mod = undefined, - is_ebin_mod = undefined, - uses_mods = undefined, - exists = false} || - M <- A#app.mods, - M#mod.incl_cond =/= undefined], - if - A#app.is_escript -> - {true, A#app{vsn = undefined, - label = undefined, - info = undefined, - mods = [], - uses_mods = undefined}}; - Mods =:= [], - A#app.mod_cond =:= undefined, - A#app.incl_cond =:= undefined, - A#app.use_selected_vsn =:= undefined -> - false; +verify_config(#state{app_tab=AppTab, sys=#sys{boot_rel = BootRel, rels = Rels}}, + RelApps, Status) -> + case lists:keymember(BootRel, #rel.name, Rels) of true -> - {Dir, Dirs, OptVsn} = - case A#app.use_selected_vsn of - undefined -> - {shrinked, [], undefined}; - false -> - {shrinked, [], undefined}; - true -> - {A#app.active_dir, [A#app.active_dir], A#app.vsn} - end, - {true, A#app{active_dir = Dir, - sorted_dirs = Dirs, - vsn = OptVsn, - label = undefined, - info = undefined, - mods = Mods, - uses_mods = undefined}} + Status2 = lists:foldl(fun(RA, Acc) -> + check_app(AppTab, RA, Acc) end, + Status, + RelApps), + lists:foldl(fun(#rel{name = RelName}, Acc)-> + check_rel(RelName, RelApps, Acc) + end, + Status2, + Rels); + false -> + reltool_utils:throw_error( + "Release ~p is mandatory (used as boot_rel)",[BootRel]) + end. + +check_app(AppTab, {RelName, AppName}, Status) -> + case ets:lookup(AppTab, AppName) of + [#app{is_pre_included=IsPreIncl, is_included=IsIncl}] + when IsPreIncl; IsIncl -> + Status; + _ -> + reltool_utils:throw_error( + "Release ~p uses non included application ~p",[RelName,AppName]) end. +check_rel(RelName, RelApps, Status) -> + EnsureApp = + fun(AppName, Acc) -> + case lists:member({RelName, AppName}, RelApps) of + true -> + Acc; + false -> + reltool_utils:throw_error( + "Mandatory application ~p is not included in " + "release ~p", [AppName,RelName]) + end + end, + Mandatory = [kernel, stdlib], + lists:foldl(EnsureApp, Status, Mandatory). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% refresh_app(#app{name = AppName, @@ -937,30 +986,57 @@ refresh_app(#app{name = AppName, AppName, DefaultVsn, Status), + + %% And read all modules from ebin and create + %% #mod record with dependencies (uses_mods). {AI, read_ebin_mods(Ebin, AppName), Status2}; - true -> + _ -> {App#app.info, Mods, Status} end, - %% Add non-existing modules - AppInfoMods = AppInfo#app_info.modules, - AppModNames = - case AppInfo#app_info.mod of - {StartModName, _} -> - case lists:member(StartModName, AppInfoMods) of - true -> AppInfoMods; - false -> [StartModName | AppInfoMods] - end; - undefined -> - AppInfoMods - end, - MissingMods = add_missing_mods(AppName, EbinMods, AppModNames), + %% Add non-existing modules - i.e. create default #mod + %% records for all modules that are listed in .app file + %% but do not exist in ebin. + AppInfoMods = lists:usort(AppInfo#app_info.modules), + Status4 = + case AppInfo#app_info.modules -- AppInfoMods of + [] -> + Status3; + DuplicatedMods -> + lists:foldl( + fun(M,S) -> + reltool_utils:add_warning( + "Module ~p duplicated in app file for " + "application ~p.", [M, AppName], S) + end, + Status3, + DuplicatedMods) + end, + AppModNames = + case AppInfo#app_info.mod of + {StartModName, _} -> + case lists:member(StartModName, AppInfoMods) of + true -> AppInfoMods; + false -> [StartModName | AppInfoMods] + end; + undefined -> + AppInfoMods + end, + MissingMods = add_missing_mods(AppName, EbinMods, AppModNames), - %% Add optional user config for each module + %% Add optional user config for each module. + %% The #mod records that are already in the #app record at + %% this point do only contain user defined configuration + %% (set by parse_options/4). So here we merge with the + %% default records from above. Mods2 = add_mod_config(MissingMods ++ EbinMods, Mods), - %% Set app flag for each module in app file + %% Set app flag for each module in app file, i.e. the flag + %% which indicates if the module is listed in the .app + %% file or not. The start module also get the flag set to true. Mods3 = set_mod_flags(Mods2, AppModNames), + + %% Finally, set label and update the #app record AppVsn = AppInfo#app_info.vsn, AppLabel = case AppVsn of @@ -971,7 +1047,7 @@ refresh_app(#app{name = AppName, label = AppLabel, info = AppInfo, mods = lists:keysort(#mod.name, Mods3)}, - {App2, Status3}; + {App2, Status4}; true -> {App, Status} end. @@ -988,22 +1064,21 @@ read_app_info(AppFileOrBin, AppFile, AppName, DefaultVsn, Status) -> AI = #app_info{vsn = DefaultVsn}, parse_app_info(AppFile, Info, AI, Status); {ok, _BadApp} -> - Text = lists:concat([AppName, - ": Illegal contents in app file ", AppFile, - ", application tuple with arity 3 expected."]), {missing_app_info(DefaultVsn), - reltool_utils:add_warning(Status, Text)}; + reltool_utils:add_warning("~p: Illegal contents in app file ~p, " + "application tuple with arity 3 expected.", + [AppName,AppFile], + Status)}; {error, Text} when Text =:= EnoentText -> - Text2 = lists:concat([AppName, - ": Missing app file ", AppFile, "."]), {missing_app_info(DefaultVsn), - reltool_utils:add_warning(Status, Text2)}; + reltool_utils:add_warning("~p: Missing app file ~p.", + [AppName,AppFile], + Status)}; {error, Text} -> - Text2 = lists:concat([AppName, - ": Cannot parse app file ", - AppFile, " (", Text, ")."]), {missing_app_info(DefaultVsn), - reltool_utils:add_warning(Status, Text2)} + reltool_utils:add_warning("~p: Cannot parse app file ~p (~p).", + [AppName,AppFile,Text], + Status)} end. parse_app_info(File, [{Key, Val} | KeyVals], AI, Status) -> @@ -1037,10 +1112,11 @@ parse_app_info(File, [{Key, Val} | KeyVals], AI, Status) -> parse_app_info(File, KeyVals, AI#app_info{start_phases = Val}, Status); _ -> - String = lists:concat(["Unexpected item ", - Key, "in app file ", File]), - parse_app_info(File, KeyVals, AI, - reltool_utils:add_warning(Status, String)) + Status2 = + reltool_utils:add_warning("Unexpected item ~p in app file ~p.", + [Key,File], + Status), + parse_app_info(File, KeyVals, AI, Status2) end; parse_app_info(_, [], AI, Status) -> {AI, Status}. @@ -1171,12 +1247,54 @@ set_mod_flags(Mods, AppModNames) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% do_get_config(S, InclDef, InclDeriv) -> - S2 = + AppTab = S#state.app_tab, + Sys = case InclDeriv of - false -> shrink_sys(S); - true -> S + false -> + %% Only the apps that exist in #sys.apps shall be + %% included,and they shall be minimized + Apps = [shrink_app(App) || + #app{name=Name} <- (S#state.sys)#sys.apps, + App <- ets:lookup(AppTab,Name)], + (S#state.sys)#sys{apps=Apps}; + true -> + sys_all_apps(S) end, - reltool_target:gen_config(S2#state.sys, InclDef). + reltool_target:gen_config(Sys, InclDef). + +shrink_app(A) -> + Mods = [M#mod{is_app_mod = undefined, + is_ebin_mod = undefined, + uses_mods = undefined, + exists = false} || + M <- A#app.mods, + M#mod.incl_cond =/= undefined], + if + A#app.is_escript -> + A#app{vsn = undefined, + label = undefined, + info = undefined, + mods = [], + uses_mods = undefined}; + true -> + {Dir, Dirs, OptVsn} = + case A#app.use_selected_vsn of + undefined -> + {shrinked, [], undefined}; + false -> + {shrinked, [], undefined}; + true -> + {A#app.active_dir, [A#app.active_dir], A#app.vsn} + end, + A#app{active_dir = Dir, + sorted_dirs = Dirs, + vsn = OptVsn, + label = undefined, + info = undefined, + mods = Mods, + uses_mods = undefined} + end. + do_save_config(S, Filename, InclDef, InclDeriv) -> {ok, Config} = do_get_config(S, InclDef, InclDeriv), @@ -1187,132 +1305,83 @@ do_save_config(S, Filename, InclDef, InclDeriv) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% do_load_config(S, SysConfig) -> - OldSys = S#state.sys, - S2 = shrink_sys(S), - ShrinkedSys = S2#state.sys, - {NewSys, Status} = - read_config(ShrinkedSys#sys{apps = []}, SysConfig, {ok, []}), - case Status of - {ok, _Warnings} -> - Force = false, - {MergedSys, Status2} = merge_config(OldSys, NewSys, Force, Status), - {S3, Status3} = - analyse(S2#state{sys = MergedSys, old_sys = OldSys}, Status2), - S4 = - case Status3 of - {ok, _Warnings2} -> - S3#state{status = Status3, old_status = S#state.status}; - {error, _} -> - %% Keep old state - S - end, - {S4, Status3}; - {error, _} -> - %% Keep old state - {S, Status} - end. + S#state{sys = read_config(default_sys(), SysConfig)}. -read_config(OldSys, Filename, Status) when is_list(Filename) -> +read_config(OldSys, Filename) when is_list(Filename) -> case file:consult(Filename) of {ok, [SysConfig | _]} -> - read_config(OldSys, SysConfig, Status); + read_config(OldSys, SysConfig); {ok, Content} -> - Text = lists:flatten(io_lib:format("~p", [Content])), - {OldSys, - reltool_utils:return_first_error(Status, - "Illegal file content: " ++ - Text)}; + reltool_utils:throw_error("Illegal file content: ~p",[Content]); {error, Reason} -> - Text = file:format_error(Reason), - {OldSys, - reltool_utils:return_first_error(Status, - "Illegal config file " ++ - Filename ++ ": " ++ Text)} + reltool_utils:throw_error("Illegal config file ~p: ~s", + [Filename,file:format_error(Reason)]) end; -read_config(OldSys, {sys, KeyVals}, Status) -> - {NewSys, Status2} = - decode(OldSys#sys{apps = [], rels = []}, KeyVals, Status), - case Status2 of - {ok, _Warnings} -> % BUGBUG: handle warnings - Apps = [A#app{mods = lists:sort(A#app.mods)} || - A <- NewSys#sys.apps], - case NewSys#sys.rels of - [] -> Rels = reltool_utils:default_rels(); - Rels -> ok - end, - NewSys2 = NewSys#sys{apps = lists:sort(Apps), - rels = lists:sort(Rels)}, - case lists:keymember(NewSys2#sys.boot_rel, - #rel.name, - NewSys2#sys.rels) of - true -> - {NewSys2, Status2}; - false -> - Text2 = lists:concat(["Release " ++ NewSys2#sys.boot_rel, - " is mandatory (used as boot_rel)"]), - {OldSys, reltool_utils:return_first_error(Status2, Text2)} - end; - {error, _} -> - %% Keep old state - {OldSys, Status2} +read_config(OldSys, {sys, KeyVals}) -> + NewSys = decode(OldSys#sys{apps = [], rels = []}, KeyVals), + Apps = [A#app{mods = lists:sort(A#app.mods)} || A <- NewSys#sys.apps], + Rels = + case NewSys#sys.rels of + [] -> reltool_utils:default_rels(); + Rs -> Rs + end, + NewSys2 = NewSys#sys{apps = lists:sort(Apps), + rels = lists:sort(Rels)}, + case lists:keymember(NewSys2#sys.boot_rel, #rel.name, NewSys2#sys.rels) of + true -> + NewSys2; + false -> + reltool_utils:throw_error( + "Release ~p is mandatory (used as boot_rel)", + [NewSys2#sys.boot_rel]) end; -read_config(OldSys, BadConfig, Status) -> - Text = lists:flatten(io_lib:format("~p", [BadConfig])), - {OldSys, - reltool_utils:return_first_error(Status, "Illegal content: " ++ Text)}. +read_config(_OldSys, BadConfig) -> + reltool_utils:throw_error("Illegal content: ~p", [BadConfig]). -decode(#sys{apps = Apps} = Sys, [{erts = Name, AppKeyVals} | SysKeyVals], - Status) +decode(#sys{apps = Apps} = Sys, [{erts = Name, AppKeyVals} | SysKeyVals]) when is_atom(Name), is_list(AppKeyVals) -> App = default_app(Name), - {App2, Status2} = decode(App, AppKeyVals, Status), - decode(Sys#sys{apps = [App2 | Apps]}, SysKeyVals, Status2); -decode(#sys{apps = Apps} = Sys, [{app, Name, AppKeyVals} | SysKeyVals], Status) + App2= decode(App, AppKeyVals), + decode(Sys#sys{apps = [App2 | Apps]}, SysKeyVals); +decode(#sys{apps = Apps} = Sys, [{app, Name, AppKeyVals} | SysKeyVals]) when is_atom(Name), is_list(AppKeyVals) -> App = default_app(Name), - {App2, Status2} = decode(App, AppKeyVals, Status), - decode(Sys#sys{apps = [App2 | Apps]}, SysKeyVals, Status2); + App2 = decode(App, AppKeyVals), + decode(Sys#sys{apps = [App2 | Apps]}, SysKeyVals); decode(#sys{apps = Apps, escripts = Escripts} = Sys, - [{escript, File, AppKeyVals} | SysKeyVals], Status) - when is_list(File), is_list(AppKeyVals) -> - {Name, Label} = split_escript_name(File), - App = default_app(Name, File), - App2 = App#app{is_escript = true, - label = Label, - info = missing_app_info(""), - active_dir = File, - sorted_dirs = [File]}, - {App3, Status2} = decode(App2, AppKeyVals, Status), - decode(Sys#sys{apps = [App3 | Apps], escripts = [File | Escripts]}, - SysKeyVals, - Status2); -decode(#sys{rels = Rels} = Sys, [{rel, Name, Vsn, RelApps} | SysKeyVals], - Status) + [{escript, File0, AppKeyVals} | SysKeyVals]) + when is_list(File0), is_list(AppKeyVals) -> + File = filename:absname(File0), + App = default_escript_app(File), + App2 = decode(App, AppKeyVals), + decode(Sys#sys{apps = [App2 | Apps], escripts = [File | Escripts]}, + SysKeyVals); +decode(#sys{rels = Rels} = Sys, [{rel, Name, Vsn, RelApps} | SysKeyVals]) when is_list(Name), is_list(Vsn), is_list(RelApps) -> Rel = #rel{name = Name, vsn = Vsn, rel_apps = []}, - {Rel2, Status2} = decode(Rel, RelApps, Status), - decode(Sys#sys{rels = [Rel2 | Rels]}, SysKeyVals, Status2); -decode(#sys{} = Sys, [{Key, Val} | KeyVals], Status) -> - {Sys3, Status3} = + Rel2 = decode(Rel, RelApps), + decode(Sys#sys{rels = [Rel2 | Rels]}, SysKeyVals); +decode(#sys{} = Sys, [{Key, Val} | KeyVals]) -> + Sys3 = case Key of root_dir when is_list(Val) -> - {Sys#sys{root_dir = Val}, Status}; + Sys#sys{root_dir = Val}; lib_dirs when is_list(Val) -> - {Sys#sys{lib_dirs = Val}, Status}; + Sys#sys{lib_dirs = Val}; mod_cond when Val =:= all; Val =:= app; Val =:= ebin; Val =:= derived; Val =:= none -> - {Sys#sys{mod_cond = Val}, Status}; + Sys#sys{mod_cond = Val}; incl_cond when Val =:= include; Val =:= exclude; Val =:= derived -> - {Sys#sys{incl_cond = Val}, Status}; + Sys#sys{incl_cond = Val}; boot_rel when is_list(Val) -> - {Sys#sys{boot_rel = Val}, Status}; + Sys#sys{boot_rel = Val}; emu_name when is_list(Val) -> - {Sys#sys{emu_name = Val}, Status}; + Sys#sys{emu_name = Val}; profile when Val =:= development; Val =:= embedded; Val =:= standalone -> @@ -1321,198 +1390,153 @@ decode(#sys{} = Sys, [{Key, Val} | KeyVals], Status) -> InclApp = reltool_utils:choose_default(incl_app_filters, Val, false), ExclApp = reltool_utils:choose_default(excl_app_filters, Val, false), AppType = reltool_utils:choose_default(embedded_app_type, Val, false), - {Sys#sys{profile = Val, - incl_sys_filters = dec_re(incl_sys_filters, - InclSys, - Sys#sys.incl_sys_filters), - excl_sys_filters = dec_re(excl_sys_filters, - ExclSys, - Sys#sys.excl_sys_filters), - incl_app_filters = dec_re(incl_app_filters, - InclApp, - Sys#sys.incl_app_filters), - excl_app_filters = dec_re(excl_app_filters, - ExclApp, - Sys#sys.excl_app_filters), - embedded_app_type = AppType}, - Status}; + Sys#sys{profile = Val, + incl_sys_filters = dec_re(incl_sys_filters, + InclSys, + Sys#sys.incl_sys_filters), + excl_sys_filters = dec_re(excl_sys_filters, + ExclSys, + Sys#sys.excl_sys_filters), + incl_app_filters = dec_re(incl_app_filters, + InclApp, + Sys#sys.incl_app_filters), + excl_app_filters = dec_re(excl_app_filters, + ExclApp, + Sys#sys.excl_app_filters), + embedded_app_type = AppType}; incl_sys_filters -> - {Sys#sys{incl_sys_filters = - dec_re(Key, - Val, - Sys#sys.incl_sys_filters)}, - Status}; + Sys#sys{incl_sys_filters = + dec_re(Key, Val, Sys#sys.incl_sys_filters)}; excl_sys_filters -> - {Sys#sys{excl_sys_filters = - dec_re(Key, - Val, - Sys#sys.excl_sys_filters)}, - Status}; + Sys#sys{excl_sys_filters = + dec_re(Key, Val, Sys#sys.excl_sys_filters)}; incl_app_filters -> - {Sys#sys{incl_app_filters = - dec_re(Key, - Val, - Sys#sys.incl_app_filters)}, - Status}; + Sys#sys{incl_app_filters = + dec_re(Key, Val, Sys#sys.incl_app_filters)}; excl_app_filters -> - {Sys#sys{excl_app_filters = - dec_re(Key, - Val, - Sys#sys.excl_app_filters)}, - Status}; + Sys#sys{excl_app_filters = + dec_re(Key, Val, Sys#sys.excl_app_filters)}; incl_archive_filters -> - {Sys#sys{incl_archive_filters = - dec_re(Key, - Val, - Sys#sys.incl_archive_filters)}, - Status}; + Sys#sys{incl_archive_filters = + dec_re(Key, Val, Sys#sys.incl_archive_filters)}; excl_archive_filters -> - {Sys#sys{excl_archive_filters = - dec_re(Key, - Val, - Sys#sys.excl_archive_filters)}, - Status}; + Sys#sys{excl_archive_filters = + dec_re(Key, Val, Sys#sys.excl_archive_filters)}; archive_opts when is_list(Val) -> - {Sys#sys{archive_opts = Val}, Status}; + Sys#sys{archive_opts = Val}; relocatable when Val =:= true; Val =:= false -> - {Sys#sys{relocatable = Val}, Status}; + Sys#sys{relocatable = Val}; rel_app_type when Val =:= permanent; Val =:= transient; Val =:= temporary; Val =:= load; Val =:= none -> - {Sys#sys{rel_app_type = Val}, Status}; + Sys#sys{rel_app_type = Val}; embedded_app_type when Val =:= permanent; Val =:= transient; Val =:= temporary; Val =:= load; Val =:= none; Val =:= undefined -> - {Sys#sys{embedded_app_type = Val}, Status}; + Sys#sys{embedded_app_type = Val}; app_file when Val =:= keep; Val =:= strip; Val =:= all -> - {Sys#sys{app_file = Val}, Status}; + Sys#sys{app_file = Val}; debug_info when Val =:= keep; Val =:= strip -> - {Sys#sys{debug_info = Val}, Status}; + Sys#sys{debug_info = Val}; _ -> - Text = lists:flatten(io_lib:format("~p", [{Key, Val}])), - {Sys, reltool_utils:return_first_error(Status, - "Illegal option: " ++ - Text)} + reltool_utils:throw_error("Illegal option: ~p", [{Key, Val}]) end, - decode(Sys3, KeyVals, Status3); -decode(#app{} = App, [{Key, Val} | KeyVals], Status) -> - {App2, Status2} = + decode(Sys3, KeyVals); +decode(#app{} = App, [{Key, Val} | KeyVals]) -> + App2 = case Key of mod_cond when Val =:= all; Val =:= app; Val =:= ebin; Val =:= derived; Val =:= none -> - {App#app{mod_cond = Val}, Status}; + App#app{mod_cond = Val}; incl_cond when Val =:= include; Val =:= exclude; Val =:= derived -> - {App#app{incl_cond = Val}, Status}; + App#app{incl_cond = Val}; debug_info when Val =:= keep; Val =:= strip -> - {App#app{debug_info = Val}, Status}; + App#app{debug_info = Val}; app_file when Val =:= keep; Val =:= strip; Val =:= all -> - {App#app{app_file = Val}, Status}; + App#app{app_file = Val}; app_type when Val =:= permanent; Val =:= transient; Val =:= temporary; Val =:= load; Val =:= none; Val =:= undefined -> - {App#app{app_type = Val}, Status}; + App#app{app_type = Val}; incl_app_filters -> - {App#app{incl_app_filters = - dec_re(Key, - Val, - App#app.incl_app_filters)}, - Status}; + App#app{incl_app_filters = + dec_re(Key, Val, App#app.incl_app_filters)}; excl_app_filters -> - {App#app{excl_app_filters = - dec_re(Key, - Val, - App#app.excl_app_filters)}, - Status}; + App#app{excl_app_filters = + dec_re(Key, Val, App#app.excl_app_filters)}; incl_archive_filters -> - {App#app{incl_archive_filters = - dec_re(Key, - Val, - App#app.incl_archive_filters)}, - Status}; + App#app{incl_archive_filters = + dec_re(Key, Val, App#app.incl_archive_filters)}; excl_archive_filters -> - {App#app{excl_archive_filters = - dec_re(Key, - Val, - App#app.excl_archive_filters)}, - Status}; + App#app{excl_archive_filters = + dec_re(Key, Val, App#app.excl_archive_filters)}; archive_opts when is_list(Val) -> - {App#app{archive_opts = Val}, Status}; + App#app{archive_opts = Val}; vsn when is_list(Val) -> - {App#app{use_selected_vsn = true, vsn = Val}, Status}; + App#app{use_selected_vsn = true, vsn = Val}; _ -> - Text = lists:flatten(io_lib:format("~p", [{Key, Val}])), - {App, reltool_utils:return_first_error(Status, - "Illegal option: " ++ Text)} + reltool_utils:throw_error("Illegal option: ~p", [{Key, Val}]) end, - decode(App2, KeyVals, Status2); -decode(#app{mods = Mods} = App, [{mod, Name, ModKeyVals} | AppKeyVals], - Status) -> - {Mod, Status2} = decode(#mod{name = Name}, ModKeyVals, Status), - decode(App#app{mods = [Mod | Mods]}, AppKeyVals, Status2); -decode(#mod{} = Mod, [{Key, Val} | KeyVals], Status) -> - {Mod2, Status2} = + decode(App2, KeyVals); +decode(#app{mods = Mods} = App, [{mod, Name, ModKeyVals} | AppKeyVals]) -> + Mod = decode(#mod{name = Name}, ModKeyVals), + decode(App#app{mods = [Mod | Mods]}, AppKeyVals); +decode(#mod{} = Mod, [{Key, Val} | KeyVals]) -> + Mod2 = case Key of incl_cond when Val =:= include; Val =:= exclude; Val =:= derived -> - {Mod#mod{incl_cond = Val}, Status}; + Mod#mod{incl_cond = Val}; debug_info when Val =:= keep; Val =:= strip -> - {Mod#mod{debug_info = Val}, Status}; + Mod#mod{debug_info = Val}; _ -> - Text = lists:flatten(io_lib:format("~p", [{Key, Val}])), - {Mod, - reltool_utils:return_first_error(Status, - "Illegal option: " ++ Text)} + reltool_utils:throw_error("Illegal option: ~p", [{Key, Val}]) end, - decode(Mod2, KeyVals, Status2); -decode(#rel{rel_apps = RelApps} = Rel, [RelApp | KeyVals], Status) -> + decode(Mod2, KeyVals); +decode(#rel{rel_apps = RelApps} = Rel, [RelApp | KeyVals]) -> {ValidTypesAssigned, RA} = case RelApp of Name when is_atom(Name) -> {true, #rel_app{name = Name}}; - {Name, Type} when is_atom(Name) -> - {is_type(Type), #rel_app{name = Name, app_type = Type}}; {Name, InclApps} when is_atom(Name), is_list(InclApps) -> VI = lists:all(fun erlang:is_atom/1, InclApps), {VI, #rel_app{name = Name, incl_apps = InclApps}}; + {Name, Type} when is_atom(Name) -> + {is_type(Type), #rel_app{name = Name, app_type = Type}}; {Name, Type, InclApps} when is_atom(Name), is_list(InclApps) -> VT = is_type(Type), VI = lists:all(fun erlang:is_atom/1, InclApps), {VT andalso VI, #rel_app{name = Name, app_type = Type, incl_apps = InclApps}}; _ -> - {false, #rel_app{incl_apps = []}} + {false, #rel_app{}} end, case ValidTypesAssigned of true -> - decode(Rel#rel{rel_apps = RelApps ++ [RA]}, KeyVals, Status); + decode(Rel#rel{rel_apps = RelApps ++ [RA]}, KeyVals); false -> - Text = lists:flatten(io_lib:format("~p", [RelApp])), - Status2 = - reltool_utils:return_first_error(Status, - "Illegal option: " ++ Text), - decode(Rel, KeyVals, Status2) + reltool_utils:throw_error("Illegal option: ~p", [RelApp]) end; -decode(Acc, [], Status) -> - {Acc, Status}; -decode(Acc, KeyVal, Status) -> - Text = lists:flatten(io_lib:format("~p", [KeyVal])), - {Acc, reltool_utils:return_first_error(Status, "Illegal option: " ++ Text)}. +decode(Acc, []) -> + Acc; +decode(_Acc, KeyVal) -> + reltool_utils:throw_error("Illegal option: ~p", [KeyVal]). is_type(Type) -> case Type of @@ -1529,79 +1553,50 @@ split_escript_name(File) when is_list(File) -> Label = filename:basename(File, ".escript"), {list_to_atom("*escript* " ++ Label), Label}. +default_escript_app(File) -> + {Name, Label} = split_escript_name(File), + App = default_app(Name, File), + App#app{is_escript = true, + label = Label, + info = missing_app_info("")}. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -refresh(#state{sys = Sys} = S, Force, Status) -> - {Sys2, Status2} = merge_config(Sys, Sys#sys{apps = []}, Force, Status), - {S#state{sys = Sys2}, Status2}. - -merge_config(OldSys, NewSys, Force, Status) -> - RootDir = filename:absname(NewSys#sys.root_dir), - LibDirs = [filename:absname(D) || D <- NewSys#sys.lib_dirs], - Escripts = [filename:absname(E) || E <- NewSys#sys.escripts], - {SourceDirs, Status2} = - libs_to_dirs(RootDir, LibDirs, Status), - MergedApps = merge_app_dirs(SourceDirs, NewSys#sys.apps, OldSys#sys.apps), - {AllApps, Status3} = - escripts_to_apps(Escripts, MergedApps, OldSys#sys.apps, Status2), - {RefreshedApps, Status4} = - refresh_apps(OldSys#sys.apps, AllApps, [], Force, Status3), - {PatchedApps, Status5} = - patch_erts_version(RootDir, RefreshedApps, Status4), - Escripts2 = [A#app.active_dir || A <- PatchedApps, A#app.is_escript], - NewSys2 = NewSys#sys{root_dir = RootDir, - lib_dirs = LibDirs, - escripts = Escripts2, - apps = PatchedApps}, - {NewSys2, Status5}. +%% Apps is a list of #app records - sorted on #app.name - containing +%% only the apps that have specific configuration (e.g. in the config +%% file) +refresh(#state{sys=Sys} = S) -> + RootDir = filename:absname(Sys#sys.root_dir), + LibDirs = [filename:absname(D) || D <- Sys#sys.lib_dirs], + Escripts = [filename:absname(E) || E <- Sys#sys.escripts], -verify_config(RelApps, #sys{boot_rel = BootRel, rels = Rels, apps = Apps}, Status) -> - case lists:keymember(BootRel, #rel.name, Rels) of - true -> - Status2 = lists:foldl(fun(RA, Acc) -> - check_app(RA, Apps, Acc) end, - Status, - RelApps), - lists:foldl(fun(#rel{name = RelName}, Acc)-> - check_rel(RelName, RelApps, Acc) - end, - Status2, - Rels); - false -> - Text = lists:concat(["Release ", BootRel, - " is mandatory (used as boot_rel)"]), - reltool_utils:return_first_error(Status, Text) - end. + %% Read all lib dirs and return sorted [{AppName,Dir}] + SourceDirs = libs_to_dirs(RootDir, LibDirs), -check_app({RelName, AppName}, Apps, Status) -> - case lists:keysearch(AppName, #app.name, Apps) of - {value, App} when App#app.is_pre_included -> - Status; - {value, App} when App#app.is_included -> - Status; - _ -> - Text = lists:concat(["Release ", RelName, - " uses non included application ", - AppName]), - reltool_utils:return_first_error(Status, Text) - end. + %% Create #app records for all apps in SourceDirs, and merge with + %% list of apps from config. + MergedApps = merge_app_dirs(SourceDirs, Sys#sys.apps), -check_rel(RelName, RelApps, Status) -> - EnsureApp = - fun(AppName, Acc) -> - case lists:member({RelName, AppName}, RelApps) of - true -> - Acc; - false -> - Text = lists:concat(["Mandatory application ", - AppName, - " is not included in release ", - RelName]), - reltool_utils:return_first_error(Acc, Text) - end - end, - Mandatory = [kernel, stdlib], - lists:foldl(EnsureApp, Status, Mandatory). + %% For each escript, find all related files and convert to #app + %% and #mod records + {AllApps, Status2} = escripts_to_apps(Escripts, MergedApps, {ok,[]}), + + %% Make sure correct version of each application is used according + %% to the user configuration. + %% Then find all modules and their dependencies and set user + %% configuration per module if it exists. + {RefreshedApps, Status3} = refresh_apps(Sys#sys.apps, AllApps, [], + true, Status2), + + %% Make sure erts exists in app list and has a version (or warn) + {PatchedApps, Status4} = patch_erts_version(RootDir, RefreshedApps, Status3), + + %% Update #sys and return + Escripts2 = [A#app.active_dir || A <- PatchedApps, A#app.is_escript], + Sys2 = Sys#sys{root_dir = RootDir, + lib_dirs = LibDirs, + escripts = Escripts2}, + {S#state{sys=Sys2}, PatchedApps, Status4}. patch_erts_version(RootDir, Apps, Status) -> AppName = erts, @@ -1615,18 +1610,17 @@ patch_erts_version(RootDir, Apps, Status) -> Apps2 = lists:keystore(AppName, #app.name, Apps, Erts2), {Apps2, Status}; Vsn =:= "" -> - {Apps, reltool_utils:add_warning(Status, - "erts has no version")}; + {Apps, reltool_utils:add_warning("erts has no version",[], + Status)}; true -> {Apps, Status} end; false -> - Text = "erts cannot be found in the root directory " ++ RootDir, - Status2 = reltool_utils:return_first_error(Status, Text), - {Apps, Status2} + reltool_utils:throw_error( + "erts cannot be found in the root directory ~p", [RootDir]) end. -libs_to_dirs(RootDir, LibDirs, Status) -> +libs_to_dirs(RootDir, LibDirs) -> case file:list_dir(RootDir) of {ok, RootFiles} -> RootLibDir = filename:join([RootDir, "lib"]), @@ -1648,21 +1642,16 @@ libs_to_dirs(RootDir, LibDirs, Status) -> end, ErtsFiles = [{erts, Fun(F)} || F <- RootFiles, lists:prefix("erts", F)], - app_dirs2(AllLibDirs, [ErtsFiles], Status); + app_dirs2(AllLibDirs, [ErtsFiles]); [Duplicate | _] -> - {[], - reltool_utils:return_first_error(Status, - "Duplicate library: " ++ - Duplicate)} + reltool_utils:throw_error("Duplicate library: ~p",[Duplicate]) end; {error, Reason} -> - Text = file:format_error(Reason), - {[], reltool_utils:return_first_error(Status, - "Missing root library " ++ - RootDir ++ ": " ++ Text)} + reltool_utils:throw_error("Missing root library ~p: ~s", + [RootDir,file:format_error(Reason)]) end. -app_dirs2([Lib | Libs], Acc, Status) -> +app_dirs2([Lib | Libs], Acc) -> case file:list_dir(Lib) of {ok, Files} -> Filter = @@ -1682,17 +1671,15 @@ app_dirs2([Lib | Libs], Acc, Status) -> end end, Files2 = lists:zf(Filter, Files), - app_dirs2(Libs, [Files2 | Acc], Status); + app_dirs2(Libs, [Files2 | Acc]); {error, Reason} -> - Text = file:format_error(Reason), - {[], reltool_utils:return_first_error(Status, - "Illegal library " ++ - Lib ++ ": " ++ Text)} + reltool_utils:throw_error("Illegal library ~p: ~s", + [Lib, file:format_error(Reason)]) end; -app_dirs2([], Acc, Status) -> - {lists:sort(lists:append(Acc)), Status}. +app_dirs2([], Acc) -> + lists:sort(lists:append(Acc)). -escripts_to_apps([Escript | Escripts], Apps, OldApps, Status) -> +escripts_to_apps([Escript | Escripts], Apps, Status) -> {EscriptAppName, _Label} = split_escript_name(Escript), Ext = code:objfile_extension(), Fun = fun(FullName, _GetInfo, GetBin, {FileAcc, StatusAcc}) -> @@ -1755,156 +1742,111 @@ escripts_to_apps([Escript | Escripts], Apps, OldApps, Status) -> end, case reltool_utils:escript_foldl(Fun, {[], Status}, Escript) of {ok, {Files, Status2}} -> + EscriptApp = + case lists:keyfind(EscriptAppName,#app.name,Apps) of + false -> default_escript_app(Escript); + EA -> EA + end, {Apps2, Status3} = - files_to_apps(Escript, - lists:sort(Files), - Apps, - Apps, - OldApps, - Status2), - escripts_to_apps(Escripts, Apps2, OldApps, Status3); + escript_files_to_apps(EscriptAppName, + lists:sort(Files), + [EscriptApp], + Apps, + Status2), + escripts_to_apps(Escripts, Apps2, Status3); {error, Reason} -> - Text = lists:flatten(io_lib:format("~p", [Reason])), - {[], reltool_utils:return_first_error(Status, - "Illegal escript " ++ - Escript ++ ": " ++ Text)} + reltool_utils:throw_error("Illegal escript ~p: ~p", [Escript,Reason]) end; -escripts_to_apps([], Apps, _OldApps, Status) -> +escripts_to_apps([], Apps, Status) -> {Apps, Status}. %% Assume that all files for an app are in consecutive order %% Assume the app info is before the mods -files_to_apps(Escript, - [{AppName, Type, Dir, ModOrInfo} | Files] = AllFiles, - Acc, - Apps, - OldApps, - Status) -> - case Type of - mod -> - case Acc of - [] -> - Info = missing_app_info(""), - {NewApp, Status2} = - merge_escript_app(AppName, - Dir, - Info, - [ModOrInfo], - Apps, - OldApps, - Status), - files_to_apps(Escript, - AllFiles, - [NewApp | Acc], - Apps, - OldApps, Status2); - [App | Acc2] when App#app.name =:= ModOrInfo#mod.app_name -> - App2 = App#app{mods = [ModOrInfo | App#app.mods]}, - files_to_apps(Escript, - Files, - [App2 | Acc2], - Apps, - OldApps, - Status); - [App | Acc2] -> - PrevApp = App#app{mods = lists:keysort(#mod.name, - App#app.mods)}, - Info = missing_app_info(""), - {NewApp, Status2} = - merge_escript_app(AppName, - Dir, - Info, - [ModOrInfo], - Apps, - OldApps, - Status), - files_to_apps(Escript, - Files, - [NewApp, PrevApp | Acc2], - Apps, - OldApps, - Status2) - end; - app -> - {App, Status2} = - merge_escript_app(AppName, Dir, ModOrInfo, [], Apps, OldApps, - Status), - files_to_apps(Escript, Files, [App | Acc], Apps, OldApps, Status2) - end; -files_to_apps(_Escript, [], Acc, _Apps, _OldApps, Status) -> - {lists:keysort(#app.name, Acc), Status}. - -merge_escript_app(AppName, Dir, Info, Mods, Apps, OldApps, Status) -> - App1 = case lists:keyfind(AppName, #app.name, OldApps) of - #app{} = App -> - App; - false -> - default_app(AppName, Dir) - end, - App2 = App1#app{is_escript = true, +escript_files_to_apps(EscriptAppName, + [{AppName, Type, Dir, ModOrInfo} | Files], + Acc, + Apps, + Status) -> + {NewAcc,Status3} = + case Type of + mod -> + case Acc of + [App | Acc2] when App#app.name =:= ModOrInfo#mod.app_name -> + Mods = lists:ukeymerge(#mod.name, + [ModOrInfo], + App#app.mods), + {[App#app{mods = Mods} | Acc2], Status}; + Acc -> + {NewApp, Status2} = init_escript_app(AppName, + EscriptAppName, + Dir, + missing_app_info(""), + [ModOrInfo], + Apps, + Status), + {[NewApp | Acc], Status2} + end; + app -> + {App, Status2} = init_escript_app(AppName, + EscriptAppName, + Dir, + ModOrInfo, + [], + Apps, + Status), + {[App | Acc], Status2} + end, + escript_files_to_apps(EscriptAppName, Files, NewAcc, Apps, Status3); +escript_files_to_apps(_EscriptAppName, [], Acc, Apps, Status) -> + {lists:ukeymerge(#app.name, lists:reverse(Acc), Apps), Status}. + +init_escript_app(AppName, EscriptAppName, Dir, Info, Mods, Apps, Status) -> + App1 = default_app(AppName, Dir), + IsEscript = + if AppName=:=EscriptAppName -> true; + true -> {inlined, EscriptAppName} + end, + InclCond = (lists:keyfind(EscriptAppName,#app.name,Apps))#app.incl_cond, + App2 = App1#app{is_escript = IsEscript, label = filename:basename(Dir, ".escript"), info = Info, mods = Mods, active_dir = Dir, - sorted_dirs = [Dir]}, + sorted_dirs = [Dir], + incl_cond = InclCond},% inlined apps inherit incl from escript case lists:keymember(AppName, #app.name, Apps) of true -> - Error = lists:concat([AppName, ": Application name clash. ", - "Escript ", Dir," contains application ", - AppName, "."]), - {App2, reltool_utils:return_first_error(Status, Error)}; + reltool_utils:throw_error( + "~p: Application name clash. Escript ~p contains application ~p.", + [AppName,Dir,AppName]); false -> {App2, Status} end. -merge_app_dirs([{Name, Dir} | Rest], [App | Apps], OldApps) - when App#app.name =:= Name -> - %% Add new dir to app - App2 = App#app{sorted_dirs = [Dir | App#app.sorted_dirs]}, - merge_app_dirs(Rest, [App2 | Apps], OldApps); -merge_app_dirs([{Name, Dir} | Rest], Apps, OldApps) -> - %% Initate app - Apps2 = sort_app_dirs(Apps), - Apps4 = +merge_app_dirs([{Name, Dir} | Rest], Apps) -> + App = case lists:keyfind(Name, #app.name, Apps) of false -> - case lists:keyfind(Name, #app.name, OldApps) of - false -> - App = default_app(Name, Dir), - [App | Apps2]; - #app{active_dir = Dir} = OldApp -> - [OldApp | Apps2]; - OldApp -> - App = - case filter_app(OldApp) of - {true, NewApp} -> - NewApp#app{active_dir = Dir, - sorted_dirs = [Dir]}; - false -> - default_app(Name, Dir) - end, - [App | Apps2] - end; + default_app(Name, Dir); OldApp -> - Apps3 = lists:keydelete(Name, #app.name, Apps2), - App = OldApp#app{sorted_dirs = [Dir | OldApp#app.sorted_dirs]}, - [App | Apps3] + SortedDirs = lists:umerge(fun reltool_utils:app_dir_test/2, + [Dir], OldApp#app.sorted_dirs), + OldApp#app{sorted_dirs = SortedDirs} end, - merge_app_dirs(Rest, Apps4, OldApps); -merge_app_dirs([], Apps, _OldApps) -> - Apps2 = sort_app_dirs(Apps), - lists:reverse(Apps2). - -sort_app_dirs([#app{sorted_dirs = Dirs} = App | Acc]) -> - SortedDirs = lists:sort(fun reltool_utils:app_dir_test/2, Dirs), - case SortedDirs of - [ActiveDir | _] -> ok; - [] -> ActiveDir = undefined - end, - [App#app{active_dir = ActiveDir, sorted_dirs = SortedDirs} | Acc]; -sort_app_dirs([]) -> + Apps2 = lists:ukeymerge(#app.name, [App], Apps), + merge_app_dirs(Rest, Apps2); +merge_app_dirs([], Apps) -> + set_active_dirs(Apps). + +%% First dir, i.e. the one with highest version, is set to active dir +set_active_dirs([#app{sorted_dirs = [ActiveDir|_]} = App | Apps]) -> + [App#app{active_dir = ActiveDir} | set_active_dirs(Apps)]; +set_active_dirs([#app{sorted_dirs = []} = App | Apps]) -> + [App#app{active_dir = undefined} | set_active_dirs(Apps)]; +set_active_dirs([]) -> []. + default_app(Name, Dir) -> App = default_app(Name), App#app{active_dir = Dir, @@ -1913,89 +1855,51 @@ default_app(Name, Dir) -> default_app(Name) -> #app{name = Name, is_escript = false, - use_selected_vsn = undefined, - active_dir = undefined, sorted_dirs = [], - vsn = undefined, - label = undefined, - info = undefined, mods = [], - - mod_cond = undefined, - incl_cond = undefined, - - status = missing, - uses_mods = undefined, - is_pre_included = undefined, - is_included = undefined, - rels = undefined}. - -%% Assume that the application are sorted -refresh_apps([Old | OldApps], [New | NewApps], Acc, Force, Status) - when New#app.name =:= Old#app.name -> - {Info, ActiveDir, Status2} = ensure_app_info(New, Status), - OptLabel = - case Info#app_info.vsn =:= New#app.vsn of - true -> New#app.label; - false -> undefined % Cause refresh - end, - {Refreshed, Status3} = - refresh_app(New#app{label = OptLabel, - active_dir = ActiveDir, - vsn = Info#app_info.vsn, - info = Info}, - Force, - Status2), - refresh_apps(OldApps, NewApps, [Refreshed | Acc], Force, Status3); -refresh_apps([Old | OldApps], [New | NewApps], Acc, Force, Status) - when New#app.name < Old#app.name -> - %% No old app version exists. Use new as is. - %% BUGBUG: Issue warning if the active_dir is not defined - {New2, Status2} = refresh_app(New, Force, Status), - refresh_apps([Old | OldApps], NewApps, [New2 | Acc], Force, Status2); -refresh_apps([Old | OldApps], [New | NewApps], Acc, Force, Status) - when New#app.name > Old#app.name -> - %% No new version. Remove the old. - Status2 = - case Old#app.name =:= ?MISSING_APP_NAME of - true -> - Status; - false -> - Warning = - lists:concat([Old#app.name, - ": The source dirs does not ", - "contain the application anymore."]), - reltool_utils:add_warning(Status, Warning) - end, - refresh_apps(OldApps, [New | NewApps], Acc, Force, Status2); -refresh_apps([], [New | NewApps], Acc, Force, Status) -> - %% No old app version exists. Use new as is. - {New2, Status2} = refresh_app(New, Force, Status), - refresh_apps([], NewApps, [New2 | Acc], Force, Status2); -refresh_apps([Old | OldApps], [], Acc, Force, Status) -> - %% No new version. Remove the old. - Status2 = - case Old#app.name =:= ?MISSING_APP_NAME of - true -> - Status; - false -> - Warning = - lists:concat([Old#app.name, - ": The source dirs does not " - "contain the application anymore."]), - reltool_utils:add_warning(Status, Warning) - end, - refresh_apps(OldApps, [], Acc, Force, Status2); -refresh_apps([], [], Acc, _Force, Status) -> + status = missing}. + + + +refresh_apps(ConfigApps, [New | NewApps], Acc, Force, Status) -> + {New2, Status3} = + case lists:keymember(New#app.name,#app.name,ConfigApps) of + true -> + %% There is user defined config for this application, make + %% sure that the application exists and that correct + %% version is used. Set active directory. + {Info, ActiveDir, Status2} = ensure_app_info(New, Status), + OptLabel = + case Info#app_info.vsn =:= New#app.vsn of + true -> New#app.label; + false -> undefined % Cause refresh + end, + refresh_app(New#app{label = OptLabel, + active_dir = ActiveDir, + vsn = Info#app_info.vsn, + info = Info}, + Force, + Status2); + false -> + %% There is no user defined config for this + %% application. This means that the app is found in the + %% lib dirs, and that the highest version shall be + %% used. I.e. the active_dir and vsn are already correct + %% from merge_app_dirs. + refresh_app(New, Force, Status) + end, + refresh_apps(ConfigApps, NewApps, [New2 | Acc], Force, Status3); +refresh_apps(_ConfigApps, [], Acc, _Force, Status) -> {lists:reverse(Acc), Status}. -ensure_app_info(#app{is_escript = true, active_dir = Dir, info = Info}, - Status) -> + +ensure_app_info(#app{is_escript = IsEscript, active_dir = Dir, info = Info}, + Status) + when IsEscript=/=false -> + %% Escript or application which is inlined in an escript {Info, Dir, Status}; -ensure_app_info(#app{name = Name, sorted_dirs = []}, Status) -> - Error = lists:concat([Name, ": Missing application directory."]), - Status2 = reltool_utils:return_first_error(Status, Error), - {missing_app_info(""), undefined, Status2}; +ensure_app_info(#app{name = Name, sorted_dirs = []}, _Status) -> + reltool_utils:throw_error("~p: : Missing application directory.",[Name]); ensure_app_info(#app{name = Name, vsn = Vsn, sorted_dirs = Dirs, @@ -2017,11 +1921,10 @@ ensure_app_info(#app{name = Name, %% No redundant info Status2; [BadVsn | _] -> - Error2 = - lists:concat([Name, ": Application version clash. ", - "Multiple directories contains version \"", - BadVsn, "\"."]), - reltool_utils:return_first_error(Status2, Error2) + reltool_utils:throw_error( + "~p: Application version clash. " + "Multiple directories contains version ~p.", + [Name,BadVsn]) end, FirstInfo = hd(AllInfo), FirstDir = hd(Dirs), @@ -2035,13 +1938,9 @@ ensure_app_info(#app{name = Name, {Info, VsnDir} -> {Info, VsnDir, Status3}; false -> - Error3 = - lists:concat([Name, - ": No application directory contains ", - "selected version \"", - Vsn, "\"."]), - Status4 = reltool_utils:return_first_error(Status3, Error3), - {FirstInfo, FirstDir, Status4} + reltool_utils:throw_error( + "~p: No application directory contains selected version ~p", + [Name,Vsn]) end end; ensure_app_info(#app{active_dir = Dir, info = Info}, Status) -> @@ -2067,6 +1966,54 @@ get_base(Name, Dir) -> filename:basename(Dir) end. +sys_all_apps(#state{app_tab=AppTab, sys=Sys}) -> + Sys#sys{apps = ets:match_object(AppTab,'_')}. + +config_and_refresh(OldS, Fun) -> + try + S = Fun(), + {S2, Apps, Status2} = refresh(S), + %% Analyse will write to app_tab and mod_tab, so we first + %% backup these tables and clear them + Backup = backup(OldS), + try + Status3 = analyse(S2, Apps, Status2), + S3 = save_old(OldS, S2, Backup, Status3), + {S3, Status3} + catch throw:{error,_} = Error1 -> + restore(Backup,OldS), + throw(Error1) + end + catch throw:{error,_} = Error2 -> + {OldS, Error2} + end. + + +backup(S) -> + Apps = ets:tab2list(S#state.app_tab), + Mods = ets:tab2list(S#state.mod_tab), + ets:delete_all_objects(S#state.app_tab), + ets:delete_all_objects(S#state.mod_tab), + ets:delete_all_objects(S#state.mod_used_by_tab), %tmp tab, no backup needed + {Apps,Mods}. + +restore({Apps,Mods}, S) -> + insert_all(S#state.app_tab,Apps), + insert_all(S#state.mod_tab,Mods). + +save_old(#state{status=OldStatus,sys=OldSys},NewS,{OldApps,OldMods},NewStatus) -> + ets:delete_all_objects(NewS#state.old_app_tab), + ets:delete_all_objects(NewS#state.old_mod_tab), + insert_all(NewS#state.old_app_tab,OldApps), + insert_all(NewS#state.old_mod_tab,OldMods), + NewS#state{old_sys=OldSys, + old_status=OldStatus, + status=NewStatus}. + +insert_all(Tab,Items) -> + lists:foreach(fun(Item) -> ets:insert(Tab,Item) end, Items). + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% sys callbacks diff --git a/lib/reltool/src/reltool_sys_win.erl b/lib/reltool/src/reltool_sys_win.erl index 8b0f64eb45..0c0b295db1 100644 --- a/lib/reltool/src/reltool_sys_win.erl +++ b/lib/reltool/src/reltool_sys_win.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2011. All Rights Reserved. +%% Copyright Ericsson AB 2009-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 @@ -56,7 +56,9 @@ derived, fgraph_wins, app_box, - mod_box + mod_box, + warning_list, + warning_wins }). -define(WIN_WIDTH, 800). @@ -88,6 +90,10 @@ -define(blacklist, "Excluded"). -define(derived, "Derived"). +-define(WARNING_COL, 0). +-define(DEFAULT_WARNING_TIP, "Warnings are listed in this window"). +-define(WARNING_POPUP_SIZE, {400,150}). + -define(safe_config,{sys,[{incl_cond,exclude}, {app,kernel,[{incl_cond,include}]}, {app,stdlib,[{incl_cond,include}]}, @@ -141,48 +147,44 @@ do_init([{safe_config, Safe}, {parent, Parent} | Options]) -> wx:debug(C#common.wx_debug), %% wx_misc:beginBusyCursor(), - case reltool_server:get_status(ServerPid) of - {ok, Warnings} -> - exit_dialog(Warnings), - {ok, Sys} = reltool_server:get_sys(ServerPid), - S = #state{parent_pid = Parent, - server_pid = ServerPid, - common = C, - config_file = filename:absname("config.reltool"), - target_dir = filename:absname("reltool_target_dir"), - app_wins = [], - sys = Sys, - fgraph_wins = []}, - S2 = create_window(S), - S5 = wx:batch(fun() -> - Title = atom_to_list(?APPLICATION), - wxFrame:setTitle(S2#state.frame, - Title), - %% wxFrame:setMinSize(Frame, - %% {?WIN_WIDTH, ?WIN_HEIGHT}), - wxStatusBar:setStatusText( - S2#state.status_bar, - "Done."), - S3 = redraw_apps(S2), - S4 = redraw_libs(S3), - redraw_config_page(S4) - end), - %% wx_misc:endBusyCursor(), - %% wxFrame:destroy(Frame), - proc_lib:init_ack(S#state.parent_pid, {ok, self()}), - loop(S5); - {error, Reason} -> - restart_server_safe_config(Safe,Parent,Reason) - end; + {ok, Warnings} = reltool_server:get_status(ServerPid), + exit_dialog(Warnings), + S = #state{parent_pid = Parent, + server_pid = ServerPid, + common = C, + config_file = filename:absname("config.reltool"), + target_dir = filename:absname("reltool_target_dir"), + app_wins = [], + sys = Sys, + fgraph_wins = [], + warning_wins = []}, + S2 = create_window(S), + S5 = wx:batch(fun() -> + Title = atom_to_list(?APPLICATION), + wxFrame:setTitle(S2#state.frame, + Title), + %% wxFrame:setMinSize(Frame, + %% {?WIN_WIDTH, ?WIN_HEIGHT}), + wxStatusBar:setStatusText( + S2#state.status_bar, + "Done."), + S3 = redraw_apps(S2), + S4 = redraw_libs(S3), + redraw_config_page(S4) + end), + %% wx_misc:endBusyCursor(), + %% wxFrame:destroy(Frame), + proc_lib:init_ack(S#state.parent_pid, {ok, self()}), + loop(S5); {error, Reason} -> - io:format("~p(~p): <ERROR> ~p\n", [?MODULE, ?LINE, Reason]), - exit(Reason) + restart_server_safe_config(Safe,Parent,Reason) end. -restart_server_safe_config(true,_Parent,Reason) -> +restart_server_safe_config(true,Parent,Reason) -> io:format("~p(~p): <ERROR> ~p\n", [?MODULE, ?LINE, Reason]), - exit(Reason); + proc_lib:init_ack(Parent, {error,Reason}); restart_server_safe_config(false,Parent,Reason) -> + wx:new(), Strings = [{?wxBLACK,"Could not start reltool server:\n\n"}, {?wxRED,Reason++"\n\n"}, @@ -197,7 +199,7 @@ restart_server_safe_config(false,Parent,Reason) -> do_init([{safe_config,true},{parent,Parent},?safe_config]); ?wxID_CANCEL -> io:format("~p(~p): <ERROR> ~p\n", [?MODULE, ?LINE, Reason]), - exit(Reason) + proc_lib:init_ack(Parent,{error,Reason}) end. exit_dialog([]) -> @@ -240,10 +242,18 @@ loop(S) -> lists:keydelete(ObjRef, #fgraph_win.frame, FWs), ?MODULE:loop(S#state{fgraph_wins = FWs2}); false -> - error_logger:format("~p~p got unexpected " - "message:\n\t~p\n", - [?MODULE, self(), Msg]), - ?MODULE:loop(S) + WWs = S#state.warning_wins, + case lists:member(ObjRef, WWs) of + true -> + wxFrame:destroy(ObjRef), + WWs2 = lists:delete(ObjRef, WWs), + ?MODULE:loop(S#state{warning_wins = WWs2}); + false -> + error_logger:format("~p~p got unexpected " + "message:\n\t~p\n", + [?MODULE, self(), Msg]), + ?MODULE:loop(S) + end end end; #wx{id = ?CLOSE_ITEM, @@ -297,8 +307,8 @@ handle_child_exit({'EXIT', Pid, _Reason} = Exit, FWs, AWs) -> msg_warning(Exit, application_window), {FWs, lists:keydelete(Pid, #app_win.pid, AWs)}; false -> - msg_warning(Exit, unknown), - {FWs, AWs} + msg_warning(Exit, unknown), + {FWs, AWs} end end. @@ -340,8 +350,12 @@ create_window(S) -> fun create_main_release_page/1, fun create_config_page/1 ]), + + S4 = create_warning_list(S3), + Sizer = wxBoxSizer:new(?wxVERTICAL), wxSizer:add(Sizer, Book, [{flag, ?wxEXPAND}, {proportion, 1}]), + wxSizer:add(Sizer, S4#state.warning_list, [{flag, ?wxEXPAND}]), wxPanel:setSizer(Panel, Sizer), wxSizer:fit(Sizer, Frame), @@ -349,7 +363,7 @@ create_window(S) -> wxFrame:connect(Frame, close_window), wxFrame:show(Frame), - S3. + S4. create_menubar(Frame) -> MenuBar = wxMenuBar:new(), @@ -444,6 +458,7 @@ create_app_list_ctrl(Panel, OuterSz, Title, Tick, Cross) -> ListItem = wxListItem:new(), wxListItem:setAlign(ListItem, ?wxLIST_FORMAT_LEFT), wxListItem:setText(ListItem, Title), + wxListItem:setWidth(ListItem, reltool_utils:get_column_width(ListCtrl)), wxListCtrl:insertColumn(ListCtrl, ?APPS_APP_COL, ListItem), wxListItem:destroy(ListItem), @@ -642,6 +657,49 @@ redraw_config_page(#state{sys = Sys, app_box = AppBox, mod_box = ModBox} = S) -> wxRadioBox:setSelection(ModBox, ModChoice), S. +create_warning_list(#state{panel = Panel} = S) -> + ListCtrl = wxListCtrl:new(Panel, + [{style, + ?wxLC_REPORT bor + ?wxLC_HRULES bor + ?wxVSCROLL}, + {size, {?WIN_WIDTH,80}}]), + reltool_utils:assign_image_list(ListCtrl), + wxListCtrl:insertColumn(ListCtrl, ?WARNING_COL, "Warnings", + [{format,?wxLIST_FORMAT_LEFT}, + {width,reltool_utils:get_column_width(ListCtrl)}]), + wxListCtrl:setToolTip(ListCtrl, ?DEFAULT_WARNING_TIP), + wxEvtHandler:connect(ListCtrl, size, + [{skip, true}, {userData, warnings}]), + wxEvtHandler:connect(ListCtrl, command_list_item_activated, + [{userData, warnings}]), + wxEvtHandler:connect(ListCtrl, motion, [{userData, warnings}]), + wxEvtHandler:connect(ListCtrl, enter_window), + S#state{warning_list=ListCtrl}. + +redraw_warnings(S) -> + {ok,Warnings} = reltool_server:get_status(S#state.server_pid), + redraw_warnings(S#state.warning_list,Warnings), + length(Warnings). + +redraw_warnings(ListCtrl, []) -> + wxListCtrl:deleteAllItems(ListCtrl), + ok; +redraw_warnings(ListCtrl, Warnings) -> + wxListCtrl:deleteAllItems(ListCtrl), + Show = fun(Warning, Row) -> + wxListCtrl:insertItem(ListCtrl, Row, ""), + wxListCtrl:setItem(ListCtrl, + Row, + ?WARNING_COL, + Warning, + [{imageId, ?WARN_IMAGE}]), + Row + 1 + end, + wx:foldl(Show, 0, Warnings), + ok. + + create_main_release_page(#state{book = Book} = S) -> Panel = wxPanel:new(Book, []), RelBook = wxNotebook:new(Panel, ?wxID_ANY, []), @@ -783,6 +841,9 @@ escript_popup(S, File, Tree, Item) -> handle_event(S, #wx{id = Id, obj= ObjRef, userData = UserData, event = Event} = _Wx) -> %% io:format("wx: ~p\n", [Wx]), case Event of + _ when UserData =:= warnings; + is_tuple(UserData), element(1,UserData)=:=warning -> + handle_warning_event(S, ObjRef, UserData, Event); #wxSize{type = size, size = {W, _H}} when UserData =:= app_list_ctrl -> wxListCtrl:setColumnWidth(ObjRef, ?APPS_APP_COL, W), S; @@ -848,7 +909,9 @@ handle_event(S, #wx{id = Id, obj= ObjRef, userData = UserData, event = Event} = when S#state.popup_menu =/= undefined -> handle_popup_event(S, Type, Id, ObjRef, UserData, Str); #wxMouse{type = enter_window} -> - wxWindow:setFocus(ObjRef), + %% The following is commented out because it raises the + %% main system window on top of popup windows. + %% wxWindow:setFocus(ObjRef), S; _ -> case wxNotebook:getPageText(S#state.book, @@ -860,6 +923,110 @@ handle_event(S, #wx{id = Id, obj= ObjRef, userData = UserData, event = Event} = end end. +handle_warning_event(S, ObjRef, _, #wxSize{type = size}) -> + ColumnWidth = reltool_utils:get_column_width(ObjRef), + wxListCtrl:setColumnWidth(ObjRef, ?WARNING_COL, ColumnWidth), + S; +handle_warning_event(S, ObjRef, _, #wxMouse{type = motion, x=X, y=Y}) -> + Pos = reltool_utils:wait_for_stop_motion(ObjRef, {X,Y}), + warning_list_set_tool_tip(os:type(),ObjRef,Pos), + S; +handle_warning_event(S, ObjRef, _, #wxList{type = command_list_item_activated, + itemIndex = Pos}) -> + Text = wxListCtrl:getItemText(ObjRef, Pos), + S#state{warning_wins = [display_warning(S,Text) | S#state.warning_wins]}; +handle_warning_event(S, _ObjRef, {warning,Frame}, + #wxCommand{type = command_button_clicked}) -> + wxFrame:destroy(Frame), + S#state{warning_wins = lists:delete(Frame,S#state.warning_wins)}. + +warning_list_set_tool_tip({win32,_},ListCtrl,{_X,Y}) -> + case win_find_item(ListCtrl,Y,0) of + -1 -> + wxListCtrl:setToolTip(ListCtrl,?DEFAULT_WARNING_TIP); + _Index -> + %% The following is commented out because there seems to + %% be an utomatic tooltip under Windows that shows the + %% expanded list item in case it is truncated because it + %% is too long for column width. + %% Tip = + %% case wxListCtrl:getItemText(ListCtrl,Index) of + %% "" -> + %% ?DEFAULT_WARNING_TIP; + %% Text -> + %% "WARNING:\n" ++ Text + %% end, + %% wxListCtrl:setToolTip(ListCtrl,Tip), + ok + end; +warning_list_set_tool_tip(_,ListCtrl,Pos) -> + case wxListCtrl:findItem(ListCtrl,-1,Pos,0) of + Index when Index >= 0 -> + Tip = + case wxListCtrl:getItemText(ListCtrl,Index) of + "" -> + ?DEFAULT_WARNING_TIP; + Text -> + "WARNING:\n" ++ Text + end, + wxListCtrl:setToolTip(ListCtrl, Tip); + _ -> + ok + end. + +win_find_item(ListCtrl,YPos,Index) -> + case wxListCtrl:getItemRect(ListCtrl,Index) of + {true,{_,Y,_,H}} when YPos>=Y, YPos=<Y+H -> + Index; + {true,_} -> + win_find_item(ListCtrl,YPos,Index+1); + {false,_} -> + -1 + end. + +display_warning(S,Warning) -> + Pos = warning_popup_position(S,?WARNING_POPUP_SIZE), + Frame = wxFrame:new(wx:null(), ?wxID_ANY, "Warning",[{pos,Pos}]), + Panel = wxPanel:new(Frame, []), + TextStyle = ?wxTE_READONLY bor ?wxTE_WORDWRAP bor ?wxTE_MULTILINE, + Text = wxTextCtrl:new(Panel, ?wxID_ANY, [{value, Warning}, + {style, TextStyle}, + {size, ?WARNING_POPUP_SIZE}]), + Attr = wxTextAttr:new(), + wxTextAttr:setLeftIndent(Attr,10), + wxTextAttr:setRightIndent(Attr,10), + true = wxTextCtrl:setDefaultStyle(Text, Attr), + wxTextAttr:destroy(Attr), + Sizer = wxBoxSizer:new(?wxVERTICAL), + wxSizer:add(Sizer, Text, [{border, 2}, + {flag, ?wxEXPAND bor ?wxALL}, + {proportion, 1}]), + + Close = wxButton:new(Panel, ?wxID_ANY, [{label, "Close"}]), + wxButton:setToolTip(Close, "Close window."), + wxButton:connect(Close, command_button_clicked, [{userData,{warning,Frame}}]), + wxSizer:add(Sizer, Close, [{flag, ?wxALIGN_CENTER_HORIZONTAL}]), + + wxPanel:setSizer(Panel, Sizer), + wxSizer:fit(Sizer, Frame), + wxSizer:setSizeHints(Sizer, Frame), + wxFrame:connect(Frame, close_window), + + wxFrame:show(Frame), + Frame. + +warning_popup_position(#state{frame=MF,warning_list=WL},{WFW,WFH}) -> + {MFX,MFY} = wxWindow:getPosition(MF), + {MFW,MFH} = wxWindow:getSize(MF), + {_WLW,WLH} = wxWindow:getSize(WL), + + %% Position the popup in the middle of the main frame, above the + %% warning list, and with a small offset from the exact middle... + Offset = 50, + X = MFX + (MFW-WFW) div 2 - Offset, + Y = MFY + (MFH-WLH-WFH) div 2 - Offset, + {X,Y}. + handle_popup_event(S, _Type, 0, _ObjRef, _UserData, _Str) -> S#state{popup_menu = undefined}; handle_popup_event(#state{popup_menu = #root_popup{dir = OldDir, @@ -1079,16 +1246,16 @@ handle_app_event(S, Event, ObjRef, UserData) -> [?MODULE, self(), ObjRef, UserData, Event]), S. -handle_app_button(#state{server_pid = ServerPid, app_wins = AppWins} = S, +handle_app_button(#state{server_pid = ServerPid, + status_bar = Bar, + app_wins = AppWins} = S, Items, Action) -> + wxStatusBar:setStatusText(Bar, "Processing libraries..."), NewApps = [move_app(S, Item, Action) || Item <- Items], case reltool_server:set_apps(ServerPid, NewApps) of - {ok, []} -> + {ok, _Warnings} -> ok; - {ok, Warnings} -> - Msg = lists:flatten([[W, $\n] || W <- Warnings]), - display_message(Msg, ?wxICON_WARNING); {error, Reason} -> display_message(Reason, ?wxICON_ERROR) end, @@ -1125,23 +1292,22 @@ move_app(S, {_ItemNo, AppBase}, Action) -> end, OldApp#app{incl_cond = AppCond}. -do_set_app(#state{server_pid = ServerPid, app_wins = AppWins} = S, NewApp) -> +do_set_app(#state{server_pid = ServerPid, + status_bar = Bar, + app_wins = AppWins} = S, NewApp) -> + wxStatusBar:setStatusText(Bar, "Processing libraries..."), Result = reltool_server:set_app(ServerPid, NewApp), - [ok = reltool_app_win:refresh(AW#app_win.pid) || AW <- AppWins], - S2 = redraw_apps(S), ReturnApp = case Result of - {ok, AnalysedApp, []} -> - AnalysedApp; - {ok, AnalysedApp, Warnings} -> - Msg = lists:flatten([[W, $\n] || W <- Warnings]), - display_message(Msg, ?wxICON_WARNING), + {ok, AnalysedApp, _Warnings} -> AnalysedApp; {error, Reason} -> display_message(Reason, ?wxICON_ERROR), {ok,OldApp} = reltool_server:get_app(ServerPid, NewApp#app.name), OldApp end, + [ok = reltool_app_win:refresh(AW#app_win.pid) || AW <- AppWins], + S2 = redraw_apps(S), {ok, ReturnApp, S2}. redraw_apps(#state{server_pid = ServerPid, @@ -1164,8 +1330,14 @@ redraw_apps(#state{server_pid = ServerPid, WhiteN = redraw_apps(WhiteApps, WhiteCtrl, ?TICK_IMAGE, ?ERR_IMAGE), redraw_apps(BlackApps2, BlackCtrl, ?CROSS_IMAGE, ?WARN_IMAGE), DerivedN = redraw_apps(DerivedApps, DerivedCtrl, ?TICK_IMAGE, ?ERR_IMAGE), + + WarningsN = redraw_warnings(S), + WarningText = if WarningsN==1 -> "warning"; + true -> "warnings" + end, Status = lists:concat([WhiteN, " whitelisted modules and ", - DerivedN, " derived modules."]), + DerivedN, " derived modules, ", + WarningsN, " ", WarningText, "."]), wxStatusBar:setStatusText(S#state.status_bar, Status), S. @@ -1323,26 +1495,28 @@ save_config(#state{config_file = OldFile} = S, InclDefaults, InclDerivates) -> S end. -gen_rel_files(#state{target_dir = OldDir} = S) -> +gen_rel_files(#state{status_bar = Bar, target_dir = OldDir} = S) -> Style = ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT, case select_dir(S#state.frame, "Select a directory to generate rel, script and boot files to", OldDir, Style) of {ok, NewDir} -> + wxStatusBar:setStatusText(Bar, "Processing libraries..."), Status = reltool_server:gen_rel_files(S#state.server_pid, NewDir), check_and_refresh(S, Status); cancel -> S end. -gen_target(#state{target_dir = OldDir} = S) -> +gen_target(#state{status_bar = Bar, target_dir = OldDir} = S) -> Style = ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT, case select_dir(S#state.frame, "Select a directory to generate a target system to", OldDir, Style) of {ok, NewDir} -> + wxStatusBar:setStatusText(Bar, "Processing libraries..."), Status = reltool_server:gen_target(S#state.server_pid, NewDir), check_and_refresh(S#state{target_dir = NewDir}, Status); cancel -> @@ -1380,8 +1554,8 @@ check_and_refresh(S, Status) -> case Status of ok -> true; - {ok, Warnings} -> - undo_dialog(S, Warnings); + {ok, _Warnings} -> + true; {error, Reason} when is_list(Reason) -> display_message(Reason, ?wxICON_ERROR), false; @@ -1435,19 +1609,6 @@ question_dialog(Question, Details) -> wxDialog:destroy(Dialog), Answer. -undo_dialog(_S, []) -> - true; -undo_dialog(S, Warnings) -> - Question = "Do you want to perform the update despite these warnings?", - Details = lists:flatten([[W, $\n] || W <- Warnings]), - case question_dialog(Question, Details) of - ?wxID_OK -> - true; - ?wxID_CANCEL -> - reltool_server:undo_config(S#state.server_pid), - false - end. - display_message(Message, Icon) -> Dialog = wxMessageDialog:new(wx:null(), Message, @@ -1491,8 +1652,6 @@ add_text(_,_,[]) -> ok. - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% sys callbacks diff --git a/lib/reltool/src/reltool_target.erl b/lib/reltool/src/reltool_target.erl index 0fcf89a360..3d83a77d99 100644 --- a/lib/reltool/src/reltool_target.erl +++ b/lib/reltool/src/reltool_target.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2011. All Rights Reserved. +%% Copyright Ericsson AB 2009-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 @@ -101,7 +101,7 @@ do_gen_config(#sys{root_dir = RootDir, || A <- Apps, A#app.name =/= ?MISSING_APP_NAME, A#app.name =/= erts, - not A#app.is_escript], + A#app.is_escript =/= true], EscriptItems = [{escript, A#app.active_dir, emit(incl_cond, A#app.incl_cond, undefined, InclDefs)} @@ -208,10 +208,10 @@ do_gen_config(#rel_app{name = Name, incl_apps = InclApps}, _InclDefs) -> case {Type, InclApps} of - {undefined, []} -> Name; - {undefined, _} -> {Name, InclApps}; - {_, []} -> {Name, Type}; - {_, _} -> {Name, Type, InclApps} + {undefined, undefined} -> Name; + {undefined, _} -> {Name, InclApps}; + {_, undefined} -> {Name, Type}; + {_, _} -> {Name, Type, InclApps} end; do_gen_config({Tag, Val}, InclDefs) -> emit(Tag, Val, undefined, InclDefs); @@ -279,7 +279,7 @@ gen_rel(Rel, Sys) -> {error, Text} end. -do_gen_rel(#rel{name = RelName, vsn = RelVsn}, +do_gen_rel(#rel{name = RelName, vsn = RelVsn, rel_apps = RelApps}, #sys{apps = Apps}, MergedApps) -> ErtsName = erts, @@ -288,7 +288,7 @@ do_gen_rel(#rel{name = RelName, vsn = RelVsn}, {release, {RelName, RelVsn}, {ErtsName, Erts#app.vsn}, - [strip_rel_info(App) || App <- MergedApps]}; + [strip_rel_info(App, RelApps) || App <- MergedApps]}; false -> reltool_utils:throw_error("Mandatory application ~p is " "not included", @@ -298,13 +298,17 @@ do_gen_rel(#rel{name = RelName, vsn = RelVsn}, strip_rel_info(#app{name = Name, vsn = Vsn, app_type = Type, - info = #app_info{incl_apps = InclApps}}) - when Type =/= undefined -> - case {Type, InclApps} of - {permanent, []} -> {Name, Vsn}; - {permanent, _} -> {Name, Vsn, InclApps}; - {_, []} -> {Name, Vsn, Type}; - {_, _} -> {Name, Vsn, Type, InclApps} + info = #app_info{incl_apps = AppInclApps}}, + RelApps) when Type =/= undefined -> + RelInclApps = case lists:keyfind(Name,#rel_app.name,RelApps) of + #rel_app{incl_apps = RIA} when RIA =/= undefined -> RIA; + _ -> undefined + end, + case {Type, RelInclApps} of + {permanent, undefined} -> {Name, Vsn}; + {permanent, _} -> {Name, Vsn, AppInclApps}; + {_, undefined} -> {Name, Vsn, Type}; + {_, _} -> {Name, Vsn, Type, AppInclApps} end. merge_apps(#rel{name = RelName, @@ -323,7 +327,7 @@ merge_apps(#rel{name = RelName, A#app.name =/= ?MISSING_APP_NAME, not lists:keymember(A#app.name, #app.name, MergedApps2)], MergedApps3 = do_merge_apps(RelName, Embedded, Apps, EmbAppType, MergedApps2), - sort_apps(MergedApps3). + sort_apps(lists:reverse(MergedApps3)). do_merge_apps(RelName, [#rel_app{name = Name} = RA | RelApps], Apps, RelAppType, Acc) -> case is_already_merged(Name, RelApps, Acc) of @@ -341,25 +345,18 @@ do_merge_apps(RelName, [Name | RelApps], Apps, RelAppType, Acc) -> true -> do_merge_apps(RelName, RelApps, Apps, RelAppType, Acc); false -> - RelApp = init_rel_app(Name, Apps), + RelApp = #rel_app{name = Name}, do_merge_apps(RelName, [RelApp | RelApps], Apps, RelAppType, Acc) end; do_merge_apps(_RelName, [], _Apps, _RelAppType, Acc) -> - lists:reverse(Acc). - -init_rel_app(Name, Apps) -> - {value, App} = lists:keysearch(Name, #app.name, Apps), - Info = App#app.info, - #rel_app{name = Name, - app_type = undefined, - incl_apps = Info#app_info.incl_apps}. + Acc. merge_app(RelName, - #rel_app{name = Name, - app_type = Type, - incl_apps = InclApps}, - RelAppType, - App) -> + #rel_app{name = Name, + app_type = Type, + incl_apps = InclApps0}, + RelAppType, + App) -> Type2 = case {Type, App#app.app_type} of {undefined, undefined} -> RelAppType; @@ -367,6 +364,11 @@ merge_app(RelName, {_, _} -> Type end, Info = App#app.info, + InclApps = + case InclApps0 of + undefined -> Info#app_info.incl_apps; + _ -> InclApps0 + end, case InclApps -- Info#app_info.incl_apps of [] -> App#app{app_type = Type2, info = Info#app_info{incl_apps = InclApps}}; @@ -421,7 +423,10 @@ do_gen_script(#rel{name = RelName, vsn = RelVsn}, Mandatory = mandatory_modules(), Early = Mandatory ++ Preloaded, {value, KernelApp} = lists:keysearch(kernel, #app.name, MergedApps), - InclApps = [I || #app{info = #app_info{incl_apps = I}} <- MergedApps], + InclApps = lists:flatmap(fun(#app{info = #app_info{incl_apps = I}}) -> + I + end, + MergedApps), %% Create the script DeepList = @@ -471,7 +476,7 @@ load_app_mods(#app{mods = Mods} = App, Mand, PathFlag, Variables) -> Path = cr_path(App, PathFlag, Variables), PartNames = lists:sort([{packages:split(M),M} || - #mod{name = M} <- Mods, + #mod{name = M, is_included=true} <- Mods, not lists:member(M, Mand)]), SplitMods = lists:foldl( @@ -513,7 +518,12 @@ sort_apps([#app{name = Name, info = Info} = App | Apps], Circular, Visited) -> {Uses, Apps1, NotFnd1} = - find_all(Name, Info#app_info.applications, Apps, Visited, [], []), + find_all(Name, + lists:reverse(Info#app_info.applications), + Apps, + Visited, + [], + []), {Incs, Apps2, NotFnd2} = find_all(Name, lists:reverse(Info#app_info.incl_apps), @@ -895,7 +905,7 @@ spec_escripts(#sys{apps = Apps}, ErtsBin, BinFiles) -> if Name =:= ?MISSING_APP_NAME -> false; - not IsEscript -> + IsEscript =/= true -> false; IsIncl; IsPre -> {true, do_spec_escript(File, ErtsBin, BinFiles)}; @@ -957,7 +967,7 @@ spec_lib_files(#sys{apps = Apps} = Sys) -> if Name =:= ?MISSING_APP_NAME -> false; - IsEscript -> + IsEscript =/= false -> false; IsIncl; IsPre -> true; diff --git a/lib/reltool/src/reltool_utils.erl b/lib/reltool/src/reltool_utils.erl index 39d057d994..b0def45213 100644 --- a/lib/reltool/src/reltool_utils.erl +++ b/lib/reltool/src/reltool_utils.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% Copyright Ericsson AB 2009-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 @@ -23,14 +23,15 @@ split_app_name/1, prim_consult/1, default_rels/0, choose_default/3, - assign_image_list/1, get_latest_resize/1, + assign_image_list/1, get_latest_resize/1, wait_for_stop_motion/2, mod_conds/0, list_to_mod_cond/1, mod_cond_to_index/1, incl_conds/0, list_to_incl_cond/1, incl_cond_to_index/1, elem_to_index/2, app_dir_test/2, split_app_dir/1, get_item/1, get_items/1, get_selected_items/3, select_items/3, select_item/2, + get_column_width/1, - safe_keysearch/5, print/4, return_first_error/2, add_warning/2, + safe_keysearch/5, print/4, add_warning/3, create_dir/1, list_dir/1, read_file_info/1, write_file_info/2, read_file/1, write_file/2, @@ -126,18 +127,14 @@ prim_parse(Tokens, Acc) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% default_rels() -> - %%Kernel = #rel_app{name = kernel, incl_apps = []}, - %%Stdlib = #rel_app{name = stdlib, incl_apps = []}, - Sasl = #rel_app{name = sasl, incl_apps = []}, + %% kernel and stdlib are added automatically in every release [ #rel{name = ?DEFAULT_REL_NAME, vsn = "1.0", rel_apps = []}, - %%rel_apps = [Kernel, Stdlib]}, #rel{name = "start_sasl", vsn = "1.0", - rel_apps = [Sasl]} - %%rel_apps = [Kernel, Sasl, Stdlib]} + rel_apps = [#rel_app{name = sasl}]} ]. choose_default(Tag, Profile, InclDefs) @@ -191,6 +188,16 @@ get_latest_resize(#wx{obj = ObjRef, event = #wxSize{}} = Wx) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +wait_for_stop_motion(ObjRef, {_,_}=Pos) -> + receive + #wx{obj = ObjRef, event = #wxMouse{type = motion, x=X, y=Y}} -> + wait_for_stop_motion(ObjRef, {X,Y}) + after 100 -> + Pos + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + mod_conds() -> ["all (ebin + app file)", "ebin + derived", "app file + derived", "derived", "none"]. @@ -377,6 +384,26 @@ select_item(ListCtrl, [{ItemNo, Text} | Items]) -> select_item(_ListCtrl, []) -> ok. +get_column_width(ListCtrl) -> + wx:batch(fun() -> + {Total, _} = wxWindow:getClientSize(ListCtrl), + Total - scroll_size(ListCtrl) + end). + +scroll_size(ObjRef) -> + case os:type() of + {win32, nt} -> 0; + {unix, darwin} -> + %% I can't figure out is there is a visible scrollbar + %% Always make room for it + wxSystemSettings:getMetric(?wxSYS_VSCROLL_X); + _ -> + case wxWindow:hasScrollbar(ObjRef, ?wxVERTICAL) of + true -> wxSystemSettings:getMetric(?wxSYS_VSCROLL_X); + false -> 0 + end + end. + safe_keysearch(Key, Pos, List, Mod, Line) -> case lists:keysearch(Key, Pos, List) of false -> @@ -392,31 +419,13 @@ print(X, X, Format, Args) -> print(_, _, _, _) -> ok. -%% -define(SAFE(M,F,A), safe(M, F, A, ?MODULE, ?LINE)). -%% -%% safe(M, F, A, Mod, Line) -> -%% case catch apply(M, F, A) of -%% {'EXIT', Reason} -> -%% io:format("~p(~p): ~p:~p~p -> ~p\n", [Mod, Line, M, F, A, Reason]), -%% timer:sleep(infinity); -%% Res -> -%% Res -%% end. - -return_first_error(Status, NewError) when is_list(NewError) -> - case Status of - {ok, _Warnings} -> - {error, NewError}; - {error, OldError} -> - {error, OldError} - end. - -add_warning(Status, Warning) -> - case Status of - {ok, Warnings} -> - {ok, [Warning | Warnings]}; - {error, Error} -> - {error, Error} +add_warning(Format, Args, {ok,Warnings}) -> + Warning = lists:flatten(io_lib:format(Format,Args)), + case lists:member(Warning,Warnings) of + true -> + {ok,Warnings}; + false -> + {ok,[Warning|Warnings]} end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/reltool/test/Makefile b/lib/reltool/test/Makefile index 767454b66a..d8a7adb837 100644 --- a/lib/reltool/test/Makefile +++ b/lib/reltool/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2009-2011. All Rights Reserved. +# Copyright Ericsson AB 2009-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 @@ -28,6 +28,7 @@ MODULES= \ reltool_app_SUITE \ reltool_wx_SUITE \ reltool_server_SUITE \ + reltool_manual_gui_SUITE \ reltool_test_lib diff --git a/lib/reltool/test/reltool.spec b/lib/reltool/test/reltool.spec index 2995720105..2501a7a203 100644 --- a/lib/reltool/test/reltool.spec +++ b/lib/reltool/test/reltool.spec @@ -1 +1,2 @@ {suites,"../reltool_test",all}. +{skip_suites,"../reltool_test",[reltool_manual_gui_SUITE],"Manual only"}. diff --git a/lib/reltool/test/reltool_manual_gui_SUITE.erl b/lib/reltool/test/reltool_manual_gui_SUITE.erl new file mode 100644 index 0000000000..0dcc5cbf15 --- /dev/null +++ b/lib/reltool/test/reltool_manual_gui_SUITE.erl @@ -0,0 +1,266 @@ +%% +%% %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(reltool_manual_gui_SUITE). + +-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, + init_per_suite/1, end_per_suite/1, + init_per_testcase/2, end_per_testcase/2]). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include("reltool_test_lib.hrl"). + +%% Initialization functions. +init_per_suite(Config) -> + reltool_test_lib:wx_init_per_suite(Config). + +end_per_suite(Config) -> + reltool_test_lib:wx_end_per_suite(Config). + +init_per_testcase(Func,Config) -> + reltool_test_lib:init_per_testcase(Func,Config). +end_per_testcase(Func,Config) -> + reltool_test_lib:end_per_testcase(Func,Config). + +%% SUITE specification +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [config, depgraphs]. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +%% The test cases + +%% Semi-automatic walkthrough of the GUI +config(Config) -> + DataDir = ?config(data_dir,Config), + PrivDir = ?config(priv_dir,Config), + {ok, SysPid} = ?msym({ok, _}, reltool:start([])), + link(SysPid), + + SimpleConfigFile = create_simple_config(PrivDir), + WarningConfigFile = create_warning_config(PrivDir,DataDir), + + break("there are no modules in the 'Included' and 'Excluded' columns, " + "and now warnings are displayed", + {"load configuration ~p",[SimpleConfigFile]}), + break("kernel, stdlib and sasl are included and all other are excluded", + "undo"), + break("we are back to default - no included and no excluded applications", + "undo again"), + break("kernel, stdlib and sasl are included and all other are excluded", + {"load configuration ~p", + [WarningConfigFile]}), + break("a warning is displayed in the warning list", + "undo"), + break("no warning is displayed in the warning list", + "load same configuration again"), + break("application a is added in the 'Included' column and " + "one warning is displayed", + "reset configuration"), + break("we are back to default - no included and no excluded applications, " + "and no warnings", + "undo"), + break("a, kernel, stdlib and sasl are included and all other are excluded. " + "One warning should now exist through the rest of this test case", + "double click the warning"), + break("a popup window occurs displaying the warning text", + "close it with the 'Close' button"), + break("it disappears", + "open it again"), + break("the warning text can be marked, copied and pasted", + "close the popup with the close box on the top frame"), + break("it disappears", + "select application a from 'Included' column and click 'cross'-button " + "with to exclude it"), + break("application a is moved to 'Excluded' column", + "select application tools from 'Excluded' column and click " + "'tick'-button to include it"), + break("application tools is moved to 'Included' column", + "select application runtime_tools from 'Excluded' column and click " + "'tick'-button to include it"), + break("application runtime_tools is moved to 'Included' column", + "undo"), + + ExplicitConfig = filename:join(PrivDir,"explicit.config"), + break("application runtime_tools is moved back to 'Excluded' column", + {"save configuration as 'explicit' to ~p",[ExplicitConfig]}), + ExpectedExplicitConfig = + {sys,[{lib_dirs,[filename:join(DataDir,"faulty_app_file")]}, + {incl_cond,exclude}, + {app,a,[{incl_cond,exclude}]}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,tools,[{incl_cond,include}]}]}, + check_config(ExpectedExplicitConfig,ExplicitConfig), + + break("The saved configuration file is checked and is ok.\n" + "Now go to the 'Libraries' tab and change the root directory to " + "some invalid directory."), + break("an error dialog occurs saying that there is no lib dir", + {"add library directory ~p", + [filename:join(DataDir,"dependencies")]}), + break("applications x, y and z are added to the 'Excluded' column in " + "'Applications' tab", + "go to the 'System settings' tab and set application inclusion policy " + "to 'derived'"), + break("a is excluded, kernel, stdlib, sasl and tools are included and " + "x, y and z are available in the 'Applications' tab", + "undo"), + break("all non included application are moved to the 'Excluded' column " + "and that 'Application inclusion policy' under 'System settings' " + "tab is set back to 'exclude'", + "undo again"), + break("applications x, y and z are in the 'Available' column", + "open application x, go to the 'Application settings' tab and set " + "'Application inclusion policy' to 'Use application specific config' " + "and 'include'. Close the window"), + break("application x is moved to the 'Included' column and z and y are moved " + "to the 'Derived' column in the system window", + "open application y"), + break("modules y1, y2 and y3 are in the 'Derived' column", + "go to 'Application dependencies' tab"), + break("application y is used by x, requires kernel and stdlib, and uses z", + "go to 'Module dependencies' tab"), + break("y is used by x2 and x3, and uses z1", + "got to 'Application settings' tab and select " + "'Source selection policy' 'Use selected version'"), + break("'Directories' frame becomes enabled (clickable)", + "select 'Module inclusion policy' 'Use application specific config' " + "and select 'app file + derived'"), + break("module y3 is moved to the 'Available' column in the 'Modules' tab", + "open module y1"), + break("module y1 is used by x2 and uses z1", + "go to the 'Code' tab and double click the line with call to z1:f()"), + break("new tab is opened with module z1", + "find something"), + break("it is found", + "goto some line"), + break("the cursor is moved to that line", + "click the 'Back' button"), + break("the cursor is moved back to the line of your previous 'find'", + "terminate the application window (but keep the module window)."), + + {ok,ServerPid} = reltool:get_server(SysPid), + unlink(SysPid), + break("the system window is still alive", + "terminate reltool by hitting 'Ctrl-q' (linux) or clicking the " + "close box on the top fram when system window is active"), + false = erlang:is_process_alive(SysPid), + false = erlang:is_process_alive(ServerPid), + + break("Check that both module window and system window are terminated"), + + ok. + + +depgraphs(Config) -> + PrivDir = ?config(priv_dir,Config), + SimpleConfigFile = create_simple_config(PrivDir), + {ok, SysPid} = ?msym({ok, _}, reltool:start([{config,SimpleConfigFile}])), + link(SysPid), + + break("Open the application dependency graph and \n\n" + "*move the complete graph by left clicking somewhere over it and drag\n" + "*move one node left clicking the node and drag\n" + "*lock node to position by holding down shift while releasing\n" + "*select several nodes with ctrl and left mouse button\n" + "*lock/unlock selected nodes with suitable buttons\n" + "*freeze\n" + "*reset\n" + "*left slider: push nodes apart\n" + "*right slider: pull nodes together\n" + "*middle slider: adjust length of links\n" + "*select node and delete\n"), + break("Open the module dependency graph and meditate over it... "), + + unlink(SysPid), + break("Terminate reltool from the file menu in the system window"), + false = erlang:is_process_alive(SysPid), + + break("Check that system window and graphs are terminated"), + + ok. + + + + +%%%----------------------------------------------------------------- +%%% Internal functions +break(CheckStr,DoStr) when is_list(CheckStr), is_list(DoStr) -> + Str = io_lib:format("Check that ~s.~n~nThen ~s.",[CheckStr,DoStr]), + break(Str); +break(Check,Do) -> + CheckStr = + case Check of + {CheckFormat,CheckArgs} -> io_lib:format(CheckFormat,CheckArgs); + _ -> Check + end, + DoStr = + case Do of + {DoFormat,DoArgs} -> io_lib:format(DoFormat,DoArgs); + _ -> Do + end, + break(CheckStr,DoStr). + +break(Str) -> + Count = + case get(count) of + undefined -> 1; + C -> C + end, + put(count,Count+1), + test_server:break("Step " ++ integer_to_list(Count) ++ ":\n" ++ Str). + +check_config(Expected,File) -> + {ok,[Config]} = file:consult(File), + ?m(Expected,Config). + +create_simple_config(PrivDir) -> + SimpleConfigFile = filename:join(PrivDir,"simple.config"), + SimpleConfig = {sys,[{incl_cond,exclude}, + {app,kernel,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}]}, + ok=file:write_file(SimpleConfigFile,io_lib:format("~p.~n",[SimpleConfig])), + SimpleConfigFile. + +create_warning_config(PrivDir,DataDir) -> + WarningConfigFile = filename:join(PrivDir,"warning.config"), + FaultyAppFileDir = filename:join(DataDir,"faulty_app_file"), + WarningConfig = {sys,[{lib_dirs,[FaultyAppFileDir]}, + {incl_cond,exclude}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,a,[{incl_cond,include}]} + ]}, + ok=file:write_file(WarningConfigFile,io_lib:format("~p.~n",[WarningConfig])), + WarningConfigFile. diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/Makefile.src b/lib/reltool/test/reltool_manual_gui_SUITE_data/Makefile.src new file mode 100644 index 0000000000..9a340274ad --- /dev/null +++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/Makefile.src @@ -0,0 +1,28 @@ +EFLAGS=+debug_info + +DEPENDENCIES= \ + dependencies/x-1.0/ebin/x1.@EMULATOR@ \ + dependencies/x-1.0/ebin/x2.@EMULATOR@ \ + dependencies/x-1.0/ebin/x3.@EMULATOR@ \ + dependencies/y-1.0/ebin/y1.@EMULATOR@ \ + dependencies/y-1.0/ebin/y2.@EMULATOR@ \ + dependencies/y-1.0/ebin/y3.@EMULATOR@ \ + dependencies/z-1.0/ebin/z1.@EMULATOR@ + + +all: $(DEPENDENCIES) + +dependencies/x-1.0/ebin/x1.@EMULATOR@: dependencies/x-1.0/src/x1.erl + erlc $(EFLAGS) -odependencies/x-1.0/ebin dependencies/x-1.0/src/x1.erl +dependencies/x-1.0/ebin/x2.@EMULATOR@: dependencies/x-1.0/src/x2.erl + erlc $(EFLAGS) -odependencies/x-1.0/ebin dependencies/x-1.0/src/x2.erl +dependencies/x-1.0/ebin/x3.@EMULATOR@: dependencies/x-1.0/src/x3.erl + erlc $(EFLAGS) -odependencies/x-1.0/ebin dependencies/x-1.0/src/x3.erl +dependencies/y-1.0/ebin/y1.@EMULATOR@: dependencies/y-1.0/src/y1.erl + erlc $(EFLAGS) -odependencies/y-1.0/ebin dependencies/y-1.0/src/y1.erl +dependencies/y-1.0/ebin/y2.@EMULATOR@: dependencies/y-1.0/src/y2.erl + erlc $(EFLAGS) -odependencies/y-1.0/ebin dependencies/y-1.0/src/y2.erl +dependencies/y-1.0/ebin/y3.@EMULATOR@: dependencies/y-1.0/src/y3.erl + erlc $(EFLAGS) -odependencies/y-1.0/ebin dependencies/y-1.0/src/y3.erl +dependencies/z-1.0/ebin/z1.@EMULATOR@: dependencies/z-1.0/src/z1.erl + erlc $(EFLAGS) -odependencies/z-1.0/ebin dependencies/z-1.0/src/z1.erl diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/ebin/x.app b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/ebin/x.app new file mode 100644 index 0000000000..ccaab8a8c7 --- /dev/null +++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/ebin/x.app @@ -0,0 +1,7 @@ +% -*-erlang-*- +{application, x, + [{description, "Main application in reltool dependency test"}, + {vsn, "1.0"}, + {modules, [x1,x2,x3]}, + {registered, []}, + {applications, [kernel, stdlib]}]}. diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x1.erl b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x1.erl new file mode 100644 index 0000000000..bf1e7f9279 --- /dev/null +++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x1.erl @@ -0,0 +1,5 @@ +-module(x1). +-compile(export_all). + +f() -> + ok. diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x2.erl b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x2.erl new file mode 100644 index 0000000000..82191ba278 --- /dev/null +++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x2.erl @@ -0,0 +1,5 @@ +-module(x2). +-compile(export_all). + +f() -> + y1:f(). diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x3.erl b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x3.erl new file mode 100644 index 0000000000..618c75c9a7 --- /dev/null +++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/x-1.0/src/x3.erl @@ -0,0 +1,5 @@ +-module(x3). +-compile(export_all). + +f() -> + y2:f(). diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/ebin/y.app b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/ebin/y.app new file mode 100644 index 0000000000..4f9b610b69 --- /dev/null +++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/ebin/y.app @@ -0,0 +1,7 @@ +% -*-erlang-*- +{application, y, + [{description, "Library application in reltool dependency test"}, + {vsn, "1.0"}, + {modules, [y1,y2]}, % y3 is skipped on purpose - to test module inclusion policy + {registered, []}, + {applications, [kernel, stdlib]}]}. diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y1.erl b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y1.erl new file mode 100644 index 0000000000..dd21b33292 --- /dev/null +++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y1.erl @@ -0,0 +1,5 @@ +-module(y1). +-compile(export_all). + +f() -> + z1:f(). diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y2.erl b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y2.erl new file mode 100644 index 0000000000..bf8ddf6080 --- /dev/null +++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y2.erl @@ -0,0 +1,5 @@ +-module(y2). +-compile(export_all). + +f() -> + ok. diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y3.erl b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y3.erl new file mode 100644 index 0000000000..915d64d5b9 --- /dev/null +++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/y-1.0/src/y3.erl @@ -0,0 +1,5 @@ +-module(y3). +-compile(export_all). + +f() -> + ok. diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/z-1.0/ebin/z.app b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/z-1.0/ebin/z.app new file mode 100644 index 0000000000..437a0968e9 --- /dev/null +++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/z-1.0/ebin/z.app @@ -0,0 +1,7 @@ +% -*-erlang-*- +{application, z, + [{description, "Library application in reltool dependency test"}, + {vsn, "1.0"}, + {modules, [z1]}, + {registered, []}, + {applications, [kernel, stdlib]}]}. diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/z-1.0/src/z1.erl b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/z-1.0/src/z1.erl new file mode 100644 index 0000000000..97ef90b87f --- /dev/null +++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/dependencies/z-1.0/src/z1.erl @@ -0,0 +1,5 @@ +-module(z1). +-compile(export_all). + +f() -> + ok. diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/ebin/a.app b/lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/ebin/a.app new file mode 100644 index 0000000000..ea77103598 --- /dev/null +++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/ebin/a.app @@ -0,0 +1 @@ +faulty app file diff --git a/lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/src/a.erl b/lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/src/a.erl new file mode 100644 index 0000000000..bb500bed69 --- /dev/null +++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/src/a.erl @@ -0,0 +1,49 @@ +%% ``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). + +-vsn(1). + +%% 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/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/src/a_sup.erl b/lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/src/a_sup.erl new file mode 100644 index 0000000000..a141c1767b --- /dev/null +++ b/lib/reltool/test/reltool_manual_gui_SUITE_data/faulty_app_file/a-1.0/src/a_sup.erl @@ -0,0 +1,37 @@ +%% ``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/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl index 9ed79e8c95..4e24a2fb55 100644 --- a/lib/reltool/test/reltool_server_SUITE.erl +++ b/lib/reltool/test/reltool_server_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2011. All Rights Reserved. +%% Copyright Ericsson AB 2009-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 @@ -24,6 +24,7 @@ -compile(export_all). +-include_lib("reltool/src/reltool.hrl"). -include("reltool_test_lib.hrl"). -include_lib("common_test/include/ct.hrl"). @@ -51,10 +52,43 @@ end_per_testcase(Func,Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [start_server, set_config, create_release, - create_script, create_target, create_embedded, - create_standalone, create_old_target, - otp_9135, otp_9229_exclude_app, otp_9229_exclude_mod]. + [start_server, + set_config, + get_config, + create_release, + create_release_sort, + create_script, + create_script_sort, + create_target, + create_embedded, + create_standalone, + create_standalone_beam, + create_standalone_app, + create_standalone_app_clash, + create_multiple_standalone, + create_old_target, + eval_target_spec, + otp_9135, + otp_9229_dupl_mod_exclude_app, + otp_9229_dupl_mod_exclude_mod, + dupl_mod_in_app_file, + get_apps, + get_mod, + get_sys, + set_app_and_undo, + set_apps_and_undo, + set_apps_inlined, + set_sys_and_undo, + load_config_and_undo, + load_config_fail, + load_config_escript_path, + load_config_same_escript_source, + load_config_same_escript_beam, + load_config_add_escript, + reset_config_and_undo, + gen_rel_files, + save_config, + dependencies]. groups() -> []. @@ -71,8 +105,6 @@ end_per_group(_GroupName, Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Start a server process and check that it does not crash -start_server(TestInfo) when is_atom(TestInfo) -> - reltool_test_lib:tc_info(TestInfo); start_server(_Config) -> {ok, Pid} = ?msym({ok, _}, reltool:start_server([])), Libs = lists:sort(erl_libs()), @@ -88,8 +120,6 @@ start_server(_Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Start a server process and check that it does not crash -set_config(TestInfo) when is_atom(TestInfo) -> - reltool_test_lib:tc_info(TestInfo); set_config(_Config) -> Libs = lists:sort(erl_libs()), Default = @@ -112,10 +142,90 @@ set_config(_Config) -> ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Check that get_config returns the expected derivates and defaults +%% as specified +get_config(_Config) -> + + KVsn = latest(kernel), + StdVsn = latest(stdlib), + SaslVsn = latest(sasl), + + Sys = {sys,[{incl_cond, exclude}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include},{vsn,SaslVsn}]}, + {app,stdlib,[{incl_cond,include}]}]}, + {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])), + ?m({ok, Sys}, reltool:get_config(Pid)), + ?m({ok, Sys}, reltool:get_config(Pid,false,false)), + + %% Include derived info + ?msym({ok,{sys,[{incl_cond, exclude}, + {erts,[]}, + {app,kernel,[{incl_cond,include},{mod,_,[]}|_]}, + {app,sasl,[{incl_cond,include},{vsn,SaslVsn},{mod,_,[]}|_]}, + {app,stdlib,[{incl_cond,include},{mod,_,[]}|_]}]}}, + reltool:get_config(Pid,false,true)), + + %% Include defaults + ?msym({ok,{sys,[{root_dir,_}, + {lib_dirs,_}, + {mod_cond,all}, + {incl_cond,exclude}, + {app,kernel,[{incl_cond,include},{vsn,undefined}]}, + {app,sasl,[{incl_cond,include},{vsn,SaslVsn}]}, + {app,stdlib,[{incl_cond,include},{vsn,undefined}]}, + {boot_rel,"start_clean"}, + {rel,"start_clean","1.0",[]}, + {rel,"start_sasl","1.0",[sasl]}, + {emu_name,"beam"}, + {relocatable,true}, + {profile,development}, + {incl_sys_filters,[".*"]}, + {excl_sys_filters,[]}, + {incl_app_filters,[".*"]}, + {excl_app_filters,[]}, + {incl_archive_filters,[".*"]}, + {excl_archive_filters,["^include$","^priv$"]}, + {archive_opts,[]}, + {rel_app_type,permanent}, + {app_file,keep}, + {debug_info,keep}]}}, + reltool:get_config(Pid,true,false)), + + %% Include both defaults and derived info + ?msym({ok,{sys,[{root_dir,_}, + {lib_dirs,_}, + {mod_cond,all}, + {incl_cond,exclude}, + {erts,[]}, + {app,kernel,[{incl_cond,include},{vsn,KVsn},{mod,_,[]}|_]}, + {app,sasl,[{incl_cond,include},{vsn,SaslVsn},{mod,_,[]}|_]}, + {app,stdlib,[{incl_cond,include},{vsn,StdVsn},{mod,_,[]}|_]}, + {boot_rel,"start_clean"}, + {rel,"start_clean","1.0",[]}, + {rel,"start_sasl","1.0",[sasl]}, + {emu_name,"beam"}, + {relocatable,true}, + {profile,development}, + {incl_sys_filters,[".*"]}, + {excl_sys_filters,[]}, + {incl_app_filters,[".*"]}, + {excl_app_filters,[]}, + {incl_archive_filters,[".*"]}, + {excl_archive_filters,["^include$","^priv$"]}, + {archive_opts,[]}, + {rel_app_type,permanent}, + {app_file,keep}, + {debug_info,keep}]}}, + reltool:get_config(Pid,true,true)), + + ?m(ok, reltool:stop(Pid)), + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% OTP-9135, test that app_file option can be set to all | keep | strip -otp_9135(TestInfo) when is_atom(TestInfo) -> - reltool_test_lib:tc_info(TestInfo); otp_9135(_Config) -> Libs = lists:sort(erl_libs()), StrippedDefaultSys = @@ -145,8 +255,6 @@ otp_9135(_Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Generate releases -create_release(TestInfo) when is_atom(TestInfo) -> - reltool_test_lib:tc_info(TestInfo); create_release(_Config) -> %% Configure the server RelName = "Just testing...", @@ -170,10 +278,135 @@ create_release(_Config) -> ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Generate releases and make sure order of applications specified in +%% 'rel' parameter is preserved and that included applications are +%% started before the including application. +%% Circular dependencies shall also be detected and cause error. + +create_release_sort(_Config) -> {skip, "Two bugs related to sorting"}; +create_release_sort(Config) -> + DataDir = ?config(data_dir,Config), + %% Configure the server + RelName1 = "MnesiaFirst", + RelName2 = "SaslFirst", + RelName3 = "Include-both", + RelName4 = "Include-only-app", + RelName5 = "Include-only-rel", + RelName6 = "Include-missing-app", + RelName7 = "Circular", + RelName8 = "Include-both-missing-app", + RelName9 = "Include-overwrite", + RelName10= "Uses-order-as-rel", + RelVsn = "1.0", + %% Application z (.app file): + %% includes [tools, mnesia] + %% uses [kernel, stdlib, sasl, inets] + Sys = + {sys, + [ + {lib_dirs, [filename:join(DataDir,"sort_apps")]}, + {boot_rel, RelName1}, + {rel, RelName1, RelVsn, [stdlib, kernel, mnesia, sasl]}, + {rel, RelName2, RelVsn, [stdlib, kernel, sasl, mnesia]}, + {rel, RelName3, RelVsn, [stdlib, kernel, {z,[tools]}, tools, mnesia]}, + {rel, RelName4, RelVsn, [stdlib, kernel, z, mnesia, tools]}, + {rel, RelName5, RelVsn, [stdlib, kernel, {sasl,[tools]}]}, + {rel, RelName6, RelVsn, [stdlib, kernel, z]}, + {rel, RelName7, RelVsn, [stdlib, kernel, mnesia, y, sasl, x]}, + {rel, RelName8, RelVsn, [stdlib, kernel, {z,[tools]}]}, + {rel, RelName9, RelVsn, [stdlib, kernel, {z,[]}]}, + {rel, RelName10, RelVsn, [stdlib, kernel, {z,[]}, inets, sasl]}, + {incl_cond,exclude}, + {mod_cond,app}, + {app,kernel,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,mnesia,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,inets,[{incl_cond,include}]}, + {app,x,[{incl_cond,include}]}, + {app,y,[{incl_cond,include}]}, + {app,z,[{incl_cond,include}]}, + {app,tools,[{mod_cond,app},{incl_cond,include}]} + ]}, + %% Generate release + + ?msym({ok, {release, {RelName1, RelVsn}, + {erts, _}, + [{kernel, _}, + {stdlib, _}, + {mnesia, _}, + {sasl, _}]}}, + reltool:get_rel([{config, Sys}], RelName1)), + + ?msym({ok, {release, {RelName2, RelVsn}, + {erts, _}, + [{kernel, _}, + {stdlib, _}, + {sasl, _}, + {mnesia, _}]}}, + reltool:get_rel([{config, Sys}], RelName2)), + + ?msym({ok, {release, {RelName3, RelVsn}, + {erts, _}, + [{kernel, _}, + {stdlib, _}, + {sasl, _}, + {inets, _}, + {tools, _}, + {z, _, [tools]}, + {mnesia, _}]}}, + reltool:get_rel([{config, Sys}], RelName3)), + + %%! BUG: same as OTP-4121, but for reltool???? Or revert tools and mnesia + ?msym({ok, {release, {RelName4, RelVsn}, + {erts, _}, + [{kernel, _}, + {stdlib, _}, + {sasl, _}, + {inets, _}, + {mnesia, _}, + {tools, _}, + {z, _}]}}, + reltool:get_rel([{config, Sys}], RelName4)), + + ?m({error,"sasl: These applications are used by release " + "Include-only-rel but are missing as included_applications " + "in the app file: [tools]"}, + reltool:get_rel([{config, Sys}], RelName5)), + + ?m({error, "Undefined applications: [tools,mnesia]"}, + reltool:get_rel([{config, Sys}], RelName6)), + + ?m({error,"Circular dependencies: [x,y]"}, + reltool:get_rel([{config, Sys}], RelName7)), + + ?m({error,"Undefined applications: [tools]"}, + reltool:get_rel([{config, Sys}], RelName8)), + + ?msym({ok,{release,{RelName9,RelVsn}, + {erts,_}, + [{kernel,_}, + {stdlib,_}, + {sasl, _}, + {inets, _}, + {z,_,[]}]}}, + reltool:get_rel([{config, Sys}], RelName9)), + + %%! BUG: same as OTP-9984, but for reltool???? Or revert inets and sasl? + ?msym({ok,{release,{RelName10,RelVsn}, + {erts,_}, + [{kernel,_}, + {stdlib,_}, + {inets, _}, + {sasl, _}, + {z,_,[]}]}}, + reltool:get_rel([{config, Sys}], RelName10)), + + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Generate boot scripts -create_script(TestInfo) when is_atom(TestInfo) -> - reltool_test_lib:tc_info(TestInfo); create_script(_Config) -> %% Configure the server RelName = "Just testing", @@ -218,10 +451,197 @@ create_script(_Config) -> ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Test creation of .script with different sorting of applications and +%% included applications. +%% Test that result is equal to what systools produces +create_script_sort(Config) -> + DataDir = ?config(data_dir,Config), + %% Configure the server + RelName1 = "MnesiaFirst", + RelName2 = "SaslFirst", + RelName3 = "Include-both", + RelName4 = "Include-only-app", + RelName5 = "Include-only-rel", + RelName6 = "Include-missing-app", + RelName7 = "Circular", + RelName8 = "Include-both-missing-app", + RelName9 = "Include-overwrite", + RelVsn = "1.0", + LibDir = filename:join(DataDir,"sort_apps"), + Sys = + {sys, + [ + {lib_dirs, [LibDir]}, + {boot_rel, RelName1}, + {rel, RelName1, RelVsn, [stdlib, kernel, mnesia, sasl]}, + {rel, RelName2, RelVsn, [stdlib, kernel, sasl, mnesia]}, + {rel, RelName3, RelVsn, [stdlib, kernel, {z,[tools]}, tools, mnesia]}, + {rel, RelName4, RelVsn, [stdlib, kernel, z, mnesia, tools]}, + {rel, RelName5, RelVsn, [stdlib, kernel, {sasl,[tools]}]}, + {rel, RelName6, RelVsn, [stdlib, kernel, z]}, + {rel, RelName7, RelVsn, [stdlib, kernel, mnesia, y, sasl, x]}, + {rel, RelName8, RelVsn, [stdlib, kernel, {z,[tools]}]}, + {rel, RelName9, RelVsn, [stdlib, kernel, {z,[]}]}, + {incl_cond,exclude}, + {mod_cond,app}, + {app,kernel,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,mnesia,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,inets,[{incl_cond,include}]}, + {app,x,[{incl_cond,include}]}, + {app,y,[{incl_cond,include}]}, + {app,z,[{incl_cond,include}]}, + {app,tools,[{mod_cond,app},{incl_cond,include}]} + ]}, + + {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])), + + %% Generate release files + application:load(sasl), + application:load(inets), + application:load(mnesia), + application:load(tools), + {ok,KernelVsn} = application:get_key(kernel,vsn), + {ok,StdlibVsn} = application:get_key(stdlib,vsn), + {ok,SaslVsn} = application:get_key(sasl,vsn), + {ok,InetsVsn} = application:get_key(inets,vsn), + {ok,MnesiaVsn} = application:get_key(mnesia,vsn), + {ok,ToolsVsn} = application:get_key(tools,vsn), + ErtsVsn = erlang:system_info(version), + + Rel1 = {release, {RelName1,RelVsn}, {erts,ErtsVsn}, + [{kernel,KernelVsn}, + {stdlib,StdlibVsn}, + {mnesia,MnesiaVsn}, + {sasl,SaslVsn}]}, + FullName1 = filename:join(?WORK_DIR,RelName1), + ?m(ok, file:write_file(FullName1 ++ ".rel", io_lib:format("~p.\n", [Rel1]))), + Rel2 = {release, {RelName2,RelVsn}, {erts,ErtsVsn}, + [{kernel,KernelVsn}, + {stdlib,StdlibVsn}, + {sasl,SaslVsn}, + {mnesia,MnesiaVsn}]}, + FullName2 = filename:join(?WORK_DIR,RelName2), + ?m(ok, file:write_file(FullName2 ++ ".rel", io_lib:format("~p.\n", [Rel2]))), + Rel3 = {release, {RelName3,RelVsn}, {erts,ErtsVsn}, + [{kernel,KernelVsn}, + {stdlib,StdlibVsn}, + {z,"1.0",[tools]}, + {tools,ToolsVsn}, + {mnesia,MnesiaVsn}, + {sasl,SaslVsn}, + {inets,InetsVsn}]}, + FullName3 = filename:join(?WORK_DIR,RelName3), + ?m(ok, file:write_file(FullName3 ++ ".rel", io_lib:format("~p.\n", [Rel3]))), + Rel4 = {release, {RelName4,RelVsn}, {erts,ErtsVsn}, + [{kernel,KernelVsn}, + {stdlib,StdlibVsn}, + {z,"1.0"}, + {tools,ToolsVsn}, + {mnesia,MnesiaVsn}, + {sasl,SaslVsn}, + {inets,InetsVsn}]}, + FullName4 = filename:join(?WORK_DIR,RelName4), + ?m(ok, file:write_file(FullName4 ++ ".rel", io_lib:format("~p.\n", [Rel4]))), + Rel5 = {release, {RelName5,RelVsn}, {erts,ErtsVsn}, + [{kernel,KernelVsn}, + {stdlib,StdlibVsn}, + {sasl,SaslVsn,[tools]}, + {tools,ToolsVsn}]}, + FullName5 = filename:join(?WORK_DIR,RelName5), + ?m(ok, file:write_file(FullName5 ++ ".rel", io_lib:format("~p.\n", [Rel5]))), + Rel6 = {release, {RelName6,RelVsn}, {erts,ErtsVsn}, + [{kernel,KernelVsn}, + {stdlib,StdlibVsn}, + {z,"1.0"}]}, + FullName6 = filename:join(?WORK_DIR,RelName6), + ?m(ok, file:write_file(FullName6 ++ ".rel", io_lib:format("~p.\n", [Rel6]))), + Rel7 = {release, {RelName7,RelVsn}, {erts,ErtsVsn}, + [{kernel,KernelVsn}, + {stdlib,StdlibVsn}, + {mnesia,MnesiaVsn}, + {y,"1.0"}, + {sasl,SaslVsn}, + {x,"1.0"}]}, + FullName7 = filename:join(?WORK_DIR,RelName7), + ?m(ok, file:write_file(FullName7 ++ ".rel", io_lib:format("~p.\n", [Rel7]))), + Rel8 = {release, {RelName8,RelVsn}, {erts,ErtsVsn}, + [{kernel,KernelVsn}, + {stdlib,StdlibVsn}, + {z,"1.0",[tools]}]}, + FullName8 = filename:join(?WORK_DIR,RelName8), + ?m(ok, file:write_file(FullName8 ++ ".rel", io_lib:format("~p.\n", [Rel8]))), + Rel9 = {release, {RelName9,RelVsn}, {erts,ErtsVsn}, + [{kernel,KernelVsn}, + {stdlib,StdlibVsn}, + {z,"1.0",[]}, + {sasl,SaslVsn}, + {inets,InetsVsn}]}, + FullName9 = filename:join(?WORK_DIR,RelName9), + ?m(ok, file:write_file(FullName9 ++ ".rel", io_lib:format("~p.\n", [Rel9]))), + + %% Generate script files with systools and reltool and compare + ZPath = filename:join([LibDir,"*",ebin]), + + ?msym({ok,_,_}, systools_make_script(FullName1,ZPath)), + {ok, [SystoolsScript1]} = ?msym({ok,[_]}, file:consult(FullName1++".script")), + {ok, Script1} = ?msym({ok, _}, reltool:get_script(Pid, RelName1)), + ?m(equal, diff_script(SystoolsScript1, Script1)), + + ?msym({ok,_,_}, systools_make_script(FullName2,ZPath)), + {ok, [SystoolsScript2]} = ?msym({ok,[_]}, file:consult(FullName2++".script")), + {ok, Script2} = ?msym({ok, _}, reltool:get_script(Pid, RelName2)), + ?m(equal, diff_script(SystoolsScript2, Script2)), + + ?msym({ok,_,_}, systools_make_script(FullName3,ZPath)), + {ok, [SystoolsScript3]} = ?msym({ok,[_]}, file:consult(FullName3++".script")), + {ok, Script3} = ?msym({ok, _}, reltool:get_script(Pid, RelName3)), + ?m(equal, diff_script(SystoolsScript3, Script3)), + + ?msym({ok,_,_}, systools_make_script(FullName4,ZPath)), + {ok, [SystoolsScript4]} = ?msym({ok,[_]}, file:consult(FullName4++".script")), + {ok, Script4} = ?msym({ok, _}, reltool:get_script(Pid, RelName4)), + ?m(equal, diff_script(SystoolsScript4, Script4)), + + ?msym({error,_,[{error_reading,{sasl,{override_include,_}}}]}, + systools_make_script(FullName5,ZPath)), + ?m({error,"sasl: These applications are used by release " + "Include-only-rel but are missing as included_applications " + "in the app file: [tools]"}, + reltool:get_script(Pid, RelName5)), + + ?msym({error,_,{undefined_applications,_}}, + systools_make_script(FullName6,ZPath)), + ?m({error, "Undefined applications: [tools,mnesia]"}, + reltool:get_script(Pid, RelName6)), + + ?msym({error,_,{circular_dependencies,_}}, + systools_make_script(FullName7,ZPath)), + ?m({error,"Circular dependencies: [x,y]"}, + reltool:get_script(Pid, RelName7)), + + ?msym({error,_,{undefined_applications,_}}, + systools_make_script(FullName8,ZPath)), + ?m({error, "Undefined applications: [tools]"}, + reltool:get_script(Pid, RelName8)), + + ?msym({ok,_,_}, systools_make_script(FullName9,ZPath)), + {ok, [SystoolsScript9]} = ?msym({ok,[_]}, file:consult(FullName9++".script")), + {ok, Script9} = ?msym({ok, _}, reltool:get_script(Pid, RelName9)), + ?m(equal, diff_script(SystoolsScript9, Script9)), + + %% Stop server + ?m(ok, reltool:stop(Pid)), + ok. + + +systools_make_script(Name,Path) -> + systools:make_script(Name,[{path,[Path]},{outdir,?WORK_DIR},silent]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Generate target system -create_target(TestInfo) when is_atom(TestInfo) -> - reltool_test_lib:tc_info(TestInfo); create_target(_Config) -> %% Configure the server RelName1 = "Just testing", @@ -243,7 +663,7 @@ create_target(_Config) -> ?m(ok, reltool_utils:recursive_delete(TargetDir)), ?m(ok, file:make_dir(TargetDir)), ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Config}])]), - ?m(ok, reltool:create_target([{config, Config}], TargetDir)), + ok = ?m(ok, reltool:create_target([{config, Config}], TargetDir)), Erl = filename:join([TargetDir, "bin", "erl"]), {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)), @@ -254,8 +674,6 @@ create_target(_Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Generate embedded target system -create_embedded(TestInfo) when is_atom(TestInfo) -> - reltool_test_lib:tc_info(TestInfo); create_embedded(_Config) -> %% Configure the server RelName1 = "Just testing", @@ -276,7 +694,7 @@ create_embedded(_Config) -> TargetDir = filename:join([?WORK_DIR, "target_embedded"]), ?m(ok, reltool_utils:recursive_delete(TargetDir)), ?m(ok, file:make_dir(TargetDir)), - ?m(ok, reltool:create_target([{config, Config}], TargetDir)), + ok = ?m(ok, reltool:create_target([{config, Config}], TargetDir)), Erl = filename:join([TargetDir, "bin", "erl"]), {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)), @@ -287,8 +705,6 @@ create_embedded(_Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Generate standalone system -create_standalone(TestInfo) when is_atom(TestInfo) -> - reltool_test_lib:tc_info(TestInfo); create_standalone(_Config) -> %% Configure the server ExDir = code:lib_dir(reltool, examples), @@ -306,30 +722,223 @@ create_standalone(_Config) -> TargetDir = filename:join([?WORK_DIR, "target_standalone"]), ?m(ok, reltool_utils:recursive_delete(TargetDir)), ?m(ok, file:make_dir(TargetDir)), - ?m(ok, reltool:create_target([{config, Config}], TargetDir)), + ok = ?m(ok, reltool:create_target([{config, Config}], TargetDir)), + %% Start the target system and fetch root dir BinDir = filename:join([TargetDir, "bin"]), Erl = filename:join([BinDir, "erl"]), {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)), RootDir = ?ignore(rpc:call(Node, code, root_dir, [])), ?msym(ok, stop_node(Node)), + %% Execute escript Expected = iolist_to_binary(["Root dir: ", RootDir, "\n" "Script args: [\"-arg1\",\"arg2\",\"arg3\"]\n", "Smp: false\n", "ExitCode:0"]), io:format("Expected: ~s\n", [Expected]), - ?m(Expected, run(BinDir, EscriptName ++ " -arg1 arg2 arg3")), + ?m(Expected, run(BinDir, EscriptName, "-arg1 arg2 arg3")), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Generate standalone system with inlined beam file + +create_standalone_beam(Config) -> + %% Read beam file + DataDir = ?config(data_dir,Config), + BeamFile = filename:join([DataDir,escript,"someapp-1.0",ebin,"mymod.beam"]), + {ok,BeamBin} = file:read_file(BeamFile), + + %% Create the escript + EscriptName = "mymod.escript", + Escript = filename:join(?WORK_DIR,EscriptName), + ok = escript:create(Escript,[shebang,{beam,BeamBin}]), + ok = file:change_mode(Escript,8#00744), + + %% Configure the server + Sys = + {sys, + [ + {lib_dirs, []}, + {escript, Escript, [{incl_cond, include}]}, + {profile, standalone} + ]}, + + %% Generate target file + TargetDir = filename:join([?WORK_DIR, "target_standalone_beam"]), + ?m(ok, reltool_utils:recursive_delete(TargetDir)), + ?m(ok, file:make_dir(TargetDir)), + ok = ?m(ok, reltool:create_target([{config, Sys}], TargetDir)), + + %% Start the target system and fetch root dir + BinDir = filename:join([TargetDir, "bin"]), + Erl = filename:join([BinDir, "erl"]), + {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)), + RootDir = ?ignore(rpc:call(Node, code, root_dir, [])), + ?msym(ok, stop_node(Node)), + + %% Execute escript + Expected = iolist_to_binary(["Root dir: ", RootDir, "\n" + "Script args: [\"-arg1\",\"arg2\",\"arg3\"]\n", + "ExitCode:0"]), + io:format("Expected: ~s\n", [Expected]), + ?m(Expected, run(BinDir, EscriptName, "-arg1 arg2 arg3")), + + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Generate standalone system with inlined archived application + +create_standalone_app(Config) -> + %% Create archive + DataDir = ?config(data_dir,Config), + EscriptDir = filename:join(DataDir,escript), + {ok,{_Archive,Bin}} = zip:create("someapp-1.0.ez",["someapp-1.0"], + [memory, + {cwd,EscriptDir}, + {compress,all}, + {uncompress,[".beam",".app"]}]), + + %% Create the escript + EscriptName = "someapp.escript", + Escript = filename:join(?WORK_DIR,EscriptName), + ok = escript:create(Escript,[shebang, + {emu_args,"-escript main mymod"}, + {archive,Bin}]), + ok = file:change_mode(Escript,8#00744), + + %% Configure the server + Sys = + {sys, + [ + {lib_dirs, []}, + {escript, Escript, [{incl_cond, include}]}, + {profile, standalone} + ]}, + + %% Generate target file + TargetDir = filename:join([?WORK_DIR, "target_standalone_app"]), + ?m(ok, reltool_utils:recursive_delete(TargetDir)), + ?m(ok, file:make_dir(TargetDir)), + ok = ?m(ok, reltool:create_target([{config, Sys}], TargetDir)), + + %% Start the target system and fetch root dir + BinDir = filename:join([TargetDir, "bin"]), + Erl = filename:join([BinDir, "erl"]), + {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)), + RootDir = ?ignore(rpc:call(Node, code, root_dir, [])), + ?msym(ok, stop_node(Node)), + + %% Execute escript + Expected = iolist_to_binary(["Root dir: ", RootDir, "\n" + "Script args: [\"-arg1\",\"arg2\",\"arg3\"]\n", + "ExitCode:0"]), + io:format("Expected: ~s\n", [Expected]), + ?m(Expected, run(BinDir, EscriptName, "-arg1 arg2 arg3")), + + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Generate standalone system with inlined archived application +%% Check that the inlined app can not be explicitly configured + +create_standalone_app_clash(Config) -> + %% Create archive + DataDir = ?config(data_dir,Config), + EscriptDir = filename:join(DataDir,escript), + {ok,{_Archive,Bin}} = zip:create("someapp-1.0.ez",["someapp-1.0"], + [memory, + {cwd,EscriptDir}, + {compress,all}, + {uncompress,[".beam",".app"]}]), + + %% Create the escript + EscriptName = "someapp.escript", + Escript = filename:join(?WORK_DIR,EscriptName), + ok = escript:create(Escript,[shebang, + {emu_args,"-escript main mymod"}, + {archive,Bin}]), + ok = file:change_mode(Escript,8#00744), + + %% Configure the server + Sys = + {sys, + [ + {lib_dirs, []}, + {escript, Escript, [{incl_cond, include}]}, + {profile, standalone}, + {app, someapp, [{incl_cond,include}]} + ]}, + + ?msym({error,"someapp: Application name clash. Escript "++_}, + reltool:start_server([{config,Sys}])), + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Generate standalone system with multiple escripts + +create_multiple_standalone(Config) -> + %% First escript + ExDir = code:lib_dir(reltool, examples), + EscriptName1 = "display_args", + Escript1 = filename:join([ExDir, EscriptName1]), + + %% Second escript + DataDir = ?config(data_dir,Config), + BeamFile = filename:join([DataDir,escript,"someapp-1.0",ebin,"mymod.beam"]), + {ok,BeamBin} = file:read_file(BeamFile), + EscriptName2 = "mymod.escript", + Escript2 = filename:join(?WORK_DIR,EscriptName2), + ok = escript:create(Escript2,[shebang,{beam,BeamBin}]), + ok = file:change_mode(Escript2,8#00744), + + %% Configure server + Sys = + {sys, + [ + {lib_dirs, []}, + {escript, Escript1, [{incl_cond, include}]}, + {escript, Escript2, [{incl_cond, include}]}, + {profile, standalone} + ]}, + + %% Generate target system + TargetDir = filename:join([?WORK_DIR, "target_multiple_standalone"]), + ?m(ok, reltool_utils:recursive_delete(TargetDir)), + ?m(ok, file:make_dir(TargetDir)), + ok = ?m(ok, reltool:create_target([{config,Sys}], TargetDir)), + + %% Start the target system and fetch root dir + BinDir = filename:join([TargetDir, "bin"]), + Erl = filename:join([BinDir, "erl"]), + {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)), + RootDir = ?ignore(rpc:call(Node, code, root_dir, [])), + ?msym(ok, stop_node(Node)), + + %% Execute escript1 + Expected1 = iolist_to_binary(["Root dir: ", RootDir, "\n" + "Script args: [\"-arg1\",\"arg2\",\"arg3\"]\n", + "Smp: false\n", + "ExitCode:0"]), + io:format("Expected1: ~s\n", [Expected1]), + ?m(Expected1, run(BinDir, EscriptName1, "-arg1 arg2 arg3")), + + + %% Execute escript2 + Expected2 = iolist_to_binary(["Root dir: ", RootDir, "\n" + "Script args: [\"-arg1\",\"arg2\",\"arg3\"]\n", + "ExitCode:0"]), + io:format("Expected2: ~s\n", [Expected2]), + ?m(Expected2, run(BinDir, EscriptName2, "-arg1 arg2 arg3")), + + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Generate old type of target system -create_old_target(TestInfo) when is_atom(TestInfo) -> - reltool_test_lib:tc_info(TestInfo); +create_old_target(_Config) -> {skip, "Old style of target"}; create_old_target(_Config) -> - ?skip("Old style of target", []), %% Configure the server RelName1 = "Just testing", @@ -350,10 +959,10 @@ create_old_target(_Config) -> TargetDir = filename:join([?WORK_DIR, "target_old_style"]), ?m(ok, reltool_utils:recursive_delete(TargetDir)), ?m(ok, file:make_dir(TargetDir)), - ?m(ok, reltool:create_target([{config, Config}], TargetDir)), + ok = ?m(ok, reltool:create_target([{config, Config}], TargetDir)), %% io:format("Will fail on Windows (should patch erl.ini)\n", []), - ?m(ok, reltool:install(RelName2, TargetDir)), + ok = ?m(ok, reltool:install(RelName2, TargetDir)), Erl = filename:join([TargetDir, "bin", "erl"]), {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)), @@ -362,11 +971,43 @@ create_old_target(_Config) -> ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Generate target system with eval_target_spec/3 + +eval_target_spec(_Config) -> + %% Configure the server + RelName1 = "Just testing", + RelName2 = "Just testing with SASL", + RelVsn = "1.0", + Config = + {sys, + [ + {root_dir, code:root_dir()}, + {lib_dirs, []}, + {boot_rel, RelName2}, + {rel, RelName1, RelVsn, [stdlib, kernel]}, + {rel, RelName2, RelVsn, [sasl, stdlib, kernel]}, + {app, sasl, [{incl_cond, include}]} + ]}, + + %% Generate target file + TargetDir = filename:join([?WORK_DIR, "eval_target_spec"]), + ?m(ok, reltool_utils:recursive_delete(TargetDir)), + ?m(ok, file:make_dir(TargetDir)), + {ok, Spec} = ?msym({ok,_}, reltool:get_target_spec([{config, Config}])), + ok = ?m(ok, reltool:eval_target_spec(Spec, code:root_dir(), TargetDir)), + + Erl = filename:join([TargetDir, "bin", "erl"]), + {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)), + ?msym(ok, stop_node(Node)), + + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% OTP-9229 - handle duplicated module names, i.e. same module name %% exists in two applications. %% Include on app, exclude the other -otp_9229_exclude_app(Config) -> +otp_9229_dupl_mod_exclude_app(Config) -> DataDir = ?config(data_dir,Config), LibDir = filename:join(DataDir,"otp_9229"), @@ -389,8 +1030,8 @@ otp_9229_exclude_app(Config) -> ?m(ok, reltool_utils:recursive_delete(TargetDir)), ?m(ok, file:make_dir(TargetDir)), ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, ExclApp}])]), - {ok,["Module mylib exists in applications x and y. Using module from application x."]} = reltool:get_status([{config, ExclApp}]), - ?m(ok, reltool:create_target([{config, ExclApp}], TargetDir)), + ?m({ok,["Module mylib exists in applications x and y. Using module from application x."]}, reltool:get_status([{config, ExclApp}])), + ok = ?m(ok, reltool:create_target([{config, ExclApp}], TargetDir)), Erl = filename:join([TargetDir, "bin", "erl"]), {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)), @@ -413,7 +1054,7 @@ otp_9229_exclude_app(Config) -> ok. %% Include both apps, but exclude common module from one app -otp_9229_exclude_mod(Config) -> +otp_9229_dupl_mod_exclude_mod(Config) -> DataDir = ?config(data_dir,Config), LibDir = filename:join(DataDir,"otp_9229"), @@ -436,8 +1077,8 @@ otp_9229_exclude_mod(Config) -> ?m(ok, reltool_utils:recursive_delete(TargetDir)), ?m(ok, file:make_dir(TargetDir)), ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, ExclMod}])]), - {ok,["Module mylib exists in applications x and y. Using module from application x."]} = reltool:get_status([{config, ExclMod}]), - ?m(ok, reltool:create_target([{config, ExclMod}], TargetDir)), + ?m({ok,["Module mylib exists in applications x and y. Using module from application x."]}, reltool:get_status([{config, ExclMod}])), + ok = ?m(ok, reltool:create_target([{config, ExclMod}], TargetDir)), Erl = filename:join([TargetDir, "bin", "erl"]), {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)), @@ -466,7 +1107,892 @@ otp_9229_exclude_mod(Config) -> ok. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Test that if a module is duplicated in a .app file, then a warning +%% is produced, but target can still be created. +dupl_mod_in_app_file(Config) -> + DataDir = ?config(data_dir,Config), + LibDir = filename:join(DataDir,"dupl_mod"), + + %% Configure the server + Sys = + {sys, + [ + {lib_dirs, [LibDir]}, + {incl_cond,exclude}, + {app,a,[{incl_cond,include}]}, + {app,kernel,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]} + ]}, + + %% Generate target file + TargetDir = filename:join([?WORK_DIR, "target_dupl_mod_in_app_file"]), + ?m(ok, reltool_utils:recursive_delete(TargetDir)), + ?m(ok, file:make_dir(TargetDir)), + ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Sys}])]), + ?m({ok,["Module a duplicated in app file for application a."]}, + reltool:get_status([{config, Sys}])), + + %%! test that only one module installed (in spec) + + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Test the interface used by the GUI: +%% get_app +%% get_apps +%% set_app +%% set_apps +%% load_config +%% reset_config +%% +%% Also, for each operation which manipulates the config, test +%% get_status and undo_config. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +get_apps(_Config) -> + Sys = {sys,[{app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,tools,[{incl_cond,derived}]}, + {app,runtime_tools,[{incl_cond,exclude}]}]}, + {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])), + + {ok,Sasl} = ?msym({ok,#app{name=sasl}}, reltool_server:get_app(Pid,sasl)), + {ok,[#app{name=kernel}, + #app{name=sasl}=Sasl, + #app{name=stdlib}] = White} = + ?msym({ok,_}, reltool_server:get_apps(Pid,whitelist)), + {ok,[#app{name=runtime_tools}] = Black} = + ?msym({ok,_}, reltool_server:get_apps(Pid,blacklist)), + + {ok,Derived} = ?msym({ok,_}, reltool_server:get_apps(Pid,derived)), + true = lists:keymember(tools,#app.name,Derived), + + {ok,Source} = ?msym({ok,_}, reltool_server:get_apps(Pid,source)), + true = lists:keymember(common_test,#app.name,Source), + + %% Check that the four lists are disjoint + Number = length(White) + length(Black) + length(Derived) + length(Source), + WN = lists:usort([N || #app{name=N} <- White]), + BN = lists:usort([N || #app{name=N} <- Black]), + DN = lists:usort([N || #app{name=N} <- Derived]), + SN = lists:usort([N || #app{name=N} <- Source]), + AllN = lists:umerge([WN,BN,DN,SN]), + ?m(Number,length(AllN)), + + ?m(ok, reltool:stop(Pid)), + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +get_mod(_Config) -> + Sys = {sys,[{app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,tools,[{incl_cond,derived}]}, + {app,runtime_tools,[{incl_cond,exclude}]}]}, + {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])), + + %% Read app and get a module from the #app record + {ok,Tools} = ?msym({ok,#app{name=tools}}, reltool_server:get_app(Pid,tools)), + Cover = lists:keyfind(cover,#mod.name,Tools#app.mods), + + %% get_mod - and check that it is equal to the one in #app.mods + ?m({ok,Cover}, reltool_server:get_mod(Pid,cover)), + + ?m(ok, reltool:stop(Pid)), + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +get_sys(_Config) -> + Sys = {sys,[{app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,tools,[{incl_cond,derived}]}, + {app,runtime_tools,[{incl_cond,exclude}]}]}, + {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])), + + RootDir = code:root_dir(), + ?msym({ok,#sys{root_dir=RootDir,apps=undefined}},reltool_server:get_sys(Pid)), + + ?m(ok, reltool:stop(Pid)), + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +set_app_and_undo(Config) -> + Sys = {sys,[{lib_dirs,[filename:join(datadir(Config),"faulty_app_file")]}, + {incl_cond, exclude}, + {app,a,[{incl_cond,include}]}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,tools,[{incl_cond,include}]}]}, + {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])), + ?m({ok, Sys}, reltool:get_config(Pid)), + ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)), + + %% Get app and mod + {ok,Tools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)), + {ok,Cover} = ?msym({ok,#mod{name=cover, is_included=true}}, + reltool_server:get_mod(Pid,cover)), + + %% Exclude one module with set_app + ExclCover = Cover#mod{incl_cond=exclude}, + Mods = Tools#app.mods, + Tools1 = Tools#app{mods = lists:keyreplace(cover,#mod.name,Mods,ExclCover)}, + {ok,ToolsNoCover,["a: Cannot parse app file"++_|_]} = + ?msym({ok,_,["a: Cannot parse app file"++_|_]}, + reltool_server:set_app(Pid,Tools1)), + ?msym({ok,["a: Cannot parse app file"++_]}, reltool_server:get_status(Pid)), + + %% Check that the module is no longer included + ?m({ok,ToolsNoCover}, reltool_server:get_app(Pid,tools)), + {ok,NoIncludeCover} = ?msym({ok,#mod{name=cover, is_included=false}}, + reltool_server:get_mod(Pid,cover)), + + %% Undo + ?m(ok, reltool_server:undo_config(Pid)), + ?m({ok,Tools}, reltool_server:get_app(Pid,tools)), + ?m({ok,Cover}, reltool_server:get_mod(Pid,cover)), + ?msym({ok,["a: Cannot parse app file"++_]}, reltool_server:get_status(Pid)), + + %% Undo again, to check that it toggles + ?msym(ok, reltool_server:undo_config(Pid)), + ?m({ok,ToolsNoCover}, reltool_server:get_app(Pid,tools)), + ?m({ok,NoIncludeCover}, reltool_server:get_mod(Pid,cover)), + ?msym({ok,["a: Cannot parse app file"++_]}, reltool_server:get_status(Pid)), + + ?m(ok, reltool:stop(Pid)), + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +set_apps_and_undo(Config) -> + Sys = {sys,[{lib_dirs,[filename:join(datadir(Config),"faulty_app_file")]}, + {incl_cond, exclude}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,tools,[{incl_cond,include}]}]}, + {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])), + ?m({ok, Sys}, reltool:get_config(Pid)), + ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)), + + %% Get app and mod + {ok,Tools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)), + ?m(true, Tools#app.is_pre_included), + ?m(true, Tools#app.is_included), + {ok,Cover} = ?msym({ok,#mod{name=cover, is_included=true}}, + reltool_server:get_mod(Pid,cover)), + + %% Exclude one application with set_apps + ExclTools = Tools#app{incl_cond=exclude}, + ?msym({ok,["a: Cannot parse app file"++_]}, + reltool_server:set_apps(Pid,[ExclTools])), + ?msym({ok,["a: Cannot parse app file"++_]}, reltool_server:get_status(Pid)), + + %% Check that the app and its modules (one of them) are no longer included + {ok,NoTools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)), + ?m(false, NoTools#app.is_pre_included), + ?m(false, NoTools#app.is_included), + {ok,NoIncludeCover} = ?msym({ok,#mod{name=cover, is_included=false}}, + reltool_server:get_mod(Pid,cover)), + + %% Undo + ?m(ok, reltool_server:undo_config(Pid)), + ?m({ok,Tools}, reltool_server:get_app(Pid,tools)), + ?m({ok,Cover}, reltool_server:get_mod(Pid,cover)), + ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)), + + %% Undo again, to check that it toggles + ?m(ok, reltool_server:undo_config(Pid)), + ?m({ok,NoTools}, reltool_server:get_app(Pid,tools)), + ?m({ok,NoIncludeCover}, reltool_server:get_mod(Pid,cover)), + ?msym({ok,["a: Cannot parse app file"++_]}, reltool_server:get_status(Pid)), + + ?m(ok, reltool:stop(Pid)), + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Test that escript can be configured, but not its inlined applications +set_apps_inlined(Config) -> + %% Create archive + DataDir = ?config(data_dir,Config), + EscriptDir = filename:join(DataDir,escript), + {ok,{_Archive,Bin}} = zip:create("someapp-1.0.ez",["someapp-1.0"], + [memory, + {cwd,EscriptDir}, + {compress,all}, + {uncompress,[".beam",".app"]}]), + + %% Create the escript + EscriptName = "someapp.escript", + Escript = filename:join(?WORK_DIR,EscriptName), + ok = escript:create(Escript,[shebang, + {emu_args,"-escript main mymod"}, + {archive,Bin}]), + ok = file:change_mode(Escript,8#00744), + + %% Configure the server + Sys = {sys,[{incl_cond, exclude}, + {escript,Escript,[]}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}]}, + {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])), + ?msym({ok,[]},reltool_server:get_status(Pid)), + + %% Get app and mod + {ok,EApp} = ?msym({ok,_}, reltool_server:get_app(Pid,'*escript* someapp')), + {ok,Someapp} = ?msym({ok,_}, reltool_server:get_app(Pid,someapp)), + ?m(undefined, EApp#app.incl_cond), + ?m(undefined, Someapp#app.incl_cond), + ?m(false, Someapp#app.is_included), + ?m(false, Someapp#app.is_pre_included), + + %% Include escript + EApp1 = EApp#app{incl_cond=include}, + ?m({ok,[]}, reltool_server:set_apps(Pid,[EApp1])), + ExpectedEApp = EApp1#app{is_included=true,is_pre_included=true}, + ?m({ok,ExpectedEApp}, reltool_server:get_app(Pid,'*escript* someapp')), + {ok,Someapp1} = ?msym({ok,_}, reltool_server:get_app(Pid,someapp)), + ?m(include, Someapp1#app.incl_cond), + ?m(true, Someapp1#app.is_included), + ?m(true, Someapp1#app.is_pre_included), + + %% Check that inlined app can not be configured + Someapp2 = Someapp1#app{incl_cond=exclude}, + ?msym({error, + "Application someapp is inlined in '*escript* someapp'. " + "Can not change configuration for an inlined application."}, + reltool_server:set_apps(Pid,[Someapp2])), + ?m({ok,Someapp1}, reltool_server:get_app(Pid,someapp)), + + %% Exclude escript + {ok,EApp2} = ?msym({ok,_}, reltool_server:get_app(Pid,'*escript* someapp')), + EApp3 = EApp2#app{incl_cond=exclude}, + ?m({ok,[]}, reltool_server:set_apps(Pid,[EApp3])), + ExpectedEApp3 = EApp3#app{is_included=false,is_pre_included=false}, + ?m({ok,ExpectedEApp3}, reltool_server:get_app(Pid,'*escript* someapp')), + {ok,Someapp3} = ?msym({ok,_}, reltool_server:get_app(Pid,someapp)), + ?m(exclude, Someapp3#app.incl_cond), + ?m(false, Someapp3#app.is_included), + ?m(false, Someapp3#app.is_pre_included), + + ?m(ok, reltool:stop(Pid)), + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +set_sys_and_undo(Config) -> + Sys1 = {sys,[{incl_cond, exclude}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,tools,[{incl_cond,include}]}]}, + {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])), + ?m({ok,[]}, reltool_server:get_status(Pid)), + + %% Read sys record + {ok, SysRec} = reltool_server:get_sys(Pid), + + %% Set lib dirs by call to set_sys + NewLib = filename:join(datadir(Config),"faulty_app_file"), + NewLibDirs = [NewLib | SysRec#sys.lib_dirs], + NewSysRec = SysRec#sys{lib_dirs=NewLibDirs}, + ?msym({ok,["a: Cannot parse app file"++_]}, + reltool_server:set_sys(Pid, NewSysRec)), + ?m({ok,NewSysRec}, reltool_server:get_sys(Pid)), + ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)), + + %% Undo + ?m(ok, reltool_server:undo_config(Pid)), + ?m({ok,SysRec}, reltool_server:get_sys(Pid)), + ?m({ok,[]}, reltool_server:get_status(Pid)), + + %% Undo again, to check that it toggles + ?m(ok,reltool_server:undo_config(Pid)), + ?m({ok,NewSysRec}, reltool_server:get_sys(Pid)), + ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)), + + ?m(ok, reltool:stop(Pid)), + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +load_config_and_undo(Config) -> + Sys1 = {sys,[{incl_cond, exclude}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,tools,[{incl_cond,include}]}]}, + {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])), + ?m({ok, Sys1}, reltool:get_config(Pid)), + ?m({ok,[]}, reltool_server:get_status(Pid)), + + %% Get app and mod + {ok,Tools1} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)), + ?m(true, Tools1#app.is_pre_included), + ?m(true, Tools1#app.is_included), + {ok,Cover1} = ?msym({ok,#mod{name=cover, + is_included=true, + is_pre_included=true}}, + reltool_server:get_mod(Pid,cover)), + + %% Change tools from include to derived by loading new config + Sys2 = {sys,[{lib_dirs,[filename:join(datadir(Config),"faulty_app_file")]}, + {app,a,[{incl_cond,include}]}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,tools,[{incl_cond,derived}]}]}, + ?msym({ok,["a: Cannot parse app file"++_]}, + reltool_server:load_config(Pid,Sys2)), +%%% OTP-0702, 15) ?m({ok, Sys2}, reltool:get_config(Pid)), +%%% Note that {incl_cond,exclude} is removed compared to Sys1 - +%%% config is merged, not overwritten - is this correct??? + ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)), + + %% Check that tools is included (since it is used by sasl) but not + %% pre-included (neither included or excluded => undefined) + {ok,Tools2} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)), + ?m(undefined, Tools2#app.is_pre_included), + ?m(true, Tools2#app.is_included), + {ok,Cover2} = ?msym({ok,#mod{name=cover, + is_included=true, + is_pre_included=undefined}}, + reltool_server:get_mod(Pid,cover)), + + %% Undo + ?m(ok, reltool_server:undo_config(Pid)), + ?m({ok,Tools1}, reltool_server:get_app(Pid,tools)), + ?m({ok,Cover1}, reltool_server:get_mod(Pid,cover)), + ?m({ok,[]}, reltool_server:get_status(Pid)), + + %% Undo again, to check that it toggles + ?m(ok, reltool_server:undo_config(Pid)), + ?m({ok,Tools2}, reltool_server:get_app(Pid,tools)), + ?m({ok,Cover2}, reltool_server:get_mod(Pid,cover)), + ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)), + + ?m(ok, reltool:stop(Pid)), + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Test that load_config is properly rolled back if it fails +load_config_fail(_Config) -> + Sys1 = {sys,[{incl_cond, exclude}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,tools,[{incl_cond,include}]}]}, + {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])), + ?m({ok, Sys1}, reltool:get_config(Pid)), + ?m({ok,[]}, reltool_server:get_status(Pid)), + + %% Get app and mod + {ok,Tools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)), + + %% Try to load a config with a faulty rel statement (includes a + %% non-existing application) + Sys2 = {sys,[{incl_cond, exclude}, + {boot_rel, "faulty_rel"}, + {rel, "faulty_rel", "1.0", [kernel, sasl, stdlib, xxx]}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}]}, + ?msym({error,"Release \"faulty_rel\" uses non existing application xxx"}, + reltool_server:load_config(Pid,Sys2)), + + %% Check that a rollback is done to the old configuration + ?m({ok, Sys1}, reltool:get_config(Pid,false,false)), + + %% and that tools is not changed (i.e. that the new configuration + %% is not applied) + ?m({ok,Tools}, reltool_server:get_app(Pid,tools)), + + ?m(ok, reltool:stop(Pid)), + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Load config with escript + +load_config_escript_path(Config) -> + %% Create escript + DataDir = ?config(data_dir,Config), + BeamFile = filename:join([DataDir,escript,"someapp-1.0",ebin,"mymod.beam"]), + {ok,BeamBin} = file:read_file(BeamFile), + EscriptName = "mymod.escript", + Escript = filename:join(?WORK_DIR,EscriptName), + ok = escript:create(Escript,[shebang,{beam,BeamBin}]), + ok = file:change_mode(Escript,8#00744), + + %% Start reltool_server with one escript in configuration + EscriptSys = + {sys, + [ + {lib_dirs, []}, + {escript, Escript, [{incl_cond, include}]}, + {profile, standalone} + ]}, + + {ok, Pid1} = ?msym({ok, _}, reltool:start_server([{config, EscriptSys}])), + {ok,[#app{name='*escript* mymod'}=A]} = + ?msym({ok,[_]}, reltool_server:get_apps(Pid1,whitelist)), + ?m(ok, reltool:stop(Pid1)), + + + %% Do same again, but now start reltool first with simple config, + %% then add escript by loading new configuration and check that + %% #app is the same + SimpleSys = + {sys, + [ + {lib_dirs, []} + ]}, + {ok, Pid2} = ?msym({ok, _}, reltool:start_server([{config, SimpleSys}])), + ?m({ok,[]}, reltool_server:get_apps(Pid2,whitelist)), + ?m({ok,[]}, reltool_server:load_config(Pid2,EscriptSys)), + ?m({ok,[A]}, reltool_server:get_apps(Pid2,whitelist)), + + ?m(ok, reltool:stop(Pid2)), + + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Load config with same (source) escript twice and check that the +%% application information is not changed. + +load_config_same_escript_source(_Config) -> + %% Create escript + ExDir = code:lib_dir(reltool, examples), + EscriptName = "display_args", + Escript = filename:join([ExDir, EscriptName]), + + %% Start reltool_server with one escript in configuration + Sys = + {sys, + [ + {lib_dirs, []}, + {escript, Escript, [{incl_cond, include}]}, + {profile, standalone} + ]}, + + {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])), +% {ok,[#app{name='*escript* display_args'}]} = + ?msym({ok,[#app{name='*escript* display_args',mods=[_]}]}, + reltool_server:get_apps(Pid,whitelist)), + + %% Load the same config again, then check that app is not changed + ?m({ok,[]}, reltool_server:load_config(Pid,Sys)), + ?msym({ok,[#app{name='*escript* display_args',mods=[_]}]}, + reltool_server:get_apps(Pid,whitelist)), + + ?m(ok, reltool:stop(Pid)), + + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Load config with same (beam) escript twice and check that the +%% application information is not changed. + +load_config_same_escript_beam(Config) -> + %% Create escript + DataDir = ?config(data_dir,Config), + BeamFile = filename:join([DataDir,escript,"someapp-1.0",ebin,"mymod.beam"]), + {ok,BeamBin} = file:read_file(BeamFile), + EscriptName = "mymod.escript", + Escript = filename:join(?WORK_DIR,EscriptName), + ok = escript:create(Escript,[shebang,{beam,BeamBin}]), + ok = file:change_mode(Escript,8#00744), + + %% Start reltool_server with one escript in configuration + Sys = + {sys, + [ + {lib_dirs, []}, + {escript, Escript, [{incl_cond, include}]}, + {profile, standalone} + ]}, + + {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])), + {ok,[#app{name='*escript* mymod'}=A]} = + ?msym({ok,[_]}, reltool_server:get_apps(Pid,whitelist)), + + %% Load the same config again, then check that app is not changed + ?m({ok,[]}, reltool_server:load_config(Pid,Sys)), + ?m({ok,[A]}, reltool_server:get_apps(Pid,whitelist)), + + ?m(ok, reltool:stop(Pid)), + + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Load config with escript + +load_config_add_escript(Config) -> + %% First escript + ExDir = code:lib_dir(reltool, examples), + EscriptName1 = "display_args", + Escript1 = filename:join([ExDir, EscriptName1]), + + %% Second escript + DataDir = ?config(data_dir,Config), + BeamFile = filename:join([DataDir,escript,"someapp-1.0",ebin,"mymod.beam"]), + {ok,BeamBin} = file:read_file(BeamFile), + EscriptName2 = "mymod.escript", + Escript2 = filename:join(?WORK_DIR,EscriptName2), + ok = escript:create(Escript2,[shebang,{beam,BeamBin}]), + ok = file:change_mode(Escript2,8#00744), + + %% Start reltool_server with one escript in configuration + Sys1 = + {sys, + [ + {lib_dirs, []}, + {escript, Escript2, [{incl_cond, include}]}, + {profile, standalone} + ]}, + + {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])), + + %% Add second escript by loading new configuration + Sys2 = + {sys, + [ + {lib_dirs, []}, + {escript, Escript1, [{incl_cond, include}]}, + {escript, Escript2, [{incl_cond, include}]}, + {profile, standalone} + ]}, + + {ok,[]} = ?m({ok,[]}, reltool_server:load_config(Pid,Sys2)), + {ok,[#app{name='*escript* display_args'}, + #app{name='*escript* mymod'}]} = + ?msym({ok,[_,_]}, reltool_server:get_apps(Pid,whitelist)), + + ?m(ok, reltool:stop(Pid)), + + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +reset_config_and_undo(Config) -> + Sys1 = {sys,[{lib_dirs,[filename:join(datadir(Config),"faulty_app_file")]}, + {incl_cond, exclude}, + {app,a,[{incl_cond,include}]}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,tools,[{incl_cond,include}]}]}, + {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])), + ?m({ok, Sys1}, reltool:get_config(Pid)), + ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)), + + %% Get app and mod + {ok,Tools1} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)), + ?m(true, Tools1#app.is_pre_included), + ?m(true, Tools1#app.is_included), + {ok,Cover1} = ?msym({ok,#mod{name=cover, + is_included=true, + is_pre_included=true}}, + reltool_server:get_mod(Pid,cover)), + + %% Exclude tools by loading new config + Sys2 = {sys,[{incl_cond, exclude}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,tools,[{incl_cond,exclude}]}]}, + ?m({ok,[]}, reltool_server:load_config(Pid,Sys2)), + ?m({ok,[]}, reltool_server:get_status(Pid)), + + %% Check that tools is excluded + {ok,Tools2} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)), + ?m(false, Tools2#app.is_pre_included), + ?m(false, Tools2#app.is_included), + {ok,Cover2} = ?msym({ok,#mod{name=cover, + is_included=false, + is_pre_included=false}}, + reltool_server:get_mod(Pid,cover)), + + %% Reset + ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:reset_config(Pid)), + ?m({ok,Tools1}, reltool_server:get_app(Pid,tools)), + ?m({ok,Cover1}, reltool_server:get_mod(Pid,cover)), + ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)), + + %% Undo + ?m(ok, reltool_server:undo_config(Pid)), + ?m({ok,Tools2}, reltool_server:get_app(Pid,tools)), + ?m({ok,Cover2}, reltool_server:get_mod(Pid,cover)), + ?m({ok,[]}, reltool_server:get_status(Pid)), + + %% Undo again, to check that it toggles + ?m(ok, reltool_server:undo_config(Pid)), + ?m({ok,Tools1}, reltool_server:get_app(Pid,tools)), + ?m({ok,Cover1}, reltool_server:get_mod(Pid,cover)), + ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)), + + ?m(ok, reltool:stop(Pid)), + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +gen_rel_files(_Config) -> + %% Configure the server + RelName = "gen_fel_files_test", + RelVsn = "1.0", + Sys = + {sys, + [ + {lib_dirs, []}, + {boot_rel, RelName}, + {rel, RelName, RelVsn, [kernel, stdlib]} + ]}, + {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])), + + %% Generate .rel, .script and .boot + Dir = filename:join(?WORK_DIR,"gen_rel_files"), + ok = file:make_dir(Dir), + ?m({ok,[]}, reltool_server:gen_rel_files(Pid,Dir)), + + Script = RelName ++ ".script", + Rel = RelName ++ ".rel", + Boot = RelName ++ ".boot", + {ok,Files} = ?msym({ok,_}, file:list_dir(Dir)), + [Boot,Rel,Script] = lists:sort(Files), + + %% Check that contents is reasonable + {ok,[S]} = ?msym({ok,[{script,_,_}]},file:consult(filename:join(Dir,Script))), + ?msym({ok,[{release,_,_,_}]}, file:consult(filename:join(Dir,Rel))), + {ok,Bin} = ?msym({ok,_}, file:read_file(filename:join(Dir,Boot))), + ?m(S,binary_to_term(Bin)), + + ?m(ok, reltool:stop(Pid)), + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +save_config(Config) -> + PrivDir = ?config(priv_dir,Config), + Sys = {sys,[{incl_cond, exclude}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}]}, + {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])), + ?m({ok, Sys}, reltool:get_config(Pid)), + + Simple = filename:join(PrivDir,"save_simple.reltool"), + ?m(ok, reltool_server:save_config(Pid,Simple,false,false)), + ?m({ok,[Sys]}, file:consult(Simple)), + + Derivates = filename:join(PrivDir,"save_derivates.reltool"), + ?m(ok, reltool_server:save_config(Pid,Derivates,false,true)), + ?msym({ok,[{sys,[{incl_cond, exclude}, + {erts,[]}, + {app,kernel,[{incl_cond,include},{mod,_,[]}|_]}, + {app,sasl,[{incl_cond,include},{mod,_,[]}|_]}, + {app,stdlib,[{incl_cond,include},{mod,_,[]}|_]}]}]}, + file:consult(Derivates)), + + Defaults = filename:join(PrivDir,"save_defaults.reltool"), + ?m(ok, reltool_server:save_config(Pid,Defaults,true,false)), + ?msym({ok,[{sys,[{root_dir,_}, + {lib_dirs,_}, + {mod_cond,all}, + {incl_cond,exclude}, + {app,kernel,[{incl_cond,include},{vsn,undefined}]}, + {app,sasl,[{incl_cond,include},{vsn,undefined}]}, + {app,stdlib,[{incl_cond,include},{vsn,undefined}]}, + {boot_rel,"start_clean"}, + {rel,"start_clean","1.0",[]}, + {rel,"start_sasl","1.0",[sasl]}, + {emu_name,"beam"}, + {relocatable,true}, + {profile,development}, + {incl_sys_filters,[".*"]}, + {excl_sys_filters,[]}, + {incl_app_filters,[".*"]}, + {excl_app_filters,[]}, + {incl_archive_filters,[".*"]}, + {excl_archive_filters,["^include$","^priv$"]}, + {archive_opts,[]}, + {rel_app_type,permanent}, + {app_file,keep}, + {debug_info,keep}]}]}, + file:consult(Defaults)), + + KVsn = latest(kernel), + StdVsn = latest(stdlib), + + All = filename:join(PrivDir,"save_all.reltool"), + ?m(ok, reltool_server:save_config(Pid,All,true,true)), + ?msym({ok,[{sys,[{root_dir,_}, + {lib_dirs,_}, + {mod_cond,all}, + {incl_cond,exclude}, + {erts,[]}, + {app,kernel,[{incl_cond,include},{vsn,KVsn},{mod,_,[]}|_]}, + {app,sasl,[{incl_cond,include},{vsn,_},{mod,_,[]}|_]}, + {app,stdlib,[{incl_cond,include},{vsn,StdVsn},{mod,_,[]}|_]}, + {boot_rel,"start_clean"}, + {rel,"start_clean","1.0",[]}, + {rel,"start_sasl","1.0",[sasl]}, + {emu_name,"beam"}, + {relocatable,true}, + {profile,development}, + {incl_sys_filters,[".*"]}, + {excl_sys_filters,[]}, + {incl_app_filters,[".*"]}, + {excl_app_filters,[]}, + {incl_archive_filters,[".*"]}, + {excl_archive_filters,["^include$","^priv$"]}, + {archive_opts,[]}, + {rel_app_type,permanent}, + {app_file,keep}, + {debug_info,keep}]}]}, + file:consult(All)), + + ?m(ok, reltool:stop(Pid)), + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Test calculation of dependencies +%% The following test applications are used +%% +%% x-1.0: x1.erl x2.erl x3.erl +%% \ / (x2 calls y1, x3 calls y2) +%% y-1.0: y1.erl y2.erl +%% \ (y1 calls z1) +%% z-1.0 z1.erl +%% +%% Test includes x and derives y and z. +%% +dependencies(Config) -> + %% Default: all modules included => y and z are included (derived) + Sys = {sys,[{lib_dirs,[filename:join(datadir(Config),"dependencies")]}, + {incl_cond, exclude}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,x,[{incl_cond,include}]}, + {app,y,[{incl_cond,derived}]}, + {app,z,[{incl_cond,derived}]}]}, + {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])), + + ?msym({ok,[#app{name=kernel}, + #app{name=sasl}, + #app{name=stdlib}, + #app{name=x,uses_apps=[y]}]}, + reltool_server:get_apps(Pid,whitelist)), + {ok, Der} = ?msym({ok,_}, + reltool_server:get_apps(Pid,derived)), + ?msym([#app{name=y,uses_apps=[z]}, + #app{name=z}], + rm_missing_app(Der)), + ?msym({ok,[]}, + reltool_server:get_apps(Pid,source)), + + %% Excluding x2 => y still included since y2 is used by x3 + %% z still included since z1 is used by y1 + Sys2 = {sys,[{lib_dirs,[filename:join(datadir(Config),"dependencies")]}, + {incl_cond, exclude}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,x,[{incl_cond,include},{mod,x2,[{incl_cond,exclude}]}]}, + {app,y,[{incl_cond,derived}]}, + {app,z,[{incl_cond,derived}]}]}, + ?m({ok,[]}, reltool_server:load_config(Pid,Sys2)), + ?msym({ok,[#app{name=kernel}, + #app{name=sasl}, + #app{name=stdlib}, + #app{name=x,uses_apps=[y]}]}, + reltool_server:get_apps(Pid,whitelist)), + {ok, Der2} = ?msym({ok,_}, + reltool_server:get_apps(Pid,derived)), + ?msym([#app{name=y,uses_apps=[z]}, + #app{name=z}], + rm_missing_app(Der2)), + ?msym({ok,[]}, + reltool_server:get_apps(Pid,source)), + + %% Excluding x3 => y still included since y1 is used by x2 + %% z still included since z1 is used by y1 + Sys3 = {sys,[{lib_dirs,[filename:join(datadir(Config),"dependencies")]}, + {incl_cond, exclude}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,x,[{incl_cond,include},{mod,x3,[{incl_cond,exclude}]}]}, + {app,y,[{incl_cond,derived}]}, + {app,z,[{incl_cond,derived}]}]}, + ?m({ok,[]}, reltool_server:load_config(Pid,Sys3)), + ?msym({ok,[#app{name=kernel}, + #app{name=sasl}, + #app{name=stdlib}, + #app{name=x,uses_apps=[y]}]}, + reltool_server:get_apps(Pid,whitelist)), + {ok, Der3} = ?msym({ok,_}, + reltool_server:get_apps(Pid,derived)), + ?msym([#app{name=y,uses_apps=[z]}, + #app{name=z}], + rm_missing_app(Der3)), + ?msym({ok,[]}, + reltool_server:get_apps(Pid,source)), + + %% Excluding x2 and x3 => y and z excluded + Sys4 = {sys,[{lib_dirs,[filename:join(datadir(Config),"dependencies")]}, + {incl_cond, exclude}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,x,[{incl_cond,include}, + {mod,x2,[{incl_cond,exclude}]}, + {mod,x3,[{incl_cond,exclude}]}]}, + {app,y,[{incl_cond,derived}]}, + {app,z,[{incl_cond,derived}]}]}, + ?m({ok,[]}, reltool_server:load_config(Pid,Sys4)), + ?msym({ok,[#app{name=kernel}, + #app{name=sasl}, + #app{name=stdlib}, + #app{name=x,uses_apps=[]}]}, + reltool_server:get_apps(Pid,whitelist)), + {ok, Der4} = ?msym({ok,_}, + reltool_server:get_apps(Pid,derived)), + ?msym([], rm_missing_app(Der4)), + ?msym({ok,[#app{name=y}, + #app{name=z}]}, + reltool_server:get_apps(Pid,source)), + + %% Excluding y1 => y still included since y2 is used by x3 + %% z excluded since not used by any other than y1 + Sys5 = {sys,[{lib_dirs,[filename:join(datadir(Config),"dependencies")]}, + {incl_cond, exclude}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,x,[{incl_cond,include}]}, + {app,y,[{incl_cond,derived}, + {mod,y1,[{incl_cond,exclude}]}]}, + {app,z,[{incl_cond,derived}]}]}, + ?m({ok,[]}, reltool_server:load_config(Pid,Sys5)), + ?msym({ok,[#app{name=kernel}, + #app{name=sasl}, + #app{name=stdlib}, + #app{name=x,uses_apps=[y]}]}, + reltool_server:get_apps(Pid,whitelist)), + {ok, Der5} = ?msym({ok,_}, + reltool_server:get_apps(Pid,derived)), + ?msym([#app{name=y,uses_apps=[]}], rm_missing_app(Der5)), + ?msym({ok,[#app{name=z}]}, + reltool_server:get_apps(Pid,source)), + + ?m(ok, reltool:stop(Pid)), + ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -478,6 +2004,20 @@ erl_libs() -> LibStr -> string:tokens(LibStr, ":;") end. +datadir(Config) -> + %% Removes the trailing slash... + filename:nativename(?config(data_dir,Config)). + +latest(App) -> + AppStr = atom_to_list(App), + AppDirs = filelib:wildcard(filename:join(code:lib_dir(),AppStr++"-*")), + [LatestAppDir|_] = lists:reverse(AppDirs), + [_,Vsn] = string:tokens(filename:basename(LatestAppDir),"-"), + Vsn. + +rm_missing_app(Apps) -> + lists:keydelete(?MISSING_APP_NAME,#app.name,Apps). + diff_script(Script, Script) -> equal; diff_script({script, Rel, Commands1}, {script, Rel, Commands2}) -> @@ -610,14 +2150,16 @@ wait_for_process(Node, Name, N) when is_integer(N), N > 0 -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Run escript -run(Dir, Cmd0) -> +run(Dir, Script, Args) -> + Cmd0 = filename:rootname(Script) ++ " " ++ Args, Cmd = case os:type() of {win32,_} -> filename:nativename(Dir) ++ "\\" ++ Cmd0; _ -> Cmd0 end, do_run(Dir, Cmd). -run(Dir, Opts, Cmd0) -> +run(Dir, Opts, Script, Args) -> + Cmd0 = filename:rootname(Script) ++ " " ++ Args, Cmd = case os:type() of {win32,_} -> Opts ++ " " ++ filename:nativename(Dir) ++ "\\" ++ Cmd0; _ -> Opts ++ " " ++ Dir ++ "/" ++ Cmd0 @@ -626,7 +2168,9 @@ run(Dir, Opts, Cmd0) -> do_run(Dir, Cmd) -> io:format("Run: ~p\n", [Cmd]), - Env = [{"PATH",Dir++":"++os:getenv("PATH")}], + Env = [{"PATH",Dir++":"++os:getenv("PATH")}, + {"ERL_FLAGS",""}, % Make sure no flags are set that can override + {"ERL_ZFLAGS",""}], % any of the flags set in the escript. Port = open_port({spawn,Cmd}, [exit_status,eof,in,{env,Env}]), Res = get_data(Port, []), receive diff --git a/lib/reltool/test/reltool_server_SUITE_data/Makefile.src b/lib/reltool/test/reltool_server_SUITE_data/Makefile.src index 049e8dd6cc..8ab077d64b 100644 --- a/lib/reltool/test/reltool_server_SUITE_data/Makefile.src +++ b/lib/reltool/test/reltool_server_SUITE_data/Makefile.src @@ -6,8 +6,19 @@ OTP9229= \ otp_9229/y-1.0/ebin/y.@EMULATOR@ \ otp_9229/y-1.0/ebin/mylib.@EMULATOR@ +DEPENDENCIES= \ + dependencies/x-1.0/ebin/x1.@EMULATOR@ \ + dependencies/x-1.0/ebin/x2.@EMULATOR@ \ + dependencies/x-1.0/ebin/x3.@EMULATOR@ \ + dependencies/y-1.0/ebin/y1.@EMULATOR@ \ + dependencies/y-1.0/ebin/y2.@EMULATOR@ \ + dependencies/z-1.0/ebin/z1.@EMULATOR@ -all: $(OTP9229) +ESCRIPT= \ + escript/someapp-1.0/ebin/mymod.@EMULATOR@ + + +all: $(OTP9229) $(DEPENDENCIES) $(ESCRIPT) otp_9229/x-1.0/ebin/x.@EMULATOR@: otp_9229/x-1.0/src/x.erl erlc $(EFLAGS) -ootp_9229/x-1.0/ebin otp_9229/x-1.0/src/x.erl @@ -17,3 +28,19 @@ otp_9229/y-1.0/ebin/y.@EMULATOR@: otp_9229/y-1.0/src/y.erl erlc $(EFLAGS) -ootp_9229/y-1.0/ebin otp_9229/y-1.0/src/y.erl otp_9229/y-1.0/ebin/mylib.@EMULATOR@: otp_9229/y-1.0/src/mylib.erl erlc $(EFLAGS) -ootp_9229/y-1.0/ebin otp_9229/y-1.0/src/mylib.erl + +dependencies/x-1.0/ebin/x1.@EMULATOR@: dependencies/x-1.0/src/x1.erl + erlc $(EFLAGS) -odependencies/x-1.0/ebin dependencies/x-1.0/src/x1.erl +dependencies/x-1.0/ebin/x2.@EMULATOR@: dependencies/x-1.0/src/x2.erl + erlc $(EFLAGS) -odependencies/x-1.0/ebin dependencies/x-1.0/src/x2.erl +dependencies/x-1.0/ebin/x3.@EMULATOR@: dependencies/x-1.0/src/x3.erl + erlc $(EFLAGS) -odependencies/x-1.0/ebin dependencies/x-1.0/src/x3.erl +dependencies/y-1.0/ebin/y1.@EMULATOR@: dependencies/y-1.0/src/y1.erl + erlc $(EFLAGS) -odependencies/y-1.0/ebin dependencies/y-1.0/src/y1.erl +dependencies/y-1.0/ebin/y2.@EMULATOR@: dependencies/y-1.0/src/y2.erl + erlc $(EFLAGS) -odependencies/y-1.0/ebin dependencies/y-1.0/src/y2.erl +dependencies/z-1.0/ebin/z1.@EMULATOR@: dependencies/z-1.0/src/z1.erl + erlc $(EFLAGS) -odependencies/z-1.0/ebin dependencies/z-1.0/src/z1.erl + +escript/someapp-1.0/ebin/mymod.@EMULATOR@: escript/someapp-1.0/src/mymod.erl + erlc $(EFLAGS) -oescript/someapp-1.0/ebin escript/someapp-1.0/src/mymod.erl diff --git a/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/ebin/x.app b/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/ebin/x.app new file mode 100644 index 0000000000..ccaab8a8c7 --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/ebin/x.app @@ -0,0 +1,7 @@ +% -*-erlang-*- +{application, x, + [{description, "Main application in reltool dependency test"}, + {vsn, "1.0"}, + {modules, [x1,x2,x3]}, + {registered, []}, + {applications, [kernel, stdlib]}]}. diff --git a/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x1.erl b/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x1.erl new file mode 100644 index 0000000000..bf1e7f9279 --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x1.erl @@ -0,0 +1,5 @@ +-module(x1). +-compile(export_all). + +f() -> + ok. diff --git a/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x2.erl b/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x2.erl new file mode 100644 index 0000000000..82191ba278 --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x2.erl @@ -0,0 +1,5 @@ +-module(x2). +-compile(export_all). + +f() -> + y1:f(). diff --git a/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x3.erl b/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x3.erl new file mode 100644 index 0000000000..618c75c9a7 --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/dependencies/x-1.0/src/x3.erl @@ -0,0 +1,5 @@ +-module(x3). +-compile(export_all). + +f() -> + y2:f(). diff --git a/lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/ebin/y.app b/lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/ebin/y.app new file mode 100644 index 0000000000..d9dac371d7 --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/ebin/y.app @@ -0,0 +1,7 @@ +% -*-erlang-*- +{application, y, + [{description, "Library application in reltool dependency test"}, + {vsn, "1.0"}, + {modules, [y1,y2]}, + {registered, []}, + {applications, [kernel, stdlib]}]}. diff --git a/lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/src/y1.erl b/lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/src/y1.erl new file mode 100644 index 0000000000..dd21b33292 --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/src/y1.erl @@ -0,0 +1,5 @@ +-module(y1). +-compile(export_all). + +f() -> + z1:f(). diff --git a/lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/src/y2.erl b/lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/src/y2.erl new file mode 100644 index 0000000000..bf8ddf6080 --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/dependencies/y-1.0/src/y2.erl @@ -0,0 +1,5 @@ +-module(y2). +-compile(export_all). + +f() -> + ok. diff --git a/lib/reltool/test/reltool_server_SUITE_data/dependencies/z-1.0/ebin/z.app b/lib/reltool/test/reltool_server_SUITE_data/dependencies/z-1.0/ebin/z.app new file mode 100644 index 0000000000..437a0968e9 --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/dependencies/z-1.0/ebin/z.app @@ -0,0 +1,7 @@ +% -*-erlang-*- +{application, z, + [{description, "Library application in reltool dependency test"}, + {vsn, "1.0"}, + {modules, [z1]}, + {registered, []}, + {applications, [kernel, stdlib]}]}. diff --git a/lib/reltool/test/reltool_server_SUITE_data/dependencies/z-1.0/src/z1.erl b/lib/reltool/test/reltool_server_SUITE_data/dependencies/z-1.0/src/z1.erl new file mode 100644 index 0000000000..97ef90b87f --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/dependencies/z-1.0/src/z1.erl @@ -0,0 +1,5 @@ +-module(z1). +-compile(export_all). + +f() -> + ok. diff --git a/lib/reltool/test/reltool_server_SUITE_data/dupl_mod/a-1.0/ebin/a.app b/lib/reltool/test/reltool_server_SUITE_data/dupl_mod/a-1.0/ebin/a.app new file mode 100644 index 0000000000..fada34847a --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/dupl_mod/a-1.0/ebin/a.app @@ -0,0 +1,7 @@ +% -*-erlang-*- +{application, a, + [{description, "Application with duplicated module name in .app file"}, + {vsn, "1.0"}, + {modules, [a,a]}, + {registered, []}, + {applications, [kernel, stdlib]}]}. diff --git a/lib/reltool/test/reltool_server_SUITE_data/escript/someapp-1.0/ebin/someapp.app b/lib/reltool/test/reltool_server_SUITE_data/escript/someapp-1.0/ebin/someapp.app new file mode 100644 index 0000000000..ea2209941e --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/escript/someapp-1.0/ebin/someapp.app @@ -0,0 +1,6 @@ +%% -*- erlang -*- +{application, someapp, + [{description, "Some app for reltool test including archives in escripts"}, + {vsn, "1.0"}, + {modules, [someapp]}, + {applications, [kernel, stdlib]}]}. diff --git a/lib/reltool/test/reltool_server_SUITE_data/escript/someapp-1.0/src/mymod.erl b/lib/reltool/test/reltool_server_SUITE_data/escript/someapp-1.0/src/mymod.erl new file mode 100644 index 0000000000..b6c71c666d --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/escript/someapp-1.0/src/mymod.erl @@ -0,0 +1,26 @@ +%% ``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(mymod). + +-export([main/1]). + +%%%----------------------------------------------------------------- +%%% escript main function +main(Args) -> + io:format("Root dir: ~s\n", [code:root_dir()]), + io:format("Script args: ~p\n", [Args]). diff --git a/lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/ebin/a.app b/lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/ebin/a.app new file mode 100644 index 0000000000..ea77103598 --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/ebin/a.app @@ -0,0 +1 @@ +faulty app file diff --git a/lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/src/a.erl b/lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/src/a.erl new file mode 100644 index 0000000000..bb500bed69 --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/src/a.erl @@ -0,0 +1,49 @@ +%% ``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). + +-vsn(1). + +%% 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/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/src/a_sup.erl b/lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/src/a_sup.erl new file mode 100644 index 0000000000..a141c1767b --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/faulty_app_file/a-1.0/src/a_sup.erl @@ -0,0 +1,37 @@ +%% ``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/reltool/test/reltool_server_SUITE_data/sort_apps/x-1.0/ebin/x.app b/lib/reltool/test/reltool_server_SUITE_data/sort_apps/x-1.0/ebin/x.app new file mode 100644 index 0000000000..5fa2a92969 --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/sort_apps/x-1.0/ebin/x.app @@ -0,0 +1,7 @@ +% -*-erlang-*- +{application, x, + [{description, "Application in reltool sort app test - circular dependency"}, + {vsn, "1.0"}, + {modules,[]}, + {registered, []}, + {applications, [kernel, stdlib, y]}]}. diff --git a/lib/reltool/test/reltool_server_SUITE_data/sort_apps/y-1.0/ebin/y.app b/lib/reltool/test/reltool_server_SUITE_data/sort_apps/y-1.0/ebin/y.app new file mode 100644 index 0000000000..c4bc62f55f --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/sort_apps/y-1.0/ebin/y.app @@ -0,0 +1,7 @@ +% -*-erlang-*- +{application, y, + [{description, "Application in reltool sort app test - circular dependency"}, + {vsn, "1.0"}, + {modules,[]}, + {registered, []}, + {applications, [kernel, stdlib, x]}]}. diff --git a/lib/reltool/test/reltool_server_SUITE_data/sort_apps/z-1.0/ebin/z.app b/lib/reltool/test/reltool_server_SUITE_data/sort_apps/z-1.0/ebin/z.app new file mode 100644 index 0000000000..8608bc554b --- /dev/null +++ b/lib/reltool/test/reltool_server_SUITE_data/sort_apps/z-1.0/ebin/z.app @@ -0,0 +1,8 @@ +% -*-erlang-*- +{application, z, + [{description, "Application in reltool sort app test - included applications"}, + {vsn, "1.0"}, + {modules,[]}, + {registered, []}, + {applications, [kernel, stdlib, sasl, inets]}, + {included_applications, [tools, mnesia]}]}. diff --git a/lib/reltool/test/reltool_test_lib.erl b/lib/reltool/test/reltool_test_lib.erl index b8bcbcd009..61f783190c 100644 --- a/lib/reltool/test/reltool_test_lib.erl +++ b/lib/reltool/test/reltool_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% Copyright Ericsson AB 2009-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 @@ -138,10 +138,6 @@ end_per_testcase(_Func, Config) when is_list(Config) -> reset_kill_timer(Config), Config. -%% Backwards compatible with test_server -tc_info(suite) -> []; -tc_info(doc) -> "". - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Use ?log(Format, Args) as wrapper diff --git a/lib/reltool/test/reltool_test_lib.hrl b/lib/reltool/test/reltool_test_lib.hrl index b592ebb2f0..0dfc08b81c 100644 --- a/lib/reltool/test/reltool_test_lib.hrl +++ b/lib/reltool/test/reltool_test_lib.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% Copyright Ericsson AB 2009-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 @@ -18,20 +18,10 @@ -include_lib("wx/include/wx.hrl"). --define(flat_format(Format,Args), lists:flatten(io_lib:format(Format,Args))). -define(log(Format,Args), reltool_test_lib:log(Format,Args,?FILE,?LINE)). --define(warning(Format,Args), ?log("<WARNING>\n " ++ Format,Args)). -define(error(Format,Args), reltool_test_lib:error(Format,Args,?FILE,?LINE)). -define(verbose(Format,Args), reltool_test_lib:verbose(Format,Args,?FILE,?LINE)). --define(fatal(Format,Args), - ?error(Format, Args), - exit({test_case_fatal, Format, Args, ?FILE, ?LINE})). - --define(skip(Format,Args), - ?warning(Format, Args), - exit({skipped, ?flat_format(Format, Args)})). - -define(ignore(Expr), fun() -> AcTuAlReS = (catch (Expr)), @@ -68,25 +58,3 @@ AcTuAlReS end end()). - --define(m_receive(ExpectedMsg), - ?m(ExpectedMsg,reltool_test_lib:pick_msg())). - --define(m_multi_receive(ExpectedMsgs), - fun() -> - TmPeXpCtEdMsGs = lists:sort(ExpectedMsgs), - AcTuAlReS = - lists:sort(lists:map(fun(_) -> - reltool_test_lib:pick_msg() - end, TmPeXpCtEdMsGs)), - case AcTuAlReS of - TmPeXpCtEdMsGs -> - ?verbose("ok: ~p\n",[AcTuAlReS]), - AcTuAlReS; - _ -> - reltool_test_lib:error("Not matching actual result was:\n ~p \nExpected ~p\n", - [AcTuAlReS, ExpectedMsgs], - ?FILE, ?LINE), - AcTuAlReS - end - end()). diff --git a/lib/reltool/test/reltool_wx_SUITE.erl b/lib/reltool/test/reltool_wx_SUITE.erl index 424bc7d189..13d71f4fd6 100644 --- a/lib/reltool/test/reltool_wx_SUITE.erl +++ b/lib/reltool/test/reltool_wx_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2011. All Rights Reserved. +%% Copyright Ericsson AB 2009-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 @@ -61,9 +61,46 @@ start_all_windows(TestInfo) when is_atom(TestInfo) -> reltool_test_lib:tc_info(TestInfo); start_all_windows(_Config) -> {ok, SysPid} = ?msym({ok, _}, reltool:start([{trap_exit, false}])), + erlang:monitor(process,SysPid), {ok, AppPid} = ?msym({ok, _}, reltool_sys_win:open_app(SysPid, stdlib)), - ?msym({ok, _}, reltool_app_win:open_mod(AppPid, escript)), + erlang:monitor(process,AppPid), + {ok, ModPid} = ?msym({ok, _}, reltool_app_win:open_mod(AppPid, escript)), + erlang:monitor(process,ModPid), + + %% Let all windows get started timer:sleep(timer:seconds(10)), + + %% Test that server pid can be fetched, and that server is alive + {ok, Server} = ?msym({ok,_}, reltool:get_server(SysPid)), + ?m(true, erlang:is_process_alive(Server)), + ?m({ok,{sys,[]}}, reltool:get_config(Server)), + + %% Terminate + check_no_win_crash(), ?m(ok, reltool:stop(SysPid)), - + wait_terminate([{sys,SysPid},{app,AppPid},{mod,ModPid}]), + ok. + + +%%%----------------------------------------------------------------- +%%% Internal functions +check_no_win_crash() -> + receive {'DOWN',_,_,_,_} = Down -> + ct:log("Unexpected termination of window:~n~p",[Down]), + ct:fail("window crashed") + after 0 -> + ok + end. + +wait_terminate([]) -> + ok; +wait_terminate([{Win,P}|Rest]) -> + receive + {'DOWN',_,process,P,shutdown} -> + wait_terminate(Rest); + {'DOWN',_,process,P,Reason} -> + ct:log("~p window terminated with unexpected reason:~n~p", + [Win,Reason]), + ct:fail("unexpected exit reason from window") + end. diff --git a/lib/runtime_tools/c_src/Makefile.in b/lib/runtime_tools/c_src/Makefile.in index 3d9a7ed69d..120f9b913f 100644 --- a/lib/runtime_tools/c_src/Makefile.in +++ b/lib/runtime_tools/c_src/Makefile.in @@ -21,6 +21,11 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk include $(ERL_TOP)/make/$(TARGET)/otp_ded.mk # ---------------------------------------------------- +# Items from top-level configure +# ---------------------------------------------------- +DTRACE_ENABLED=@DTRACE_ENABLED@ +DTRACE_ENABLED_2STEP=@DTRACE_ENABLED_2STEP@ +# ---------------------------------------------------- # Application version # ---------------------------------------------------- include ../vsn.mk @@ -38,6 +43,8 @@ SHELL = /bin/sh LIBS = $(DED_LIBS) LDFLAGS += $(DED_LDFLAGS) +DTRACE_LIBNAME = dyntrace + SYSINCLUDE = $(DED_SYS_INCLUDE) ifeq ($(findstring vxworks,$(TARGET)),vxworks) SYSINCLUDE += -I$(ERL_TOP)/erts/etc/vxworks @@ -45,15 +52,20 @@ endif TRACE_DRV_INCLUDES = $(SYSINCLUDE) -ALL_CFLAGS = $(CFLAGS) @DEFS@ $(TYPE_FLAGS) $(TRACE_DRV_INCLUDES) - +ALL_CFLAGS = $(CFLAGS) @DEFS@ $(TYPE_FLAGS) $(TRACE_DRV_INCLUDES) \ + -I$(OBJDIR) -I$(ERL_TOP)/erts/emulator/$(TARGET) ifeq ($(TYPE),debug) TYPEMARKER = .debug -TYPE_FLAGS = -g -DDEBUG @DEBUG_FLAGS@ +TYPE_FLAGS = $(subst -O3,,$(subst -O2,,$(CFLAGS))) -DDEBUG @DEBUG_FLAGS@ +else +ifeq ($(TYPE),valgrind) +TYPEMARKER = .valgrind +TYPE_FLAGS = $(subst -O3,,$(subst -O2,,$(CFLAGS))) -DVALGRIND else TYPEMARKER = -TYPE_FLAGS = -O2 +TYPE_FLAGS = $(CFLAGS) +endif endif ROOTDIR = $(ERL_TOP)/lib @@ -69,6 +81,16 @@ RELSYSDIR = $(RELEASE_PATH)/lib/runtime_tools-$(VSN) # ---------------------------------------------------- # Misc Macros # ---------------------------------------------------- +before_DTrace_OBJS = $(OBJDIR)/dyntrace$(TYPEMARKER).o +## NIF_MAKEFILE = $(PRIVDIR)/Makefile + +# Higher-level makefiles says that we can only compile on UNIX flavors +NIF_LIB = $(LIBDIR)/dyntrace$(TYPEMARKER).@DED_EXT@ + +ifeq ($(HOST_OS),) +HOST_OS := $(shell $(ERL_TOP)/erts/autoconf/config.guess) +endif + TRACE_IP_DRV_OBJS = \ $(OBJDIR)/trace_ip_drv.o @@ -91,7 +113,44 @@ endif _create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR)) -debug opt: $(SOLIBS) +debug opt valgrind: $(SOLIBS) $(OBJDIR) $(LIBDIR) $(NIF_LIB) + +ifdef DTRACE_ENABLED +DTRACE_USER_HEADER=$(OBJDIR)/dtrace_user.h +$(OBJDIR)/dtrace_user.h: ./dtrace_user.d + dtrace -h -C $(INCLUDES) \ + -s ./dtrace_user.d \ + -o ./dtrace_user.tmp + sed -e '/^#define[ ]*ERLANG_[A-Z0-9_]*(.*)/y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' ./dtrace_user.tmp > $@ + rm ./dtrace_user.tmp +else +DTRACE_USER_HEADER= +endif + +DTRACE_OBJS = +ifdef DTRACE_ENABLED_2STEP +DTRACE_OBJS += $(OBJDIR)/dtrace_user.o +$(OBJDIR)/dtrace_user.o: $(before_DTrace_OBJS) $(OBJDIR)/dtrace_user.h + dtrace -G -C \ + -s ./dtrace_user.d \ + -o $@ $(before_DTrace_OBJS) +endif + +DYNTRACE_OBJS = $(before_DTrace_OBJS) $(DTRACE_OBJS) + +$(OBJDIR): + -@mkdir -p $(OBJDIR) + +$(LIBDIR): + -@mkdir -p $(LIBDIR) + +$(OBJDIR)/dyntrace$(TYPEMARKER).o: dyntrace.c $(DTRACE_USER_HEADER) + $(INSTALL_DIR) $(OBJDIR) + $(CC) -c -o $@ $(ALL_CFLAGS) $< + +$(NIF_LIB): $(DYNTRACE_OBJS) + $(INSTALL_DIR) $(LIBDIR) + $(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(OBJDIR)/%.o: %.c $(CC) -c -o $@ $(ALL_CFLAGS) $< @@ -118,6 +177,12 @@ $(LIBDIR)/trace_file_drv.eld: $(TRACE_FILE_DRV_OBJS) clean: rm -f $(SOLIBS) $(TRACE_IP_DRV_OBJS) $(TRACE_FILE_DRV_OBJS) + rm -f $(LIBDIR)/dyntrace.@DED_EXT@ + rm -f $(LIBDIR)/dyntrace.debug.@DED_EXT@ + rm -f $(LIBDIR)/dyntrace.valgrind.@DED_EXT@ + rm -f $(OBJDIR)/dyntrace.o + rm -f $(OBJDIR)/dyntrace.debug.o + rm -f $(OBJDIR)/dyntrace.valgrind.o rm -f core *~ docs: @@ -128,8 +193,10 @@ docs: include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/priv/obj $(INSTALL_DIR) $(RELSYSDIR)/priv/lib - $(INSTALL_PROGRAM) $(SOLIBS) $(RELSYSDIR)/priv/lib + $(INSTALL_PROGRAM) $(DYNTRACE_OBJS) $(RELSYSDIR)/priv/obj + $(INSTALL_PROGRAM) $(NIF_LIB) $(SOLIBS) $(RELSYSDIR)/priv/lib release_docs_spec: diff --git a/lib/runtime_tools/c_src/dtrace_user.d b/lib/runtime_tools/c_src/dtrace_user.d new file mode 100644 index 0000000000..45d3ef3b66 --- /dev/null +++ b/lib/runtime_tools/c_src/dtrace_user.d @@ -0,0 +1,53 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. + * 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% + */ + +provider erlang { + /** + * Send a single string to a probe. + * + * @param NUL-terminated string + */ + probe user_trace__s1(char* message); + + /** + * Multi-purpose probe: up to 4 NUL-terminated strings and 4 + * 64-bit integer arguments. + * + * @param proc, the PID (string form) of the sending process + * @param user_tag, the user tag of the sender + * @param i1, integer + * @param i2, integer + * @param i3, integer + * @param i4, integer + * @param s1, string/iolist. D's arg6 is NULL if not given by Erlang + * @param s2, string/iolist. D's arg7 is NULL if not given by Erlang + * @param s3, string/iolist. D's arg8 is NULL if not given by Erlang + * @param s4, string/iolist. D's arg9 is NULL if not given by Erlang + */ + probe user_trace__i4s4(char *proc, char *user_tag, + int i1, int i2, int i3, int i4, + char *s1, char *s2, char *s3, char *s4); +}; + +#pragma D attributes Evolving/Evolving/Common provider erlang provider +#pragma D attributes Private/Private/Common provider erlang module +#pragma D attributes Private/Private/Common provider erlang function +#pragma D attributes Evolving/Evolving/Common provider erlang name +#pragma D attributes Evolving/Evolving/Common provider erlang args diff --git a/lib/runtime_tools/c_src/dyntrace.c b/lib/runtime_tools/c_src/dyntrace.c new file mode 100644 index 0000000000..d94014559d --- /dev/null +++ b/lib/runtime_tools/c_src/dyntrace.c @@ -0,0 +1,172 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. 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: Dynamically loadable NIF library for DTrace + */ + + + +#include "erl_nif.h" +#include "config.h" +#include "sys.h" +#include "dtrace-wrapper.h" +#if defined(USE_DYNAMIC_TRACE) && (defined(USE_DTRACE) || defined(USE_SYSTEMTAP)) +#define HAVE_USE_DTRACE 1 +#endif +#ifdef HAVE_USE_DTRACE +#include "dtrace_user.h" +#endif + +void dtrace_nifenv_str(ErlNifEnv *env, char *process_buf); +void get_string_maybe(ErlNifEnv *env, const ERL_NIF_TERM term, char **ptr, char *buf, int bufsiz); + +#ifdef VALGRIND + # include <valgrind/memcheck.h> +#endif + +#ifdef __GNUC__ + # define INLINE __inline__ +#else + # define INLINE +#endif + +#define MESSAGE_BUFSIZ 1024 + +/* NIF interface declarations */ +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); + +/* The NIFs: */ +static ERL_NIF_TERM available(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM user_trace_s1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM user_trace_i4s4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); + +static ErlNifFunc nif_funcs[] = { + {"available", 0, available}, + {"user_trace_s1", 1, user_trace_s1}, + {"user_trace_i4s4", 9, user_trace_i4s4} +}; + +ERL_NIF_INIT(dyntrace, nif_funcs, load, NULL, NULL, NULL) + +static ERL_NIF_TERM atom_true; +static ERL_NIF_TERM atom_false; +static ERL_NIF_TERM atom_error; +static ERL_NIF_TERM atom_not_available; +static ERL_NIF_TERM atom_badarg; +static ERL_NIF_TERM atom_ok; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + atom_true = enif_make_atom(env,"true"); + atom_false = enif_make_atom(env,"false"); + atom_error = enif_make_atom(env,"error"); + atom_not_available = enif_make_atom(env,"not_available"); + atom_badarg = enif_make_atom(env,"badarg"); + atom_ok = enif_make_atom(env,"ok"); + + return 0; +} + +static ERL_NIF_TERM available(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#ifdef HAVE_USE_DTRACE + return atom_true; +#else + return atom_false; +#endif +} + +static ERL_NIF_TERM user_trace_s1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#ifdef HAVE_USE_DTRACE + ErlNifBinary message_bin; + DTRACE_CHARBUF(messagebuf, MESSAGE_BUFSIZ + 1); + + if (DTRACE_ENABLED(user_trace_s1)) { + if (!enif_inspect_iolist_as_binary(env, argv[0], &message_bin) || + message_bin.size > MESSAGE_BUFSIZ) { + return atom_badarg; + } + memcpy(messagebuf, (char *) message_bin.data, message_bin.size); + messagebuf[message_bin.size] = '\0'; + DTRACE1(user_trace_s1, messagebuf); + return atom_true; + } else { + return atom_false; + } +#else + return atom_error; +#endif +} + +void +get_string_maybe(ErlNifEnv *env, + const ERL_NIF_TERM term, char **ptr, char *buf, int bufsiz) +{ + ErlNifBinary str_bin; + + if (!enif_inspect_iolist_as_binary(env, term, &str_bin) || + str_bin.size > bufsiz) { + *ptr = NULL; + } else { + memcpy(buf, (char *) str_bin.data, str_bin.size); + buf[str_bin.size] = '\0'; + *ptr = buf; + } +} + +static ERL_NIF_TERM user_trace_i4s4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#ifdef HAVE_USE_DTRACE + DTRACE_CHARBUF(procbuf, 32 + 1); + DTRACE_CHARBUF(user_tagbuf, MESSAGE_BUFSIZ + 1); + char *utbuf = NULL; + ErlNifSInt64 i1, i2, i3, i4; + DTRACE_CHARBUF(messagebuf1, MESSAGE_BUFSIZ + 1); + DTRACE_CHARBUF(messagebuf2, MESSAGE_BUFSIZ + 1); + DTRACE_CHARBUF(messagebuf3, MESSAGE_BUFSIZ + 1); + DTRACE_CHARBUF(messagebuf4, MESSAGE_BUFSIZ + 1); + char *mbuf1 = NULL, *mbuf2 = NULL, *mbuf3 = NULL, *mbuf4 = NULL; + + if (DTRACE_ENABLED(user_trace_i4s4)) { + dtrace_nifenv_str(env, procbuf); + get_string_maybe(env, argv[0], &utbuf, user_tagbuf, MESSAGE_BUFSIZ); + if (! enif_get_int64(env, argv[1], &i1)) + i1 = 0; + if (! enif_get_int64(env, argv[2], &i2)) + i2 = 0; + if (! enif_get_int64(env, argv[3], &i3)) + i3 = 0; + if (! enif_get_int64(env, argv[4], &i4)) + i4 = 0; + get_string_maybe(env, argv[5], &mbuf1, messagebuf1, MESSAGE_BUFSIZ); + get_string_maybe(env, argv[6], &mbuf2, messagebuf2, MESSAGE_BUFSIZ); + get_string_maybe(env, argv[7], &mbuf3, messagebuf3, MESSAGE_BUFSIZ); + get_string_maybe(env, argv[8], &mbuf4, messagebuf4, MESSAGE_BUFSIZ); + DTRACE10(user_trace_i4s4, procbuf, utbuf, + i1, i2, i3, i4, mbuf1, mbuf2, mbuf3, mbuf4); + return atom_true; + } else { + return atom_false; + } +#else + return atom_error; +#endif +} diff --git a/lib/runtime_tools/doc/src/Makefile b/lib/runtime_tools/doc/src/Makefile index dbbae81cfe..f1dd788f80 100644 --- a/lib/runtime_tools/doc/src/Makefile +++ b/lib/runtime_tools/doc/src/Makefile @@ -40,7 +40,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) # Target Specs # ---------------------------------------------------- XML_APPLICATION_FILES = ref_man.xml -XML_REF3_FILES = dbg.xml erts_alloc_config.xml +XML_REF3_FILES = dbg.xml dyntrace.xml erts_alloc_config.xml XML_REF6_FILES = runtime_tools_app.xml XML_PART_FILES = part_notes.xml part_notes_history.xml diff --git a/lib/runtime_tools/doc/src/dyntrace.xml b/lib/runtime_tools/doc/src/dyntrace.xml new file mode 100644 index 0000000000..5fc5530f25 --- /dev/null +++ b/lib/runtime_tools/doc/src/dyntrace.xml @@ -0,0 +1,209 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2012</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>dyntrace</title> + <prepared>Patrik Nyblom</prepared> + <responsible></responsible> + <docno>1</docno> + <approved>ETX/B/SFP (Kenneth Lundin)</approved> + <checked></checked> + <date>12-03-20</date> + <rev>A</rev> + <file>dyntrace.xml</file> + </header> + <module>dyntrace</module> + <modulesummary>Interface to dynamic tracing</modulesummary> + <description> + <p>This module implements interfaces to dynamic tracing, should such be compiled into the virtual machine. For a standard and/or commercial build, no dynamic tracing is available, in which case none of the functions in this module is usable or give any effect.</p> + <p>Should dynamic tracing be enabled in the current build, either by configuring with <c>./configure --with-dynamic-trace=dtrace</c> or with <c>./configure --with-dynamic-trace=systemtap</c>, the module can be used for two things:</p> + <list type="bulleted"> + <item>Trigger the user-probe <c>user_trace_i4s4</c> in the NIF library <c>dyntrace.so</c> by calling <c>dyntrace:p/{1,2,3,4,5,6,7,8}</c>.</item> + <item>Set a user specified tag that will be present in the trace messages of both the <c>efile_drv</c> and the user-probe mentioned above.</item> + </list> + <p>Both building with dynamic trace probes and using them is experimental and unsupported by Erlang/OTP. It is included as an option for the developer to trace and debug performance issues in their systems.</p> + <p>The original implementation is mostly done by Scott Lystiger Fritchie as an Open Source Contribution and it should be viewed as such even though the source for dynamic tracing as well as this module is included in the main distribution. However, the ability to use dynamic tracing of the virtual machine is a very valuable contribution which OTP has every intention to maintain as a tool for the developer.</p> + <p>How to write <c>d</c> programs or <c>systemtap</c> scripts can be learned from books and from a lot of pages on the Internet. This manual page does not include any documentation about using the dynamic trace tools of respective platform. The <c>examples</c> directory of the <c>runtime_tools</c> application however contains comprehensive examples of both <c>d</c> and <c>systemtap</c> programs that will help you get started. Another source of information is the <c>README.dtrace(.md)</c> and <c>README.systemtap(.md)</c> files in the Erlang source top directory.</p> + </description> + <funcs> + <func> + <name>available() -> boolean()</name> + <fsummary>Check if dynamic tracing is available</fsummary> + <desc> + <p>This function uses the NIF library to determine if dynamic + tracing is available. Usually calling <seealso + marker="erts:erlang#system_info/1">erlang:system_info/1</seealso> + is a better indicator of the availability of dynamic + tracing.</p> + <p>The function will throw an exception if the <c>dyntrace</c> NIF library could not be loaded by the on_load function of this module.</p> + </desc> + </func> + <func> + <name>p() -> true | false | error | badarg</name> + <fsummary>Trigger the user trace probe.</fsummary> + <desc> + <p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message only containing the user tag and zeroes/empty strings in all other fields.</p> + </desc> + </func> + <func> + <name>p(integer() | string()) -> true | false | error | badarg</name> + <fsummary>Trigger the user trace probe.</fsummary> + <desc> + <p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer or string parameter in the first integer/string field.</p> + </desc> + </func> + <func> + <name>p(integer() | string(), integer() | string()) -> true | false | error | badarg</name> + <fsummary>Trigger the user trace probe.</fsummary> + <desc> + <p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters. I.e. <c>p(1,"Hello")</c> is ok, as is <c>p(1,1)</c> and <c>p("Hello","Again")</c>, but not <c>p("Hello",1)</c>.</p> + </desc> + </func> + <func> + <name>p(integer() | string(), integer() | string(), integer() | string()) -> true | false | error | badarg</name> + <fsummary>Trigger the user trace probe.</fsummary> + <desc> + <p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in <seealso marker="#p/2">p/2</seealso>.</p> + </desc> + </func> + <func> + <name>p(integer() | string(), integer() | string(), integer() | string(), integer() | string()) -> true | false | error | badarg</name> + <fsummary>Trigger the user trace probe.</fsummary> + <desc> + <p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in <seealso marker="#p/2">p/2</seealso>.</p> + </desc> + </func> + <func> + <name>p(integer(), integer() | string(), integer() | string(), integer() | string(), string()) -> true | false | error | badarg</name> + <fsummary>Trigger the user trace probe.</fsummary> + <desc> + <p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in <seealso marker="#p/2">p/2</seealso>.</p> + <p>There can be no more than four parameters of any type (integer() or string()), so the first parameter has to be an integer() and the last a string().</p> + </desc> + </func> + <func> + <name>p(integer(), integer(), integer() | string(), integer() | string(), string(), string()) -> true | false | error | badarg</name> + <fsummary>Trigger the user trace probe.</fsummary> + <desc> + <p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in <seealso marker="#p/2">p/2</seealso>.</p> + <p>There can be no more than four parameters of any type (integer() or string()), so the first two parameters has to be integer()'s and the last two string()'s.</p> + </desc> + </func> + <func> + <name>p(integer(), integer(), integer(), integer() | string(), string(), string(), string()) -> true | false | error | badarg</name> + <fsummary>Trigger the user trace probe.</fsummary> + <desc> + <p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in <seealso marker="#p/2">p/2</seealso>.</p> + <p>There can be no more than four parameters of any type (integer() or string()), so the first three parameters has to be integer()'s and the last three string()'s.</p> + </desc> + </func> + <func> + <name>p(integer(), integer(), integer(), integer(), string(), string(), string(), string()) -> true | false | error | badarg</name> + <fsummary>Trigger the user trace probe.</fsummary> + <desc> + <p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing all the integer()'s and string()'s provided, as well as any user tag set in the current process.</p> + </desc> + </func> + <func> + <name>get_tag() -> binary() | undefined</name> + <fsummary>Get the user tag set in the process.</fsummary> + <desc> + <p>This function returns the user tag set in the current + process. If no tag is set or dynamic tracing is not available, + it returns <c>undefined</c></p> + </desc> + </func> + <func> + <name>get_tag() -> binary() | undefined</name> + <fsummary>Get the user tag set in the process or sent to the process.</fsummary> + <desc> + <p>This function returns the user tag set in the current + process or, if no user tag is present, the last user tag sent + to the process together with a message (in the same way as + <seealso marker="kernel:seq_trace">sequential trace + tokens</seealso> are spread to other processes together with + messages. For an explanation of how user tags can be spread + together with messages, see <seealso + marker="#spread_tag/1">spread_tag/1</seealso>. If no tag is + found or dynamic tracing is not available, it returns + <c>undefined</c></p> + </desc> + </func> + + <func> + <name>put_tag(Item) -> binary() | undefined </name> + <fsummary>Set the user tag of the current process.</fsummary> + <type> + <v>Item = iodata()</v> + </type> + <desc> + <p>This function sets the user tag of the current process. The user tag is a binary(), but can be specified as any iodata(), which is automatically converted to a binary by this function.</p> + <p>The user tag is provided to the user probes triggered by calls top <c>dyntrace:p/{1,2,3,4,5,6,7,8}</c> as well as probes in the efile_driver. In the future, user tags might be added to more probes.</p> + <p>The old user tag (if any) is returned, or <c>undefined</c> if no user tag was present or dynamic tracing is not enabled.</p> + </desc> + </func> + <func> + <name>spread_tag(boolean()) -> TagData</name> + <fsummary>Start or stop spreading dynamic trace user tags with the next message.</fsummary> + <type> + <v>TagData = opaque data that can be used as parameter to <seealso marker="#restore_tag/1">restore_tag/1</seealso></v> + </type> + <desc> + <p>This function controls if user tags are to be spread to other processes with the next message. Spreading of user tags work like spreading of sequential trace tokens, so that a received user tag will be active in the process until the next message arrives (if that message does not also contain the user tag.</p> + <p>This functionality is used when a client process communicates with a file i/o-server to spread the user tag to the I/O-server and then down to the efile_drv driver. By using <c>spread_tag/1</c> and <c>restore_tag/1</c>, one can enable or disable spreading of user tags to other processes and then restore the previous state of the user tag. The TagData returned from this call contains all previous information so the state (including any previously spread user tags) will be completely restored by a later call to <c>restore_tag/1</c>.</p> + <p>The <seealso marker="kernel:file">file</seealso> module already spread's tags, so there is noo need to manually call these function to get user tags spread to the efile driver through that module.</p> + <p>The most use of this function would be if one for example uses the <seealso marker="stdlib:io">io</seealso> module to communicate with an I/O-server for a regular file, like in the following example:</p> +<pre> +f() -> + {ok, F} = file:open("test.tst",[write]), + Saved = dyntrace:spread_tag(true), + io:format(F,"Hello world!",[]), + dyntrace:restore_tag(Saved), + file:close(F). +</pre> + <p>In this example, any user tag set in the calling process will be spread to the I/O-server when the io:format call is done.</p> + </desc> + </func> + <func> + <name>restore_tag(TagData) -> true</name> + <fsummary>Restore to a previous state of user tag spreading.</fsummary> + <type> + <v>TagData = opaque data returned by <seealso marker="#spread_tag/1">spread_tag/1</seealso></v> + </type> + <desc> + <p>Restores the previous state of user tags and their spreading as it was before a call to <seealso marker="#spread_tag/1">spread_tag/1</seealso>. Note that the restoring is not limited to the same process, one can utilize this to turn off spreding in one process and restore it in a newly created, the one that actually is going to send messages:</p> +<pre> +f() -> + TagData=dyntrace:spread_tag(false), + spawn(fun() -> + dyntrace:restore_tag(TagData), + do_something() + end), + do_something_else(), + dyntrace:restore_tag(TagData). +</pre> + <p>Correctly handling user tags and their spreading might take some effort, as Erlang programs tend to send and receive messages so that sometimes the user tag gets lost due to various things, like double receives or communication with a port (ports do not handle user tags, in the same way as they do not handle regular sequential trace tokens).</p> + </desc> + </func> + </funcs> + </erlref> + diff --git a/lib/runtime_tools/doc/src/ref_man.xml b/lib/runtime_tools/doc/src/ref_man.xml index 579efcd969..41fa5f17c4 100644 --- a/lib/runtime_tools/doc/src/ref_man.xml +++ b/lib/runtime_tools/doc/src/ref_man.xml @@ -33,6 +33,7 @@ </description> <xi:include href="runtime_tools_app.xml"/> <xi:include href="dbg.xml"/> + <xi:include href="dyntrace.xml"/> <xi:include href="erts_alloc_config.xml"/> </application> diff --git a/lib/runtime_tools/examples/dist.d b/lib/runtime_tools/examples/dist.d new file mode 100644 index 0000000000..550e10d363 --- /dev/null +++ b/lib/runtime_tools/examples/dist.d @@ -0,0 +1,62 @@ +/* example usage: dtrace -q -s /path/to/dist.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. 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% + */ + +erlang*:::dist-monitor +{ + printf("monitor: pid %d, who %s, what %s, node %s, type %s, reason %s\n", + pid, + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3), + copyinstr(arg4)); +} + +erlang*:::dist-port_busy +{ + printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); + /* + * For variable use advice, see: + * http://dtrace.org/blogs/brendan/2011/11/25/dtrace-variable-types/ + * + * Howevever, it's quite possible for the blocked events to span + * threads, so we'll use globals. + */ + blocked_procs[copyinstr(arg3)] = timestamp; +} + +erlang*:::dist-output +{ + printf("dist output: node %s, port %s, remote_node %s bytes %d\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); +} + +erlang*:::dist-outputv +{ + printf("port outputv: node %s, port %s, remote_node %s bytes %d\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); +} + +erlang*:::process-scheduled +/blocked_procs[copyinstr(arg0)]/ +{ + pidstr = copyinstr(arg0); + printf("blocked pid %s scheduled now, waited %d microseconds\n", + pidstr, (timestamp - blocked_procs[pidstr]) / 1000); + blocked_procs[pidstr] = 0; +} diff --git a/lib/runtime_tools/examples/dist.systemtap b/lib/runtime_tools/examples/dist.systemtap new file mode 100644 index 0000000000..af27b2cab6 --- /dev/null +++ b/lib/runtime_tools/examples/dist.systemtap @@ -0,0 +1,76 @@ +/* example usage: stap /path/to/dist.systemtap -x <pid> */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. 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% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("dist-monitor") +{ + printf("monitor: pid %d, who %s, what %s, node %s, type %s, reason %s\n", + pid(), + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4), + user_string($arg5)); +} + +probe process("beam").mark("dist-port_busy") +{ + printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); + blocked_procs[user_string($arg4)] = timestamp; +} + +probe process("beam").mark("dist-port_busy") +{ + printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); + blocked_procs[user_string($arg4)] = timestamp; +} + +probe process("beam").mark("dist-output") +{ + printf("dist output: node %s, port %s, remote_node %s bytes %d\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4); +} + +probe process("beam").mark("dist-outputv") +{ + printf("port outputv: node %s, port %s, remote_node %s bytes %d\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4); +} + +probe process("beam").mark("process-scheduled") +{ + pidstr = user_string($arg1); + if (pidstr in blocked_procs) { + printf("blocked pid %s scheduled now, waited %d microseconds\n", + pidstr, (timestamp - blocked_procs[pidstr]) / 1000); + delete blocked_procs[pidstr]; + } +} + +global blocked_procs; diff --git a/lib/runtime_tools/examples/driver1.d b/lib/runtime_tools/examples/driver1.d new file mode 100644 index 0000000000..9f53ffeb2a --- /dev/null +++ b/lib/runtime_tools/examples/driver1.d @@ -0,0 +1,114 @@ +/* example usage: dtrace -q -s /path/to/driver1.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. 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% + */ + +erlang*:::driver-init +{ + printf("driver init name %s major %d minor %d flags %d\n", + copyinstr(arg0), arg1, arg2, arg3); +} + +erlang*:::driver-start +{ + printf("driver start pid %s driver name %s port %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-stop +{ + printf("driver stop pid %s driver name %s port %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-finish +{ + printf("driver finish driver name %s port %s\n", + copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::driver-flush +{ + printf("driver flush pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-output +{ + printf("driver output pid %s port %s port name %s bytes %d\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); +} + +erlang*:::driver-outputv +{ + printf("driver outputv pid %s port %s port name %s bytes %d\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); +} + +erlang*:::driver-control +{ + printf("driver control pid %s port %s port name %s command %d bytes %d\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3, arg4); +} + +erlang*:::driver-call +{ + printf("driver call pid %s port %s port name %s command %d bytes %d\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3, arg4); +} + +erlang*:::driver-event +{ + printf("driver event pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-ready_input +{ + printf("driver ready_input pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-ready_output +{ + printf("driver ready_output pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-timeout +{ + printf("driver timeout pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-ready_async +{ + printf("driver ready_async pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-process_exit +{ + printf("driver process_exit pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-stop_select +{ + printf("driver stop_select driver name %s\n", copyinstr(arg0)); +} diff --git a/lib/runtime_tools/examples/driver1.systemtap b/lib/runtime_tools/examples/driver1.systemtap new file mode 100644 index 0000000000..8b99e465b7 --- /dev/null +++ b/lib/runtime_tools/examples/driver1.systemtap @@ -0,0 +1,125 @@ +/* example usage: stap /path/to/driver1.systemtap -x <pid> */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. 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% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("driver-init") +{ + printf("driver init name %s major %d minor %d flags %d\n", + user_string($arg1), $arg2, $arg3, $arg4); +} + +probe process("beam").mark("driver-start") +{ + printf("driver start pid %s driver name %s port %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-stop") +{ + printf("driver stop pid %s driver name %s port %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-finish") +{ + printf("driver finish driver name %s\n", + user_string($arg1)); +} + +probe process("beam").mark("driver-flush") +{ + printf("driver flush pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-output") +{ + printf("driver output pid %s port %s port name %s bytes %d\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4); +} + +probe process("beam").mark("driver-outputv") +{ + printf("driver outputv pid %s port %s port name %s bytes %d\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4); +} + +probe process("beam").mark("driver-control") +{ + printf("driver control pid %s port %s port name %s command %d bytes %d\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4, $arg5); +} + +probe process("beam").mark("driver-call") +{ + printf("driver call pid %s port %s port name %s command %d bytes %d\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4, $arg5); +} + +probe process("beam").mark("driver-event") +{ + printf("driver event pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-ready_input") +{ + printf("driver ready_input pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-ready_output") +{ + printf("driver ready_output pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-timeout") +{ + printf("driver timeout pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-ready_async") +{ + printf("driver ready_async pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-process_exit") +{ + printf("driver process_exit pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-stop_select") +{ + printf("driver stop_select driver name %s\n", user_string($arg1)); +} diff --git a/lib/runtime_tools/examples/efile_drv.d b/lib/runtime_tools/examples/efile_drv.d new file mode 100644 index 0000000000..085995ce58 --- /dev/null +++ b/lib/runtime_tools/examples/efile_drv.d @@ -0,0 +1,104 @@ +/* example usage: dtrace -q -s /path/to/efile_drv.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. 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% + */ + +BEGIN +{ + op_map[1] = "OPEN"; + op_map[2] = "READ"; + op_map[3] = "LSEEK"; + op_map[4] = "WRITE"; + op_map[5] = "FSTAT"; + op_map[6] = "PWD"; + op_map[7] = "READDIR"; + op_map[8] = "CHDIR"; + op_map[9] = "FSYNC"; + op_map[10] = "MKDIR"; + op_map[11] = "DELETE"; + op_map[12] = "RENAME"; + op_map[13] = "RMDIR"; + op_map[14] = "TRUNCATE"; + op_map[15] = "READ_FILE"; + op_map[16] = "WRITE_INFO"; + op_map[19] = "LSTAT"; + op_map[20] = "READLINK"; + op_map[21] = "LINK"; + op_map[22] = "SYMLINK"; + op_map[23] = "CLOSE"; + op_map[24] = "PWRITEV"; + op_map[25] = "PREADV"; + op_map[26] = "SETOPT"; + op_map[27] = "IPREAD"; + op_map[28] = "ALTNAME"; + op_map[29] = "READ_LINE"; + op_map[30] = "FDATASYNC"; + op_map[31] = "FADVISE"; +} + +erlang*:::aio_pool-add +{ + printf("async I/O pool port %s queue len %d\n", copyinstr(arg0), arg1); +} + +erlang*:::aio_pool-get +{ + printf("async I/O pool port %s queue len %d\n", copyinstr(arg0), arg1); +} + +erlang*:::efile_drv-entry +{ + printf("efile_drv enter tag={%d,%d} %s%s | %s (%d) | args: %s %s , %d %d (port %s)\n", + arg0, arg1, + arg2 == NULL ? "" : "user tag ", + arg2 == NULL ? "" : copyinstr(arg2), + op_map[arg3], arg3, + arg4 == NULL ? "" : copyinstr(arg4), + arg5 == NULL ? "" : copyinstr(arg5), arg6, arg7, + /* NOTE: port name in args[10] is experimental */ + (args[10] == NULL) ? + "?" : copyinstr((user_addr_t) args[10])); +} + +erlang*:::efile_drv-int* +{ + printf("async I/O worker tag={%d,%d} | %s (%d) | %s\n", + arg0, arg1, op_map[arg2], arg2, probename); +} + +/* efile_drv-return error case */ +erlang*:::efile_drv-return +/arg4 == 0/ +{ + printf("efile_drv return tag={%d,%d} %s%s | %s (%d) | errno %d\n", + arg0, arg1, + arg2 == NULL ? "" : "user tag ", + arg2 == NULL ? "" : copyinstr(arg2), + op_map[arg3], arg3, + arg5); +} + +/* efile_drv-return success case */ +erlang*:::efile_drv-return +/arg4 != 0/ +{ + printf("efile_drv return tag={%d,%d} %s | %s (%d) ok\n", + arg0, arg1, + arg2 == NULL ? "" : copyinstr(arg2), + op_map[arg3], arg3); +} diff --git a/lib/runtime_tools/examples/efile_drv.systemtap b/lib/runtime_tools/examples/efile_drv.systemtap new file mode 100644 index 0000000000..5a47b3e22b --- /dev/null +++ b/lib/runtime_tools/examples/efile_drv.systemtap @@ -0,0 +1,112 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. 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% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe begin +{ + op_map[1] = "OPEN"; + op_map[2] = "READ"; + op_map[3] = "LSEEK"; + op_map[4] = "WRITE"; + op_map[5] = "FSTAT"; + op_map[6] = "PWD"; + op_map[7] = "READDIR"; + op_map[8] = "CHDIR"; + op_map[9] = "FSYNC"; + op_map[10] = "MKDIR"; + op_map[11] = "DELETE"; + op_map[12] = "RENAME"; + op_map[13] = "RMDIR"; + op_map[14] = "TRUNCATE"; + op_map[15] = "READ_FILE"; + op_map[16] = "WRITE_INFO"; + op_map[19] = "LSTAT"; + op_map[20] = "READLINK"; + op_map[21] = "LINK"; + op_map[22] = "SYMLINK"; + op_map[23] = "CLOSE"; + op_map[24] = "PWRITEV"; + op_map[25] = "PREADV"; + op_map[26] = "SETOPT"; + op_map[27] = "IPREAD"; + op_map[28] = "ALTNAME"; + op_map[29] = "READ_LINE"; + op_map[30] = "FDATASYNC"; + op_map[31] = "FADVISE"; +} + +probe process("beam").mark("aio_pool-add") +{ + printf("async I/O pool port %s queue len %d\n", user_string($arg1), $arg2); +} + +probe process("beam").mark("aio_pool-get") +{ + printf("async I/O pool port %s queue len %d\n", user_string($arg1), $arg2); +} + +probe process("beam").mark("efile_drv-entry") +{ + printf("efile_drv enter tag={%d,%d} %s%s | %s (%d) | args: %s %s , %d %d (port %s)\n", + $arg1, $arg2, + $arg3 == NULL ? "" : "user tag ", + $arg3 == NULL ? "" : user_string($arg3), + op_map[$arg4], $arg4, + $arg5 == NULL ? "" : user_string($arg5), + $arg6 == NULL ? "" : user_string($arg6), $arg7, $arg8, + /* NOTE: port name in $arg[11] is experimental */ + user_string($arg11)) +} + +probe process("beam").mark("efile_drv-int*") +{ + printf("async I/O worker tag={%d,%d} | %s (%d) | %s\n", + $arg1, $arg2, op_map[$arg3], $arg3, probefunc()); +} + +probe process("beam").mark("efile_drv-return") +{ + if ($arg5 == 0) { + /* efile_drv-return error case */ + printf("efile_drv return tag={%d,%d} %s%s | %s (%d) | errno %d\n", + $arg1, $arg2, + $arg3 == NULL ? "" : "user tag ", + $arg3 == NULL ? "" : user_string($arg3), + op_map[$arg4], $arg4, + $arg6); + } else { + /* efile_drv-return success case */ + printf("efile_drv return tag={%d,%d} %s | %s (%d) ok\n", + $arg1, $arg2, + $arg3 == NULL ? "" : user_string($arg3), + op_map[$arg4], $arg4); + } +} + +global op_map; diff --git a/lib/runtime_tools/examples/function-calls.d b/lib/runtime_tools/examples/function-calls.d new file mode 100644 index 0000000000..3e015dc2d2 --- /dev/null +++ b/lib/runtime_tools/examples/function-calls.d @@ -0,0 +1,57 @@ +/* example usage: dtrace -q -s /path/to/function-calls.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. 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% + */ + +erlang*:::local-function-entry +{ + printf("pid %s enter (local) %s depth %d\n", + copyinstr(arg0), copyinstr(arg1), arg2); +} + +erlang*:::global-function-entry +{ + printf("pid %s enter (global) %s depth %d\n", + copyinstr(arg0), copyinstr(arg1), arg2); +} + +erlang*:::function-return +{ + printf("pid %s return %s depth %d\n", + copyinstr(arg0), copyinstr(arg1), arg2); +} + +erlang*:::bif-entry +{ + printf("pid %s BIF entry mfa %s\n", copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::bif-return +{ + printf("pid %s BIF return mfa %s\n", copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::nif-entry +{ + printf("pid %s NIF entry mfa %s\n", copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::nif-return +{ + printf("pid %s NIF return mfa %s\n", copyinstr(arg0), copyinstr(arg1)); +} diff --git a/lib/runtime_tools/examples/function-calls.systemtap b/lib/runtime_tools/examples/function-calls.systemtap new file mode 100644 index 0000000000..16c9c04918 --- /dev/null +++ b/lib/runtime_tools/examples/function-calls.systemtap @@ -0,0 +1,67 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. 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% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("local-function-entry") +{ + printf("pid %s enter (local) %s depth %d\n", + user_string($arg1), user_string($arg2), $arg3); +} + +probe process("beam").mark("global-function-entry") +{ + printf("pid %s enter (global) %s depth %d\n", + user_string($arg1), user_string($arg2), $arg3); +} + +probe process("beam").mark("function-return") +{ + printf("pid %s return %s depth %d\n", + user_string($arg1), user_string($arg2), $arg3); +} + +probe process("beam").mark("bif-entry") +{ + printf("pid %s BIF entry mfa %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("beam").mark("bif-return") +{ + printf("pid %s BIF return mfa %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("beam").mark("nif-entry") +{ + printf("pid %s NIF entry mfa %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("beam").mark("nif-return") +{ + printf("pid %s NIF return mfa %s\n", user_string($arg1), user_string($arg2)); +} diff --git a/lib/runtime_tools/examples/garbage-collection.d b/lib/runtime_tools/examples/garbage-collection.d new file mode 100644 index 0000000000..f234e7d4db --- /dev/null +++ b/lib/runtime_tools/examples/garbage-collection.d @@ -0,0 +1,39 @@ +/* example usage: dtrace -q -s /path/to/garbage-collection.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. 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% + */ + +erlang*:::gc_major-start +{ + printf("GC major start pid %s need %d words\n", copyinstr(arg0), arg1); +} + +erlang*:::gc_minor-start +{ + printf("GC minor start pid %s need %d words\n", copyinstr(arg0), arg1); +} + +erlang*:::gc_major-end +{ + printf("GC major end pid %s reclaimed %d words\n", copyinstr(arg0), arg1); +} + +erlang*:::gc_minor-start +{ + printf("GC minor end pid %s reclaimed %d words\n", copyinstr(arg0), arg1); +} diff --git a/lib/runtime_tools/examples/garbage-collection.systemtap b/lib/runtime_tools/examples/garbage-collection.systemtap new file mode 100644 index 0000000000..64d69c6fbd --- /dev/null +++ b/lib/runtime_tools/examples/garbage-collection.systemtap @@ -0,0 +1,49 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. 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% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("gc_major-start") +{ + printf("GC major start pid %s need %d words\n", user_string($arg1), $arg2); +} + +probe process("beam").mark("gc_minor-start") +{ + printf("GC minor start pid %s need %d words\n", user_string($arg1), $arg2); +} + +probe process("beam").mark("gc_major-end") +{ + printf("GC major end pid %s reclaimed %d words\n", user_string($arg1), $arg2); +} + +probe process("beam").mark("gc_minor-start") +{ + printf("GC minor end pid %s reclaimed %d words\n", user_string($arg1), $arg2); +} diff --git a/lib/runtime_tools/examples/memory1.d b/lib/runtime_tools/examples/memory1.d new file mode 100644 index 0000000000..c2e16e0779 --- /dev/null +++ b/lib/runtime_tools/examples/memory1.d @@ -0,0 +1,41 @@ +/* example usage: dtrace -q -s /path/to/memory1.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. 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% + */ + +erlang*:::copy-struct +{ + printf("copy_struct %d bytes\n", arg0); +} + +erlang*:::copy-object +{ + printf("copy_object pid %s %d bytes\n", copyinstr(arg0), arg1); +} + +erlang*:::process-heap_grow +{ + printf("proc heap grow pid %s %d -> %d bytes\n", copyinstr(arg0), + arg1, arg2); +} + +erlang*:::process-heap_shrink +{ + printf("proc heap shrink pid %s %d -> %d bytes\n", copyinstr(arg0), + arg1, arg2); +} diff --git a/lib/runtime_tools/examples/memory1.systemtap b/lib/runtime_tools/examples/memory1.systemtap new file mode 100644 index 0000000000..9723f2d02d --- /dev/null +++ b/lib/runtime_tools/examples/memory1.systemtap @@ -0,0 +1,51 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. 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% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("copy-struct") +{ + printf("copy_struct %d bytes\n", $arg1); +} + +probe process("beam").mark("copy-object") +{ + printf("copy_object pid %s %d bytes\n", user_string($arg1), $arg2); +} + +probe process("beam").mark("process-heap_grow") +{ + printf("proc heap grow pid %s %d -> %d bytes\n", user_string($arg1), + $arg2, $arg3); +} + +probe process("beam").mark("process-heap_shrink") +{ + printf("proc heap shrink pid %s %d -> %d bytes\n", user_string($arg1), + $arg2, $arg3); +} diff --git a/lib/runtime_tools/examples/messages.d b/lib/runtime_tools/examples/messages.d new file mode 100644 index 0000000000..6361f3a220 --- /dev/null +++ b/lib/runtime_tools/examples/messages.d @@ -0,0 +1,94 @@ +/* example usage: dtrace -q -s /path/to/messages.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. 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% + */ + +BEGIN +{ + printf("\n"); + printf("NOTE: message-queue message size 4294967295 means an external\n"); + printf(" message that the code isn't smart enough to determine\n"); + printf(" the actual size.\n"); + printf("\n"); +} + +erlang*:::message-send +/arg3 == 0 && arg4 == 0 && arg5 == 0/ +{ + printf("send: %s -> %s: %d words\n", + copyinstr(arg0), copyinstr(arg1), arg2); +} + +erlang*:::message-send +/arg3 != 0 || arg4 != 0 || arg5 != 0/ +{ + printf("send: %s label %d token {%d,%d} -> %s: %d words\n", + copyinstr(arg0), + arg3, arg4, arg5, + copyinstr(arg1), arg2); +} + +/* + * TODO: + * Weird, on my OS X box, beam says arg6 = 0 but this script says 4294967296. + */ + +erlang*:::message-send-remote +/arg4 == 0 && arg5 == 0 && (arg6 == 0 || arg6 >= 4294967296)/ +{ + printf("send : %s -> %s %s: %d words\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); +} + +erlang*:::message-send-remote +/arg4 != 0 || arg5 != 0 || arg6 < 4294967296/ +{ + printf("send : %s label %d token {%d,%d} -> %s %s: %d words\n", + copyinstr(arg0), + arg4, arg5, arg6, + copyinstr(arg1), copyinstr(arg2), arg3); +} + +erlang*:::message-queued +/arg3 == 0 && arg4 == 0 && arg5 == 0/ +{ + printf("queued: %s: %d words, queue len %d\n", copyinstr(arg0), arg1, arg2); +} + +erlang*:::message-queued +/arg3 != 0 || arg4 != 0 || arg5 != 0/ +{ + printf("queued: %s label %d token {%d,%d}: %d words, queue len %d\n", + copyinstr(arg0), arg3, arg4, arg5, + arg1, arg2); +} + +erlang*:::message-receive +/arg3 == 0 && arg4 == 0 && arg5 == 0/ +{ + printf("receive: %s: %d words, queue len %d\n", + copyinstr(arg0), arg1, arg2); +} + +erlang*:::message-receive +/arg3 != 0 || arg4 != 0 || arg5 != 0/ +{ + printf("receive: %s label %d token {%d,%d}: %d words, queue len %d\n", + copyinstr(arg0), arg3, arg4, arg5, + arg1, arg2); +} diff --git a/lib/runtime_tools/examples/messages.systemtap b/lib/runtime_tools/examples/messages.systemtap new file mode 100644 index 0000000000..ff8f4076b1 --- /dev/null +++ b/lib/runtime_tools/examples/messages.systemtap @@ -0,0 +1,87 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. 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% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe begin +{ + printf("\n"); + printf("NOTE: message-queue message size 4294967295 means an external\n"); + printf(" message that the code isn't smart enough to determine\n"); + printf(" the actual size.\n"); + printf("\n"); +} + +probe process("beam").mark("message-send") +{ + if ($arg4 == 0 && $arg5 == 0 && $arg6 == 0) { + printf("send: %s -> %s: %d words\n", + user_string($arg1), user_string($arg2), $arg3); + } else { + printf("send: %s label %d token {%d,%d} -> %s: %d words\n", + user_string($arg1), + $arg4, $arg5, $arg6, + user_string($arg2), $arg3); + } +} + +probe process("beam").mark("message-send-remote") +{ + if ($arg5 == 0 && $arg6 == 0 && $arg7 == 0) { + printf("send : %s -> %s %s: %d words\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4); + } else { + printf("send : %s label %d token {%d,%d} -> %s %s: %d words\n", + user_string($arg1), + $arg5, $arg6, $arg7, + user_string($arg2), user_string($arg3), $arg4); + } +} + +probe process("beam").mark("message-queued") +{ + if ($arg4 == 0 && $arg5 == 0 && $arg6 == 0) { + printf("queued: %s: %d words, queue len %d\n", user_string($arg1), $arg2, $arg3); + } else { + printf("queued: %s label %d token {%d,%d}: %d words, queue len %d\n", + user_string($arg1), $arg4, $arg5, $arg6, + $arg2, $arg3); + } +} + +probe process("beam").mark("message-receive") +{ + if ($arg4 == 0 && $arg5 == 0 && $arg6 == 0) { + printf("receive: %s: %d words, queue len %d\n", + user_string($arg1), $arg2, $arg3); + } else { + printf("receive: %s label %d token {%d,%d}: %d words, queue len %d\n", + user_string($arg1), $arg4, $arg5, $arg6, + $arg2, $arg3); + } +} diff --git a/lib/runtime_tools/examples/port1.d b/lib/runtime_tools/examples/port1.d new file mode 100644 index 0000000000..204abbd3b8 --- /dev/null +++ b/lib/runtime_tools/examples/port1.d @@ -0,0 +1,142 @@ +/* example usage: dtrace -q -s /path/to/port1.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. 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% + */ + +BEGIN +{ + driver_map["tcp_inet", 1] = "OPEN"; + driver_map["tcp_inet", 2] = "CLOSE"; + driver_map["tcp_inet", 3] = "CONNECT"; + driver_map["tcp_inet", 4] = "PEER"; + driver_map["tcp_inet", 5] = "NAME"; + driver_map["tcp_inet", 6] = "BIND"; + driver_map["tcp_inet", 7] = "SETOPTS"; + driver_map["tcp_inet", 8] = "GETOPTS"; + driver_map["tcp_inet", 11] = "GETSTAT"; + driver_map["tcp_inet", 12] = "GETHOSTNAME"; + driver_map["tcp_inet", 13] = "FDOPEN"; + driver_map["tcp_inet", 14] = "GETFD"; + driver_map["tcp_inet", 15] = "GETTYPE"; + driver_map["tcp_inet", 16] = "GETSTATUS"; + driver_map["tcp_inet", 17] = "GETSERVBYNAME"; + driver_map["tcp_inet", 18] = "GETSERVBYPORT"; + driver_map["tcp_inet", 19] = "SETNAME"; + driver_map["tcp_inet", 20] = "SETPEER"; + driver_map["tcp_inet", 21] = "GETIFLIST"; + driver_map["tcp_inet", 22] = "IFGET"; + driver_map["tcp_inet", 23] = "IFSET"; + driver_map["tcp_inet", 24] = "SUBSCRIBE"; + driver_map["tcp_inet", 25] = "GETIFADDRS"; + driver_map["tcp_inet", 40] = "ACCEPT"; + driver_map["tcp_inet", 41] = "LISTEN"; + driver_map["tcp_inet", 42] = "RECV"; + driver_map["tcp_inet", 43] = "UNRECV"; + driver_map["tcp_inet", 44] = "SHUTDOWN"; + driver_map["tcp_inet", 60] = "RECV"; + driver_map["tcp_inet", 61] = "LISTEN"; + driver_map["tcp_inet", 62] = "BINDX"; + /* No looping constructs, so repeat for udp_inet */ + driver_map["udp_inet", 1] = "OPEN"; + driver_map["udp_inet", 2] = "CLOSE"; + driver_map["udp_inet", 3] = "CONNECT"; + driver_map["udp_inet", 4] = "PEER"; + driver_map["udp_inet", 5] = "NAME"; + driver_map["udp_inet", 6] = "BIND"; + driver_map["udp_inet", 7] = "SETOPTS"; + driver_map["udp_inet", 8] = "GETOPTS"; + driver_map["udp_inet", 11] = "GETSTAT"; + driver_map["udp_inet", 12] = "GETHOSTNAME"; + driver_map["udp_inet", 13] = "FDOPEN"; + driver_map["udp_inet", 14] = "GETFD"; + driver_map["udp_inet", 15] = "GETTYPE"; + driver_map["udp_inet", 16] = "GETSTATUS"; + driver_map["udp_inet", 17] = "GETSERVBYNAME"; + driver_map["udp_inet", 18] = "GETSERVBYPORT"; + driver_map["udp_inet", 19] = "SETNAME"; + driver_map["udp_inet", 20] = "SETPEER"; + driver_map["udp_inet", 21] = "GETIFLIST"; + driver_map["udp_inet", 22] = "IFGET"; + driver_map["udp_inet", 23] = "IFSET"; + driver_map["udp_inet", 24] = "SUBSCRIBE"; + driver_map["udp_inet", 25] = "GETIFADDRS"; + driver_map["udp_inet", 40] = "ACCEPT"; + driver_map["udp_inet", 41] = "LISTEN"; + driver_map["udp_inet", 42] = "RECV"; + driver_map["udp_inet", 43] = "UNRECV"; + driver_map["udp_inet", 44] = "SHUTDOWN"; + driver_map["udp_inet", 60] = "RECV"; + driver_map["udp_inet", 61] = "LISTEN"; + driver_map["udp_inet", 62] = "BINDX"; +} + +erlang*:::port-open +{ + printf("port open pid %s port name %s port %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::port-command +{ + printf("port command pid %s port %s port name %s command type %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); +} + +erlang*:::port-control +{ + /* http://dtrace.org/blogs/brendan/2011/11/25/dtrace-variable-types/ */ + this->cmd = driver_map[copyinstr(arg2), arg3]; + this->cmd_str = (this->cmd == 0) ? "unknown" : this->cmd; + printf("port control pid %s port %s port name %s command %d %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3, + this->cmd_str); +} + +/* port-exit is fired as a result of port_close() or exit signal */ + +erlang*:::port-exit +{ + printf("port exit pid %s port %s port name %s reason %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); +} + +erlang*:::port-connect +{ + printf("port connect pid %s port %s port name %s new pid %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); +} + +erlang*:::port-busy +{ + printf("port busy %s\n", copyinstr(arg0)); +} + +erlang*:::port-not_busy +{ + printf("port not busy %s\n", copyinstr(arg0)); +} + +erlang*:::aio_pool-add +{ + printf("async I/O pool add thread %d queue len %d\n", arg0, arg1); +} + +erlang*:::aio_pool-get +{ + printf("async I/O pool get thread %d queue len %d\n", arg0, arg1); +} diff --git a/lib/runtime_tools/examples/port1.systemtap b/lib/runtime_tools/examples/port1.systemtap new file mode 100644 index 0000000000..a63d9b670c --- /dev/null +++ b/lib/runtime_tools/examples/port1.systemtap @@ -0,0 +1,152 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. 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% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe begin +{ + driver_map["tcp_inet", 1] = "OPEN"; + driver_map["tcp_inet", 2] = "CLOSE"; + driver_map["tcp_inet", 3] = "CONNECT"; + driver_map["tcp_inet", 4] = "PEER"; + driver_map["tcp_inet", 5] = "NAME"; + driver_map["tcp_inet", 6] = "BIND"; + driver_map["tcp_inet", 7] = "SETOPTS"; + driver_map["tcp_inet", 8] = "GETOPTS"; + driver_map["tcp_inet", 11] = "GETSTAT"; + driver_map["tcp_inet", 12] = "GETHOSTNAME"; + driver_map["tcp_inet", 13] = "FDOPEN"; + driver_map["tcp_inet", 14] = "GETFD"; + driver_map["tcp_inet", 15] = "GETTYPE"; + driver_map["tcp_inet", 16] = "GETSTATUS"; + driver_map["tcp_inet", 17] = "GETSERVBYNAME"; + driver_map["tcp_inet", 18] = "GETSERVBYPORT"; + driver_map["tcp_inet", 19] = "SETNAME"; + driver_map["tcp_inet", 20] = "SETPEER"; + driver_map["tcp_inet", 21] = "GETIFLIST"; + driver_map["tcp_inet", 22] = "IFGET"; + driver_map["tcp_inet", 23] = "IFSET"; + driver_map["tcp_inet", 24] = "SUBSCRIBE"; + driver_map["tcp_inet", 25] = "GETIFADDRS"; + driver_map["tcp_inet", 40] = "ACCEPT"; + driver_map["tcp_inet", 41] = "LISTEN"; + driver_map["tcp_inet", 42] = "RECV"; + driver_map["tcp_inet", 43] = "UNRECV"; + driver_map["tcp_inet", 44] = "SHUTDOWN"; + driver_map["tcp_inet", 60] = "RECV"; + driver_map["tcp_inet", 61] = "LISTEN"; + driver_map["tcp_inet", 62] = "BINDX"; + /* No looping constructs, so repeat for udp_inet */ + driver_map["udp_inet", 1] = "OPEN"; + driver_map["udp_inet", 2] = "CLOSE"; + driver_map["udp_inet", 3] = "CONNECT"; + driver_map["udp_inet", 4] = "PEER"; + driver_map["udp_inet", 5] = "NAME"; + driver_map["udp_inet", 6] = "BIND"; + driver_map["udp_inet", 7] = "SETOPTS"; + driver_map["udp_inet", 8] = "GETOPTS"; + driver_map["udp_inet", 11] = "GETSTAT"; + driver_map["udp_inet", 12] = "GETHOSTNAME"; + driver_map["udp_inet", 13] = "FDOPEN"; + driver_map["udp_inet", 14] = "GETFD"; + driver_map["udp_inet", 15] = "GETTYPE"; + driver_map["udp_inet", 16] = "GETSTATUS"; + driver_map["udp_inet", 17] = "GETSERVBYNAME"; + driver_map["udp_inet", 18] = "GETSERVBYPORT"; + driver_map["udp_inet", 19] = "SETNAME"; + driver_map["udp_inet", 20] = "SETPEER"; + driver_map["udp_inet", 21] = "GETIFLIST"; + driver_map["udp_inet", 22] = "IFGET"; + driver_map["udp_inet", 23] = "IFSET"; + driver_map["udp_inet", 24] = "SUBSCRIBE"; + driver_map["udp_inet", 25] = "GETIFADDRS"; + driver_map["udp_inet", 40] = "ACCEPT"; + driver_map["udp_inet", 41] = "LISTEN"; + driver_map["udp_inet", 42] = "RECV"; + driver_map["udp_inet", 43] = "UNRECV"; + driver_map["udp_inet", 44] = "SHUTDOWN"; + driver_map["udp_inet", 60] = "RECV"; + driver_map["udp_inet", 61] = "LISTEN"; + driver_map["udp_inet", 62] = "BINDX"; +} + +probe process("beam").mark("port-open") +{ + printf("port open pid %s port name %s port %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("port-command") +{ + printf("port command pid %s port %s port name %s command type %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); +} + +probe process("beam").mark("port-control") +{ + cmd = driver_map[user_string($arg3), $arg4]; + cmd_str = (cmd == "") ? "unknown" : cmd; + printf("port control pid %s port %s port name %s command %d %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4, cmd_str); +} + +/* port-exit is fired as a result of port_close() or exit signal */ + +probe process("beam").mark("port-exit") +{ + printf("port exit pid %s port %s port name %s reason %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); +} + +probe process("beam").mark("port-connect") +{ + printf("port connect pid %s port %s port name %s new pid %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); +} + +probe process("beam").mark("port-busy") +{ + printf("port busy %s\n", user_string($arg1)); +} + +probe process("beam").mark("port-not_busy") +{ + printf("port not busy %s\n", user_string($arg1)); +} + +probe process("beam").mark("aio_pool-add") +{ + printf("async I/O pool add thread %d queue len %d\n", $arg1, $arg2); +} + +probe process("beam").mark("aio_pool-get") +{ + printf("async I/O pool get thread %d queue len %d\n", $arg1, $arg2); +} + +global driver_map;
\ No newline at end of file diff --git a/lib/runtime_tools/examples/process-scheduling.d b/lib/runtime_tools/examples/process-scheduling.d new file mode 100644 index 0000000000..79e9cc598c --- /dev/null +++ b/lib/runtime_tools/examples/process-scheduling.d @@ -0,0 +1,35 @@ +/* example usage: dtrace -q -s /path/to/process-scheduling.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. 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% + */ + +erlang*:::process-scheduled +{ + printf(" Schedule pid %s mfa %s\n", copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::process-unscheduled +{ + printf("Unschedule pid %s\n", copyinstr(arg0)); +} + +erlang*:::process-hibernate +{ + printf(" Hibernate pid %s resume mfa %s\n", + copyinstr(arg0), copyinstr(arg1)); +} diff --git a/lib/runtime_tools/examples/process-scheduling.systemtap b/lib/runtime_tools/examples/process-scheduling.systemtap new file mode 100644 index 0000000000..c8cee60a07 --- /dev/null +++ b/lib/runtime_tools/examples/process-scheduling.systemtap @@ -0,0 +1,45 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. 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% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("process-scheduled") +{ + printf(" Schedule pid %s mfa %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("beam").mark("process-unscheduled") +{ + printf("Unschedule pid %s\n", user_string($arg1)); +} + +probe process("beam").mark("process-hibernate") +{ + printf(" Hibernate pid %s resume mfa %s\n", + user_string($arg1), user_string($arg2)); +} diff --git a/lib/runtime_tools/examples/spawn-exit.d b/lib/runtime_tools/examples/spawn-exit.d new file mode 100644 index 0000000000..7310f3343d --- /dev/null +++ b/lib/runtime_tools/examples/spawn-exit.d @@ -0,0 +1,41 @@ +/* example usage: dtrace -q -s /path/to/spawn-exit.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. 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% + */ + +erlang*:::process-spawn +{ + printf("pid %s mfa %s\n", copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::process-exit +{ + printf("pid %s reason %s\n", copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::process-exit_signal +{ + printf("sender %s -> pid %s reason %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::process-exit_signal-remote +{ + printf("sender %s -> node %s pid %s reason %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); +} diff --git a/lib/runtime_tools/examples/spawn-exit.systemtap b/lib/runtime_tools/examples/spawn-exit.systemtap new file mode 100644 index 0000000000..5e3be9fc1b --- /dev/null +++ b/lib/runtime_tools/examples/spawn-exit.systemtap @@ -0,0 +1,51 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. 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% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("process-spawn") +{ + printf("pid %s mfa %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("beam").mark("process-exit") +{ + printf("pid %s reason %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("beam").mark("process-exit_signal") +{ + printf("sender %s -> pid %s reason %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("process-exit_signal-remote") +{ + printf("sender %s -> node %s pid %s reason %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); +} diff --git a/lib/runtime_tools/examples/user-probe.d b/lib/runtime_tools/examples/user-probe.d new file mode 100644 index 0000000000..13baff6a32 --- /dev/null +++ b/lib/runtime_tools/examples/user-probe.d @@ -0,0 +1,36 @@ +/* example usage: dtrace -q -s /path/to/user-probe.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. 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% + */ + +erlang*:::user_trace-s1 +{ + printf("%s\n", copyinstr(arg0)); +} + +erlang*:::user_trace-i4s4 +{ + printf("%s %s %d %d %d %d '%s' '%s' '%s' '%s'\n", + copyinstr(arg0), + arg1 == NULL ? "" : copyinstr(arg1), + arg2, arg3, arg4, arg5, + arg6 == NULL ? "" : copyinstr(arg6), + arg7 == NULL ? "" : copyinstr(arg7), + arg8 == NULL ? "" : copyinstr(arg8), + arg9 == NULL ? "" : copyinstr(arg9)); +} diff --git a/lib/runtime_tools/examples/user-probe.systemtap b/lib/runtime_tools/examples/user-probe.systemtap new file mode 100644 index 0000000000..84a45709e8 --- /dev/null +++ b/lib/runtime_tools/examples/user-probe.systemtap @@ -0,0 +1,46 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. 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% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("dyntrace.so").mark("user_trace-s1") +{ + printf("%s\n", user_string($arg1)); +} + +probe process("dyntrace.so").mark("user_trace-i4s4") +{ + printf("%s %s %d %d %d %d '%s' '%s' '%s' '%s'\n", + user_string($arg1), + $arg2 == NULL ? "" : user_string($arg2), + $arg3, $arg4, $arg5, $arg6, + $arg7 == NULL ? "" : user_string($arg7), + $arg8 == NULL ? "" : user_string($arg8), + $arg9 == NULL ? "" : user_string($arg9), + $arg9 == NULL ? "" : user_string($arg9)); +} diff --git a/lib/runtime_tools/src/Makefile b/lib/runtime_tools/src/Makefile index 946409b262..6dc89bea32 100644 --- a/lib/runtime_tools/src/Makefile +++ b/lib/runtime_tools/src/Makefile @@ -45,6 +45,7 @@ MODULES= \ runtime_tools \ runtime_tools_sup \ dbg \ + dyntrace \ percept_profile \ observer_backend \ ttb_autostart @@ -64,10 +65,15 @@ APPUP_FILE= runtime_tools.appup APPUP_SRC= $(APPUP_FILE).src APPUP_TARGET= $(EBIN)/$(APPUP_FILE) +EXAMPLE_FILES= \ + ../examples/* # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- -ERL_COMPILE_FLAGS += -I../include +ERL_COMPILE_FLAGS += \ + -I../include \ + -I ../../et/include \ + -I ../../../libraries/et/include # ---------------------------------------------------- # Targets @@ -97,6 +103,8 @@ release_spec: opt $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src $(INSTALL_DIR) $(RELSYSDIR)/include $(INSTALL_DATA) $(HRL_FILES) $(RELSYSDIR)/include + $(INSTALL_DIR) $(RELSYSDIR)/examples + $(INSTALL_DATA) $(EXAMPLE_FILES) $(RELSYSDIR)/examples $(INSTALL_DIR) $(RELSYSDIR)/ebin $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin diff --git a/lib/runtime_tools/src/dyntrace.erl b/lib/runtime_tools/src/dyntrace.erl new file mode 100644 index 0000000000..388c7679b9 --- /dev/null +++ b/lib/runtime_tools/src/dyntrace.erl @@ -0,0 +1,279 @@ +-module(dyntrace). + +%%% @doc The Dynamic tracing interface module +%%% +%%% This Dynamic tracing interface module, with the corresponding NIFs, should +%%% work on any operating system platform where user-space DTrace/Systemtap +%%% (and in the future LttNG UST) probes are supported. +%%% +%%% Use the `dyntrace:init()' function to load the NIF shared library and +%%% to initialize library's private state. +%%% +%%% It is recommended that you use the `dyntrace:p()' function to add +%%% Dynamic trace probes to your Erlang code. This function can accept up to +%%% four integer arguments and four string arguments; the integer +%%% argument(s) must come before any string argument. For example: +%%% ``` +%%% 1> dyntrace:put_tag("GGOOOAAALL!!!!!"). +%%% true +%%% 2> dyntrace:init(). +%%% ok +%%% +%%% % % % If using dtrace, enable the Dynamic trace probe using the 'dtrace' +%%% % % % command. +%%% +%%% 3> dyntrace:p(7, 8, 9, "one", "four"). +%%% true +%%% ''' +%%% +%%% Output from the example D script `user-probe.d' looks like: +%%% ``` +%%% <0.34.0> GGOOOAAALL!!!!! 7 8 9 0 'one' 'four' '' '' +%%% ''' +%%% +%%% If the expected type of variable is not present, e.g. integer when +%%% integer() is expected, or an I/O list when iolist() is expected, +%%% then the driver will ignore the user's input and use a default +%%% value of 0 or NULL, respectively. + +-export([available/0, + user_trace_s1/1, % TODO: unify with pid & tag args like user_trace_i4s4 + p/0, p/1, p/2, p/3, p/4, p/5, p/6, p/7, p/8]). +-export([put_tag/1, get_tag/0, get_tag_data/0, spread_tag/1, restore_tag/1]). + +-export([scaff/0]). % Development only +-export([user_trace_i4s4/9]). % Know what you're doing! +-on_load(on_load/0). + +-type probe_arg() :: integer() | iolist(). +-type int_p_arg() :: integer() | iolist() | undef. + +%% The *_maybe() types use atom() instead of a stricter 'undef' +%% because user_trace_i4s4/9 is exposed to the outside world, and +%% because the driver will allow any atom to be used as a "not +%% present" indication, we'll allow any atom in the types. + +-type integer_maybe() :: integer() | atom(). +-type iolist_maybe() :: iolist() | atom(). + +on_load() -> + PrivDir = code:priv_dir(runtime_tools), + LibName = "dyntrace", + Lib = filename:join([PrivDir, "lib", LibName]), + Status = case erlang:load_nif(Lib, 0) of + ok -> ok; + {error, {load_failed, _}}=Error1 -> + ArchLibDir = + filename:join([PrivDir, "lib", + erlang:system_info(system_architecture)]), + Candidate = + filelib:wildcard(filename:join([ArchLibDir,LibName ++ "*" ])), + case Candidate of + [] -> Error1; + _ -> + ArchLib = filename:join([ArchLibDir, LibName]), + erlang:load_nif(ArchLib, 0) + end; + Error1 -> Error1 + end, + case Status of + ok -> ok; + {error, {E, Str}} -> + case erlang:system_info(dynamic_trace) of + none -> + ok; + _ -> + error_logger:error_msg("Unable to load dyntrace library. Failed with error:~n +\"~p, ~s\"~n" + "Dynamic tracing is enabled but the driver is not built correctly~n",[ + E,Str]), + Status + end + end. + +%%% +%%% NIF placeholders +%%% + +-spec available() -> true | false. + +available() -> + erlang:nif_error(nif_not_loaded). + +-spec user_trace_s1(iolist()) -> true | false | error | badarg. + +user_trace_s1(_Message) -> + erlang:nif_error(nif_not_loaded). + +-spec user_trace_i4s4(iolist(), + integer_maybe(), integer_maybe(), + integer_maybe(), integer_maybe(), + iolist_maybe(), iolist_maybe(), + iolist_maybe(), iolist_maybe()) -> + true | false | error | badarg. + +user_trace_i4s4(_, _, _, _, _, _, _, _, _) -> + erlang:nif_error(nif_not_loaded). + +%%% +%%% Erlang support functions +%%% + +-spec p() -> true | false | error | badarg. + +p() -> + user_trace_int(undef, undef, undef, undef, undef, undef, undef, undef). + +-spec p(probe_arg()) -> true | false | error | badarg. + +p(I1) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, undef, undef, undef, undef); +p(S1) -> + user_trace_int(undef, undef, undef, undef, S1, undef, undef, undef). + +-spec p(probe_arg(), probe_arg()) -> true | false | error | badarg. + +p(I1, I2) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, undef, undef, undef, undef); +p(I1, S1) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, undef, undef, undef); +p(S1, S2) -> + user_trace_int(undef, undef, undef, undef, S1, S2, undef, undef). + +-spec p(probe_arg(), probe_arg(), probe_arg()) -> true | false | error | badarg. + +p(I1, I2, I3) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, undef, undef, undef, undef); +p(I1, I2, S1) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, undef, undef, undef); +p(I1, S1, S2) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, S2, undef, undef); +p(S1, S2, S3) -> + user_trace_int(undef, undef, undef, undef, S1, S2, S3, undef). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, undef, undef, undef, undef); +p(I1, I2, I3, S1) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, undef, undef, undef); +p(I1, I2, S1, S2) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, S2, undef, undef); +p(I1, S1, S2, S3) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, S2, S3, undef); +p(S1, S2, S3, S4) -> + user_trace_int(undef, undef, undef, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, undef, undef, undef); +p(I1, I2, I3, S1, S2) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, S2, undef, undef); +p(I1, I2, S1, S2, S3) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, S2, S3, undef); +p(I1, S1, S2, S3, S4) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1, S2) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, S2, undef, undef); +p(I1, I2, I3, S1, S2, S3) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, S2, S3, undef); +p(I1, I2, S1, S2, S3, S4) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg(), probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1, S2, S3) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, S2, S3, undef); +p(I1, I2, I3, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg(), probe_arg(), probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4). + +-spec user_trace_int(int_p_arg(), int_p_arg(), int_p_arg(), int_p_arg(), + int_p_arg(), int_p_arg(), int_p_arg(), int_p_arg()) -> + true | false | error | badarg. + +user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4) -> + UTag = get_tag(), + try + user_trace_i4s4(UTag, I1, I2, I3, I4, S1, S2, S3, S4) + catch + error:nif_not_loaded -> + false + end. + +-spec put_tag(undefined | iodata()) -> binary() | undefined. +put_tag(Data) -> + erlang:dt_put_tag(unicode:characters_to_binary(Data)). + +-spec get_tag() -> binary() | undefined. +get_tag() -> + erlang:dt_get_tag(). + +-spec get_tag_data() -> binary() | undefined. +%% Gets tag if set, otherwise the spread tag data from last incoming message +get_tag_data() -> + erlang:dt_get_tag_data(). + +-spec spread_tag(boolean()) -> true | {non_neg_integer(), binary() | []}. +%% Makes the tag behave as a sequential trace token, will spread with +%% messages to be picked up by someone using get_tag_data +spread_tag(B) -> + erlang:dt_spread_tag(B). + +-spec restore_tag(true | {non_neg_integer(), binary() | []}) -> true. +restore_tag(T) -> + erlang:dt_restore_tag(T). + + +%% Scaffolding to write tedious code: quick brute force and not 100% correct. + +scaff_int_args(N) -> + L = lists:sublist(["I1", "I2", "I3", "I4"], N), + [string:join(L, ", ")]. + +scaff_int_guards(N) -> + L = lists:sublist(["is_integer(I1)", "is_integer(I2)", "is_integer(I3)", + "is_integer(I4)"], N), + lists:flatten(string:join(L, ", ")). + +scaff_char_args(N) -> + L = lists:sublist(["S1", "S2", "S3", "S4"], N), + [string:join(L, ", ")]. + +scaff_fill(N) -> + [string:join(lists:duplicate(N, "undef"), ", ")]. + +scaff() -> + L = [begin + IntArgs = scaff_int_args(N_int), + IntGuards = scaff_int_guards(N_int), + IntFill = scaff_fill(4 - N_int), + CharArgs = scaff_char_args(N_char), + CharFill = scaff_fill(4 - N_char), + InArgs = string:join(IntArgs ++ CharArgs, ", "), + OutArgs = string:join(IntArgs ++ IntFill ++ CharArgs ++ CharFill, + ", "), + {N_int + N_char, + lists:flatten([io_lib:format("p(~s) when ~s ->\n", + [InArgs, IntGuards]), + io_lib:format(" user_trace_int(~s);\n", [OutArgs]) + ])} + end || N_int <- [0,1,2,3,4], N_char <- [0,1,2,3,4]], + [io:format("%%~p\n~s", [N, Str]) || {N, Str} <- lists:sort(L)]. diff --git a/lib/runtime_tools/src/runtime_tools.app.src b/lib/runtime_tools/src/runtime_tools.app.src index 76fd998530..a9d2d68857 100644 --- a/lib/runtime_tools/src/runtime_tools.app.src +++ b/lib/runtime_tools/src/runtime_tools.app.src @@ -23,7 +23,7 @@ inviso_rt,inviso_rt_lib,inviso_rt_meta, inviso_as_lib,inviso_autostart,inviso_autostart_server, runtime_tools,runtime_tools_sup,erts_alloc_config, - ttb_autostart]}, + ttb_autostart,dyntrace]}, {registered, [runtime_tools_sup,inviso_rt,inviso_rt_meta]}, {applications, [kernel, stdlib]}, % {env, [{inviso_autostart_mod,your_own_autostart_module}]}, diff --git a/lib/sasl/doc/src/rel.xml b/lib/sasl/doc/src/rel.xml index 470adf3c03..68ef90330f 100644 --- a/lib/sasl/doc/src/rel.xml +++ b/lib/sasl/doc/src/rel.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>1997</year> - <year>2011</year> + <year>2012</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -88,7 +88,7 @@ <p>The list must be a subset of the included applications specified in the application resource file (<c>Application.app</c>) and overrides this value. Defaults - to the empty list.</p> + to the same value as in the application resource file.</p> </item> </list> <note> diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl index 12ba2a5476..3c1002e4a6 100644 --- a/lib/sasl/src/systools_make.erl +++ b/lib/sasl/src/systools_make.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 @@ -375,7 +375,7 @@ get_release1(File, Path, ModTestP, Machine) -> {ok, Release, Warnings1} = read_release(File, Path), {ok, Appls0} = collect_applications(Release, Path), {ok, Appls1} = check_applications(Appls0), - {ok, Appls2} = sort_included_applications(Appls1, Release), % OTP-4121 + {ok, Appls2} = sort_used_and_incl_appls(Appls1, Release), % OTP-4121, OTP-9984 {ok, Warnings2} = check_modules(Appls2, Path, ModTestP, Machine), {ok, Appls} = sort_appls(Appls2), {ok, Release, Appls, Warnings1 ++ Warnings2}. @@ -842,34 +842,45 @@ undefined_applications(Appls) -> filter(fun(X) -> not member(X, Defined) end, Uses). %%______________________________________________________________________ -%% sort_included_applications(Applications, Release) -> Applications +%% sort_used_and_incl_appls(Applications, Release) -> Applications %% Applications = [{{Name,Vsn},#application}] %% Release = #release{} %% -%% Check that included applications are given in the same order as in -%% the release resource file (.rel). Otherwise load instructions in -%% the boot script, and consequently release upgrade instructions in -%% relup, may end up in the wrong order. +%% OTP-4121, OTP-9984 +%% Check that used and included applications are given in the same +%% order as in the release resource file (.rel). Otherwise load and +%% start instructions in the boot script, and consequently release +%% upgrade instructions in relup, may end up in the wrong order. -sort_included_applications(Applications, Release) when is_tuple(Release) -> +sort_used_and_incl_appls(Applications, Release) when is_tuple(Release) -> {ok, - sort_included_applications(Applications, Release#release.applications)}; - -sort_included_applications([{Tuple,Appl}|Appls], OrderedAppls) -> - case Appl#application.includes of - Incls when length(Incls)>1 -> - IndexedIncls = find_pos(Incls, OrderedAppls), - SortedIndexedIncls = lists:keysort(1, IndexedIncls), - Incls2 = lists:map(fun({_Index,Name}) -> Name end, - SortedIndexedIncls), - Appl2 = Appl#application{includes=Incls2}, - [{Tuple,Appl2}|sort_included_applications(Appls, OrderedAppls)]; - _Incls -> - [{Tuple,Appl}|sort_included_applications(Appls, OrderedAppls)] - end; -sort_included_applications([], _OrderedAppls) -> + sort_used_and_incl_appls(Applications, Release#release.applications)}; + +sort_used_and_incl_appls([{Tuple,Appl}|Appls], OrderedAppls) -> + Incls2 = + case Appl#application.includes of + Incls when length(Incls)>1 -> + sort_appl_list(Incls, OrderedAppls); + Incls -> + Incls + end, + Uses2 = + case Appl#application.uses of + Uses when length(Uses)>1 -> + sort_appl_list(Uses, OrderedAppls); + Uses -> + Uses + end, + Appl2 = Appl#application{includes=Incls2, uses=Uses2}, + [{Tuple,Appl2}|sort_used_and_incl_appls(Appls, OrderedAppls)]; +sort_used_and_incl_appls([], _OrderedAppls) -> []. +sort_appl_list(List, Order) -> + IndexedList = find_pos(List, Order), + SortedIndexedList = lists:keysort(1, IndexedList), + lists:map(fun({_Index,Name}) -> Name end, SortedIndexedList). + find_pos([Name|Incs], OrderedAppls) -> [find_pos(1, Name, OrderedAppls)|find_pos(Incs, OrderedAppls)]; find_pos([], _OrderedAppls) -> @@ -1253,7 +1264,8 @@ sort_appls(Appls) -> {ok, sort_appls(Appls, [], [], [])}. sort_appls([{N, A}|T], Missing, Circular, Visited) -> {Name,_Vsn} = N, - {Uses, T1, NotFnd1} = find_all(Name, A#application.uses, T, Visited, [], []), + {Uses, T1, NotFnd1} = find_all(Name, lists:reverse(A#application.uses), + T, Visited, [], []), {Incs, T2, NotFnd2} = find_all(Name, lists:reverse(A#application.includes), T1, Visited, [], []), Missing1 = NotFnd1 ++ NotFnd2 ++ Missing, diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl index 4cf7364d74..72b3eb8954 100644 --- a/lib/sasl/test/systools_SUITE.erl +++ b/lib/sasl/test/systools_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011. All Rights Reserved. +%% 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 @@ -45,7 +45,7 @@ abnormal_script/1, src_tests_script/1, crazy_script/1, included_script/1, included_override_script/1, included_fail_script/1, included_bug_script/1, exref_script/1, - otp_3065_circular_dependenies/1]). + otp_3065_circular_dependenies/1, included_and_used_sort_script/1]). -export([tar_options/1, normal_tar/1, no_mod_vsn_tar/1, system_files_tar/1, system_files_tar/2, invalid_system_files_tar/1, invalid_system_files_tar/2, variable_tar/1, @@ -80,7 +80,7 @@ groups() -> no_sasl_script, src_tests_script, crazy_script, included_script, included_override_script, included_fail_script, included_bug_script, exref_script, - otp_3065_circular_dependenies]}, + otp_3065_circular_dependenies, included_and_used_sort_script]}, {tar, [], [tar_options, normal_tar, no_mod_vsn_tar, system_files_tar, invalid_system_files_tar, variable_tar, @@ -600,6 +600,24 @@ otp_3065_circular_dependenies(Config) when is_list(Config) -> ok = file:set_cwd(OldDir), ok. +%% Test sorting of included applications and used applications +included_and_used_sort_script(Config) when is_list(Config) -> + {ok, OldDir} = file:get_cwd(), + {LatestDir1, LatestName1} = create_include_files(sort_apps, Config), + ok = file:set_cwd(LatestDir1), + ok = systools:make_script(LatestName1), + ok = check_include_script(LatestName1, + [t20,t19,t18,t17,t16,t15,t14],[t20,t19,t18,t14]), + + {LatestDir2, LatestName2} = create_include_files(sort_apps_rev, Config), + ok = file:set_cwd(LatestDir2), + ok = systools:make_script(LatestName2), + ok = check_include_script(LatestName2, + [t18,t19,t20,t15,t16,t17,t14],[t18,t19,t20,t14]), + + ok = file:set_cwd(OldDir), + ok. + %% make_script: Check that make_script exref option works. exref_script(Config) when is_list(Config) -> @@ -2301,8 +2319,53 @@ create_include_files(otp_3065_circular_dependenies, Config) -> " {chAts, \"1.0\"}, {aa12, \"1.0\"}, \n" " {chTraffic, \"1.0\"}]}.\n", file:write_file(Name ++ ".rel", list_to_binary(Rel)), + {filename:dirname(Name), filename:basename(Name)}; + +create_include_files(sort_apps, Config) -> + PrivDir = ?privdir, + Name = fname(PrivDir, sort_apps), + create_sort_apps(PrivDir), + + Apps = application_controller:which_applications(), + {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + + Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\n" + " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" + ++ StdlibVer ++ "\"},\n" + " {t14, \"1.0\"}, \n" + " {t20, \"1.0\"}, \n" + " {t19, \"1.0\"}, \n" + " {t18, \"1.0\"}, \n" + " {t17, \"1.0\"}, \n" + " {t16, \"1.0\"}, \n" + " {t15, \"1.0\"}]}.\n", + file:write_file(Name ++ ".rel", list_to_binary(Rel)), + {filename:dirname(Name), filename:basename(Name)}; + +create_include_files(sort_apps_rev, Config) -> + PrivDir = ?privdir, + Name = fname(PrivDir, sort_apps_rev), + create_sort_apps(PrivDir), + + Apps = application_controller:which_applications(), + {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + + Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\n" + " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" + ++ StdlibVer ++ "\"},\n" + " {t14, \"1.0\"}, \n" + " {t18, \"1.0\"}, \n" + " {t19, \"1.0\"}, \n" + " {t20, \"1.0\"}, \n" + " {t15, \"1.0\"}, \n" + " {t16, \"1.0\"}, \n" + " {t17, \"1.0\"}]}.\n", + file:write_file(Name ++ ".rel", list_to_binary(Rel)), {filename:dirname(Name), filename:basename(Name)}. + create_apps(Dir) -> T1 = "{application, t1,\n" " [{vsn, \"1.0\"},\n" @@ -2451,6 +2514,70 @@ create_apps_3065(Dir) -> " {registered, []}]}.\n", file:write_file(fname(Dir, 'aa12.app'), list_to_binary(T13)). +create_sort_apps(Dir) -> + T14 = "{application, t14,\n" + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, [t18,t20,t19]},\n" + " {included_applications, [t15,t17,t16]},\n" + " {registered, []}]}.\n", + file:write_file(fname(Dir, 't14.app'), list_to_binary(T14)), + + T15 = "{application, t15,\n" + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, []},\n" + " {registered, []}]}.\n", + file:write_file(fname(Dir, 't15.app'), list_to_binary(T15)), + + T16 = "{application, t16,\n" + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, []},\n" + " {registered, []}]}.\n", + file:write_file(fname(Dir, 't16.app'), list_to_binary(T16)), + + T17 = "{application, t17,\n" + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, []},\n" + " {registered, []}]}.\n", + file:write_file(fname(Dir, 't17.app'), list_to_binary(T17)), + + T18 = "{application, t18,\n" + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, []},\n" + " {registered, []}]}.\n", + file:write_file(fname(Dir, 't18.app'), list_to_binary(T18)), + + T19 = "{application, t19,\n" + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, []},\n" + " {registered, []}]}.\n", + file:write_file(fname(Dir, 't19.app'), list_to_binary(T19)), + + T20 = "{application, t20,\n" + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, []},\n" + " {registered, []}]}.\n", + file:write_file(fname(Dir, 't20.app'), list_to_binary(T20)). + fname(N) -> filename:join(N). diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src index 21a0582c06..0542054596 100644 --- a/lib/ssh/src/ssh.appup.src +++ b/lib/ssh/src/ssh.appup.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-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 @@ -18,26 +18,12 @@ %% {"%VSN%", - [ - {"2.0.8", [{load_module, ssh_sftpd_file_api, soft_purge, soft_purge, []}, - {load_module, ssh_channel, soft_purge, soft_purge, []}]}, - {"2.0.7", [{load_module, ssh_sftp, soft_purge, soft_purge, []}]}, - {"2.0.6", [{load_module, ssh_userreg, soft_purge, soft_purge, []}, - {load_module, ssh_sftp, soft_purge, soft_purge, []}]}, - {"2.0.5", [{load_module, ssh_userreg, soft_purge, soft_purge, []}, - {load_module, ssh_sftp, soft_purge, soft_purge, []}, - {load_module, ssh_connection_handler, soft_purge, soft_purge, [ssh_userreg]}]} + [ + {<<"2\\.*">>, [{restart_application, ssh}]}, + {<<"1\\.*">>, [{restart_application, ssh}]} ], [ - {"2.0.8", [{load_module, ssh_sftpd_file_api, soft_purge, soft_purge, []}, - {load_module, ssh_channel, soft_purge, soft_purge, []}]}, - {"2.0.7", [{load_module, ssh_sftp, soft_purge, soft_purge, []}]}, - {"2.0.6", [{load_module, ssh_userreg, soft_purge, soft_purge, []}, - {load_module, ssh_sftp, soft_purge, soft_purge, []}]}, - {"2.0.5", [{load_module, ssh_userreg, soft_purge, soft_purge, []}, - {load_module, ssh_sftp, soft_purge, soft_purge, []}, - {load_module, ssh_connection_handler, soft_purge, soft_purge, [ssh_userreg]}]} + {<<"2\\.*">>, [{restart_application, ssh}]}, + {<<"1\\.*">>, [{restart_application, ssh}]} ] }. - - diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk index 42f860d6ae..bff73a1b40 100644 --- a/lib/ssh/vsn.mk +++ b/lib/ssh/vsn.mk @@ -1,5 +1,5 @@ #-*-makefile-*- ; force emacs to enter makefile-mode -SSH_VSN = 2.0.9 +SSH_VSN = 2.1 APP_VSN = "ssh-$(SSH_VSN)" diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src index 1b07e76d6a..e346b1e9e6 100644 --- a/lib/ssl/src/ssl.appup.src +++ b/lib/ssl/src/ssl.appup.src @@ -1,23 +1,13 @@ %% -*- erlang -*- {"%VSN%", [ - {"4.1.6", [{restart_application, ssl}]}, - {"4.1.5", [{restart_application, ssl}]}, - {"4.1.4", [{restart_application, ssl}]}, - {"4.1.3", [{restart_application, ssl}]}, - {"4.1.2", [{restart_application, ssl}]}, - {"4.1.1", [{restart_application, ssl}]}, - {"4.1", [{restart_application, ssl}]}, - {"4.0.1", [{restart_application, ssl}]} + {"5.0", [{restart_application, ssl}]}, + {<<"4\\.*">>, [{restart_application, ssl}]}, + {<<"3\\.*">>, [{restart_application, ssl}]} ], [ - {"4.1.6", [{restart_application, ssl}]}, - {"4.1.5", [{restart_application, ssl}]}, - {"4.1.4", [{restart_application, ssl}]}, - {"4.1.3", [{restart_application, ssl}]}, - {"4.1.2", [{restart_application, ssl}]}, - {"4.1.1", [{restart_application, ssl}]}, - {"4.1", [{restart_application, ssl}]}, - {"4.0.1", [{restart_application, ssl}]} + {"5.0", [{restart_application, ssl}]}, + {<<"4\\.*">>, [{restart_application, ssl}]}, + {<<"3\\.*">>, [{restart_application, ssl}]} ]}. diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk index 2255798f1d..0fccbfe908 100644 --- a/lib/ssl/vsn.mk +++ b/lib/ssl/vsn.mk @@ -1 +1 @@ -SSL_VSN = 5.0 +SSL_VSN = 5.0.1 diff --git a/lib/stdlib/src/erl_compile.erl b/lib/stdlib/src/erl_compile.erl index ff032b129c..81bec21a3f 100644 --- a/lib/stdlib/src/erl_compile.erl +++ b/lib/stdlib/src/erl_compile.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-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 @@ -57,17 +57,7 @@ compile_cmdline(List) -> end. my_halt(Reason) -> - case process_info(group_leader(), status) of - {_,waiting} -> - %% Now all output data is down in the driver. - %% Give the driver some extra time before halting. - receive after 1 -> ok end, - halt(Reason); - _ -> - %% Probably still processing I/O requests. - erlang:yield(), - my_halt(Reason) - end. + erlang:halt(Reason). %% Run the the compiler in a separate process, trapping EXITs. diff --git a/lib/stdlib/src/erl_internal.erl b/lib/stdlib/src/erl_internal.erl index cd3b531d10..3063881890 100644 --- a/lib/stdlib/src/erl_internal.erl +++ b/lib/stdlib/src/erl_internal.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2011. All Rights Reserved. +%% Copyright Ericsson AB 1998-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 @@ -287,6 +287,7 @@ bif(group_leader, 0) -> true; bif(group_leader, 2) -> true; bif(halt, 0) -> true; bif(halt, 1) -> true; +bif(halt, 2) -> true; bif(hd, 1) -> true; bif(integer_to_list, 1) -> true; bif(integer_to_list, 2) -> true; diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl index ad49d89908..27e70ac4d4 100644 --- a/lib/stdlib/src/escript.erl +++ b/lib/stdlib/src/escript.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-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 @@ -848,17 +848,7 @@ fatal(Str) -> throw(Str). my_halt(Reason) -> - case process_info(group_leader(), status) of - {_,waiting} -> - %% Now all output data is down in the driver. - %% Give the driver some extra time before halting. - receive after 1 -> ok end, - halt(Reason); - _ -> - %% Probably still processing I/O requests. - erlang:yield(), - my_halt(Reason) - end. + erlang:halt(Reason). hidden_apply(App, M, F, Args) -> try diff --git a/lib/stdlib/test/edlin_expand_SUITE.erl b/lib/stdlib/test/edlin_expand_SUITE.erl index a0e198ce09..f8d4fb4b6a 100644 --- a/lib/stdlib/test/edlin_expand_SUITE.erl +++ b/lib/stdlib/test/edlin_expand_SUITE.erl @@ -46,10 +46,10 @@ groups() -> []. init_per_suite(Config) -> - true = code:delete(expand_test), - true = code:delete(expand_test1), - true = code:delete('ExpandTestCaps'), - true = code:delete('ExpandTestCaps1'), + (catch code:delete(expand_test)), + (catch code:delete(expand_test1)), + (catch code:delete('ExpandTestCaps')), + (catch code:delete('ExpandTestCaps1')), Config. end_per_suite(_Config) -> diff --git a/lib/stdlib/test/io_proto_SUITE.erl b/lib/stdlib/test/io_proto_SUITE.erl index b69cd74edb..0b74d04b85 100644 --- a/lib/stdlib/test/io_proto_SUITE.erl +++ b/lib/stdlib/test/io_proto_SUITE.erl @@ -50,7 +50,7 @@ -define(privdir(Conf), ?config(priv_dir, Conf)). -endif. --define(debug, true). +%%-define(debug, true). -ifdef(debug). -define(format(S, A), io:format(S, A)). diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl index 50a76cdfb5..1e74ad7727 100644 --- a/lib/stdlib/test/qlc_SUITE.erl +++ b/lib/stdlib/test/qlc_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-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 @@ -7927,15 +7927,23 @@ run_test(Config, Extra, {cres, Body, Opts, ExpectedCompileReturn}) -> ok end, + wait_for_expected(R, Before, SourceFile, true), + code:purge(Mod); +run_test(Config, Extra, Body) -> + run_test(Config, Extra, {cres,Body,[]}). + +wait_for_expected(R, Before, SourceFile, Wait) -> Ms = erlang:process_info(self(),messages), After = {get(), pps(), ets:all(), Ms}, - code:purge(Mod), case {R, After} of - {ok, Before} -> ok; - _ -> expected({ok,Before}, {R,After}, SourceFile) - end; -run_test(Config, Extra, Body) -> - run_test(Config, Extra, {cres,Body,[]}). + {ok, Before} -> + ok; + _ when Wait -> + timer:sleep(1000), + wait_for_expected(R, Before, SourceFile, false); + _ -> + expected({ok,Before}, {R,After}, SourceFile) + end. unload_pt() -> erlang:garbage_collect(), % get rid of references to qlc_pt... diff --git a/lib/wx/api_gen/gl_gen.erl b/lib/wx/api_gen/gl_gen.erl index ce0cb922e9..331ba32ba4 100644 --- a/lib/wx/api_gen/gl_gen.erl +++ b/lib/wx/api_gen/gl_gen.erl @@ -190,14 +190,17 @@ parse_define([#xmlElement{name=initializer,content=[#xmlText{value=V}]}|_],Def,_ try case Val0 of "0x" ++ Val1 -> - Val = http_util:hexlist_to_integer(Val1), - Def#def{val=Val, type=hex}; + _ = http_util:hexlist_to_integer(Val1), + Def#def{val=Val1, type=hex}; _ -> Val = list_to_integer(Val0), Def#def{val=Val, type=int} end - catch _:_ -> - Def#def{val=Val0, type=string} + catch _:_ -> + case catch list_to_float(Val0) of + {'EXIT', _} -> Def#def{val=Val0, type=string}; + _ -> Def#def{val=Val0, type=float_str} + end end; parse_define([_|R], D, Opts) -> parse_define(R, D, Opts); diff --git a/lib/wx/api_gen/gl_gen_erl.erl b/lib/wx/api_gen/gl_gen_erl.erl index f77b2d8e24..25f89e4ad4 100644 --- a/lib/wx/api_gen/gl_gen_erl.erl +++ b/lib/wx/api_gen/gl_gen_erl.erl @@ -54,8 +54,10 @@ glu_defines(Defs) -> gen_define(#def{name=N, val=Val, type=int}) -> w("-define(~s, ~p).~n", [N,Val]); +gen_define(#def{name=N, val=Val, type=float_str}) -> + w("-define(~s, ~s).~n", [N,Val]); gen_define(#def{name=N, val=Val, type=hex}) -> - w("-define(~s, ~.16#).~n", [N,Val]); + w("-define(~s, 16#~s).~n", [N,Val]); gen_define(#def{name=N, val=Val, type=string}) -> w("-define(~s, ?~s).~n", [N,Val]); gen_define(#def{name="GLEXT_64_TYPES"++_, val=undefined, type=undefined}) -> diff --git a/lib/wx/api_gen/wx_gen_cpp.erl b/lib/wx/api_gen/wx_gen_cpp.erl index 69e7510a95..2209e4a53b 100644 --- a/lib/wx/api_gen/wx_gen_cpp.erl +++ b/lib/wx/api_gen/wx_gen_cpp.erl @@ -350,8 +350,12 @@ declare_type(N,false,_,#type{name="wxDateTime"}) -> w(" wxDateTime ~s;~n", [N]); declare_type(N,false,_,#type{name="wxColour"}) -> w(" wxColour ~s;~n", [N]); +declare_type(N,false,_,#type{name=Type, base=int, ref=reference}) -> + w(" ~s ~s;~n", [Type,N]); declare_type(N,false,_,#type{name=Type, base=int64, ref=reference}) -> w(" ~s ~s;~n", [Type,N]); +declare_type(N,false,_,#type{base={comp,_,_},single=true,name=Type,ref=reference}) -> + w(" ~s ~s;~n", [Type,N]); declare_type(N,true,Def,#type{base=Base,single=true,name=Type,by_val=true}) when Base =:= int; Base =:= long; Base =:= float; Base =:= double; Base =:= bool -> w(" ~s ~s=~s;~n", [Type,N,Def]); @@ -812,6 +816,7 @@ call_arg(#param{name=N,in=false,type=#type{by_val=false, single=true}}) -> "&" + call_arg(#param{name=N,def=Def,type=#type{base={comp,_,_},ref={pointer,1},single=true}}) when Def =:= none -> "&" ++N; +call_arg(#param{name=N,type=#type{base=int, ref=reference, single=true}}) -> "*" ++ N; call_arg(#param{name=N,type=#type{by_val=false}}) -> N; call_arg(#param{name=N,type={merged,_,#type{base={class,_},single=true, by_val=ByVal, @@ -888,7 +893,7 @@ build_return_vals(Type,Ps) -> build_ret_types(void,Ps) -> Calc = fun(#param{name=N,in=False,type=T}, Free) when False =/= true -> - case build_ret(N, False, T) of + case build_ret(N, {arg, False}, T) of ok -> Free; Other -> [Other|Free] end; @@ -896,12 +901,12 @@ build_ret_types(void,Ps) -> end, lists:foldl(Calc, [], Ps); build_ret_types(Type,Ps) -> - Free = case build_ret("Result", out, Type) of + Free = case build_ret("Result", {ret, out}, Type) of ok -> []; FreeStr -> [FreeStr] end, Calc = fun(#param{name=N,in=False,type=T}, FreeAcc) when False =/= true -> - case build_ret(N, False, T) of + case build_ret(N, {arg, False}, T) of ok -> FreeAcc; FreeMe -> [FreeMe|FreeAcc] end; @@ -927,13 +932,13 @@ build_ret(Name,_,#type{base={enum,_Type},single=true}) -> w(" rt.addInt(~s);~n",[Name]); build_ret(Name,_,#type{base={comp,_,{record, _}},single=true}) -> w(" rt.add(~s);~n", [Name]); -build_ret(Name,_,#type{base={comp,_,_},single=true, ref=reference}) -> +build_ret(Name,{ret,_},#type{base={comp,_,_},single=true, ref=reference}) -> w(" rt.add((*~s));~n",[Name]); build_ret(Name,_,#type{base={comp,_,_},single=true}) -> w(" rt.add(~s);~n",[Name]); build_ret(Name,_,#type{base=bool,single=true,by_val=true}) -> w(" rt.addBool(~s);~n",[Name]); -build_ret(Name,both,#type{base=int,single=true,mod=M}) -> +build_ret(Name,{arg, both},#type{base=int,single=true,mod=M}) -> case lists:member(unsigned, M) of true -> w(" rt.addUint(*~s);~n",[Name]); false -> w(" rt.addInt(*~s);~n",[Name]) diff --git a/lib/wx/api_gen/wx_gen_erl.erl b/lib/wx/api_gen/wx_gen_erl.erl index aac57586bc..6159b7c4bd 100644 --- a/lib/wx/api_gen/wx_gen_erl.erl +++ b/lib/wx/api_gen/wx_gen_erl.erl @@ -177,7 +177,18 @@ parents_check([Parent|Ps]) -> w("parent_class(~s) -> true;~n",[Parent]), parents_check(Ps). -check_class(#type{base={class,"wx"}}) -> ok; +check_class(#type{name="wxObject", base={class,"wx"}}) -> + "wx:wx_object()"; +check_class(#type{name="wxIconLocation", base={class,"wx"}}) -> + "wx:wx_object()"; +check_class(#type{name="wxToolBarToolBase", base={class,"wx"}, mod=Mod}) -> + %% Implement this some day + "wx:wx_object()"; +check_class(#type{name="wxValidator", base={class,"wx"}, mod=Mod}) -> + %% Implement this some day + "wx:wx_object()"; +check_class(#type{name=Name, base={class,"wx"}}) -> + exit({class, Name}); check_class(#type{base={class,Name},xml=Xml}) -> case get({class,Name}) of undefined -> @@ -190,12 +201,15 @@ check_class(#type{base={class,Name},xml=Xml}) -> _ -> ?warning("~s:~s: Class ~p used but not defined~n (see ~p)~n", [get(current_class),get(current_func),Name, Xml]) - end; + end, + "wx:wx_object()"; _ -> ?warning("~s:~s: Class ~p used is enum~n", - [get(current_class),get(current_func),Name]) + [get(current_class),get(current_func),Name]), + exit(class_enum) end; - _ -> ok + _ -> + Name ++ ":" ++ Name ++ "()" end. gen_export(#class{name=Class,abstract=Abs},Ms0) -> @@ -766,21 +780,21 @@ doc_arg_type3(#type{base=eventType}, _) -> "atom()"; doc_arg_type3(#type{base={ref,N}}, _) -> N++"()"; doc_arg_type3(#type{base={term,_N}}, _) -> "term()"; doc_arg_type3(T=#type{base={class,N}}, _) -> - check_class(T), - case get(current_class) of - N -> N ++ "()"; - _ -> N++":" ++ N++"()" + ClassType = check_class(T), + Current = get(current_class), + if N =:= Current -> N ++ "()"; + true -> ClassType end; doc_arg_type3({merged,_,T1=#type{base={class,N1}},_,_,T2=#type{base={class,N2}},_}, _) -> - check_class(T1), - check_class(T2), + CT1 = check_class(T1), + CT2 = check_class(T2), Curr = get(current_class), if - N1 =:= Curr, N2 =:= Curr -> N1++"() | "++ N2++"()"; - N1 =:= Curr -> N1++"() | "++ N2++":" ++ N2++"()"; - N2 =:= Curr -> N1++":" ++ N1++"() | "++ N2++"()"; + N1 =:= Curr, N2 =:= Curr -> N1++"()"; + N1 =:= Curr -> N1++"() | "++ CT2; + N2 =:= Curr -> CT1 ++ " | "++ N2++"()"; true -> - N1++":" ++ N1++"() | "++ N2++":" ++ N2++"()" + CT1 ++ " | " ++ CT2 end; %% doc_arg_type3(#type{base={enum,{_,N}}}, _) -> uppercase(N); %% doc_arg_type3(#type{base={enum,N}}, _) -> uppercase(N); @@ -1010,12 +1024,13 @@ enum_name(Name) -> gen_enums_ints() -> %% open_write("../include/wx.hrl"), opened in gen_event_recs w("~n%% Hardcoded Records~n", []), - w("-record(wxMouseState, {x, y, %% integer()~n" - " leftDown, middleDown, rightDown, %% bool()~n" - " controlDown, shiftDown, altDown, metaDown, cmdDown %% bool()~n" + w("-record(wxMouseState, {x :: integer(), y :: integer(),~n" + " leftDown :: boolean(), middleDown :: boolean, rightDown :: boolean, ~n" + " controlDown :: boolean(), shiftDown :: boolean(),~n" + " altDown :: boolean(), metaDown :: boolean(), cmdDown :: boolean()~n" " }).~n", []), w("-record(wxHtmlLinkInfo, {~n" - " href, target %% unicode:chardata()~n" + " href :: unicode:chardata(), target :: unicode:chardata()~n" " }).~n", []), w("~n%% Hardcoded Defines~n", []), Enums = [E || {{enum,_},E = #enum{as_atom=false}} <- get()], @@ -1045,16 +1060,16 @@ build_enum_ints(#enum{from=From, vals=Vals},Done) -> Format = fun(#const{name="wxEVT_" ++ _}) -> ignore; %% Ignore event macros they are not valid in our event model - (#const{name=Name,val=Value,is_const=true}) when is_integer(Value) -> + (#const{name=Name,val=Value,is_const=true}) when is_number(Value) -> w("-define(~s, ~p).~n", [enum_name(Name),Value]); - (#const{name=Name,val=Value,is_const=false}) when is_integer(Value) -> + (#const{name=Name,val=Value,is_const=false}) when is_number(Value) -> w("-define(~s, wxe_util:get_const(~s)).~n", [enum_name(Name),enum_name(Name)]); (#const{name=Name,val={Str,0}}) -> case string:tokens(Str, " |()") of [Token] -> - w("-define(~s, ?~s).~n", [enum_name(Name),Token]); + w("-define(~s, ~s).~n", [enum_name(Name),const_value(Token)]); Tokens -> - Def = args(fun(T) -> [$?|T] end, " bor ", Tokens), + Def = args(fun(T) -> const_value(T) end, " bor ", Tokens), w("-define(~s, (~s)).~n", [enum_name(Name),Def]) end; (#const{name=Name,val={Str,N}}) -> @@ -1079,6 +1094,17 @@ build_enum_ints(#enum{from=From, vals=Vals},Done) -> end, lists:foldl(Write, Done, Vals). +const_value(V) when is_integer(V) -> integer_to_list(V); +const_value(V = "16#" ++ IntList) -> + _ = http_util:hexlist_to_integer(IntList), %% ASSERT + V; +const_value(V0) -> + try + _ = list_to_integer(V0), + V0 + catch _:_ -> [$?|V0] + end. + gen_event_recs() -> open_write("../include/wx.hrl"), erl_copyright(), diff --git a/lib/wx/api_gen/wxapi.conf b/lib/wx/api_gen/wxapi.conf index 383addfe3f..1f6225ce60 100644 --- a/lib/wx/api_gen/wxapi.conf +++ b/lib/wx/api_gen/wxapi.conf @@ -776,10 +776,12 @@ 'GetEditControl', 'GetImageList','GetItem','GetItemBackgroundColour', 'GetItemCount',{'GetItemData', [{return, {base,int}}]}, - 'GetItemFont','GetItemPosition','GetItemRect', - 'GetItemSpacing','GetItemState','GetItemText','GetItemTextColour', + 'GetItemFont', {'GetItemPosition', [{"pos", out}]},{'GetItemRect',[{"rect", out}]}, + 'GetItemSpacing','GetItemState', + 'GetItemText','GetItemTextColour', 'GetNextItem','GetSelectedItemCount','GetTextColour','GetTopItem', - 'GetViewRect',{'HitTest',[{"pSubItem",nowhere}]},'InsertColumn','InsertItem', + 'GetViewRect',{'HitTest',[{"pSubItem",nowhere}, {"flags", in}]}, + 'InsertColumn','InsertItem', %%'OnGetItemAttr', 'OnGetItemImage','OnGetItemText', 'RefreshItem','RefreshItems','ScrollList', 'SetBackgroundColour','SetColumn','SetColumnWidth','SetImageList','SetItem', diff --git a/lib/wx/c_src/gen/wxe_funcs.cpp b/lib/wx/c_src/gen/wxe_funcs.cpp index c81b3c88c0..15012011ed 100644 --- a/lib/wx/c_src/gen/wxe_funcs.cpp +++ b/lib/wx/c_src/gen/wxe_funcs.cpp @@ -15420,25 +15420,21 @@ case wxListCtrl_GetItemFont: { // wxListCtrl::GetItemFont break; } case wxListCtrl_GetItemPosition: { // wxListCtrl::GetItemPosition + wxPoint pos; wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4; int * item = (int *) bp; bp += 4; - int * posX = (int *) bp; bp += 4; - int * posY = (int *) bp; bp += 4; - wxPoint pos = wxPoint(*posX,*posY); if(!This) throw wxe_badarg(0); bool Result = This->GetItemPosition((long) *item,pos); rt.addBool(Result); + rt.add(pos); + rt.addTupleCount(2); break; } case wxListCtrl_GetItemRect: { // wxListCtrl::GetItemRect + wxRect rect; int code=wxLIST_RECT_BOUNDS; wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4; int * item = (int *) bp; bp += 4; - int * rectX = (int *) bp; bp += 4; - int * rectY = (int *) bp; bp += 4; - int * rectW = (int *) bp; bp += 4; - int * rectH = (int *) bp; bp += 4; - wxRect rect = wxRect(*rectX,*rectY,*rectW,*rectH); while( * (int*) bp) { switch (* (int*) bp) { case 1: {bp += 4; code = (int)*(int *) bp; bp += 4; @@ -15447,6 +15443,8 @@ case wxListCtrl_GetItemRect: { // wxListCtrl::GetItemRect if(!This) throw wxe_badarg(0); bool Result = This->GetItemRect((long) *item,rect,code); rt.addBool(Result); + rt.add(rect); + rt.addTupleCount(2); break; } case wxListCtrl_GetItemSpacing: { // wxListCtrl::GetItemSpacing @@ -15528,16 +15526,14 @@ case wxListCtrl_GetViewRect: { // wxListCtrl::GetViewRect break; } case wxListCtrl_HitTest: { // wxListCtrl::HitTest - int flags; wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4; int * pointX = (int *) bp; bp += 4; int * pointY = (int *) bp; bp += 4; wxPoint point = wxPoint(*pointX,*pointY); + int * flags = (int *) bp; bp += 4; if(!This) throw wxe_badarg(0); - long Result = This->HitTest(point,flags); + long Result = This->HitTest(point,*flags); rt.addInt(Result); - rt.addInt(flags); - rt.addTupleCount(2); break; } case wxListCtrl_InsertColumn_2: { // wxListCtrl::InsertColumn diff --git a/lib/wx/include/gl.hrl b/lib/wx/include/gl.hrl index c643ae0962..9004a8aa31 100644 --- a/lib/wx/include/gl.hrl +++ b/lib/wx/include/gl.hrl @@ -37,16 +37,16 @@ -define(GL_3_BYTES, 16#1408). -define(GL_4_BYTES, 16#1409). -define(GL_DOUBLE, 16#140A). --define(GL_POINTS, 16#0). --define(GL_LINES, 16#1). --define(GL_LINE_LOOP, 16#2). --define(GL_LINE_STRIP, 16#3). --define(GL_TRIANGLES, 16#4). --define(GL_TRIANGLE_STRIP, 16#5). --define(GL_TRIANGLE_FAN, 16#6). --define(GL_QUADS, 16#7). --define(GL_QUAD_STRIP, 16#8). --define(GL_POLYGON, 16#9). +-define(GL_POINTS, 16#0000). +-define(GL_LINES, 16#0001). +-define(GL_LINE_LOOP, 16#0002). +-define(GL_LINE_STRIP, 16#0003). +-define(GL_TRIANGLES, 16#0004). +-define(GL_TRIANGLE_STRIP, 16#0005). +-define(GL_TRIANGLE_FAN, 16#0006). +-define(GL_QUADS, 16#0007). +-define(GL_QUAD_STRIP, 16#0008). +-define(GL_POLYGON, 16#0009). -define(GL_VERTEX_ARRAY, 16#8074). -define(GL_NORMAL_ARRAY, 16#8075). -define(GL_COLOR_ARRAY, 16#8076). @@ -87,35 +87,35 @@ -define(GL_T2F_N3F_V3F, 16#2A2B). -define(GL_T2F_C4F_N3F_V3F, 16#2A2C). -define(GL_T4F_C4F_N3F_V4F, 16#2A2D). --define(GL_MATRIX_MODE, 16#BA0). +-define(GL_MATRIX_MODE, 16#0BA0). -define(GL_MODELVIEW, 16#1700). -define(GL_PROJECTION, 16#1701). -define(GL_TEXTURE, 16#1702). --define(GL_POINT_SMOOTH, 16#B10). --define(GL_POINT_SIZE, 16#B11). --define(GL_POINT_SIZE_GRANULARITY, 16#B13). --define(GL_POINT_SIZE_RANGE, 16#B12). --define(GL_LINE_SMOOTH, 16#B20). --define(GL_LINE_STIPPLE, 16#B24). --define(GL_LINE_STIPPLE_PATTERN, 16#B25). --define(GL_LINE_STIPPLE_REPEAT, 16#B26). --define(GL_LINE_WIDTH, 16#B21). --define(GL_LINE_WIDTH_GRANULARITY, 16#B23). --define(GL_LINE_WIDTH_RANGE, 16#B22). +-define(GL_POINT_SMOOTH, 16#0B10). +-define(GL_POINT_SIZE, 16#0B11). +-define(GL_POINT_SIZE_GRANULARITY, 16#0B13). +-define(GL_POINT_SIZE_RANGE, 16#0B12). +-define(GL_LINE_SMOOTH, 16#0B20). +-define(GL_LINE_STIPPLE, 16#0B24). +-define(GL_LINE_STIPPLE_PATTERN, 16#0B25). +-define(GL_LINE_STIPPLE_REPEAT, 16#0B26). +-define(GL_LINE_WIDTH, 16#0B21). +-define(GL_LINE_WIDTH_GRANULARITY, 16#0B23). +-define(GL_LINE_WIDTH_RANGE, 16#0B22). -define(GL_POINT, 16#1B00). -define(GL_LINE, 16#1B01). -define(GL_FILL, 16#1B02). --define(GL_CW, 16#900). --define(GL_CCW, 16#901). --define(GL_FRONT, 16#404). --define(GL_BACK, 16#405). --define(GL_POLYGON_MODE, 16#B40). --define(GL_POLYGON_SMOOTH, 16#B41). --define(GL_POLYGON_STIPPLE, 16#B42). --define(GL_EDGE_FLAG, 16#B43). --define(GL_CULL_FACE, 16#B44). --define(GL_CULL_FACE_MODE, 16#B45). --define(GL_FRONT_FACE, 16#B46). +-define(GL_CW, 16#0900). +-define(GL_CCW, 16#0901). +-define(GL_FRONT, 16#0404). +-define(GL_BACK, 16#0405). +-define(GL_POLYGON_MODE, 16#0B40). +-define(GL_POLYGON_SMOOTH, 16#0B41). +-define(GL_POLYGON_STIPPLE, 16#0B42). +-define(GL_EDGE_FLAG, 16#0B43). +-define(GL_CULL_FACE, 16#0B44). +-define(GL_CULL_FACE_MODE, 16#0B45). +-define(GL_FRONT_FACE, 16#0B46). -define(GL_POLYGON_OFFSET_FACTOR, 16#8038). -define(GL_POLYGON_OFFSET_UNITS, 16#2A00). -define(GL_POLYGON_OFFSET_POINT, 16#2A01). @@ -123,25 +123,25 @@ -define(GL_POLYGON_OFFSET_FILL, 16#8037). -define(GL_COMPILE, 16#1300). -define(GL_COMPILE_AND_EXECUTE, 16#1301). --define(GL_LIST_BASE, 16#B32). --define(GL_LIST_INDEX, 16#B33). --define(GL_LIST_MODE, 16#B30). --define(GL_NEVER, 16#200). --define(GL_LESS, 16#201). --define(GL_EQUAL, 16#202). --define(GL_LEQUAL, 16#203). --define(GL_GREATER, 16#204). --define(GL_NOTEQUAL, 16#205). --define(GL_GEQUAL, 16#206). --define(GL_ALWAYS, 16#207). --define(GL_DEPTH_TEST, 16#B71). --define(GL_DEPTH_BITS, 16#D56). --define(GL_DEPTH_CLEAR_VALUE, 16#B73). --define(GL_DEPTH_FUNC, 16#B74). --define(GL_DEPTH_RANGE, 16#B70). --define(GL_DEPTH_WRITEMASK, 16#B72). +-define(GL_LIST_BASE, 16#0B32). +-define(GL_LIST_INDEX, 16#0B33). +-define(GL_LIST_MODE, 16#0B30). +-define(GL_NEVER, 16#0200). +-define(GL_LESS, 16#0201). +-define(GL_EQUAL, 16#0202). +-define(GL_LEQUAL, 16#0203). +-define(GL_GREATER, 16#0204). +-define(GL_NOTEQUAL, 16#0205). +-define(GL_GEQUAL, 16#0206). +-define(GL_ALWAYS, 16#0207). +-define(GL_DEPTH_TEST, 16#0B71). +-define(GL_DEPTH_BITS, 16#0D56). +-define(GL_DEPTH_CLEAR_VALUE, 16#0B73). +-define(GL_DEPTH_FUNC, 16#0B74). +-define(GL_DEPTH_RANGE, 16#0B70). +-define(GL_DEPTH_WRITEMASK, 16#0B72). -define(GL_DEPTH_COMPONENT, 16#1902). --define(GL_LIGHTING, 16#B50). +-define(GL_LIGHTING, 16#0B50). -define(GL_LIGHT0, 16#4000). -define(GL_LIGHT1, 16#4001). -define(GL_LIGHT2, 16#4002). @@ -164,85 +164,85 @@ -define(GL_SPOT_DIRECTION, 16#1204). -define(GL_AMBIENT_AND_DIFFUSE, 16#1602). -define(GL_COLOR_INDEXES, 16#1603). --define(GL_LIGHT_MODEL_TWO_SIDE, 16#B52). --define(GL_LIGHT_MODEL_LOCAL_VIEWER, 16#B51). --define(GL_LIGHT_MODEL_AMBIENT, 16#B53). --define(GL_FRONT_AND_BACK, 16#408). --define(GL_SHADE_MODEL, 16#B54). +-define(GL_LIGHT_MODEL_TWO_SIDE, 16#0B52). +-define(GL_LIGHT_MODEL_LOCAL_VIEWER, 16#0B51). +-define(GL_LIGHT_MODEL_AMBIENT, 16#0B53). +-define(GL_FRONT_AND_BACK, 16#0408). +-define(GL_SHADE_MODEL, 16#0B54). -define(GL_FLAT, 16#1D00). -define(GL_SMOOTH, 16#1D01). --define(GL_COLOR_MATERIAL, 16#B57). --define(GL_COLOR_MATERIAL_FACE, 16#B55). --define(GL_COLOR_MATERIAL_PARAMETER, 16#B56). --define(GL_NORMALIZE, 16#BA1). +-define(GL_COLOR_MATERIAL, 16#0B57). +-define(GL_COLOR_MATERIAL_FACE, 16#0B55). +-define(GL_COLOR_MATERIAL_PARAMETER, 16#0B56). +-define(GL_NORMALIZE, 16#0BA1). -define(GL_CLIP_PLANE0, 16#3000). -define(GL_CLIP_PLANE1, 16#3001). -define(GL_CLIP_PLANE2, 16#3002). -define(GL_CLIP_PLANE3, 16#3003). -define(GL_CLIP_PLANE4, 16#3004). -define(GL_CLIP_PLANE5, 16#3005). --define(GL_ACCUM_RED_BITS, 16#D58). --define(GL_ACCUM_GREEN_BITS, 16#D59). --define(GL_ACCUM_BLUE_BITS, 16#D5A). --define(GL_ACCUM_ALPHA_BITS, 16#D5B). --define(GL_ACCUM_CLEAR_VALUE, 16#B80). --define(GL_ACCUM, 16#100). --define(GL_ADD, 16#104). --define(GL_LOAD, 16#101). --define(GL_MULT, 16#103). --define(GL_RETURN, 16#102). --define(GL_ALPHA_TEST, 16#BC0). --define(GL_ALPHA_TEST_REF, 16#BC2). --define(GL_ALPHA_TEST_FUNC, 16#BC1). --define(GL_BLEND, 16#BE2). --define(GL_BLEND_SRC, 16#BE1). --define(GL_BLEND_DST, 16#BE0). +-define(GL_ACCUM_RED_BITS, 16#0D58). +-define(GL_ACCUM_GREEN_BITS, 16#0D59). +-define(GL_ACCUM_BLUE_BITS, 16#0D5A). +-define(GL_ACCUM_ALPHA_BITS, 16#0D5B). +-define(GL_ACCUM_CLEAR_VALUE, 16#0B80). +-define(GL_ACCUM, 16#0100). +-define(GL_ADD, 16#0104). +-define(GL_LOAD, 16#0101). +-define(GL_MULT, 16#0103). +-define(GL_RETURN, 16#0102). +-define(GL_ALPHA_TEST, 16#0BC0). +-define(GL_ALPHA_TEST_REF, 16#0BC2). +-define(GL_ALPHA_TEST_FUNC, 16#0BC1). +-define(GL_BLEND, 16#0BE2). +-define(GL_BLEND_SRC, 16#0BE1). +-define(GL_BLEND_DST, 16#0BE0). -define(GL_ZERO, 16#0). -define(GL_ONE, 16#1). --define(GL_SRC_COLOR, 16#300). --define(GL_ONE_MINUS_SRC_COLOR, 16#301). --define(GL_SRC_ALPHA, 16#302). --define(GL_ONE_MINUS_SRC_ALPHA, 16#303). --define(GL_DST_ALPHA, 16#304). --define(GL_ONE_MINUS_DST_ALPHA, 16#305). --define(GL_DST_COLOR, 16#306). --define(GL_ONE_MINUS_DST_COLOR, 16#307). --define(GL_SRC_ALPHA_SATURATE, 16#308). +-define(GL_SRC_COLOR, 16#0300). +-define(GL_ONE_MINUS_SRC_COLOR, 16#0301). +-define(GL_SRC_ALPHA, 16#0302). +-define(GL_ONE_MINUS_SRC_ALPHA, 16#0303). +-define(GL_DST_ALPHA, 16#0304). +-define(GL_ONE_MINUS_DST_ALPHA, 16#0305). +-define(GL_DST_COLOR, 16#0306). +-define(GL_ONE_MINUS_DST_COLOR, 16#0307). +-define(GL_SRC_ALPHA_SATURATE, 16#0308). -define(GL_FEEDBACK, 16#1C01). -define(GL_RENDER, 16#1C00). -define(GL_SELECT, 16#1C02). --define(GL_2D, 16#600). --define(GL_3D, 16#601). --define(GL_3D_COLOR, 16#602). --define(GL_3D_COLOR_TEXTURE, 16#603). --define(GL_4D_COLOR_TEXTURE, 16#604). --define(GL_POINT_TOKEN, 16#701). --define(GL_LINE_TOKEN, 16#702). --define(GL_LINE_RESET_TOKEN, 16#707). --define(GL_POLYGON_TOKEN, 16#703). --define(GL_BITMAP_TOKEN, 16#704). --define(GL_DRAW_PIXEL_TOKEN, 16#705). --define(GL_COPY_PIXEL_TOKEN, 16#706). --define(GL_PASS_THROUGH_TOKEN, 16#700). --define(GL_FEEDBACK_BUFFER_POINTER, 16#DF0). --define(GL_FEEDBACK_BUFFER_SIZE, 16#DF1). --define(GL_FEEDBACK_BUFFER_TYPE, 16#DF2). --define(GL_SELECTION_BUFFER_POINTER, 16#DF3). --define(GL_SELECTION_BUFFER_SIZE, 16#DF4). --define(GL_FOG, 16#B60). --define(GL_FOG_MODE, 16#B65). --define(GL_FOG_DENSITY, 16#B62). --define(GL_FOG_COLOR, 16#B66). --define(GL_FOG_INDEX, 16#B61). --define(GL_FOG_START, 16#B63). --define(GL_FOG_END, 16#B64). +-define(GL_2D, 16#0600). +-define(GL_3D, 16#0601). +-define(GL_3D_COLOR, 16#0602). +-define(GL_3D_COLOR_TEXTURE, 16#0603). +-define(GL_4D_COLOR_TEXTURE, 16#0604). +-define(GL_POINT_TOKEN, 16#0701). +-define(GL_LINE_TOKEN, 16#0702). +-define(GL_LINE_RESET_TOKEN, 16#0707). +-define(GL_POLYGON_TOKEN, 16#0703). +-define(GL_BITMAP_TOKEN, 16#0704). +-define(GL_DRAW_PIXEL_TOKEN, 16#0705). +-define(GL_COPY_PIXEL_TOKEN, 16#0706). +-define(GL_PASS_THROUGH_TOKEN, 16#0700). +-define(GL_FEEDBACK_BUFFER_POINTER, 16#0DF0). +-define(GL_FEEDBACK_BUFFER_SIZE, 16#0DF1). +-define(GL_FEEDBACK_BUFFER_TYPE, 16#0DF2). +-define(GL_SELECTION_BUFFER_POINTER, 16#0DF3). +-define(GL_SELECTION_BUFFER_SIZE, 16#0DF4). +-define(GL_FOG, 16#0B60). +-define(GL_FOG_MODE, 16#0B65). +-define(GL_FOG_DENSITY, 16#0B62). +-define(GL_FOG_COLOR, 16#0B66). +-define(GL_FOG_INDEX, 16#0B61). +-define(GL_FOG_START, 16#0B63). +-define(GL_FOG_END, 16#0B64). -define(GL_LINEAR, 16#2601). --define(GL_EXP, 16#800). --define(GL_EXP2, 16#801). --define(GL_LOGIC_OP, 16#BF1). --define(GL_INDEX_LOGIC_OP, 16#BF1). --define(GL_COLOR_LOGIC_OP, 16#BF2). --define(GL_LOGIC_OP_MODE, 16#BF0). +-define(GL_EXP, 16#0800). +-define(GL_EXP2, 16#0801). +-define(GL_LOGIC_OP, 16#0BF1). +-define(GL_INDEX_LOGIC_OP, 16#0BF1). +-define(GL_COLOR_LOGIC_OP, 16#0BF2). +-define(GL_LOGIC_OP_MODE, 16#0BF0). -define(GL_CLEAR, 16#1500). -define(GL_SET, 16#150F). -define(GL_COPY, 16#1503). @@ -259,32 +259,32 @@ -define(GL_AND_INVERTED, 16#1504). -define(GL_OR_REVERSE, 16#150B). -define(GL_OR_INVERTED, 16#150D). --define(GL_STENCIL_BITS, 16#D57). --define(GL_STENCIL_TEST, 16#B90). --define(GL_STENCIL_CLEAR_VALUE, 16#B91). --define(GL_STENCIL_FUNC, 16#B92). --define(GL_STENCIL_VALUE_MASK, 16#B93). --define(GL_STENCIL_FAIL, 16#B94). --define(GL_STENCIL_PASS_DEPTH_FAIL, 16#B95). --define(GL_STENCIL_PASS_DEPTH_PASS, 16#B96). --define(GL_STENCIL_REF, 16#B97). --define(GL_STENCIL_WRITEMASK, 16#B98). +-define(GL_STENCIL_BITS, 16#0D57). +-define(GL_STENCIL_TEST, 16#0B90). +-define(GL_STENCIL_CLEAR_VALUE, 16#0B91). +-define(GL_STENCIL_FUNC, 16#0B92). +-define(GL_STENCIL_VALUE_MASK, 16#0B93). +-define(GL_STENCIL_FAIL, 16#0B94). +-define(GL_STENCIL_PASS_DEPTH_FAIL, 16#0B95). +-define(GL_STENCIL_PASS_DEPTH_PASS, 16#0B96). +-define(GL_STENCIL_REF, 16#0B97). +-define(GL_STENCIL_WRITEMASK, 16#0B98). -define(GL_STENCIL_INDEX, 16#1901). -define(GL_KEEP, 16#1E00). -define(GL_REPLACE, 16#1E01). -define(GL_INCR, 16#1E02). -define(GL_DECR, 16#1E03). -define(GL_NONE, 16#0). --define(GL_LEFT, 16#406). --define(GL_RIGHT, 16#407). --define(GL_FRONT_LEFT, 16#400). --define(GL_FRONT_RIGHT, 16#401). --define(GL_BACK_LEFT, 16#402). --define(GL_BACK_RIGHT, 16#403). --define(GL_AUX0, 16#409). --define(GL_AUX1, 16#40A). --define(GL_AUX2, 16#40B). --define(GL_AUX3, 16#40C). +-define(GL_LEFT, 16#0406). +-define(GL_RIGHT, 16#0407). +-define(GL_FRONT_LEFT, 16#0400). +-define(GL_FRONT_RIGHT, 16#0401). +-define(GL_BACK_LEFT, 16#0402). +-define(GL_BACK_RIGHT, 16#0403). +-define(GL_AUX0, 16#0409). +-define(GL_AUX1, 16#040A). +-define(GL_AUX2, 16#040B). +-define(GL_AUX3, 16#040C). -define(GL_COLOR_INDEX, 16#1900). -define(GL_RED, 16#1903). -define(GL_GREEN, 16#1904). @@ -292,161 +292,161 @@ -define(GL_ALPHA, 16#1906). -define(GL_LUMINANCE, 16#1909). -define(GL_LUMINANCE_ALPHA, 16#190A). --define(GL_ALPHA_BITS, 16#D55). --define(GL_RED_BITS, 16#D52). --define(GL_GREEN_BITS, 16#D53). --define(GL_BLUE_BITS, 16#D54). --define(GL_INDEX_BITS, 16#D51). --define(GL_SUBPIXEL_BITS, 16#D50). --define(GL_AUX_BUFFERS, 16#C00). --define(GL_READ_BUFFER, 16#C02). --define(GL_DRAW_BUFFER, 16#C01). --define(GL_DOUBLEBUFFER, 16#C32). --define(GL_STEREO, 16#C33). +-define(GL_ALPHA_BITS, 16#0D55). +-define(GL_RED_BITS, 16#0D52). +-define(GL_GREEN_BITS, 16#0D53). +-define(GL_BLUE_BITS, 16#0D54). +-define(GL_INDEX_BITS, 16#0D51). +-define(GL_SUBPIXEL_BITS, 16#0D50). +-define(GL_AUX_BUFFERS, 16#0C00). +-define(GL_READ_BUFFER, 16#0C02). +-define(GL_DRAW_BUFFER, 16#0C01). +-define(GL_DOUBLEBUFFER, 16#0C32). +-define(GL_STEREO, 16#0C33). -define(GL_BITMAP, 16#1A00). -define(GL_COLOR, 16#1800). -define(GL_DEPTH, 16#1801). -define(GL_STENCIL, 16#1802). --define(GL_DITHER, 16#BD0). +-define(GL_DITHER, 16#0BD0). -define(GL_RGB, 16#1907). -define(GL_RGBA, 16#1908). --define(GL_MAX_LIST_NESTING, 16#B31). --define(GL_MAX_EVAL_ORDER, 16#D30). --define(GL_MAX_LIGHTS, 16#D31). --define(GL_MAX_CLIP_PLANES, 16#D32). --define(GL_MAX_TEXTURE_SIZE, 16#D33). --define(GL_MAX_PIXEL_MAP_TABLE, 16#D34). --define(GL_MAX_ATTRIB_STACK_DEPTH, 16#D35). --define(GL_MAX_MODELVIEW_STACK_DEPTH, 16#D36). --define(GL_MAX_NAME_STACK_DEPTH, 16#D37). --define(GL_MAX_PROJECTION_STACK_DEPTH, 16#D38). --define(GL_MAX_TEXTURE_STACK_DEPTH, 16#D39). --define(GL_MAX_VIEWPORT_DIMS, 16#D3A). --define(GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, 16#D3B). --define(GL_ATTRIB_STACK_DEPTH, 16#BB0). --define(GL_CLIENT_ATTRIB_STACK_DEPTH, 16#BB1). --define(GL_COLOR_CLEAR_VALUE, 16#C22). --define(GL_COLOR_WRITEMASK, 16#C23). --define(GL_CURRENT_INDEX, 16#B01). --define(GL_CURRENT_COLOR, 16#B00). --define(GL_CURRENT_NORMAL, 16#B02). --define(GL_CURRENT_RASTER_COLOR, 16#B04). --define(GL_CURRENT_RASTER_DISTANCE, 16#B09). --define(GL_CURRENT_RASTER_INDEX, 16#B05). --define(GL_CURRENT_RASTER_POSITION, 16#B07). --define(GL_CURRENT_RASTER_TEXTURE_COORDS, 16#B06). --define(GL_CURRENT_RASTER_POSITION_VALID, 16#B08). --define(GL_CURRENT_TEXTURE_COORDS, 16#B03). --define(GL_INDEX_CLEAR_VALUE, 16#C20). --define(GL_INDEX_MODE, 16#C30). --define(GL_INDEX_WRITEMASK, 16#C21). --define(GL_MODELVIEW_MATRIX, 16#BA6). --define(GL_MODELVIEW_STACK_DEPTH, 16#BA3). --define(GL_NAME_STACK_DEPTH, 16#D70). --define(GL_PROJECTION_MATRIX, 16#BA7). --define(GL_PROJECTION_STACK_DEPTH, 16#BA4). --define(GL_RENDER_MODE, 16#C40). --define(GL_RGBA_MODE, 16#C31). --define(GL_TEXTURE_MATRIX, 16#BA8). --define(GL_TEXTURE_STACK_DEPTH, 16#BA5). --define(GL_VIEWPORT, 16#BA2). --define(GL_AUTO_NORMAL, 16#D80). --define(GL_MAP1_COLOR_4, 16#D90). --define(GL_MAP1_INDEX, 16#D91). --define(GL_MAP1_NORMAL, 16#D92). --define(GL_MAP1_TEXTURE_COORD_1, 16#D93). --define(GL_MAP1_TEXTURE_COORD_2, 16#D94). --define(GL_MAP1_TEXTURE_COORD_3, 16#D95). --define(GL_MAP1_TEXTURE_COORD_4, 16#D96). --define(GL_MAP1_VERTEX_3, 16#D97). --define(GL_MAP1_VERTEX_4, 16#D98). --define(GL_MAP2_COLOR_4, 16#DB0). --define(GL_MAP2_INDEX, 16#DB1). --define(GL_MAP2_NORMAL, 16#DB2). --define(GL_MAP2_TEXTURE_COORD_1, 16#DB3). --define(GL_MAP2_TEXTURE_COORD_2, 16#DB4). --define(GL_MAP2_TEXTURE_COORD_3, 16#DB5). --define(GL_MAP2_TEXTURE_COORD_4, 16#DB6). --define(GL_MAP2_VERTEX_3, 16#DB7). --define(GL_MAP2_VERTEX_4, 16#DB8). --define(GL_MAP1_GRID_DOMAIN, 16#DD0). --define(GL_MAP1_GRID_SEGMENTS, 16#DD1). --define(GL_MAP2_GRID_DOMAIN, 16#DD2). --define(GL_MAP2_GRID_SEGMENTS, 16#DD3). --define(GL_COEFF, 16#A00). --define(GL_ORDER, 16#A01). --define(GL_DOMAIN, 16#A02). --define(GL_PERSPECTIVE_CORRECTION_HINT, 16#C50). --define(GL_POINT_SMOOTH_HINT, 16#C51). --define(GL_LINE_SMOOTH_HINT, 16#C52). --define(GL_POLYGON_SMOOTH_HINT, 16#C53). --define(GL_FOG_HINT, 16#C54). +-define(GL_MAX_LIST_NESTING, 16#0B31). +-define(GL_MAX_EVAL_ORDER, 16#0D30). +-define(GL_MAX_LIGHTS, 16#0D31). +-define(GL_MAX_CLIP_PLANES, 16#0D32). +-define(GL_MAX_TEXTURE_SIZE, 16#0D33). +-define(GL_MAX_PIXEL_MAP_TABLE, 16#0D34). +-define(GL_MAX_ATTRIB_STACK_DEPTH, 16#0D35). +-define(GL_MAX_MODELVIEW_STACK_DEPTH, 16#0D36). +-define(GL_MAX_NAME_STACK_DEPTH, 16#0D37). +-define(GL_MAX_PROJECTION_STACK_DEPTH, 16#0D38). +-define(GL_MAX_TEXTURE_STACK_DEPTH, 16#0D39). +-define(GL_MAX_VIEWPORT_DIMS, 16#0D3A). +-define(GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, 16#0D3B). +-define(GL_ATTRIB_STACK_DEPTH, 16#0BB0). +-define(GL_CLIENT_ATTRIB_STACK_DEPTH, 16#0BB1). +-define(GL_COLOR_CLEAR_VALUE, 16#0C22). +-define(GL_COLOR_WRITEMASK, 16#0C23). +-define(GL_CURRENT_INDEX, 16#0B01). +-define(GL_CURRENT_COLOR, 16#0B00). +-define(GL_CURRENT_NORMAL, 16#0B02). +-define(GL_CURRENT_RASTER_COLOR, 16#0B04). +-define(GL_CURRENT_RASTER_DISTANCE, 16#0B09). +-define(GL_CURRENT_RASTER_INDEX, 16#0B05). +-define(GL_CURRENT_RASTER_POSITION, 16#0B07). +-define(GL_CURRENT_RASTER_TEXTURE_COORDS, 16#0B06). +-define(GL_CURRENT_RASTER_POSITION_VALID, 16#0B08). +-define(GL_CURRENT_TEXTURE_COORDS, 16#0B03). +-define(GL_INDEX_CLEAR_VALUE, 16#0C20). +-define(GL_INDEX_MODE, 16#0C30). +-define(GL_INDEX_WRITEMASK, 16#0C21). +-define(GL_MODELVIEW_MATRIX, 16#0BA6). +-define(GL_MODELVIEW_STACK_DEPTH, 16#0BA3). +-define(GL_NAME_STACK_DEPTH, 16#0D70). +-define(GL_PROJECTION_MATRIX, 16#0BA7). +-define(GL_PROJECTION_STACK_DEPTH, 16#0BA4). +-define(GL_RENDER_MODE, 16#0C40). +-define(GL_RGBA_MODE, 16#0C31). +-define(GL_TEXTURE_MATRIX, 16#0BA8). +-define(GL_TEXTURE_STACK_DEPTH, 16#0BA5). +-define(GL_VIEWPORT, 16#0BA2). +-define(GL_AUTO_NORMAL, 16#0D80). +-define(GL_MAP1_COLOR_4, 16#0D90). +-define(GL_MAP1_INDEX, 16#0D91). +-define(GL_MAP1_NORMAL, 16#0D92). +-define(GL_MAP1_TEXTURE_COORD_1, 16#0D93). +-define(GL_MAP1_TEXTURE_COORD_2, 16#0D94). +-define(GL_MAP1_TEXTURE_COORD_3, 16#0D95). +-define(GL_MAP1_TEXTURE_COORD_4, 16#0D96). +-define(GL_MAP1_VERTEX_3, 16#0D97). +-define(GL_MAP1_VERTEX_4, 16#0D98). +-define(GL_MAP2_COLOR_4, 16#0DB0). +-define(GL_MAP2_INDEX, 16#0DB1). +-define(GL_MAP2_NORMAL, 16#0DB2). +-define(GL_MAP2_TEXTURE_COORD_1, 16#0DB3). +-define(GL_MAP2_TEXTURE_COORD_2, 16#0DB4). +-define(GL_MAP2_TEXTURE_COORD_3, 16#0DB5). +-define(GL_MAP2_TEXTURE_COORD_4, 16#0DB6). +-define(GL_MAP2_VERTEX_3, 16#0DB7). +-define(GL_MAP2_VERTEX_4, 16#0DB8). +-define(GL_MAP1_GRID_DOMAIN, 16#0DD0). +-define(GL_MAP1_GRID_SEGMENTS, 16#0DD1). +-define(GL_MAP2_GRID_DOMAIN, 16#0DD2). +-define(GL_MAP2_GRID_SEGMENTS, 16#0DD3). +-define(GL_COEFF, 16#0A00). +-define(GL_ORDER, 16#0A01). +-define(GL_DOMAIN, 16#0A02). +-define(GL_PERSPECTIVE_CORRECTION_HINT, 16#0C50). +-define(GL_POINT_SMOOTH_HINT, 16#0C51). +-define(GL_LINE_SMOOTH_HINT, 16#0C52). +-define(GL_POLYGON_SMOOTH_HINT, 16#0C53). +-define(GL_FOG_HINT, 16#0C54). -define(GL_DONT_CARE, 16#1100). -define(GL_FASTEST, 16#1101). -define(GL_NICEST, 16#1102). --define(GL_SCISSOR_BOX, 16#C10). --define(GL_SCISSOR_TEST, 16#C11). --define(GL_MAP_COLOR, 16#D10). --define(GL_MAP_STENCIL, 16#D11). --define(GL_INDEX_SHIFT, 16#D12). --define(GL_INDEX_OFFSET, 16#D13). --define(GL_RED_SCALE, 16#D14). --define(GL_RED_BIAS, 16#D15). --define(GL_GREEN_SCALE, 16#D18). --define(GL_GREEN_BIAS, 16#D19). --define(GL_BLUE_SCALE, 16#D1A). --define(GL_BLUE_BIAS, 16#D1B). --define(GL_ALPHA_SCALE, 16#D1C). --define(GL_ALPHA_BIAS, 16#D1D). --define(GL_DEPTH_SCALE, 16#D1E). --define(GL_DEPTH_BIAS, 16#D1F). --define(GL_PIXEL_MAP_S_TO_S_SIZE, 16#CB1). --define(GL_PIXEL_MAP_I_TO_I_SIZE, 16#CB0). --define(GL_PIXEL_MAP_I_TO_R_SIZE, 16#CB2). --define(GL_PIXEL_MAP_I_TO_G_SIZE, 16#CB3). --define(GL_PIXEL_MAP_I_TO_B_SIZE, 16#CB4). --define(GL_PIXEL_MAP_I_TO_A_SIZE, 16#CB5). --define(GL_PIXEL_MAP_R_TO_R_SIZE, 16#CB6). --define(GL_PIXEL_MAP_G_TO_G_SIZE, 16#CB7). --define(GL_PIXEL_MAP_B_TO_B_SIZE, 16#CB8). --define(GL_PIXEL_MAP_A_TO_A_SIZE, 16#CB9). --define(GL_PIXEL_MAP_S_TO_S, 16#C71). --define(GL_PIXEL_MAP_I_TO_I, 16#C70). --define(GL_PIXEL_MAP_I_TO_R, 16#C72). --define(GL_PIXEL_MAP_I_TO_G, 16#C73). --define(GL_PIXEL_MAP_I_TO_B, 16#C74). --define(GL_PIXEL_MAP_I_TO_A, 16#C75). --define(GL_PIXEL_MAP_R_TO_R, 16#C76). --define(GL_PIXEL_MAP_G_TO_G, 16#C77). --define(GL_PIXEL_MAP_B_TO_B, 16#C78). --define(GL_PIXEL_MAP_A_TO_A, 16#C79). --define(GL_PACK_ALIGNMENT, 16#D05). --define(GL_PACK_LSB_FIRST, 16#D01). --define(GL_PACK_ROW_LENGTH, 16#D02). --define(GL_PACK_SKIP_PIXELS, 16#D04). --define(GL_PACK_SKIP_ROWS, 16#D03). --define(GL_PACK_SWAP_BYTES, 16#D00). --define(GL_UNPACK_ALIGNMENT, 16#CF5). --define(GL_UNPACK_LSB_FIRST, 16#CF1). --define(GL_UNPACK_ROW_LENGTH, 16#CF2). --define(GL_UNPACK_SKIP_PIXELS, 16#CF4). --define(GL_UNPACK_SKIP_ROWS, 16#CF3). --define(GL_UNPACK_SWAP_BYTES, 16#CF0). --define(GL_ZOOM_X, 16#D16). --define(GL_ZOOM_Y, 16#D17). +-define(GL_SCISSOR_BOX, 16#0C10). +-define(GL_SCISSOR_TEST, 16#0C11). +-define(GL_MAP_COLOR, 16#0D10). +-define(GL_MAP_STENCIL, 16#0D11). +-define(GL_INDEX_SHIFT, 16#0D12). +-define(GL_INDEX_OFFSET, 16#0D13). +-define(GL_RED_SCALE, 16#0D14). +-define(GL_RED_BIAS, 16#0D15). +-define(GL_GREEN_SCALE, 16#0D18). +-define(GL_GREEN_BIAS, 16#0D19). +-define(GL_BLUE_SCALE, 16#0D1A). +-define(GL_BLUE_BIAS, 16#0D1B). +-define(GL_ALPHA_SCALE, 16#0D1C). +-define(GL_ALPHA_BIAS, 16#0D1D). +-define(GL_DEPTH_SCALE, 16#0D1E). +-define(GL_DEPTH_BIAS, 16#0D1F). +-define(GL_PIXEL_MAP_S_TO_S_SIZE, 16#0CB1). +-define(GL_PIXEL_MAP_I_TO_I_SIZE, 16#0CB0). +-define(GL_PIXEL_MAP_I_TO_R_SIZE, 16#0CB2). +-define(GL_PIXEL_MAP_I_TO_G_SIZE, 16#0CB3). +-define(GL_PIXEL_MAP_I_TO_B_SIZE, 16#0CB4). +-define(GL_PIXEL_MAP_I_TO_A_SIZE, 16#0CB5). +-define(GL_PIXEL_MAP_R_TO_R_SIZE, 16#0CB6). +-define(GL_PIXEL_MAP_G_TO_G_SIZE, 16#0CB7). +-define(GL_PIXEL_MAP_B_TO_B_SIZE, 16#0CB8). +-define(GL_PIXEL_MAP_A_TO_A_SIZE, 16#0CB9). +-define(GL_PIXEL_MAP_S_TO_S, 16#0C71). +-define(GL_PIXEL_MAP_I_TO_I, 16#0C70). +-define(GL_PIXEL_MAP_I_TO_R, 16#0C72). +-define(GL_PIXEL_MAP_I_TO_G, 16#0C73). +-define(GL_PIXEL_MAP_I_TO_B, 16#0C74). +-define(GL_PIXEL_MAP_I_TO_A, 16#0C75). +-define(GL_PIXEL_MAP_R_TO_R, 16#0C76). +-define(GL_PIXEL_MAP_G_TO_G, 16#0C77). +-define(GL_PIXEL_MAP_B_TO_B, 16#0C78). +-define(GL_PIXEL_MAP_A_TO_A, 16#0C79). +-define(GL_PACK_ALIGNMENT, 16#0D05). +-define(GL_PACK_LSB_FIRST, 16#0D01). +-define(GL_PACK_ROW_LENGTH, 16#0D02). +-define(GL_PACK_SKIP_PIXELS, 16#0D04). +-define(GL_PACK_SKIP_ROWS, 16#0D03). +-define(GL_PACK_SWAP_BYTES, 16#0D00). +-define(GL_UNPACK_ALIGNMENT, 16#0CF5). +-define(GL_UNPACK_LSB_FIRST, 16#0CF1). +-define(GL_UNPACK_ROW_LENGTH, 16#0CF2). +-define(GL_UNPACK_SKIP_PIXELS, 16#0CF4). +-define(GL_UNPACK_SKIP_ROWS, 16#0CF3). +-define(GL_UNPACK_SWAP_BYTES, 16#0CF0). +-define(GL_ZOOM_X, 16#0D16). +-define(GL_ZOOM_Y, 16#0D17). -define(GL_TEXTURE_ENV, 16#2300). -define(GL_TEXTURE_ENV_MODE, 16#2200). --define(GL_TEXTURE_1D, 16#DE0). --define(GL_TEXTURE_2D, 16#DE1). +-define(GL_TEXTURE_1D, 16#0DE0). +-define(GL_TEXTURE_2D, 16#0DE1). -define(GL_TEXTURE_WRAP_S, 16#2802). -define(GL_TEXTURE_WRAP_T, 16#2803). -define(GL_TEXTURE_MAG_FILTER, 16#2800). -define(GL_TEXTURE_MIN_FILTER, 16#2801). -define(GL_TEXTURE_ENV_COLOR, 16#2201). --define(GL_TEXTURE_GEN_S, 16#C60). --define(GL_TEXTURE_GEN_T, 16#C61). --define(GL_TEXTURE_GEN_R, 16#C62). --define(GL_TEXTURE_GEN_Q, 16#C63). +-define(GL_TEXTURE_GEN_S, 16#0C60). +-define(GL_TEXTURE_GEN_T, 16#0C61). +-define(GL_TEXTURE_GEN_R, 16#0C62). +-define(GL_TEXTURE_GEN_Q, 16#0C63). -define(GL_TEXTURE_GEN_MODE, 16#2500). -define(GL_TEXTURE_BORDER_COLOR, 16#1004). -define(GL_TEXTURE_WIDTH, 16#1000). @@ -482,33 +482,33 @@ -define(GL_VERSION, 16#1F02). -define(GL_EXTENSIONS, 16#1F03). -define(GL_NO_ERROR, 16#0). --define(GL_INVALID_ENUM, 16#500). --define(GL_INVALID_VALUE, 16#501). --define(GL_INVALID_OPERATION, 16#502). --define(GL_STACK_OVERFLOW, 16#503). --define(GL_STACK_UNDERFLOW, 16#504). --define(GL_OUT_OF_MEMORY, 16#505). --define(GL_CURRENT_BIT, 16#1). --define(GL_POINT_BIT, 16#2). --define(GL_LINE_BIT, 16#4). --define(GL_POLYGON_BIT, 16#8). --define(GL_POLYGON_STIPPLE_BIT, 16#10). --define(GL_PIXEL_MODE_BIT, 16#20). --define(GL_LIGHTING_BIT, 16#40). --define(GL_FOG_BIT, 16#80). --define(GL_DEPTH_BUFFER_BIT, 16#100). --define(GL_ACCUM_BUFFER_BIT, 16#200). --define(GL_STENCIL_BUFFER_BIT, 16#400). --define(GL_VIEWPORT_BIT, 16#800). --define(GL_TRANSFORM_BIT, 16#1000). --define(GL_ENABLE_BIT, 16#2000). --define(GL_COLOR_BUFFER_BIT, 16#4000). --define(GL_HINT_BIT, 16#8000). --define(GL_EVAL_BIT, 16#10000). --define(GL_LIST_BIT, 16#20000). --define(GL_TEXTURE_BIT, 16#40000). --define(GL_SCISSOR_BIT, 16#80000). --define(GL_ALL_ATTRIB_BITS, 16#FFFFF). +-define(GL_INVALID_ENUM, 16#0500). +-define(GL_INVALID_VALUE, 16#0501). +-define(GL_INVALID_OPERATION, 16#0502). +-define(GL_STACK_OVERFLOW, 16#0503). +-define(GL_STACK_UNDERFLOW, 16#0504). +-define(GL_OUT_OF_MEMORY, 16#0505). +-define(GL_CURRENT_BIT, 16#00000001). +-define(GL_POINT_BIT, 16#00000002). +-define(GL_LINE_BIT, 16#00000004). +-define(GL_POLYGON_BIT, 16#00000008). +-define(GL_POLYGON_STIPPLE_BIT, 16#00000010). +-define(GL_PIXEL_MODE_BIT, 16#00000020). +-define(GL_LIGHTING_BIT, 16#00000040). +-define(GL_FOG_BIT, 16#00000080). +-define(GL_DEPTH_BUFFER_BIT, 16#00000100). +-define(GL_ACCUM_BUFFER_BIT, 16#00000200). +-define(GL_STENCIL_BUFFER_BIT, 16#00000400). +-define(GL_VIEWPORT_BIT, 16#00000800). +-define(GL_TRANSFORM_BIT, 16#00001000). +-define(GL_ENABLE_BIT, 16#00002000). +-define(GL_COLOR_BUFFER_BIT, 16#00004000). +-define(GL_HINT_BIT, 16#00008000). +-define(GL_EVAL_BIT, 16#00010000). +-define(GL_LIST_BIT, 16#00020000). +-define(GL_TEXTURE_BIT, 16#00040000). +-define(GL_SCISSOR_BIT, 16#00080000). +-define(GL_ALL_ATTRIB_BITS, 16#000FFFFF). -define(GL_PROXY_TEXTURE_1D, 16#8063). -define(GL_PROXY_TEXTURE_2D, 16#8064). -define(GL_TEXTURE_PRIORITY, 16#8066). @@ -549,8 +549,8 @@ -define(GL_RGB10_A2, 16#8059). -define(GL_RGBA12, 16#805A). -define(GL_RGBA16, 16#805B). --define(GL_CLIENT_PIXEL_STORE_BIT, 16#1). --define(GL_CLIENT_VERTEX_ARRAY_BIT, 16#2). +-define(GL_CLIENT_PIXEL_STORE_BIT, 16#00000001). +-define(GL_CLIENT_VERTEX_ARRAY_BIT, 16#00000002). -define(GL_ALL_CLIENT_ATTRIB_BITS, 16#FFFFFFFF). -define(GL_CLIENT_ALL_ATTRIB_BITS, 16#FFFFFFFF). -define(GL_RESCALE_NORMAL, 16#803A). @@ -578,10 +578,10 @@ -define(GL_TEXTURE_MAX_LOD, 16#813B). -define(GL_TEXTURE_BASE_LEVEL, 16#813C). -define(GL_TEXTURE_MAX_LEVEL, 16#813D). --define(GL_SMOOTH_POINT_SIZE_RANGE, 16#B12). --define(GL_SMOOTH_POINT_SIZE_GRANULARITY, 16#B13). --define(GL_SMOOTH_LINE_WIDTH_RANGE, 16#B22). --define(GL_SMOOTH_LINE_WIDTH_GRANULARITY, 16#B23). +-define(GL_SMOOTH_POINT_SIZE_RANGE, 16#0B12). +-define(GL_SMOOTH_POINT_SIZE_GRANULARITY, 16#0B13). +-define(GL_SMOOTH_LINE_WIDTH_RANGE, 16#0B22). +-define(GL_SMOOTH_LINE_WIDTH_GRANULARITY, 16#0B23). -define(GL_ALIASED_POINT_SIZE_RANGE, 16#846D). -define(GL_ALIASED_LINE_WIDTH_RANGE, 16#846E). -define(GL_PACK_SKIP_IMAGES, 16#806B). @@ -808,14 +808,14 @@ -define(GL_UNSIGNED_SHORT_15_1_MESA, 16#8753). -define(GL_UNSIGNED_SHORT_1_15_REV_MESA, 16#8754). -define(GL_MESA_program_debug, 1). --define(GL_FRAGMENT_PROGRAM_POSITION_MESA, 16#8BB0). --define(GL_FRAGMENT_PROGRAM_CALLBACK_MESA, 16#8BB1). --define(GL_FRAGMENT_PROGRAM_CALLBACK_FUNC_MESA, 16#8BB2). --define(GL_FRAGMENT_PROGRAM_CALLBACK_DATA_MESA, 16#8BB3). --define(GL_VERTEX_PROGRAM_POSITION_MESA, 16#8BB4). --define(GL_VERTEX_PROGRAM_CALLBACK_MESA, 16#8BB5). --define(GL_VERTEX_PROGRAM_CALLBACK_FUNC_MESA, 16#8BB6). --define(GL_VERTEX_PROGRAM_CALLBACK_DATA_MESA, 16#8BB7). +-define(GL_FRAGMENT_PROGRAM_POSITION_MESA, 16#8bb0). +-define(GL_FRAGMENT_PROGRAM_CALLBACK_MESA, 16#8bb1). +-define(GL_FRAGMENT_PROGRAM_CALLBACK_FUNC_MESA, 16#8bb2). +-define(GL_FRAGMENT_PROGRAM_CALLBACK_DATA_MESA, 16#8bb3). +-define(GL_VERTEX_PROGRAM_POSITION_MESA, 16#8bb4). +-define(GL_VERTEX_PROGRAM_CALLBACK_MESA, 16#8bb5). +-define(GL_VERTEX_PROGRAM_CALLBACK_FUNC_MESA, 16#8bb6). +-define(GL_VERTEX_PROGRAM_CALLBACK_DATA_MESA, 16#8bb7). -define(GL_MESA_texture_array, 1). -define(GL_TEXTURE_1D_ARRAY_EXT, 16#8C18). -define(GL_PROXY_TEXTURE_1D_ARRAY_EXT, 16#8C19). @@ -1034,14 +1034,14 @@ -define(GL_CLIP_DISTANCE5, 16#3005). -define(GL_CLIP_DISTANCE6, 16#3006). -define(GL_CLIP_DISTANCE7, 16#3007). --define(GL_MAX_CLIP_DISTANCES, 16#D32). +-define(GL_MAX_CLIP_DISTANCES, 16#0D32). -define(GL_MAJOR_VERSION, 16#821B). -define(GL_MINOR_VERSION, 16#821C). -define(GL_NUM_EXTENSIONS, 16#821D). -define(GL_CONTEXT_FLAGS, 16#821E). -define(GL_COMPRESSED_RED, 16#8225). -define(GL_COMPRESSED_RG, 16#8226). --define(GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT, 16#1). +-define(GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT, 16#0001). -define(GL_RGBA32F, 16#8814). -define(GL_RGB32F, 16#8815). -define(GL_RGBA16F, 16#881A). @@ -1159,12 +1159,12 @@ -define(GL_SIGNED_NORMALIZED, 16#8F9C). -define(GL_PRIMITIVE_RESTART, 16#8F9D). -define(GL_PRIMITIVE_RESTART_INDEX, 16#8F9E). --define(GL_CONTEXT_CORE_PROFILE_BIT, 16#1). --define(GL_CONTEXT_COMPATIBILITY_PROFILE_BIT, 16#2). --define(GL_LINES_ADJACENCY, 16#A). --define(GL_LINE_STRIP_ADJACENCY, 16#B). --define(GL_TRIANGLES_ADJACENCY, 16#C). --define(GL_TRIANGLE_STRIP_ADJACENCY, 16#D). +-define(GL_CONTEXT_CORE_PROFILE_BIT, 16#00000001). +-define(GL_CONTEXT_COMPATIBILITY_PROFILE_BIT, 16#00000002). +-define(GL_LINES_ADJACENCY, 16#000A). +-define(GL_LINE_STRIP_ADJACENCY, 16#000B). +-define(GL_TRIANGLES_ADJACENCY, 16#000C). +-define(GL_TRIANGLE_STRIP_ADJACENCY, 16#000D). -define(GL_PROGRAM_POINT_SIZE, 16#8642). -define(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, 16#8C29). -define(GL_FRAMEBUFFER_ATTACHMENT_LAYERED, 16#8DA7). @@ -1551,7 +1551,7 @@ -define(GL_DEPTH_COMPONENT32F, 16#8CAC). -define(GL_DEPTH32F_STENCIL8, 16#8CAD). -define(GL_FLOAT_32_UNSIGNED_INT_24_8_REV, 16#8DAD). --define(GL_INVALID_FRAMEBUFFER_OPERATION, 16#506). +-define(GL_INVALID_FRAMEBUFFER_OPERATION, 16#0506). -define(GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, 16#8210). -define(GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE, 16#8211). -define(GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, 16#8212). @@ -1632,10 +1632,10 @@ -define(GL_TEXTURE_LUMINANCE_TYPE, 16#8C14). -define(GL_TEXTURE_INTENSITY_TYPE, 16#8C15). -define(GL_FRAMEBUFFER_SRGB, 16#8DB9). --define(GL_LINES_ADJACENCY_ARB, 16#A). --define(GL_LINE_STRIP_ADJACENCY_ARB, 16#B). --define(GL_TRIANGLES_ADJACENCY_ARB, 16#C). --define(GL_TRIANGLE_STRIP_ADJACENCY_ARB, 16#D). +-define(GL_LINES_ADJACENCY_ARB, 16#000A). +-define(GL_LINE_STRIP_ADJACENCY_ARB, 16#000B). +-define(GL_TRIANGLES_ADJACENCY_ARB, 16#000C). +-define(GL_TRIANGLE_STRIP_ADJACENCY_ARB, 16#000D). -define(GL_PROGRAM_POINT_SIZE_ARB, 16#8642). -define(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB, 16#8C29). -define(GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB, 16#8DA7). @@ -1652,12 +1652,12 @@ -define(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB, 16#8DE1). -define(GL_HALF_FLOAT, 16#140B). -define(GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB, 16#88FE). --define(GL_MAP_READ_BIT, 16#1). --define(GL_MAP_WRITE_BIT, 16#2). --define(GL_MAP_INVALIDATE_RANGE_BIT, 16#4). --define(GL_MAP_INVALIDATE_BUFFER_BIT, 16#8). --define(GL_MAP_FLUSH_EXPLICIT_BIT, 16#10). --define(GL_MAP_UNSYNCHRONIZED_BIT, 16#20). +-define(GL_MAP_READ_BIT, 16#0001). +-define(GL_MAP_WRITE_BIT, 16#0002). +-define(GL_MAP_INVALIDATE_RANGE_BIT, 16#0004). +-define(GL_MAP_INVALIDATE_BUFFER_BIT, 16#0008). +-define(GL_MAP_FLUSH_EXPLICIT_BIT, 16#0010). +-define(GL_MAP_UNSYNCHRONIZED_BIT, 16#0020). -define(GL_TEXTURE_BUFFER_ARB, 16#8C2A). -define(GL_MAX_TEXTURE_BUFFER_SIZE_ARB, 16#8C2B). -define(GL_TEXTURE_BINDING_BUFFER_ARB, 16#8C2C). @@ -1722,7 +1722,7 @@ -define(GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER, 16#8A44). -define(GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER, 16#8A45). -define(GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER, 16#8A46). --define(GL_INVALID_INDEX, 16#FFFFFFFF). +-define(GL_INVALID_INDEX, 16#FFFFFFFFu). -define(GL_COPY_READ_BUFFER, 16#8F36). -define(GL_COPY_WRITE_BUFFER, 16#8F37). -define(GL_DEPTH_CLAMP, 16#864F). @@ -1744,8 +1744,8 @@ -define(GL_TIMEOUT_EXPIRED, 16#911B). -define(GL_CONDITION_SATISFIED, 16#911C). -define(GL_WAIT_FAILED, 16#911D). --define(GL_SYNC_FLUSH_COMMANDS_BIT, 16#1). --define(GL_TIMEOUT_IGNORED, 16#FFFFFFFFFFFFFFFF). +-define(GL_SYNC_FLUSH_COMMANDS_BIT, 16#00000001). +-define(GL_TIMEOUT_IGNORED, 16#FFFFFFFFFFFFFFFFull). -define(GL_SAMPLE_POSITION, 16#8E50). -define(GL_SAMPLE_MASK, 16#8E51). -define(GL_SAMPLE_MASK_VALUE, 16#8E52). @@ -1828,7 +1828,7 @@ -define(GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS, 16#8DE8). -define(GL_NUM_COMPATIBLE_SUBROUTINES, 16#8E4A). -define(GL_COMPATIBLE_SUBROUTINES, 16#8E4B). --define(GL_PATCHES, 16#E). +-define(GL_PATCHES, 16#000E). -define(GL_PATCH_VERTICES, 16#8E72). -define(GL_PATCH_DEFAULT_INNER_LEVEL, 16#8E73). -define(GL_PATCH_DEFAULT_OUTER_LEVEL, 16#8E74). @@ -1884,11 +1884,11 @@ -define(GL_PROGRAM_BINARY_LENGTH, 16#8741). -define(GL_NUM_PROGRAM_BINARY_FORMATS, 16#87FE). -define(GL_PROGRAM_BINARY_FORMATS, 16#87FF). --define(GL_VERTEX_SHADER_BIT, 16#1). --define(GL_FRAGMENT_SHADER_BIT, 16#2). --define(GL_GEOMETRY_SHADER_BIT, 16#4). --define(GL_TESS_CONTROL_SHADER_BIT, 16#8). --define(GL_TESS_EVALUATION_SHADER_BIT, 16#10). +-define(GL_VERTEX_SHADER_BIT, 16#00000001). +-define(GL_FRAGMENT_SHADER_BIT, 16#00000002). +-define(GL_GEOMETRY_SHADER_BIT, 16#00000004). +-define(GL_TESS_CONTROL_SHADER_BIT, 16#00000008). +-define(GL_TESS_EVALUATION_SHADER_BIT, 16#00000010). -define(GL_ALL_SHADER_BITS, 16#FFFFFFFF). -define(GL_PROGRAM_SEPARABLE, 16#8258). -define(GL_ACTIVE_PROGRAM, 16#8259). @@ -1923,7 +1923,7 @@ -define(GL_DEBUG_SEVERITY_HIGH_ARB, 16#9146). -define(GL_DEBUG_SEVERITY_MEDIUM_ARB, 16#9147). -define(GL_DEBUG_SEVERITY_LOW_ARB, 16#9148). --define(GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB, 16#4). +-define(GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB, 16#00000004). -define(GL_LOSE_CONTEXT_ON_RESET_ARB, 16#8252). -define(GL_GUILTY_CONTEXT_RESET_ARB, 16#8253). -define(GL_INNOCENT_CONTEXT_RESET_ARB, 16#8254). @@ -1969,18 +1969,18 @@ -define(GL_ACTIVE_ATOMIC_COUNTER_BUFFERS, 16#92D9). -define(GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX, 16#92DA). -define(GL_UNSIGNED_INT_ATOMIC_COUNTER, 16#92DB). --define(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT, 16#1). --define(GL_ELEMENT_ARRAY_BARRIER_BIT, 16#2). --define(GL_UNIFORM_BARRIER_BIT, 16#4). --define(GL_TEXTURE_FETCH_BARRIER_BIT, 16#8). --define(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT, 16#20). --define(GL_COMMAND_BARRIER_BIT, 16#40). --define(GL_PIXEL_BUFFER_BARRIER_BIT, 16#80). --define(GL_TEXTURE_UPDATE_BARRIER_BIT, 16#100). --define(GL_BUFFER_UPDATE_BARRIER_BIT, 16#200). --define(GL_FRAMEBUFFER_BARRIER_BIT, 16#400). --define(GL_TRANSFORM_FEEDBACK_BARRIER_BIT, 16#800). --define(GL_ATOMIC_COUNTER_BARRIER_BIT, 16#1000). +-define(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT, 16#00000001). +-define(GL_ELEMENT_ARRAY_BARRIER_BIT, 16#00000002). +-define(GL_UNIFORM_BARRIER_BIT, 16#00000004). +-define(GL_TEXTURE_FETCH_BARRIER_BIT, 16#00000008). +-define(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT, 16#00000020). +-define(GL_COMMAND_BARRIER_BIT, 16#00000040). +-define(GL_PIXEL_BUFFER_BARRIER_BIT, 16#00000080). +-define(GL_TEXTURE_UPDATE_BARRIER_BIT, 16#00000100). +-define(GL_BUFFER_UPDATE_BARRIER_BIT, 16#00000200). +-define(GL_FRAMEBUFFER_BARRIER_BIT, 16#00000400). +-define(GL_TRANSFORM_FEEDBACK_BARRIER_BIT, 16#00000800). +-define(GL_ATOMIC_COUNTER_BARRIER_BIT, 16#00001000). -define(GL_ALL_BARRIER_BITS, 16#FFFFFFFF). -define(GL_MAX_IMAGE_UNITS, 16#8F38). -define(GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS, 16#8F39). @@ -2337,8 +2337,8 @@ -define(GL_FRAMEZOOM_SGIX, 16#818B). -define(GL_FRAMEZOOM_FACTOR_SGIX, 16#818C). -define(GL_MAX_FRAMEZOOM_FACTOR_SGIX, 16#818D). --define(GL_TEXTURE_DEFORMATION_BIT_SGIX, 16#1). --define(GL_GEOMETRY_DEFORMATION_BIT_SGIX, 16#2). +-define(GL_TEXTURE_DEFORMATION_BIT_SGIX, 16#00000001). +-define(GL_GEOMETRY_DEFORMATION_BIT_SGIX, 16#00000002). -define(GL_GEOMETRY_DEFORMATION_SGIX, 16#8194). -define(GL_TEXTURE_DEFORMATION_SGIX, 16#8195). -define(GL_DEFORMATIONS_MASK_SGIX, 16#8196). @@ -2377,24 +2377,24 @@ -define(GL_VERTEX_CONSISTENT_HINT_PGI, 16#1A22B). -define(GL_MATERIAL_SIDE_HINT_PGI, 16#1A22C). -define(GL_MAX_VERTEX_HINT_PGI, 16#1A22D). --define(GL_COLOR3_BIT_PGI, 16#10000). --define(GL_COLOR4_BIT_PGI, 16#20000). --define(GL_EDGEFLAG_BIT_PGI, 16#40000). --define(GL_INDEX_BIT_PGI, 16#80000). --define(GL_MAT_AMBIENT_BIT_PGI, 16#100000). --define(GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI, 16#200000). --define(GL_MAT_DIFFUSE_BIT_PGI, 16#400000). --define(GL_MAT_EMISSION_BIT_PGI, 16#800000). --define(GL_MAT_COLOR_INDEXES_BIT_PGI, 16#1000000). --define(GL_MAT_SHININESS_BIT_PGI, 16#2000000). --define(GL_MAT_SPECULAR_BIT_PGI, 16#4000000). --define(GL_NORMAL_BIT_PGI, 16#8000000). +-define(GL_COLOR3_BIT_PGI, 16#00010000). +-define(GL_COLOR4_BIT_PGI, 16#00020000). +-define(GL_EDGEFLAG_BIT_PGI, 16#00040000). +-define(GL_INDEX_BIT_PGI, 16#00080000). +-define(GL_MAT_AMBIENT_BIT_PGI, 16#00100000). +-define(GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI, 16#00200000). +-define(GL_MAT_DIFFUSE_BIT_PGI, 16#00400000). +-define(GL_MAT_EMISSION_BIT_PGI, 16#00800000). +-define(GL_MAT_COLOR_INDEXES_BIT_PGI, 16#01000000). +-define(GL_MAT_SHININESS_BIT_PGI, 16#02000000). +-define(GL_MAT_SPECULAR_BIT_PGI, 16#04000000). +-define(GL_NORMAL_BIT_PGI, 16#08000000). -define(GL_TEXCOORD1_BIT_PGI, 16#10000000). -define(GL_TEXCOORD2_BIT_PGI, 16#20000000). -define(GL_TEXCOORD3_BIT_PGI, 16#40000000). -define(GL_TEXCOORD4_BIT_PGI, 16#80000000). --define(GL_VERTEX23_BIT_PGI, 16#4). --define(GL_VERTEX4_BIT_PGI, 16#8). +-define(GL_VERTEX23_BIT_PGI, 16#00000004). +-define(GL_VERTEX4_BIT_PGI, 16#00000008). -define(GL_PREFER_DOUBLEBUFFER_HINT_PGI, 16#1A1F8). -define(GL_CONSERVE_MEMORY_HINT_PGI, 16#1A1FD). -define(GL_RECLAIM_MEMORY_HINT_PGI, 16#1A1FE). @@ -2591,9 +2591,9 @@ -define(GL_TEXTURE_CONSTANT_DATA_SUNX, 16#81D6). -define(GL_GLOBAL_ALPHA_SUN, 16#81D9). -define(GL_GLOBAL_ALPHA_FACTOR_SUN, 16#81DA). --define(GL_RESTART_SUN, 16#1). --define(GL_REPLACE_MIDDLE_SUN, 16#2). --define(GL_REPLACE_OLDEST_SUN, 16#3). +-define(GL_RESTART_SUN, 16#0001). +-define(GL_REPLACE_MIDDLE_SUN, 16#0002). +-define(GL_REPLACE_OLDEST_SUN, 16#0003). -define(GL_TRIANGLE_LIST_SUN, 16#81D7). -define(GL_REPLACEMENT_CODE_SUN, 16#81D8). -define(GL_REPLACEMENT_CODE_ARRAY_SUN, 16#85C0). @@ -3112,19 +3112,19 @@ -define(GL_SWIZZLE_STQ_DQ_ATI, 16#8979). -define(GL_SWIZZLE_STRQ_ATI, 16#897A). -define(GL_SWIZZLE_STRQ_DQ_ATI, 16#897B). --define(GL_RED_BIT_ATI, 16#1). --define(GL_GREEN_BIT_ATI, 16#2). --define(GL_BLUE_BIT_ATI, 16#4). --define(GL_2X_BIT_ATI, 16#1). --define(GL_4X_BIT_ATI, 16#2). --define(GL_8X_BIT_ATI, 16#4). --define(GL_HALF_BIT_ATI, 16#8). --define(GL_QUARTER_BIT_ATI, 16#10). --define(GL_EIGHTH_BIT_ATI, 16#20). --define(GL_SATURATE_BIT_ATI, 16#40). --define(GL_COMP_BIT_ATI, 16#2). --define(GL_NEGATE_BIT_ATI, 16#4). --define(GL_BIAS_BIT_ATI, 16#8). +-define(GL_RED_BIT_ATI, 16#00000001). +-define(GL_GREEN_BIT_ATI, 16#00000002). +-define(GL_BLUE_BIT_ATI, 16#00000004). +-define(GL_2X_BIT_ATI, 16#00000001). +-define(GL_4X_BIT_ATI, 16#00000002). +-define(GL_8X_BIT_ATI, 16#00000004). +-define(GL_HALF_BIT_ATI, 16#00000008). +-define(GL_QUARTER_BIT_ATI, 16#00000010). +-define(GL_EIGHTH_BIT_ATI, 16#00000020). +-define(GL_SATURATE_BIT_ATI, 16#00000040). +-define(GL_COMP_BIT_ATI, 16#00000002). +-define(GL_NEGATE_BIT_ATI, 16#00000004). +-define(GL_BIAS_BIT_ATI, 16#00000008). -define(GL_PN_TRIANGLES_ATI, 16#87F0). -define(GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI, 16#87F1). -define(GL_PN_TRIANGLES_POINT_MODE_ATI, 16#87F2). @@ -3409,7 +3409,7 @@ -define(GL_MAX_PROGRAM_IF_DEPTH_NV, 16#88F6). -define(GL_MAX_PROGRAM_LOOP_DEPTH_NV, 16#88F7). -define(GL_MAX_PROGRAM_LOOP_COUNT_NV, 16#88F8). --define(GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 16#506). +-define(GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 16#0506). -define(GL_MAX_RENDERBUFFER_SIZE_EXT, 16#84E8). -define(GL_FRAMEBUFFER_BINDING_EXT, 16#8CA6). -define(GL_RENDERBUFFER_BINDING_EXT, 16#8CA7). @@ -3506,10 +3506,10 @@ -define(GL_MAX_PROGRAM_RESULT_COMPONENTS_NV, 16#8909). -define(GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV, 16#8DA5). -define(GL_MAX_PROGRAM_GENERIC_RESULTS_NV, 16#8DA6). --define(GL_LINES_ADJACENCY_EXT, 16#A). --define(GL_LINE_STRIP_ADJACENCY_EXT, 16#B). --define(GL_TRIANGLES_ADJACENCY_EXT, 16#C). --define(GL_TRIANGLE_STRIP_ADJACENCY_EXT, 16#D). +-define(GL_LINES_ADJACENCY_EXT, 16#000A). +-define(GL_LINE_STRIP_ADJACENCY_EXT, 16#000B). +-define(GL_TRIANGLES_ADJACENCY_EXT, 16#000C). +-define(GL_TRIANGLE_STRIP_ADJACENCY_EXT, 16#000D). -define(GL_GEOMETRY_PROGRAM_NV, 16#8C26). -define(GL_MAX_PROGRAM_OUTPUT_VERTICES_NV, 16#8C27). -define(GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV, 16#8C28). @@ -3891,18 +3891,18 @@ -define(GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT, 16#906C). -define(GL_MAX_IMAGE_SAMPLES_EXT, 16#906D). -define(GL_IMAGE_BINDING_FORMAT_EXT, 16#906E). --define(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT, 16#1). --define(GL_ELEMENT_ARRAY_BARRIER_BIT_EXT, 16#2). --define(GL_UNIFORM_BARRIER_BIT_EXT, 16#4). --define(GL_TEXTURE_FETCH_BARRIER_BIT_EXT, 16#8). --define(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT, 16#20). --define(GL_COMMAND_BARRIER_BIT_EXT, 16#40). --define(GL_PIXEL_BUFFER_BARRIER_BIT_EXT, 16#80). --define(GL_TEXTURE_UPDATE_BARRIER_BIT_EXT, 16#100). --define(GL_BUFFER_UPDATE_BARRIER_BIT_EXT, 16#200). --define(GL_FRAMEBUFFER_BARRIER_BIT_EXT, 16#400). --define(GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT, 16#800). --define(GL_ATOMIC_COUNTER_BARRIER_BIT_EXT, 16#1000). +-define(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT, 16#00000001). +-define(GL_ELEMENT_ARRAY_BARRIER_BIT_EXT, 16#00000002). +-define(GL_UNIFORM_BARRIER_BIT_EXT, 16#00000004). +-define(GL_TEXTURE_FETCH_BARRIER_BIT_EXT, 16#00000008). +-define(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT, 16#00000020). +-define(GL_COMMAND_BARRIER_BIT_EXT, 16#00000040). +-define(GL_PIXEL_BUFFER_BARRIER_BIT_EXT, 16#00000080). +-define(GL_TEXTURE_UPDATE_BARRIER_BIT_EXT, 16#00000100). +-define(GL_BUFFER_UPDATE_BARRIER_BIT_EXT, 16#00000200). +-define(GL_FRAMEBUFFER_BARRIER_BIT_EXT, 16#00000400). +-define(GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT, 16#00000800). +-define(GL_ATOMIC_COUNTER_BARRIER_BIT_EXT, 16#00001000). -define(GL_ALL_BARRIER_BITS_EXT, 16#FFFFFFFF). -define(GL_DOUBLE_VEC2_EXT, 16#8FFC). -define(GL_DOUBLE_VEC3_EXT, 16#8FFD). @@ -3952,7 +3952,7 @@ -define(GL_FLOAT16_VEC2_NV, 16#8FF9). -define(GL_FLOAT16_VEC3_NV, 16#8FFA). -define(GL_FLOAT16_VEC4_NV, 16#8FFB). --define(GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV, 16#10). +-define(GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV, 16#00000010). -define(GL_MAX_PROGRAM_PATCH_ATTRIBS_NV, 16#86D8). -define(GL_TESS_CONTROL_PROGRAM_NV, 16#891E). -define(GL_TESS_EVALUATION_PROGRAM_NV, 16#891F). diff --git a/lib/wx/include/glu.hrl b/lib/wx/include/glu.hrl index a2ab55d054..dc55c5bb96 100644 --- a/lib/wx/include/glu.hrl +++ b/lib/wx/include/glu.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-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 @@ -174,4 +174,4 @@ -define(GLU_TESS_WINDING_POSITIVE, 100132). -define(GLU_TESS_WINDING_NEGATIVE, 100133). -define(GLU_TESS_WINDING_ABS_GEQ_TWO, 100134). --define(GLU_TESS_MAX_COORD, ?1.0e150). +-define(GLU_TESS_MAX_COORD, 1.0e150). diff --git a/lib/wx/include/wx.hrl b/lib/wx/include/wx.hrl index fba99a1f07..62979908a6 100644 --- a/lib/wx/include/wx.hrl +++ b/lib/wx/include/wx.hrl @@ -316,12 +316,13 @@ -type wxEventType() :: wxAuiManagerEventType() | wxAuiNotebookEventType() | wxCalendarEventType() | wxChildFocusEventType() | wxCloseEventType() | wxColourPickerEventType() | wxCommandEventType() | wxContextMenuEventType() | wxDateEventType() | wxDisplayChangedEventType() | wxEraseEventType() | wxFileDirPickerEventType() | wxFocusEventType() | wxFontPickerEventType() | wxGridEventType() | wxHelpEventType() | wxHtmlLinkEventType() | wxIconizeEventType() | wxIdleEventType() | wxJoystickEventType() | wxKeyEventType() | wxListEventType() | wxMaximizeEventType() | wxMenuEventType() | wxMouseCaptureChangedEventType() | wxMouseEventType() | wxMoveEventType() | wxNavigationKeyEventType() | wxNcPaintEventType() | wxNotebookEventType() | wxPaintEventType() | wxPaletteChangedEventType() | wxQueryNewPaletteEventType() | wxSashEventType() | wxScrollEventType() | wxScrollWinEventType() | wxSetCursorEventType() | wxShowEventType() | wxSizeEventType() | wxSpinEventType() | wxSplitterEventType() | wxStyledTextEventType() | wxSysColourChangedEventType() | wxTaskBarIconEventType() | wxTreeEventType() | wxUpdateUIEventType() | wxWindowCreateEventType() | wxWindowDestroyEventType(). %% Hardcoded Records --record(wxMouseState, {x, y, %% integer() - leftDown, middleDown, rightDown, %% bool() - controlDown, shiftDown, altDown, metaDown, cmdDown %% bool() +-record(wxMouseState, {x :: integer(), y :: integer(), + leftDown :: boolean(), middleDown :: boolean, rightDown :: boolean, + controlDown :: boolean(), shiftDown :: boolean(), + altDown :: boolean(), metaDown :: boolean(), cmdDown :: boolean() }). -record(wxHtmlLinkInfo, { - href, target %% unicode:chardata() + href :: unicode:chardata(), target :: unicode:chardata() }). %% Hardcoded Defines @@ -984,7 +985,7 @@ -define(wxRESET, 16384). -define(wxBACKWARD, 8192). -define(wxFORWARD, 4096). --define(wxICON_MASK, (?16#00000100 bor ?16#00000200 bor ?16#00000400 bor ?16#00000800)). +-define(wxICON_MASK, (16#00000100 bor 16#00000200 bor 16#00000400 bor 16#00000800)). -define(wxICON_ASTERISK, ?wxICON_INFORMATION). -define(wxICON_STOP, ?wxICON_HAND). -define(wxICON_INFORMATION, 2048). diff --git a/lib/wx/src/gen/wxAuiManager.erl b/lib/wx/src/gen/wxAuiManager.erl index 95dd5d64a5..71e851f706 100644 --- a/lib/wx/src/gen/wxAuiManager.erl +++ b/lib/wx/src/gen/wxAuiManager.erl @@ -119,7 +119,7 @@ detachPane(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef}) <<ThisRef:32/?UI,WindowRef:32/?UI>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauimanager.html#wxauimanagergetallpanes">external documentation</a>. --spec getAllPanes(This) -> wxAuiPaneInfoArray:wxAuiPaneInfoArray() when +-spec getAllPanes(This) -> wx:wx_object() when This::wxAuiManager(). getAllPanes(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxAuiManager), diff --git a/lib/wx/src/gen/wxBitmapButton.erl b/lib/wx/src/gen/wxBitmapButton.erl index 79e51da801..ddddbbc1dd 100644 --- a/lib/wx/src/gen/wxBitmapButton.erl +++ b/lib/wx/src/gen/wxBitmapButton.erl @@ -101,7 +101,7 @@ new(Parent,Id,Bitmap) Option :: {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id,#wx_ref{type=BitmapT,ref=BitmapRef}, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ParentT,wxWindow), @@ -129,7 +129,7 @@ create(This,Parent,Id,Bitmap) Option :: {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,#wx_ref{type=BitmapT,ref=BitmapRef}, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ThisT,wxBitmapButton), diff --git a/lib/wx/src/gen/wxButton.erl b/lib/wx/src/gen/wxButton.erl index ae78f53e6f..a27e5d91c2 100644 --- a/lib/wx/src/gen/wxButton.erl +++ b/lib/wx/src/gen/wxButton.erl @@ -99,7 +99,7 @@ new(Parent,Id) | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ParentT,wxWindow), @@ -128,7 +128,7 @@ create(This,Parent,Id) | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ThisT,wxButton), diff --git a/lib/wx/src/gen/wxCheckBox.erl b/lib/wx/src/gen/wxCheckBox.erl index 37bca77cae..6e30f14207 100644 --- a/lib/wx/src/gen/wxCheckBox.erl +++ b/lib/wx/src/gen/wxCheckBox.erl @@ -99,7 +99,7 @@ new(Parent,Id,Label) Option :: {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options) when is_integer(Id),is_list(Label),is_list(Options) -> ?CLASS(ParentT,wxWindow), @@ -127,7 +127,7 @@ create(This,Parent,Id,Label) Option :: {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options) when is_integer(Id),is_list(Label),is_list(Options) -> ?CLASS(ThisT,wxCheckBox), diff --git a/lib/wx/src/gen/wxCheckListBox.erl b/lib/wx/src/gen/wxCheckListBox.erl index 71199fed3b..083a9e32f4 100644 --- a/lib/wx/src/gen/wxCheckListBox.erl +++ b/lib/wx/src/gen/wxCheckListBox.erl @@ -106,7 +106,7 @@ new(Parent,Id) | {size, {W::integer(), H::integer()}} | {choices, [[unicode:chardata()]]} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ParentT,wxWindow), diff --git a/lib/wx/src/gen/wxChoice.erl b/lib/wx/src/gen/wxChoice.erl index b9cac3926c..2a2b2688fe 100644 --- a/lib/wx/src/gen/wxChoice.erl +++ b/lib/wx/src/gen/wxChoice.erl @@ -104,7 +104,7 @@ new(Parent,Id) | {size, {W::integer(), H::integer()}} | {choices, [[unicode:chardata()]]} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ParentT,wxWindow), @@ -130,7 +130,7 @@ create(This,Parent,Id,Pos={PosX,PosY},Size={SizeW,SizeH},Choices) -spec create(This, Parent, Id, Pos, Size, Choices, [Option]) -> boolean() when This::wxChoice(), Parent::wxWindow:wxWindow(), Id::integer(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[unicode:chardata()]], Option :: {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,{PosX,PosY},{SizeW,SizeH},Choices, Options) when is_integer(Id),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices),is_list(Options) -> ?CLASS(ThisT,wxChoice), diff --git a/lib/wx/src/gen/wxColourPickerCtrl.erl b/lib/wx/src/gen/wxColourPickerCtrl.erl index 5fd51eba15..1ba771695f 100644 --- a/lib/wx/src/gen/wxColourPickerCtrl.erl +++ b/lib/wx/src/gen/wxColourPickerCtrl.erl @@ -104,7 +104,7 @@ new(Parent,Id) | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ParentT,wxWindow), @@ -133,7 +133,7 @@ create(This,Parent,Id) | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ThisT,wxColourPickerCtrl), diff --git a/lib/wx/src/gen/wxComboBox.erl b/lib/wx/src/gen/wxComboBox.erl index b9224d18b9..c67ff82bbc 100644 --- a/lib/wx/src/gen/wxComboBox.erl +++ b/lib/wx/src/gen/wxComboBox.erl @@ -107,7 +107,7 @@ new(Parent,Id) | {size, {W::integer(), H::integer()}} | {choices, [[unicode:chardata()]]} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ParentT,wxWindow), @@ -134,7 +134,7 @@ create(This,Parent,Id,Value,Pos={PosX,PosY},Size={SizeW,SizeH},Choices) -spec create(This, Parent, Id, Value, Pos, Size, Choices, [Option]) -> boolean() when This::wxComboBox(), Parent::wxWindow:wxWindow(), Id::integer(), Value::unicode:chardata(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[unicode:chardata()]], Option :: {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Value,{PosX,PosY},{SizeW,SizeH},Choices, Options) when is_integer(Id),is_list(Value),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices),is_list(Options) -> ?CLASS(ThisT,wxComboBox), diff --git a/lib/wx/src/gen/wxDatePickerCtrl.erl b/lib/wx/src/gen/wxDatePickerCtrl.erl index ad66d1cf03..6ffc2ca3f5 100644 --- a/lib/wx/src/gen/wxDatePickerCtrl.erl +++ b/lib/wx/src/gen/wxDatePickerCtrl.erl @@ -104,7 +104,7 @@ new(Parent,Id) | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ParentT,wxWindow), diff --git a/lib/wx/src/gen/wxDirPickerCtrl.erl b/lib/wx/src/gen/wxDirPickerCtrl.erl index 5bc79ca7a1..bbc169ae03 100644 --- a/lib/wx/src/gen/wxDirPickerCtrl.erl +++ b/lib/wx/src/gen/wxDirPickerCtrl.erl @@ -105,7 +105,7 @@ new(Parent,Id) | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ParentT,wxWindow), @@ -136,7 +136,7 @@ create(This,Parent,Id) | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ThisT,wxDirPickerCtrl), diff --git a/lib/wx/src/gen/wxFilePickerCtrl.erl b/lib/wx/src/gen/wxFilePickerCtrl.erl index f13c20f6c7..d19c8c00cb 100644 --- a/lib/wx/src/gen/wxFilePickerCtrl.erl +++ b/lib/wx/src/gen/wxFilePickerCtrl.erl @@ -106,7 +106,7 @@ new(Parent,Id) | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ParentT,wxWindow), @@ -139,7 +139,7 @@ create(This,Parent,Id) | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ThisT,wxFilePickerCtrl), diff --git a/lib/wx/src/gen/wxFontPickerCtrl.erl b/lib/wx/src/gen/wxFontPickerCtrl.erl index 2659d4e2e3..46c0dbab4d 100644 --- a/lib/wx/src/gen/wxFontPickerCtrl.erl +++ b/lib/wx/src/gen/wxFontPickerCtrl.erl @@ -105,7 +105,7 @@ new(Parent,Id) | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ParentT,wxWindow), @@ -134,7 +134,7 @@ create(This,Parent,Id) | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ThisT,wxFontPickerCtrl), diff --git a/lib/wx/src/gen/wxGLCanvas.erl b/lib/wx/src/gen/wxGLCanvas.erl index 3a9cb39020..46168374af 100644 --- a/lib/wx/src/gen/wxGLCanvas.erl +++ b/lib/wx/src/gen/wxGLCanvas.erl @@ -96,7 +96,7 @@ new(Parent) %% | {palette, wxPalette:wxPalette()}.<br /> %% -spec new(Parent, Shared) -> wxGLCanvas() when - Parent::wxWindow:wxWindow(), Shared::wxGLContext:wxGLContext() | wxGLCanvas(); + Parent::wxWindow:wxWindow(), Shared::wx:wx_object() | wxGLCanvas(); (Parent, [Option]) -> wxGLCanvas() when Parent::wxWindow:wxWindow(), Option :: {id, integer()} @@ -128,7 +128,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef}, Options) %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxglcanvas.html#wxglcanvaswxglcanvas">external documentation</a>. -spec new(Parent, Shared, [Option]) -> wxGLCanvas() when - Parent::wxWindow:wxWindow(), Shared::wxGLContext:wxGLContext() | wxGLCanvas(), + Parent::wxWindow:wxWindow(), Shared::wx:wx_object() | wxGLCanvas(), Option :: {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} @@ -159,7 +159,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},#wx_ref{type=SharedT,ref=SharedRef}, Opt <<ParentRef:32/?UI,SharedRef:32/?UI, BinOpt/binary>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxglcanvas.html#wxglcanvasgetcontext">external documentation</a>. --spec getContext(This) -> wxGLContext:wxGLContext() when +-spec getContext(This) -> wx:wx_object() when This::wxGLCanvas(). getContext(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxGLCanvas), diff --git a/lib/wx/src/gen/wxGauge.erl b/lib/wx/src/gen/wxGauge.erl index c35a2574f6..7f892355c7 100644 --- a/lib/wx/src/gen/wxGauge.erl +++ b/lib/wx/src/gen/wxGauge.erl @@ -99,7 +99,7 @@ new(Parent,Id,Range) Option :: {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Range, Options) when is_integer(Id),is_integer(Range),is_list(Options) -> ?CLASS(ParentT,wxWindow), @@ -126,7 +126,7 @@ create(This,Parent,Id,Range) Option :: {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Range, Options) when is_integer(Id),is_integer(Range),is_list(Options) -> ?CLASS(ThisT,wxGauge), diff --git a/lib/wx/src/gen/wxGridBagSizer.erl b/lib/wx/src/gen/wxGridBagSizer.erl index 6a978efc85..e8a9ff6d76 100644 --- a/lib/wx/src/gen/wxGridBagSizer.erl +++ b/lib/wx/src/gen/wxGridBagSizer.erl @@ -98,7 +98,7 @@ add(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ItemT,ref=ItemRef}) -> %% Option :: {proportion, integer()}<br /> %% | {flag, integer()}<br /> %% | {border, integer()}<br /> -%% | {userData, wx:wx()}.<br /> +%% | {userData, wx:wx_object()}.<br /> %% -spec add(This, Width, Height) -> wxSizerItem:wxSizerItem() when This::wxGridBagSizer(), Width::integer(), Height::integer(); @@ -109,7 +109,7 @@ add(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ItemT,ref=ItemRef}) -> Option :: {proportion, integer()} | {flag, integer()} | {border, integer()} - | {userData, wx:wx()}. + | {userData, wx:wx_object()}. add(This,Width,Height) when is_record(This, wx_ref),is_integer(Width),is_integer(Height) -> @@ -143,13 +143,13 @@ add(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef}, Options %% Option :: {proportion, integer()}<br /> %% | {flag, integer()}<br /> %% | {border, integer()}<br /> -%% | {userData, wx:wx()};<br /> +%% | {userData, wx:wx_object()};<br /> %% (This, Window, Pos, [Option]) -> wxSizerItem:wxSizerItem() when<br /> %% This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Pos::{R::integer(), C::integer()},<br /> %% Option :: {span, {RS::integer(), CS::integer()}}<br /> %% | {flag, integer()}<br /> %% | {border, integer()}<br /> -%% | {userData, wx:wx()}.<br /> +%% | {userData, wx:wx_object()}.<br /> %% -spec add(This, Width, Height, Pos) -> wxSizerItem:wxSizerItem() when This::wxGridBagSizer(), Width::integer(), Height::integer(), Pos::{R::integer(), C::integer()}; @@ -158,13 +158,13 @@ add(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef}, Options Option :: {proportion, integer()} | {flag, integer()} | {border, integer()} - | {userData, wx:wx()}; + | {userData, wx:wx_object()}; (This, Window, Pos, [Option]) -> wxSizerItem:wxSizerItem() when This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Pos::{R::integer(), C::integer()}, Option :: {span, {RS::integer(), CS::integer()}} | {flag, integer()} | {border, integer()} - | {userData, wx:wx()}. + | {userData, wx:wx_object()}. add(This,Width,Height,Pos={PosR,PosC}) when is_record(This, wx_ref),is_integer(Width),is_integer(Height),is_integer(PosR),is_integer(PosC) -> @@ -204,7 +204,7 @@ add(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef},{PosR,Po Option :: {span, {RS::integer(), CS::integer()}} | {flag, integer()} | {border, integer()} - | {userData, wx:wx()}. + | {userData, wx:wx_object()}. add(#wx_ref{type=ThisT,ref=ThisRef},Width,Height,{PosR,PosC}, Options) when is_integer(Width),is_integer(Height),is_integer(PosR),is_integer(PosC),is_list(Options) -> ?CLASS(ThisT,wxGridBagSizer), @@ -305,7 +305,7 @@ findItemAtPosition(#wx_ref{type=ThisT,ref=ThisRef},{PosR,PosC}) %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizerfinditemwithdata">external documentation</a>. -spec findItemWithData(This, UserData) -> wxGBSizerItem:wxGBSizerItem() when - This::wxGridBagSizer(), UserData::wx:wx(). + This::wxGridBagSizer(), UserData::wx:wx_object(). findItemWithData(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=UserDataT,ref=UserDataRef}) -> ?CLASS(ThisT,wxGridBagSizer), ?CLASS(UserDataT,wx), diff --git a/lib/wx/src/gen/wxIcon.erl b/lib/wx/src/gen/wxIcon.erl index c726f2ed4c..0f31278732 100644 --- a/lib/wx/src/gen/wxIcon.erl +++ b/lib/wx/src/gen/wxIcon.erl @@ -50,13 +50,13 @@ new() -> %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxicon.html#wxiconwxicon">external documentation</a>. %% <br /> Also:<br /> %% new(Loc) -> wxIcon() when<br /> -%% Loc::wx:wx().<br /> +%% Loc::wx:wx_object().<br /> %% %%<br /> Type = ?wxBITMAP_TYPE_INVALID | ?wxBITMAP_TYPE_BMP | ?wxBITMAP_TYPE_BMP_RESOURCE | ?wxBITMAP_TYPE_RESOURCE | ?wxBITMAP_TYPE_ICO | ?wxBITMAP_TYPE_ICO_RESOURCE | ?wxBITMAP_TYPE_CUR | ?wxBITMAP_TYPE_CUR_RESOURCE | ?wxBITMAP_TYPE_XBM | ?wxBITMAP_TYPE_XBM_DATA | ?wxBITMAP_TYPE_XPM | ?wxBITMAP_TYPE_XPM_DATA | ?wxBITMAP_TYPE_TIF | ?wxBITMAP_TYPE_TIF_RESOURCE | ?wxBITMAP_TYPE_GIF | ?wxBITMAP_TYPE_GIF_RESOURCE | ?wxBITMAP_TYPE_PNG | ?wxBITMAP_TYPE_PNG_RESOURCE | ?wxBITMAP_TYPE_JPEG | ?wxBITMAP_TYPE_JPEG_RESOURCE | ?wxBITMAP_TYPE_PNM | ?wxBITMAP_TYPE_PNM_RESOURCE | ?wxBITMAP_TYPE_PCX | ?wxBITMAP_TYPE_PCX_RESOURCE | ?wxBITMAP_TYPE_PICT | ?wxBITMAP_TYPE_PICT_RESOURCE | ?wxBITMAP_TYPE_ICON | ?wxBITMAP_TYPE_ICON_RESOURCE | ?wxBITMAP_TYPE_ANI | ?wxBITMAP_TYPE_IFF | ?wxBITMAP_TYPE_TGA | ?wxBITMAP_TYPE_MACCURSOR | ?wxBITMAP_TYPE_MACCURSOR_RESOURCE | ?wxBITMAP_TYPE_ANY -spec new(Filename) -> wxIcon() when Filename::unicode:chardata(); (Loc) -> wxIcon() when - Loc::wx:wx(). + Loc::wx:wx_object(). new(Filename) when is_list(Filename) -> diff --git a/lib/wx/src/gen/wxListBox.erl b/lib/wx/src/gen/wxListBox.erl index bcaf5fad3b..3b41de9ffc 100644 --- a/lib/wx/src/gen/wxListBox.erl +++ b/lib/wx/src/gen/wxListBox.erl @@ -104,7 +104,7 @@ new(Parent,Id) | {size, {W::integer(), H::integer()}} | {choices, [[unicode:chardata()]]} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ParentT,wxWindow), @@ -130,7 +130,7 @@ create(This,Parent,Id,Pos={PosX,PosY},Size={SizeW,SizeH},Choices) -spec create(This, Parent, Id, Pos, Size, Choices, [Option]) -> boolean() when This::wxListBox(), Parent::wxWindow:wxWindow(), Id::integer(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[unicode:chardata()]], Option :: {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,{PosX,PosY},{SizeW,SizeH},Choices, Options) when is_integer(Id),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices),is_list(Options) -> ?CLASS(ThisT,wxListBox), diff --git a/lib/wx/src/gen/wxListCtrl.erl b/lib/wx/src/gen/wxListCtrl.erl index 16e8ae4508..a6288fc02a 100644 --- a/lib/wx/src/gen/wxListCtrl.erl +++ b/lib/wx/src/gen/wxListCtrl.erl @@ -34,10 +34,10 @@ deleteItem/2,destroy/1,editLabel/2,ensureVisible/2,findItem/3,findItem/4, getColumn/3,getColumnCount/1,getColumnWidth/2,getCountPerPage/1,getEditControl/1, getImageList/2,getItem/2,getItemBackgroundColour/2,getItemCount/1, - getItemData/2,getItemFont/2,getItemPosition/3,getItemRect/3,getItemRect/4, + getItemData/2,getItemFont/2,getItemPosition/2,getItemRect/2,getItemRect/3, getItemSpacing/1,getItemState/3,getItemText/2,getItemTextColour/2, getNextItem/2,getNextItem/3,getSelectedItemCount/1,getTextColour/1, - getTopItem/1,getViewRect/1,hitTest/2,insertColumn/3,insertColumn/4, + getTopItem/1,getViewRect/1,hitTest/3,insertColumn/3,insertColumn/4, insertItem/2,insertItem/3,insertItem/4,refreshItem/2,refreshItems/3, scrollList/3,setBackgroundColour/2,setColumn/3,setColumnWidth/3,setImageList/3, setItem/2,setItem/4,setItem/5,setItemBackgroundColour/3,setItemColumnImage/4, @@ -391,34 +391,37 @@ getItemFont(#wx_ref{type=ThisT,ref=ThisRef},Item) <<ThisRef:32/?UI,Item:32/?UI>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlgetitemposition">external documentation</a>. --spec getItemPosition(This, Item, Pos) -> boolean() when - This::wxListCtrl(), Item::integer(), Pos::{X::integer(), Y::integer()}. -getItemPosition(#wx_ref{type=ThisT,ref=ThisRef},Item,{PosX,PosY}) - when is_integer(Item),is_integer(PosX),is_integer(PosY) -> +-spec getItemPosition(This, Item) -> Result when + Result ::{Res ::boolean(), Pos::{X::integer(), Y::integer()}}, + This::wxListCtrl(), Item::integer(). +getItemPosition(#wx_ref{type=ThisT,ref=ThisRef},Item) + when is_integer(Item) -> ?CLASS(ThisT,wxListCtrl), wxe_util:call(?wxListCtrl_GetItemPosition, - <<ThisRef:32/?UI,Item:32/?UI,PosX:32/?UI,PosY:32/?UI>>). + <<ThisRef:32/?UI,Item:32/?UI>>). -%% @equiv getItemRect(This,Item,Rect, []) --spec getItemRect(This, Item, Rect) -> boolean() when - This::wxListCtrl(), Item::integer(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}. +%% @equiv getItemRect(This,Item, []) +-spec getItemRect(This, Item) -> Result when + Result ::{Res ::boolean(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}}, + This::wxListCtrl(), Item::integer(). -getItemRect(This,Item,Rect={RectX,RectY,RectW,RectH}) - when is_record(This, wx_ref),is_integer(Item),is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) -> - getItemRect(This,Item,Rect, []). +getItemRect(This,Item) + when is_record(This, wx_ref),is_integer(Item) -> + getItemRect(This,Item, []). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlgetitemrect">external documentation</a>. --spec getItemRect(This, Item, Rect, [Option]) -> boolean() when - This::wxListCtrl(), Item::integer(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, +-spec getItemRect(This, Item, [Option]) -> Result when + Result :: {Res ::boolean(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}}, + This::wxListCtrl(), Item::integer(), Option :: {code, integer()}. -getItemRect(#wx_ref{type=ThisT,ref=ThisRef},Item,{RectX,RectY,RectW,RectH}, Options) - when is_integer(Item),is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH),is_list(Options) -> +getItemRect(#wx_ref{type=ThisT,ref=ThisRef},Item, Options) + when is_integer(Item),is_list(Options) -> ?CLASS(ThisT,wxListCtrl), MOpts = fun({code, Code}, Acc) -> [<<1:32/?UI,Code:32/?UI>>|Acc]; (BadOpt, _) -> erlang:error({badoption, BadOpt}) end, BinOpt = list_to_binary(lists:foldl(MOpts, [<<0:32>>], Options)), wxe_util:call(?wxListCtrl_GetItemRect, - <<ThisRef:32/?UI,Item:32/?UI,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI, BinOpt/binary>>). + <<ThisRef:32/?UI,Item:32/?UI, BinOpt/binary>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlgetitemspacing">external documentation</a>. -spec getItemSpacing(This) -> {W::integer(), H::integer()} when @@ -511,14 +514,13 @@ getViewRect(#wx_ref{type=ThisT,ref=ThisRef}) -> <<ThisRef:32/?UI>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlhittest">external documentation</a>. --spec hitTest(This, Point) -> Result when - Result ::{Res ::integer(), Flags::integer()}, - This::wxListCtrl(), Point::{X::integer(), Y::integer()}. -hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PointX,PointY}) - when is_integer(PointX),is_integer(PointY) -> +-spec hitTest(This, Point, Flags) -> integer() when + This::wxListCtrl(), Point::{X::integer(), Y::integer()}, Flags::integer(). +hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PointX,PointY},Flags) + when is_integer(PointX),is_integer(PointY),is_integer(Flags) -> ?CLASS(ThisT,wxListCtrl), wxe_util:call(?wxListCtrl_HitTest, - <<ThisRef:32/?UI,PointX:32/?UI,PointY:32/?UI>>). + <<ThisRef:32/?UI,PointX:32/?UI,PointY:32/?UI,Flags:32/?UI>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlinsertcolumn">external documentation</a>. %% <br /> Also:<br /> diff --git a/lib/wx/src/gen/wxRadioBox.erl b/lib/wx/src/gen/wxRadioBox.erl index 1b3717de23..7843fde488 100644 --- a/lib/wx/src/gen/wxRadioBox.erl +++ b/lib/wx/src/gen/wxRadioBox.erl @@ -93,7 +93,7 @@ new(Parent,Id,Title,Pos={PosX,PosY},Size={SizeW,SizeH},Choices) Parent::wxWindow:wxWindow(), Id::integer(), Title::unicode:chardata(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[unicode:chardata()]], Option :: {majorDim, integer()} | {style, integer()} - | {val, wx:wx()}. + | {val, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title,{PosX,PosY},{SizeW,SizeH},Choices, Options) when is_integer(Id),is_list(Title),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices),is_list(Options) -> ?CLASS(ParentT,wxWindow), @@ -121,7 +121,7 @@ create(This,Parent,Id,Title,Pos={PosX,PosY},Size={SizeW,SizeH},Choices) This::wxRadioBox(), Parent::wxWindow:wxWindow(), Id::integer(), Title::unicode:chardata(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[unicode:chardata()]], Option :: {majorDim, integer()} | {style, integer()} - | {val, wx:wx()}. + | {val, wx:wx_object()}. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title,{PosX,PosY},{SizeW,SizeH},Choices, Options) when is_integer(Id),is_list(Title),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices),is_list(Options) -> ?CLASS(ThisT,wxRadioBox), diff --git a/lib/wx/src/gen/wxRadioButton.erl b/lib/wx/src/gen/wxRadioButton.erl index a013bd65e4..beb052b873 100644 --- a/lib/wx/src/gen/wxRadioButton.erl +++ b/lib/wx/src/gen/wxRadioButton.erl @@ -97,7 +97,7 @@ new(Parent,Id,Label) Option :: {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options) when is_integer(Id),is_list(Label),is_list(Options) -> ?CLASS(ParentT,wxWindow), @@ -125,7 +125,7 @@ create(This,Parent,Id,Label) Option :: {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options) when is_integer(Id),is_list(Label),is_list(Options) -> ?CLASS(ThisT,wxRadioButton), diff --git a/lib/wx/src/gen/wxScrollBar.erl b/lib/wx/src/gen/wxScrollBar.erl index 30272312ab..4370bd1635 100644 --- a/lib/wx/src/gen/wxScrollBar.erl +++ b/lib/wx/src/gen/wxScrollBar.erl @@ -98,7 +98,7 @@ new(Parent,Id) Option :: {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ParentT,wxWindow), @@ -125,7 +125,7 @@ create(This,Parent,Id) Option :: {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ThisT,wxScrollBar), diff --git a/lib/wx/src/gen/wxSizer.erl b/lib/wx/src/gen/wxSizer.erl index 104e1bcdc9..7edc01aa2a 100644 --- a/lib/wx/src/gen/wxSizer.erl +++ b/lib/wx/src/gen/wxSizer.erl @@ -56,7 +56,7 @@ add(This,Window) %% Option :: {proportion, integer()}<br /> %% | {flag, integer()}<br /> %% | {border, integer()}<br /> -%% | {userData, wx:wx()};<br /> +%% | {userData, wx:wx_object()};<br /> %% (This, Window, Flags) -> wxSizerItem:wxSizerItem() when<br /> %% This::wxSizer(), Window::wxWindow:wxWindow() | wxSizer(), Flags::wxSizerFlags:wxSizerFlags().<br /> %% @@ -67,7 +67,7 @@ add(This,Window) Option :: {proportion, integer()} | {flag, integer()} | {border, integer()} - | {userData, wx:wx()}; + | {userData, wx:wx_object()}; (This, Window, Flags) -> wxSizerItem:wxSizerItem() when This::wxSizer(), Window::wxWindow:wxWindow() | wxSizer(), Flags::wxSizerFlags:wxSizerFlags(). @@ -110,7 +110,7 @@ add(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef},#wx_ref{ Option :: {proportion, integer()} | {flag, integer()} | {border, integer()} - | {userData, wx:wx()}. + | {userData, wx:wx_object()}. add(#wx_ref{type=ThisT,ref=ThisRef},Width,Height, Options) when is_integer(Width),is_integer(Height),is_list(Options) -> ?CLASS(ThisT,wxSizer), @@ -350,7 +350,7 @@ insert(#wx_ref{type=ThisT,ref=ThisRef},Index,#wx_ref{type=ItemT,ref=ItemRef}) %% Option :: {proportion, integer()}<br /> %% | {flag, integer()}<br /> %% | {border, integer()}<br /> -%% | {userData, wx:wx()};<br /> +%% | {userData, wx:wx_object()};<br /> %% (This, Index, Window, Flags) -> wxSizerItem:wxSizerItem() when<br /> %% This::wxSizer(), Index::integer(), Window::wxWindow:wxWindow() | wxSizer(), Flags::wxSizerFlags:wxSizerFlags().<br /> %% @@ -361,7 +361,7 @@ insert(#wx_ref{type=ThisT,ref=ThisRef},Index,#wx_ref{type=ItemT,ref=ItemRef}) Option :: {proportion, integer()} | {flag, integer()} | {border, integer()} - | {userData, wx:wx()}; + | {userData, wx:wx_object()}; (This, Index, Window, Flags) -> wxSizerItem:wxSizerItem() when This::wxSizer(), Index::integer(), Window::wxWindow:wxWindow() | wxSizer(), Flags::wxSizerFlags:wxSizerFlags(). @@ -405,7 +405,7 @@ insert(#wx_ref{type=ThisT,ref=ThisRef},Index,#wx_ref{type=WindowT,ref=WindowRef} Option :: {proportion, integer()} | {flag, integer()} | {border, integer()} - | {userData, wx:wx()}. + | {userData, wx:wx_object()}. insert(#wx_ref{type=ThisT,ref=ThisRef},Index,Width,Height, Options) when is_integer(Index),is_integer(Width),is_integer(Height),is_list(Options) -> ?CLASS(ThisT,wxSizer), @@ -497,7 +497,7 @@ prepend(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ItemT,ref=ItemRef}) -> %% Option :: {proportion, integer()}<br /> %% | {flag, integer()}<br /> %% | {border, integer()}<br /> -%% | {userData, wx:wx()};<br /> +%% | {userData, wx:wx_object()};<br /> %% (This, Window, Flags) -> wxSizerItem:wxSizerItem() when<br /> %% This::wxSizer(), Window::wxWindow:wxWindow() | wxSizer(), Flags::wxSizerFlags:wxSizerFlags().<br /> %% @@ -508,7 +508,7 @@ prepend(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ItemT,ref=ItemRef}) -> Option :: {proportion, integer()} | {flag, integer()} | {border, integer()} - | {userData, wx:wx()}; + | {userData, wx:wx_object()}; (This, Window, Flags) -> wxSizerItem:wxSizerItem() when This::wxSizer(), Window::wxWindow:wxWindow() | wxSizer(), Flags::wxSizerFlags:wxSizerFlags(). @@ -551,7 +551,7 @@ prepend(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef},#wx_ Option :: {proportion, integer()} | {flag, integer()} | {border, integer()} - | {userData, wx:wx()}. + | {userData, wx:wx_object()}. prepend(#wx_ref{type=ThisT,ref=ThisRef},Width,Height, Options) when is_integer(Width),is_integer(Height),is_list(Options) -> ?CLASS(ThisT,wxSizer), diff --git a/lib/wx/src/gen/wxSizerItem.erl b/lib/wx/src/gen/wxSizerItem.erl index 22533500da..62655864d1 100644 --- a/lib/wx/src/gen/wxSizerItem.erl +++ b/lib/wx/src/gen/wxSizerItem.erl @@ -72,7 +72,7 @@ new(Width,Height,#wx_ref{type=FlagsT,ref=FlagsRef}) %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemwxsizeritem">external documentation</a>. -spec new(Window, Proportion, Flag, Border, UserData) -> wxSizerItem() when - Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Proportion::integer(), Flag::integer(), Border::integer(), UserData::wx:wx(). + Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Proportion::integer(), Flag::integer(), Border::integer(), UserData::wx:wx_object(). new(#wx_ref{type=WindowT,ref=WindowRef},Proportion,Flag,Border,#wx_ref{type=UserDataT,ref=UserDataRef}) when is_integer(Proportion),is_integer(Flag),is_integer(Border) -> WindowOP = case ?CLASS_T(WindowT,wxWindow) of @@ -88,7 +88,7 @@ new(#wx_ref{type=WindowT,ref=WindowRef},Proportion,Flag,Border,#wx_ref{type=User %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemwxsizeritem">external documentation</a>. -spec new(Width, Height, Proportion, Flag, Border, UserData) -> wxSizerItem() when - Width::integer(), Height::integer(), Proportion::integer(), Flag::integer(), Border::integer(), UserData::wx:wx(). + Width::integer(), Height::integer(), Proportion::integer(), Flag::integer(), Border::integer(), UserData::wx:wx_object(). new(Width,Height,Proportion,Flag,Border,#wx_ref{type=UserDataT,ref=UserDataRef}) when is_integer(Width),is_integer(Height),is_integer(Proportion),is_integer(Flag),is_integer(Border) -> ?CLASS(UserDataT,wx), @@ -200,7 +200,7 @@ getSpacer(#wx_ref{type=ThisT,ref=ThisRef}) -> <<ThisRef:32/?UI>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemgetuserdata">external documentation</a>. --spec getUserData(This) -> wx:wx() when +-spec getUserData(This) -> wx:wx_object() when This::wxSizerItem(). getUserData(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxSizerItem), diff --git a/lib/wx/src/gen/wxSlider.erl b/lib/wx/src/gen/wxSlider.erl index e951e559ca..459e9b9c35 100644 --- a/lib/wx/src/gen/wxSlider.erl +++ b/lib/wx/src/gen/wxSlider.erl @@ -99,7 +99,7 @@ new(Parent,Id,Value,MinValue,MaxValue) Option :: {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Value,MinValue,MaxValue, Options) when is_integer(Id),is_integer(Value),is_integer(MinValue),is_integer(MaxValue),is_list(Options) -> ?CLASS(ParentT,wxWindow), @@ -126,7 +126,7 @@ create(This,Parent,Id,Value,MinValue,MaxValue) Option :: {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Value,MinValue,MaxValue, Options) when is_integer(Id),is_integer(Value),is_integer(MinValue),is_integer(MaxValue),is_list(Options) -> ?CLASS(ThisT,wxSlider), diff --git a/lib/wx/src/gen/wxStyledTextCtrl.erl b/lib/wx/src/gen/wxStyledTextCtrl.erl index 057e01ddd5..f6dc2176b7 100644 --- a/lib/wx/src/gen/wxStyledTextCtrl.erl +++ b/lib/wx/src/gen/wxStyledTextCtrl.erl @@ -252,7 +252,7 @@ addText(#wx_ref{type=ThisT,ref=ThisRef},Text) %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrladdstyledtext">external documentation</a>. -spec addStyledText(This, Data) -> ok when - This::wxStyledTextCtrl(), Data::wxMemoryBuffer:wxMemoryBuffer(). + This::wxStyledTextCtrl(), Data::wx:wx_object(). addStyledText(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=DataT,ref=DataRef}) -> ?CLASS(ThisT,wxStyledTextCtrl), ?CLASS(DataT,wxMemoryBuffer), @@ -361,7 +361,7 @@ setSavePoint(#wx_ref{type=ThisT,ref=ThisRef}) -> <<ThisRef:32/?UI>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlgetstyledtext">external documentation</a>. --spec getStyledText(This, StartPos, EndPos) -> wxMemoryBuffer:wxMemoryBuffer() when +-spec getStyledText(This, StartPos, EndPos) -> wx:wx_object() when This::wxStyledTextCtrl(), StartPos::integer(), EndPos::integer(). getStyledText(#wx_ref{type=ThisT,ref=ThisRef},StartPos,EndPos) when is_integer(StartPos),is_integer(EndPos) -> diff --git a/lib/wx/src/gen/wxTextCtrl.erl b/lib/wx/src/gen/wxTextCtrl.erl index 21ff062d5b..e1f82c40c3 100644 --- a/lib/wx/src/gen/wxTextCtrl.erl +++ b/lib/wx/src/gen/wxTextCtrl.erl @@ -106,7 +106,7 @@ new(Parent,Id) | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ParentT,wxWindow), @@ -201,7 +201,7 @@ create(This,Parent,Id) | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options) when is_integer(Id),is_list(Options) -> ?CLASS(ThisT,wxTextCtrl), diff --git a/lib/wx/src/gen/wxToggleButton.erl b/lib/wx/src/gen/wxToggleButton.erl index 1d770b5ca5..ed2f564952 100644 --- a/lib/wx/src/gen/wxToggleButton.erl +++ b/lib/wx/src/gen/wxToggleButton.erl @@ -97,7 +97,7 @@ new(Parent,Id,Label) Option :: {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options) when is_integer(Id),is_list(Label),is_list(Options) -> ?CLASS(ParentT,wxWindow), @@ -125,7 +125,7 @@ create(This,Parent,Id,Label) Option :: {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options) when is_integer(Id),is_list(Label),is_list(Options) -> ?CLASS(ThisT,wxToggleButton), diff --git a/lib/wx/src/gen/wxToolBar.erl b/lib/wx/src/gen/wxToolBar.erl index e55becb748..9401e30e20 100644 --- a/lib/wx/src/gen/wxToolBar.erl +++ b/lib/wx/src/gen/wxToolBar.erl @@ -86,7 +86,7 @@ parent_class(_Class) -> erlang:error({badtype, ?MODULE}). -type wxToolBar() :: wx:wx_object(). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbaraddcontrol">external documentation</a>. --spec addControl(This, Control) -> wx:wx() when +-spec addControl(This, Control) -> wx:wx_object() when This::wxToolBar(), Control::wxControl:wxControl(). addControl(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ControlT,ref=ControlRef}) -> ?CLASS(ThisT,wxToolBar), @@ -95,7 +95,7 @@ addControl(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ControlT,ref=ControlRef} <<ThisRef:32/?UI,ControlRef:32/?UI>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbaraddseparator">external documentation</a>. --spec addSeparator(This) -> wx:wx() when +-spec addSeparator(This) -> wx:wx_object() when This::wxToolBar(). addSeparator(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxToolBar), @@ -103,8 +103,8 @@ addSeparator(#wx_ref{type=ThisT,ref=ThisRef}) -> <<ThisRef:32/?UI>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbaraddtool">external documentation</a>. --spec addTool(This, Tool) -> wx:wx() when - This::wxToolBar(), Tool::wx:wx(). +-spec addTool(This, Tool) -> wx:wx_object() when + This::wxToolBar(), Tool::wx:wx_object(). addTool(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ToolT,ref=ToolRef}) -> ?CLASS(ThisT,wxToolBar), ?CLASS(ToolT,wx), @@ -112,7 +112,7 @@ addTool(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ToolT,ref=ToolRef}) -> <<ThisRef:32/?UI,ToolRef:32/?UI>>). %% @equiv addTool(This,Toolid,Bitmap, []) --spec addTool(This, Toolid, Bitmap) -> wx:wx() when +-spec addTool(This, Toolid, Bitmap) -> wx:wx_object() when This::wxToolBar(), Toolid::integer(), Bitmap::wxBitmap:wxBitmap(). addTool(This,Toolid,Bitmap) @@ -121,19 +121,19 @@ addTool(This,Toolid,Bitmap) %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbaraddtool">external documentation</a>. %% <br /> Also:<br /> -%% addTool(This, Toolid, Bitmap, BmpDisabled) -> wx:wx() when<br /> +%% addTool(This, Toolid, Bitmap, BmpDisabled) -> wx:wx_object() when<br /> %% This::wxToolBar(), Toolid::integer(), Bitmap::wxBitmap:wxBitmap(), BmpDisabled::wxBitmap:wxBitmap();<br /> -%% (This, Toolid, Bitmap, [Option]) -> wx:wx() when<br /> +%% (This, Toolid, Bitmap, [Option]) -> wx:wx_object() when<br /> %% This::wxToolBar(), Toolid::integer(), Bitmap::wxBitmap:wxBitmap(),<br /> %% Option :: {shortHelpString, unicode:chardata()}<br /> %% | {longHelpString, unicode:chardata()}.<br /> %% %%<br /> Kind = ?wxITEM_SEPARATOR | ?wxITEM_NORMAL | ?wxITEM_CHECK | ?wxITEM_RADIO | ?wxITEM_MAX --spec addTool(This, Toolid, Label, Bitmap) -> wx:wx() when +-spec addTool(This, Toolid, Label, Bitmap) -> wx:wx_object() when This::wxToolBar(), Toolid::integer(), Label::unicode:chardata(), Bitmap::wxBitmap:wxBitmap(); - (This, Toolid, Bitmap, BmpDisabled) -> wx:wx() when + (This, Toolid, Bitmap, BmpDisabled) -> wx:wx_object() when This::wxToolBar(), Toolid::integer(), Bitmap::wxBitmap:wxBitmap(), BmpDisabled::wxBitmap:wxBitmap(); - (This, Toolid, Bitmap, [Option]) -> wx:wx() when + (This, Toolid, Bitmap, [Option]) -> wx:wx_object() when This::wxToolBar(), Toolid::integer(), Bitmap::wxBitmap:wxBitmap(), Option :: {shortHelpString, unicode:chardata()} | {longHelpString, unicode:chardata()}. @@ -158,28 +158,28 @@ addTool(#wx_ref{type=ThisT,ref=ThisRef},Toolid,#wx_ref{type=BitmapT,ref=BitmapRe %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbaraddtool">external documentation</a>. %% <br /> Also:<br /> -%% addTool(This, Toolid, Label, Bitmap, [Option]) -> wx:wx() when<br /> +%% addTool(This, Toolid, Label, Bitmap, [Option]) -> wx:wx_object() when<br /> %% This::wxToolBar(), Toolid::integer(), Label::unicode:chardata(), Bitmap::wxBitmap:wxBitmap(),<br /> %% Option :: {shortHelp, unicode:chardata()}<br /> %% | {kind, wx:wx_enum()};<br /> -%% (This, Toolid, Bitmap, BmpDisabled, [Option]) -> wx:wx() when<br /> +%% (This, Toolid, Bitmap, BmpDisabled, [Option]) -> wx:wx_object() when<br /> %% This::wxToolBar(), Toolid::integer(), Bitmap::wxBitmap:wxBitmap(), BmpDisabled::wxBitmap:wxBitmap(),<br /> %% Option :: {toggle, boolean()}<br /> -%% | {clientData, wx:wx()}<br /> +%% | {clientData, wx:wx_object()}<br /> %% | {shortHelpString, unicode:chardata()}<br /> %% | {longHelpString, unicode:chardata()}.<br /> %% %%<br /> Kind = ?wxITEM_SEPARATOR | ?wxITEM_NORMAL | ?wxITEM_CHECK | ?wxITEM_RADIO | ?wxITEM_MAX --spec addTool(This, Toolid, Label, Bitmap, BmpDisabled) -> wx:wx() when +-spec addTool(This, Toolid, Label, Bitmap, BmpDisabled) -> wx:wx_object() when This::wxToolBar(), Toolid::integer(), Label::unicode:chardata(), Bitmap::wxBitmap:wxBitmap(), BmpDisabled::wxBitmap:wxBitmap(); - (This, Toolid, Label, Bitmap, [Option]) -> wx:wx() when + (This, Toolid, Label, Bitmap, [Option]) -> wx:wx_object() when This::wxToolBar(), Toolid::integer(), Label::unicode:chardata(), Bitmap::wxBitmap:wxBitmap(), Option :: {shortHelp, unicode:chardata()} | {kind, wx:wx_enum()}; - (This, Toolid, Bitmap, BmpDisabled, [Option]) -> wx:wx() when + (This, Toolid, Bitmap, BmpDisabled, [Option]) -> wx:wx_object() when This::wxToolBar(), Toolid::integer(), Bitmap::wxBitmap:wxBitmap(), BmpDisabled::wxBitmap:wxBitmap(), Option :: {toggle, boolean()} - | {clientData, wx:wx()} + | {clientData, wx:wx_object()} | {shortHelpString, unicode:chardata()} | {longHelpString, unicode:chardata()}. @@ -213,22 +213,22 @@ addTool(#wx_ref{type=ThisT,ref=ThisRef},Toolid,#wx_ref{type=BitmapT,ref=BitmapRe %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbaraddtool">external documentation</a>. %% <br /> Also:<br /> -%% addTool(This, Toolid, Label, Bitmap, BmpDisabled, [Option]) -> wx:wx() when<br /> +%% addTool(This, Toolid, Label, Bitmap, BmpDisabled, [Option]) -> wx:wx_object() when<br /> %% This::wxToolBar(), Toolid::integer(), Label::unicode:chardata(), Bitmap::wxBitmap:wxBitmap(), BmpDisabled::wxBitmap:wxBitmap(),<br /> %% Option :: {kind, wx:wx_enum()}<br /> %% | {shortHelp, unicode:chardata()}<br /> %% | {longHelp, unicode:chardata()}<br /> -%% | {data, wx:wx()}.<br /> +%% | {data, wx:wx_object()}.<br /> %% %%<br /> Kind = ?wxITEM_SEPARATOR | ?wxITEM_NORMAL | ?wxITEM_CHECK | ?wxITEM_RADIO | ?wxITEM_MAX --spec addTool(This, Toolid, Bitmap, BmpDisabled, Toggle, XPos) -> wx:wx() when +-spec addTool(This, Toolid, Bitmap, BmpDisabled, Toggle, XPos) -> wx:wx_object() when This::wxToolBar(), Toolid::integer(), Bitmap::wxBitmap:wxBitmap(), BmpDisabled::wxBitmap:wxBitmap(), Toggle::boolean(), XPos::integer(); - (This, Toolid, Label, Bitmap, BmpDisabled, [Option]) -> wx:wx() when + (This, Toolid, Label, Bitmap, BmpDisabled, [Option]) -> wx:wx_object() when This::wxToolBar(), Toolid::integer(), Label::unicode:chardata(), Bitmap::wxBitmap:wxBitmap(), BmpDisabled::wxBitmap:wxBitmap(), Option :: {kind, wx:wx_enum()} | {shortHelp, unicode:chardata()} | {longHelp, unicode:chardata()} - | {data, wx:wx()}. + | {data, wx:wx_object()}. addTool(This,Toolid,Bitmap,BmpDisabled,Toggle,XPos) when is_record(This, wx_ref),is_integer(Toolid),is_record(Bitmap, wx_ref),is_record(BmpDisabled, wx_ref),is_boolean(Toggle),is_integer(XPos) -> @@ -249,10 +249,10 @@ addTool(#wx_ref{type=ThisT,ref=ThisRef},Toolid,Label,#wx_ref{type=BitmapT,ref=Bi <<ThisRef:32/?UI,Toolid:32/?UI,(byte_size(Label_UC)):32/?UI,(Label_UC)/binary, 0:(((8- ((4+byte_size(Label_UC)) band 16#7)) band 16#7))/unit:8,BitmapRef:32/?UI,BmpDisabledRef:32/?UI, BinOpt/binary>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbaraddtool">external documentation</a>. --spec addTool(This, Toolid, Bitmap, BmpDisabled, Toggle, XPos, [Option]) -> wx:wx() when +-spec addTool(This, Toolid, Bitmap, BmpDisabled, Toggle, XPos, [Option]) -> wx:wx_object() when This::wxToolBar(), Toolid::integer(), Bitmap::wxBitmap:wxBitmap(), BmpDisabled::wxBitmap:wxBitmap(), Toggle::boolean(), XPos::integer(), Option :: {yPos, integer()} - | {clientData, wx:wx()} + | {clientData, wx:wx_object()} | {shortHelp, unicode:chardata()} | {longHelp, unicode:chardata()}. addTool(#wx_ref{type=ThisT,ref=ThisRef},Toolid,#wx_ref{type=BitmapT,ref=BitmapRef},#wx_ref{type=BmpDisabledT,ref=BmpDisabledRef},Toggle,XPos, Options) @@ -270,7 +270,7 @@ addTool(#wx_ref{type=ThisT,ref=ThisRef},Toolid,#wx_ref{type=BitmapT,ref=BitmapRe <<ThisRef:32/?UI,Toolid:32/?UI,BitmapRef:32/?UI,BmpDisabledRef:32/?UI,(wxe_util:from_bool(Toggle)):32/?UI,XPos:32/?UI, BinOpt/binary>>). %% @equiv addCheckTool(This,Toolid,Label,Bitmap, []) --spec addCheckTool(This, Toolid, Label, Bitmap) -> wx:wx() when +-spec addCheckTool(This, Toolid, Label, Bitmap) -> wx:wx_object() when This::wxToolBar(), Toolid::integer(), Label::unicode:chardata(), Bitmap::wxBitmap:wxBitmap(). addCheckTool(This,Toolid,Label,Bitmap) @@ -278,12 +278,12 @@ addCheckTool(This,Toolid,Label,Bitmap) addCheckTool(This,Toolid,Label,Bitmap, []). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbaraddchecktool">external documentation</a>. --spec addCheckTool(This, Toolid, Label, Bitmap, [Option]) -> wx:wx() when +-spec addCheckTool(This, Toolid, Label, Bitmap, [Option]) -> wx:wx_object() when This::wxToolBar(), Toolid::integer(), Label::unicode:chardata(), Bitmap::wxBitmap:wxBitmap(), Option :: {bmpDisabled, wxBitmap:wxBitmap()} | {shortHelp, unicode:chardata()} | {longHelp, unicode:chardata()} - | {data, wx:wx()}. + | {data, wx:wx_object()}. addCheckTool(#wx_ref{type=ThisT,ref=ThisRef},Toolid,Label,#wx_ref{type=BitmapT,ref=BitmapRef}, Options) when is_integer(Toolid),is_list(Label),is_list(Options) -> ?CLASS(ThisT,wxToolBar), @@ -299,7 +299,7 @@ addCheckTool(#wx_ref{type=ThisT,ref=ThisRef},Toolid,Label,#wx_ref{type=BitmapT,r <<ThisRef:32/?UI,Toolid:32/?UI,(byte_size(Label_UC)):32/?UI,(Label_UC)/binary, 0:(((8- ((4+byte_size(Label_UC)) band 16#7)) band 16#7))/unit:8,BitmapRef:32/?UI, 0:32,BinOpt/binary>>). %% @equiv addRadioTool(This,Toolid,Label,Bitmap, []) --spec addRadioTool(This, Toolid, Label, Bitmap) -> wx:wx() when +-spec addRadioTool(This, Toolid, Label, Bitmap) -> wx:wx_object() when This::wxToolBar(), Toolid::integer(), Label::unicode:chardata(), Bitmap::wxBitmap:wxBitmap(). addRadioTool(This,Toolid,Label,Bitmap) @@ -307,12 +307,12 @@ addRadioTool(This,Toolid,Label,Bitmap) addRadioTool(This,Toolid,Label,Bitmap, []). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbaraddradiotool">external documentation</a>. --spec addRadioTool(This, Toolid, Label, Bitmap, [Option]) -> wx:wx() when +-spec addRadioTool(This, Toolid, Label, Bitmap, [Option]) -> wx:wx_object() when This::wxToolBar(), Toolid::integer(), Label::unicode:chardata(), Bitmap::wxBitmap:wxBitmap(), Option :: {bmpDisabled, wxBitmap:wxBitmap()} | {shortHelp, unicode:chardata()} | {longHelp, unicode:chardata()} - | {data, wx:wx()}. + | {data, wx:wx_object()}. addRadioTool(#wx_ref{type=ThisT,ref=ThisRef},Toolid,Label,#wx_ref{type=BitmapT,ref=BitmapRef}, Options) when is_integer(Toolid),is_list(Label),is_list(Options) -> ?CLASS(ThisT,wxToolBar), @@ -355,7 +355,7 @@ enableTool(#wx_ref{type=ThisT,ref=ThisRef},Toolid,Enable) <<ThisRef:32/?UI,Toolid:32/?UI,(wxe_util:from_bool(Enable)):32/?UI>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbarfindbyid">external documentation</a>. --spec findById(This, Toolid) -> wx:wx() when +-spec findById(This, Toolid) -> wx:wx_object() when This::wxToolBar(), Toolid::integer(). findById(#wx_ref{type=ThisT,ref=ThisRef},Toolid) when is_integer(Toolid) -> @@ -373,7 +373,7 @@ findControl(#wx_ref{type=ThisT,ref=ThisRef},Toolid) <<ThisRef:32/?UI,Toolid:32/?UI>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbarfindtoolforposition">external documentation</a>. --spec findToolForPosition(This, X, Y) -> wx:wx() when +-spec findToolForPosition(This, X, Y) -> wx:wx_object() when This::wxToolBar(), X::integer(), Y::integer(). findToolForPosition(#wx_ref{type=ThisT,ref=ThisRef},X,Y) when is_integer(X),is_integer(Y) -> @@ -467,7 +467,7 @@ getToolState(#wx_ref{type=ThisT,ref=ThisRef},Toolid) <<ThisRef:32/?UI,Toolid:32/?UI>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbarinsertcontrol">external documentation</a>. --spec insertControl(This, Pos, Control) -> wx:wx() when +-spec insertControl(This, Pos, Control) -> wx:wx_object() when This::wxToolBar(), Pos::integer(), Control::wxControl:wxControl(). insertControl(#wx_ref{type=ThisT,ref=ThisRef},Pos,#wx_ref{type=ControlT,ref=ControlRef}) when is_integer(Pos) -> @@ -477,7 +477,7 @@ insertControl(#wx_ref{type=ThisT,ref=ThisRef},Pos,#wx_ref{type=ControlT,ref=Cont <<ThisRef:32/?UI,Pos:32/?UI,ControlRef:32/?UI>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbarinsertseparator">external documentation</a>. --spec insertSeparator(This, Pos) -> wx:wx() when +-spec insertSeparator(This, Pos) -> wx:wx_object() when This::wxToolBar(), Pos::integer(). insertSeparator(#wx_ref{type=ThisT,ref=ThisRef},Pos) when is_integer(Pos) -> @@ -486,8 +486,8 @@ insertSeparator(#wx_ref{type=ThisT,ref=ThisRef},Pos) <<ThisRef:32/?UI,Pos:32/?UI>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbarinserttool">external documentation</a>. --spec insertTool(This, Pos, Tool) -> wx:wx() when - This::wxToolBar(), Pos::integer(), Tool::wx:wx(). +-spec insertTool(This, Pos, Tool) -> wx:wx_object() when + This::wxToolBar(), Pos::integer(), Tool::wx:wx_object(). insertTool(#wx_ref{type=ThisT,ref=ThisRef},Pos,#wx_ref{type=ToolT,ref=ToolRef}) when is_integer(Pos) -> ?CLASS(ThisT,wxToolBar), @@ -496,7 +496,7 @@ insertTool(#wx_ref{type=ThisT,ref=ThisRef},Pos,#wx_ref{type=ToolT,ref=ToolRef}) <<ThisRef:32/?UI,Pos:32/?UI,ToolRef:32/?UI>>). %% @equiv insertTool(This,Pos,Toolid,Bitmap, []) --spec insertTool(This, Pos, Toolid, Bitmap) -> wx:wx() when +-spec insertTool(This, Pos, Toolid, Bitmap) -> wx:wx_object() when This::wxToolBar(), Pos::integer(), Toolid::integer(), Bitmap::wxBitmap:wxBitmap(). insertTool(This,Pos,Toolid,Bitmap) @@ -505,22 +505,22 @@ insertTool(This,Pos,Toolid,Bitmap) %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbarinserttool">external documentation</a>. %% <br /> Also:<br /> -%% insertTool(This, Pos, Toolid, Bitmap, [Option]) -> wx:wx() when<br /> +%% insertTool(This, Pos, Toolid, Bitmap, [Option]) -> wx:wx_object() when<br /> %% This::wxToolBar(), Pos::integer(), Toolid::integer(), Bitmap::wxBitmap:wxBitmap(),<br /> %% Option :: {bmpDisabled, wxBitmap:wxBitmap()}<br /> %% | {toggle, boolean()}<br /> -%% | {clientData, wx:wx()}<br /> +%% | {clientData, wx:wx_object()}<br /> %% | {shortHelp, unicode:chardata()}<br /> %% | {longHelp, unicode:chardata()}.<br /> %% %%<br /> Kind = ?wxITEM_SEPARATOR | ?wxITEM_NORMAL | ?wxITEM_CHECK | ?wxITEM_RADIO | ?wxITEM_MAX --spec insertTool(This, Pos, Toolid, Label, Bitmap) -> wx:wx() when +-spec insertTool(This, Pos, Toolid, Label, Bitmap) -> wx:wx_object() when This::wxToolBar(), Pos::integer(), Toolid::integer(), Label::unicode:chardata(), Bitmap::wxBitmap:wxBitmap(); - (This, Pos, Toolid, Bitmap, [Option]) -> wx:wx() when + (This, Pos, Toolid, Bitmap, [Option]) -> wx:wx_object() when This::wxToolBar(), Pos::integer(), Toolid::integer(), Bitmap::wxBitmap:wxBitmap(), Option :: {bmpDisabled, wxBitmap:wxBitmap()} | {toggle, boolean()} - | {clientData, wx:wx()} + | {clientData, wx:wx_object()} | {shortHelp, unicode:chardata()} | {longHelp, unicode:chardata()}. @@ -543,13 +543,13 @@ insertTool(#wx_ref{type=ThisT,ref=ThisRef},Pos,Toolid,#wx_ref{type=BitmapT,ref=B %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbarinserttool">external documentation</a>. %%<br /> Kind = ?wxITEM_SEPARATOR | ?wxITEM_NORMAL | ?wxITEM_CHECK | ?wxITEM_RADIO | ?wxITEM_MAX --spec insertTool(This, Pos, Toolid, Label, Bitmap, [Option]) -> wx:wx() when +-spec insertTool(This, Pos, Toolid, Label, Bitmap, [Option]) -> wx:wx_object() when This::wxToolBar(), Pos::integer(), Toolid::integer(), Label::unicode:chardata(), Bitmap::wxBitmap:wxBitmap(), Option :: {bmpDisabled, wxBitmap:wxBitmap()} | {kind, wx:wx_enum()} | {shortHelp, unicode:chardata()} | {longHelp, unicode:chardata()} - | {clientData, wx:wx()}. + | {clientData, wx:wx_object()}. insertTool(#wx_ref{type=ThisT,ref=ThisRef},Pos,Toolid,Label,#wx_ref{type=BitmapT,ref=BitmapRef}, Options) when is_integer(Pos),is_integer(Toolid),is_list(Label),is_list(Options) -> ?CLASS(ThisT,wxToolBar), @@ -574,7 +574,7 @@ realize(#wx_ref{type=ThisT,ref=ThisRef}) -> <<ThisRef:32/?UI>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbarremovetool">external documentation</a>. --spec removeTool(This, Toolid) -> wx:wx() when +-spec removeTool(This, Toolid) -> wx:wx_object() when This::wxToolBar(), Toolid::integer(). removeTool(#wx_ref{type=ThisT,ref=ThisRef},Toolid) when is_integer(Toolid) -> diff --git a/lib/wx/src/gen/wxTreeCtrl.erl b/lib/wx/src/gen/wxTreeCtrl.erl index fef9916fff..dfa9e691ce 100644 --- a/lib/wx/src/gen/wxTreeCtrl.erl +++ b/lib/wx/src/gen/wxTreeCtrl.erl @@ -118,7 +118,7 @@ new(Parent) | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. new(#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> ?CLASS(ParentT,wxWindow), @@ -235,7 +235,7 @@ create(This,Parent) | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} - | {validator, wx:wx()}. + | {validator, wx:wx_object()}. create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> ?CLASS(ThisT,wxTreeCtrl), diff --git a/lib/wx/src/gen/wxWindow.erl b/lib/wx/src/gen/wxWindow.erl index d31f489726..229633a106 100644 --- a/lib/wx/src/gen/wxWindow.erl +++ b/lib/wx/src/gen/wxWindow.erl @@ -526,7 +526,7 @@ getCursor(#wx_ref{type=ThisT,ref=ThisRef}) -> <<ThisRef:32/?UI>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetdroptarget">external documentation</a>. --spec getDropTarget(This) -> wxDropTarget:wxDropTarget() when +-spec getDropTarget(This) -> wx:wx_object() when This::wxWindow(). getDropTarget(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxWindow), @@ -1384,7 +1384,7 @@ setOwnForegroundColour(#wx_ref{type=ThisT,ref=ThisRef},Colour) %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowsetdroptarget">external documentation</a>. -spec setDropTarget(This, DropTarget) -> ok when - This::wxWindow(), DropTarget::wxDropTarget:wxDropTarget(). + This::wxWindow(), DropTarget::wx:wx_object(). setDropTarget(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=DropTargetT,ref=DropTargetRef}) -> ?CLASS(ThisT,wxWindow), ?CLASS(DropTargetT,wxDropTarget), diff --git a/lib/wx/src/wx.erl b/lib/wx/src/wx.erl index 32e9f5da3f..7d62305048 100644 --- a/lib/wx/src/wx.erl +++ b/lib/wx/src/wx.erl @@ -71,13 +71,17 @@ retain_memory/1, release_memory/1]). -export([demo/0]). --export_type([wx_colour/0, wx_datetime/0, wx_enum/0, wx_mouseState/0, wx_wxHtmlLinkInfo/0]). + +-export_type([wx_object/0, wx_env/0, wx_memory/0]). +-export_type([wx_colour/0, wx_colour4/0, wx_datetime/0, + wx_enum/0, wx_wxMouseState/0, wx_wxHtmlLinkInfo/0]). + -include("wxe.hrl"). -include("../include/wx.hrl"). --opaque wx_object() :: #wx_ref{}. %% Opaque object reference --opaque wx_env() :: #wx_env{}. %% Opaque process environment --opaque wx_memory() :: binary() | #wx_mem{}. %% Opaque memory reference +-type wx_object() :: #wx_ref{}. %% Opaque object reference +-type wx_env() :: #wx_env{}. %% Opaque process environment +-type wx_memory() :: binary() | #wx_mem{}. %% Opaque memory reference -type wx_colour4() :: {R::byte(),G::byte(),B::byte(), A::byte()}. -type wx_colour() :: {R::byte(),G::byte(),B::byte()} | wx_colour4(). @@ -85,7 +89,7 @@ -type wx_datetime() :: {{Year::integer(),Month::integer(),Day::integer()}, {Hour::integer(),Minute::integer(),Second::integer()}}. %% In Local Timezone --type wx_mouseState() :: #wxMouseState{}. %% See #wxMouseState{} defined in wx.hrl +-type wx_wxMouseState() :: #wxMouseState{}. %% See #wxMouseState{} defined in wx.hrl -type wx_enum() :: integer(). %% Constant defined in wx.hrl -type wx_wxHtmlLinkInfo() :: #wxHtmlLinkInfo{}. @@ -311,14 +315,15 @@ debug(Level) when is_integer(Level) -> end. %% @doc Starts a wxErlang demo if examples directory exists and is compiled --spec demo() -> ok. +-spec demo() -> ok | {error, atom()}. demo() -> Priv = code:priv_dir(wx), Demo = filename:join([filename:dirname(Priv),examples,demo]), Mod = list_to_atom("demo"), %% Fool xref tests case file:set_cwd(Demo) of ok -> - apply(Mod, start, []); + apply(Mod, start, []), + ok; _ -> {error, no_demo_dir} end. diff --git a/lib/xmerl/include/xmerl_xlink.hrl b/lib/xmerl/include/xmerl_xlink.hrl deleted file mode 100644 index 375e244c23..0000000000 --- a/lib/xmerl/include/xmerl_xlink.hrl +++ /dev/null @@ -1,26 +0,0 @@ - - - -%% The following is a brief summary of the element types (columns) on -%% which the global attributes are allowed: -%% -%% simple extended locator arc resource title -%% type X X X X X X -%% href X X -%% role X X X X -%% title X X X X -%% show X X X -%% actuate X X X -%% from X -%% to X -%% --record(xlink, { - type, % simple | extended | locator | arc | resource | title - href, - role - title, - show, - actuate, - from, - to - }). diff --git a/lib/xmerl/src/Makefile b/lib/xmerl/src/Makefile index 7009b50f6c..5b77c9478b 100644 --- a/lib/xmerl/src/Makefile +++ b/lib/xmerl/src/Makefile @@ -94,7 +94,6 @@ MODULES = $(EDOC_MODULES) \ HRL_FILES = \ ../include/xmerl.hrl \ - ../include/xmerl_xlink.hrl \ ../include/xmerl_xpath.hrl \ ../include/xmerl_xsd.hrl diff --git a/lib/xmerl/src/xmerl_sax_parser.erl b/lib/xmerl/src/xmerl_sax_parser.erl index 45e2a928ac..1d795799ce 100644 --- a/lib/xmerl/src/xmerl_sax_parser.erl +++ b/lib/xmerl/src/xmerl_sax_parser.erl @@ -217,7 +217,7 @@ check_encoding_option(E) when E==utf8; E=={utf16,little}; E=={utf16,big}; check_encoding_option(utf16) -> {utf16,big}; check_encoding_option(E) -> - {error, io_lib:format("Charcter set ~p not supported", [E])}. + {error, io_lib:format("Character set ~p not supported", [E])}. %%---------------------------------------------------------------------- %% Function: detect_charset(Xml, State) @@ -279,6 +279,7 @@ convert_encoding(Enc) -> %% Just for 7,8 bit + utf8 case string:to_lower(Enc) of "utf-8" -> utf8; "us-ascii" -> utf8; + "latin1" -> latin1; "iso-8859-1" -> latin1; % Handle all iso-8859 as latin1 "iso-8859-2" -> latin1; "iso-8859-3" -> latin1; diff --git a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc index c25cde0472..e988c49292 100644 --- a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc +++ b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc @@ -39,6 +39,9 @@ %% Internal exports %%---------------------------------------------------------------------- -export([ + cf/3, + cf/4, + cf/5 ]). %%---------------------------------------------------------------------- |