diff options
Diffstat (limited to 'lib/reltool/src')
-rw-r--r-- | lib/reltool/src/Makefile | 42 | ||||
-rw-r--r-- | lib/reltool/src/files.mk | 32 | ||||
-rw-r--r-- | lib/reltool/src/reltool.app.src | 45 | ||||
-rw-r--r-- | lib/reltool/src/reltool.appup.src | 22 | ||||
-rw-r--r-- | lib/reltool/src/reltool.erl | 97 | ||||
-rw-r--r-- | lib/reltool/src/reltool.hrl | 142 | ||||
-rw-r--r-- | lib/reltool/src/reltool_mod_win.erl | 4 | ||||
-rw-r--r-- | lib/reltool/src/reltool_server.erl | 561 | ||||
-rw-r--r-- | lib/reltool/src/reltool_sys_win.erl | 2 | ||||
-rw-r--r-- | lib/reltool/src/reltool_target.erl | 493 | ||||
-rw-r--r-- | lib/reltool/src/reltool_utils.erl | 82 |
11 files changed, 911 insertions, 611 deletions
diff --git a/lib/reltool/src/Makefile b/lib/reltool/src/Makefile index 7fac7cbf88..4e6a112b7e 100644 --- a/lib/reltool/src/Makefile +++ b/lib/reltool/src/Makefile @@ -28,7 +28,6 @@ include ../vsn.mk VSN = $(RELTOOL_VSN) APP_VSN = "reltool-$(VSN)" - # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- @@ -39,25 +38,20 @@ RELSYSDIR = $(RELEASE_PATH)/lib/reltool-$(VSN) # Target Specs # ---------------------------------------------------- -MODULES = \ - reltool \ - reltool_app_win \ - reltool_fgraph \ - reltool_fgraph_win \ - reltool_mod_win \ - reltool_sys_win \ - reltool_server \ - reltool_target \ - reltool_utils - -HRL_FILES = - -INTERNAL_HRL_FILES = reltool.hrl reltool_fgraph.hrl +include files.mk ERL_FILES = $(MODULES:%=%.erl) TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) +APP_FILE = reltool.app +APP_SRC = $(APP_FILE).src +APP_TARGET = $(EBIN)/$(APP_FILE) + +APPUP_FILE = reltool.appup +APPUP_SRC = $(APPUP_FILE).src +APPUP_TARGET = $(EBIN)/$(APPUP_FILE) + # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -69,15 +63,28 @@ ERL_COMPILE_FLAGS += +'{parse_transform,sys_pre_attributes}' \ # Targets # ---------------------------------------------------- -debug opt: $(TARGET_FILES) $(HRL_FILES) +debug: + @${MAKE} TYPE=debug opt + +opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) clean: - rm -f $(TARGET_FILES) + rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) rm -f core docs: # ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- + +$(APP_TARGET): $(APP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +# ---------------------------------------------------- # Dependencies # ---------------------------------------------------- @@ -94,6 +101,7 @@ release_spec: opt $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src $(INSTALL_DIR) $(RELSYSDIR)/ebin $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin release_docs_spec: diff --git a/lib/reltool/src/files.mk b/lib/reltool/src/files.mk new file mode 100644 index 0000000000..99a1f1c14a --- /dev/null +++ b/lib/reltool/src/files.mk @@ -0,0 +1,32 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +MODULES = \ + reltool \ + reltool_app_win \ + reltool_fgraph \ + reltool_fgraph_win \ + reltool_mod_win \ + reltool_sys_win \ + reltool_server \ + reltool_target \ + reltool_utils + +HRL_FILES = + +INTERNAL_HRL_FILES = reltool.hrl reltool_fgraph.hrl diff --git a/lib/reltool/src/reltool.app.src b/lib/reltool/src/reltool.app.src index f83042c157..b80753e8fc 100644 --- a/lib/reltool/src/reltool.app.src +++ b/lib/reltool/src/reltool.app.src @@ -1,37 +1,38 @@ %% This is an -*- erlang -*- file. %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% -%% %CopyrightEnd% %% +%% %CopyrightEnd% {application, reltool, - [{description, "Release management tool"}, - {vsn, "%VSN%"}, - {modules, [ - reltool, - reltool_app, - reltool_fgraph, - reltool_fgraph_win, - reltool_gen, - reltool_mod, - reltool_sys, - reltool_server, - reltool_utils - ]}, - {applications, [kernel, stdlib]} - ] -}. + [{description, "Reltool the release management tool"}, + {vsn, "%VSN%"}, + {modules, + [ + reltool_app_win, + reltool, + reltool_fgraph, + reltool_fgraph_win, + reltool_mod_win, + reltool_server, + reltool_sys_win, + reltool_target, + reltool_utils + ]}, + {registered, []}, + {applications, [stdlib, kernel]}, + {env, []} + ]}. diff --git a/lib/reltool/src/reltool.appup.src b/lib/reltool/src/reltool.appup.src new file mode 100644 index 0000000000..c02edd2afb --- /dev/null +++ b/lib/reltool/src/reltool.appup.src @@ -0,0 +1,22 @@ +%% This is an -*- erlang -*- file. +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% + +{"%VSN%", + [ ] +}. diff --git a/lib/reltool/src/reltool.erl b/lib/reltool/src/reltool.erl index e6a8bca069..9dd0a24f46 100644 --- a/lib/reltool/src/reltool.erl +++ b/lib/reltool/src/reltool.erl @@ -20,9 +20,8 @@ %% Public -export([ - main/1, % Escript start/0, start/1, start_link/1, debug/0, % GUI - start_server/1, get_server/1, stop/1, + start_server/1, get_server/1, get_status/1, stop/1, get_config/1, get_config/3, get_rel/2, get_script/2, create_target/2, get_target_spec/1, eval_target_spec/3, install/2 @@ -32,39 +31,26 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Main function for escript --spec main([escript_arg()]) -> ok. -main(_) -> - process_flag(trap_exit, true), - {ok, WinPid} = start_link([]), - receive - {'EXIT', WinPid, shutdown} -> - ok; - {'EXIT', WinPid, normal} -> - ok; - {'EXIT', WinPid, Reason} -> - io:format("EXIT: ~p\n", [Reason]), - erlang:halt(1) - end. - %% Start main window process --spec start() -> {ok, window_pid()}. +-spec start() -> {ok, window_pid()} | {error, reason()}. start() -> start([]). %% Start main window process --spec start(options()) -> {ok, window_pid() | {error, reason()}}. +-spec start(options()) -> {ok, window_pid()} | {error, reason()}. start(Options)when is_list(Options) -> - {ok, WinPid} = start_link(Options), - unlink(WinPid), - {ok, WinPid}. + case start_link(Options) of + {ok, WinPid} -> + unlink(WinPid), + {ok, WinPid}; + Other-> + Other + end. %% Start main window process with wx debugging enabled --spec debug() -> {ok, window_pid()}. +-spec debug() -> {ok, window_pid()} | {error, reason()}. debug() -> - {ok, WinPid} = start_link([{wx_debug, 2}]), - unlink(WinPid), - {ok, WinPid}. + start([{wx_debug, 2}]). %% Start main window process with options -spec start_link(options()) -> {ok, window_pid() | {error, reason()}}. @@ -110,20 +96,48 @@ stop(Pid) when is_pid(Pid) -> end. %% Internal library function --spec eval_server(server(), fun((server_pid()) -> term())) -> +-spec eval_server(server(), boolean(), fun((server_pid()) -> term())) -> {ok, server_pid()} | {error, reason()}. -eval_server(Pid, Fun) when is_pid(Pid) -> +eval_server(Pid, DisplayWarnings, Fun) + when is_pid(Pid) -> Fun(Pid); -eval_server(Options, Fun) when is_list(Options), is_function(Fun, 1) -> - case start_server(Options) of - {ok, Pid} -> - Res = Fun(Pid), - stop(Pid), - Res; - {error, Reason} -> - {error, Reason} +eval_server(Options, DisplayWarnings, Fun) + when is_list(Options) -> + TrapExit = process_flag(trap_exit, true), + Res = case start_server(Options) of + {ok, Pid} -> + apply_fun(Pid, DisplayWarnings, Fun); + {error, Reason} -> + {error, Reason} + end, + process_flag(trap_exit, TrapExit), + Res. + +apply_fun(Pid, false, Fun) -> + Res = Fun(Pid), + stop(Pid), + Res; +apply_fun(Pid, true, Fun) -> + case get_status(Pid) of + {ok, Warnings} -> + [io:format("~p: ~s\n", [?APPLICATION, W]) || W <- Warnings], + apply_fun(Pid, false, Fun); + {error, Reason} -> + stop(Pid), + {error, Reason} end. +%% Get status about the configuration +-type warning() :: string(). +-spec get_status(server()) -> + {ok, [warning()]} | {error, reason()}. +get_status(PidOrOptions) + when is_pid(PidOrOptions); is_list(PidOrOptions) -> + eval_server(PidOrOptions, false, + fun(Pid) -> + reltool_server:get_status(Pid) + end). + %% Get reltool configuration -spec get_config(server()) -> {ok, config()} | {error, reason()}. get_config(PidOrOption) -> @@ -133,7 +147,7 @@ get_config(PidOrOption) -> {ok, config()} | {error, reason()}. get_config(PidOrOptions, InclDef, InclDeriv) when is_pid(PidOrOptions); is_list(PidOrOptions) -> - eval_server(PidOrOptions, + eval_server(PidOrOptions, true, fun(Pid) -> reltool_server:get_config(Pid, InclDef, InclDeriv) end). @@ -142,7 +156,7 @@ get_config(PidOrOptions, InclDef, InclDeriv) -spec get_rel(server(), rel_name()) -> {ok, rel_file()} | {error, reason()}. get_rel(PidOrOptions, RelName) when is_pid(PidOrOptions); is_list(PidOrOptions) -> - eval_server(PidOrOptions, + eval_server(PidOrOptions, true, fun(Pid) -> reltool_server:get_rel(Pid, RelName) end). %% Get contents of boot script file @@ -150,21 +164,22 @@ get_rel(PidOrOptions, RelName) {ok, script_file()} | {error, reason()}. get_script(PidOrOptions, RelName) when is_pid(PidOrOptions); is_list(PidOrOptions) -> - eval_server(PidOrOptions, + eval_server(PidOrOptions, true, fun(Pid) -> reltool_server:get_script(Pid, RelName) end). %% Generate a target system -spec create_target(server(), target_dir()) -> ok | {error, reason()}. create_target(PidOrOptions, TargetDir) when is_pid(PidOrOptions); is_list(PidOrOptions) -> - eval_server(PidOrOptions, + eval_server(PidOrOptions, true, fun(Pid) -> reltool_server:gen_target(Pid, TargetDir) end). %% Generate a target system -spec get_target_spec(server()) -> {ok, target_spec()} | {error, reason()}. get_target_spec(PidOrOptions) when is_pid(PidOrOptions); is_list(PidOrOptions) -> - eval_server(PidOrOptions, fun(Pid) -> reltool_server:gen_spec(Pid) end). + eval_server(PidOrOptions, true, + fun(Pid) -> reltool_server:gen_spec(Pid) end). %% Generate a target system -spec eval_target_spec(target_spec(), root_dir(), target_dir()) -> diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl index 8a6a2142fd..1a34ced89d 100644 --- a/lib/reltool/src/reltool.hrl +++ b/lib/reltool/src/reltool.hrl @@ -17,7 +17,7 @@ %% %CopyrightEnd% -define(APPLICATION, reltool). --define(MISSING_APP, '*MISSING*'). +-define(MISSING_APP_NAME, '*MISSING*'). -define(MISSING_APP_TEXT, "*MISSING*"). -type file() :: string(). @@ -104,7 +104,7 @@ -type rel_file() :: term(). -type script_file() :: term(). -type reason() :: string(). --type escript_arg() :: string(). + -type base_dir() :: dir(). -type base_file() :: file(). -type top_dir() :: file(). @@ -112,10 +112,7 @@ -type target_spec() :: [target_spec()] | {create_dir, base_dir(), [target_spec()]} | {create_dir, base_dir(), top_dir(), [target_spec()]} - | {archive, - base_file(), - [archive_opt()], - [target_spec()]} + | {archive, base_file(), [archive_opt()], [target_spec()]} | {copy_file, base_file()} | {copy_file, base_file(), top_file()} | {write_file, base_file(), iolist()} @@ -139,57 +136,58 @@ -record(mod, {%% Static - name :: mod_name(), - app_name :: app_name(), - incl_cond :: incl_cond() | undefined, - debug_info :: debug_info() | undefined, - is_app_mod :: boolean(), + name :: mod_name(), + app_name :: app_name(), + incl_cond :: incl_cond() | undefined, + debug_info :: debug_info() | undefined, + is_app_mod :: boolean(), is_ebin_mod :: boolean(), - uses_mods :: [mod_name()], - exists :: boolean(), + uses_mods :: [mod_name()], + exists :: boolean(), + %% Dynamic - status :: status(), - used_by_mods :: [mod_name()], + status :: status(), + used_by_mods :: [mod_name()], is_pre_included :: boolean() | undefined, - is_included :: boolean() | undefined + is_included :: boolean() | undefined }). -record(app_info, { - description = "", - id = "", - vsn = "", - modules = [], - maxP = infinity, - maxT = infinity, - registered = [], - incl_apps = [], - applications = [], - env = [], - mod = undefined, - start_phases = undefined + description = "" :: string(), + id = "" :: string(), + vsn = "" :: app_vsn(), + modules = [] :: [mod_name()], + maxP = infinity :: integer() | infinity, + maxT = infinity :: integer() | infinity, + registered = [] :: [atom()], + incl_apps = [] :: [app_name()], + applications = [] :: [app_name()], + env = [] :: [{atom(), term()}], + mod = undefined :: {mod_name(), [term()]} | undefined, + start_phases = undefined :: [{atom(), term()}] | undefined }). -record(app, {%% Static info - name :: app_name(), - is_escript :: boolean(), + name :: app_name(), + is_escript :: boolean(), use_selected_vsn :: boolean() | undefined, - active_dir :: dir(), - sorted_dirs :: [dir()], - vsn :: app_vsn(), - label :: app_label(), - info :: #app_info{} | undefined, - mods :: [#mod{}], + active_dir :: dir(), + sorted_dirs :: [dir()], + vsn :: app_vsn(), + label :: app_label(), + info :: #app_info{} | undefined, + mods :: [#mod{}], %% Static source cond - mod_cond :: mod_cond() | undefined, + mod_cond :: mod_cond() | undefined, incl_cond :: incl_cond() | undefined, %% Static target cond - debug_info :: debug_info() | undefined, - app_file :: app_file() | undefined, - app_type :: app_type(), + debug_info :: debug_info() | undefined, + app_file :: app_file() | undefined, + app_type :: app_type() | undefined, incl_app_filters :: incl_app_filters(), excl_app_filters :: excl_app_filters(), incl_archive_filters :: incl_archive_filters(), @@ -197,19 +195,20 @@ archive_opts :: [archive_opt()], %% Dynamic - status :: status(), - uses_mods :: [mod_name()], - used_by_mods :: [mod_name()], - uses_apps :: [app_name()], - used_by_apps :: [app_name()], + status :: status(), + uses_mods :: [mod_name()], + used_by_mods :: [mod_name()], + uses_apps :: [app_name()], + used_by_apps :: [app_name()], is_pre_included :: boolean(), - is_included :: boolean() + is_included :: boolean(), + rels :: [rel_name()] }). -record(rel_app, { - name :: app_name(), - app_type :: app_type(), + name :: app_name(), + app_type :: app_type(), incl_apps :: [incl_app()] }). @@ -231,21 +230,22 @@ apps :: [#app{}], %% Target cond - boot_rel :: boot_rel(), - rels :: [#rel{}], - emu_name :: emu_name(), - profile :: profile(), - incl_sys_filters :: incl_sys_filters(), - excl_sys_filters :: excl_sys_filters(), - incl_app_filters :: incl_app_filters(), - excl_app_filters :: excl_app_filters(), + boot_rel :: boot_rel(), + rels :: [#rel{}], + emu_name :: emu_name(), + profile :: profile(), + incl_sys_filters :: incl_sys_filters(), + excl_sys_filters :: excl_sys_filters(), + incl_app_filters :: incl_app_filters(), + excl_app_filters :: excl_app_filters(), incl_archive_filters :: incl_archive_filters(), excl_archive_filters :: excl_archive_filters(), - archive_opts :: [archive_opt()], - relocatable :: boolean(), - app_type :: app_type(), - app_file :: app_file(), - debug_info :: debug_info() + archive_opts :: [archive_opt()], + relocatable :: boolean(), + rel_app_type :: app_type(), + embedded_app_type :: app_type() | undefined, + app_file :: app_file(), + debug_info :: debug_info() }). -record(regexp, {source, compiled}). @@ -268,7 +268,8 @@ -define(DEFAULT_EMU_NAME, "beam"). -define(DEFAULT_PROFILE, development). -define(DEFAULT_RELOCATABLE, true). --define(DEFAULT_APP_TYPE, permanent). +-define(DEFAULT_REL_APP_TYPE, permanent). +-define(DEFAULT_EMBEDDED_APP_TYPE, undefined). -define(DEFAULT_APP_FILE, keep). -define(DEFAULT_DEBUG_INFO, keep). @@ -282,22 +283,23 @@ -define(DEFAULT_EXCL_APP_FILTERS, []). -define(EMBEDDED_INCL_SYS_FILTERS, ["^bin", - "^erts", - "^lib", - "^releases"]). + "^erts", + "^lib", + "^releases"]). -define(EMBEDDED_EXCL_SYS_FILTERS, ["^bin/(erlc|dialyzer|typer)(|\\.exe)\$", "^erts.*/bin/(erlc|dialyzer|typer)(|\\.exe)\$", "^erts.*/bin/.*(debug|pdb)"]). -define(EMBEDDED_INCL_APP_FILTERS, ["^ebin", - "^priv", - "^include"]). + "^include", + "^priv"]). -define(EMBEDDED_EXCL_APP_FILTERS, []). +-define(EMBEDDED_APP_TYPE, load). -define(STANDALONE_INCL_SYS_FILTERS, ["^bin/(erl|epmd)(|\\.exe|\\.ini)\$", - "^bin/start(|_clean).boot\$", - "^erts.*/bin", - "^lib\$"]). + "^bin/start(|_clean).boot\$", + "^erts.*/bin", + "^lib\$"]). -define(STANDALONE_EXCL_SYS_FILTERS, ["^erts.*/bin/(erlc|dialyzer|typer)(|\\.exe)\$", "^erts.*/bin/(start|escript|to_erl|run_erl)(|\\.exe)\$", diff --git a/lib/reltool/src/reltool_mod_win.erl b/lib/reltool/src/reltool_mod_win.erl index c2544cc2d8..f68c61fd6f 100644 --- a/lib/reltool/src/reltool_mod_win.erl +++ b/lib/reltool/src/reltool_mod_win.erl @@ -514,7 +514,7 @@ select_image(Xref, ModName) -> {ok, M} = reltool_server:get_mod(Xref, ModName), Image = case M#mod.is_included of - _ when M#mod.app_name =:= ?MISSING_APP -> ?ERR_IMAGE; + _ when M#mod.app_name =:= ?MISSING_APP_NAME -> ?ERR_IMAGE; true -> ?TICK_IMAGE; false -> ?WARN_IMAGE; undefined -> ?ERR_IMAGE @@ -674,7 +674,7 @@ do_goto_function(#state{active_page = P} = S, [FunName]) -> find_regexp_forward(S, "^" ++ FunName ++ "("); do_goto_function(S, [ModStr, FunStr]) -> case reltool_server:get_mod(S#state.xref_pid, list_to_atom(ModStr)) of - {ok, Mod} when Mod#mod.app_name =/= ?MISSING_APP -> + {ok, Mod} when Mod#mod.app_name =/= ?MISSING_APP_NAME -> S2 = create_code_page(S#state{mod = Mod}, ModStr), find_regexp_forward(S2, "^" ++ FunStr ++ "("); {ok, _} -> diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl index a7064f7651..039ad56aa8 100644 --- a/lib/reltool/src/reltool_server.erl +++ b/lib/reltool/src/reltool_server.erl @@ -132,19 +132,20 @@ init(Options) -> end. do_init(Options) -> - case parse_options(Options) of - {#state{parent_pid = ParentPid, common = C, sys = Sys} = S, Status} -> - %% 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} -> - loop(S3#state{status = Status3, old_status = {ok, []}}); - {error, Reason} -> - exit(Reason) - end + {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) -> @@ -161,33 +162,28 @@ parse_options(Opts) -> rels = reltool_utils:default_rels(), emu_name = ?DEFAULT_EMU_NAME, profile = ?DEFAULT_PROFILE, - incl_sys_filters = - reltool_utils:decode_regexps(incl_sys_filters, - ?DEFAULT_INCL_SYS_FILTERS, - []), - excl_sys_filters = - reltool_utils:decode_regexps(excl_sys_filters, - ?DEFAULT_EXCL_SYS_FILTERS, - []), - incl_app_filters = - reltool_utils:decode_regexps(incl_app_filters, - ?DEFAULT_INCL_APP_FILTERS, - []), - excl_app_filters = - reltool_utils:decode_regexps(excl_app_filters, - ?DEFAULT_EXCL_APP_FILTERS, - []), + 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, - app_type = ?DEFAULT_APP_TYPE, + rel_app_type = ?DEFAULT_REL_APP_TYPE, + embedded_app_type = ?DEFAULT_EMBEDDED_APP_TYPE, app_file = ?DEFAULT_APP_FILE, - incl_archive_filters = - reltool_utils:decode_regexps(incl_archive_filters, - ?DEFAULT_INCL_ARCHIVE_FILTERS, - []), - excl_archive_filters = - reltool_utils:decode_regexps(excl_archive_filters, - ?DEFAULT_EXCL_ARCHIVE_FILTERS, - []), + 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 = [], @@ -199,6 +195,9 @@ parse_options(Opts) -> S = #state{options = Opts}, parse_options(Opts, S, C2, Sys, {ok, []}). +dec_re(Key, Regexps, Old) -> + reltool_utils:decode_regexps(Key, Regexps, Old). + parse_options([{Key, Val} | KeyVals], S, C, Sys, Status) -> case Key of parent -> @@ -261,6 +260,7 @@ loop(#state{common = C, sys = Sys} = S) -> {ok, _Warnings} -> S5#state{status = Status3, old_status = S#state.status}; {error, _} -> + %% Keep old state S end, reltool_utils:reply(ReplyTo, Ref, Status3), @@ -277,9 +277,9 @@ loop(#state{common = C, sys = Sys} = S) -> Reply = case lists:keysearch(RelName, #rel.name, Sys#sys.rels) of {value, Rel} -> - {ok, reltool_target:gen_rel(Rel, Sys)}; + reltool_target:gen_rel(Rel, Sys); false -> - {error, "No such release"} + {error, "No such release: " ++ RelName} end, reltool_utils:reply(ReplyTo, Ref, Reply), ?MODULE:loop(S); @@ -292,7 +292,7 @@ loop(#state{common = C, sys = Sys} = S) -> Vars = [], reltool_target:gen_script(Rel, Sys, PathFlag, Vars); false -> - {error, "No such release"} + {error, "No such release: " ++ RelName} end, reltool_utils:reply(ReplyTo, Ref, Reply), ?MODULE:loop(S); @@ -302,7 +302,7 @@ loop(#state{common = C, sys = Sys} = S) -> [M] -> {ok, M}; [] -> - {ok, missing_mod(ModName, ?MISSING_APP)} + {ok, missing_mod(ModName, ?MISSING_APP_NAME)} end, reltool_utils:reply(ReplyTo, Ref, Reply), ?MODULE:loop(S); @@ -312,7 +312,8 @@ loop(#state{common = C, sys = Sys} = S) -> {value, App} -> {ok, App}; false -> - {error, enoent} + {error, "No such application: " ++ + atom_to_list(AppName)} end, reltool_utils:reply(ReplyTo, Ref, Reply), ?MODULE:loop(S); @@ -327,6 +328,7 @@ loop(#state{common = C, sys = Sys} = S) -> 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; @@ -372,16 +374,20 @@ loop(#state{common = C, sys = Sys} = S) -> (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), - S6 = - case Status2 of - {ok, _Warnings} -> - S4#state{status = Status2, old_status = S#state.status}; - {error, _} -> - S - end, - reltool_utils:reply(ReplyTo, Ref, Status2), - ?MODULE:loop(S6); + {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); {call, ReplyTo, Ref, get_status} -> reltool_utils:reply(ReplyTo, Ref, S#state.status), ?MODULE:loop(S); @@ -427,15 +433,24 @@ do_set_app(#state{sys = Sys} = S, App, Status) -> Sys2 = Sys#sys{apps = Apps2, escripts = Escripts}, {S#state{sys = Sys2}, Status2}. -analyse(#state{common = C, sys = #sys{apps = Apps0} = Sys} = S, Status) -> - Apps = lists:keydelete(?MISSING_APP, #app.name, Apps0), +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, "missing"), + MissingApp = default_app(?MISSING_APP_NAME, "missing"), ets:insert(C#common.app_tab, MissingApp), - Apps2 = lists:map(fun(App) -> app_init_is_included(C, Sys, App) end, Apps), + {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 [] -> @@ -452,17 +467,59 @@ analyse(#state{common = C, sys = #sys{apps = Apps0} = Sys} = S, Status) -> app_propagate_is_used_by(C, Apps3), Apps4 = read_apps(C, Sys, Apps3, []), %% io:format("Missing app: ~p\n", - %% [lists:keysearch(?MISSING_APP, #app.name, Apps4)]), + %% [lists:keysearch(?MISSING_APP_NAME, #app.name, Apps4)]), Sys2 = Sys#sys{apps = Apps4}, - try - Status2 = verify_config(Sys2, Status), - {S#state{sys = Sys2}, Status2} - catch - throw:{error, Status3} -> - {S, Status3} + + case verify_config(RelApps2, Sys2, Status3) of + {ok, _Warnings} = Status4 -> + {S#state{sys = Sys2}, Status4}; + {error, _} = Status4 -> + {S, Status4} end. -app_init_is_included(C, Sys, #app{mods = Mods} = A) -> +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). + +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) -> + case lists:member(RA, Acc) of + true -> + more_apps_in_rels(RelApps, Apps, Acc, Status); + false -> + case lists:keysearch(AppName, #app.name, Apps) of + {value, #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); + 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) + end + end; +more_apps_in_rels([], _Apps, Acc, Status) -> + {Acc, Status}. + +app_init_is_included(C, + Sys, + #app{name = AppName, mods = Mods} = A, + RelApps, + Status) -> AppCond = case A#app.incl_cond of undefined -> Sys#sys.incl_cond; @@ -473,24 +530,37 @@ app_init_is_included(C, Sys, #app{mods = Mods} = A) -> undefined -> Sys#sys.mod_cond; _ -> A#app.mod_cond end, - IsIncl = - case AppCond of - include -> true; - exclude -> false; - derived -> undefined + Rels = [RelName || {RelName, AN} <- RelApps, AN =:= AppName], + {Default, IsPreIncl, IsIncl, Status2} = + case {AppCond, Rels} of + {include, _} -> + {undefined, true, true, Status}; + {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}; + {derived, []} -> + {undefined, undefined, undefined, Status}; + {derived, [_ | _]} -> % App is included in at least one rel + {true, undefined, true, Status} end, - A2 = A#app{is_pre_included = IsIncl, is_included = IsIncl}, + A2 = A#app{is_pre_included = IsPreIncl, + is_included = IsIncl, + rels = Rels}, ets:insert(C#common.app_tab, A2), lists:foreach(fun(Mod) -> mod_init_is_included(C, Mod, ModCond, AppCond, - undefined) + Default) end, Mods), - %%app_mod_init_is_included(C, AppName, Info, ModCond, AppCond), - A2. + {A2, Status2}. mod_init_is_included(C, M, ModCond, AppCond, Default) -> %% print(M#mod.name, hipe, "incl_cond -> ~p\n", [AppCond]), @@ -635,7 +705,7 @@ mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) -> Acc2) end; [] -> - M = missing_mod(ModName, ?MISSING_APP), + 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}), @@ -646,7 +716,7 @@ mod_mark_is_included(_C, _Sys, _UsedByName, [], Acc) -> Acc. app_propagate_is_used_by(C, [#app{mods = Mods, name = Name} | Apps]) -> - case Name =:= ?MISSING_APP of + case Name =:= ?MISSING_APP_NAME of true -> ok; false -> ok end, @@ -672,8 +742,6 @@ mod_propagate_is_used_by(_C, []) -> read_apps(C, Sys, [#app{mods = Mods, is_included = IsIncl} = A | Apps], Acc) -> {Mods2, IsIncl2} = read_apps(C, Sys, A, Mods, [], IsIncl), - %% reltool_utils:print(A#app.name, stdlib, "Mods2: ~p\n", - %% [[M#mod.status || M <- Mods2]]), Status = case lists:keysearch(missing, #mod.status, Mods2) of {value, _} -> missing; @@ -736,9 +804,7 @@ filter_app(A) -> Mods = [M#mod{is_app_mod = undefined, is_ebin_mod = undefined, uses_mods = undefined, - exists = false, - is_pre_included = undefined, - is_included = undefined} || + exists = false} || M <- A#app.mods, M#mod.incl_cond =/= undefined], if @@ -747,8 +813,7 @@ filter_app(A) -> label = undefined, info = undefined, mods = [], - uses_mods = undefined, - is_included = undefined}}; + uses_mods = undefined}}; Mods =:= [], A#app.mod_cond =:= undefined, A#app.incl_cond =:= undefined, @@ -778,8 +843,7 @@ filter_app(A) -> label = undefined, info = undefined, mods = Mods, - uses_mods = undefined, - is_included = undefined}} + uses_mods = undefined}} end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -816,16 +880,16 @@ refresh_app(#app{name = AppName, end, %% Add non-existing modules + AppInfoMods = AppInfo#app_info.modules, AppModNames = case AppInfo#app_info.mod of {StartModName, _} -> - case lists:member(StartModName, - AppInfo#app_info.modules) of - true -> AppInfo#app_info.modules; - false -> [StartModName | AppInfo#app_info.modules] + case lists:member(StartModName, AppInfoMods) of + true -> AppInfoMods; + false -> [StartModName | AppInfoMods] end; undefined -> - AppInfo#app_info.modules + AppInfoMods end, MissingMods = add_missing_mods(AppName, EbinMods, AppModNames), @@ -862,11 +926,15 @@ read_app_info(AppFileOrBin, AppFile, AppName, DefaultVsn, Status) -> parse_app_info(AppFile, Info, AI, Status); {ok, _BadApp} -> Text = lists:concat([AppName, - ": Illegal contents in app file ", AppFile]), + ": Illegal contents in app file ", AppFile, + ", application tuple with arity 3 expected."]), {missing_app_info(DefaultVsn), reltool_utils:add_warning(Status, Text)}; - {error, Text} when Text =:= EnoentText-> - {missing_app_info(DefaultVsn), Status}; + {error, Text} when Text =:= EnoentText -> + Text2 = lists:concat([AppName, + ": Missing app file ", AppFile, "."]), + {missing_app_info(DefaultVsn), + reltool_utils:add_warning(Status, Text2)}; {error, Text} -> Text2 = lists:concat([AppName, ": Cannot parse app file ", @@ -1045,7 +1113,7 @@ do_get_config(S, InclDef, InclDeriv) -> false -> shrink_sys(S); true -> S end, - {ok, reltool_target:gen_config(S2#state.sys, InclDef)}. + reltool_target:gen_config(S2#state.sys, InclDef). do_save_config(S, Filename, InclDef, InclDeriv) -> {ok, Config} = do_get_config(S, InclDef, InclDeriv), @@ -1072,6 +1140,7 @@ do_load_config(S, SysConfig) -> {ok, _Warnings2} -> S3#state{status = Status3, old_status = S#state.status}; {error, _} -> + %% Keep old state S end, {S4, Status3}; @@ -1093,29 +1162,36 @@ read_config(OldSys, Filename, Status) when is_list(Filename) -> {error, Reason} -> Text = file:format_error(Reason), {OldSys, - reltool_utils:return_first_error(Status, "File access: " ++ - Text)} + reltool_utils:return_first_error(Status, + "Illegal config file " ++ + Filename ++ ": " ++ Text)} end; read_config(OldSys, {sys, KeyVals}, Status) -> {NewSys, Status2} = - try - decode(OldSys#sys{apps = [], rels = []}, KeyVals, Status) - catch - throw:{error, Text} -> - {OldSys, reltool_utils:return_first_error(Status, Text)} - end, - 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:keysearch(NewSys2#sys.boot_rel, #rel.name, NewSys2#sys.rels) of - {value, _} -> - {NewSys2, Status2}; - false -> - Text2 = "Missing rel: " ++ NewSys2#sys.boot_rel, - {OldSys, reltool_utils:return_first_error(Status2, Text2)} + 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:keysearch(NewSys2#sys.boot_rel, + #rel.name, + NewSys2#sys.rels) of + {value, _} -> + {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} end; read_config(OldSys, BadConfig, Status) -> Text = lists:flatten(io_lib:format("~p", [BadConfig])), @@ -1160,120 +1236,96 @@ decode(#sys{} = Sys, [{Key, Val} | KeyVals], Status) -> {Sys#sys{root_dir = Val}, Status}; lib_dirs when is_list(Val) -> {Sys#sys{lib_dirs = Val}, Status}; - mod_cond when Val =:= all; Val =:= app; - Val =:= ebin; Val =:= derived; + mod_cond when Val =:= all; + Val =:= app; + Val =:= ebin; + Val =:= derived; Val =:= none -> {Sys#sys{mod_cond = Val}, Status}; - incl_cond when Val =:= include; Val =:= exclude; + incl_cond when Val =:= include; + Val =:= exclude; Val =:= derived -> {Sys#sys{incl_cond = Val}, Status}; boot_rel when is_list(Val) -> {Sys#sys{boot_rel = Val}, Status}; emu_name when is_list(Val) -> {Sys#sys{emu_name = Val}, Status}; - profile when Val =:= development -> - Val = ?DEFAULT_PROFILE, % assert, - {Sys#sys{profile = Val, - incl_sys_filters = - reltool_utils:decode_regexps(incl_sys_filters, - ?DEFAULT_INCL_SYS_FILTERS, - Sys#sys.incl_sys_filters), - excl_sys_filters = - reltool_utils:decode_regexps(excl_sys_filters, - ?DEFAULT_EXCL_SYS_FILTERS, - Sys#sys.excl_sys_filters), - incl_app_filters = - reltool_utils:decode_regexps(incl_app_filters, - ?DEFAULT_INCL_APP_FILTERS, - Sys#sys.incl_app_filters), - excl_app_filters = - reltool_utils:decode_regexps(excl_app_filters, - ?DEFAULT_EXCL_APP_FILTERS, - Sys#sys.excl_app_filters)}, - Status}; - profile when Val =:= embedded -> - {Sys#sys{profile = Val, - incl_sys_filters = - reltool_utils:decode_regexps(incl_sys_filters, - ?EMBEDDED_INCL_SYS_FILTERS, - Sys#sys.incl_sys_filters), - excl_sys_filters = - reltool_utils:decode_regexps(excl_sys_filters, - ?EMBEDDED_EXCL_SYS_FILTERS, - Sys#sys.excl_sys_filters), - incl_app_filters = - reltool_utils:decode_regexps(incl_app_filters, - ?EMBEDDED_INCL_APP_FILTERS, - Sys#sys.incl_app_filters), - excl_app_filters = - reltool_utils:decode_regexps(excl_app_filters, - ?EMBEDDED_EXCL_APP_FILTERS, - Sys#sys.excl_app_filters)}, - Status}; - profile when Val =:= standalone -> - {Sys#sys{profile = Val, - incl_sys_filters = - reltool_utils:decode_regexps(incl_sys_filters, - ?STANDALONE_INCL_SYS_FILTERS, - Sys#sys.incl_sys_filters), - excl_sys_filters = - reltool_utils:decode_regexps(excl_sys_filters, - ?STANDALONE_EXCL_SYS_FILTERS, - Sys#sys.excl_sys_filters), - incl_app_filters = - reltool_utils:decode_regexps(incl_app_filters, - ?STANDALONE_INCL_APP_FILTERS, - Sys#sys.incl_app_filters), - excl_app_filters = - reltool_utils:decode_regexps(excl_app_filters, - ?STANDALONE_EXCL_APP_FILTERS, - Sys#sys.excl_app_filters)}, + profile when Val =:= development; + Val =:= embedded; + Val =:= standalone -> + InclSys = reltool_utils:choose_default(incl_sys_filters, Val, false), + ExclSys = reltool_utils:choose_default(excl_sys_filters, Val, false), + 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}; incl_sys_filters -> {Sys#sys{incl_sys_filters = - reltool_utils:decode_regexps(Key, - Val, - Sys#sys.incl_sys_filters)}, + dec_re(Key, + Val, + Sys#sys.incl_sys_filters)}, Status}; excl_sys_filters -> {Sys#sys{excl_sys_filters = - reltool_utils:decode_regexps(Key, - Val, - Sys#sys.excl_sys_filters)}, + dec_re(Key, + Val, + Sys#sys.excl_sys_filters)}, Status}; incl_app_filters -> {Sys#sys{incl_app_filters = - reltool_utils:decode_regexps(Key, - Val, - Sys#sys.incl_app_filters)}, + dec_re(Key, + Val, + Sys#sys.incl_app_filters)}, Status}; excl_app_filters -> {Sys#sys{excl_app_filters = - reltool_utils:decode_regexps(Key, - Val, - Sys#sys.excl_app_filters)}, + dec_re(Key, + Val, + Sys#sys.excl_app_filters)}, Status}; incl_archive_filters -> {Sys#sys{incl_archive_filters = - reltool_utils:decode_regexps(Key, - Val, - Sys#sys.incl_archive_filters)}, + dec_re(Key, + Val, + Sys#sys.incl_archive_filters)}, Status}; excl_archive_filters -> {Sys#sys{excl_archive_filters = - reltool_utils:decode_regexps(Key, - Val, - Sys#sys.excl_archive_filters)}, + dec_re(Key, + Val, + Sys#sys.excl_archive_filters)}, Status}; archive_opts when is_list(Val) -> {Sys#sys{archive_opts = Val}, Status}; relocatable when Val =:= true; Val =:= false -> {Sys#sys{relocatable = Val}, Status}; - app_type when Val =:= permanent; - Val =:= transient; - Val =:= temporary; - Val =:= load; Val =:= none -> - {Sys#sys{app_type = Val}, Status}; + rel_app_type when Val =:= permanent; + Val =:= transient; + Val =:= temporary; + Val =:= load; + Val =:= none -> + {Sys#sys{rel_app_type = Val}, Status}; + embedded_app_type when Val =:= permanent; + Val =:= transient; + Val =:= temporary; + Val =:= load; + Val =:= none; + Val =:= undefined -> + {Sys#sys{embedded_app_type = Val}, Status}; app_file when Val =:= keep; Val =:= strip, Val =:= all -> {Sys#sys{app_file = Val}, Status}; debug_info when Val =:= keep; Val =:= strip -> @@ -1303,38 +1355,39 @@ decode(#app{} = App, [{Key, Val} | KeyVals], Status) -> Val =:= strip -> {App#app{debug_info = Val}, Status}; app_file when Val =:= keep; - Val =:= strip, + Val =:= strip; Val =:= all -> {App#app{app_file = Val}, Status}; app_type when Val =:= permanent; Val =:= transient; Val =:= temporary; Val =:= load; - Val =:= none -> + Val =:= none; + Val =:= undefined -> {App#app{app_type = Val}, Status}; incl_app_filters -> {App#app{incl_app_filters = - reltool_utils:decode_regexps(Key, - Val, - App#app.incl_app_filters)}, + dec_re(Key, + Val, + App#app.incl_app_filters)}, Status}; excl_app_filters -> {App#app{excl_app_filters = - reltool_utils:decode_regexps(Key, - Val, - App#app.excl_app_filters)}, + dec_re(Key, + Val, + App#app.excl_app_filters)}, Status}; incl_archive_filters -> {App#app{incl_archive_filters = - reltool_utils:decode_regexps(Key, - Val, - App#app.incl_archive_filters)}, + dec_re(Key, + Val, + App#app.incl_archive_filters)}, Status}; excl_archive_filters -> {App#app{excl_archive_filters = - reltool_utils:decode_regexps(Key, - Val, - App#app.excl_archive_filters)}, + dec_re(Key, + Val, + App#app.excl_archive_filters)}, Status}; archive_opts when is_list(Val) -> {App#app{archive_opts = Val}, Status}; @@ -1439,54 +1492,53 @@ merge_config(OldSys, NewSys, Force, Status) -> apps = PatchedApps}, {NewSys2, Status5}. -verify_config(Sys, Status) -> - case lists:keymember(Sys#sys.boot_rel, #rel.name, Sys#sys.rels) of +verify_config(RelApps, #sys{boot_rel = BootRel, rels = Rels, apps = Apps}, Status) -> + case lists:keymember(BootRel, #rel.name, Rels) of true -> - lists:foreach(fun(Rel)-> check_rel(Rel, Sys, Status) end, - Sys#sys.rels), - Status; + 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([Sys#sys.boot_rel, ": release is mandatory"]), - Status2 = reltool_utils:return_first_error(Status, Text), - throw({error, Status2}) + Text = lists:concat(["Release ", BootRel, + " is mandatory (used as boot_rel)"]), + reltool_utils:return_first_error(Status, Text) + end. + +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. -check_rel(#rel{name = RelName, rel_apps = RelApps}, - #sys{apps = Apps}, - Status) -> +check_rel(RelName, RelApps, Status) -> EnsureApp = - fun(AppName) -> - case lists:keymember(AppName, #rel_app.name, RelApps) of + fun(AppName, Acc) -> + case lists:member({RelName, AppName}, RelApps) of true -> - ok; + Acc; false -> - Text = lists:concat([RelName, ": ", AppName, - " is not included."]), - Status2 = - reltool_utils:return_first_error(Status, Text), - throw({error, Status2}) - end - end, - EnsureApp(kernel), - EnsureApp(stdlib), - CheckRelApp = - fun(#rel_app{name = AppName}) -> - case lists:keysearch(AppName, #app.name, Apps) of - {value, App} when App#app.is_pre_included -> - ok; - {value, App} when App#app.is_included -> - ok; - _ -> - Text = - lists:concat([RelName, ": uses application ", - AppName, " that not is included."]), - Status2 = - reltool_utils:return_first_error(Status, Text), - %% throw BUGBUG: add throw - ({error, Status2}) + Text = lists:concat(["Mandatory application ", + AppName, + " is not included in release ", + RelName]), + reltool_utils:return_first_error(Acc, Text) end end, - lists:foreach(CheckRelApp, RelApps). + Mandatory = [kernel, stdlib], + lists:foldl(EnsureApp, Status, Mandatory). patch_erts_version(RootDir, Apps, Status) -> AppName = erts, @@ -1507,7 +1559,7 @@ patch_erts_version(RootDir, Apps, Status) -> {Apps, Status} end; false -> - Text = "erts cannnot be found in the root directory " ++ RootDir, + Text = "erts cannot be found in the root directory " ++ RootDir, Status2 = reltool_utils:return_first_error(Status, Text), {Apps, Status2} end. @@ -1813,7 +1865,8 @@ default_app(Name) -> status = missing, uses_mods = undefined, is_pre_included = undefined, - is_included = undefined}. + is_included = undefined, + rels = undefined}. %% Assume that the application are sorted refresh_apps([Old | OldApps], [New | NewApps], Acc, Force, Status) @@ -1842,7 +1895,7 @@ 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 of + case Old#app.name =:= ?MISSING_APP_NAME of true -> Status; false -> @@ -1860,7 +1913,7 @@ refresh_apps([], [New | NewApps], Acc, Force, Status) -> refresh_apps([Old | OldApps], [], Acc, Force, Status) -> %% No new version. Remove the old. Status2 = - case Old#app.name =:= ?MISSING_APP of + case Old#app.name =:= ?MISSING_APP_NAME of true -> Status; false -> diff --git a/lib/reltool/src/reltool_sys_win.erl b/lib/reltool/src/reltool_sys_win.erl index 2e226d9147..dbb8e32aa2 100644 --- a/lib/reltool/src/reltool_sys_win.erl +++ b/lib/reltool/src/reltool_sys_win.erl @@ -1227,7 +1227,7 @@ create_fgraph_window(S, Title, Nodes, Links) -> Panel = wxPanel:new(Frame, []), Options = [{size, {lists:max([100, ?WIN_WIDTH - 100]), ?WIN_HEIGHT}}], {Server, Fgraph} = reltool_fgraph_win:new(Panel, Options), - Choose = fun(?MISSING_APP) -> alternate; + Choose = fun(?MISSING_APP_NAME) -> alternate; (_) -> default end, [reltool_fgraph_win:add_node(Server, N, Choose(N)) || N <- Nodes], diff --git a/lib/reltool/src/reltool_target.erl b/lib/reltool/src/reltool_target.erl index e079a02f3c..dd6f75b9fc 100644 --- a/lib/reltool/src/reltool_target.erl +++ b/lib/reltool/src/reltool_target.erl @@ -31,7 +31,7 @@ gen_target/2, install/2 ]). --compile(export_all). + -include("reltool.hrl"). -include_lib("kernel/include/file.hrl"). @@ -64,54 +64,60 @@ kernel_processes(KernelApp) -> %% Generate the contents of a config file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -gen_config(#sys{root_dir = RootDir, - lib_dirs = LibDirs, - mod_cond = ModCond, - incl_cond = AppCond, - apps = Apps, - boot_rel = BootRel, - rels = Rels, - emu_name = EmuName, - profile = Profile, - incl_sys_filters = InclSysFiles, - excl_sys_filters = ExclSysFiles, - incl_app_filters = InclAppFiles, - excl_app_filters = ExclAppFiles, - incl_archive_filters = InclArchiveDirs, - excl_archive_filters = ExclArchiveDirs, - archive_opts = ArchiveOpts, - relocatable = Relocatable, - app_type = AppType, - app_file = AppFile, - debug_info = DebugInfo}, - InclDefs) -> +gen_config(Sys, InclDefs) -> + {ok, do_gen_config(Sys, InclDefs)}. + +do_gen_config(#sys{root_dir = RootDir, + lib_dirs = LibDirs, + mod_cond = ModCond, + incl_cond = AppCond, + apps = Apps, + boot_rel = BootRel, + rels = Rels, + emu_name = EmuName, + profile = Profile, + incl_sys_filters = InclSysFiles, + excl_sys_filters = ExclSysFiles, + incl_app_filters = InclAppFiles, + excl_app_filters = ExclAppFiles, + incl_archive_filters = InclArchiveDirs, + excl_archive_filters = ExclArchiveDirs, + archive_opts = ArchiveOpts, + relocatable = Relocatable, + rel_app_type = RelAppType, + embedded_app_type = InclAppType, + app_file = AppFile, + debug_info = DebugInfo}, + InclDefs) -> ErtsItems = case lists:keysearch(erts, #app.name, Apps) of {value, Erts} -> - [{erts, gen_config(Erts, InclDefs)}]; + [{erts, do_gen_config(Erts, InclDefs)}]; false -> [] end, AppsItems = - [{app, A#app.name, gen_config(A, InclDefs)} + [do_gen_config(A, InclDefs) || A <- Apps, - A#app.name =/= ?MISSING_APP, + A#app.name =/= ?MISSING_APP_NAME, A#app.name =/= erts, - A#app.is_included =:= true, - A#app.is_escript =/= true], + not A#app.is_escript], EscriptItems = [{escript, A#app.active_dir, emit(incl_cond, A#app.incl_cond, undefined, InclDefs)} - || A <- Apps, A#app.is_escript], + || A <- Apps, A#app.is_escript], DefaultRels = reltool_utils:default_rels(), RelsItems = - case {[{rel, R#rel.name, R#rel.vsn, gen_config(R, InclDefs)} || - R <- Rels], - [{rel, R#rel.name, R#rel.vsn, gen_config(R, InclDefs)} || - R <- DefaultRels]} of - {RI, RI} -> []; - {RI, _} -> RI - end, + [{rel, R#rel.name, R#rel.vsn, do_gen_config(R, InclDefs)} || + R <- Rels], + DefaultRelsItems = + [{rel, R#rel.name, R#rel.vsn, do_gen_config(R, InclDefs)} || + R <- DefaultRels], + RelsItems2 = + case InclDefs of + true -> RelsItems; + false -> RelsItems -- DefaultRelsItems + end, X = fun(List) -> [Re || #regexp{source = Re} <- List] end, {sys, emit(root_dir, RootDir, code:root_dir(), InclDefs) ++ @@ -120,78 +126,103 @@ gen_config(#sys{root_dir = RootDir, emit(mod_cond, ModCond, ?DEFAULT_MOD_COND, InclDefs) ++ emit(incl_cond, AppCond, ?DEFAULT_INCL_COND, InclDefs) ++ ErtsItems ++ - AppsItems ++ + lists:flatten(AppsItems) ++ emit(boot_rel, BootRel, ?DEFAULT_REL_NAME, InclDefs) ++ - RelsItems ++ + RelsItems2 ++ emit(emu_name, EmuName, ?DEFAULT_EMU_NAME, InclDefs) ++ emit(relocatable, Relocatable, ?DEFAULT_RELOCATABLE, InclDefs) ++ emit(profile, Profile, ?DEFAULT_PROFILE, InclDefs) ++ - emit(incl_sys_filters, X(InclSysFiles), ?DEFAULT_INCL_SYS_FILTERS, InclDefs) ++ - emit(excl_sys_filters, X(ExclSysFiles), ?DEFAULT_EXCL_SYS_FILTERS, InclDefs) ++ - emit(incl_app_filters, X(InclAppFiles), ?DEFAULT_INCL_APP_FILTERS, InclDefs) ++ - emit(excl_app_filters, X(ExclAppFiles), ?DEFAULT_EXCL_APP_FILTERS, InclDefs) ++ + emit(incl_sys_filters, X(InclSysFiles), reltool_utils:choose_default(incl_sys_filters, Profile, InclDefs), InclDefs) ++ + emit(excl_sys_filters, X(ExclSysFiles), reltool_utils:choose_default(excl_sys_filters, Profile, InclDefs), InclDefs) ++ + emit(incl_app_filters, X(InclAppFiles), reltool_utils:choose_default(incl_app_filters, Profile, InclDefs), InclDefs) ++ + emit(excl_app_filters, X(ExclAppFiles), reltool_utils:choose_default(excl_app_filters, Profile, InclDefs), InclDefs) ++ emit(incl_archive_filters, X(InclArchiveDirs), ?DEFAULT_INCL_ARCHIVE_FILTERS, InclDefs) ++ emit(excl_archive_filters, X(ExclArchiveDirs), ?DEFAULT_EXCL_ARCHIVE_FILTERS, InclDefs) ++ emit(archive_opts, ArchiveOpts, ?DEFAULT_ARCHIVE_OPTS, InclDefs) ++ - emit(app_type, AppType, ?DEFAULT_APP_TYPE, InclDefs) ++ + emit(rel_app_type, RelAppType, ?DEFAULT_REL_APP_TYPE, InclDefs) ++ + emit(embedded_app_type, InclAppType, reltool_utils:choose_default(embedded_app_type, Profile, InclDefs), InclDefs) ++ emit(app_file, AppFile, ?DEFAULT_APP_FILE, InclDefs) ++ emit(debug_info, DebugInfo, ?DEFAULT_DEBUG_INFO, InclDefs)}; -gen_config(#app{name = _Name, - mod_cond = ModCond, - incl_cond = AppCond, - debug_info = DebugInfo, - app_file = AppFile, - incl_app_filters = InclAppFiles, - excl_app_filters = ExclAppFiles, - incl_archive_filters = InclArchiveDirs, - excl_archive_filters = ExclArchiveDirs, - archive_opts = ArchiveOpts, - use_selected_vsn = UseSelected, - vsn = Vsn, - mods = Mods}, - InclDefs) -> - emit(mod_cond, ModCond, undefined, InclDefs) ++ - emit(incl_cond, AppCond, undefined, InclDefs) ++ - emit(debug_info, DebugInfo, undefined, InclDefs) ++ - emit(app_file, AppFile, undefined, InclDefs) ++ - emit(incl_app_filters, InclAppFiles, undefined, InclDefs) ++ - emit(excl_app_filters, ExclAppFiles, undefined, InclDefs) ++ - emit(incl_archive_filters, InclArchiveDirs, undefined, InclDefs) ++ - emit(excl_archive_filters, ExclArchiveDirs, undefined, InclDefs) ++ - emit(archive_opts, ArchiveOpts, undefined, InclDefs) ++ - emit(vsn, Vsn, undefined, InclDefs orelse UseSelected =/= true) ++ - [{mod, M#mod.name, gen_config(M, InclDefs)} || - M <- Mods, - M#mod.is_included =:= true]; -gen_config(#mod{name = _Name, - incl_cond = AppCond, - debug_info = DebugInfo}, - InclDefs) -> - emit(incl_cond, AppCond, undefined, InclDefs) ++ - emit(debug_info, DebugInfo, undefined, InclDefs); -gen_config(#rel{name = _Name, - vsn = _Vsn, - rel_apps = RelApps}, - InclDefs) -> - [gen_config(RA, InclDefs) || RA <- RelApps]; -gen_config(#rel_app{name = Name, - app_type = Type, - incl_apps = InclApps}, - _InclDefs) -> +do_gen_config(#app{name = Name, + mod_cond = ModCond, + incl_cond = AppCond, + debug_info = DebugInfo, + app_file = AppFile, + incl_app_filters = InclAppFiles, + excl_app_filters = ExclAppFiles, + incl_archive_filters = InclArchiveDirs, + excl_archive_filters = ExclArchiveDirs, + archive_opts = ArchiveOpts, + use_selected_vsn = UseSelected, + vsn = Vsn, + mods = Mods, + is_included = IsIncl}, + InclDefs) -> + AppConfig = + [ + emit(mod_cond, ModCond, undefined, InclDefs), + emit(incl_cond, AppCond, undefined, InclDefs), + emit(debug_info, DebugInfo, undefined, InclDefs), + emit(app_file, AppFile, undefined, InclDefs), + emit(incl_app_filters, InclAppFiles, undefined, InclDefs), + emit(excl_app_filters, ExclAppFiles, undefined, InclDefs), + emit(incl_archive_filters, InclArchiveDirs, undefined, InclDefs), + emit(excl_archive_filters, ExclArchiveDirs, undefined, InclDefs), + emit(archive_opts, ArchiveOpts, undefined, InclDefs), + if + IsIncl, InclDefs -> [{vsn, Vsn}]; + UseSelected -> [{vsn, Vsn}]; + true -> [] + end, + [do_gen_config(M, InclDefs) || M <- Mods] + ], + case lists:flatten(AppConfig) of + FlatAppConfig when FlatAppConfig =/= []; IsIncl -> + [{app, Name, FlatAppConfig}]; + [] -> + [] + end; +do_gen_config(#mod{name = Name, + incl_cond = AppCond, + debug_info = DebugInfo, + is_included = IsIncl}, + InclDefs) -> + ModConfig = + [ + emit(incl_cond, AppCond, undefined, InclDefs), + emit(debug_info, DebugInfo, undefined, InclDefs) + ], + case lists:flatten(ModConfig) of + FlatModConfig when FlatModConfig =/= []; IsIncl -> + [{mod, Name, FlatModConfig}]; + _ -> + [] + end; +do_gen_config(#rel{name = _Name, + vsn = _Vsn, + rel_apps = RelApps}, + InclDefs) -> + [do_gen_config(RA, InclDefs) || RA <- RelApps]; +do_gen_config(#rel_app{name = Name, + app_type = Type, + incl_apps = InclApps}, + _InclDefs) -> case {Type, InclApps} of {undefined, []} -> Name; {undefined, _} -> {Name, InclApps}; {_, []} -> {Name, Type}; {_, _} -> {Name, Type, InclApps} end; -gen_config({Tag, Val}, InclDefs) -> +do_gen_config({Tag, Val}, InclDefs) -> emit(Tag, Val, undefined, InclDefs); -gen_config([], _InclDefs) -> +do_gen_config([], _InclDefs) -> []; -gen_config([H | T], InclDefs) -> - lists:flatten([gen_config(H, InclDefs), gen_config(T, InclDefs)]). +do_gen_config([H | T], InclDefs) -> + lists:flatten([do_gen_config(H, InclDefs), do_gen_config(T, InclDefs)]). emit(Tag, Val, Default, InclDefs) -> + %% io:format("~p(~p):\n\t~p\n\t~p\n", + %% [Tag, Val =/= Default, Val, Default]), if Val == undefined -> []; InclDefs -> [{Tag, Val}]; @@ -239,24 +270,127 @@ gen_app(#app{name = Name, %% Generate the contents of a rel file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -gen_rel(#rel{name = RelName, vsn = RelVsn, rel_apps = RelApps}, - #sys{apps = Apps}) -> - {value, Erts} = lists:keysearch(erts, #app.name, Apps), - {release, - {RelName, RelVsn}, - {erts, Erts#app.vsn}, - [app_to_rel(RA, Apps ) || RA <- RelApps]}. - -app_to_rel(#rel_app{name = Name, app_type = Type, incl_apps = InclApps}, - Apps) -> - {value, #app{vsn = Vsn}} = lists:keysearch(Name, #app.name, Apps), +gen_rel(Rel, Sys) -> + try + MergedApps = merge_apps(Rel, Sys), + {ok, do_gen_rel(Rel, Sys, MergedApps)} + catch + throw:{error, Text} -> + {error, Text} + end. + +do_gen_rel(#rel{name = RelName, vsn = RelVsn}, + #sys{apps = Apps}, + MergedApps) -> + ErtsName = erts, + case lists:keysearch(ErtsName, #app.name, Apps) of + {value, Erts} -> + {release, + {RelName, RelVsn}, + {ErtsName, Erts#app.vsn}, + [strip_rel_info(App) || App <- MergedApps]}; + false -> + reltool_utils:throw_error("Mandatory application ~p is " + "not included", + [ErtsName]) + end. + +strip_rel_info(#app{name = Name, + vsn = Vsn, + app_type = Type, + info = #app_info{incl_apps = InclApps}}) + when Type =/= undefined -> case {Type, InclApps} of - {undefined, []} -> {Name, Vsn}; - {undefined, _} -> {Name, Vsn, InclApps}; + {permanent, []} -> {Name, Vsn}; + {permanent, _} -> {Name, Vsn, InclApps}; {_, []} -> {Name, Vsn, Type}; {_, _} -> {Name, Vsn, Type, InclApps} end. +merge_apps(#rel{name = RelName, + rel_apps = RelApps}, + #sys{apps = Apps, + rel_app_type = RelAppType, + embedded_app_type = EmbAppType}) -> + Mandatory = [kernel, stdlib], + MergedApps = do_merge_apps(RelName, Mandatory, Apps, permanent, []), + MergedApps2 = do_merge_apps(RelName, RelApps, Apps, RelAppType, MergedApps), + Embedded = + [A#app.name || A <- Apps, + EmbAppType =/= undefined, + A#app.is_included, + A#app.name =/= erts, + 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). + +do_merge_apps(RelName, [#rel_app{name = Name} = RA | RelApps], Apps, RelAppType, Acc) -> + case is_already_merged(Name, RelApps, Acc) of + true -> + do_merge_apps(RelName, RelApps, Apps, RelAppType, Acc); + false -> + {value, App} = lists:keysearch(Name, #app.name, Apps), + MergedApp = merge_app(RelName, RA, RelAppType, App), + MoreNames = (MergedApp#app.info)#app_info.applications, + Acc2 = [MergedApp | Acc], + do_merge_apps(RelName, MoreNames ++ RelApps, Apps, RelAppType, Acc2) + end; +do_merge_apps(RelName, [Name | RelApps], Apps, RelAppType, Acc) -> + case is_already_merged(Name, RelApps, Acc) of + true -> + do_merge_apps(RelName, RelApps, Apps, RelAppType, Acc); + false -> + RelApp = init_rel_app(Name, Apps), + 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}. + +merge_app(RelName, + #rel_app{name = Name, + app_type = Type, + incl_apps = InclApps}, + RelAppType, + App) -> + Type2 = + case {Type, App#app.app_type} of + {undefined, undefined} -> RelAppType; + {undefined, AppAppType} -> AppAppType; + {_, _} -> Type + end, + Info = App#app.info, + case InclApps -- Info#app_info.incl_apps of + [] -> + App#app{app_type = Type2, info = Info#app_info{incl_apps = InclApps}}; + BadIncl -> + reltool_utils:throw_error("~p: These applications are " + "used by release ~s but are " + "missing as included_applications " + "in the app file: ~p", + [Name, RelName, BadIncl]) + end. + +is_already_merged(Name, [Name | _], _MergedApps) -> + true; +is_already_merged(Name, [#rel_app{name = Name} | _], _MergedApps) -> + true; +is_already_merged(Name, [_ | RelApps], MergedApps) -> + is_already_merged(Name, RelApps, MergedApps); +is_already_merged(Name, [], [#app{name = Name} | _MergedApps]) -> + true; +is_already_merged(Name, [] = RelApps, [_ | MergedApps]) -> + is_already_merged(Name, RelApps, MergedApps); +is_already_merged(_Name, [], []) -> + false. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Generate the contents of a boot file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -270,27 +404,24 @@ gen_boot({script, {_, _}, _} = Script) -> gen_script(Rel, Sys, PathFlag, Variables) -> try - do_gen_script(Rel, Sys, PathFlag, Variables) + MergedApps = merge_apps(Rel, Sys), + do_gen_script(Rel, Sys, MergedApps, PathFlag, Variables) catch throw:{error, Text} -> {error, Text} end. -do_gen_script(#rel{name = RelName, vsn = RelVsn, rel_apps = RelApps}, - #sys{apps = Apps, app_type = DefaultType}, +do_gen_script(#rel{name = RelName, vsn = RelVsn}, + #sys{apps = Apps}, + MergedApps, PathFlag, Variables) -> {value, Erts} = lists:keysearch(erts, #app.name, Apps), Preloaded = [Mod#mod.name || Mod <- Erts#app.mods], Mandatory = mandatory_modules(), Early = Mandatory ++ Preloaded, - MergedApps = [merge_app(RA, Apps, DefaultType) || RA <- RelApps], - SortedApps = sort_apps(MergedApps), - {value, KernelApp} = lists:keysearch(kernel, #app.name, SortedApps), - - InclApps = - lists:append([I || - #app{info = #app_info{incl_apps = I}} <- SortedApps]), + {value, KernelApp} = lists:keysearch(kernel, #app.name, MergedApps), + InclApps = [I || #app{info = #app_info{incl_apps = I}} <- MergedApps], %% Create the script DeepList = @@ -300,30 +431,30 @@ do_gen_script(#rel{name = RelName, vsn = RelVsn, rel_apps = RelApps}, {progress, preloaded}, %% Load mandatory modules - {path, create_mandatory_path(SortedApps, PathFlag, Variables)}, + {path, create_mandatory_path(MergedApps, PathFlag, Variables)}, {primLoad, lists:sort(Mandatory)}, {kernel_load_completed}, {progress, kernel_load_completed}, %% Load remaining modules - [load_app_mods(A, Early, PathFlag, Variables) || A <- SortedApps], + [load_app_mods(A, Early, PathFlag, Variables) || A <- MergedApps], {progress, modules_loaded}, %% Start kernel processes - {path, create_path(SortedApps, PathFlag, Variables)}, + {path, create_path(MergedApps, PathFlag, Variables)}, kernel_processes(gen_app(KernelApp)), {progress, init_kernel_started}, %% Load applications [{apply, {application, load, [gen_app(A)]}} || - A = #app{name = Name, app_type = Type} <- SortedApps, + A = #app{name = Name, app_type = Type} <- MergedApps, Name =/= kernel, Type =/= none], {progress, applications_loaded}, %% Start applications [{apply, {application, start_boot, [Name, Type]}} || - #app{name = Name, app_type = Type} <- SortedApps, + #app{name = Name, app_type = Type} <- MergedApps, Type =/= none, Type =/= load, not lists:member(Name, InclApps)], @@ -334,28 +465,6 @@ do_gen_script(#rel{name = RelName, vsn = RelVsn, rel_apps = RelApps}, ], {ok, {script, {RelName, RelVsn}, lists:flatten(DeepList)}}. -merge_app(#rel_app{name = Name, app_type = Type, incl_apps = RelIncl}, - Apps, - DefaultType) -> - {value, App} = lists:keysearch(Name, #app.name, Apps), - Type2 = - case {Type, App#app.app_type} of - {undefined, undefined} -> DefaultType; - {undefined, AppType} -> AppType; - {_, _} -> Type - end, - Info = App#app.info, - case RelIncl -- Info#app_info.incl_apps of - [] -> - App#app{app_type = Type2, - info = Info#app_info{incl_apps = RelIncl}}; - BadIncl -> - reltool_utils:throw_error("~p: These applications are " - "missing as included_applications " - "in the app file: ~p\n", - [Name, BadIncl]) - end. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% load_app_mods(#app{mods = Mods} = App, Mand, PathFlag, Variables) -> @@ -438,13 +547,13 @@ sort_apps([], [], [], _) -> []; sort_apps([], Missing, [], _) -> %% this has already been checked before, but as we have the info... - reltool_utils:throw_error("Undefined applications: ~p\n", + reltool_utils:throw_error("Undefined applications: ~p", [make_set(Missing)]); sort_apps([], [], Circular, _) -> - reltool_utils:throw_error("Circular dependencies: ~p\n", + reltool_utils:throw_error("Circular dependencies: ~p", [make_set(Circular)]); sort_apps([], Missing, Circular, _) -> - reltool_utils:throw_error("Circular dependencies: ~p\n" + reltool_utils:throw_error("Circular dependencies: ~p" "Undefined applications: ~p\n", [make_set(Circular), make_set(Missing)]). @@ -603,14 +712,15 @@ gen_rel_files(Sys, TargetDir) -> spec_rel_files(#sys{rels = Rels} = Sys) -> lists:append([do_spec_rel_files(R, Sys) || R <- Rels]). -do_spec_rel_files(#rel{name = Name} = Rel, Sys) -> - RelFile = Name ++ ".rel", - ScriptFile = Name ++ ".script", - BootFile = Name ++ ".boot", - GenRel = gen_rel(Rel, Sys), +do_spec_rel_files(#rel{name = RelName} = Rel, Sys) -> + RelFile = RelName ++ ".rel", + ScriptFile = RelName ++ ".script", + BootFile = RelName ++ ".boot", + MergedApps = merge_apps(Rel, Sys), + GenRel = do_gen_rel(Rel, Sys, MergedApps), PathFlag = true, Variables = [], - {ok, Script} = do_gen_script(Rel, Sys, PathFlag, Variables), + {ok, Script} = do_gen_script(Rel, Sys, MergedApps, PathFlag, Variables), {ok, BootBin} = gen_boot(Script), Date = date(), Time = time(), @@ -665,8 +775,6 @@ do_gen_spec(#sys{root_dir = RootDir, {create_dir,BootVsn, RelFiles}]}, {create_dir, "bin", BinFiles} ] ++ SysFiles2, - %% io:format("InclRegexps2: ~p\n", [InclRegexps2]), - %% io:format("ExclRegexps2: ~p\n", [ExclRegexps2]), SysFiles4 = filter_spec(SysFiles3, InclRegexps2, ExclRegexps2), SysFiles5 = SysFiles4 ++ [{create_dir, "lib", LibFiles}], check_sys(["bin", "erts", "lib"], SysFiles5), @@ -678,23 +786,25 @@ strip_sys_files(Relocatable, SysFiles, Apps, ExclRegexps) -> true -> ExtraExcl = ["^erts.*/bin/.*src\$"], reltool_utils:decode_regexps(excl_sys_filters, - {add, ExtraExcl}, ExclRegexps); + {add, ExtraExcl}, + ExclRegexps); false -> ExclRegexps end, {value, Erts} = lists:keysearch(erts, #app.name, Apps), FilterErts = fun(Spec) -> - File = element(2, Spec), - case lists:prefix("erts", File) of - true -> - if - File =:= Erts#app.label -> - replace_dyn_erl(Relocatable, Spec); - true -> - false - end; - false -> + File = element(2, Spec), + case File of + "erts" -> + reltool_utils:throw_error("This system is not installed. " + "The directory ~s is missing.", + [Erts#app.label]); + _ when File =:= Erts#app.label -> + replace_dyn_erl(Relocatable, Spec); + "erts-" ++ _ -> + false; + _ -> true end end, @@ -707,7 +817,8 @@ strip_sys_files(Relocatable, SysFiles, Apps, ExclRegexps) -> replace_dyn_erl(false, _ErtsSpec) -> true; replace_dyn_erl(true, {create_dir, ErtsDir, ErtsFiles}) -> - [{create_dir, _, BinFiles}] = safe_lookup_spec("bin", ErtsFiles), + [{create_dir, _, BinFiles}] = + safe_lookup_spec("bin", ErtsFiles), case lookup_spec("dyn_erl", BinFiles) of [] -> case lookup_spec("erl.ini", BinFiles) of @@ -759,20 +870,31 @@ spec_bin_files(Sys, AllSysFiles, StrippedSysFiles, RelFiles, InclRegexps) -> GoodNames = [F || {copy_file, F} <- OldBinFiles, not lists:suffix(".boot", F), not lists:suffix(".script", F)], - BinFiles2 = [Map(S) || S <- BinFiles, lists:member(element(2, S), GoodNames)], + BinFiles2 = [Map(S) || S <- BinFiles, + lists:member(element(2, S), GoodNames)], BootFiles = [F || F <- RelFiles, lists:suffix(".boot", element(2, F))], - [{write_file, _, BootRel}] = safe_lookup_spec(Sys#sys.boot_rel ++ ".boot", BootFiles), - BootFiles2 = lists:keystore("start.boot", 2, BootFiles, {write_file, "start.boot", BootRel}), - MakeRegexp = fun(File) -> "^bin/" ++ element(2, File) ++ "(|.escript)\$" end, + [{write_file, _, BootRel}] = + safe_lookup_spec(Sys#sys.boot_rel ++ ".boot", BootFiles), + BootFiles2 = lists:keystore("start.boot", + 2, + BootFiles, + {write_file, "start.boot", BootRel}), + MakeRegexp = + fun(File) -> "^bin/" ++ element(2, File) ++ "(|.escript)\$" end, ExtraIncl = lists:map(MakeRegexp, Escripts), - InclRegexps2 = reltool_utils:decode_regexps(incl_sys_filters, {add, ExtraIncl}, InclRegexps), + InclRegexps2 = reltool_utils:decode_regexps(incl_sys_filters, + {add, ExtraIncl}, + InclRegexps), {InclRegexps2, Escripts ++ BinFiles2 ++ BootFiles2}. spec_escripts(#sys{apps = Apps}, ErtsBin, BinFiles) -> - Filter = fun(#app{is_escript = IsEscript, is_included = IsIncl, - is_pre_included = IsPre, name = Name, active_dir = File}) -> + Filter = fun(#app{is_escript = IsEscript, + is_included = IsIncl, + is_pre_included = IsPre, + name = Name, + active_dir = File}) -> if - Name =:= ?MISSING_APP -> + Name =:= ?MISSING_APP_NAME -> false; not IsEscript -> false; @@ -796,7 +918,6 @@ check_sys(Mandatory, SysFiles) -> lists:foreach(fun(M) -> do_check_sys(M, SysFiles) end, Mandatory). do_check_sys(Prefix, Specs) -> - %%io:format("Prefix: ~p\n", [Prefix]), case lookup_spec(Prefix, Specs) of [] -> reltool_utils:throw_error("Mandatory system directory ~s " @@ -820,6 +941,7 @@ lookup_spec(Prefix, Specs) -> safe_lookup_spec(Prefix, Specs) -> case lookup_spec(Prefix, Specs) of [] -> + %% io:format("lookup fail ~s:\n\t~p\n", [Prefix, Specs]), reltool_utils:throw_error("Mandatory system file ~s is " "not included", [Prefix]); Match -> @@ -834,7 +956,7 @@ spec_lib_files(#sys{apps = Apps} = Sys) -> Filter = fun(#app{is_escript = IsEscript, is_included = IsIncl, is_pre_included = IsPre, name = Name}) -> if - Name =:= ?MISSING_APP -> + Name =:= ?MISSING_APP_NAME -> false; IsEscript -> false; @@ -863,10 +985,10 @@ check_apps([], _) -> spec_app(#app{name = Name, mods = Mods, active_dir = SourceDir, - incl_app_filters = AppInclRegexps, - excl_app_filters = AppExclRegexps} = App, - #sys{incl_app_filters = SysInclRegexps, - excl_app_filters = SysExclRegexps, + incl_app_filters = AppInclRegexps, + excl_app_filters = AppExclRegexps} = App, + #sys{incl_app_filters = SysInclRegexps, + excl_app_filters = SysExclRegexps, debug_info = SysDebugInfo} = Sys) -> %% List files recursively {create_dir, _, AppFiles} = spec_dir(SourceDir), @@ -942,13 +1064,13 @@ spec_dir(Dir) -> Base, [spec_dir(filename:join([Dir, F])) || F <- Files]}; error -> - reltool_utils:throw_error("list dir ~s failed\n", [Dir]) + reltool_utils:throw_error("list dir ~s failed", [Dir]) end; {ok, #file_info{type = regular}} -> %% Plain file {copy_file, Base}; _ -> - reltool_utils:throw_error("read file info ~s failed\n", [Dir]) + reltool_utils:throw_error("read file info ~s failed", [Dir]) end. spec_mod(Mod, DebugInfo) -> @@ -1082,7 +1204,7 @@ do_eval_spec({archive, Archive, Options, Files}, {ok, _} -> ok; {error, Reason} -> - reltool_utils:throw_error("create archive ~s: ~p\n", + reltool_utils:throw_error("create archive ~s failed: ~p", [ArchiveFile, Reason]) end; do_eval_spec({copy_file, File}, _OrigSourceDir, SourceDir, TargetDir) -> @@ -1216,18 +1338,7 @@ opt_join(Path, File) -> filename:join([Path, File]). match(String, InclRegexps, ExclRegexps) -> - %%case - match(String, InclRegexps) andalso not match(String, ExclRegexps). -%% of -%% true -> -%% true; -%% false -> -%% io:format("no match: ~p\n" -%% " incl: ~p\n" -%% " excl: ~p\n", -%% [String, InclRegexps, ExclRegexps]), -%% false -%% end. + match(String, InclRegexps) andalso not match(String, ExclRegexps). %% Match at least one regexp match(_String, []) -> @@ -1284,7 +1395,7 @@ do_install(RelName, TargetDir) -> ok = release_handler:create_RELEASES(TargetDir2, RelFile), ok; _ -> - reltool_utils:throw_error("~s: Illegal syntax.\n", [DataFile]) + reltool_utils:throw_error("~s: Illegal data file syntax", [DataFile]) end. subst_src_scripts(Scripts, SrcDir, DestDir, Vars, Opts) -> diff --git a/lib/reltool/src/reltool_utils.erl b/lib/reltool/src/reltool_utils.erl index 403fa574c5..39d057d994 100644 --- a/lib/reltool/src/reltool_utils.erl +++ b/lib/reltool/src/reltool_utils.erl @@ -19,7 +19,30 @@ -module(reltool_utils). %% Public --compile([export_all]). +-export([root_dir/0, erl_libs/0, lib_dirs/1, + split_app_name/1, prim_consult/1, + default_rels/0, choose_default/3, + + assign_image_list/1, get_latest_resize/1, + 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, + + safe_keysearch/5, print/4, return_first_error/2, add_warning/2, + + create_dir/1, list_dir/1, read_file_info/1, + write_file_info/2, read_file/1, write_file/2, + recursive_delete/1, delete/2, recursive_copy_file/2, copy_file/2, + + throw_error/2, + + decode_regexps/3, + default_val/2, + escript_foldl/3, + + call/2, cast/2, reply/3]). -include_lib("kernel/include/file.hrl"). -include_lib("wx/include/wx.hrl"). @@ -103,18 +126,46 @@ 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 = #rel_app{name = kernel, incl_apps = []}, + %%Stdlib = #rel_app{name = stdlib, incl_apps = []}, + Sasl = #rel_app{name = sasl, incl_apps = []}, [ #rel{name = ?DEFAULT_REL_NAME, vsn = "1.0", - rel_apps = [Kernel, Stdlib]}, + rel_apps = []}, + %%rel_apps = [Kernel, Stdlib]}, #rel{name = "start_sasl", vsn = "1.0", - rel_apps = [Kernel, Sasl, Stdlib]} + rel_apps = [Sasl]} + %%rel_apps = [Kernel, Sasl, Stdlib]} ]. +choose_default(Tag, Profile, InclDefs) + when Profile =:= ?DEFAULT_PROFILE; InclDefs -> + case Tag of + incl_sys_filters -> ?DEFAULT_INCL_SYS_FILTERS; + excl_sys_filters -> ?DEFAULT_EXCL_SYS_FILTERS; + incl_app_filters -> ?DEFAULT_INCL_APP_FILTERS; + excl_app_filters -> ?DEFAULT_EXCL_APP_FILTERS; + embedded_app_type -> ?DEFAULT_EMBEDDED_APP_TYPE + end; +choose_default(Tag, standalone, _InclDefs) -> + case Tag of + incl_sys_filters -> ?STANDALONE_INCL_SYS_FILTERS; + excl_sys_filters -> ?STANDALONE_EXCL_SYS_FILTERS; + incl_app_filters -> ?STANDALONE_INCL_APP_FILTERS; + excl_app_filters -> ?STANDALONE_EXCL_APP_FILTERS; + embedded_app_type -> ?DEFAULT_EMBEDDED_APP_TYPE + end; +choose_default(Tag, embedded, _InclDefs) -> + case Tag of + incl_sys_filters -> ?EMBEDDED_INCL_SYS_FILTERS; + excl_sys_filters -> ?EMBEDDED_EXCL_SYS_FILTERS; + incl_app_filters -> ?EMBEDDED_INCL_APP_FILTERS; + excl_app_filters -> ?EMBEDDED_EXCL_APP_FILTERS; + embedded_app_type -> ?EMBEDDED_APP_TYPE + end. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% assign_image_list(ListCtrl) -> @@ -379,7 +430,7 @@ create_dir(Dir) -> ok; {error, Reason} -> Text = file:format_error(Reason), - throw_error("create dir ~s: ~s\n", [Dir, Text]) + throw_error("create dir ~s: ~s", [Dir, Text]) end. list_dir(Dir) -> @@ -388,7 +439,7 @@ list_dir(Dir) -> Files; error -> Text = file:format_error(enoent), - throw_error("list dir ~s: ~s\n", [Dir, Text]) + throw_error("list dir ~s: ~s", [Dir, Text]) end. read_file_info(File) -> @@ -397,7 +448,7 @@ read_file_info(File) -> Info; {error, Reason} -> Text = file:format_error(Reason), - throw_error("read file info ~s: ~s\n", [File, Text]) + throw_error("read file info ~s: ~s", [File, Text]) end. write_file_info(File, Info) -> @@ -406,7 +457,7 @@ write_file_info(File, Info) -> ok; {error, Reason} -> Text = file:format_error(Reason), - throw_error("write file info ~s: ~s\n", [File, Text]) + throw_error("write file info ~s: ~s", [File, Text]) end. read_file(File) -> @@ -415,7 +466,7 @@ read_file(File) -> Bin; {error, Reason} -> Text = file:format_error(Reason), - throw_error("read file ~s: ~s\n", [File, Text]) + throw_error("read file ~s: ~s", [File, Text]) end. write_file(File, IoList) -> @@ -424,7 +475,7 @@ write_file(File, IoList) -> ok; {error, Reason} -> Text = file:format_error(Reason), - throw_error("write file ~s: ~s\n", [File, Text]) + throw_error("write file ~s: ~s", [File, Text]) end. recursive_delete(Dir) -> @@ -560,7 +611,12 @@ escript_foldl(Fun, Acc, File) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% call(Name, Msg) when is_atom(Name) -> - call(whereis(Name), Msg); + case whereis(Name) of + undefined -> + {error, {noproc, Name}}; + Pid -> + call(Pid, Msg) + end; call(Pid, Msg) when is_pid(Pid) -> Ref = erlang:monitor(process, Pid), Pid ! {call, self(), Ref, Msg}, |