aboutsummaryrefslogtreecommitdiffstats
path: root/lib/reltool
diff options
context:
space:
mode:
Diffstat (limited to 'lib/reltool')
-rwxr-xr-xlib/reltool/bin/reltool.escript249
-rw-r--r--lib/reltool/doc/src/notes.xml145
-rw-r--r--lib/reltool/doc/src/reltool.xml245
-rw-r--r--lib/reltool/doc/src/reltool_examples.xml6
-rw-r--r--lib/reltool/doc/src/reltool_usage.xml72
-rw-r--r--lib/reltool/src/Makefile54
-rw-r--r--lib/reltool/src/files.mk32
-rw-r--r--lib/reltool/src/reltool.app.src45
-rw-r--r--lib/reltool/src/reltool.appup.src22
-rw-r--r--lib/reltool/src/reltool.erl248
-rw-r--r--lib/reltool/src/reltool.hrl379
-rw-r--r--lib/reltool/src/reltool_app_win.erl248
-rw-r--r--lib/reltool/src/reltool_fgraph.erl34
-rw-r--r--lib/reltool/src/reltool_fgraph_win.erl277
-rw-r--r--lib/reltool/src/reltool_mod_win.erl251
-rw-r--r--lib/reltool/src/reltool_server.erl1328
-rw-r--r--lib/reltool/src/reltool_sys_win.erl536
-rw-r--r--lib/reltool/src/reltool_target.erl803
-rw-r--r--lib/reltool/src/reltool_utils.erl143
-rw-r--r--lib/reltool/test/Makefile20
-rw-r--r--lib/reltool/test/reltool.cover2
-rw-r--r--lib/reltool/test/reltool.spec3
-rw-r--r--lib/reltool/test/reltool_app_SUITE.erl292
-rw-r--r--lib/reltool/test/reltool_server_SUITE.erl229
-rw-r--r--lib/reltool/test/reltool_server_SUITE_data/Makefile.src19
-rw-r--r--lib/reltool/test/reltool_server_SUITE_data/otp_9229/x-1.0/ebin/x.app7
-rw-r--r--lib/reltool/test/reltool_server_SUITE_data/otp_9229/x-1.0/src/mylib.erl4
-rw-r--r--lib/reltool/test/reltool_server_SUITE_data/otp_9229/x-1.0/src/x.erl4
-rw-r--r--lib/reltool/test/reltool_server_SUITE_data/otp_9229/y-1.0/ebin/y.app7
-rw-r--r--lib/reltool/test/reltool_server_SUITE_data/otp_9229/y-1.0/src/mylib.erl4
-rw-r--r--lib/reltool/test/reltool_server_SUITE_data/otp_9229/y-1.0/src/y.erl4
-rw-r--r--lib/reltool/test/reltool_test_lib.erl22
-rw-r--r--lib/reltool/test/reltool_test_lib.hrl11
-rw-r--r--lib/reltool/test/reltool_wx_SUITE.erl29
-rwxr-xr-xlib/reltool/test/rtt12
-rw-r--r--lib/reltool/test/rtt.erl2
-rw-r--r--lib/reltool/vsn.mk10
37 files changed, 4002 insertions, 1796 deletions
diff --git a/lib/reltool/bin/reltool.escript b/lib/reltool/bin/reltool.escript
new file mode 100755
index 0000000000..0dcd5ad1e9
--- /dev/null
+++ b/lib/reltool/bin/reltool.escript
@@ -0,0 +1,249 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+%%
+%% %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%
+
+-include_lib("reltool/src/reltool.hrl").
+
+main(Args) ->
+ process_flag(trap_exit, true),
+ try
+ Tokens = scan_args(Args, [], []),
+ {Options, Actions} = parse_args(Tokens, []),
+ case invoke(Options, Actions) of
+ ok ->
+ safe_stop(0);
+ {error, ReasonString} ->
+ fatal_error(ReasonString, 2)
+ end
+ catch
+ throw:usage ->
+ usage(),
+ safe_stop(1);
+ exit:Reason ->
+ String = lists:flatten(io_lib:format("EXIT: ~p", [Reason])),
+ fatal_error(String, 3)
+ end.
+
+usage() ->
+ Usage =
+ [
+ "[Config] [--window]",
+ "[Config] --create_config [-defaults] [-derived] [ConfigFile]",
+ "[Config] --create_rel RelName [RelFile]",
+ "[Config] --create_script RelName [ScriptFile]",
+ "[Config] --create_target TargetDir",
+ "[Config] --create_target_spec [SpecFile]",
+ "[Config] --eval_target_spec Spec TargetDir RootDir"
+ ],
+ Script = script_name(),
+ String = lists:flatten([[Script, " ", U, "\n"] || U <- Usage]),
+ io:format("Erlang/OTP release management tool\n\n"
+ "~s\nConfig = ConfigFile | '{sys, [sys()]}'\n"
+ "Spec = SpecFile | '{spec, [target_spec()}']\n\n"
+ "See User's guide and Reference manual for more info.\n",
+ [String]).
+
+safe_stop(Code) ->
+ init:stop(Code),
+ timer:sleep(infinity).
+
+invoke(Options, Actions) ->
+ case Actions of
+ [] ->
+ invoke(Options, [["--window"]]);
+ [["--window"]] ->
+ start_window(Options);
+ [["--create_config" | OptArgs]] ->
+ DefArg = "-defaults",
+ DerivArg = "-derived",
+ InclDef = lists:member(DefArg, OptArgs),
+ InclDeriv = lists:member(DerivArg, OptArgs),
+ case reltool:get_config(Options, InclDef, InclDeriv) of
+ {ok, Config} ->
+ String = pretty("config", Config),
+ case OptArgs -- [DefArg, DerivArg] of
+ [] ->
+ format("~s", [String]);
+ [ConfigFile] ->
+ write_file(ConfigFile, String);
+ _ ->
+ throw(usage)
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ [["--create_rel", RelName | OptArgs]] ->
+ case reltool:get_rel(Options, RelName) of
+ {ok, Rel} ->
+ String = pretty("rel", Rel),
+ case OptArgs of
+ [] ->
+ format("~s", [String]);
+ [RelFile] ->
+ write_file(RelFile, String);
+ _ ->
+ throw(usage)
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ [["--create_script", RelName | OptArgs]] ->
+ case reltool:get_script(Options, RelName) of
+ {ok, Script} ->
+ String = pretty("script", Script),
+ case OptArgs of
+ [] ->
+ format("~s", [String]);
+ [ScriptFile] ->
+ write_file(ScriptFile, String);
+ _ ->
+ throw(usage)
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ [["--create_target", TargetDir]] ->
+ reltool:create_target(Options, TargetDir);
+ [["--create_target_spec" | OptArgs]] ->
+ case reltool:get_target_spec(Options) of
+ {ok, Script} ->
+ String = pretty("target_spec", Script),
+ case OptArgs of
+ [] ->
+ format("~s", [String]);
+ [SpecFile] ->
+ write_file(SpecFile, String);
+ _ ->
+ throw(usage)
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ [["--eval_target_spec", TargetSpec, TargetDir, RootDir]] ->
+ try
+ {ok, Tokens, _} = erl_scan:string(TargetSpec ++ ". "),
+ {ok, {spec, Spec}} = erl_parse:parse_term(Tokens),
+ reltool:eval_target_spec(Spec, TargetDir, RootDir)
+ catch
+ error:{badmatch, _} ->
+ case file:consult(TargetSpec) of
+ {ok, Spec2} ->
+ reltool:eval_target_spec(Spec2, TargetDir, RootDir);
+ {error, Reason} ->
+ Text = file:format_error(Reason),
+ {error, TargetSpec ++ ": " ++ Text}
+ end
+ end;
+ _ ->
+ throw(usage)
+ end.
+
+start_window(Options) ->
+ case reltool:start_link(Options) of
+ {ok, WinPid} ->
+ receive
+ {'EXIT', WinPid, shutdown} ->
+ ok;
+ {'EXIT', WinPid, normal} ->
+ ok;
+ {'EXIT', WinPid, Reason} ->
+ exit(Reason)
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Helpers
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+script_name() ->
+ filename:basename(escript:script_name(), ".escript").
+
+fatal_error(String, Code) ->
+ io:format(standard_error, "~s: ~s\n", [script_name(), String]),
+ safe_stop(Code).
+
+write_file(File, IoList) ->
+ case file:write_file(File, IoList) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ {error, file:format_error(Reason)}
+ end.
+
+format(Format, Args) ->
+ io:format(Format, Args),
+ %% Wait a while for the I/O to be processed
+ timer:sleep(timer:seconds(1)).
+
+pretty(Tag, Term) ->
+ lists:flatten(io_lib:format("%% ~s generated at ~w ~w\n~p.\n\n",
+ [Tag, date(), time(), Term])).
+
+scan_args([H | T], Single, Multi) ->
+ case H of
+ "--" ++ _ when Single =:= [] ->
+ scan_args(T, [H], Multi);
+ "--" ++ _ ->
+ scan_args(T, [H], [lists:reverse(Single) | Multi]);
+ _ ->
+ scan_args(T, [H | Single], Multi)
+ end;
+scan_args([], [], Multi) ->
+ lists:reverse(Multi);
+scan_args([], Single, Multi) ->
+ lists:reverse([lists:reverse(Single) | Multi]).
+
+parse_args([H | T] = Args, Options) ->
+ case H of
+ ["--wx_debug" | Levels] ->
+ Dbg =
+ fun(L) ->
+ case catch list_to_integer(L) of
+ {'EXIT', _} ->
+ case catch list_to_atom(L) of
+ {'EXIT', _} ->
+ exit("Illegal wx debug level: " ++ L);
+ Atom ->
+ Atom
+ end;
+ Int ->
+ Int
+ end
+ end,
+ Levels2 = lists:map(Dbg, Levels),
+ parse_args(T, [{wx_debug, Levels2} | Options]);
+ ["--" ++ _ | _] ->
+ %% No more options
+ {lists:reverse(Options), Args};
+ [Config] ->
+ try
+ {ok, Tokens, _} = erl_scan:string(Config ++ ". "),
+ {ok, {sys, _} = Sys} = erl_parse:parse_term(Tokens),
+ parse_args(T, [{config, Sys} | Options])
+ catch
+ error:{badmatch, _} ->
+ parse_args(T, [{config, Config} | Options]);
+ X:Y ->
+ io:format("\n\n~p\n\n", [{X, Y}])
+ end
+ end;
+parse_args([], Options) ->
+ {lists:reverse(Options), []}.
diff --git a/lib/reltool/doc/src/notes.xml b/lib/reltool/doc/src/notes.xml
index 524d728901..5304b996a4 100644
--- a/lib/reltool/doc/src/notes.xml
+++ b/lib/reltool/doc/src/notes.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2009</year>
- <year>2009</year>
+ <year>2011</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -37,6 +37,149 @@
thus constitutes one section in this document. The title of each
section is the version number of Reltool.</p>
+ <section><title>Reltool 0.5.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ If a module was duplicated in the library directories
+ visible to reltool, and the configuration did not point
+ out which file to use, then reltool:start would always
+ fail. A pop-up is added which asks if you want to
+ continue with a safe and minimal configuration.</p>
+ <p>
+ Own Id: OTP-9383</p>
+ </item>
+ <item>
+ <p>
+ wx would sometimes crash due to an empty radiobox on the
+ 'releases' tab of the system window. This radiobox is
+ removed, and replaced by a listbox which will always
+ contain at least kernel and stdlib applications.</p>
+ <p>
+ Own Id: OTP-9384</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Reltool 0.5.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The system level option <c>app_files</c> is documented to
+ allow the values <c>keep | strip | all</c>, but it only
+ allowed <c>keep</c>. This is corrected.</p>
+ <p>
+ Own Id: OTP-9135</p>
+ </item>
+ <item>
+ <p>
+ Allow the same module name in multiple applications
+ visible to reltool, as long as all but one of the
+ applications/modules are explicitely excluded. (Thanks to
+ Andrew Gopienko and Jay Nelson)</p>
+ <p>
+ Own Id: OTP-9229</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Reltool 0.5.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The reltool module contained two seriously erroneous
+ specs which caused bogus warnings when dialyzing reltool
+ and some correct code of users. These were fixed (specs
+ for start_link/1 and eval_server/3)</p>
+ <p>
+ - Code cleanups and simplifications - Fix a bug in the
+ calculation of circular dependencies - Eliminate two
+ dialyzer warnings - Put files alphabetically</p>
+ <p>
+ Own Id: OTP-9120</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Reltool 0.5.4</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Added function <c>zip:foldl/3</c> to iterate over zip
+ archives.</p>
+ <p>
+ Added functions to create and extract escripts. See
+ <c>escript:create/2</c> and <c>escript:extract/2</c>.</p>
+ <p>
+ The undocumented function <c>escript:foldl/3</c> has been
+ removed. The same functionality can be achieved with the
+ more flexible functions <c>escript:extract/2</c> and
+ <c>zip:foldl/3</c>.</p>
+ <p>
+ Record fields has been annotated with type info. Source
+ files as been adapted to fit within 80 chars and trailing
+ whitespace has been removed.</p>
+ <p>
+ Own Id: OTP-8521</p>
+ </item>
+ <item>
+ <p>A new escript, called <c>reltool</c>, has been
+ introduced in order to simplify the usage of the reltool
+ application from makefiles.</p>
+ <p>The handling of applications included in releases has
+ been improved. Applications that are required to be
+ started before other applications in a release are now
+ automatically included in the release. The <c>kernel</c>
+ and <c>stdlib</c> applications are always included as
+ they are mandatory.</p>
+ <p>Applications that are (explicitly or implicitly)
+ included in a release are now automatically included as
+ if they were explicitly included with the incl_cond
+ flag.</p>
+ <p>A new <c>embedded_app_type</c> option has been
+ introduced. It is intended to be used for embedded
+ systems where all included applications must be loaded
+ from the boot script, as these systems does not utilize
+ dynamic code loading. If <c>embedded_app_type </c> is set
+ to something else than <c>undefined</c>, all included
+ applications will be included in both the release as well
+ as in the boot script. If the <c>profile</c> is
+ <c>embedded</c> the <c>embedded_app_type</c> option
+ defaults to <c>load</c>.</p>
+ <p>A new function called <c>reltool:get_status/1</c> has
+ been introduced. It returns status about the
+ configuration in the server.</p>
+ <p>The API functions that may take <c>PidOrOptions</c> as
+ input and actually gets <c>Options</c> does now print out
+ warnings.</p>
+ <p>The internal error handling has been improved. For
+ example <c>{error,Reason}</c> is always returned in case
+ of errors even when the server dies.</p>
+ <p><c>app</c> and <c>appup</c> files has been added as
+ well as a corresponding test suite.</p>
+ <p>Various cleanups has been made in the code and in the
+ documentation.</p>
+ <p>
+ Own Id: OTP-8590</p>
+ </item>
+ </list>
+ </section>
+
+ </section>
<section><title>Reltool 0.5.3</title>
diff --git a/lib/reltool/doc/src/reltool.xml b/lib/reltool/doc/src/reltool.xml
index 9786928ae8..31e15e34e7 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>2009</year>
+ <year>2011</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -48,8 +48,8 @@
<c>root_dir</c> is the root directory of the analysed system and
it defaults to the system executing <c>reltool</c>. Applications
may also be located outside <c>root_dir</c>. <c>lib_dirs</c>
- defines additional library directories where applications
- additional may reside and it defaults to the the directories
+ defines library directories where additional applications
+ may reside and it defaults to the directories
listed by the operating system environment variable
<c>ERL_LIBS</c>. See the module <c>code</c> for more info.
Finally single modules and entire applications may be read from
@@ -58,23 +58,23 @@
<p>Some configuration parameters control the behavior of Reltool
on system (<c>sys</c>) level. Others provide control on
application (<c>app</c>) level and yet others are on module
- (<c>mod</c>) level. Module level parameters overrides application
- level parameters and application level parameters overrides system
+ (<c>mod</c>) level. Module level parameters override application
+ level parameters and application level parameters override system
level parameters. Escript <c>escript</c> level parameters
- overrides system level parameters.</p>
+ override system level parameters.</p>
<p>The following top level <c>options</c> are supported:</p>
<taglist>
- <tag><c><![CDATA[config]]></c></tag>
+ <tag><c>config</c></tag>
<item>
<p>This is the main option and it controls the configuration
of <c>reltool</c>. It can either be a <c>sys</c> tuple or
a name of a <c>file</c> containing a sys tuple.</p>
</item>
- <tag><c><![CDATA[trap_exit]]></c></tag>
+ <tag><c>trap_exit</c></tag>
<item>
<p>This option controls the error handling behavior of
<c>reltool</c>. By default the window processes traps
@@ -82,7 +82,7 @@
<c>trap_exit</c> to <c>false</c>.</p>
</item>
- <tag><c><![CDATA[wx_debug]]></c></tag>
+ <tag><c>wx_debug</c></tag>
<item>
<p>This option controls the debug level of <c>wx</c>. As its
name indicates it is only useful for debugging. See
@@ -97,36 +97,36 @@
<taglist>
- <tag><c><![CDATA[erts]]></c></tag>
+ <tag><c>erts</c></tag>
<item>
<p>Erts specific configuration. See application level options
below.</p>
</item>
- <tag><c><![CDATA[escript]]></c></tag>
+ <tag><c>escript</c></tag>
<item>
<p>Escript specific configuration. An escript has a mandatory
file name and escript level options that are described
below.</p>
</item>
- <tag><c><![CDATA[app]]></c></tag>
+ <tag><c>app</c></tag>
<item>
<p>Application specific configuration. An application has a
mandatory name and application level options that are
described below.</p>
</item>
- <tag><c><![CDATA[mod_cond]]></c></tag>
+ <tag><c>mod_cond</c></tag>
<item>
<p>This parameter controls the module inclusion policy. It
defaults to <c>all</c> which means that if an application is
included (either explicitly or implicitly) all modules in that
application will be included. This implies that both modules
- that exists on the <c>ebin</c> directory of the application,
+ that exist in the <c>ebin</c> directory of the application,
as well as modules that are named in the <c>app</c> file will
be included. If the parameter is set to <c>ebin</c>, both
- modules on the <c>ebin</c> directory and derived modules are
+ modules in the <c>ebin</c> directory and derived modules are
included. If the parameter is set to <c>app</c>, both modules
in the <c>app</c> file and derived modules are included.
<c>derived</c> means that only modules that are used by other
@@ -134,69 +134,69 @@
system level is used as default for all applications.</p>
</item>
- <tag><c><![CDATA[incl_cond]]></c></tag>
+ <tag><c>incl_cond</c></tag>
<item>
- <p>This parameter controls the application and escript
- inclusion policy. It defaults to <c>derived</c> which means
- that the applications that not have any explicit
- <c>incl_cond</c> setting, will only be included if any other
- (explicitly or implicitly included) application uses it. The
- value <c>include</c> implies that all applications and
- escripts that that not have any explicit <c>incl_cond</c>
- setting will be included. <c>exclude</c> implies that all
- applications and escripts) that that not have any explicit
- <c>incl_cond</c> setting will be excluded.</p>
+ <p>This parameter controls the application and escript
+ inclusion policy. It defaults to <c>derived</c> which means
+ that the applications that do not have any explicit
+ <c>incl_cond</c> setting, will only be included if any other
+ (explicitly or implicitly included) application uses it. The
+ value <c>include</c> implies that all applications and
+ escripts that do not have any explicit <c>incl_cond</c>
+ setting will be included. <c>exclude</c> implies that all
+ applications and escripts) that do not have any explicit
+ <c>incl_cond</c> setting will be excluded.</p>
</item>
- <tag><c><![CDATA[boot_rel]]></c></tag>
+ <tag><c>boot_rel</c></tag>
<item>
<p>A target system may have several releases but the one given
as <c>boot_rel</c> will be used as default when the system is
booting up.</p>
</item>
- <tag><c><![CDATA[rel]]></c></tag>
+ <tag><c>rel</c></tag>
<item>
<p>Release specific configuration. Each release maps to a
- <c>rel</c>, <c>script</c> and <c>boot </c> file. See the
+ <c>rel</c>, <c>script</c> and <c>boot</c> file. See the
module <c>systools</c> for more info about the details. Each
release has a name, a version and a set of applications with a
few release specific parameters such as type and included
applications.</p>
</item>
- <tag><c><![CDATA[relocatable]]></c></tag>
+ <tag><c>relocatable</c></tag>
<item>
- <p>This parameter controls whether the <c>erl</c> executable
- in the target system automatically should determine where it
- is installed or if it should use a hardcoded path to the
- installation. In the latter case the target system must be
- installed with <c>reltool:install/2</c> before it can be
- used. If the system is relocatable, the file tree containing
- the target system can be moved to another location without
- re-installation. The default is <c>true</c>.</p>
+ <p>This parameter controls whether the <c>erl</c> executable
+ in the target system should automatically determine where it
+ is installed or if it should use a hardcoded path to the
+ installation. In the latter case the target system must be
+ installed with <c>reltool:install/2</c> before it can be
+ used. If the system is relocatable, the file tree containing
+ the target system can be moved to another location without
+ re-installation. The default is <c>true</c>.</p>
</item>
- <tag><c><![CDATA[profile]]></c></tag>
+ <tag><c>profile</c></tag>
<item>
- <p>The creation of the specification for a target system is
- performed in two steps. In the first step a complete
- specification is generated. It will likely contain much more
- files than you are interested in your customized target
- system. In the second step the specification will be filtered
- according to your filters. There you have the ability to
- specify filters per application as well as system wide
- filters. You can also select a <c>profile</c> for your
- system. Depending on the <c>profile</c>, different default
- filters will be used. There are three different profiles to
- choose from: <c>development</c>, <c>embedded</c> and
- <c>standalone</c>. <c>development</c> is default. The
- parameters that are affected by the <c>profile</c> are:
- <c>incl_sys_filters</c>, <c>excl_sys_filters</c>,
- <c>incl_app_filters</c> and <c>excl_app_filters</c>.</p>
+ <p>The creation of the specification for a target system is
+ performed in two steps. In the first step a complete
+ specification is generated. It will likely contain much more
+ files than you are interested in in your customized target
+ system. In the second step the specification will be filtered
+ according to your filters. There you have the ability to
+ specify filters per application as well as system wide
+ filters. You can also select a <c>profile</c> for your
+ system. Depending on the <c>profile</c>, different default
+ filters will be used. There are three different profiles to
+ choose from: <c>development</c>, <c>embedded</c> and
+ <c>standalone</c>. <c>development</c> is default. The
+ parameters that are affected by the <c>profile</c> are:
+ <c>incl_sys_filters</c>, <c>excl_sys_filters</c>,
+ <c>incl_app_filters</c> and <c>excl_app_filters</c>.</p>
</item>
- <tag><c><![CDATA[app_file]]></c></tag>
+ <tag><c>app_file</c></tag>
<item>
<p>This parameter controls the default handling of the
<c>app</c> files when a target system is generated. It
@@ -213,7 +213,7 @@
and <c>strip</c>.</p>
</item>
- <tag><c><![CDATA[debug_info]]></c></tag>
+ <tag><c>debug_info</c></tag>
<item>
<p>The <c>debug_info</c> parameter controls whether the debug
information in the beam file should be kept (<c>keep</c>) or
@@ -221,31 +221,31 @@
system.</p>
</item>
- <tag><c><![CDATA[incl_sys_filters]]></c></tag>
+ <tag><c>incl_sys_filters</c></tag>
<item>
<p>This parameter normally contains a list of regular
- expressions that controls which files in the system that
+ expressions that controls which files in the system
should be included. Each file in the target system must match
at least one of the listed regular expressions in order to be
included. Further the files may not match any filter in
<c>excl_sys_filters</c> in order to be included. Which
- application files that should be included are controlled with
+ application files should be included is controlled with
the parameters <c>incl_app_filters</c> and
<c>excl_app_filters</c>. This parameter defaults to
<c>[".*"]</c>.</p>
</item>
- <tag><c><![CDATA[excl_sys_filters]]></c></tag>
+ <tag><c>excl_sys_filters</c></tag>
<item>
<p>This parameter normally contains a list of regular
- expressions that controls which files in the system that not
- should be included in the target system. In order to be
+ expressions that controls which files in the system should
+ not be included in the target system. In order to be
included, a file must match some filter in
<c>incl_sys_filters</c> but not any filter in
<c>excl_sys_filters</c>. This parameter defaults to
<c>[]</c>.</p>
</item>
- <tag><c><![CDATA[incl_app_filters]]></c></tag>
+ <tag><c>incl_app_filters</c></tag>
<item>
<p>This parameter normally contains a list of regular
expressions that controls which application specific files
@@ -256,23 +256,23 @@
parameter defaults to <c>[".*"]</c>.</p>
</item>
- <tag><c><![CDATA[excl_app_filters]]></c></tag>
+ <tag><c>excl_app_filters</c></tag>
<item>
<p>This parameter normally contains a list of regular
expressions that controls which application specific files
- that not should be included in the target system. In order to
+ should not be included in the target system. In order to
be included, a file must match some filter in
<c>incl_app_filters</c> but not any filter in
<c>excl_app_filters</c>. This parameter defaults to
<c>[]</c>.</p>
</item>
- <tag><c><![CDATA[incl_archive_filters]]></c></tag>
+ <tag><c>incl_archive_filters</c></tag>
<item>
<p>This parameter normally contains a list of regular
expressions that controls which top level directories in an
- application that should be included in an archive file (as
- opposed of beeing included as a regular directory outside the
+ application should be included in an archive file (as
+ opposed to being included as a regular directory outside the
archive). Each top directory in the application must match at
least one of the listed regular expressions in order to be
included. Further the files may not match any filter in
@@ -280,122 +280,122 @@
parameter defaults to <c>[".*"]</c>.</p>
</item>
- <tag><c><![CDATA[excl_archive_filters]]></c></tag>
+ <tag><c>excl_archive_filters</c></tag>
<item>
<p>This parameter normally contains a list of regular
expressions that controls which top level directories in an
- application that not should be included in an archive file. In
+ application should not be included in an archive file. In
order to be included in the application archive, a top
directory must match some filter in <c>incl_archive_filters</c>
but not any filter in <c>excl_archive_filters</c>. This
parameter defaults to <c>["^include$","^priv$"]</c>.</p>
</item>
- <tag><c><![CDATA[archive_opts]]></c></tag>
+ <tag><c>archive_opts</c></tag>
<item>
<p>This parameter contains a list of options that are given to
<c>zip:create/3</c> when application specific files are
- packaged into an archive. All options are not supported. The
- most useful options in this context, are the ones that
- controls which types of files that should be compressed. This
+ packaged into an archive. Only a subset of the options are
+ supported. The most useful options in this context are the ones
+ that control which types of files should be compressed. This
parameter defaults to <c>[]</c>.</p>
</item>
</taglist>
- <p>On application (<c>escript</c>) level,the following options are
+ <p>On application (<c>escript</c>) level, the following options are
supported:</p>
<taglist>
- <tag><c><![CDATA[incl_cond]]></c></tag>
+ <tag><c>incl_cond</c></tag>
<item>
<p>The value of this parameter overrides the parameter with the
same name on system level.</p>
</item>
</taglist>
- <p>On application (<c>app</c>) level,the following options are
+ <p>On application (<c>app</c>) level, the following options are
supported:</p>
<taglist>
- <tag><c><![CDATA[vsn]]></c></tag>
+ <tag><c>vsn</c></tag>
<item>
<p>The version of the application. In an installed system there may
exist several versions of an application. The <c>vsn</c> parameter
- controls which version of the application that will be choosen. If it
- is omitted, the latest version will be choosen.</p>
+ controls which version of the application will be chosen. If it
+ is omitted, the latest version will be chosen.</p>
</item>
- <tag><c><![CDATA[mod]]></c></tag>
+ <tag><c>mod</c></tag>
<item>
<p>Module specific configuration. A module has a mandatory
name and module level options that are described below.</p>
</item>
- <tag><c><![CDATA[mod_cond]]></c></tag>
+ <tag><c>mod_cond</c></tag>
<item>
<p>The value of this parameter overrides the parameter with the
same name on system level.</p>
</item>
- <tag><c><![CDATA[incl_cond]]></c></tag>
+ <tag><c>incl_cond</c></tag>
<item>
<p>The value of this parameter overrides the parameter with the
same name on system level.</p>
</item>
- <tag><c><![CDATA[app_file]]></c></tag>
+ <tag><c>app_file</c></tag>
<item>
<p>The value of this parameter overrides the parameter with the
same name on system level.</p>
</item>
- <tag><c><![CDATA[debug_info]]></c></tag>
+ <tag><c>debug_info</c></tag>
<item>
<p>The value of this parameter overrides the parameter with the
same name on system level.</p>
</item>
- <tag><c><![CDATA[incl_app_filters]]></c></tag>
+ <tag><c>incl_app_filters</c></tag>
<item>
<p>The value of this parameter overrides the parameter with the
same name on system level.</p>
</item>
- <tag><c><![CDATA[excl_app_filters]]></c></tag>
+ <tag><c>excl_app_filters</c></tag>
<item>
<p>The value of this parameter overrides the parameter with the
same name on system level.</p>
</item>
- <tag><c><![CDATA[incl_archive_filters]]></c></tag>
+ <tag><c>incl_archive_filters</c></tag>
<item>
<p>The value of this parameter overrides the parameter with the
same name on system level.</p>
</item>
- <tag><c><![CDATA[excl_archive_filters]]></c></tag>
+ <tag><c>excl_archive_filters</c></tag>
<item>
<p>The value of this parameter overrides the parameter with the
same name on system level.</p>
</item>
- <tag><c><![CDATA[archive_opts]]></c></tag>
+ <tag><c>archive_opts</c></tag>
<item>
<p>The value of this parameter overrides the parameter with the
same name on system level.</p>
</item>
</taglist>
- <p>On module (<c>mod</c>) level,the following options are
+ <p>On module (<c>mod</c>) level, the following options are
supported:</p>
<taglist>
- <tag><c><![CDATA[incl_cond]]></c></tag>
+ <tag><c>incl_cond</c></tag>
<item>
- <p>This parameter controls whether the module is included or not. By
- default the <c>mod_incl</c> parameter on application and system level
- will be used to control whether the module is included or not. The
- value of <c>incl_cond</c> overrides the module inclusion policy.
- <c>include</c> implies that the module is included, while
- <c>exclude</c> implies that the module not is included.
- <c>derived</c> implies that the is included if any included uses the
- module.</p>
+ <p>This parameter controls whether the module is included or not. By
+ default the <c>mod_incl</c> parameter on application and system level
+ will be used to control whether the module is included or not. The
+ value of <c>incl_cond</c> overrides the module inclusion policy.
+ <c>include</c> implies that the module is included, while
+ <c>exclude</c> implies that the module is not included.
+ <c>derived</c> implies that the module is included if it is used
+ by any other included module.</p>
</item>
- <tag><c><![CDATA[debug_info]]></c></tag>
+ <tag><c>debug_info</c></tag>
<item>
<p>The value of this parameter overrides the parameter with
the same name on application level.</p>
@@ -477,7 +477,9 @@ mod_name() = atom()
profile() = development | embedded | standalone
re_regexp() = string()
reason() = string()
-regexps() = [re_regexp()] | {add, [re_regexp()]} | {del, [re_regexp()]}
+regexps() = [re_regexp()]
+ | {add, [re_regexp()]}
+ | {del, [re_regexp()]}
rel_file() = term()
rel_name() = string()
rel_vsn() = string()
@@ -487,7 +489,19 @@ script_file() = term()
server() = server_pid() | options()
server_pid() = pid()
target_dir() = file()
-window_pid() = pid()]]></code>
+window_pid() = pid()
+base_dir() = dir()
+base_file() = file()
+top_dir() = file()
+top_file() = file()
+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()]}
+ | {copy_file, base_file()}
+ | {copy_file, base_file(), top_file()}
+ | {write_file, base_file(), iolist()}
+ | {strip_beam_file, base_file()}]]></code>
<marker id="start"></marker>
</section>
@@ -497,9 +511,9 @@ window_pid() = pid()]]></code>
<name>create_target(Server, TargetDir) -> ok | {error, Reason}</name>
<fsummary>Create a target system</fsummary>
<type>
- <v>Server = server()</v>
+ <v>Server = server()</v>
<v>TargetDir = target_dir()</v>
- <v>Reason = reason()</v>
+ <v>Reason = reason()</v>
</type>
<desc><p>Create a target system. Gives the same result as
<c>{ok,TargetSpec}=reltool:get_target_spec(Server)</c> and
@@ -532,12 +546,12 @@ window_pid() = pid()]]></code>
files are by default copied to the target system. The
<c>releases</c> directory contains generated <c>rel</c>,
<c>script</c>, and <c>boot</c> files. The <c>lib</c> directory
- contains the applications. Which applications that are included
+ contains the applications. Which applications are included
and if they should be customized (archived, stripped from debug
info etc.) is specified with various configuration
parameters. The files in the <c>bin</c> directory are copied
from the <c>erts-vsn/bin</c> directory, but only those files
- that was originally included in <c>bin</c> directory of the
+ that were originally included in the <c>bin</c> directory of the
source system.</p>
<p>If the configuration parameter <c>relocatable</c> was set to
@@ -570,10 +584,10 @@ window_pid() = pid()]]></code>
<v>Reason = reason()</v>
</type>
<desc><p>Get reltool configuration. Normally, only the explicit
- configuration parameters with values that differs from their
+ configuration parameters with values that differ from their
defaults are interesting. But the builtin default values can be
returned by setting <c>InclDefaults</c> to <c>true</c>. The
- derived configuration can be return by setting
+ derived configuration can be returned by setting
<c>InclDerived</c> to <c>true</c>.</p></desc>
</func>
@@ -604,6 +618,17 @@ window_pid() = pid()]]></code>
</func>
<func>
+ <name>get_status(Server) -> {ok, [Warning]} | {error, Reason}</name>
+ <fsummary>Get contents of a release file</fsummary>
+ <type>
+ <v>Server = server()</v>
+ <v>Warning = string()</v>
+ <v>Reason = reason()</v>
+ </type>
+ <desc><p>Get status about the configuration</p></desc>
+ </func>
+
+ <func>
<name>get_server(WindowPid) -> {ok, ServerPid} | {error, Reason}</name>
<fsummary>Start server process with options</fsummary>
<type>
@@ -680,7 +705,7 @@ window_pid() = pid()]]></code>
<v>Reason = reason()</v>
</type>
<desc><p>Start a server process with options. The server process
- identity can be given as argument to several other functions in the
+ identity can be given as an argument to several other functions in the
API.</p></desc>
</func>
diff --git a/lib/reltool/doc/src/reltool_examples.xml b/lib/reltool/doc/src/reltool_examples.xml
index d6db246f6c..19a3f37819 100644
--- a/lib/reltool/doc/src/reltool_examples.xml
+++ b/lib/reltool/doc/src/reltool_examples.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2009</year>
- <year>2009</year>
+ <year>2011</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -249,11 +249,11 @@ Eshell V5.7.3 (abort with ^G)
<pre>
5&gt; {ok, Server} = reltool:start_server([{config, {sys, [{boot_rel, "NAME"},
{rel, "NAME", "VSN",
- [kernel, stdlib, sasl]}]}}]).
+ [sasl]}]}}]).
{ok,&lt;0.1288.0&gt;}
6&gt; reltool:get_config(Server).
{ok,{sys,[{boot_rel,"NAME"},
- {rel,"NAME","VSN",[kernel,stdlib,sasl]}]}}
+ {rel,"NAME","VSN",[sasl]}]}}
7&gt; reltool:get_rel(Server, "NAME").
{ok,{release,{"NAME","VSN"},
{erts,"5.7"},
diff --git a/lib/reltool/doc/src/reltool_usage.xml b/lib/reltool/doc/src/reltool_usage.xml
index 885828d1f0..d128e80a77 100644
--- a/lib/reltool/doc/src/reltool_usage.xml
+++ b/lib/reltool/doc/src/reltool_usage.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2009</year>
- <year>2009</year>
+ <year>2011</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -44,7 +44,7 @@
<section>
<title>System window</title>
<p>The system window is started with the function
- <c>reltool:start/1</c>. At startup the tool will process the all
+ <c>reltool:start/1</c>. At startup the tool will process all
<c>beam</c> files and <c>app</c> files in order to find out dependencies
between applications and their modules. Once all this information has been
derived, it will be possible to explore the tool.</p>
@@ -67,29 +67,29 @@
<section>
<title>Libraries</title>
<p>On the library page it is possible to control which sources
- that the tool will use. The page is organized as a tree which
+ the tool will use. The page is organized as a tree which
can be expanded and collapsed by clicking on the little symbol
in the beginning of the expandable/collapsible lines.</p>
<p>The <c>Root directory</c> can be edited by selecting the
line where the path of the root directory is displayed and
- clicking with the right mouse button. Choose edit in the menu
- that pops up. </p>
+ clicking the right mouse button. Choose edit in the menu
+ that pops up.</p>
<p>Library directories can be added, edited or deleted. This
is done by selecting the line where the path to a library
- directory is displayed and clicking with the right mouse
+ directory is displayed and clicking the right mouse
button. Choose add, edit or delete in the menu that pops
up. New library directories can also be added by selecting the
- line <c>Library directories</c> and clicking with the right
+ line <c>Library directories</c> and clicking the right
mouse button. Choose add in the menu that pops up.</p>
<p>Escript files can be added, edited or deleted. This is done
by selecting the line where the path to an escript file is
- displayed and clicking with the right mouse button. Choose
+ displayed and clicking the right mouse button. Choose
add, edit or delete in the menu that pops up. New escripts can
also be added by selecting the line <c>Escript files</c> and
- clicking with the right mouse button. Choose add in the menu
+ clicking the right mouse button. Choose add in the menu
that pops up.</p>
<p>When libraries and escripts are expanded, the names of
@@ -102,7 +102,7 @@
<p>On the system settings page it is possible to control some
global settings that are used as defaults for all
applications. Set the <c>Application inclusion policy</c> to
- <c>include</c> to include all applications that not are
+ <c>include</c> to include all applications that are not
explicitly excluded. See <c>incl_cond</c> (application
inclusion) and <c>mod_cond</c> (module inclusion) in the
reference manual for the module <c>reltool</c> for more
@@ -131,14 +131,14 @@
<p>The symbols in front of the application names are intended
to describe the status of the application. There are error
- symbols and warning symbols that means that there are
- something that needs attention. The tick symbol means that the
+ and warning symbols to signalize that there is
+ something which needs attention. The tick symbol means that the
application is included or derived and no problem has been
detected. The cross symbol means that the application is
excluded or available and no problem has been
detected. Applications with error symbols are listed first in
- each category, then comes the warnings and the normal ones
- (ticks and crosses) are found at the end.</p>
+ each category and are followed by the warnings and the
+ normal ones (ticks and crosses) at the end.</p>
<p>Double click on an application to launch its application
window.</p>
@@ -175,8 +175,8 @@
</item>
<item>
<p><c>Save configuration</c> - Saves the current
- configuration to file. Normally, only the explictit
- configuration parameters with values that differs from their
+ configuration to file. Normally, only the explicit
+ configuration parameters with values that differ from their
defaults are saved. But the configuration with or without
default values and with or without derived values may also
be saved.</p>
@@ -204,21 +204,21 @@
<p>It is possible to perform some limited manipulations of the
graph. Nodes can be moved, selected, locked or deleted. Move a
single node or the entire graph by moving the mouse while the
- left mouse button is pressed. A node is can be locked into a fix
+ left mouse button is pressed. A node can be locked into a fix
position by holding down the shift button when the left mouse
button is released. Select several nodes by moving the mouse
- while the control key and the left mouse button i
+ while the control key and the left mouse button are
pressed. Selected nodes can be locked, unlocked or deleted by
- klicking on a suitable button.</p>
+ clicking on a suitable button.</p>
<p>The algorithm that is used to draw a graph with as few
crossed links as possible is called force graph. A force graph
- consists of nodes and directed link between nodes. Each node is
+ consists of nodes and directed links between nodes. Each node is
associated with a repulsive force that pushes nodes away from
each other. This force can be adjusted with the left slider or
with the mouse wheel. Each link is associated with an attractive
- force that pulls the nodes nearer each other. This force can be
- adjusted with the right slider. If this force becomes to strong,
+ force that pulls the nodes nearer to each other. This force can be
+ adjusted with the right slider. If this force becomes too strong,
the graph will be unstable. The third parameter that can be
adjusted is the length of the links. It is adjusted with the
middle slider.</p>
@@ -256,7 +256,7 @@
<p>Select version of the application in the <c>Source selection
policy</c> part of the page. By default the latest version of the
application is selected, but it is possible to override this by
- explicitly select another version.</p>
+ explicitly selecting another version.</p>
<p>By default the <c>Application inclusion policy</c> on system
level is used for all applications. Set the value to
@@ -272,10 +272,10 @@
want actually used modules to be included. Set it to <c>app</c> if
you, besides derived modules, also want the modules listed in the
app file to be included. Set it to <c>ebin</c> if you, besides
- derived modules, also want the modules that exists as beam files
- on the ebin directory to be included. Set it to <c>all</c> if you
+ derived modules, also want the modules that exist as beam files
+ in the ebin directory to be included. Set it to <c>all</c> if you
want all modules to be included, that is the union of modules
- found on the ebin directory and listed in the app file.</p>
+ found in the ebin directory and listed in the app file.</p>
<p>The application settings page is rather incomplete.</p>
</section>
@@ -299,16 +299,16 @@
undone.</p>
<p>The symbols in front of the module names are intended to
- describe the status of the module. There are error symbols
- and warning symbols that means that there are something that needs
+ describe the status of the module. There are error and
+ and warning symbols to signalize that there is something that needs
attention. The tick symbol means that the module is included
or derived and no problem has been detected. The cross symbol
means that the module is excluded or available and no problem
has been detected. Modules with error symbols are listed
- first in each category, then comes the warnings and the normal
- ones (ticks and crosses) are found at the end.</p>
+ first in each category and are followed by warnings and the
+ normal ones (ticks and crosses) at the end.</p>
- <p>Double click on an module to launch its module window.</p>
+ <p>Double click on a module to launch its module window.</p>
</section>
@@ -323,7 +323,7 @@
<c>app</c> file. If the application includes other applications,
these are listed under <c>Included</c>. These applications are
listed in the <c>included_applications</c> part of the <c>app</c>
- file. If the application uses modules other applications, these
+ file. If the application uses other applications, these
are listed under <c>Uses</c>.</p>
<p>Double click on an application name to launch an application window.</p>
@@ -336,7 +336,7 @@
<p>There are two categories of modules on the <c>Module
dependencies</c> page. If the module is used by other modules,
these are listed under <c>Modules used by others</c>. If the
- module uses modules other modules, these are listed under <c>Used
+ module uses other modules, these are listed under <c>Used
modules</c>.</p>
<p>Double click on an module name to launch a module window.</p>
@@ -365,8 +365,8 @@
<p>There are two categories of modules on the <c>Dependencies</c>
page. If the module is used by other modules, these are listed
- under <c>Modules used by others</c>. If the module uses modules
- other modules, these are listed under <c>Used modules</c>.</p>
+ under <c>Modules used by others</c>. If the module uses other
+ modules, these are listed under <c>Used modules</c>.</p>
<p>Double click on an module name to launch a module window.</p>
@@ -378,7 +378,7 @@
<p>On the <c>Code</c> page the Erlang source code is displayed. It
is possible to search forwards and backwards for text in the
module. Enter a regular expression in the <c>Find</c> field and
- press enter. It is also possible to goto a certain line on the
+ press enter. It is also possible to go to a certain line in the
module. The <c>Back</c> button can be used to go back to the
previous position.</p>
diff --git a/lib/reltool/src/Makefile b/lib/reltool/src/Makefile
index fa24efbb8c..4e6a112b7e 100644
--- a/lib/reltool/src/Makefile
+++ b/lib/reltool/src/Makefile
@@ -1,19 +1,19 @@
#
# %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%
include $(ERL_TOP)/make/target.mk
@@ -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
# ----------------------------------------------------
@@ -85,7 +92,7 @@ $(TARGET_FILES): $(HRL_FILES) $(INTERNAL_HRL_FILES)
# ----------------------------------------------------
# Release Target
-# ----------------------------------------------------
+# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
@@ -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..4188f341f1 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-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%
%%
+%% %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,
+ reltool_app_win,
+ 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 e6548bfe68..54eb1ca9e1 100644
--- a/lib/reltool/src/reltool.erl
+++ b/lib/reltool/src/reltool.erl
@@ -1,170 +1,66 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2009-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%
-module(reltool).
%% 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,
+ create_target/2, get_target_spec/1, eval_target_spec/3,
install/2
]).
--type file() :: string().
--type dir() :: string().
--type mod_cond() :: all | app | ebin | derived | none.
--type incl_cond() :: include | exclude | derived.
--type debug_info() :: keep | strip.
--type app_file() :: keep | strip | all.
--type re_regexp() :: string().
--type regexps() :: [re_regexp()] | {add, [re_regexp()]} | {del, [re_regexp()]} .
--type incl_sys_filters() :: regexps().
--type excl_sys_filters() :: regexps().
--type incl_app_filters() :: regexps().
--type excl_app_filters() :: regexps().
--type incl_archive_filters() :: regexps().
--type excl_archive_filters() :: regexps().
--type archive_opt() :: term().
--type root_dir() :: dir().
--type lib_dir() :: dir().
--type profile() :: development | embedded | standalone.
--type relocatable() :: boolean().
--type escript_file() :: file().
--type mod_name() :: atom().
--type app_name() :: atom().
--type app_vsn() :: string().
--type app_type() :: permanent | transient | temporary | load | none.
--type incl_app() :: app_name().
--type rel_name() :: string().
--type rel_vsn() :: string().
--type boot_rel() :: rel_name().
--type rel_app() :: app_name()
- | {app_name(), app_type()}
- | {app_name(), [incl_app()]}
- | {app_name(), app_type(), [incl_app()]}.
--type mod() :: {incl_cond, incl_cond()}
- | {debug_info, debug_info()}.
--type app() :: {vsn, app_vsn()}
- | {mod, mod_name(), mod()}
- | {mod_cond, mod_cond()}
- | {incl_cond, incl_cond()}
- | {app_file, app_file()}
- | {debug_info, debug_info()}
- | {incl_app_filters, incl_app_filters()}
- | {excl_app_filters, excl_app_filters()}
- | {incl_archive_filters, incl_archive_filters()}
- | {excl_archive_filters, excl_archive_filters()}.
--type escript() :: {incl_cond, incl_cond()}.
--type sys() :: {mod_cond, mod_cond()}
- | {incl_cond, incl_cond()}
- | {debug_info, debug_info()}
- | {app_file, app_file()}
- | {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()]}
- | {root_dir, root_dir()}
- | {lib_dirs, [lib_dir()]}
- | {boot_rel, boot_rel()}
- | {rel, rel_name(), rel_vsn(), [rel_app()]}
- | {relocatable, relocatable()}
- | {erts, app()}
- | {escript, escript_file(), [escript()]}
- | {app, app_name(), [app()]}.
--type config() :: {sys, [sys()]}.
--type option() :: {wx_debug, term()} | {trap_exit, boolean()} | config() | {config, config() | file()}.
--type options() :: [option()].
--type server_pid() :: pid().
--type window_pid() :: pid().
--type server() :: server_pid() | options().
--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().
-%%-type top_file() :: file().
-%%-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()]}
-%% | {copy_file, base_file()}
-%% | {copy_file, base_file(), top_file()}
-%% | {write_file, base_file(), iolist()}
-%% | {strip_beam_file, base_file()}.
--type target_spec() :: term().
--type target_dir() :: dir().
--type incl_defaults() :: boolean().
--type incl_derived() :: boolean().
+-include("reltool.hrl").
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% 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()}}.
-start(Options)when is_list(Options) ->
- {ok, WinPid} = start_link(Options),
- unlink(WinPid),
- {ok, WinPid}.
+-spec start(options()) -> {ok, window_pid()} | {error, reason()}.
+start(Options) when is_list(Options) ->
+ case start_link(Options) of
+ {ok, WinPid} = OK ->
+ unlink(WinPid),
+ OK;
+ {error, _Reason} = Error ->
+ Error
+ 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()}}.
+-spec start_link(options()) -> {ok, window_pid()} | {error, reason()}.
start_link(Options) when is_list(Options) ->
case reltool_sys_win:start_link(Options) of
- {ok, WinPid} ->
- {ok, WinPid};
+ {ok, _WinPid} = OK ->
+ OK;
{error, Reason} ->
{error, lists:flatten(io_lib:format("~p", [Reason]))}
- end.
+ end.
%% Start server process with options
-spec start_server(options()) -> {ok, server_pid()} | {error, reason()}.
@@ -180,8 +76,8 @@ start_server(Options) ->
-spec get_server(window_pid()) -> {ok, server_pid()} | {error, reason()}.
get_server(WinPid) ->
case reltool_sys_win:get_server(WinPid) of
- {ok, ServerPid} ->
- {ok, ServerPid};
+ {ok, _ServerPid} = OK ->
+ OK;
{error, Reason} ->
{error, lists:flatten(io_lib:format("~p", [Reason]))}
end.
@@ -200,51 +96,93 @@ stop(Pid) when is_pid(Pid) ->
end.
%% Internal library function
--spec eval_server(server(), fun((server_pid()) -> term())) -> {ok, server_pid()} | {error, reason()}.
-eval_server(Pid, Fun) when is_pid(Pid) ->
+-spec eval_server(server(), boolean(), fun((server_pid()) -> Ret)) ->
+ Ret | {error, reason()} when Ret :: term().
+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 ->
+ Error
+ 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} = Error ->
+ stop(Pid),
+ Error
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) ->
get_config(PidOrOption, false, false).
--spec get_config(server(), incl_defaults(), incl_derived()) -> {ok, config()} | {error, reason()}.
-get_config(PidOrOptions, InclDefaults, InclDerived) when is_pid(PidOrOptions); is_list(PidOrOptions) ->
- eval_server(PidOrOptions, fun(Pid) -> reltool_server:get_config(Pid, InclDefaults, InclDerived) end).
+-spec get_config(server(), incl_defaults(), incl_derived()) ->
+ {ok, config()} | {error, reason()}.
+get_config(PidOrOptions, InclDef, InclDeriv)
+ when is_pid(PidOrOptions); is_list(PidOrOptions) ->
+ eval_server(PidOrOptions, true,
+ fun(Pid) ->
+ reltool_server:get_config(Pid, InclDef, InclDeriv)
+ end).
%% Get contents of release file
-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, fun(Pid) -> reltool_server:get_rel(Pid, RelName) end).
+get_rel(PidOrOptions, RelName)
+ when is_pid(PidOrOptions); is_list(PidOrOptions) ->
+ eval_server(PidOrOptions, true,
+ fun(Pid) -> reltool_server:get_rel(Pid, RelName) end).
%% Get contents of boot script file
--spec get_script(server(), rel_name()) -> {ok, script_file()} | {error, reason()}.
-get_script(PidOrOptions, RelName) when is_pid(PidOrOptions); is_list(PidOrOptions) ->
- eval_server(PidOrOptions, fun(Pid) -> reltool_server:get_script(Pid, RelName) end).
+-spec get_script(server(), rel_name()) ->
+ {ok, script_file()} | {error, reason()}.
+get_script(PidOrOptions, RelName)
+ when is_pid(PidOrOptions); is_list(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, fun(Pid) -> reltool_server:gen_target(Pid, TargetDir) end).
+create_target(PidOrOptions, TargetDir)
+ when is_pid(PidOrOptions); is_list(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).
+get_target_spec(PidOrOptions)
+ when is_pid(PidOrOptions); is_list(PidOrOptions) ->
+ 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()) -> ok | {error, reason()}.
-eval_target_spec(Spec, SourceDir, TargetDir) when is_list(SourceDir), is_list(TargetDir) ->
+-spec eval_target_spec(target_spec(), root_dir(), target_dir()) ->
+ ok | {error, reason()}.
+eval_target_spec(Spec, SourceDir, TargetDir)
+ when is_list(SourceDir), is_list(TargetDir) ->
reltool_target:eval_spec(Spec, SourceDir, TargetDir).
%% Install a target system
diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl
index 736daab0f0..93f47f6381 100644
--- a/lib/reltool/src/reltool.hrl
+++ b/lib/reltool/src/reltool.hrl
@@ -1,152 +1,251 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2009-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%
--define(APPLICATION, reltool).
--define(MISSING_APP, '*MISSING*').
+-define(APPLICATION, reltool).
+-define(MISSING_APP_NAME, '*MISSING*').
-define(MISSING_APP_TEXT, "*MISSING*").
--record(common,
- {
- sys_debug, % term()
- wx_debug, % term()
- trap_exit, % bool()
- app_tab, % ets_tab()
- mod_tab, % ets_tab()
- mod_used_by_tab % ets_tab()
- }).
+-type file() :: file:filename().
+-type dir() :: file:filename().
+%% app - Include all modules in app file
+%% ebin - Include all modules on ebin directory
+%% derived - Include only those modules that others are dependent on
+-type mod_cond() :: all | app | ebin | derived | none.
+-type incl_cond() :: include | exclude | derived.
+-type debug_info() :: keep | strip.
+-type app_file() :: keep | strip | all.
+-type re_regexp() :: string(). % re:regexp()
+-type regexps() :: [re_regexp()] |
+ {add, [re_regexp()]} |
+ {del, [re_regexp()]} .
+-type incl_sys_filters() :: regexps().
+-type excl_sys_filters() :: regexps().
+-type incl_app_filters() :: regexps().
+-type excl_app_filters() :: regexps().
+-type incl_archive_filters() :: regexps().
+-type excl_archive_filters() :: regexps().
+-type archive_opt() :: term(). % zip:create()
+-type root_dir() :: dir().
+-type lib_dir() :: dir().
+-type profile() :: development | embedded | standalone.
+-type relocatable() :: boolean().
+-type escript_file() :: file().
+-type mod_name() :: atom().
+-type app_name() :: atom().
+-type app_vsn() :: string(). % e.g. "4.7"
+-type app_label() :: string(). % e.g. "mnesia" or "mnesia-4.7"
+-type app_type() :: permanent | transient | temporary | load | none.
+-type incl_app() :: app_name().
+-type emu_name() :: string().
+-type rel_name() :: string().
+-type rel_vsn() :: string().
+-type boot_rel() :: rel_name().
+-type rel_app() :: app_name()
+ | {app_name(), app_type()}
+ | {app_name(), [incl_app()]}
+ | {app_name(), app_type(), [incl_app()]}.
+-type mod() :: {incl_cond, incl_cond()}
+ | {debug_info, debug_info()}.
+-type app() :: {vsn, app_vsn()}
+ | {mod, mod_name(), mod()}
+ | {mod_cond, mod_cond()}
+ | {incl_cond, incl_cond()}
+ | {app_file, app_file()}
+ | {debug_info, debug_info()}
+ | {incl_app_filters, incl_app_filters()}
+ | {excl_app_filters, excl_app_filters()}
+ | {incl_archive_filters, incl_archive_filters()}
+ | {excl_archive_filters, excl_archive_filters()}.
+-type escript() :: {incl_cond, incl_cond()}.
+-type sys() :: {mod_cond, mod_cond()}
+ | {incl_cond, incl_cond()}
+ | {debug_info, debug_info()}
+ | {app_file, app_file()}
+ | {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()]}
+ | {root_dir, root_dir()}
+ | {lib_dirs, [lib_dir()]}
+ | {boot_rel, boot_rel()}
+ | {rel, rel_name(), rel_vsn(), [rel_app()]}
+ | {relocatable, relocatable()}
+ | {erts, app()}
+ | {escript, escript_file(), [escript()]}
+ | {app, app_name(), [app()]}.
+-type config() :: {sys, [sys()]}.
+-type option() :: {wx_debug, term()}
+ | {trap_exit, boolean()}
+ | config()
+ | {config, config() | file()}.
+-type options() :: [option()].
+-type server_pid() :: pid().
+-type window_pid() :: pid().
+-type server() :: server_pid() | options().
+-type rel_file() :: term().
+-type script_file() :: term().
+-type reason() :: string().
--record(sys,
+-type base_dir() :: dir().
+-type base_file() :: file().
+-type top_dir() :: file().
+-type top_file() :: file().
+-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()]}
+ | {copy_file, base_file()}
+ | {copy_file, base_file(), top_file()}
+ | {write_file, base_file(), iolist()}
+ | {strip_beam_file, base_file()}.
+-type target_dir() :: dir().
+-type incl_defaults() :: boolean().
+-type incl_derived() :: boolean().
+-type status() :: missing | ok.
+
+-record(common,
{
- %% Sources
- root_dir, % directory()
- lib_dirs, % [directory()]
- escripts, % [file()]
- mod_cond, % all | app | ebin | derived | none
- incl_cond, % include | exclude | derived
- apps, % [#app{}]
+ sys_debug :: term(),
+ wx_debug :: term(),
+ trap_exit :: boolean(),
+ app_tab :: ets:tab(),
+ mod_tab :: ets:tab(),
+ mod_used_by_tab :: ets:tab()
+ }).
- %% Target cond
- boot_rel, % string()
- rels, % [#rel{}]
- emu_name, % string()
- profile, % standalone | development | embedded
- incl_sys_filters, % [regexp()]
- excl_sys_filters, % [regexp()]
- incl_app_filters, % [regexp()]
- excl_app_filters, % [regexp()]
- incl_archive_filters, % [regexp()]
- excl_archive_filters, % [regexp()]
- archive_opts, % [zip:create()]
- relocatable, % bool()
- app_type, % permanent | transient | temporary | load | none
- app_file, % keep | strip | all
- debug_info % keep | strip
- }).
+-record(mod,
+ { %% Static
+ 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(),
+ %% Dynamic
+ status :: status(),
+ used_by_mods :: [mod_name()],
+ is_pre_included :: boolean() | undefined,
+ is_included :: boolean() | undefined
+ }).
--record(rel,
+-record(app_info,
{
- name, % string()
- vsn, % string()
- rel_apps % [#rel_app{}]
- }).
+ 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(rel_app,
- {
- name, % atom()
- app_type, % permanent | transient | temporary | load | none
- incl_apps % [atom()]
- }).
+-record(regexp, {source, compiled}).
-record(app,
- {%% Static info
- name, % atom()
- is_escript, % bool()
- use_selected_vsn,% bool() | undefined
- active_dir, % dir_name()
- sorted_dirs, % [dir_name()]
- vsn, % string() e.g. "4.7"
- label, % string() e.g. "mnesia" or "mnesia-4.7"
- info, % #app_info{} | undefined
- mods, % [#mod{}]
+ { %% Static info
+ 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{}],
%% Static source cond
- mod_cond, % all | app | ebin | derived | none | undefined
- incl_cond, % include | exclude | derived | undefined
+ mod_cond :: mod_cond() | undefined,
+ incl_cond :: incl_cond() | undefined,
%% Static target cond
- debug_info, % keep | strip | undefined
- app_file, % keep | strip | all | undefined
- app_type, % permanent | transient | temporary | load | none
- incl_app_filters, % [regexp()]
- excl_app_filters, % [regexp()]
- incl_archive_filters, % [regexp()]
- excl_archive_filters, % [regexp()]
- archive_opts, % [zip_create_opt()]
+ debug_info :: debug_info() | undefined,
+ app_file :: app_file() | undefined,
+ app_type :: app_type() | undefined,
+ incl_app_filters :: [#regexp{}],
+ excl_app_filters :: [#regexp{}],
+ incl_archive_filters :: [#regexp{}],
+ excl_archive_filters :: [#regexp{}],
+ archive_opts :: [archive_opt()],
%% Dynamic
- status, % missing | ok
- uses_mods, % [atom()]
- used_by_mods, % [atom()]
- uses_apps, % [atom()]
- used_by_apps, % [atom()]
- is_pre_included, % bool()
- is_included % bool()
- }).
-
--record(mod,
- {%% Static
- name, % atom()
- app_name, % atom()
- incl_cond, % include | exclude | derived | undefined
- debug_info, % keep | strip | undefined
- is_app_mod, % bool(),
- is_ebin_mod, % bool(),
- uses_mods, % [module()]
- exists, % bool()
- %% Dynamic
- status, % missing | ok
- used_by_mods, % [atom()]
- is_pre_included, % bool() | undefined
- is_included % bool() | undefined
- }).
+ 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(),
+ rels :: [rel_name()]
+ }).
-%% app - Include all modules in app file
-%% ebin - Include all modules on ebin directory
-%% derived - Include only those modules that others are dependent on
+-record(rel_app,
+ {
+ name :: app_name(),
+ app_type :: app_type() | undefined,
+ incl_apps = [] :: [incl_app()]
+ }).
--record(app_info,
+-record(rel,
{
- description = "",
- id = "",
- vsn = "",
- modules = [],
- maxP = infinity,
- maxT = infinity,
- registered = [],
- incl_apps = [],
- applications = [],
- env = [],
- mod = undefined,
- start_phases = undefined
- }).
+ name :: rel_name(),
+ vsn :: rel_vsn(),
+ rel_apps :: [#rel_app{}]
+ }).
+
+-record(sys,
+ { %% Sources
+ root_dir :: dir(),
+ lib_dirs :: [dir()],
+ escripts :: [file()],
+ mod_cond :: mod_cond(),
+ incl_cond :: incl_cond(),
+ apps :: [#app{}],
+
+ %% Target cond
+ boot_rel :: boot_rel(),
+ rels :: [#rel{}],
+ emu_name :: emu_name(),
+ profile :: profile(),
+ incl_sys_filters :: [#regexp{}],
+ excl_sys_filters :: [#regexp{}],
+ incl_app_filters :: [#regexp{}],
+ excl_app_filters :: [#regexp{}],
+ incl_archive_filters :: [#regexp{}],
+ excl_archive_filters :: [#regexp{}],
+ 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}).
-
-define(ERR_IMAGE, 0).
-define(WARN_IMAGE, 1).
-define(QUEST_IMAGE, 2).
@@ -165,38 +264,42 @@
-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).
-define(DEFAULT_INCL_ARCHIVE_FILTERS, [".*"]).
--define(DEFAULT_EXCL_ARCHIVE_FILTERS, ["^include$", "^priv$"]).
--define(DEFAULT_ARCHIVE_OPTS, []).
+-define(DEFAULT_EXCL_ARCHIVE_FILTERS, ["^include\$", "^priv\$"]).
+-define(DEFAULT_ARCHIVE_OPTS, []).
-define(DEFAULT_INCL_SYS_FILTERS, [".*"]).
-define(DEFAULT_EXCL_SYS_FILTERS, []).
-define(DEFAULT_INCL_APP_FILTERS, [".*"]).
-define(DEFAULT_EXCL_APP_FILTERS, []).
--define(EMBEDDED_INCL_SYS_FILTERS, ["^bin",
- "^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_SYS_FILTERS, ["^bin",
+ "^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$"]).
--define(STANDALONE_EXCL_SYS_FILTERS, ["^erts.*/bin/(erlc|dialyzer|typer)(|\\.exe)$",
- "^erts.*/bin/(start|escript|to_erl|run_erl)(|\\.exe)$",
- "^erts.*/bin/.*(debug|pdb)"]).
--define(STANDALONE_INCL_APP_FILTERS, ["^ebin",
- "^priv"]).
--define(STANDALONE_EXCL_APP_FILTERS, ["^ebin/.*\\.appup$"]).
+-define(STANDALONE_INCL_SYS_FILTERS, ["^bin/(erl|epmd)(|\\.exe|\\.ini)\$",
+ "^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)\$",
+ "^erts.*/bin/.*(debug|pdb)"]).
+-define(STANDALONE_INCL_APP_FILTERS, ["^ebin",
+ "^priv"]).
+-define(STANDALONE_EXCL_APP_FILTERS, ["^ebin/.*\\.appup\$"]).
diff --git a/lib/reltool/src/reltool_app_win.erl b/lib/reltool/src/reltool_app_win.erl
index 6083493c02..70bd72b258 100644
--- a/lib/reltool/src/reltool_app_win.erl
+++ b/lib/reltool/src/reltool_app_win.erl
@@ -1,19 +1,19 @@
%%
%% %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%
-module(reltool_app_win).
@@ -34,7 +34,7 @@
-include_lib("wx/include/wx.hrl").
-include("reltool.hrl").
--record(state,
+-record(state,
{parent_pid,
xref_pid,
mod_wins,
@@ -63,7 +63,7 @@
%% -define(APPS_APP_COL_WIDTH, 250).
-define(CLOSE_ITEM, ?wxID_EXIT). %% Use OS specific version if available
--define(ABOUT_ITEM, ?wxID_ABOUT). %% Use OS specific
+-define(ABOUT_ITEM, ?wxID_ABOUT). %% Use OS specific
-define(CONTENTS_ITEM, 300).
-define(MODS_MOD_COL, 0).
@@ -79,7 +79,11 @@
%% Client
start_link(WxEnv, Xref, Common, AppName) ->
- proc_lib:start_link(?MODULE, init, [self(), WxEnv, Xref, Common, AppName], infinity, []).
+ proc_lib:start_link(?MODULE,
+ init,
+ [self(), WxEnv, Xref, Common, AppName],
+ infinity,
+ []).
raise(Pid) ->
reltool_utils:cast(Pid, raise).
@@ -121,7 +125,12 @@ loop(#state{xref_pid = Xref, common = C, app = App} = S) ->
receive
{system, From, Msg} ->
Dbg = C#common.sys_debug,
- sys:handle_system_msg(Msg, From, S#state.parent_pid, ?MODULE, Dbg, S);
+ sys:handle_system_msg(Msg,
+ From,
+ S#state.parent_pid,
+ ?MODULE,
+ Dbg,
+ S);
{cast, _From, raise} ->
wxFrame:raise(S#state.frame),
wxFrame:setFocus(S#state.frame),
@@ -131,7 +140,8 @@ loop(#state{xref_pid = Xref, common = C, app = App} = S) ->
{ok, App2} ->
{ok, Sys} = reltool_server:get_sys(Xref),
S2 = redraw_window(S#state{sys = Sys, app = App2}),
- [ok = reltool_mod_win:refresh(MW#mod_win.pid) || MW <- S2#state.mod_wins],
+ [ok = reltool_mod_win:refresh(MW#mod_win.pid) ||
+ MW <- S2#state.mod_wins],
?MODULE:loop(S2);
{error, _Reason} ->
wxFrame:destroy(S#state.frame),
@@ -139,7 +149,8 @@ loop(#state{xref_pid = Xref, common = C, app = App} = S) ->
end;
{call, ReplyTo, Ref, {open_mod, ModName}} ->
S2 = create_mod_window(S, ModName),
- {value, #mod_win{pid = ModPid}} = lists:keysearch(ModName, #mod_win.name, S2#state.mod_wins),
+ {value, #mod_win{pid = ModPid}} =
+ lists:keysearch(ModName, #mod_win.name, S2#state.mod_wins),
reltool_utils:reply(ReplyTo, Ref, {ok, ModPid}),
?MODULE:loop(S2);
#wx{event = #wxSize{}} = Wx ->
@@ -157,7 +168,9 @@ loop(#state{xref_pid = Xref, common = C, app = App} = S) ->
exit(Reason);
{'EXIT', Pid, _Reason} = Exit ->
exit_warning(Exit),
- S2 = S#state{mod_wins = lists:keydelete(Pid, #mod_win.pid, S#state.mod_wins)},
+ S2 = S#state{mod_wins = lists:keydelete(Pid,
+ #mod_win.pid,
+ S#state.mod_wins)},
?MODULE:loop(S2);
Msg ->
error_logger:format("~p~p got unexpected message:\n\t~p\n",
@@ -179,7 +192,7 @@ create_window(#state{app = App} = S) ->
StatusBar = wxFrame:createStatusBar(Frame,[]),
Book = wxNotebook:new(Panel, ?wxID_ANY, []),
-
+
S2 = S#state{frame = Frame,
panel = Panel,
book = Book,
@@ -210,12 +223,16 @@ create_apps_page(S, Derived) ->
Lower = wxBoxSizer:new(?wxHORIZONTAL),
UsedByCtrl = create_apps_list_ctrl(Panel, Upper, "Used by"),
- wxSizer:add(Upper, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]),
-
+ wxSizer:add(Upper,
+ wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]),
+ [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]),
+
RequiredCtrl = create_apps_list_ctrl(Panel, Upper, "Required"),
- wxSizer:add(Upper, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]),
+ wxSizer:add(Upper, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]),
+ [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]),
InclCtrl = create_apps_list_ctrl(Panel, Upper, "Included"),
- wxSizer:add(Upper, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]),
+ wxSizer:add(Upper, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]),
+ [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]),
UsesCtrl = create_apps_list_ctrl(Panel, Upper, "Uses"),
S2 = S#state{app_required_ctrl = RequiredCtrl,
app_used_by_ctrl = UsedByCtrl,
@@ -262,8 +279,10 @@ create_apps_list_ctrl(Panel, Sizer, Text) ->
[{border, 2},
{flag, ?wxALL bor ?wxEXPAND},
{proportion, 1}]),
- wxEvtHandler:connect(ListCtrl, size, [{skip, true}, {userData, apps_list_ctrl}]),
- wxListCtrl:connect(ListCtrl, command_list_item_activated, [{userData, open_app}]),
+ wxEvtHandler:connect(ListCtrl, size,
+ [{skip, true}, {userData, apps_list_ctrl}]),
+ wxListCtrl:connect(ListCtrl, command_list_item_activated,
+ [{userData, open_app}]),
wxWindow:connect(ListCtrl, enter_window),
ListCtrl.
@@ -271,9 +290,20 @@ create_deps_page(S, Derived) ->
Panel = wxPanel:new(S#state.book, []),
Main = wxBoxSizer:new(?wxHORIZONTAL),
- UsedByCtrl = create_mods_list_ctrl(Panel, Main, "Modules used by others", " and their applications", undefined, undefined),
- wxSizer:add(Main, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]),
- UsesCtrl = create_mods_list_ctrl(Panel, Main, "Used modules", " and their applications", undefined, undefined),
+ UsedByCtrl = create_mods_list_ctrl(Panel,
+ Main,
+ "Modules used by others",
+ " and their applications",
+ undefined,
+ undefined),
+ wxSizer:add(Main, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]),
+ [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]),
+ UsesCtrl = create_mods_list_ctrl(Panel,
+ Main,
+ "Used modules",
+ " and their applications",
+ undefined,
+ undefined),
S2 = S#state{deps_used_by_ctrl = UsedByCtrl,
deps_uses_ctrl = UsesCtrl},
redraw_mods(S2, Derived),
@@ -285,13 +315,36 @@ create_mods_page(S, Derived) ->
Panel = wxPanel:new(S#state.book, []),
MainSz = wxBoxSizer:new(?wxHORIZONTAL),
- SourceCtrl = create_mods_list_ctrl(Panel, MainSz, ?source, "", whitelist_add, blacklist_add),
- wxSizer:add(MainSz, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]),
- WhiteCtrl = create_mods_list_ctrl(Panel, MainSz, ?whitelist, "", whitelist_del, blacklist_add),
- wxSizer:add(MainSz, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]),
- BlackCtrl = create_mods_list_ctrl(Panel, MainSz, ?blacklist, "", whitelist_add, blacklist_del),
- wxSizer:add(MainSz, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]),
- DerivedCtrl = create_mods_list_ctrl(Panel, MainSz, ?derived, "", whitelist_add, blacklist_add),
+ SourceCtrl = create_mods_list_ctrl(Panel,
+ MainSz,
+ ?source,
+ "",
+ whitelist_add,
+ blacklist_add),
+ wxSizer:add(MainSz, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]),
+ [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]),
+ WhiteCtrl = create_mods_list_ctrl(Panel,
+ MainSz,
+ ?whitelist,
+ "",
+ whitelist_del,
+ blacklist_add),
+ wxSizer:add(MainSz, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]),
+ [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]),
+ BlackCtrl = create_mods_list_ctrl(Panel,
+ MainSz,
+ ?blacklist,
+ "",
+ whitelist_add,
+ blacklist_del),
+ wxSizer:add(MainSz, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]),
+ [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]),
+ DerivedCtrl = create_mods_list_ctrl(Panel,
+ MainSz,
+ ?derived,
+ "",
+ whitelist_add,
+ blacklist_add),
S2 = S#state{mods_source_ctrl = SourceCtrl,
mods_white_ctrl = WhiteCtrl,
mods_black_ctrl = BlackCtrl,
@@ -309,7 +362,8 @@ create_mods_list_ctrl(Panel, OuterSz, Title, AppText, Tick, Cross) ->
%% ?wxLC_SINGLE_SEL bor
?wxHSCROLL bor
?wxVSCROLL}]),
- ToolTip = "Select module(s) or open separate module window with a double click.",
+ ToolTip = "Select module(s) or open separate module "
+ "window with a double click.",
wxListCtrl:setToolTip(ListCtrl, ToolTip),
%% Prep images
@@ -326,7 +380,8 @@ create_mods_list_ctrl(Panel, OuterSz, Title, AppText, Tick, Cross) ->
true ->
wxListItem:setText(ListItem, AppText),
wxListCtrl:insertColumn(ListCtrl, ?MODS_APP_COL, ListItem),
- %% wxListCtrl:setColumnWidth(ListCtrl, ?MODS_APP_COL, ?MODS_APP_COL_WIDTH),
+ %% wxListCtrl:setColumnWidth(ListCtrl, ?MODS_APP_COL,
+ %% ?MODS_APP_COL_WIDTH),
2;
false ->
1
@@ -336,9 +391,11 @@ create_mods_list_ctrl(Panel, OuterSz, Title, AppText, Tick, Cross) ->
ButtonSz = wxBoxSizer:new(?wxHORIZONTAL),
create_button(Panel, ButtonSz, ListCtrl, Title, "wxART_TICK_MARK", Tick),
create_button(Panel, ButtonSz, ListCtrl, Title, "wxART_CROSS_MARK", Cross),
- wxEvtHandler:connect(ListCtrl, size, [{skip, true}, {userData, mods_list_ctrl}]),
- wxListCtrl:connect(ListCtrl, command_list_item_activated, [{userData, open_mod}]),
- wxWindow:connect(ListCtrl, enter_window),
+ wxEvtHandler:connect(ListCtrl, size,
+ [{skip, true}, {userData, mods_list_ctrl}]),
+ wxListCtrl:connect(ListCtrl, command_list_item_activated,
+ [{userData, open_mod}]),
+ wxWindow:connect(ListCtrl, enter_window),
InnerSz = wxBoxSizer:new(?wxVERTICAL),
wxSizer:add(InnerSz, ListCtrl,
[{border, 2},
@@ -377,7 +434,7 @@ action_to_tool_tip(Label, Action) ->
"Remove selected module(s)from whitelist.";
blacklist_add when Label =:= ?blacklist ->
"Remove selected module(s) from blacklist.";
- blacklist_add ->
+ blacklist_add ->
"Add selected module(s) to blacklist.";
blacklist_del ->
"Remove selected module(s) from blacklist."
@@ -444,8 +501,8 @@ create_config_page(#state{app = App} = S) ->
wxNotebook:addPage(S2#state.book, Panel, "Application settings", []),
S2.
-create_double_box(Panel, Sizer, TopLabel,
- OuterText, OuterData,
+create_double_box(Panel, Sizer, TopLabel,
+ OuterText, OuterData,
InnerText, InnerData,
InternalLabel, InternalChoices, InternalChoiceData) ->
TopSizer = wxStaticBoxSizer:new(?wxVERTICAL, Panel,
@@ -457,10 +514,10 @@ create_double_box(Panel, Sizer, TopLabel,
[{userData, OuterData}]),
InnerRadio = wxRadioButton:new(Panel, ?wxID_ANY, InnerText),
wxEvtHandler:connect(InnerRadio, command_radiobutton_selected,
- [{userData, InnerData}]),
- InnerBox = wxRadioBox:new(Panel,
+ [{userData, InnerData}]),
+ InnerBox = wxRadioBox:new(Panel,
?wxID_ANY,
- InternalLabel,
+ InternalLabel,
?wxDefaultPosition,
?wxDefaultSize,
InternalChoices,
@@ -487,29 +544,38 @@ handle_event(#state{sys = Sys, app = App} = S, Wx) ->
#wx{obj = ObjRef, event = #wxMouse{type = enter_window}} ->
wxWindow:setFocus(ObjRef),
S;
- #wx{obj= ListCtrl, userData = mods_list_ctrl, event = #wxSize{type = size, size = {W, _H}}} ->
+ #wx{obj= ListCtrl,
+ userData = mods_list_ctrl,
+ event = #wxSize{type = size, size = {W, _H}}} ->
HasApps = (wxListCtrl:getColumnCount(ListCtrl) > 1),
case HasApps of
false ->
wxListCtrl:setColumnWidth(ListCtrl, ?MODS_MOD_COL, W);
true ->
- wxListCtrl:setColumnWidth(ListCtrl, ?MODS_MOD_COL, (2 * W) div 3),
+ wxListCtrl:setColumnWidth(ListCtrl,
+ ?MODS_MOD_COL,
+ (2 * W) div 3),
wxListCtrl:setColumnWidth(ListCtrl, ?MODS_APP_COL, W div 3)
end,
S;
- #wx{obj= ListCtrl, userData = apps_list_ctrl, event = #wxSize{type = size, size = {W, _H}}} ->
+ #wx{obj = ListCtrl,
+ userData = apps_list_ctrl,
+ event = #wxSize{type = size, size = {W, _H}}} ->
wxListCtrl:setColumnWidth(ListCtrl, ?APPS_APP_COL, W),
S;
#wx{userData = open_app,
obj = ListCtrl,
- event = #wxList{type = command_list_item_activated, itemIndex = Pos}} ->
+ event = #wxList{type = command_list_item_activated,
+ itemIndex = Pos}} ->
AppBase = wxListCtrl:getItemText(ListCtrl, Pos),
{AppName, _AppVsn} = reltool_utils:split_app_name(AppBase),
- {ok, _AppPid} = reltool_sys_win:open_app(S#state.parent_pid, AppName),
+ {ok, _AppPid} = reltool_sys_win:open_app(S#state.parent_pid,
+ AppName),
S;
#wx{userData = open_mod,
obj = ListCtrl,
- event = #wxList{type = command_list_item_activated, itemIndex = Pos}} ->
+ event = #wxList{type = command_list_item_activated,
+ itemIndex = Pos}} ->
ModName = list_to_atom(wxListCtrl:getItemText(ListCtrl, Pos)),
create_mod_window(S, ModName);
#wx{userData = global_incl_cond} ->
@@ -560,16 +626,19 @@ handle_event(#state{sys = Sys, app = App} = S, Wx) ->
Items = reltool_utils:get_items(ListCtrl),
handle_mod_button(S, Items, Action);
_ ->
- error_logger:format("~p~p got unexpected app event from wx:\n\t~p\n",
+ error_logger:format("~p~p got unexpected app event from "
+ "wx:\n\t~p\n",
[?MODULE, self(), Wx]),
S
end.
-create_mod_window(#state{parent_pid = RelPid, xref_pid = Xref, common = C} = S, ModName) ->
+create_mod_window(#state{parent_pid = RelPid, xref_pid = Xref, common = C} = S,
+ ModName) ->
case lists:keysearch(ModName, #mod_win.name, S#state.mod_wins) of
false ->
WxEnv = wx:get_env(),
- {ok, Pid} = reltool_mod_win:start_link(WxEnv, Xref, RelPid, C, ModName),
+ {ok, Pid} =
+ reltool_mod_win:start_link(WxEnv, Xref, RelPid, C, ModName),
MW = #mod_win{name = ModName, pid = Pid},
S#state{mod_wins = [MW | S#state.mod_wins]};
{value, MW} ->
@@ -578,7 +647,9 @@ create_mod_window(#state{parent_pid = RelPid, xref_pid = Xref, common = C} = S,
end.
handle_mod_button(#state{app = App} = S, Items, Action) ->
- App2 = lists:foldl(fun(Item, A) -> move_mod(A, Item, Action) end, App, Items),
+ App2 = lists:foldl(fun(Item, A) -> move_mod(A, Item, Action) end,
+ App,
+ Items),
{ok, App3} = reltool_sys_win:set_app(S#state.parent_pid, App2),
S2 = S#state{app = App3},
redraw_window(S2).
@@ -587,7 +658,7 @@ move_mod(App, {_ItemNo, ModStr}, Action) ->
ModName = list_to_atom(ModStr),
Mods = App#app.mods,
{value, M} = lists:keysearch(ModName, #mod.name, Mods),
- AppCond =
+ AppCond =
case Action of
whitelist_add ->
case M#mod.incl_cond of
@@ -597,12 +668,13 @@ move_mod(App, {_ItemNo, ModStr}, Action) ->
end;
whitelist_del ->
undefined;
- blacklist_add ->
+ blacklist_add ->
exclude;
blacklist_del ->
undefined;
_ ->
- error_logger:format("~p~p got unexpected mod button event: ~p\n\t ~p\n",
+ error_logger:format("~p~p got unexpected mod "
+ "button event: ~p\n\t ~p\n",
[?MODULE, self(), ModName, Action]),
M#mod.incl_cond
end,
@@ -623,7 +695,10 @@ change_mod_cond(S, App, NewModCond) ->
redraw_window(S2).
change_version(S, App, NewDir) ->
- App2 = App#app{active_dir = NewDir, label = undefined, vsn = undefined, info = undefined},
+ App2 = App#app{active_dir = NewDir,
+ label = undefined,
+ vsn = undefined,
+ info = undefined},
{ok, App3} = reltool_sys_win:set_app(S#state.parent_pid, App2),
Title = app_title(App3),
wxFrame:setTitle(S#state.frame, Title),
@@ -635,8 +710,14 @@ redraw_apps(#state{app = #app{info = AppInfo},
app_incl_ctrl = InclCtrl,
app_uses_ctrl = UsesCtrl,
xref_pid = Xref},
- {_SourceMods, _WhiteMods, _BlackMods, _DerivedMods, UsedByMods, UsesMods}) ->
- UsedByApps = lists:usort([{M#mod.app_name, Image} || {Image, _, M} <- UsedByMods]),
+ {_SourceMods,
+ _WhiteMods,
+ _BlackMods,
+ _DerivedMods,
+ UsedByMods,
+ UsesMods}) ->
+ UsedByApps =
+ lists:usort([{M#mod.app_name, Image} || {Image, _, M} <- UsedByMods]),
Select =
fun(AppName) ->
{ok, App} = reltool_server:get_app(Xref, AppName),
@@ -647,7 +728,8 @@ redraw_apps(#state{app = #app{info = AppInfo},
end,
RequiredApps = lists:sort(lists:map(Select, AppInfo#app_info.applications)),
InclApps = lists:map(Select, AppInfo#app_info.incl_apps),
- UsesApps = lists:usort([{M#mod.app_name, Image} || {Image, _, M} <- UsesMods]),
+ UsesApps =
+ lists:usort([{M#mod.app_name, Image} || {Image, _, M} <- UsesMods]),
do_redraw_apps(UsedByCtrl, UsedByApps),
do_redraw_apps(RequiredCtrl, RequiredApps),
do_redraw_apps(InclCtrl, InclApps),
@@ -656,19 +738,26 @@ redraw_apps(#state{app = #app{info = AppInfo},
do_redraw_apps(ListCtrl, []) ->
wxListCtrl:deleteAllItems(ListCtrl);
- %% wxListCtrl:setColumnWidth(ListCtrl, ?APPS_APP_COL, ?wxLIST_AUTOSIZE_USEHEADER);
+ %% wxListCtrl:setColumnWidth(ListCtrl, ?APPS_APP_COL,
+%% ?wxLIST_AUTOSIZE_USEHEADER);
do_redraw_apps(ListCtrl, AppImages) ->
wxListCtrl:deleteAllItems(ListCtrl),
Add =
fun({AppName, ImageId}, {Row, Prev}) when AppName =/= Prev ->
- wxListCtrl:insertItem(ListCtrl, Row, ""),
- if (Row rem 2) =:= 0 ->
- wxListCtrl:setItemBackgroundColour(ListCtrl, Row, {240,240,255});
+ wxListCtrl:insertItem(ListCtrl, Row, ""),
+ if (Row rem 2) =:= 0 ->
+ wxListCtrl:setItemBackgroundColour(ListCtrl,
+ Row,
+ {240,240,255});
true ->
ignore
end,
Str = atom_to_list(AppName),
- wxListCtrl:setItem(ListCtrl, Row, ?APPS_APP_COL, Str, [{imageId, ImageId}]),
+ wxListCtrl:setItem(ListCtrl,
+ Row,
+ ?APPS_APP_COL,
+ Str,
+ [{imageId, ImageId}]),
{Row + 1, AppName};
({_, _}, Acc) ->
Acc
@@ -688,8 +777,13 @@ redraw_mods(#state{mods_source_ctrl = SourceCtrl,
deps_uses_ctrl = UsesCtrl,
app = #app{is_pre_included = IsPre, is_included = IsIncl},
status_bar = Bar},
- {SourceMods, WhiteMods, BlackMods, DerivedMods, UsedByMods, UsesMods}) ->
- InclStatus =
+ {SourceMods,
+ WhiteMods,
+ BlackMods,
+ DerivedMods,
+ UsedByMods,
+ UsesMods}) ->
+ InclStatus =
case IsIncl of
true when IsPre =:= true -> "Whitelist - ";
true -> "Derived - ";
@@ -711,7 +805,7 @@ app_to_mods(#state{xref_pid = Xref, app = App}) ->
SourceMods = [M || M <- App#app.mods,
M#mod.is_included =/= true,
M#mod.is_pre_included =/= false],
- WhiteMods = [M || M <- App#app.mods,
+ WhiteMods = [M || M <- App#app.mods,
M#mod.is_pre_included =:= true],
BlackMods = [M || M <- App#app.mods,
M#mod.is_pre_included =:= false],
@@ -722,7 +816,8 @@ app_to_mods(#state{xref_pid = Xref, app = App}) ->
fun(ModName) when is_atom(ModName) ->
{ok, M} = reltool_server:get_mod(Xref, ModName),
if
- M#mod.app_name =:= App#app.name, M#mod.is_included =:= true ->
+ M#mod.app_name =:= App#app.name,
+ M#mod.is_included =:= true ->
false;
true ->
{true, M}
@@ -780,20 +875,26 @@ opt_redraw_mods(undefined, _ImageMods) ->
opt_redraw_mods(ListCtrl, ImageMods) ->
HasApps = (wxListCtrl:getColumnCount(ListCtrl) > 1),
do_redraw_mods(ListCtrl, ImageMods, HasApps).
-
+
do_redraw_mods(ListCtrl, [], _HasApps) ->
wxListCtrl:deleteAllItems(ListCtrl);
do_redraw_mods(ListCtrl, ImageMods, HasApps) ->
wxListCtrl:deleteAllItems(ListCtrl),
Add =
fun({ImageId, AppName, #mod{name = ModName}}, Row) ->
- wxListCtrl:insertItem(ListCtrl, Row, ""),
- if (Row rem 2) =:= 0 ->
- wxListCtrl:setItemBackgroundColour(ListCtrl, Row, {240,240,255});
+ wxListCtrl:insertItem(ListCtrl, Row, ""),
+ if (Row rem 2) =:= 0 ->
+ wxListCtrl:setItemBackgroundColour(ListCtrl,
+ Row,
+ {240,240,255});
true ->
ignore
end,
- wxListCtrl:setItem(ListCtrl, Row, ?MODS_MOD_COL, atom_to_list(ModName), [{imageId, ImageId}]),
+ wxListCtrl:setItem(ListCtrl,
+ Row,
+ ?MODS_MOD_COL,
+ atom_to_list(ModName),
+ [{imageId, ImageId}]),
case HasApps of
false ->
ok;
@@ -842,13 +943,14 @@ redraw_config(#state{sys = #sys{incl_cond = GlobalIncl,
SelectedRadio,
SourceBox,
fun(true) ->
- reltool_utils:elem_to_index(ActiveDir, SortedDirs) - 1;
+ reltool_utils:elem_to_index(ActiveDir,
+ SortedDirs) - 1;
(false) ->
0
end).
redraw_double_box(Global, Local, GlobalRadio, LocalRadio, LocalBox, GetChoice) ->
- AppCond =
+ AppCond =
case Local of
undefined ->
wxRadioButton:setValue(GlobalRadio, true),
diff --git a/lib/reltool/src/reltool_fgraph.erl b/lib/reltool/src/reltool_fgraph.erl
index 09c4f8c8ce..2e8f39e418 100644
--- a/lib/reltool/src/reltool_fgraph.erl
+++ b/lib/reltool/src/reltool_fgraph.erl
@@ -1,19 +1,19 @@
%%
%% %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%
-module(reltool_fgraph).
@@ -80,7 +80,7 @@ foreach(Fun, Fg) ->
end, Fg),
Fg.
-map(Fun, Fg) ->
+map(Fun, Fg) ->
lists:foreach(fun
(Key) -> put(Key,Fun(get(Key)))
end, Fg),
@@ -105,7 +105,9 @@ step(Vs, Es) -> step(Vs, Es, {0,0}).
step(Vs, Es, Pa) ->
?MODULE:map(fun
(Node = {_, #fg_v{ type = static }}) -> Node;
- ({Key, Value = #fg_v{ p = {Px, Py}, v = {Vx, Vy}, type = dynamic}}) when is_float(Px), is_float(Py), is_float(Vx), is_float(Vy) ->
+ ({Key, Value = #fg_v{ p = {Px, Py}, v = {Vx, Vy}, type = dynamic}})
+ when is_float(Px), is_float(Py),
+ is_float(Vx), is_float(Vy) ->
F0 = {0.0,0.0},
F1 = coulomb_repulsion(Key, Value, Vs, F0),
F2 = hooke_attraction(Key, Value, Vs, Es, F1),
@@ -115,7 +117,7 @@ step(Vs, Es, Pa) ->
Vx1 = (Vx + ?fg_th*Fx)*?fg_damp,
Vy1 = (Vy + ?fg_th*Fy)*?fg_damp,
-
+
Px1 = Px + ?fg_th*Vx1,
Py1 = Py + ?fg_th*Vy1,
@@ -123,14 +125,16 @@ step(Vs, Es, Pa) ->
(Node) -> Node
end, Vs).
-point_attraction(_, #fg_v{ p = P0 }, Pa, {Fx, Fy}) when is_float(Fx), is_float(Fy) ->
+point_attraction(_, #fg_v{ p = P0 }, Pa, {Fx, Fy})
+ when is_float(Fx), is_float(Fy) ->
K = 20,
L = 150,
{R, {Cx,Cy}} = composition(P0, Pa),
F = -K*?fg_stretch*(R - L),
{Fx + Cx*F, Fy + Cy*F}.
-
-coulomb_repulsion(K0, #fg_v{ p = P0, q = Q0}, Vs, {Fx0, Fy0}) when is_float(Fx0), is_float(Fy0) ->
+
+coulomb_repulsion(K0, #fg_v{ p = P0, q = Q0}, Vs, {Fx0, Fy0})
+ when is_float(Fx0), is_float(Fy0) ->
?MODULE:foldl(fun
({K1, _}, F) when K1 == K0 -> F;
({_, #fg_v{ p = P1, q = Q1}}, {Fx, Fy}) ->
@@ -140,7 +144,8 @@ coulomb_repulsion(K0, #fg_v{ p = P0, q = Q0}, Vs, {Fx0, Fy0}) when is_float(Fx0)
(_, F) -> F
end, {Fx0, Fy0}, Vs).
-hooke_attraction(Key0, #fg_v{ p = P0 }, Vs, Es, {Fx0, Fy0}) when is_float(Fx0), is_float(Fy0) ->
+hooke_attraction(Key0, #fg_v{ p = P0 }, Vs, Es, {Fx0, Fy0})
+ when is_float(Fx0), is_float(Fy0) ->
?MODULE:foldl(fun
({{Key1,Key1}, _}, F) -> F;
({{Key1,Key2}, #fg_e{ l = L, k = K}}, {Fx, Fy}) when Key1 =:= Key0->
@@ -153,10 +158,11 @@ hooke_attraction(Key0, #fg_v{ p = P0 }, Vs, Es, {Fx0, Fy0}) when is_float(Fx0),
{R, {Cx,Cy}} = composition(P0, P1),
F = -K*?fg_stretch*(R - L),
{Fx + Cx*F, Fy + Cy*F};
- (_, F) -> F
+ (_, F) -> F
end, {Fx0, Fy0}, Es).
-composition({Px1, Py1}, {Px0, Py0}) when is_float(Px1), is_float(Py1), is_float(Px0), is_float(Py0) ->
+composition({Px1, Py1}, {Px0, Py0})
+ when is_float(Px1), is_float(Py1), is_float(Px0), is_float(Py0) ->
Dx = Px1 - Px0,
Dy = Py1 - Py0,
R = math:sqrt(Dx*Dx + Dy*Dy + 0.001),
diff --git a/lib/reltool/src/reltool_fgraph_win.erl b/lib/reltool/src/reltool_fgraph_win.erl
index b063fb94ba..b0deb1bab2 100644
--- a/lib/reltool/src/reltool_fgraph_win.erl
+++ b/lib/reltool/src/reltool_fgraph_win.erl
@@ -1,19 +1,19 @@
%%
%% %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%
-module(reltool_fgraph_win).
@@ -95,7 +95,7 @@ change_node(Pid, Key, Color) -> Pid ! {change_node, Key, Color}.
add_link(Pid, {FromKey, ToKey}) -> Pid ! {add_link, {FromKey, ToKey}}.
del_link(Pid, {FromKey, ToKey}) -> Pid ! {del_link, {FromKey, ToKey}}.
-stop(Pid, Reason) ->
+stop(Pid, Reason) ->
Ref = erlang:monitor(process, Pid),
Pid ! {stop, Reason},
receive
@@ -110,21 +110,24 @@ new(Parent, Options) ->
Me = self(),
Pid = spawn_link(fun() -> init([Parent, Me, Env, Options]) end),
receive {Pid, {?MODULE, Panel}} -> {Pid,Panel} end.
-
+
init([ParentWin, Pid, Env, Options]) ->
wx:set_env(Env),
-
+
BReset = wxButton:new(ParentWin, ?reset, [{label,"Reset"}]),
BFreeze = wxButton:new(ParentWin, ?freeze, [{label,"Freeze"}]),
BLock = wxButton:new(ParentWin, ?lock, [{label,"Lock"}]),
BUnlock = wxButton:new(ParentWin, ?unlock, [{label,"Unlock"}]),
BDelete = wxButton:new(ParentWin, ?delete, [{label,"Delete"}]),
- SQ = wxSlider:new(ParentWin, ?q_slider, ?default_q, 1, 500, [{style, ?wxVERTICAL}]),
- SL = wxSlider:new(ParentWin, ?l_slider, ?default_l, 1, 500, [{style, ?wxVERTICAL}]),
- SK = wxSlider:new(ParentWin, ?k_slider, ?default_k, 1, 500, [{style, ?wxVERTICAL}]),
+ SQ = wxSlider:new(ParentWin, ?q_slider, ?default_q, 1, 500,
+ [{style, ?wxVERTICAL}]),
+ SL = wxSlider:new(ParentWin, ?l_slider, ?default_l, 1, 500,
+ [{style, ?wxVERTICAL}]),
+ SK = wxSlider:new(ParentWin, ?k_slider, ?default_k, 1, 500,
+ [{style, ?wxVERTICAL}]),
Win = wxWindow:new(ParentWin, ?wxID_ANY, Options),
-
+
ButtonSizer = wxBoxSizer:new(?wxVERTICAL),
wxSizer:add(ButtonSizer, BReset),
wxSizer:add(ButtonSizer, BFreeze),
@@ -141,31 +144,34 @@ init([ParentWin, Pid, Env, Options]) ->
WindowSizer = wxBoxSizer:new(?wxHORIZONTAL),
wxSizer:add(WindowSizer, ButtonSizer, [{flag, ?wxEXPAND}, {proportion, 0}]),
wxSizer:add(WindowSizer, Win, [{flag, ?wxEXPAND}, {proportion, 1}]),
-
+
wxButton:setToolTip(BReset, "Remove selection and unlock all nodes."),
wxButton:setToolTip(BFreeze, "Start/stop redraw of screen."),
wxButton:setToolTip(BLock, "Lock all selected nodes."),
wxButton:setToolTip(BUnlock, "Unlock all selected nodes."),
wxButton:setToolTip(BDelete, "Delete all selected nodes."),
- wxButton:setToolTip(SQ, "Control repulsive force. This can also be controlled with the mouse wheel on the canvas."),
+ wxButton:setToolTip(SQ, "Control repulsive force. This can also be"
+ " controlled with the mouse wheel on the canvas."),
wxButton:setToolTip(SL, "Control link length."),
wxButton:setToolTip(SK, "Control attractive force. Use with care."),
- wxButton:setToolTip(Win,
- "Drag mouse while left mouse button is pressed to perform various operations. "
- "Combine with control key to select. Combine with shift key to lock single node."),
+ wxButton:setToolTip(Win,
+ "Drag mouse while left mouse button is pressed "
+ "to perform various operations. "
+ "Combine with control key to select. Combine "
+ "with shift key to lock single node."),
wxButton:connect(BReset, command_button_clicked),
wxButton:connect(BFreeze, command_button_clicked),
wxButton:connect(BLock, command_button_clicked),
wxButton:connect(BUnlock, command_button_clicked),
wxButton:connect(BDelete, command_button_clicked),
-
+
wxWindow:connect(SQ, command_slider_updated),
wxWindow:connect(SL, command_slider_updated),
wxWindow:connect(SK, command_slider_updated),
-
- wxWindow:connect(Win, enter_window),
+
+ wxWindow:connect(Win, enter_window),
wxWindow:connect(Win, move),
wxWindow:connect(Win, motion),
wxWindow:connect(Win, mousewheel),
@@ -174,7 +180,7 @@ init([ParentWin, Pid, Env, Options]) ->
wxWindow:connect(Win, left_up),
wxWindow:connect(Win, right_down),
wxWindow:connect(Win, paint, [{skip, true}]),
-
+
Pen = wxPen:new({0,0,0}, [{width, 3}]),
Font = wxFont:new(12, ?wxSWISS, ?wxNORMAL, ?wxNORMAL,[]),
Brush = wxBrush:new({0,0,0}),
@@ -182,13 +188,13 @@ init([ParentWin, Pid, Env, Options]) ->
Pid ! {self(), {?MODULE, WindowSizer}},
wxWindow:setFocus(Win), %% Get keyboard focus
-
+
Vs = reltool_fgraph:new(),
Es = reltool_fgraph:new(),
Me = self(),
Ticker = spawn_link(fun() -> ticker_init(Me) end),
-
+
loop( #state{ parent_pid = Pid,
q_slider = SQ,
l_slider = SL,
@@ -215,14 +221,17 @@ graph_add_node(Key, Color, G = #graph{ vs = Vs}) ->
M = 0.5, % mass
P = {float(450 + random:uniform(100)),
float(450 + random:uniform(100))},
- G#graph{ vs = reltool_fgraph:add(Key, #fg_v{ p = P, m = M, q = Q, color = Color}, Vs)}.
+ G#graph{ vs = reltool_fgraph:add(Key,
+ #fg_v{ p = P, m = M, q = Q, color = Color},
+ Vs)}.
graph_change_node(Key, Color, G) ->
case reltool_fgraph:get(Key, G#graph.vs) of
- undefined ->
+ undefined ->
G;
V ->
- G#graph{ vs = reltool_fgraph:set(Key, V#fg_v{ color = Color }, G#graph.vs)}
+ G#graph{ vs = reltool_fgraph:set(Key, V#fg_v{ color = Color },
+ G#graph.vs)}
end.
graph_del_node(Key, G = #graph{ vs = Vs0, es = Es0}) ->
@@ -231,7 +240,7 @@ graph_del_node(Key, G = #graph{ vs = Vs0, es = Es0}) ->
G#graph{ vs = Vs, es = Es }.
graph_add_link(Key0, Key1, G = #graph{ es = Es}) ->
- K = 60.0, % attractive force
+ K = 60.0, % attractive force
L = 5.0, % spring length
G#graph{ es = reltool_fgraph:add({Key0, Key1}, #fg_e{ k = K, l = L}, Es) }.
@@ -249,15 +258,17 @@ ticker_loop(Pid, Time) ->
D = timer:now_diff(T1, T0)/1000,
case round(40 - D) of
Ms when Ms < 0 ->
- %io:format("ticker: wait is 0 ms [fg ~7s ms] [fps ~7s]~n", [s(D), s(1000/D)]),
+ %io:format("ticker: wait is 0 ms [fg ~7s ms] [fps ~7s]~n",
+ % [s(D), s(1000/D)]),
ticker_loop(Pid, 0);
Ms ->
- %io:format("ticker: wait is ~3s ms [fg ~7s ms] [fps ~7s]~n", [s(Ms), s(D), s(1000/40)]),
+ %io:format("ticker: wait is ~3s ms [fg ~7s ms] [fps ~7s]~n",
+ % [s(Ms), s(D), s(1000/40)]),
ticker_loop(Pid, Ms)
end
end.
-delete_edges(Es, []) ->
+delete_edges(Es, []) ->
Es;
delete_edges(Es, [Key|Keys]) ->
Edges = reltool_fgraph:foldl(fun
@@ -269,7 +280,7 @@ delete_edges(Es, [Key|Keys]) ->
(K, Esi) -> reltool_fgraph:del(K, Esi)
end, Es, Edges),
delete_edges(Es1, Keys).
-
+
set_charge(Q, Vs) -> % Repulsive force
F = fun({Key, Value}) -> {Key, Value#fg_v{ q = Q}} end,
@@ -295,36 +306,47 @@ loop(S, G) ->
wxSlider:setValue(S#state.k_slider, K),
Es = set_length(L, G#graph.es),
Es2 = set_spring(K, Es),
-
- Vs2 = reltool_fgraph:map(fun({Key, V}) ->
- {Key, V#fg_v{selected = false, type = dynamic, q = Q}}
- end,
- G#graph.vs),
-
- {Xs, Ys} = reltool_fgraph:foldl(fun({_Key, #fg_v{p = {X, Y}}}, {Xs, Ys}) ->
- {[X| Xs], [Y | Ys]}
- end,
- {[], []},
- Vs2),
+
+ Vs2 =
+ reltool_fgraph:map(fun({Key, V}) ->
+ {Key, V#fg_v{selected = false,
+ type = dynamic,
+ q = Q}}
+ end,
+ G#graph.vs),
+
+ {Xs, Ys} =
+ reltool_fgraph:foldl(fun({_Key,
+ #fg_v{p = {X, Y}}}, {Xs, Ys}) ->
+ {[X| Xs], [Y | Ys]}
+ end,
+ {[], []},
+ Vs2),
%% io:format("Before: ~p\n", [G#graph.offset]),
Offset =
case length(Xs) of
0 ->
{0, 0};
N ->
- MeanX = (lists:sum(Xs) / N),
+ MeanX = (lists:sum(Xs) / N),
MeanY = (lists:sum(Ys) / N),
{SizeX, SizeY} = wxWindow:getSize(S#state.window),
- %% io:format("Min: ~p\n", [{lists:min(Xs), lists:min(Ys)}]),
- %% io:format("Mean: ~p\n", [{MeanX, MeanY}]),
- %% io:format("Max: ~p\n", [{lists:max(Xs), lists:max(Ys)}]),
+ %% io:format("Min: ~p\n",
+ %% [{lists:min(Xs), lists:min(Ys)}]),
+ %% io:format("Mean: ~p\n",
+ %% [{MeanX, MeanY}]),
+ %% io:format("Max: ~p\n",
+ %% [{lists:max(Xs), lists:max(Ys)}]),
%% io:format("Size: ~p\n", [{SizeX, SizeY}]),
%% {XM - (XS / 2), YM - (YS / 2)}
%% {0 - lists:min(Xs) + 20, 0 - lists:min(Ys) + 20}
{0 - MeanX + (SizeX / 2), 0 - MeanY + (SizeY / 2)}
end,
%% io:format("After: ~p\n", [Offset]),
- loop(S, G#graph{vs = Vs2, es = Es2, offset = Offset, offset_state = false});
+ loop(S, G#graph{vs = Vs2,
+ es = Es2,
+ offset = Offset,
+ offset_state = false});
#wx{id = ?freeze, event = #wxCommand{type=command_button_clicked}} ->
%% Start/stop redraw of screen
IsFrozen =
@@ -354,10 +376,15 @@ loop(S, G) ->
loop(S, G#graph{ vs = Vs });
#wx{id = ?delete, event = #wxCommand{type=command_button_clicked}} ->
%% Delete all selected nodes
- {Vs1, Keys} = reltool_fgraph:foldl(fun
- ({Key, #fg_v{ selected = true}}, {Vs, Ks}) ->
- {reltool_fgraph:del(Key,Vs), [Key|Ks]};
- (_, {Vs, Ks}) -> {Vs, Ks}
+ {Vs1, Keys} =
+ reltool_fgraph:foldl(fun
+ ({Key,
+ #fg_v{ selected = true}},
+ {Vs, Ks}) ->
+ {reltool_fgraph:del(Key,Vs),
+ [Key|Ks]};
+ (_, {Vs, Ks}) ->
+ {Vs, Ks}
end, {G#graph.vs,[]}, G#graph.vs),
Es = delete_edges(G#graph.es, Keys),
loop(S, G#graph{ vs = Vs1, es = Es});
@@ -368,20 +395,26 @@ loop(S, G) ->
#wx{id = ?move, event = #wxCommand{type=command_button_clicked}} ->
loop(S#state{ mouse_act = ?move }, G);
- #wx{id = ?q_slider, event = #wxCommand{type=command_slider_updated, commandInt = Q}} ->
+ #wx{id = ?q_slider, event = #wxCommand{type=command_slider_updated,
+ commandInt = Q}} ->
loop(S, G#graph{ vs = set_charge(Q, G#graph.vs)});
- #wx{id = ?l_slider, event = #wxCommand{type=command_slider_updated, commandInt = L}} ->
+ #wx{id = ?l_slider, event = #wxCommand{type=command_slider_updated,
+ commandInt = L}} ->
loop(S, G#graph{ es = set_length(L, G#graph.es)});
- #wx{id = ?k_slider, event = #wxCommand{type=command_slider_updated, commandInt = K}} ->
+ #wx{id = ?k_slider, event = #wxCommand{type=command_slider_updated,
+ commandInt = K}} ->
loop(S, G#graph{ es = set_spring(K, G#graph.es)});
#wx{event=#wxKey{type=key_up, keyCode = 127}} -> % delete
{Vs1, Keys} =
- reltool_fgraph:foldl(fun({Key, #fg_v{ selected = true}}, {Vs, Ks}) ->
- {reltool_fgraph:del(Key,Vs), [Key|Ks]};
- (_, {Vs, Ks}) ->
- {Vs, Ks}
- end,
- {G#graph.vs,[]}, G#graph.vs),
+ reltool_fgraph:foldl(fun({Key,
+ #fg_v{ selected = true}},
+ {Vs, Ks}) ->
+ {reltool_fgraph:del(Key,Vs),
+ [Key|Ks]};
+ (_, {Vs, Ks}) ->
+ {Vs, Ks}
+ end,
+ {G#graph.vs,[]}, G#graph.vs),
Es = delete_edges(G#graph.es, Keys),
loop(S, G#graph{ vs = Vs1, es = Es});
#wx{event=#wxKey{type=key_up}} ->
@@ -390,7 +423,11 @@ loop(S, G) ->
loop(S, G);
%% mouse
- #wx{event=#wxMouse{type=left_down, shiftDown=Shift, controlDown=Ctrl, x=X, y=Y}} ->
+ #wx{event=#wxMouse{type=left_down,
+ shiftDown=Shift,
+ controlDown=Ctrl,
+ x=X,
+ y=Y}} ->
if
Shift ->
loop(S, mouse_left_down_move(G, {X,Y}));
@@ -401,7 +438,11 @@ loop(S, G) ->
S#state.mouse_act =:= ?select ->
loop(S, mouse_left_down_select(G, {X,Y}))
end;
- #wx{event=#wxMouse{type=motion, shiftDown=Shift, controlDown=Ctrl, x=X, y=Y}} ->
+ #wx{event=#wxMouse{type=motion,
+ shiftDown=Shift,
+ controlDown=Ctrl,
+ x=X,
+ y=Y}} ->
if
Shift ->
loop(S, mouse_motion_move(G, {X,Y}));
@@ -412,7 +453,9 @@ loop(S, G) ->
S#state.mouse_act =:= ?select ->
loop(S, mouse_motion_select(G, {X,Y}))
end;
- #wx{event=#wxMouse{type=left_up, shiftDown=Shift, controlDown=Ctrl, x=X, y=Y}} ->
+ #wx{event=#wxMouse{type=left_up,
+ shiftDown=Shift,
+ controlDown=Ctrl, x=X, y=Y}} ->
if
Shift ->
loop(S, mouse_left_up_move(G, {X,Y}, Shift));
@@ -424,7 +467,7 @@ loop(S, G) ->
loop(S, mouse_left_up_select(G, {X,Y}))
end;
- #wx{event=#wxMouse{type=right_down,x=_X,y=_Y}} ->
+ #wx{event=#wxMouse{type=right_down,x=_X,y=_Y}} ->
loop(S, G);
%% mouse wheel
#wx{event=#wxMouse{type=mousewheel, wheelRotation=Rotation}} ->
@@ -436,7 +479,7 @@ loop(S, G) ->
Rotation < 0 ->
wxSlider:setValue(S#state.q_slider, Q + 4),
loop(S, G#graph{ vs = set_charge(Q + 4, G#graph.vs) });
- true ->
+ true ->
loop(S, G)
end;
@@ -448,7 +491,7 @@ loop(S, G) ->
redraw(S, G),
loop(S, G);
#wx{obj=Win,event=#wxMouse{type=enter_window}} ->
- wxWindow:setFocus(Win),
+ wxWindow:setFocus(Win),
loop(S, G);
%% Graph manipulation
@@ -465,9 +508,11 @@ loop(S, G) ->
{Req, redraw} ->
{SizeX, SizeY} = wxWindow:getSize(S#state.window),
- Vs = reltool_fgraph:step(G#graph.vs, G#graph.es, {SizeX/2.0 - 20.0, SizeY/2.0}),
+ Vs = reltool_fgraph:step(G#graph.vs,
+ G#graph.es,
+ {SizeX/2.0 - 20.0, SizeY/2.0}),
case S#state.is_frozen of
- false ->
+ false ->
Req ! {self(), ok};
true ->
ignore
@@ -481,7 +526,7 @@ loop(S, G) ->
Other ->
error_logger:format("~p~p got unexpected message:\n\t~p\n",
- [?MODULE, self(), Other]),
+ [?MODULE, self(), Other]),
loop(S, G)
end.
@@ -494,17 +539,22 @@ mouse_left_down_move(#graph{vs = Vs} = G, {X, Y}) ->
false ->
G#graph{ offset_state = {X,Y}};
{true, Key} ->
- V = #fg_v{ type = Type} = reltool_fgraph:get(Key, Vs),
- G#graph{ vs = reltool_fgraph:set(Key, V#fg_v{ type = moving}, Vs), select = {node, Key, Type, X, Y} }
+ V = #fg_v{ type = Type} = reltool_fgraph:get(Key, Vs),
+ G#graph{ vs = reltool_fgraph:set(Key,
+ V#fg_v{ type = moving}, Vs),
+ select = {node, Key, Type, X, Y} }
end.
coord_to_key(#graph{vs = Vs, offset = {Xo, Yo}}, {X, Y}) ->
Xr = X - Xo,
Yr = Y - Yo,
- reltool_fgraph:foldl(fun({Key, #fg_v{ p = {Px, Py}}}, _) when abs(Px - Xr) < 10,
- abs(Py - Yr) < 10 -> {true, Key};
- (_, Out) -> Out
- end, false, Vs).
+ reltool_fgraph:foldl(fun({Key, #fg_v{ p = {Px, Py}}}, _)
+ when abs(Px - Xr) < 10,
+ abs(Py - Yr) < 10 ->
+ {true, Key};
+ (_, Out) ->
+ Out
+ end, false, Vs).
mouse_left_up_select(G, {_X,_Y}) ->
case G#graph.select of
@@ -524,7 +574,7 @@ mouse_left_up_select(G, {_X,_Y}) ->
_ ->
G#graph{ select = none}
end.
-
+
mouse_left_up_move(G = #graph{ select = Select, vs = Vs} = G, {X,Y}, Shift) ->
case Select of
{node, Key, _, X, Y} ->
@@ -543,7 +593,7 @@ mouse_left_up_move(G = #graph{ select = Select, vs = Vs} = G, {X,Y}, Shift) ->
_ ->
G#graph{ select = none, offset_state = false }
end.
-
+
mouse_motion_select(G, {X,Y}) ->
case G#graph.select of
{P0, _P1} -> G#graph{ select = {P0, {X,Y}}};
@@ -557,11 +607,11 @@ mouse_motion_move(G = #graph{ select = {node, Key, _, _, _}, vs = Vs}, {X,Y}) ->
G#graph{ vs = reltool_fgraph:set(Key, V2, Vs) };
mouse_motion_move(G, {X,Y}) ->
case G#graph.offset_state of
- {X1,Y1} ->
+ {X1,Y1} ->
{X0, Y0} = G#graph.offset,
G#graph{ offset_state = {X,Y},
offset = {X0 - (X1 - X), Y0 - (Y1 - Y)} };
- _ ->
+ _ ->
G
end.
@@ -574,9 +624,9 @@ redraw(#state{window=Win}, G) ->
wxClientDC:destroy(DC0),
ok.
-redraw(DC, _Size, G) ->
- wx:batch(fun() ->
-
+redraw(DC, _Size, G) ->
+ wx:batch(fun() ->
+
Pen = G#graph.pen,
Font = G#graph.font,
Brush = G#graph.brush,
@@ -587,7 +637,7 @@ redraw(DC, _Size, G) ->
wxPen:setWidth(Pen, 1),
wxDC:clear(DC),
- % draw vertices and edges
+ % draw vertices and edges
wxPen:setColour(Pen, ?color_fg),
wxDC:setPen(DC,Pen),
@@ -602,7 +652,9 @@ redraw(DC, _Size, G) ->
% draw information text
wxFont:setWeight(Font,?wxNORMAL),
- draw_text(DC, reltool_fgraph:size(G#graph.vs), reltool_fgraph:size(G#graph.es), G#graph.ke),
+ draw_text(DC,
+ reltool_fgraph:'size'(G#graph.vs),
+ reltool_fgraph:'size'(G#graph.es), G#graph.ke),
ok
end).
@@ -612,14 +664,14 @@ draw_select_box(DC, {{X0,Y0}, {X1,Y1}}) ->
draw_line(DC, {X1,Y1}, {X0,Y1}, {0,0}),
draw_line(DC, {X0,Y0}, {X0,Y1}, {0,0}),
ok;
-draw_select_box(_DC, _) ->
+draw_select_box(_DC, _) ->
ok.
draw_es(DC, Vs, Es, Po, Pen, Brush) ->
reltool_fgraph:foreach(fun
({{K1, K2}, _}) ->
- #fg_v{ p = P1} = reltool_fgraph:get(K1, Vs),
- #fg_v{ p = P2} = reltool_fgraph:get(K2, Vs),
+ #fg_v{ p = P1} = reltool_fgraph:'get'(K1, Vs),
+ #fg_v{ p = P2} = reltool_fgraph:'get'(K2, Vs),
draw_arrow(DC, P1, P2, Po, Pen, Brush)
end, Es).
@@ -650,10 +702,15 @@ draw_arrow(DC, {X0,Y0}, {X1, Y1}, {X, Y}, Pen, Brush) ->
wxDC:drawPolygon(DC, Points, []).
draw_line(DC, {X0,Y0}, {X1, Y1}, {X, Y}) ->
- wxDC:drawLine(DC, {round(X0 + X), round(Y0 + Y)}, {round(X1 + X), round(Y1 + Y)}).
-
+ wxDC:drawLine(DC,
+ {round(X0 + X), round(Y0 + Y)},
+ {round(X1 + X), round(Y1 + Y)}).
+
draw_vs(DC, Vs, {Xo, Yo}, Pen, Brush) ->
- reltool_fgraph:foreach(fun({Key, #fg_v{ p ={X, Y}, color = Color, selected = Sel}}) ->
+ reltool_fgraph:foreach(fun({Key,
+ #fg_v{p ={X, Y},
+ color = Color,
+ selected = Sel}}) ->
String = s(Key),
case Sel of
true ->
@@ -661,35 +718,49 @@ draw_vs(DC, Vs, {Xo, Yo}, Pen, Brush) ->
wxBrush:setColour(Brush, ?color_bg),
wxDC:setPen(DC,Pen),
wxDC:setBrush(DC, Brush),
- SelProps = {round(X-12 + Xo), round(Y-12 + Yo), 24, 24},
- wxDC:drawRoundedRectangle(DC, SelProps, float(?ARC_R)),
+ SelProps = {round(X-12 + Xo),
+ round(Y-12 + Yo),
+ 24,
+ 24},
+ wxDC:drawRoundedRectangle(DC,
+ SelProps,
+ float(?ARC_R)),
ok;
false ->
ok
end,
case Color of
- default ->
+ default ->
wxPen:setColour(Pen, ?color_default),
- wxBrush:setColour(Brush, ?color_default_bg);
- alternate ->
- wxPen:setColour(Pen, ?color_alternate),
- wxBrush:setColour(Brush, ?color_alternate_bg);
+ wxBrush:setColour(Brush,
+ ?color_default_bg);
+ alternate ->
+ wxPen:setColour(Pen,
+ ?color_alternate),
+ wxBrush:setColour(Brush,
+ ?color_alternate_bg);
{FgColor, BgColor} ->
wxPen:setColour(Pen, FgColor),
- wxBrush:setColour(Brush, BgColor);
+ wxBrush:setColour(Brush, BgColor);
Color ->
wxPen:setColour(Pen, Color),
wxBrush:setColour(Brush, Color)
end,
wxDC:setPen(DC,Pen),
wxDC:setBrush(DC, Brush),
- NodeProps = {round(X-8 + Xo),round(Y-8 + Yo),17,17},
- wxDC:drawRoundedRectangle(DC, NodeProps, float(?ARC_R)),
- wxDC:drawText(DC, String, {round(X + Xo), round(Y + Yo)}),
+ NodeProps = {round(X-8 + Xo),
+ round(Y-8 + Yo),17,17},
+ wxDC:drawRoundedRectangle(DC,
+ NodeProps,
+ float(?ARC_R)),
+ wxDC:drawText(DC,
+ String,
+ {round(X + Xo),
+ round(Y + Yo)}),
ok;
(_) ->
ok
- end,
+ end,
Vs).
draw_text(DC, Nvs, Nes, _KE) ->
@@ -720,7 +791,7 @@ calc_point({X, Y}, Length, Radians) ->
%% %% Convert from an angle in radians to degrees
%% radians_to_degrees(Radians) ->
%% Radians * 180 / math:pi().
-%%
+%%
%% %% Convert from an angle in degrees to radians
%% degrees_to_radians(Degrees) ->
%% Degrees * math:pi() / 180.
diff --git a/lib/reltool/src/reltool_mod_win.erl b/lib/reltool/src/reltool_mod_win.erl
index c05f73cde8..e1c2fa5100 100644
--- a/lib/reltool/src/reltool_mod_win.erl
+++ b/lib/reltool/src/reltool_mod_win.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2009-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%
-module(reltool_mod_win).
@@ -34,7 +34,7 @@
-include_lib("wx/include/wx.hrl").
-include("reltool.hrl").
--record(state,
+-record(state,
{parent_pid,
xref_pid,
rel_pid,
@@ -73,7 +73,7 @@
-define(WIN_HEIGHT, 600).
-define(CLOSE_ITEM, ?wxID_EXIT). %% Use OS specific version if available
--define(ABOUT_ITEM, ?wxID_ABOUT). %% Use OS specific
+-define(ABOUT_ITEM, ?wxID_ABOUT). %% Use OS specific
-define(CONTENTS_ITEM, 300).
-define(SEARCH_ENTRY, 413).
-define(GOTO_ENTRY, 414).
@@ -87,7 +87,11 @@
%% Client
start_link(WxEnv, Xref, RelPid, Common, ModName) ->
- proc_lib:start_link(?MODULE, init, [self(), WxEnv, Xref, RelPid, Common, ModName], infinity, []).
+ proc_lib:start_link(?MODULE,
+ init,
+ [self(), WxEnv, Xref, RelPid, Common, ModName],
+ infinity,
+ []).
raise(Pid) ->
reltool_utils:cast(Pid, raise).
@@ -127,10 +131,15 @@ loop(#state{xref_pid = Xref, common = C, mod = Mod} = S) ->
receive
Msg ->
%% io:format("~s~p -> ~p\n", [S#state.name, self(), Msg]),
- case Msg of
+ case Msg of
{system, From, SysMsg} ->
Dbg = C#common.sys_debug,
- sys:handle_system_msg(SysMsg, From, S#state.parent_pid, ?MODULE, Dbg, S);
+ sys:handle_system_msg(SysMsg,
+ From,
+ S#state.parent_pid,
+ ?MODULE,
+ Dbg,
+ S);
{cast, _From, raise} ->
wxFrame:raise(S#state.frame),
wxFrame:setFocus(S#state.frame),
@@ -169,7 +178,7 @@ loop(#state{xref_pid = Xref, common = C, mod = Mod} = S) ->
create_window(#state{mod = Mod, name = ModStr} = S) ->
Title = atom_to_list(?APPLICATION) ++ " - " ++
- atom_to_list(Mod#mod.app_name) ++ " - " ++
+ atom_to_list(Mod#mod.app_name) ++ " - " ++
ModStr ++ ".erl",
Frame = wxFrame:new(wx:null(), ?wxID_ANY, Title, []),
%% wxFrame:setSize(Frame, {?WIN_WIDTH, ?WIN_HEIGHT}),
@@ -177,7 +186,7 @@ create_window(#state{mod = Mod, name = ModStr} = S) ->
StatusBar = wxFrame:createStatusBar(Frame,[]),
Book = wxNotebook:new(Panel, ?wxID_ANY, []),
-
+
S2 = S#state{frame = Frame,
panel = Panel,
book = Book,
@@ -204,11 +213,17 @@ create_deps_page(S) ->
Panel = wxPanel:new(S#state.book, []),
Main = wxBoxSizer:new(?wxHORIZONTAL),
- UsedByCtrl = create_mods_list_ctrl(Panel, Main, "Modules used by others", " and their applications"),
+ UsedByCtrl = create_mods_list_ctrl(Panel,
+ Main,
+ "Modules used by others",
+ " and their applications"),
wxSizer:add(Main,
wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]),
[{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]),
- UsesCtrl = create_mods_list_ctrl(Panel, Main, "Used modules", " and their applications"),
+ UsesCtrl = create_mods_list_ctrl(Panel,
+ Main,
+ "Used modules",
+ " and their applications"),
S2 = S#state{deps_used_by_ctrl = UsedByCtrl,
deps_uses_ctrl = UsesCtrl},
redraw_mods(S2),
@@ -242,8 +257,10 @@ create_mods_list_ctrl(Panel, Sizer, ModText, AppText) ->
%% wxListCtrl:setColumnWidth(ListCtrl, ?MODS_APP_COL, ?MODS_APP_COL_WIDTH),
wxListItem:destroy(ListItem),
- wxEvtHandler:connect(ListCtrl, size, [{skip, true}, {userData, mods_list_ctrl}]),
- wxListCtrl:connect(ListCtrl, command_list_item_activated, [{userData, open_app}]),
+ wxEvtHandler:connect(ListCtrl, size,
+ [{skip, true}, {userData, mods_list_ctrl}]),
+ wxListCtrl:connect(ListCtrl, command_list_item_activated,
+ [{userData, open_app}]),
wxWindow:connect(ListCtrl, enter_window),
wxSizer:add(Sizer, ListCtrl,
@@ -252,7 +269,8 @@ create_mods_list_ctrl(Panel, Sizer, ModText, AppText) ->
{proportion, 1}]),
ListCtrl.
-create_code_page(#state{book = Book, code_pages = Pages, name = ModStr} = S, PageName) ->
+create_code_page(#state{book = Book, code_pages = Pages, name = ModStr} = S,
+ PageName) ->
case find_page(S, PageName) of
not_found ->
Page = do_create_code_page(S, PageName),
@@ -260,7 +278,7 @@ create_code_page(#state{book = Book, code_pages = Pages, name = ModStr} = S, Pag
Pos = length(Pages2),
wxNotebook:setSelection(Book, Pos),
case find_page(S, ?INITIAL_CODE_PAGE_NAME) of
- not_found ->
+ not_found ->
ignore;
{found, _, CodePos} ->
%% Rename initial code page
@@ -288,33 +306,37 @@ find_page([], _PageName, _Pos) ->
do_create_code_page(#state{xref_pid = Xref, mod = M} = S, PageName) ->
Panel = wxPanel:new(S#state.book, []),
Editor = create_editor(Panel),
- ToolTip = "Double click on a function call to search the function definition.",
+ ToolTip = "Double click on a function call to "
+ "search the function definition.",
wxBitmapButton:setToolTip(Editor, ToolTip),
{Objs, Data, SearchSz} = create_search_area(Panel),
{ok, App} = reltool_server:get_app(Xref, M#mod.app_name),
- ErlBin =
+ ErlBin =
case App#app.is_escript of
true -> find_escript_bin(App, M);
false -> find_regular_bin(App, M)
end,
-
+
load_code(Editor, ErlBin),
-
+
Sizer = wxBoxSizer:new(?wxVERTICAL),
wxSizer:add(Sizer, Editor, [{flag, ?wxEXPAND}, {proportion, 1}]),
wxSizer:add(Sizer, SearchSz, [{flag, ?wxEXPAND}]),
wxPanel:setSizer(Panel, Sizer),
wxNotebook:addPage(S#state.book, Panel, PageName, []),
- #code_page{name = PageName, editor = Editor, find_objs = Objs, find_data = Data}.
+ #code_page{name = PageName,
+ editor = Editor,
+ find_objs = Objs,
+ find_data = Data}.
find_regular_bin(App, Mod) ->
ActiveDir = App#app.active_dir,
SrcDir = filename:join([ActiveDir, "src"]),
ModStr = atom_to_list(Mod#mod.name),
- Base = ModStr ++ ".erl",
- Find = fun(F, _Acc) -> file:read_file(F) end,
- case filelib:fold_files(SrcDir, Base, true, Find, {error, enoent}) of
+ Base = "^" ++ ModStr ++ "\\.erl$",
+ Find = fun(F, _Acc) -> throw(file:read_file(F)) end,
+ case catch filelib:fold_files(SrcDir, Base, true, Find, {error, enoent}) of
{ok, Bin} ->
Bin;
{error, enoent} ->
@@ -322,9 +344,11 @@ find_regular_bin(App, Mod) ->
BeamFile = filename:join([ActiveDir, "ebin", ModStr ++ ".beam"]),
case beam_lib:chunks(BeamFile, [abstract_code]) of
{ok,{_,[{abstract_code,{_,AC}}]}} ->
- list_to_binary(erl_prettypr:format(erl_syntax:form_list(AC)));
+ IoList = erl_prettypr:format(erl_syntax:form_list(AC)),
+ list_to_binary(IoList);
_ ->
- list_to_binary(["%% Bad luck, cannot find any debug info in the file \"", BeamFile])
+ list_to_binary(["%% Bad luck, cannot find any "
+ "debug info in the file \"", BeamFile])
end
end.
@@ -340,10 +364,17 @@ find_escript_bin(#app{active_dir = ActiveDir}, Mod) ->
[_] ->
Bin = GetBin(),
case beam_lib:version(Bin) of
- {ok,{M, _}} when M =:= ModName; FullName =:= "." ->
- case beam_lib:chunks(Bin, [abstract_code]) of
+ {ok,{M, _}} when M =:= ModName;
+ FullName =:= "." ->
+ case beam_lib:chunks(Bin,
+ [abstract_code]) of
{ok,{_,[{abstract_code,{_,AC}}]}} ->
- {obj, list_to_binary(erl_prettypr:format(erl_syntax:form_list(AC)))};
+ Form =
+ erl_syntax:form_list(AC),
+ IoList =
+ erl_prettypr:format(Form),
+ {obj,
+ list_to_binary(IoList)};
_ ->
Acc
end;
@@ -363,10 +394,14 @@ find_escript_bin(#app{active_dir = ActiveDir}, Mod) ->
{fun(FullName, _GetInfo, GetBin, Acc) ->
io:format("", []),
case filename:split(FullName) of
- [_AppName, "ebin", F] when F =:= ObjFile, Acc =:= NotFound ->
- case beam_lib:chunks(GetBin(), [abstract_code]) of
+ [_AppName, "ebin", F]
+ when F =:= ObjFile, Acc =:= NotFound ->
+ case beam_lib:chunks(GetBin(),
+ [abstract_code]) of
{ok,{_,[{abstract_code,{_,AC}}]}} ->
- {obj, list_to_binary(erl_prettypr:format(erl_syntax:form_list(AC)))};
+ Form = erl_syntax:form_list(AC),
+ IoList = erl_prettypr:format(Form),
+ {obj, list_to_binary(IoList)};
_ ->
Acc
end;
@@ -379,17 +414,19 @@ find_escript_bin(#app{active_dir = ActiveDir}, Mod) ->
filename:dirname(ActiveDir)}
end,
try
- case escript:foldl(Fun, NotFound, Escript) of
+ case reltool_utils:escript_foldl(Fun, NotFound, Escript) of
{ok, {text, Bin}} ->
Bin;
{ok, {obj, Bin}} ->
Bin;
_ ->
- list_to_binary(["%% Bad luck, cannot find the code in the escript ", Escript, "."])
+ list_to_binary(["%% Bad luck, cannot find the "
+ "code in the escript ", Escript, "."])
end
- catch
+ catch
throw:Reason when is_list(Reason) ->
- list_to_binary(["%% Bad luck, cannot find the code in the escript ", Escript, ": ", Reason])
+ list_to_binary(["%% Bad luck, cannot find the code "
+ "in the escript ", Escript, ": ", Reason])
end.
create_config_page(S) ->
@@ -400,13 +437,16 @@ create_config_page(S) ->
handle_event(#state{xref_pid = Xref} = S, Wx) ->
%% io:format("wx: ~p\n", [Wx]),
case Wx of
- #wx{obj= ListCtrl, userData = mods_list_ctrl, event = #wxSize{type = size, size = {W, _H}}} ->
+ #wx{obj= ListCtrl,
+ userData = mods_list_ctrl,
+ event = #wxSize{type = size, size = {W, _H}}} ->
wxListCtrl:setColumnWidth(ListCtrl, ?MODS_MOD_COL, (2 * W) div 3),
wxListCtrl:setColumnWidth(ListCtrl, ?MODS_APP_COL, W div 3),
S;
#wx{userData = open_app,
obj = ListCtrl,
- event = #wxList{type = command_list_item_activated, itemIndex = Pos}} ->
+ event = #wxList{type = command_list_item_activated,
+ itemIndex = Pos}} ->
ModStr = wxListCtrl:getItemText(ListCtrl, Pos),
ModName = list_to_atom(ModStr),
{ok, Mod} = reltool_server:get_mod(Xref, ModName),
@@ -431,13 +471,15 @@ handle_event(#state{xref_pid = Xref} = S, Wx) ->
Page = lists:nth(N, S#state.code_pages),
S#state{active_page = Page}
end;
- #wx{event = #wxCommand{type = command_button_clicked}, userData = history_back} ->
+ #wx{event = #wxCommand{type = command_button_clicked},
+ userData = history_back} ->
goto_back(S);
#wx{obj = ObjRef, event = #wxMouse{type = enter_window}} ->
wxWindow:setFocus(ObjRef),
S;
_ ->
- error_logger:format("~p~p got unexpected mod event from wx:\n\t~p\n",
+ error_logger:format("~p~p got unexpected mod event from "
+ "wx:\n\t~p\n",
[?MODULE, self(), Wx]),
S
end.
@@ -450,7 +492,7 @@ redraw_mods(#state{xref_pid = Xref,
uses_mods = UsesModNames,
used_by_mods = UsedByModNames},
status_bar = Bar}) ->
- InclStatus =
+ InclStatus =
case IsIncl of
true when IsPre =:= true -> "Whitelist - ";
true -> "Derived - ";
@@ -458,8 +500,10 @@ redraw_mods(#state{xref_pid = Xref,
undefined -> "Source - "
end,
Status = lists:concat([InclStatus,
- " uses ", length(UsesModNames), " modules and ",
- " is used by ", length(UsedByModNames), " modules."]),
+ " uses ", length(UsesModNames),
+ " modules and ",
+ " is used by ", length(UsedByModNames),
+ " modules."]),
wxStatusBar:setStatusText(Bar, Status),
UsesMods = [select_image(Xref, M) || M <- UsesModNames],
UsedByMods = [select_image(Xref, M) || M <- UsedByModNames],
@@ -470,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
@@ -483,9 +527,11 @@ redraw_mods(ListCtrl, ImageMods) ->
wxListCtrl:deleteAllItems(ListCtrl),
Add =
fun({ImageId, AppName, #mod{name = ModName}}, Row) ->
- wxListCtrl:insertItem(ListCtrl, Row, ""),
- if (Row rem 2) =:= 0 ->
- wxListCtrl:setItemBackgroundColour(ListCtrl, Row, {240,240,255});
+ wxListCtrl:insertItem(ListCtrl, Row, ""),
+ if (Row rem 2) =:= 0 ->
+ wxListCtrl:setItemBackgroundColour(ListCtrl,
+ Row,
+ {240,240,255});
true ->
ignore
end,
@@ -515,16 +561,16 @@ goto_line(#state{active_page = P} = S, LineNo) when is_integer(LineNo) ->
wxStyledTextCtrl:setSelection(Editor, Left, Right),
S;
goto_line(#state{active_page = P} =S, Str) when is_list(Str) ->
- try
+ try
LineNo = list_to_integer(Str),
CurrentPos = wxStyledTextCtrl:getCurrentPos(P#code_page.editor),
S2 = add_pos_to_history(S, CurrentPos),
goto_line(S2, LineNo - 1)
- catch
+ catch
_:_ ->
wxStatusBar:setStatusText(S#state.status_bar, "Not a line number"),
S
- end.
+ end.
find_string(S, Str) ->
find_string(S, Str, 0).
@@ -535,19 +581,20 @@ find_regexp_forward(S, Str) ->
wxTextCtrl:setValue(TextCtrl, Str),
S2.
-find_string(#state{active_page = #code_page{editor = Editor,
- find_objs = #find_objs{radio={NextO,_,CaseO}},
- find_data = #find_data{found = Found} = Data} = P} = S,
+find_string(#state{active_page =
+ #code_page{editor = Editor,
+ find_objs = #find_objs{radio={NextO,_,CaseO}},
+ find_data = #find_data{found = Found} = Data} = P} = S,
Str,
Flag) ->
wxStyledTextCtrl:hideSelection(Editor, true),
Dir = wxRadioButton:getValue(NextO) xor wx_misc:getKeyState(?WXK_SHIFT),
Case = wxCheckBox:getValue(CaseO),
Pos =
- if
+ if
Found, Dir -> %% Forward Continuation
wxStyledTextCtrl:getAnchor(Editor);
- Found -> %% Backward Continuation
+ Found -> %% Backward Continuation
wxStyledTextCtrl:getCurrentPos(Editor);
Dir -> %% Forward wrap
0;
@@ -556,18 +603,18 @@ find_string(#state{active_page = #code_page{editor = Editor,
end,
wxStyledTextCtrl:gotoPos(Editor,Pos),
wxStyledTextCtrl:searchAnchor(Editor),
- Flag2 =
+ Flag2 =
if Case -> Flag bor ?wxSTC_FIND_MATCHCASE;
true -> Flag
end,
- Res =
- if
+ Res =
+ if
Dir -> wxStyledTextCtrl:searchNext(Editor, Flag2, Str);
true -> wxStyledTextCtrl:searchPrev(Editor, Flag2, Str)
end,
- Found2 =
+ Found2 =
case Res >= 0 of
- true ->
+ true ->
wxStyledTextCtrl:hideSelection(Editor, false),
%% io:format("Found ~p ~n",[Res]),
LineNo = wxStyledTextCtrl:lineFromPosition(Editor,Res),
@@ -576,11 +623,15 @@ find_string(#state{active_page = #code_page{editor = Editor,
true;
false ->
wxStatusBar:setStatusText(S#state.status_bar,
- "Not found (Hit Enter to wrap search)"),
+ "Not found (Hit Enter to "
+ "wrap search)"),
false
- end,
+ end,
P2 = P#code_page{find_data = Data#find_data{found = Found2}},
- Pages = lists:keystore(P#code_page.name, #code_page.name, S#state.code_pages, P2),
+ Pages = lists:keystore(P#code_page.name,
+ #code_page.name,
+ S#state.code_pages,
+ P2),
S#state{active_page = P2, code_pages = Pages}.
goto_function(S, Editor) ->
@@ -589,14 +640,14 @@ goto_function(S, Editor) ->
Left = wxStyledTextCtrl:wordStartPosition(Editor, CurrentPos, true),
Right = wxStyledTextCtrl:wordEndPosition(Editor, CurrentPos, true),
ColonPos = Left - 1,
- Left2 =
+ Left2 =
case wxStyledTextCtrl:getCharAt(Editor, ColonPos) of
$: ->
wxStyledTextCtrl:wordStartPosition(Editor, ColonPos, true);
_ ->
Left
end,
- Right2 =
+ Right2 =
case wxStyledTextCtrl:getCharAt(Editor, Right) of
$: ->
wxStyledTextCtrl:wordEndPosition(Editor, Right + 1, true);
@@ -623,33 +674,41 @@ 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, _} ->
- wxStatusBar:setStatusText(S#state.status_bar, "No such module: " ++ ModStr),
+ wxStatusBar:setStatusText(S#state.status_bar,
+ "No such module: " ++ ModStr),
S
end.
-goto_back(#state{active_page = #code_page{editor = Editor, find_data = Data} = Page,
+goto_back(#state{active_page =
+ #code_page{editor = Editor, find_data = Data} = Page,
code_pages = Pages} = S) ->
case Data#find_data.history of
[PrevPos | History] ->
LineNo = wxStyledTextCtrl:lineFromPosition(Editor, PrevPos),
Data2 = Data#find_data{history = History},
Page2 = Page#code_page{find_data = Data2},
- Pages2 = lists:keystore(Page2#code_page.name, #code_page.name, Pages, Page2),
- goto_line(S#state{active_page = Page2, code_pages = Pages2}, LineNo);
+ Pages2 = lists:keystore(Page2#code_page.name,
+ #code_page.name,
+ Pages,
+ Page2),
+ goto_line(S#state{active_page = Page2, code_pages = Pages2},
+ LineNo);
[] ->
wxStatusBar:setStatusText(S#state.status_bar, "No history"),
S
end.
-add_pos_to_history(#state{active_page = Page, code_pages = Pages} = S, CurrentPos) ->
+add_pos_to_history(#state{active_page = Page, code_pages = Pages} = S,
+ CurrentPos) ->
Data = Page#code_page.find_data,
Data2 = Data#find_data{history = [CurrentPos | Data#find_data.history]},
Page2 = Page#code_page{find_data = Data2},
- Pages2 = lists:keystore(Page2#code_page.name, #code_page.name, Pages, Page2),
+ Pages2 =
+ lists:keystore(Page2#code_page.name, #code_page.name, Pages, Page2),
S#state{active_page = Page2, code_pages = Pages2}.
create_editor(Parent) ->
@@ -685,24 +744,31 @@ create_editor(Parent) ->
wxStyledTextCtrl:styleSetFont(Ed, Style, FixedFont),
wxStyledTextCtrl:styleSetForeground(Ed, Style, Color)
end,
- [SetStyle(Style) || Style <- Styles],
+ lists:foreach(fun (Style) -> SetStyle(Style) end, Styles),
wxStyledTextCtrl:setKeyWords(Ed, 0, keyWords()),
%% Margins Markers
%% Breakpoint Should be a pixmap?
- wxStyledTextCtrl:markerDefine(Ed, 0, ?wxSTC_MARK_CIRCLE, [{foreground, {170,20,20}}]),
- wxStyledTextCtrl:markerDefine(Ed, 0, ?wxSTC_MARK_CIRCLE, [{background, {200,120,120}}]),
- %% Disabled Breakpoint
- wxStyledTextCtrl:markerDefine(Ed, 1, ?wxSTC_MARK_CIRCLE, [{foreground, {20,20,170}}]),
- wxStyledTextCtrl:markerDefine(Ed, 1, ?wxSTC_MARK_CIRCLE, [{background, {120,120,200}}]),
-
+ wxStyledTextCtrl:markerDefine(Ed, 0, ?wxSTC_MARK_CIRCLE,
+ [{foreground, {170,20,20}}]),
+ wxStyledTextCtrl:markerDefine(Ed, 0, ?wxSTC_MARK_CIRCLE,
+ [{background, {200,120,120}}]),
+ %% Disabled Breakpoint
+ wxStyledTextCtrl:markerDefine(Ed, 1, ?wxSTC_MARK_CIRCLE,
+ [{foreground, {20,20,170}}]),
+ wxStyledTextCtrl:markerDefine(Ed, 1, ?wxSTC_MARK_CIRCLE,
+ [{background, {120,120,200}}]),
+
%% Current Line
- wxStyledTextCtrl:markerDefine(Ed, 2, ?wxSTC_MARK_ARROW, [{foreground, {20,170,20}}]),
- wxStyledTextCtrl:markerDefine(Ed, 2, ?wxSTC_MARK_ARROW, [{background, {200,255,200}}]),
- wxStyledTextCtrl:markerDefine(Ed, 3, ?wxSTC_MARK_BACKGROUND, [{background, {200,255,200}}]),
+ wxStyledTextCtrl:markerDefine(Ed, 2, ?wxSTC_MARK_ARROW,
+ [{foreground, {20,170,20}}]),
+ wxStyledTextCtrl:markerDefine(Ed, 2, ?wxSTC_MARK_ARROW,
+ [{background, {200,255,200}}]),
+ wxStyledTextCtrl:markerDefine(Ed, 3, ?wxSTC_MARK_BACKGROUND,
+ [{background, {200,255,200}}]),
%% Scrolling
- Policy = ?wxSTC_CARET_SLOP bor ?wxSTC_CARET_JUMPS bor ?wxSTC_CARET_EVEN,
+ Policy = ?wxSTC_CARET_SLOP bor ?wxSTC_CARET_JUMPS bor ?wxSTC_CARET_EVEN,
wxStyledTextCtrl:setYCaretPolicy(Ed, Policy, 3),
wxStyledTextCtrl:setVisiblePolicy(Ed, Policy, 3),
@@ -714,9 +780,9 @@ create_editor(Parent) ->
create_search_area(Parent) ->
Sizer = wxBoxSizer:new(?wxHORIZONTAL),
- wxSizer:add(Sizer, wxStaticText:new(Parent, ?wxID_ANY, "Find:"),
+ wxSizer:add(Sizer, wxStaticText:new(Parent, ?wxID_ANY, "Find:"),
[{flag,?wxALIGN_CENTER_VERTICAL}]),
- TC1 = wxTextCtrl:new(Parent, ?SEARCH_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]),
+ TC1 = wxTextCtrl:new(Parent, ?SEARCH_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]),
wxSizer:add(Sizer, TC1, [{proportion,3}, {flag, ?wxEXPAND}]),
Nbtn = wxRadioButton:new(Parent, ?wxID_ANY, "Next"),
wxRadioButton:setValue(Nbtn, true),
@@ -726,14 +792,15 @@ create_search_area(Parent) ->
Cbtn = wxCheckBox:new(Parent, ?wxID_ANY, "Match Case"),
wxSizer:add(Sizer,Cbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]),
wxSizer:add(Sizer, 15,15, [{proportion,1}, {flag, ?wxEXPAND}]),
- wxSizer:add(Sizer, wxStaticText:new(Parent, ?wxID_ANY, "Goto Line:"),
+ wxSizer:add(Sizer, wxStaticText:new(Parent, ?wxID_ANY, "Goto Line:"),
[{flag,?wxALIGN_CENTER_VERTICAL}]),
- TC2 = wxTextCtrl:new(Parent, ?GOTO_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]),
+ TC2 = wxTextCtrl:new(Parent, ?GOTO_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]),
wxSizer:add(Sizer, TC2, [{proportion,0}, {flag, ?wxEXPAND}]),
Button = wxButton:new(Parent, ?wxID_ANY, [{label, "Back"}]),
wxSizer:add(Sizer, Button, []),
- wxEvtHandler:connect(Button, command_button_clicked, [{userData, history_back}]),
+ wxEvtHandler:connect(Button, command_button_clicked,
+ [{userData, history_back}]),
%% wxTextCtrl:connect(TC1, command_text_updated),
wxTextCtrl:connect(TC1, command_text_enter),
%% wxTextCtrl:connect(TC1, kill_focus),
@@ -748,7 +815,9 @@ load_code(Ed, Code) when is_binary(Code) ->
wxStyledTextCtrl:setTextRaw(Ed, <<Code/binary, 0:8>>),
Lines = wxStyledTextCtrl:getLineCount(Ed),
Sz = trunc(math:log10(Lines))+1,
- LW = wxStyledTextCtrl:textWidth(Ed, ?wxSTC_STYLE_LINENUMBER, lists:duplicate(Sz, $9)),
+ LW = wxStyledTextCtrl:textWidth(Ed,
+ ?wxSTC_STYLE_LINENUMBER,
+ lists:duplicate(Sz, $9)),
%%io:format("~p ~p ~p~n", [Lines, Sz, LW]),
wxStyledTextCtrl:setMarginWidth(Ed, 0, LW+5),
wxStyledTextCtrl:setReadOnly(Ed, true),
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index 8d4530131f..692baea0a4 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2009-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%
-module(reltool_server).
@@ -44,7 +44,7 @@
-include("reltool.hrl").
--record(state,
+-record(state,
{options,
parent_pid,
common,
@@ -60,16 +60,20 @@ start_link() ->
start_link([]).
start_link(Options) ->
- proc_lib:start_link(?MODULE, init, [[{parent, self()} | Options]], infinity, []).
+ proc_lib:start_link(?MODULE,
+ init,
+ [[{parent, self()} | Options]],
+ infinity,
+ []).
-get_config(Pid, InclDefaults, InclDerivates) ->
- reltool_utils:call(Pid, {get_config, InclDefaults, InclDerivates}).
+get_config(Pid, InclDef, InclDeriv) ->
+ reltool_utils:call(Pid, {get_config, InclDef, InclDeriv}).
load_config(Pid, FilenameOrConfig) ->
reltool_utils:call(Pid, {load_config, FilenameOrConfig}).
-save_config(Pid, Filename, InclDefaults, InclDerivates) ->
- reltool_utils:call(Pid, {save_config, Filename, InclDefaults, InclDerivates}).
+save_config(Pid, Filename, InclDef, InclDeriv) ->
+ reltool_utils:call(Pid, {save_config, Filename, InclDef, InclDeriv}).
reset_config(Pid) ->
reltool_utils:call(Pid, reset_config).
@@ -128,18 +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) ->
@@ -156,15 +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 = [],
@@ -176,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 ->
@@ -194,30 +216,38 @@ parse_options([{Key, Val} | KeyVals], S, C, Sys, Status) ->
parse_options(KeyVals, S, C, Sys2, Status2);
_ ->
Text = lists:flatten(io_lib:format("~p", [{Key, Val}])),
- Status2 = reltool_utils:return_first_error(Status, "Illegal option: " ++ Text),
+ Status2 =
+ reltool_utils:return_first_error(Status,
+ "Illegal option: " ++ Text),
parse_options(KeyVals, S, C, Sys, Status2)
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),
+ Status2 = reltool_utils:return_first_error(Status,
+ "Illegal options: " ++ Text),
{S#state{common = C, sys = Sys}, Status2}.
loop(#state{common = C, sys = Sys} = S) ->
receive
{system, From, Msg} ->
- sys:handle_system_msg(Msg, From, S#state.parent_pid, ?MODULE, C#common.sys_debug, S);
- {call, ReplyTo, Ref, {get_config, InclDefaults, InclDerivates}} ->
- Reply = do_get_config(S, InclDefaults, InclDerivates),
+ sys:handle_system_msg(Msg,
+ From,
+ S#state.parent_pid,
+ ?MODULE,
+ C#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);
- {call, ReplyTo, Ref, {save_config, Filename, InclDefaults, InclDerivates}} ->
- Reply = do_save_config(S, Filename, InclDefaults, InclDerivates),
+ {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} ->
@@ -225,43 +255,44 @@ loop(#state{common = C, sys = Sys} = S) ->
S3 = shrink_sys(S2),
{S4, Status2} = refresh(S3, true, Status),
{S5, Status3} = analyse(S4#state{old_sys = S4#state.sys}, Status2),
- S6 =
+ 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);
{call, ReplyTo, Ref, undo_config} ->
reltool_utils:reply(ReplyTo, Ref, ok),
- S2 = S#state{sys = S#state.old_sys,
+ S2 = S#state{sys = S#state.old_sys,
old_sys = S#state.sys,
status = S#state.old_status,
old_status = S#state.status},
?MODULE:loop(S2);
{call, ReplyTo, Ref, {get_rel, RelName}} ->
Sys = S#state.sys,
- Reply =
+ 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);
{call, ReplyTo, Ref, {get_script, RelName}} ->
Sys = S#state.sys,
- Reply =
+ Reply =
case lists:keysearch(RelName, #rel.name, Sys#sys.rels) of
{value, Rel} ->
PathFlag = true,
- Variables = [],
- reltool_target:gen_script(Rel, Sys, PathFlag, Variables);
+ 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);
@@ -271,17 +302,18 @@ 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);
{call, ReplyTo, Ref, {get_app, AppName}} when is_atom(AppName) ->
- Reply =
+ Reply =
case lists:keysearch(AppName, #app.name, Sys#sys.apps) of
{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);
@@ -296,21 +328,22 @@ 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;
{call, ReplyTo, Ref, {get_apps, Kind}} ->
AppNames =
case Kind of
- whitelist ->
+ whitelist ->
[A ||
A <- Sys#sys.apps,
A#app.is_pre_included =:= true];
- blacklist ->
+ blacklist ->
[A ||
A <- Sys#sys.apps,
A#app.is_pre_included =:= false];
- source ->
+ source ->
[A ||
A <- Sys#sys.apps,
A#app.is_included =/= true,
@@ -324,9 +357,10 @@ loop(#state{common = C, sys = Sys} = S) ->
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),
+ {S2, Status} =
+ lists:foldl(fun(A, {X, Y}) -> do_set_app(X, A, Y) end,
+ {S, {ok, []}},
+ Apps),
{S3, Status2} = analyse(S2, Status),
reltool_utils:reply(ReplyTo, Ref, Status2),
?MODULE:loop(S3);
@@ -335,26 +369,30 @@ loop(#state{common = C, sys = Sys} = S) ->
?MODULE:loop(S);
{call, ReplyTo, Ref, {set_sys, Sys2}} ->
S2 = S#state{sys = Sys2#sys{apps = Sys#sys.apps}},
- Force =
+ 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),
- 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);
{call, ReplyTo, Ref, {gen_rel_files, Dir}} ->
- Status =
+ Status =
case reltool_target:gen_rel_files(S#state.sys, Dir) of
ok ->
{ok, []};
@@ -395,16 +433,25 @@ 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),
- Apps3 =
+ {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;
@@ -412,25 +459,68 @@ analyse(#state{common = C, sys = #sys{apps = Apps0} = Sys} = S, Status) ->
%% io:format("Missing mods: ~p\n", [MissingMods]),
MissingApp2 = MissingApp#app{label = ?MISSING_APP_TEXT,
info = missing_app_info(""),
- mods = MissingMods,
+ mods = MissingMods,
status = missing,
uses_mods = []},
[MissingApp2 | Apps2]
end,
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)]),
+ {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},
- try
- Status2 = verify_config(Sys2, Status),
- {S#state{sys = Sys2}, Status2}
- catch
- throw:{error, Status3} ->
- {S, Status3}
+
+ case verify_config(RelApps2, Sys2, Status4) of
+ {ok, _Warnings} = Status5 ->
+ {S#state{sys = Sys2}, Status5};
+ {error, _} = Status5 ->
+ {S, Status5}
end.
-app_init_is_included(C, Sys, #app{mods = Mods} = A) ->
- AppCond =
+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: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);
+ 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;
_ -> A#app.incl_cond
@@ -440,19 +530,42 @@ 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},
+ {Mods2,Status3} = lists:mapfoldl(fun(Mod,Acc) ->
+ mod_init_is_included(C,
+ Mod,
+ ModCond,
+ AppCond,
+ Default,
+ Acc)
+ end,
+ Status2,
+ Mods),
+ A2 = A#app{mods = Mods2,
+ 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) end, Mods),
- %%app_mod_init_is_included(C, AppName, Info, ModCond, AppCond),
- A2.
+ {A2, Status3}.
-mod_init_is_included(C, M, ModCond, AppCond, Default) ->
+mod_init_is_included(C, M, ModCond, AppCond, Default, Status) ->
%% print(M#mod.name, hipe, "incl_cond -> ~p\n", [AppCond]),
IsIncl =
case AppCond of
@@ -463,7 +576,8 @@ mod_init_is_included(C, M, ModCond, AppCond, Default) ->
exclude ->
false;
undefined ->
- %% print(M#mod.name, hipe, "mod_cond -> ~p\n", [ModCond]),
+ %% print(M#mod.name, hipe, "mod_cond -> ~p\n",
+ %% [ModCond]),
case ModCond of
all -> true;
app -> false_to_undefined(M#mod.is_app_mod);
@@ -484,16 +598,59 @@ mod_init_is_included(C, M, ModCond, AppCond, Default) ->
Default
end
end,
+
M2 = M#mod{is_pre_included = IsIncl, is_included = IsIncl},
+
+ Status2 =
+ case ets:lookup(C#common.mod_tab,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);
+ {_,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);
+ {_,_} ->
+ 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)
+ end;
+ [] ->
+ ets:insert(C#common.mod_tab, M2),
+ Status
+ end,
+
%% print(M#mod.name, hipe, "~p -> ~p\n", [M2, IsIncl]),
- ets:insert(C#common.mod_tab, M2).
+ {M2,Status2}.
false_to_undefined(Bool) ->
case Bool of
false -> undefined;
_ -> 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);
@@ -501,29 +658,39 @@ app_propagate_is_included(_C, _Sys, [], Acc) ->
Acc.
mod_propagate_is_included(C, Sys, A, [#mod{name = ModName} | Mods], Acc) ->
- [M2] = ets:lookup(C#common.mod_tab, ModName),
- %% 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]),
- Acc2 =
- 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,
+ 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.
mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) ->
- Acc3 =
+ Acc3 =
case ets:lookup(C#common.mod_tab, 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]),
+ [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
@@ -533,19 +700,22 @@ mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) ->
Acc;
undefined ->
%% Mark and propagate
- M2 =
+ M2 =
case M#mod.incl_cond of
include ->
- M#mod{is_pre_included = true, is_included = true};
+ M#mod{is_pre_included = true,
+ is_included = true};
exclude ->
- M#mod{is_pre_included = true, is_included = true};
+ M#mod{is_pre_included = true,
+ is_included = true};
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]),
+ %% 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),
- Acc2 =
+ Acc2 =
case A#app.is_included of
true ->
Acc;
@@ -557,7 +727,7 @@ mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) ->
undefined -> Sys#sys.mod_cond;
_ -> A#app.mod_cond
end,
- Filter =
+ Filter =
fun(M3) ->
case ModCond of
all -> true;
@@ -569,15 +739,25 @@ mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) ->
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]]),
+ %% [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, ModName, [M3#mod.name || M3 <- Mods], Acc)
+ ets:insert(C#common.app_tab, A2),
+ mod_mark_is_included(C,
+ Sys,
+ ModName,
+ [M3#mod.name ||
+ M3 <- Mods],
+ Acc)
end,
- mod_mark_is_included(C, Sys, ModName, M2#mod.uses_mods, Acc2)
+ mod_mark_is_included(C,
+ Sys,
+ ModName,
+ M2#mod.uses_mods,
+ 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}),
@@ -588,7 +768,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,
@@ -612,50 +792,72 @@ mod_propagate_is_used_by(C, [#mod{name = ModName} | Mods]) ->
mod_propagate_is_used_by(_C, []) ->
ok.
-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;
- false -> 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),
+ AppStatus =
+ case lists:keymember(missing, #mod.status, Mods2) of
+ true -> missing;
+ false -> ok
end,
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)],
+ UsesApps = [M#mod.app_name || ModName <- UsesMods2,
+ M <- ets:lookup(C#common.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)],
+ UsedByApps = [M#mod.app_name || ModName <- UsedByMods2,
+ M <- ets:lookup(C#common.mod_tab, ModName)],
UsedByApps2 = lists:usort(UsedByApps),
-
+
A2 = A#app{mods = Mods2,
- status = Status,
+ status = AppStatus,
uses_mods = UsesMods2,
used_by_mods = UsedByMods2,
uses_apps = UsesApps2,
used_by_apps = UsedByApps2,
is_included = IsIncl2},
- read_apps(C, Sys, Apps, [A2 | Acc]);
-read_apps(_C, _Sys, [], Acc) ->
- lists:reverse(Acc).
-
-read_apps(C, Sys, A, [#mod{name = ModName} | Mods], Acc, IsIncl) ->
- [M2] = ets:lookup(C#common.mod_tab, ModName),
- Status = do_get_status(M2),
- %% print(M2#mod.name, hipe, "status -> ~p\n", [Status]),
- {IsIncl2, M3} =
- case M2#mod.is_included of
- true ->
- UsedByMods = [N || {_, N} <- ets:lookup(C#common.mod_used_by_tab, ModName)],
- {true, M2#mod{status = Status, used_by_mods = UsedByMods}};
- _ ->
- {IsIncl, M2#mod{status = Status, used_by_mods = []}}
- end,
- ets:insert(C#common.mod_tab, M3),
- read_apps(C, Sys, A, Mods, [M3 | Acc], IsIncl2);
-read_apps(_C, _Sys, _A, [], Acc, IsIncl) ->
- {lists:reverse(Acc), IsIncl}.
+ 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}.
+
+mod_recap_dependencies(C, Sys, A, [#mod{name = ModName}=M1 | Mods], Acc, IsIncl, Status) ->
+ case ets:lookup(C#common.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]),
+ {IsIncl2, M3} =
+ case M2#mod.is_included of
+ true ->
+ UsedByMods =
+ [N || {_, N} <- ets:lookup(C#common.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);
+ [_] 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);
+ [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)
+ end;
+mod_recap_dependencies(_C, _Sys, _A, [], Acc, IsIncl, Status) ->
+ {lists:reverse(Acc), IsIncl, Status}.
do_get_status(M) ->
if
@@ -669,14 +871,12 @@ 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) ->
+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} ||
- M <- A#app.mods,
+ exists = false} ||
+ M <- A#app.mods,
M#mod.incl_cond =/= undefined],
if
A#app.is_escript ->
@@ -684,30 +884,21 @@ 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,
A#app.use_selected_vsn =:= undefined ->
false;
true ->
- {Dir, Dirs} =
+ {Dir, Dirs, OptVsn} =
case A#app.use_selected_vsn of
- undefined ->
- {shrinked, []};
+ undefined ->
+ {shrinked, [], undefined};
false ->
- {shrinked, []};
+ {shrinked, [], undefined};
true ->
- {A#app.active_dir, [A#app.active_dir]};
- _ when A#app.is_escript ->
- {A#app.active_dir, [A#app.active_dir]}
- end,
- OptVsn =
- case A#app.use_selected_vsn of
- undefined -> undefined;
- false -> undefined;
- true -> A#app.vsn
+ {A#app.active_dir, [A#app.active_dir], A#app.vsn}
end,
{true, A#app{active_dir = Dir,
sorted_dirs = Dirs,
@@ -715,8 +906,7 @@ filter_app(A) ->
label = undefined,
info = undefined,
mods = Mods,
- uses_mods = undefined,
- is_included = undefined}}
+ uses_mods = undefined}}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -730,37 +920,45 @@ refresh_app(#app{name = AppName,
Status) ->
if
Force; OptLabel =:= undefined ->
- {AppInfo, EbinMods, Status3} =
+ {AppInfo, EbinMods, Status3} =
case IsEscript of
false ->
-
+
%% Add info from .app file
Base = get_base(AppName, ActiveDir),
{_, DefaultVsn} = reltool_utils:split_app_name(Base),
Ebin = filename:join([ActiveDir, "ebin"]),
- AppFile = filename:join([Ebin, atom_to_list(AppName) ++ ".app"]),
- {AI, Status2} = read_app_info(AppFile, AppFile, AppName, DefaultVsn, Status),
+ AppFile =
+ filename:join([Ebin,
+ atom_to_list(AppName) ++ ".app"]),
+ {AI, Status2} =
+ read_app_info(AppFile,
+ AppFile,
+ AppName,
+ DefaultVsn,
+ Status),
{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, 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
+ undefined ->
+ AppInfoMods
end,
MissingMods = add_missing_mods(AppName, EbinMods, AppModNames),
-
+
%% Add optional user config for each module
Mods2 = add_mod_config(MissingMods ++ EbinMods, Mods),
-
+
%% Set app flag for each module in app file
Mods3 = set_mod_flags(Mods2, AppModNames),
AppVsn = AppInfo#app_info.vsn,
@@ -770,7 +968,7 @@ refresh_app(#app{name = AppName,
_ -> atom_to_list(AppName) ++ "-" ++ AppVsn
end,
App2 = App#app{vsn = AppVsn,
- label = AppLabel,
+ label = AppLabel,
info = AppInfo,
mods = lists:keysort(#mod.name, Mods3)},
{App2, Status3};
@@ -790,30 +988,59 @@ 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]),
- {missing_app_info(DefaultVsn), reltool_utils:add_warning(Status, Text)};
- {error, Text} when Text =:= EnoentText->
- {missing_app_info(DefaultVsn), Status};
+ 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)};
+ {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 ", AppFile, " (", Text, ")."]),
- {missing_app_info(DefaultVsn), reltool_utils:add_warning(Status, Text2)}
+ Text2 = lists:concat([AppName,
+ ": Cannot parse app file ",
+ AppFile, " (", Text, ")."]),
+ {missing_app_info(DefaultVsn),
+ reltool_utils:add_warning(Status, Text2)}
end.
parse_app_info(File, [{Key, Val} | KeyVals], AI, Status) ->
case Key of
- description -> parse_app_info(File, KeyVals, AI#app_info{description = Val}, Status);
- id -> parse_app_info(File, KeyVals, AI#app_info{id = Val}, Status);
- vsn -> parse_app_info(File, KeyVals, AI#app_info{vsn = Val}, Status);
- modules -> parse_app_info(File, KeyVals, AI#app_info{modules = Val}, Status);
- maxP -> parse_app_info(File, KeyVals, AI#app_info{maxP = Val}, Status);
- maxT -> parse_app_info(File, KeyVals, AI#app_info{maxT = Val}, Status);
- registered -> parse_app_info(File, KeyVals, AI#app_info{registered = Val}, Status);
- included_applications -> parse_app_info(File, KeyVals, AI#app_info{incl_apps = Val}, Status);
- applications -> parse_app_info(File, KeyVals, AI#app_info{applications = Val}, Status);
- env -> parse_app_info(File, KeyVals, AI#app_info{env = Val}, Status);
- mod -> parse_app_info(File, KeyVals, AI#app_info{mod = Val}, Status);
- start_phases -> parse_app_info(File, KeyVals, AI#app_info{start_phases = Val}, Status);
- _ -> parse_app_info(File, KeyVals, AI, reltool_utils:add_warning(Status, lists:concat(["Unexpected item ", Key, "in app file ", File])))
+ description ->
+ parse_app_info(File, KeyVals, AI#app_info{description = Val},
+ Status);
+ id ->
+ parse_app_info(File, KeyVals, AI#app_info{id = Val}, Status);
+ vsn ->
+ parse_app_info(File, KeyVals, AI#app_info{vsn = Val}, Status);
+ modules ->
+ parse_app_info(File, KeyVals, AI#app_info{modules = Val}, Status);
+ maxP ->
+ parse_app_info(File, KeyVals, AI#app_info{maxP = Val}, Status);
+ maxT ->
+ parse_app_info(File, KeyVals, AI#app_info{maxT = Val}, Status);
+ registered ->
+ parse_app_info(File, KeyVals, AI#app_info{registered = Val},
+ Status);
+ included_applications ->
+ parse_app_info(File, KeyVals, AI#app_info{incl_apps = Val}, Status);
+ applications ->
+ parse_app_info(File, KeyVals, AI#app_info{applications = Val},
+ Status);
+ env ->
+ parse_app_info(File, KeyVals, AI#app_info{env = Val}, Status);
+ mod ->
+ parse_app_info(File, KeyVals, AI#app_info{mod = Val}, Status);
+ start_phases ->
+ 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))
end;
parse_app_info(_, [], AI, Status) ->
{AI, Status}.
@@ -824,7 +1051,7 @@ read_ebin_mods(Ebin, AppName) ->
Ext = code:objfile_extension(),
InitMod = fun(F) ->
File = filename:join([Ebin, F]),
- init_mod(AppName, File, File, Ext)
+ init_mod(AppName, File, File, Ext)
end,
Files2 = [F || F <- Files, filename:extension(F) =:= Ext],
pmap(InitMod, Files2);
@@ -839,7 +1066,7 @@ pmap(Fun, List) ->
%% -record(pmap_res, {count, ref, res}).
%% -record(pmap_wait, {count, ref, pid}).
-%%
+%%
%% pmap(Fun, [H | T], N, Max, Count, WaitFor, Results) when N < Max ->
%% Ref = make_ref(),
%% Parent = self(),
@@ -923,8 +1150,8 @@ missing_mod(ModName, AppName) ->
add_mod_config(Mods, ModConfigs) ->
AddConfig =
fun(Config, Acc) ->
- case lists:keysearch(Config#mod.name, #mod.name, Mods) of
- {value, M} ->
+ case lists:keyfind(Config#mod.name, #mod.name, Mods) of
+ #mod{} = M ->
M2 = M#mod{incl_cond = Config#mod.incl_cond},
lists:keystore(Config#mod.name, #mod.name, Acc, M2);
false ->
@@ -943,16 +1170,16 @@ set_mod_flags(Mods, AppModNames) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-do_get_config(S, InclDefaults, InclDerivates) ->
+do_get_config(S, InclDef, InclDeriv) ->
S2 =
- case InclDerivates of
+ case InclDeriv of
false -> shrink_sys(S);
true -> S
end,
- {ok, reltool_target:gen_config(S2#state.sys, InclDefaults)}.
+ reltool_target:gen_config(S2#state.sys, InclDef).
-do_save_config(S, Filename, InclDefaults, InclDerivates) ->
- {ok, Config} = do_get_config(S, InclDefaults, InclDerivates),
+do_save_config(S, Filename, InclDef, InclDeriv) ->
+ {ok, Config} = do_get_config(S, InclDef, InclDeriv),
IoList = io_lib:format("%% config generated at ~w ~w\n~p.\n\n",
[date(), time(), Config]),
file:write_file(Filename, IoList).
@@ -963,17 +1190,20 @@ 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, []}),
+ {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 =
+ {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};
@@ -988,37 +1218,51 @@ read_config(OldSys, Filename, Status) when is_list(Filename) ->
read_config(OldSys, SysConfig, Status);
{ok, Content} ->
Text = lists:flatten(io_lib:format("~p", [Content])),
- {OldSys, reltool_utils:return_first_error(Status, "Illegal file content: " ++ Text)};
+ {OldSys,
+ reltool_utils:return_first_error(Status,
+ "Illegal file content: " ++
+ Text)};
{error, Reason} ->
Text = file:format_error(Reason),
- {OldSys, reltool_utils:return_first_error(Status, "File access: " ++ Text)}
+ {OldSys,
+ 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: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}
end;
read_config(OldSys, BadConfig, Status) ->
Text = lists:flatten(io_lib:format("~p", [BadConfig])),
- {OldSys, reltool_utils:return_first_error(Status, "Illegal content: " ++ Text)}.
+ {OldSys,
+ reltool_utils:return_first_error(Status, "Illegal content: " ++ Text)}.
-decode(#sys{apps = Apps} = Sys, [{erts = Name, AppKeyVals} | SysKeyVals], Status)
+decode(#sys{apps = Apps} = Sys, [{erts = Name, AppKeyVals} | SysKeyVals],
+ Status)
when is_atom(Name), is_list(AppKeyVals) ->
App = default_app(Name),
{App2, Status2} = decode(App, AppKeyVals, Status),
@@ -1028,7 +1272,8 @@ decode(#sys{apps = Apps} = Sys, [{app, Name, AppKeyVals} | SysKeyVals], Status)
App = default_app(Name),
{App2, Status2} = decode(App, AppKeyVals, Status),
decode(Sys#sys{apps = [App2 | Apps]}, SysKeyVals, Status2);
-decode(#sys{apps = Apps, escripts = Escripts} = Sys, [{escript, File, AppKeyVals} | SysKeyVals], Status)
+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),
@@ -1038,173 +1283,229 @@ decode(#sys{apps = Apps, escripts = Escripts} = Sys, [{escript, File, AppKeyVals
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)
+ decode(Sys#sys{apps = [App3 | Apps], escripts = [File | Escripts]},
+ SysKeyVals,
+ Status2);
+decode(#sys{rels = Rels} = Sys, [{rel, Name, Vsn, RelApps} | SysKeyVals],
+ Status)
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} =
+ {Sys3, Status3} =
case Key of
root_dir when is_list(Val) ->
{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;
- Val =:= none ->
+ 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;
- Val =:= derived ->
+ 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)}, Status};
+ {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)}, Status};
+ {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)}, Status};
+ {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)}, Status};
+ {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)}, Status};
+ {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)}, Status};
+ {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};
- app_file when Val =:= keep; Val =:= strip, Val =:= all ->
+ 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 ->
+ debug_info when Val =:= keep; Val =:= strip ->
{Sys#sys{debug_info = Val}, Status};
_ ->
Text = lists:flatten(io_lib:format("~p", [{Key, Val}])),
- {Sys, reltool_utils:return_first_error(Status, "Illegal option: " ++ Text)}
+ {Sys, reltool_utils:return_first_error(Status,
+ "Illegal option: " ++
+ Text)}
end,
decode(Sys3, KeyVals, Status3);
decode(#app{} = App, [{Key, Val} | KeyVals], Status) ->
- {App2, Status2} =
+ {App2, Status2} =
case Key of
- mod_cond when Val =:= all; Val =:= app; Val =:= ebin; Val =:= derived; Val =:= none ->
+ mod_cond when Val =:= all;
+ Val =:= app;
+ Val =:= ebin;
+ Val =:= derived;
+ Val =:= none ->
{App#app{mod_cond = Val}, Status};
- incl_cond when Val =:= include; Val =:= exclude; Val =:= derived ->
+ incl_cond when Val =:= include;
+ Val =:= exclude;
+ Val =:= derived ->
{App#app{incl_cond = Val}, Status};
- debug_info when Val =:= keep; Val =:= strip ->
+ debug_info when Val =:= keep;
+ Val =:= strip ->
{App#app{debug_info = Val}, Status};
- app_file when Val =:= keep; Val =:= strip, Val =:= all ->
+ app_file when Val =:= keep;
+ Val =:= strip;
+ Val =:= all ->
{App#app{app_file = Val}, Status};
- app_type when Val =:= permanent; Val =:= transient; Val =:= temporary;
- Val =:= load; Val =:= none ->
+ app_type when Val =:= permanent;
+ Val =:= transient;
+ Val =:= temporary;
+ Val =:= load;
+ 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)}, Status};
+ {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)}, Status};
+ {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)}, Status};
+ {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)}, Status};
+ {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};
- vsn when is_list(Val) ->
+ vsn when is_list(Val) ->
{App#app{use_selected_vsn = true, vsn = Val}, Status};
_ ->
Text = lists:flatten(io_lib:format("~p", [{Key, Val}])),
- {App, reltool_utils:return_first_error(Status, "Illegal option: " ++ Text)}
+ {App, reltool_utils:return_first_error(Status,
+ "Illegal option: " ++ Text)}
end,
decode(App2, KeyVals, Status2);
-decode(#app{mods = Mods} = App, [{mod, Name, ModKeyVals} | AppKeyVals], Status) ->
+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} =
+ {Mod2, Status2} =
case Key of
- incl_cond when Val =:= include; Val =:= exclude; Val =:= derived ->
+ incl_cond when Val =:= include; Val =:= exclude; Val =:= derived ->
{Mod#mod{incl_cond = Val}, Status};
- debug_info when Val =:= keep; Val =:= strip ->
+ debug_info when Val =:= keep; Val =:= strip ->
{Mod#mod{debug_info = Val}, Status};
_ ->
Text = lists:flatten(io_lib:format("~p", [{Key, Val}])),
- {Mod, reltool_utils:return_first_error(Status, "Illegal option: " ++ Text)}
+ {Mod,
+ reltool_utils:return_first_error(Status,
+ "Illegal option: " ++ Text)}
end,
decode(Mod2, KeyVals, Status2);
decode(#rel{rel_apps = RelApps} = Rel, [RelApp | KeyVals], Status) ->
- RA =
+ {ValidTypesAssigned, RA} =
case RelApp of
Name when is_atom(Name) ->
- #rel_app{name = Name, app_type = undefined, incl_apps = []};
+ {true, #rel_app{name = Name}};
{Name, Type} when is_atom(Name) ->
- #rel_app{name = Name, app_type = Type, incl_apps = []};
+ {is_type(Type), #rel_app{name = Name, app_type = Type}};
{Name, InclApps} when is_atom(Name), is_list(InclApps) ->
- #rel_app{name = Name, app_type = undefined, incl_apps = InclApps};
+ VI = lists:all(fun erlang:is_atom/1, InclApps),
+ {VI, #rel_app{name = Name, incl_apps = InclApps}};
{Name, Type, InclApps} when is_atom(Name), is_list(InclApps) ->
- #rel_app{name = Name, app_type = Type, incl_apps = 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}};
_ ->
- #rel_app{incl_apps = []}
+ {false, #rel_app{incl_apps = []}}
end,
- IsType = is_type(RA#rel_app.app_type),
- NonAtoms = [IA || IA <- RA#rel_app.incl_apps, not is_atom(IA)],
- if
- IsType, NonAtoms =:= [] ->
+ case ValidTypesAssigned of
+ true ->
decode(Rel#rel{rel_apps = RelApps ++ [RA]}, KeyVals, Status);
- true ->
+ false ->
Text = lists:flatten(io_lib:format("~p", [RelApp])),
- Status2 = reltool_utils:return_first_error(Status, "Illegal option: " ++ Text),
+ Status2 =
+ reltool_utils:return_first_error(Status,
+ "Illegal option: " ++ Text),
decode(Rel, KeyVals, Status2)
end;
decode(Acc, [], Status) ->
@@ -1227,7 +1528,7 @@ is_type(Type) ->
split_escript_name(File) when is_list(File) ->
Label = filename:basename(File, ".escript"),
{list_to_atom("*escript* " ++ Label), Label}.
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
refresh(#state{sys = Sys} = S, Force, Status) ->
@@ -1245,7 +1546,8 @@ merge_config(OldSys, NewSys, Force, Status) ->
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),
+ {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,
@@ -1253,54 +1555,59 @@ 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
- true ->
- lists:foreach(fun(Rel)-> check_rel(Rel, Sys, Status) end, Sys#sys.rels),
- Status;
+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([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_rel(#rel{name = RelName, rel_apps = RelApps}, #sys{apps = Apps}, Status) ->
+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(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,
- case lists:keysearch(AppName, #app.name, Apps) of
- {value, Erts} ->
+ case lists:keyfind(AppName, #app.name, Apps) of
+ #app{vsn = Vsn} = Erts ->
LocalRoot = code:root_dir(),
- Vsn = Erts#app.vsn,
if
LocalRoot =:= RootDir, Vsn =:= "" ->
Vsn2 = erlang:system_info(version),
@@ -1308,13 +1615,14 @@ 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(Status,
+ "erts has no version")};
true ->
{Apps, Status}
end;
false ->
- Text = "erts cannnot be found in the root directory " ++ RootDir,
- Status2 = reltool_utils:return_first_error(Status, Text),
+ Text = "erts cannot be found in the root directory " ++ RootDir,
+ Status2 = reltool_utils:return_first_error(Status, Text),
{Apps, Status2}
end.
@@ -1327,21 +1635,31 @@ libs_to_dirs(RootDir, LibDirs, Status) ->
[] ->
Fun = fun(Base) ->
AppDir = filename:join([RootLibDir, Base]),
- case filelib:is_dir(filename:join([AppDir, "ebin"]), erl_prim_loader) of
+ case filelib:is_dir(filename:join([AppDir,
+ "ebin"]),
+ erl_prim_loader) of
true ->
AppDir;
false ->
- filename:join([RootDir, Base, "preloaded"])
+ filename:join([RootDir,
+ Base,
+ "preloaded"])
end
end,
- ErtsFiles = [{erts, Fun(F)} || F <- RootFiles, lists:prefix("erts", F)],
+ ErtsFiles = [{erts, Fun(F)} || F <- RootFiles,
+ lists:prefix("erts", F)],
app_dirs2(AllLibDirs, [ErtsFiles], Status);
[Duplicate | _] ->
- {[], reltool_utils:return_first_error(Status, "Duplicate library: " ++ Duplicate)}
+ {[],
+ reltool_utils:return_first_error(Status,
+ "Duplicate library: " ++
+ Duplicate)}
end;
{error, Reason} ->
Text = file:format_error(Reason),
- {[], reltool_utils:return_first_error(Status, "Missing root library " ++ RootDir ++ ": " ++ Text)}
+ {[], reltool_utils:return_first_error(Status,
+ "Missing root library " ++
+ RootDir ++ ": " ++ Text)}
end.
app_dirs2([Lib | Libs], Acc, Status) ->
@@ -1352,8 +1670,9 @@ app_dirs2([Lib | Libs], Acc, Status) ->
AppDir = filename:join([Lib, Base]),
EbinDir = filename:join([AppDir, "ebin"]),
case filelib:is_dir(EbinDir, erl_prim_loader) of
- true ->
- {Name, _Vsn} = reltool_utils:split_app_name(Base),
+ true ->
+ {Name, _Vsn} =
+ reltool_utils:split_app_name(Base),
case Name of
erts -> false;
_ -> {true, {Name, AppDir}}
@@ -1366,7 +1685,9 @@ app_dirs2([Lib | Libs], Acc, Status) ->
app_dirs2(Libs, [Files2 | Acc], Status);
{error, Reason} ->
Text = file:format_error(Reason),
- {[], reltool_utils:return_first_error(Status, "Illegal library " ++ Lib ++ ": " ++ Text)}
+ {[], reltool_utils:return_first_error(Status,
+ "Illegal library " ++
+ Lib ++ ": " ++ Text)}
end;
app_dirs2([], Acc, Status) ->
{lists:sort(lists:append(Acc)), Status}.
@@ -1380,17 +1701,29 @@ escripts_to_apps([Escript | Escripts], Apps, OldApps, Status) ->
[AppLabel, "ebin", File] ->
case filename:extension(File) of
".app" ->
- {AppName, DefaultVsn} = reltool_utils:split_app_name(AppLabel),
- AppFileName = filename:join([Escript, FullName]),
+ {AppName, DefaultVsn} =
+ reltool_utils:split_app_name(AppLabel),
+ AppFileName =
+ filename:join([Escript, FullName]),
{Info, StatusAcc2} =
- read_app_info(GetBin(), AppFileName, AppName, DefaultVsn, Status),
+ read_app_info(GetBin(),
+ AppFileName,
+ AppName,
+ DefaultVsn,
+ Status),
Dir = filename:join([Escript, AppName]),
- {[{AppName, app, Dir, Info} | FileAcc], StatusAcc2};
+ {[{AppName, app, Dir, Info} | FileAcc],
+ StatusAcc2};
E when E =:= Ext ->
- {AppName, _} = reltool_utils:split_app_name(AppLabel),
- Mod = init_mod(AppName, File, {File, GetBin()}, Ext),
+ {AppName, _} =
+ reltool_utils:split_app_name(AppLabel),
+ Mod = init_mod(AppName,
+ File,
+ {File, GetBin()},
+ Ext),
Dir = filename:join([Escript, AppName]),
- {[{AppName, mod, Dir, Mod} | FileAcc], StatusAcc};
+ {[{AppName, mod, Dir, Mod} | FileAcc],
+ StatusAcc};
_ ->
{FileAcc, StatusAcc}
end;
@@ -1398,13 +1731,21 @@ escripts_to_apps([Escript | Escripts], Apps, OldApps, Status) ->
Bin = GetBin(),
{ok, {ModName, _}} = beam_lib:version(Bin),
ModStr = atom_to_list(ModName) ++ Ext,
- Mod = init_mod(EscriptAppName, ModStr, {ModStr, GetBin()}, Ext),
- {[{EscriptAppName, mod, Escript, Mod} | FileAcc], StatusAcc};
+ Mod = init_mod(EscriptAppName,
+ ModStr,
+ {ModStr, GetBin()},
+ Ext),
+ {[{EscriptAppName, mod, Escript, Mod} | FileAcc],
+ StatusAcc};
[File] ->
case filename:extension(File) of
E when E =:= Ext ->
- Mod = init_mod(EscriptAppName, File, {File, GetBin()}, Ext),
- {[{EscriptAppName, mod, File, Mod} | FileAcc], StatusAcc};
+ Mod = init_mod(EscriptAppName,
+ File,
+ {File, GetBin()},
+ Ext),
+ {[{EscriptAppName, mod, File, Mod} | FileAcc],
+ StatusAcc};
_ ->
{FileAcc, StatusAcc}
end;
@@ -1412,71 +1753,111 @@ escripts_to_apps([Escript | Escripts], Apps, OldApps, Status) ->
{FileAcc, StatusAcc}
end
end,
- try
- case escript:foldl(Fun, {[], Status}, Escript) of
- {ok, {Files, Status2}} ->
- {Apps2, Status3} = files_to_apps(Escript, lists:sort(Files), Apps, Apps, OldApps, Status2),
- escripts_to_apps(Escripts, Apps2, OldApps, Status3);
- {error, Reason} ->
- Text = lists:flatten(io_lib:format("~p", [Reason])),
- {[], reltool_utils:return_first_error(Status, "Illegal escript " ++ Escript ++ ": " ++ Text)}
- end
- catch
- throw:Reason2 when is_list(Reason2) ->
- {[], reltool_utils:return_first_error(Status, "Illegal escript " ++ Escript ++ ": " ++ Reason2)}
+ case reltool_utils:escript_foldl(Fun, {[], Status}, Escript) of
+ {ok, {Files, Status2}} ->
+ {Apps2, Status3} =
+ files_to_apps(Escript,
+ lists:sort(Files),
+ Apps,
+ Apps,
+ OldApps,
+ Status2),
+ escripts_to_apps(Escripts, Apps2, OldApps, Status3);
+ {error, Reason} ->
+ Text = lists:flatten(io_lib:format("~p", [Reason])),
+ {[], reltool_utils:return_first_error(Status,
+ "Illegal escript " ++
+ Escript ++ ": " ++ Text)}
end;
escripts_to_apps([], Apps, _OldApps, 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) ->
+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);
+ {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);
+ files_to_apps(Escript,
+ Files,
+ [App2 | Acc2],
+ Apps,
+ OldApps,
+ Status);
[App | Acc2] ->
- PrevApp = App#app{mods = lists:keysort(#mod.name, App#app.mods)},
+ 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)
+ {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),
+ {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) ->
- case lists:keysearch(AppName, #app.name, OldApps) of
- {value, App} ->
- ok;
- false ->
- App = default_app(AppName, Dir)
- end,
- App2 = App#app{is_escript = true,
- label = filename:basename(Dir, ".escript"),
- info = Info,
- mods = Mods,
- active_dir = Dir,
- sorted_dirs = [Dir]},
- case lists:keysearch(AppName, #app.name, Apps) of
- {value, _} ->
+ App1 = case lists:keyfind(AppName, #app.name, OldApps) of
+ #app{} = App ->
+ App;
+ false ->
+ default_app(AppName, Dir)
+ end,
+ App2 = App1#app{is_escript = true,
+ label = filename:basename(Dir, ".escript"),
+ info = Info,
+ mods = Mods,
+ active_dir = Dir,
+ sorted_dirs = [Dir]},
+ case lists:keymember(AppName, #app.name, Apps) of
+ true ->
Error = lists:concat([AppName, ": Application name clash. ",
- "Escript ", Dir," contains application ", AppName, "."]),
+ "Escript ", Dir," contains application ",
+ AppName, "."]),
{App2, reltool_utils:return_first_error(Status, Error)};
false ->
{App2, Status}
end.
-merge_app_dirs([{Name, Dir} | Rest], [App | Apps], OldApps)
+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]},
@@ -1485,25 +1866,26 @@ merge_app_dirs([{Name, Dir} | Rest], Apps, OldApps) ->
%% Initate app
Apps2 = sort_app_dirs(Apps),
Apps4 =
- case lists:keysearch(Name, #app.name, Apps) of
+ case lists:keyfind(Name, #app.name, Apps) of
false ->
- case lists:keysearch(Name, #app.name, OldApps) of
- {value, OldApp} when OldApp#app.active_dir =:= Dir ->
+ case lists:keyfind(Name, #app.name, OldApps) of
+ false ->
+ App = default_app(Name, Dir),
+ [App | Apps2];
+ #app{active_dir = Dir} = OldApp ->
[OldApp | Apps2];
- {value, OldApp} ->
- App =
+ OldApp ->
+ App =
case filter_app(OldApp) of
{true, NewApp} ->
- NewApp#app{active_dir = Dir, sorted_dirs = [Dir]};
+ NewApp#app{active_dir = Dir,
+ sorted_dirs = [Dir]};
false ->
default_app(Name, Dir)
end,
- [App | Apps2];
- false ->
- App = default_app(Name, Dir),
[App | Apps2]
end;
- {value, OldApp} ->
+ OldApp ->
Apps3 = lists:keydelete(Name, #app.name, Apps2),
App = OldApp#app{sorted_dirs = [Dir | OldApp#app.sorted_dirs]},
[App | Apps3]
@@ -1545,12 +1927,14 @@ 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) when New#app.name =:= Old#app.name ->
+%% 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 =
+ OptLabel =
case Info#app_info.vsn =:= New#app.vsn of
true -> New#app.label;
false -> undefined % Cause refresh
@@ -1559,23 +1943,28 @@ refresh_apps([Old | OldApps], [New | NewApps], Acc, Force, Status) when New#app.
refresh_app(New#app{label = OptLabel,
active_dir = ActiveDir,
vsn = Info#app_info.vsn,
- info = Info},
+ 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 ->
+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 ->
+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 ->
- Warning = lists:concat([Old#app.name, ": The source dirs does not contain the application anymore."]),
+ 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);
@@ -1586,25 +1975,32 @@ 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 ->
- Warning = lists:concat([Old#app.name, ": The source dirs ",
- "does not contain the application anymore."]),
+ 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) ->
{lists:reverse(Acc), Status}.
-ensure_app_info(#app{is_escript = true, active_dir = Dir, info = Info}, Status) ->
+ensure_app_info(#app{is_escript = true, active_dir = Dir, info = Info},
+ Status) ->
{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, vsn = Vsn, sorted_dirs = Dirs, info = undefined}, Status) ->
+ensure_app_info(#app{name = Name,
+ vsn = Vsn,
+ sorted_dirs = Dirs,
+ info = undefined},
+ Status) ->
ReadInfo =
fun(Dir, StatusAcc) ->
Base = get_base(Name, Dir),
@@ -1621,8 +2017,10 @@ ensure_app_info(#app{name = Name, vsn = Vsn, sorted_dirs = Dirs, info = undefine
%% No redundant info
Status2;
[BadVsn | _] ->
- Error2 = lists:concat([Name, ": Application version clash. ",
- "Multiple directories contains version \"", BadVsn, "\"."]),
+ Error2 =
+ lists:concat([Name, ": Application version clash. ",
+ "Multiple directories contains version \"",
+ BadVsn, "\"."]),
reltool_utils:return_first_error(Status2, Error2)
end,
FirstInfo = hd(AllInfo),
@@ -1637,7 +2035,11 @@ ensure_app_info(#app{name = Name, vsn = Vsn, sorted_dirs = Dirs, info = undefine
{Info, VsnDir} ->
{Info, VsnDir, Status3};
false ->
- Error3 = lists:concat([Name, ": No application directory contains selected version \"", Vsn, "\"."]),
+ Error3 =
+ lists:concat([Name,
+ ": No application directory contains ",
+ "selected version \"",
+ Vsn, "\"."]),
Status4 = reltool_utils:return_first_error(Status3, Error3),
{FirstInfo, FirstDir, Status4}
end
diff --git a/lib/reltool/src/reltool_sys_win.erl b/lib/reltool/src/reltool_sys_win.erl
index ea80ab7e85..8b0f64eb45 100644
--- a/lib/reltool/src/reltool_sys_win.erl
+++ b/lib/reltool/src/reltool_sys_win.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2009-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%
-module(reltool_sys_win).
@@ -34,7 +34,7 @@
-include_lib("wx/include/wx.hrl").
-include("reltool.hrl").
--record(state,
+-record(state,
{parent_pid,
server_pid,
app_wins,
@@ -54,14 +54,16 @@
whitelist,
blacklist,
derived,
- fgraph_wins
+ fgraph_wins,
+ app_box,
+ mod_box
}).
-define(WIN_WIDTH, 800).
-define(WIN_HEIGHT, 600).
-define(CLOSE_ITEM, ?wxID_EXIT). %% Use OS specific version if available
--define(ABOUT_ITEM, ?wxID_ABOUT). %% Use OS specific
+-define(ABOUT_ITEM, ?wxID_ABOUT). %% Use OS specific
-define(CONTENTS_ITEM, 300).
-define(APP_GRAPH_ITEM, 301).
-define(MOD_GRAPH_ITEM, 302).
@@ -86,6 +88,11 @@
-define(blacklist, "Excluded").
-define(derived, "Derived").
+-define(safe_config,{sys,[{incl_cond,exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]}]}).
+
-record(root_data, {dir}).
-record(lib_data, {dir, tree, item}).
-record(escript_data, {file, tree, item}).
@@ -100,7 +107,11 @@
%% Client
start_link(Opts) ->
- proc_lib:start_link(?MODULE, init, [[{parent, self()} | Opts]], infinity, []).
+ proc_lib:start_link(?MODULE,
+ init,
+ [[{safe_config, false}, {parent, self()} | Opts]],
+ infinity,
+ []).
get_server(Pid) ->
reltool_utils:call(Pid, get_server).
@@ -122,49 +133,73 @@ init(Options) ->
exit({Reason, erlang:get_stacktrace()})
end.
-do_init([{parent, Parent} | Options]) ->
+do_init([{safe_config, Safe}, {parent, Parent} | Options]) ->
case reltool_server:start_link(Options) of
{ok, ServerPid, C, Sys} ->
process_flag(trap_exit, C#common.trap_exit),
- 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 = []},
wx:new(),
wx:debug(C#common.wx_debug),
- S2 = create_window(S),
%% wx_misc:beginBusyCursor(),
case reltool_server:get_status(ServerPid) of
{ok, Warnings} ->
exit_dialog(Warnings),
- {ok, Sys2} = reltool_server:get_sys(ServerPid),
- S3 = S2#state{sys = Sys2},
+ {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(S3#state.frame, Title),
- %% wxFrame:setMinSize(Frame, {?WIN_WIDTH, ?WIN_HEIGHT}),
- wxStatusBar:setStatusText(S3#state.status_bar, "Done."),
- S4 = redraw_apps(S3),
- redraw_libs(S4)
+ 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;
{error, Reason} ->
io:format("~p(~p): <ERROR> ~p\n", [?MODULE, ?LINE, Reason]),
exit(Reason)
end.
+restart_server_safe_config(true,_Parent,Reason) ->
+ io:format("~p(~p): <ERROR> ~p\n", [?MODULE, ?LINE, Reason]),
+ exit(Reason);
+restart_server_safe_config(false,Parent,Reason) ->
+ Strings =
+ [{?wxBLACK,"Could not start reltool server:\n\n"},
+ {?wxRED,Reason++"\n\n"},
+ {?wxBLACK,
+ io_lib:format(
+ "Resetting the configuration to:~n~n ~p~n~n"
+ "Do you want to continue with this configuration?",
+ [?safe_config])}],
+
+ case question_dialog_2("Reltool server start error", Strings) of
+ ?wxID_OK ->
+ do_init([{safe_config,true},{parent,Parent},?safe_config]);
+ ?wxID_CANCEL ->
+ io:format("~p(~p): <ERROR> ~p\n", [?MODULE, ?LINE, Reason]),
+ exit(Reason)
+ end.
+
exit_dialog([]) ->
ok;
exit_dialog(Warnings) ->
@@ -182,7 +217,12 @@ loop(S) ->
receive
{system, From, Msg} ->
Common = S#state.common,
- sys:handle_system_msg(Msg, From, S#state.parent_pid, ?MODULE, Common#common.sys_debug, S);
+ sys:handle_system_msg(Msg,
+ From,
+ S#state.parent_pid,
+ ?MODULE,
+ Common#common.sys_debug,
+ S);
#wx{obj = ObjRef,
event = #wxClose{type = close_window}} = Msg ->
if
@@ -193,17 +233,22 @@ loop(S) ->
FWs = S#state.fgraph_wins,
case lists:keysearch(ObjRef, #fgraph_win.frame, FWs) of
{value, FW} ->
- reltool_fgraph_win:stop(FW#fgraph_win.pid, shutdown),
+ reltool_fgraph_win:stop(FW#fgraph_win.pid,
+ shutdown),
wxFrame:destroy(ObjRef),
- FWs2 = lists:keydelete(ObjRef, #fgraph_win.frame, FWs),
+ FWs2 =
+ 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]),
+ error_logger:format("~p~p got unexpected "
+ "message:\n\t~p\n",
+ [?MODULE, self(), Msg]),
?MODULE:loop(S)
end
end;
- #wx{id = ?CLOSE_ITEM, event = #wxCommand{type = command_menu_selected}, userData = main_window} ->
+ #wx{id = ?CLOSE_ITEM,
+ event = #wxCommand{type = command_menu_selected},
+ userData = main_window} ->
wxFrame:destroy(S#state.frame),
exit(shutdown);
#wx{event = #wxSize{}} = Wx ->
@@ -222,14 +267,18 @@ loop(S) ->
?MODULE:loop(S2);
{call, ReplyTo, Ref, {open_app, AppName}} ->
S2 = do_open_app(S, AppName),
- {value, #app_win{pid = AppPid}} = lists:keysearch(AppName, #app_win.name, S2#state.app_wins),
+ {value, #app_win{pid = AppPid}} =
+ lists:keysearch(AppName, #app_win.name, S2#state.app_wins),
reltool_utils:reply(ReplyTo, Ref, {ok, AppPid}),
?MODULE:loop(S2);
{'EXIT', Pid, Reason} when Pid =:= S#state.parent_pid ->
- [reltool_fgraph_win:stop(FW#fgraph_win.pid, Reason) || FW <- S#state.fgraph_wins],
+ [reltool_fgraph_win:stop(FW#fgraph_win.pid, Reason) ||
+ FW <- S#state.fgraph_wins],
exit(Reason);
{'EXIT', _Pid, _Reason} = Exit ->
- {FWs, AWs} = handle_child_exit(Exit, S#state.fgraph_wins, S#state.app_wins),
+ {FWs, AWs} = handle_child_exit(Exit,
+ S#state.fgraph_wins,
+ S#state.app_wins),
?MODULE:loop(S#state{fgraph_wins = FWs, app_wins = AWs});
Msg ->
error_logger:format("~p~p got unexpected message:\n\t~p\n",
@@ -261,7 +310,8 @@ msg_warning(Exit, Type) ->
create_window(S) ->
Title = lists:concat([?APPLICATION, " - starting up"]),
- Frame = wxFrame:new(wx:null(), ?wxID_ANY, Title, [{size, {?WIN_WIDTH, ?WIN_HEIGHT}}]),
+ Frame = wxFrame:new(wx:null(), ?wxID_ANY, Title,
+ [{size, {?WIN_WIDTH, ?WIN_HEIGHT}}]),
%%wxFrame:setSize(Frame, {?WIN_WIDTH, ?WIN_HEIGHT}),
%% wxFrame:setMinSize(Frame, {?WIN_WIDTH, ?WIN_HEIGHT}),
Bar = wxFrame:createStatusBar(Frame,[]),
@@ -306,21 +356,29 @@ create_menubar(Frame) ->
File = wxMenu:new([]),
Help = wxMenu:new([]),
wxMenuBar:append(MenuBar, File, "File" ),
- wxMenu:append(File, ?APP_GRAPH_ITEM, "Display application dependency graph" ),
- wxMenu:append(File, ?MOD_GRAPH_ITEM, "Display module dependency graph" ),
+ wxMenu:append(File, ?APP_GRAPH_ITEM,
+ "Display application dependency graph" ),
+ wxMenu:append(File, ?MOD_GRAPH_ITEM,
+ "Display module dependency graph" ),
wxMenu:appendSeparator(File),
wxMenu:append(File, ?RESET_CONFIG_ITEM, "Reset configuration to default" ),
wxMenu:append(File, ?UNDO_CONFIG_ITEM, "Undo configuration (toggle)" ),
wxMenu:append(File, ?LOAD_CONFIG_ITEM, "Load configuration" ),
Save = wxMenu:new(),
- wxMenu:append(Save, ?SAVE_CONFIG_NODEF_NODER_ITEM, "Save explicit configuration (neither defaults nor derivates)"),
- wxMenu:append(Save, ?SAVE_CONFIG_DEF_NODER_ITEM , "Save configuration defaults (defaults only)"),
- wxMenu:append(Save, ?SAVE_CONFIG_NODEF_DER_ITEM, "Save configuration derivates (derivates only))"),
- wxMenu:append(Save, ?SAVE_CONFIG_DEF_DER_ITEM, "Save extended configuration (both defaults and derivates)"),
+ wxMenu:append(Save, ?SAVE_CONFIG_NODEF_NODER_ITEM,
+ "Save explicit configuration "
+ "(neither defaults nor derivates)"),
+ wxMenu:append(Save, ?SAVE_CONFIG_DEF_NODER_ITEM,
+ "Save configuration defaults (defaults only)"),
+ wxMenu:append(Save, ?SAVE_CONFIG_NODEF_DER_ITEM,
+ "Save configuration derivates (derivates only))"),
+ wxMenu:append(Save, ?SAVE_CONFIG_DEF_DER_ITEM,
+ "Save extended configuration (both defaults and derivates)"),
wxMenu:append(File, ?wxID_ANY, "Save configuration", Save),
wxMenu:appendSeparator(File),
- wxMenu:append(File, ?GEN_REL_FILES_ITEM, "Generate rel, script and boot files" ),
+ wxMenu:append(File, ?GEN_REL_FILES_ITEM,
+ "Generate rel, script and boot files" ),
wxMenu:append(File, ?GEN_TARGET_ITEM, "Generate target system" ),
wxMenu:appendSeparator(File),
wxMenu:append(File, ?CLOSE_ITEM, "Close" ),
@@ -375,12 +433,13 @@ create_app_list_ctrl(Panel, OuterSz, Title, Tick, Cross) ->
%% ?wxLC_SINGLE_SEL bor
?wxVSCROLL},
{size, {Width, Height}}]),
- ToolTip = "Select application(s) or open separate application window with a double click.",
+ ToolTip = "Select application(s) or open separate "
+ "application window with a double click.",
wxListCtrl:setToolTip(ListCtrl, ToolTip),
%% Prep images
reltool_utils:assign_image_list(ListCtrl),
-
+
%% Prep column label
ListItem = wxListItem:new(),
wxListItem:setAlign(ListItem, ?wxLIST_FORMAT_LEFT),
@@ -395,7 +454,7 @@ create_app_list_ctrl(Panel, OuterSz, Title, Tick, Cross) ->
InnerSz = wxBoxSizer:new(?wxVERTICAL),
- wxSizer:add(InnerSz,
+ wxSizer:add(InnerSz,
ListCtrl,
[{border, 2},
{flag, ?wxALL bor ?wxEXPAND},
@@ -408,9 +467,10 @@ create_app_list_ctrl(Panel, OuterSz, Title, Tick, Cross) ->
[{flag, ?wxEXPAND}, {proportion, 1}]),
%% Subscribe on events
- wxEvtHandler:connect(ListCtrl, size, [{skip, true}, {userData, app_list_ctrl}]),
+ wxEvtHandler:connect(ListCtrl, size,
+ [{skip, true}, {userData, app_list_ctrl}]),
wxEvtHandler:connect(ListCtrl, command_list_item_activated),
- wxWindow:connect(ListCtrl, enter_window),
+ wxWindow:connect(ListCtrl, enter_window),
ListCtrl.
@@ -423,7 +483,7 @@ create_button(Panel, Sizer, ListCtrl, Title, BitMapName, Action) ->
wxBitmapButton:setToolTip(Button, ToolTip),
Options = [{userData, {app_button, Action, ListCtrl}}],
wxEvtHandler:connect(Button, command_button_clicked, Options),
- wxSizer:add(Sizer,
+ wxSizer:add(Sizer,
Button,
[{border, 2},
{flag, ?wxALL},
@@ -439,7 +499,7 @@ action_to_tool_tip(Label, Action) ->
"Remove selected application(s)from whitelist.";
blacklist_add when Label =:= ?blacklist ->
"Remove selected application(s) from blacklist.";
- blacklist_add ->
+ blacklist_add ->
"Add selected application(s) to blacklist.";
blacklist_del ->
"Remove selected application(s) from blacklist."
@@ -448,8 +508,9 @@ action_to_tool_tip(Label, Action) ->
create_lib_page(#state{book = Book} = S) ->
Panel = wxPanel:new(Book, []),
Sizer = wxBoxSizer:new(?wxHORIZONTAL),
-
- Tree = wxTreeCtrl:new(Panel, [{style , ?wxTR_HAS_BUTTONS bor ?wxTR_HIDE_ROOT}]),
+
+ Tree = wxTreeCtrl:new(Panel,
+ [{style , ?wxTR_HAS_BUTTONS bor ?wxTR_HIDE_ROOT}]),
ToolTip = "Edit application sources.",
wxBitmapButton:setToolTip(Tree, ToolTip),
@@ -478,7 +539,9 @@ redraw_libs(#state{lib_tree = Tree, sys = Sys} = S) ->
[append_lib(Tree, LibItem, Dir) || Dir <- Sys#sys.lib_dirs],
EscriptItem = append_item(Tree, Top, "Escript files", undefined),
- EscriptData = #escript_data{file = undefined, tree = Tree, item = EscriptItem},
+ EscriptData = #escript_data{file = undefined,
+ tree = Tree,
+ item = EscriptItem},
wxTreeCtrl:setItemData(Tree,EscriptItem, EscriptData),
[append_escript(Tree, EscriptItem, File) || File <- Sys#sys.escripts],
wxTreeCtrl:expand(Tree, LibItem),
@@ -529,9 +592,9 @@ create_config_page(#state{sys = Sys, book = Book} = S) ->
Panel = wxPanel:new(Book, []),
Sizer = wxBoxSizer:new(?wxHORIZONTAL),
AppConds = reltool_utils:incl_conds(),
- AppBox = wxRadioBox:new(Panel,
+ AppBox = wxRadioBox:new(Panel,
?wxID_ANY,
- "Application inclusion policy",
+ "Application inclusion policy",
?wxDefaultPosition,
?wxDefaultSize,
AppConds,
@@ -543,9 +606,9 @@ create_config_page(#state{sys = Sys, book = Book} = S) ->
wxEvtHandler:connect(AppBox, command_radiobox_selected,
[{userData, config_incl_cond}]),
ModConds = reltool_utils:mod_conds(),
- ModBox = wxRadioBox:new(Panel,
+ ModBox = wxRadioBox:new(Panel,
?wxID_ANY,
- "Module inclusion policy",
+ "Module inclusion policy",
?wxDefaultPosition,
?wxDefaultSize,
ModConds,
@@ -570,6 +633,13 @@ create_config_page(#state{sys = Sys, book = Book} = S) ->
{proportion, 1}]),
wxPanel:setSizer(Panel, Sizer),
wxNotebook:addPage(Book, Panel, ?SYS_PAGE, []),
+ S#state{app_box = AppBox, mod_box = ModBox}.
+
+redraw_config_page(#state{sys = Sys, app_box = AppBox, mod_box = ModBox} = S) ->
+ AppChoice = reltool_utils:incl_cond_to_index(Sys#sys.incl_cond),
+ wxRadioBox:setSelection(AppBox, AppChoice),
+ ModChoice = reltool_utils:mod_cond_to_index(Sys#sys.mod_cond),
+ wxRadioBox:setSelection(ModBox, ModChoice),
S.
create_main_release_page(#state{book = Book} = S) ->
@@ -582,19 +652,19 @@ create_main_release_page(#state{book = Book} = S) ->
wxButton:setToolTip(Create, "Create a new release."),
wxButton:connect(Create, command_button_clicked, [{userData, create_rel}]),
wxSizer:add(ButtonSizer, Create),
-
+
Delete = wxButton:new(Panel, ?wxID_ANY, [{label, "Delete"}]),
wxButton:setToolTip(Delete, "Delete a release."),
wxButton:connect(Delete, command_button_clicked, [{userData, delete_rel}]),
wxSizer:add(ButtonSizer, Delete),
-
+
View = wxButton:new(Panel, ?wxID_ANY, [{label, "View script"}]),
wxButton:setToolTip(View, "View generated script file."),
wxButton:connect(View, command_button_clicked, [{userData, view_script}]),
wxSizer:add(ButtonSizer, View),
[add_release_page(RelBook, Rel) || Rel <- (S#state.sys)#sys.rels],
-
+
wxSizer:add(Sizer, RelBook, [{flag, ?wxEXPAND}, {proportion, 1}]),
wxSizer:add(Sizer, ButtonSizer, [{flag, ?wxEXPAND}]),
wxPanel:setSizer(Panel, Sizer),
@@ -604,16 +674,18 @@ create_main_release_page(#state{book = Book} = S) ->
add_release_page(Book, #rel{name = RelName, rel_apps = RelApps}) ->
Panel = wxPanel:new(Book, []),
Sizer = wxBoxSizer:new(?wxHORIZONTAL),
- RelBox = wxRadioBox:new(Panel,
- ?wxID_ANY,
- "Applications included in the release " ++ RelName,
- ?wxDefaultPosition,
- ?wxDefaultSize,
- [atom_to_list(RA#rel_app.name) || RA <- RelApps],
- []),
- %% wxRadioBox:setSelection(RelBox, 2), % mandatory
- wxEvtHandler:connect(RelBox, command_radiobox_selected, [{userData, {config_rel_cond, RelName}}]),
- RelToolTip = "Choose which applications that shall be included in the release resource file.",
+ AppNames = [kernel, stdlib |
+ [RA#rel_app.name || RA <- RelApps] -- [kernel, stdlib]],
+ RelBox = wxListBox:new(
+ Panel,?wxID_ANY,
+ [{pos,?wxDefaultPosition},
+ {size,?wxDefaultSize},
+ {choices,[[atom_to_list(AppName)] || AppName <- AppNames]},
+ {style,?wxLB_EXTENDED}]),
+ wxEvtHandler:connect(RelBox, command_listbox_selected,
+ [{userData, {config_rel_cond, RelName}}]),
+ RelToolTip = "Choose which applications that shall "
+ "be included in the release resource file.",
wxBitmapButton:setToolTip(RelBox, RelToolTip),
wxSizer:add(Sizer,
@@ -629,11 +701,14 @@ do_open_app(S, AppBase) when is_list(AppBase) ->
do_open_app(S, AppName);
do_open_app(S, '') ->
S;
-do_open_app(#state{server_pid = ServerPid, common = C, app_wins = AppWins} = S, AppName) when is_atom(AppName) ->
+do_open_app(#state{server_pid = ServerPid, common = C, app_wins = AppWins} = S,
+ AppName)
+ when is_atom(AppName) ->
case lists:keysearch(AppName, #app_win.name, AppWins) of
false ->
WxEnv = wx:get_env(),
- {ok, Pid} = reltool_app_win:start_link(WxEnv, ServerPid, C, AppName),
+ {ok, Pid} =
+ reltool_app_win:start_link(WxEnv, ServerPid, C, AppName),
AW = #app_win{name = AppName, pid = Pid},
S#state{app_wins = [AW | AppWins]};
{value, AW} ->
@@ -651,7 +726,10 @@ root_popup(S, Root, Tree, Item) ->
wxEvtHandler:connect(PopupMenu, menu_close),
wxWindow:popupMenu(S#state.frame, PopupMenu),
- Popup = #root_popup{dir = Root, choices = Choices, tree = Tree, item = Item},
+ Popup = #root_popup{dir = Root,
+ choices = Choices,
+ tree = Tree,
+ item = Item},
S#state{popup_menu = Popup}.
lib_popup(S, Lib, Tree, Item) ->
@@ -693,7 +771,10 @@ escript_popup(S, File, Tree, Item) ->
wxEvtHandler:connect(PopupMenu, menu_close),
wxWindow:popupMenu(S#state.frame, PopupMenu),
- Popup = #escript_popup{file = File, choices = Choices, tree = Tree, item = Item},
+ Popup = #escript_popup{file = File,
+ choices = Choices,
+ tree = Tree,
+ item = Item},
S#state{popup_menu = Popup}.
@@ -705,29 +786,40 @@ handle_event(S, #wx{id = Id, obj= ObjRef, userData = UserData, event = Event} =
#wxSize{type = size, size = {W, _H}} when UserData =:= app_list_ctrl ->
wxListCtrl:setColumnWidth(ObjRef, ?APPS_APP_COL, W),
S;
- #wxCommand{type = command_menu_selected} when Id =:= ?APP_GRAPH_ITEM ->
+ #wxCommand{type = command_menu_selected}
+ when Id =:= ?APP_GRAPH_ITEM ->
update_app_graph(S);
- #wxCommand{type = command_menu_selected} when Id =:= ?MOD_GRAPH_ITEM ->
+ #wxCommand{type = command_menu_selected}
+ when Id =:= ?MOD_GRAPH_ITEM ->
update_mod_graph(S);
- #wxCommand{type = command_menu_selected} when Id =:= ?RESET_CONFIG_ITEM ->
+ #wxCommand{type = command_menu_selected}
+ when Id =:= ?RESET_CONFIG_ITEM ->
reset_config(S);
- #wxCommand{type = command_menu_selected} when Id =:= ?UNDO_CONFIG_ITEM ->
+ #wxCommand{type = command_menu_selected}
+ when Id =:= ?UNDO_CONFIG_ITEM ->
undo_config(S);
- #wxCommand{type = command_menu_selected} when Id =:= ?LOAD_CONFIG_ITEM ->
+ #wxCommand{type = command_menu_selected}
+ when Id =:= ?LOAD_CONFIG_ITEM ->
load_config(S);
- #wxCommand{type = command_menu_selected} when Id =:= ?SAVE_CONFIG_NODEF_NODER_ITEM ->
+ #wxCommand{type = command_menu_selected}
+ when Id =:= ?SAVE_CONFIG_NODEF_NODER_ITEM ->
save_config(S, false, false);
- #wxCommand{type = command_menu_selected} when Id =:= ?SAVE_CONFIG_NODEF_DER_ITEM ->
+ #wxCommand{type = command_menu_selected}
+ when Id =:= ?SAVE_CONFIG_NODEF_DER_ITEM ->
save_config(S, false, true);
#wxCommand{type = command_menu_selected} when Id =:= ?SAVE_CONFIG_DEF_NODER_ITEM ->
save_config(S, true, false);
- #wxCommand{type = command_menu_selected} when Id =:= ?SAVE_CONFIG_DEF_DER_ITEM ->
+ #wxCommand{type = command_menu_selected}
+ when Id =:= ?SAVE_CONFIG_DEF_DER_ITEM ->
save_config(S, true, true);
- #wxCommand{type = command_menu_selected} when Id =:= ?GEN_REL_FILES_ITEM ->
+ #wxCommand{type = command_menu_selected}
+ when Id =:= ?GEN_REL_FILES_ITEM ->
gen_rel_files(S);
- #wxCommand{type = command_menu_selected} when Id =:= ?GEN_TARGET_ITEM ->
+ #wxCommand{type = command_menu_selected}
+ when Id =:= ?GEN_TARGET_ITEM ->
gen_target(S);
- #wxCommand{type = command_menu_selected} when UserData =:= main_window, Id =:= ?CONTENTS_ITEM ->
+ #wxCommand{type = command_menu_selected}
+ when UserData =:= main_window, Id =:= ?CONTENTS_ITEM ->
{file, BeamFile} = code:is_loaded(?MODULE),
EbinDir = filename:dirname(BeamFile),
AppDir = filename:dirname(EbinDir),
@@ -735,16 +827,17 @@ handle_event(S, #wx{id = Id, obj= ObjRef, userData = UserData, event = Event} =
Url = "file://" ++ filename:absname(HelpFile),
wx_misc:launchDefaultBrowser(Url),
S;
- #wxCommand{type = command_menu_selected} when UserData =:= main_window, Id =:= ?ABOUT_ITEM ->
- AboutStr = "Reltool is a release management tool. It analyses a given"
- " Erlang/OTP installation and determines various dependencies"
- " between applications. The graphical frontend depicts the"
- " dependencies and enables interactive customization of a"
- " target system. The backend provides a batch interface"
- " for generation of customized target systems.",
- MD = wxMessageDialog:new(S#state.frame,
+ #wxCommand{type = command_menu_selected}
+ when UserData =:= main_window, Id =:= ?ABOUT_ITEM ->
+ AboutStr = "Reltool is a release management tool. It analyses a "
+ " given Erlang/OTP installation and determines various "
+ " dependencies between applications. The graphical frontend "
+ " depicts the dependencies and enables interactive "
+ " customization of a target system. The backend provides a "
+ " batch interface for generation of customized target systems.",
+ MD = wxMessageDialog:new(S#state.frame,
AboutStr,
- [{style, ?wxOK bor ?wxICON_INFORMATION},
+ [{style, ?wxOK bor ?wxICON_INFORMATION},
{caption, "About Reltool"}]),
wxMessageDialog:showModal(MD),
wxMessageDialog:destroy(MD),
@@ -758,7 +851,8 @@ handle_event(S, #wx{id = Id, obj= ObjRef, userData = UserData, event = Event} =
wxWindow:setFocus(ObjRef),
S;
_ ->
- case wxNotebook:getPageText(S#state.book, wxNotebook:getSelection(S#state.book)) of
+ case wxNotebook:getPageText(S#state.book,
+ wxNotebook:getSelection(S#state.book)) of
?APP_PAGE -> handle_app_event(S, Event, ObjRef, UserData);
?LIB_PAGE -> handle_source_event(S, Event, ObjRef, UserData);
?SYS_PAGE -> handle_system_event(S, Event, ObjRef, UserData);
@@ -768,13 +862,17 @@ handle_event(S, #wx{id = Id, obj= ObjRef, userData = UserData, event = Event} =
handle_popup_event(S, _Type, 0, _ObjRef, _UserData, _Str) ->
S#state{popup_menu = undefined};
-handle_popup_event(#state{popup_menu = #root_popup{dir = OldDir, choices = Choices},
+handle_popup_event(#state{popup_menu = #root_popup{dir = OldDir,
+ choices = Choices},
sys = Sys} = S,
_Type, Pos, _ObjRef, _UserData, _Str) ->
case lists:nth(Pos, Choices) of
edit ->
Style = ?wxFD_OPEN bor ?wxFD_FILE_MUST_EXIST,
- case select_dir(S#state.frame, "Change root directory", OldDir, Style) of
+ case select_dir(S#state.frame,
+ "Change root directory",
+ OldDir,
+ Style) of
{ok, NewDir} when NewDir =:= OldDir ->
%% Same dir.Ignore.
S#state{popup_menu = undefined};
@@ -785,7 +883,8 @@ handle_popup_event(#state{popup_menu = #root_popup{dir = OldDir, choices = Choic
S#state{popup_menu = undefined}
end
end;
-handle_popup_event(#state{popup_menu = #lib_popup{dir = OldDir, choices = Choices},
+handle_popup_event(#state{popup_menu = #lib_popup{dir = OldDir,
+ choices = Choices},
sys = Sys} = S,
_Type, Pos, _ObjRef, _UserData, _Str) ->
case lists:nth(Pos, Choices) of
@@ -801,14 +900,18 @@ handle_popup_event(#state{popup_menu = #lib_popup{dir = OldDir, choices = Choice
false ->
LibDirs = Sys#sys.lib_dirs ++ [NewDir],
Sys2 = Sys#sys{lib_dirs = LibDirs},
- do_set_sys(S#state{popup_menu = undefined, sys = Sys2})
+ do_set_sys(S#state{popup_menu = undefined,
+ sys = Sys2})
end;
cancel ->
S#state{popup_menu = undefined}
end;
edit ->
Style = ?wxFD_OPEN bor ?wxFD_FILE_MUST_EXIST,
- case select_dir(S#state.frame, "Change library directory", OldDir, Style) of
+ case select_dir(S#state.frame,
+ "Change library directory",
+ OldDir,
+ Style) of
{ok, NewDir} ->
case lists:member(NewDir, Sys#sys.lib_dirs) of
true ->
@@ -820,7 +923,8 @@ handle_popup_event(#state{popup_menu = #lib_popup{dir = OldDir, choices = Choice
lists:splitwith(Pred, Sys#sys.lib_dirs),
LibDirs2 = Before ++ [NewDir | After],
Sys2 = Sys#sys{lib_dirs = LibDirs2},
- do_set_sys(S#state{popup_menu = undefined, sys = Sys2})
+ do_set_sys(S#state{popup_menu = undefined,
+ sys = Sys2})
end;
cancel ->
S#state{popup_menu = undefined}
@@ -828,14 +932,15 @@ handle_popup_event(#state{popup_menu = #lib_popup{dir = OldDir, choices = Choice
delete ->
LibDirs = Sys#sys.lib_dirs -- [OldDir],
Sys2 = Sys#sys{lib_dirs = LibDirs},
- do_set_sys(S#state{popup_menu = undefined, sys = Sys2})
+ do_set_sys(S#state{popup_menu = undefined, sys = Sys2})
end;
-handle_popup_event(#state{popup_menu = #escript_popup{file = OldFile, choices = Choices},
+handle_popup_event(#state{popup_menu = #escript_popup{file = OldFile,
+ choices = Choices},
sys = Sys} = S,
_Type, Pos, _ObjRef, _UserData, _Str) ->
case lists:nth(Pos, Choices) of
add ->
- OldFile2 =
+ OldFile2 =
case OldFile of
undefined ->
{ok, Cwd} = file:get_cwd(),
@@ -844,7 +949,10 @@ handle_popup_event(#state{popup_menu = #escript_popup{file = OldFile, choices =
OldFile
end,
Style = ?wxFD_OPEN bor ?wxFD_FILE_MUST_EXIST,
- case select_file(S#state.frame, "Select an escript file to add", OldFile2, Style) of
+ case select_file(S#state.frame,
+ "Select an escript file to add",
+ OldFile2,
+ Style) of
{ok, NewFile} ->
case lists:member(NewFile, Sys#sys.escripts) of
true ->
@@ -860,7 +968,10 @@ handle_popup_event(#state{popup_menu = #escript_popup{file = OldFile, choices =
end;
edit ->
Style = ?wxFD_OPEN bor ?wxFD_FILE_MUST_EXIST,
- case select_file(S#state.frame, "Change escript file name", OldFile, Style) of
+ case select_file(S#state.frame,
+ "Change escript file name",
+ OldFile,
+ Style) of
{ok, NewFile} ->
case lists:member(NewFile, Sys#sys.escripts) of
true ->
@@ -868,10 +979,12 @@ handle_popup_event(#state{popup_menu = #escript_popup{file = OldFile, choices =
S#state{popup_menu = undefined};
false ->
Pred = fun(E) -> E =/= OldFile end,
- {Before, [_| After]} = lists:splitwith(Pred, Sys#sys.escripts),
+ {Before, [_| After]} =
+ lists:splitwith(Pred, Sys#sys.escripts),
Escripts2 = Before ++ [NewFile | After],
Sys2 = Sys#sys{escripts = Escripts2},
- do_set_sys(S#state{popup_menu = undefined, sys = Sys2})
+ do_set_sys(S#state{popup_menu = undefined,
+ sys = Sys2})
end;
cancel ->
S#state{popup_menu = undefined}
@@ -879,25 +992,28 @@ handle_popup_event(#state{popup_menu = #escript_popup{file = OldFile, choices =
delete ->
Escripts = Sys#sys.escripts -- [OldFile],
Sys2 = Sys#sys{escripts = Escripts},
- do_set_sys(S#state{popup_menu = undefined, sys = Sys2})
+ do_set_sys(S#state{popup_menu = undefined, sys = Sys2})
end.
handle_system_event(#state{sys = Sys} = S,
- #wxCommand{type = command_radiobox_selected, cmdString = Choice},
+ #wxCommand{type = command_radiobox_selected,
+ cmdString = Choice},
_ObjRef,
config_mod_cond) ->
ModCond = reltool_utils:list_to_mod_cond(Choice),
Sys2 = Sys#sys{mod_cond = ModCond},
do_set_sys(S#state{sys = Sys2});
handle_system_event(#state{sys = Sys} = S,
- #wxCommand{type = command_radiobox_selected, cmdString = Choice},
+ #wxCommand{type = command_radiobox_selected,
+ cmdString = Choice},
_ObjRef,
config_incl_cond) ->
AppCond = reltool_utils:list_to_incl_cond(Choice),
Sys2 = Sys#sys{incl_cond = AppCond},
do_set_sys(S#state{sys = Sys2});
handle_system_event(S, Event, ObjRef, UserData) ->
- error_logger:format("~p~p got unexpected wx sys event to ~p with user data: ~p\n\t ~p\n",
+ error_logger:format("~p~p got unexpected wx sys event to ~p "
+ "with user data: ~p\n\t ~p\n",
[?MODULE, self(), ObjRef, UserData, Event]),
S.
@@ -905,7 +1021,11 @@ handle_release_event(S, _Event, _ObjRef, UserData) ->
io:format("Release data: ~p\n", [UserData]),
S.
-handle_source_event(S, #wxTree{type = command_tree_item_activated, item = Item}, ObjRef, _UserData) ->
+handle_source_event(S,
+ #wxTree{type = command_tree_item_activated,
+ item = Item},
+ ObjRef,
+ _UserData) ->
case wxTreeCtrl:getItemData(ObjRef, Item) of
#root_data{dir = _Dir} ->
%% io:format("Root dialog: ~p\n", [Dir]),
@@ -921,7 +1041,11 @@ handle_source_event(S, #wxTree{type = command_tree_item_activated, item = Item},
undefined ->
S
end;
-handle_source_event(S, #wxTree{type = command_tree_item_right_click, item = Item}, Tree, _UserData) ->
+handle_source_event(S,
+ #wxTree{type = command_tree_item_right_click,
+ item = Item},
+ Tree,
+ _UserData) ->
case wxTreeCtrl:getItemData(Tree, Item) of
#root_data{dir = Dir} ->
wx:batch(fun() -> root_popup(S, Dir, Tree, Item) end);
@@ -936,18 +1060,28 @@ handle_source_event(S, #wxTree{type = command_tree_item_right_click, item = Item
S
end.
-handle_app_event(S, #wxList{type = command_list_item_activated, itemIndex = Pos}, ListCtrl, _UserData) ->
+handle_app_event(S,
+ #wxList{type = command_list_item_activated,
+ itemIndex = Pos},
+ ListCtrl,
+ _UserData) ->
AppName = wxListCtrl:getItemText(ListCtrl, Pos),
do_open_app(S, AppName);
-handle_app_event(S, #wxCommand{type = command_button_clicked}, _ObjRef, {app_button, Action, ListCtrl}) ->
+handle_app_event(S,
+ #wxCommand{type = command_button_clicked},
+ _ObjRef,
+ {app_button, Action, ListCtrl}) ->
Items = reltool_utils:get_items(ListCtrl),
handle_app_button(S, Items, Action);
handle_app_event(S, Event, ObjRef, UserData) ->
- error_logger:format("~p~p got unexpected wx app event to ~p with user data: ~p\n\t ~p\n",
+ error_logger:format("~p~p got unexpected wx app event to "
+ "~p with user data: ~p\n\t ~p\n",
[?MODULE, self(), ObjRef, UserData, Event]),
S.
-handle_app_button(#state{server_pid = ServerPid, app_wins = AppWins} = S, Items, Action) ->
+handle_app_button(#state{server_pid = ServerPid, app_wins = AppWins} = S,
+ Items,
+ Action) ->
NewApps = [move_app(S, Item, Action) || Item <- Items],
case reltool_server:set_apps(ServerPid, NewApps) of
{ok, []} ->
@@ -967,9 +1101,9 @@ do_set_sys(#state{sys = Sys, server_pid = ServerPid, status_bar = Bar} = S) ->
check_and_refresh(S, Status).
move_app(S, {_ItemNo, AppBase}, Action) ->
- {AppName, _Vsn} = reltool_utils:split_app_name(AppBase),
+ {AppName, _Vsn} = reltool_utils:split_app_name(AppBase),
{ok, OldApp} = reltool_server:get_app(S#state.server_pid, AppName),
- AppCond =
+ AppCond =
case Action of
whitelist_add ->
case OldApp#app.incl_cond of
@@ -979,29 +1113,36 @@ move_app(S, {_ItemNo, AppBase}, Action) ->
end;
whitelist_del ->
undefined;
- blacklist_add ->
+ blacklist_add ->
exclude;
blacklist_del ->
undefined;
_ ->
- error_logger:format("~p~p got unexpected app button event: ~p ~p\n",
+ error_logger:format("~p~p got unexpected app "
+ "button event: ~p ~p\n",
[?MODULE, self(), Action, AppBase]),
OldApp#app.incl_cond
end,
OldApp#app{incl_cond = AppCond}.
do_set_app(#state{server_pid = ServerPid, app_wins = AppWins} = S, NewApp) ->
- {ok, AnalysedApp, Warnings} = reltool_server:set_app(ServerPid, NewApp),
+ Result = reltool_server:set_app(ServerPid, NewApp),
[ok = reltool_app_win:refresh(AW#app_win.pid) || AW <- AppWins],
S2 = redraw_apps(S),
- case Warnings of
- [] ->
- ignore;
- _ ->
- Msg = lists:flatten([[W, $\n] || W <- Warnings]),
- display_message(Msg, ?wxICON_WARNING)
- end,
- {ok, AnalysedApp, S2}.
+ ReturnApp =
+ case Result of
+ {ok, AnalysedApp, []} ->
+ AnalysedApp;
+ {ok, AnalysedApp, Warnings} ->
+ Msg = lists:flatten([[W, $\n] || W <- Warnings]),
+ display_message(Msg, ?wxICON_WARNING),
+ AnalysedApp;
+ {error, Reason} ->
+ display_message(Reason, ?wxICON_ERROR),
+ {ok,OldApp} = reltool_server:get_app(ServerPid, NewApp#app.name),
+ OldApp
+ end,
+ {ok, ReturnApp, S2}.
redraw_apps(#state{server_pid = ServerPid,
source = SourceCtrl,
@@ -1047,14 +1188,21 @@ do_redraw_apps(ListCtrl, Apps, OkImage, ErrImage) ->
ImageApps = lists:map(AddImage, Apps),
Show =
fun({ImageId, Text, App}, {Row, ModCount, Items}) ->
- wxListCtrl:insertItem(ListCtrl, Row, ""),
- if (Row rem 2) =:= 0 ->
- wxListCtrl:setItemBackgroundColour(ListCtrl, Row, {240,240,255});
+ wxListCtrl:insertItem(ListCtrl, Row, ""),
+ if (Row rem 2) =:= 0 ->
+ wxListCtrl:setItemBackgroundColour(ListCtrl,
+ Row,
+ {240,240,255});
true ->
ignore
end,
- wxListCtrl:setItem(ListCtrl, Row, ?APPS_APP_COL, Text, [{imageId, ImageId}]),
- N = length([M || M <- App#app.mods, M#mod.is_included =:= true]),
+ wxListCtrl:setItem(ListCtrl,
+ Row,
+ ?APPS_APP_COL,
+ Text,
+ [{imageId, ImageId}]),
+ N = length([M || M <- App#app.mods,
+ M#mod.is_included =:= true]),
{Row + 1, ModCount + N, [{Row, Text} | Items]}
end,
{_, N, NewItems} = wx:foldl(Show, {0, 0, []}, lists:sort(ImageApps)),
@@ -1068,8 +1216,10 @@ update_app_graph(S) ->
WhiteNames = [A#app.name || A <- WhiteApps],
DerivedNames = [A#app.name || A <- DerivedApps],
Nodes = WhiteNames ++ DerivedNames,
- %% WhiteUses = [N || A <- WhiteApps, N <- A#app.uses_apps, lists:member(N, Nodes)],
- %% DerivedUses = [N || A <- DerivedApps, N <- A#app.uses_apps, lists:member(N, Nodes)],
+ %% WhiteUses = [N || A <- WhiteApps,
+ %% N <- A#app.uses_apps, lists:member(N, Nodes)],
+ %% DerivedUses = [N || A <- DerivedApps,
+ %% N <- A#app.uses_apps, lists:member(N, Nodes)],
WhiteLinks = [[A#app.name, U] || A <- WhiteApps,
U <- A#app.uses_apps,
@@ -1078,7 +1228,7 @@ update_app_graph(S) ->
DerivedLinks = [[A#app.name, U] || A <- DerivedApps,
U <- A#app.uses_apps,
U =/= A#app.name,
- lists:member(U, Nodes)],
+ lists:member(U, Nodes)],
Links = lists:usort(WhiteLinks ++ DerivedLinks),
%% io:format("Links: ~p\n", [Links]),
Title = lists:concat([?APPLICATION, " - application graph"]),
@@ -1087,8 +1237,12 @@ update_app_graph(S) ->
update_mod_graph(S) ->
{ok, WhiteApps} = reltool_server:get_apps(S#state.server_pid, whitelist),
{ok, DerivedApps} = reltool_server:get_apps(S#state.server_pid, derived),
- WhiteMods = lists:usort([M || A <- WhiteApps, M <- A#app.mods, M#mod.is_included =:= true]),
- DerivedMods = lists:usort([M || A <- DerivedApps, M <- A#app.mods, M#mod.is_included =:= true]),
+ WhiteMods = lists:usort([M || A <- WhiteApps,
+ M <- A#app.mods,
+ M#mod.is_included =:= true]),
+ DerivedMods = lists:usort([M || A <- DerivedApps,
+ M <- A#app.mods,
+ M#mod.is_included =:= true]),
WhiteNames = [M#mod.name || M <- WhiteMods],
DerivedNames = [M#mod.name || M <- DerivedMods],
@@ -1113,7 +1267,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],
@@ -1141,7 +1295,10 @@ undo_config(#state{status_bar = Bar} = S) ->
load_config(#state{status_bar = Bar, config_file = OldFile} = S) ->
Style = ?wxFD_OPEN bor ?wxFD_FILE_MUST_EXIST,
- case select_file(S#state.frame, "Select a file to load the configuration from", OldFile, Style) of
+ case select_file(S#state.frame,
+ "Select a file to load the configuration from",
+ OldFile,
+ Style) of
{ok, NewFile} ->
wxStatusBar:setStatusText(Bar, "Processing libraries..."),
Status = reltool_server:load_config(S#state.server_pid, NewFile),
@@ -1151,18 +1308,27 @@ load_config(#state{status_bar = Bar, config_file = OldFile} = S) ->
end.
save_config(#state{config_file = OldFile} = S, InclDefaults, InclDerivates) ->
- Style = ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT,
- case select_file(S#state.frame, "Select a file to save the configuration to", OldFile, Style) of
+ Style = ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT,
+ case select_file(S#state.frame,
+ "Select a file to save the configuration to",
+ OldFile,
+ Style) of
{ok, NewFile} ->
- Status = reltool_server:save_config(S#state.server_pid, NewFile, InclDefaults, InclDerivates),
+ Status = reltool_server:save_config(S#state.server_pid,
+ NewFile,
+ InclDefaults,
+ InclDerivates),
check_and_refresh(S#state{config_file = NewFile}, Status);
cancel ->
S
end.
gen_rel_files(#state{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
+ 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} ->
Status = reltool_server:gen_rel_files(S#state.server_pid, NewDir),
check_and_refresh(S, Status);
@@ -1171,8 +1337,11 @@ gen_rel_files(#state{target_dir = OldDir} = S) ->
end.
gen_target(#state{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
+ 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} ->
Status = reltool_server:gen_target(S#state.server_pid, NewDir),
check_and_refresh(S#state{target_dir = NewDir}, Status);
@@ -1186,7 +1355,7 @@ select_file(Frame, Message, DefaultFile, Style) ->
{defaultDir, filename:dirname(DefaultFile)},
{defaultFile, filename:basename(DefaultFile)},
{style, Style}]),
- Choice =
+ Choice =
case wxMessageDialog:showModal(Dialog) of
?wxID_CANCEL -> cancel;
?wxID_OK -> {ok, wxFileDialog:getPath(Dialog)}
@@ -1199,7 +1368,7 @@ select_dir(Frame, Message, DefaultDir, Style) ->
[{title, Message},
{defaultPath, DefaultDir},
{style, Style}]),
- Choice =
+ Choice =
case wxMessageDialog:showModal(Dialog) of
?wxID_CANCEL -> cancel;
?wxID_OK -> {ok, wxDirDialog:getPath(Dialog)}
@@ -1228,29 +1397,36 @@ refresh(S) ->
[ok = reltool_app_win:refresh(AW#app_win.pid) || AW <- S#state.app_wins],
S2 = S#state{sys = Sys},
S3 = redraw_libs(S2),
- redraw_apps(S3).
-
+ S4 = redraw_apps(S3),
+ redraw_config_page(S4).
+
question_dialog(Question, Details) ->
%% Parent = S#state.frame,
Parent = wx:typeCast(wx:null(), wxWindow),
%% [{style, ?wxYES_NO bor ?wxICON_ERROR bor ?wx}]),
DialogStyle = ?wxRESIZE_BORDER bor ?wxCAPTION bor ?wxSYSTEM_MENU bor
?wxMINIMIZE_BOX bor ?wxMAXIMIZE_BOX bor ?wxCLOSE_BOX,
- Dialog = wxDialog:new(Parent, ?wxID_ANY, "Undo dialog", [{style, DialogStyle}]),
+ Dialog = wxDialog:new(Parent, ?wxID_ANY, "Undo dialog",
+ [{style, DialogStyle}]),
Color = wxWindow:getBackgroundColour(Dialog),
TextStyle = ?wxTE_READONLY bor ?wxTE_MULTILINE bor ?wxHSCROLL,
- Text1 = wxTextCtrl:new(Dialog, ?wxID_ANY, [{style, ?wxTE_READONLY bor ?wxBORDER_NONE}]),
+ Text1 = wxTextCtrl:new(Dialog, ?wxID_ANY,
+ [{style, ?wxTE_READONLY bor ?wxBORDER_NONE}]),
wxWindow:setBackgroundColour(Text1, Color),
wxTextCtrl:appendText(Text1, Question),
- Text2 = wxTextCtrl:new(Dialog, ?wxID_ANY, [{size, {600, 400}}, {style, TextStyle}]),
+ Text2 = wxTextCtrl:new(Dialog, ?wxID_ANY,
+ [{size, {600, 400}}, {style, TextStyle}]),
wxWindow:setBackgroundColour(Text2, Color),
wxTextCtrl:appendText(Text2, Details),
%% wxDialog:setAffirmativeId(Dialog, ?wxID_YES),
%% wxDialog:setEscapeId(Dialog, ?wxID_NO),
Sizer = wxBoxSizer:new(?wxVERTICAL),
wxSizer:add(Sizer, Text1, [{border, 2}, {flag, ?wxEXPAND}]),
- wxSizer:add(Sizer, Text2, [{border, 2}, {flag, ?wxEXPAND}, {proportion, 1}]),
- ButtSizer = wxDialog:createStdDialogButtonSizer(Dialog, ?wxOK bor ?wxCANCEL),
+ wxSizer:add(Sizer, Text2, [{border, 2},
+ {flag, ?wxEXPAND},
+ {proportion, 1}]),
+ ButtSizer = wxDialog:createStdDialogButtonSizer(Dialog,
+ ?wxOK bor ?wxCANCEL),
wxSizer:add(Sizer, ButtSizer, [{border, 2}, {flag, ?wxEXPAND}]),
wxPanel:setSizer(Dialog, Sizer),
wxSizer:fit(Sizer, Dialog),
@@ -1279,6 +1455,44 @@ display_message(Message, Icon) ->
wxMessageDialog:showModal(Dialog),
wxMessageDialog:destroy(Dialog).
+%% Strings = [{Color,String}]
+question_dialog_2(DialogLabel, Strings) ->
+ %% Parent = S#state.frame,
+ Parent = wx:typeCast(wx:null(), wxWindow),
+ %% [{style, ?wxYES_NO bor ?wxICON_ERROR bor ?wx}]),
+ DialogStyle = ?wxRESIZE_BORDER bor ?wxCAPTION bor ?wxSYSTEM_MENU bor
+ ?wxMINIMIZE_BOX bor ?wxMAXIMIZE_BOX bor ?wxCLOSE_BOX,
+ Dialog = wxDialog:new(Parent, ?wxID_ANY, DialogLabel,
+ [{style, DialogStyle}]),
+ Color = wxWindow:getBackgroundColour(Dialog),
+ TextStyle = ?wxTE_READONLY bor ?wxTE_MULTILINE bor ?wxHSCROLL,
+ Text = wxTextCtrl:new(Dialog, ?wxID_ANY,
+ [{size, {600, 400}}, {style, TextStyle}]),
+ wxWindow:setBackgroundColour(Text, Color),
+ TextAttr = wxTextAttr:new(),
+ add_text(Text,TextAttr,Strings),
+ Sizer = wxBoxSizer:new(?wxVERTICAL),
+ wxSizer:add(Sizer, Text, [{border, 2}, {flag, ?wxEXPAND}, {proportion, 1}]),
+ ButtSizer = wxDialog:createStdDialogButtonSizer(Dialog, ?wxOK bor ?wxCANCEL),
+ wxSizer:add(Sizer, ButtSizer, [{border, 2}, {flag, ?wxEXPAND}]),
+ wxPanel:setSizer(Dialog, Sizer),
+ wxSizer:fit(Sizer, Dialog),
+ wxSizer:setSizeHints(Sizer, Dialog),
+ Answer = wxDialog:showModal(Dialog),
+ wxDialog:destroy(Dialog),
+ Answer.
+
+add_text(Text,Attr,[{Color,String}|Strings]) ->
+ wxTextAttr:setTextColour(Attr, Color),
+ wxTextCtrl:setDefaultStyle(Text, Attr),
+ wxTextCtrl:appendText(Text, String),
+ add_text(Text,Attr,Strings);
+add_text(_,_,[]) ->
+ ok.
+
+
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% sys callbacks
diff --git a/lib/reltool/src/reltool_target.erl b/lib/reltool/src/reltool_target.erl
index 6d85a98d9f..0fcf89a360 100644
--- a/lib/reltool/src/reltool_target.erl
+++ b/lib/reltool/src/reltool_target.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2009-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
@@ -22,7 +22,7 @@
-export([
gen_config/2,
gen_app/1,
- gen_rel/2,
+ gen_rel/2,
gen_rel_files/2,
gen_boot/1,
gen_script/4,
@@ -31,7 +31,7 @@
gen_target/2,
install/2
]).
--compile(export_all).
+
-include("reltool.hrl").
-include_lib("kernel/include/file.hrl").
@@ -55,147 +55,186 @@ kernel_processes(KernelApp) ->
[
{kernelProcess, heart, {heart, start, []}},
{kernelProcess, error_logger , {error_logger, start_link, []}},
- {kernelProcess, application_controller, {application_controller, start, [KernelApp]}}
+ {kernelProcess,
+ application_controller,
+ {application_controller, start, [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},
- InclDefaults) ->
- ErtsItems =
- case lists:keysearch(erts, #app.name, Apps) of
- {value, Erts} ->
- [{erts, gen_config(Erts, InclDefaults)}];
- false ->
- []
+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:keyfind(erts, #app.name, Apps) of
+ false ->
+ [];
+ Erts ->
+ [{erts, do_gen_config(Erts, InclDefs)}]
end,
AppsItems =
- [{app, A#app.name, gen_config(A, InclDefaults)}
- || A <- Apps,
- A#app.name =/= ?MISSING_APP,
+ [do_gen_config(A, InclDefs)
+ || A <- Apps,
+ A#app.name =/= ?MISSING_APP_NAME,
A#app.name =/= erts,
- A#app.is_included =:= true,
- A#app.is_escript =/= true],
- EscriptItems = [{escript, A#app.active_dir, emit(incl_cond, A#app.incl_cond, undefined, InclDefaults)}
- || A <- Apps, A#app.is_escript],
+ 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],
DefaultRels = reltool_utils:default_rels(),
RelsItems =
- case {[{rel, R#rel.name, R#rel.vsn, gen_config(R, InclDefaults)} || R <- Rels],
- [{rel, R#rel.name, R#rel.vsn, gen_config(R, InclDefaults)} || 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(), InclDefaults) ++
- emit(lib_dirs, LibDirs, ?DEFAULT_LIBS, InclDefaults) ++
+ emit(root_dir, RootDir, code:root_dir(), InclDefs) ++
+ emit(lib_dirs, LibDirs, ?DEFAULT_LIBS, InclDefs) ++
EscriptItems ++
- emit(mod_cond, ModCond, ?DEFAULT_MOD_COND, InclDefaults) ++
- emit(incl_cond, AppCond, ?DEFAULT_INCL_COND, InclDefaults) ++
+ emit(mod_cond, ModCond, ?DEFAULT_MOD_COND, InclDefs) ++
+ emit(incl_cond, AppCond, ?DEFAULT_INCL_COND, InclDefs) ++
ErtsItems ++
- AppsItems ++
- emit(boot_rel, BootRel, ?DEFAULT_REL_NAME, InclDefaults) ++
- RelsItems ++
- emit(emu_name, EmuName, ?DEFAULT_EMU_NAME, InclDefaults) ++
- emit(relocatable, Relocatable, ?DEFAULT_RELOCATABLE, InclDefaults) ++
- emit(profile, Profile, ?DEFAULT_PROFILE, InclDefaults) ++
- emit(incl_sys_filters, X(InclSysFiles), ?DEFAULT_INCL_SYS_FILTERS, InclDefaults) ++
- emit(excl_sys_filters, X(ExclSysFiles), ?DEFAULT_EXCL_SYS_FILTERS, InclDefaults) ++
- emit(incl_app_filters, X(InclAppFiles), ?DEFAULT_INCL_APP_FILTERS, InclDefaults) ++
- emit(excl_app_filters, X(ExclAppFiles), ?DEFAULT_EXCL_APP_FILTERS, InclDefaults) ++
- emit(incl_archive_filters, X(InclArchiveDirs), ?DEFAULT_INCL_ARCHIVE_FILTERS, InclDefaults) ++
- emit(excl_archive_filters, X(ExclArchiveDirs), ?DEFAULT_EXCL_ARCHIVE_FILTERS, InclDefaults) ++
- emit(archive_opts, ArchiveOpts, ?DEFAULT_ARCHIVE_OPTS, InclDefaults) ++
- emit(app_type, AppType, ?DEFAULT_APP_TYPE, InclDefaults) ++
- emit(app_file, AppFile, ?DEFAULT_APP_FILE, InclDefaults) ++
- emit(debug_info, DebugInfo, ?DEFAULT_DEBUG_INFO, InclDefaults)};
-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},
- InclDefaults) ->
- emit(mod_cond, ModCond, undefined, InclDefaults) ++
- emit(incl_cond, AppCond, undefined, InclDefaults) ++
- emit(debug_info, DebugInfo, undefined, InclDefaults) ++
- emit(app_file, AppFile, undefined, InclDefaults) ++
- emit(incl_app_filters, InclAppFiles, undefined, InclDefaults) ++
- emit(excl_app_filters, ExclAppFiles, undefined, InclDefaults) ++
- emit(incl_archive_filters, InclArchiveDirs, undefined, InclDefaults) ++
- emit(excl_archive_filters, ExclArchiveDirs, undefined, InclDefaults) ++
- emit(archive_opts, ArchiveOpts, undefined, InclDefaults) ++
- emit(vsn, Vsn, undefined, InclDefaults orelse UseSelected =/= true) ++
- [{mod, M#mod.name, gen_config(M, InclDefaults)} || M <- Mods, M#mod.is_included =:= true];
-gen_config(#mod{name = _Name,
- incl_cond = AppCond,
- debug_info = DebugInfo},
- InclDefaults) ->
- emit(incl_cond, AppCond, undefined, InclDefaults) ++
- emit(debug_info, DebugInfo, undefined, InclDefaults);
-gen_config(#rel{name = _Name,
- vsn = _Vsn,
- rel_apps = RelApps},
- InclDefaults) ->
- [gen_config(RA, InclDefaults) || RA <- RelApps];
-gen_config(#rel_app{name = Name,
- app_type = Type,
- incl_apps = InclApps},
- _InclDefaults) ->
+ lists:flatten(AppsItems) ++
+ emit(boot_rel, BootRel, ?DEFAULT_REL_NAME, InclDefs) ++
+ 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), 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(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)};
+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}, InclDefaults) ->
- emit(Tag, Val, undefined, InclDefaults);
-gen_config([], _InclDefaults) ->
+do_gen_config({Tag, Val}, InclDefs) ->
+ emit(Tag, Val, undefined, InclDefs);
+do_gen_config([], _InclDefs) ->
[];
-gen_config([H | T], InclDefaults) ->
- lists:flatten([gen_config(H, InclDefaults), gen_config(T, InclDefaults)]).
+do_gen_config([H | T], InclDefs) ->
+ lists:flatten([do_gen_config(H, InclDefs), do_gen_config(T, InclDefs)]).
-emit(Tag, Val, Default, InclDefaults) ->
+emit(Tag, Val, Default, InclDefs) ->
+ %% io:format("~p(~p):\n\t~p\n\t~p\n",
+ %% [Tag, Val =/= Default, Val, Default]),
if
Val == undefined -> [];
- InclDefaults -> [{Tag, Val}];
+ InclDefs -> [{Tag, Val}];
Val =/= Default -> [{Tag, Val}];
true -> []
- end.
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate the contents of an app file
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-gen_app(#app{name = Name,
+gen_app(#app{name = Name,
info = #app_info{description = Desc,
id = Id,
vsn = Vsn,
@@ -231,22 +270,126 @@ 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]}.
+gen_rel(Rel, Sys) ->
+ try
+ MergedApps = merge_apps(Rel, Sys),
+ {ok, do_gen_rel(Rel, Sys, MergedApps)}
+ catch
+ throw:{error, Text} ->
+ {error, Text}
+ end.
-app_to_rel(#rel_app{name = Name, app_type = Type, incl_apps = InclApps}, Apps) ->
- {value, #app{vsn = Vsn}} = lists:keysearch(Name, #app.name, Apps),
+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.
+ 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
@@ -261,25 +404,24 @@ gen_boot({script, {_, _}, _} = Script) ->
gen_script(Rel, Sys, PathFlag, Variables) ->
try
- do_gen_script(Rel, Sys, PathFlag, Variables)
- catch
+ 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 =
@@ -289,32 +431,32 @@ 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,
- Type =/= none,
- Type =/= load,
+ #app{name = Name, app_type = Type} <- MergedApps,
+ Type =/= none,
+ Type =/= load,
not lists:member(Name, InclApps)],
%% Apply user specific customizations
@@ -323,24 +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) ->
@@ -359,7 +483,7 @@ load_app_mods(#app{mods = Mods} = App, Mand, PathFlag, Variables) ->
Subs ->
[{Subs, [M]}|[{Last,Acc}|Rest]]
end
- end,
+ end,
[{[],
[]}],
PartNames),
@@ -381,17 +505,25 @@ load_app_mods(#app{mods = Mods} = App, Mand, PathFlag, Variables) ->
%% Mod. by mbj
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-sort_apps(Apps) ->
+sort_apps(Apps) ->
sort_apps(Apps, [], [], []).
-sort_apps([#app{name = Name, info = Info} = App | Apps], Missing, Circular, Visited) ->
- {Uses, Apps1, NotFnd1} = find_all(Name, Info#app_info.applications, Apps, Visited, [], []),
- {Incs, Apps2, NotFnd2} = find_all(Name, lists:reverse(Info#app_info.incl_apps),
- Apps1, Visited, [], []),
-
+sort_apps([#app{name = Name, info = Info} = App | Apps],
+ Missing,
+ Circular,
+ Visited) ->
+ {Uses, Apps1, NotFnd1} =
+ find_all(Name, Info#app_info.applications, Apps, Visited, [], []),
+ {Incs, Apps2, NotFnd2} =
+ find_all(Name,
+ lists:reverse(Info#app_info.incl_apps),
+ Apps1,
+ Visited,
+ [],
+ []),
Missing1 = NotFnd1 ++ NotFnd2 ++ Missing,
case Uses ++ Incs of
- [] ->
+ [] ->
%% No more app that must be started before this one is
%% found; they are all already taken care of (and present
%% in Visited list)
@@ -400,9 +532,9 @@ sort_apps([#app{name = Name, info = Info} = App | Apps], Missing, Circular, Visi
%% The apps in L must be started before the app.
%% Check if we have already taken care of some app in L,
%% in that case we have a circular dependency.
- NewCircular = [N1 || N1 <- L, N2 <- Visited, N1 =:= N2],
- Circular1 = case NewCircular of
- [] -> Circular;
+ NewCircular = [N || #app{name = N} <- L, N2 <- Visited, N =:= N2],
+ Circular1 = case NewCircular of
+ [] -> Circular;
_ -> [Name | NewCircular] ++ Circular
end,
%% L must be started before N, try again, with all apps
@@ -414,41 +546,68 @@ 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", [make_set(Missing)]);
+ reltool_utils:throw_error("Undefined applications: ~p",
+ [make_set(Missing)]);
sort_apps([], [], Circular, _) ->
- reltool_utils:throw_error("Circular dependencies: ~p\n", [make_set(Circular)]);
+ 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)]).
find_all(CheckingApp, [Name | Names], Apps, Visited, Found, NotFound) ->
- case lists:keysearch(Name, #app.name, Apps) of
- {value, #app{info = Info} = App} ->
- %% It is OK to have a dependecy like
+ case lists:keyfind(Name, #app.name, Apps) of
+ #app{info = Info} = App ->
+ %% It is OK to have a dependency like
%% X includes Y, Y uses X.
case lists:member(CheckingApp, Info#app_info.incl_apps) of
true ->
case lists:member(Name, Visited) of
true ->
- find_all(CheckingApp, Names, Apps, Visited, Found, NotFound);
+ find_all(CheckingApp,
+ Names,
+ Apps,
+ Visited,
+ Found,
+ NotFound);
false ->
- find_all(CheckingApp, Names, Apps, Visited, Found, [Name | NotFound])
+ find_all(CheckingApp,
+ Names,
+ Apps,
+ Visited,
+ Found,
+ [Name | NotFound])
end;
false ->
- find_all(CheckingApp, Names, Apps -- [App], Visited, [App|Found], NotFound)
+ find_all(CheckingApp,
+ Names,
+ Apps -- [App],
+ Visited,
+ [App|Found],
+ NotFound)
end;
false ->
case lists:member(Name, Visited) of
true ->
- find_all(CheckingApp, Names, Apps, Visited, Found, NotFound);
+ find_all(CheckingApp,
+ Names,
+ Apps,
+ Visited,
+ Found,
+ NotFound);
false ->
- find_all(CheckingApp, Names, Apps, Visited, Found, [Name|NotFound])
+ find_all(CheckingApp,
+ Names,
+ Apps,
+ Visited,
+ Found,
+ [Name|NotFound])
end
end;
find_all(_CheckingApp, [], Apps, _Visited, Found, NotFound) ->
{Found, Apps, NotFound}.
-
+
del_apps([Name | Names], Apps) ->
del_apps(Names, lists:keydelete(Name, #app.name, Apps));
del_apps([], Apps) ->
@@ -470,7 +629,9 @@ create_path(Apps, PathFlag, Variables) ->
%% (The otp_build flag is only used for OTP internal system make)
cr_path(#app{label = Label}, true, []) ->
filename:join(["$ROOT", "lib", Label, "ebin"]);
-cr_path(#app{name = Name, vsn = Vsn, label = Label, active_dir = Dir}, true, Variables) ->
+cr_path(#app{name = Name, vsn = Vsn, label = Label, active_dir = Dir},
+ true,
+ Variables) ->
Tail = [Label, "ebin"],
case variable_dir(Dir, atom_to_list(Name), Vsn, Variables) of
{ok, VarDir} ->
@@ -542,7 +703,7 @@ gen_rel_files(Sys, TargetDir) ->
try
Spec = spec_rel_files(Sys),
eval_spec(Spec, Sys#sys.root_dir, TargetDir)
- catch
+ catch
throw:{error, Text} ->
{error, Text}
end.
@@ -550,14 +711,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(),
@@ -579,15 +741,15 @@ gen_target(Sys, TargetDir) ->
try
Spec = do_gen_spec(Sys),
eval_spec(Spec, Sys#sys.root_dir, TargetDir)
- catch
+ catch
throw:{error, Text} ->
{error, Text}
end.
-
+
gen_spec(Sys) ->
try
{ok, do_gen_spec(Sys)}
- catch
+ catch
throw:{error, Text} ->
{error, Text}
end.
@@ -598,20 +760,20 @@ do_gen_spec(#sys{root_dir = RootDir,
relocatable = Relocatable,
apps = Apps} = Sys) ->
{create_dir, _, SysFiles} = spec_dir(RootDir),
- {ExclRegexps2, SysFiles2} = strip_sys_files(Relocatable, SysFiles, Apps, ExclRegexps),
+ {ExclRegexps2, SysFiles2} =
+ strip_sys_files(Relocatable, SysFiles, Apps, ExclRegexps),
RelFiles = spec_rel_files(Sys),
- {InclRegexps2, BinFiles} = spec_bin_files(Sys, SysFiles, SysFiles2, RelFiles, InclRegexps),
+ {InclRegexps2, BinFiles} =
+ spec_bin_files(Sys, SysFiles, SysFiles2, RelFiles, InclRegexps),
LibFiles = spec_lib_files(Sys),
{BootVsn, StartFile} = spec_start_file(Sys),
SysFiles3 =
[
- {create_dir, "releases",
+ {create_dir, "releases",
[StartFile,
{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),
@@ -621,24 +783,27 @@ strip_sys_files(Relocatable, SysFiles, Apps, ExclRegexps) ->
ExclRegexps2 =
case Relocatable of
true ->
- ExtraExcl = ["^erts.*/bin/.*src$"],
- reltool_utils:decode_regexps(excl_sys_filters, {add, ExtraExcl}, ExclRegexps);
+ ExtraExcl = ["^erts.*/bin/.*src\$"],
+ reltool_utils:decode_regexps(excl_sys_filters,
+ {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 ->
+ fun(Spec) ->
+ 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,
@@ -651,7 +816,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
@@ -660,7 +826,11 @@ replace_dyn_erl(true, {create_dir, ErtsDir, ErtsFiles}) ->
[{copy_file, ErlIni}] ->
%% Remove Windows .ini file
BinFiles2 = lists:keydelete(ErlIni, 2, BinFiles),
- ErtsFiles2 = lists:keyreplace("bin", 2, ErtsFiles, {create_dir, "bin", BinFiles2}),
+ ErtsFiles2 =
+ lists:keyreplace("bin",
+ 2,
+ ErtsFiles,
+ {create_dir, "bin", BinFiles2}),
{true, {create_dir, ErtsDir, ErtsFiles2}}
end;
[{copy_file, DynErlExe}] ->
@@ -668,42 +838,62 @@ replace_dyn_erl(true, {create_dir, ErtsDir, ErtsFiles}) ->
ErlExe = "erl" ++ filename:extension(DynErlExe),
BinFiles2 = lists:keydelete(DynErlExe, 2, BinFiles),
DynErlExe2 = filename:join([ErtsDir, "bin", DynErlExe]),
- BinFiles3 = lists:keyreplace(ErlExe, 2, BinFiles2, {copy_file, ErlExe, DynErlExe2}),
- ErtsFiles2 = lists:keyreplace("bin", 2, ErtsFiles, {create_dir, "bin", BinFiles3}),
+ BinFiles3 = lists:keyreplace(ErlExe,
+ 2,
+ BinFiles2,
+ {copy_file, ErlExe, DynErlExe2}),
+ ErtsFiles2 = lists:keyreplace("bin",
+ 2,
+ ErtsFiles,
+ {create_dir, "bin", BinFiles3}),
{true, {create_dir, ErtsDir, ErtsFiles2}}
end.
spec_bin_files(Sys, AllSysFiles, StrippedSysFiles, RelFiles, InclRegexps) ->
- [{create_dir, ErtsLabel, ErtsFiles}] = safe_lookup_spec("erts", StrippedSysFiles),
+ [{create_dir, ErtsLabel, ErtsFiles}] =
+ safe_lookup_spec("erts", StrippedSysFiles),
[{create_dir, _, BinFiles}] = safe_lookup_spec("bin", ErtsFiles),
ErtsBin = filename:join([ErtsLabel, "bin"]),
Escripts = spec_escripts(Sys, ErtsBin, BinFiles),
Map = fun({copy_file, File}) ->
{copy_file, File, filename:join([ErtsBin, File])};
({copy_file, NewFile, OldFile}) ->
- {_, OldFile2} = abs_to_rel_path(ErtsBin, filename:join([ErtsBin, OldFile])),
+ {_, OldFile2} =
+ abs_to_rel_path(ErtsBin,
+ filename:join([ErtsBin, OldFile])),
{copy_file, NewFile, OldFile2}
end,
%% Do only copy those bin files from erts/bin that also exists in bin
[{create_dir, _, OldBinFiles}] = safe_lookup_spec("bin", AllSysFiles),
GoodNames = [F || {copy_file, F} <- OldBinFiles,
- not lists:suffix(".boot", F),
+ 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;
@@ -722,15 +912,15 @@ do_spec_escript(File, ErtsBin, BinFiles) ->
ExeExt = filename:extension(EscriptExe),
[{copy_file, Base ++ EscriptExt, File},
{copy_file, Base ++ ExeExt, filename:join([ErtsBin, EscriptExe])}].
-
+
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 is not included",
+ reltool_utils:throw_error("Mandatory system directory ~s "
+ "is not included",
[Prefix]);
_ ->
ok
@@ -750,7 +940,9 @@ lookup_spec(Prefix, Specs) ->
safe_lookup_spec(Prefix, Specs) ->
case lookup_spec(Prefix, Specs) of
[] ->
- reltool_utils:throw_error("Mandatory system file ~s is not included", [Prefix]);
+ %% io:format("lookup fail ~s:\n\t~p\n", [Prefix, Specs]),
+ reltool_utils:throw_error("Mandatory system file ~s is "
+ "not included", [Prefix]);
Match ->
Match
end.
@@ -763,7 +955,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;
@@ -780,7 +972,8 @@ spec_lib_files(#sys{apps = Apps} = Sys) ->
check_apps([Mandatory | Names], Apps) ->
case lists:keymember(Mandatory, #app.name, Apps) of
false ->
- reltool_utils:throw_error("Mandatory application ~p is not included in ~p",
+ reltool_utils:throw_error("Mandatory application ~p is "
+ "not included in ~p",
[Mandatory, Apps]);
true ->
check_apps(Names, Apps)
@@ -791,10 +984,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),
@@ -804,8 +997,12 @@ spec_app(#app{name = Name,
EbinDir = filename:join([SourceDir, "ebin"]),
OptAppUpFileSpec = spec_opt_copy_file(EbinDir, AppUpFilename),
OptAppFileSpec = spec_app_file(App, Sys, EbinDir),
- ModSpecs = [spec_mod(M, SysDebugInfo) || M <- Mods, M#mod.is_included, M#mod.exists],
- NewEbin = {create_dir, "ebin", OptAppUpFileSpec ++ OptAppFileSpec ++ ModSpecs},
+ ModSpecs = [spec_mod(M, SysDebugInfo) || M <- Mods,
+ M#mod.is_included,
+ M#mod.exists],
+ NewEbin = {create_dir,
+ "ebin",
+ OptAppUpFileSpec ++ OptAppFileSpec ++ ModSpecs},
AppFiles2 = lists:keystore("ebin", 2, AppFiles, NewEbin),
%% Apply file filter
@@ -826,24 +1023,32 @@ spec_archive(#app{label = Label,
excl_archive_filters = SysExclArchiveDirs,
archive_opts = SysArchiveOpts},
Files) ->
- InclArchiveDirs = reltool_utils:default_val(AppInclArchiveDirs, SysInclArchiveDirs),
- ExclArchiveDirs = reltool_utils:default_val(AppExclArchiveDirs, SysExclArchiveDirs),
- ArchiveOpts = reltool_utils:default_val(AppArchiveOpts, SysArchiveOpts),
+ InclArchiveDirs =
+ reltool_utils:default_val(AppInclArchiveDirs, SysInclArchiveDirs),
+ ExclArchiveDirs =
+ reltool_utils:default_val(AppExclArchiveDirs, SysExclArchiveDirs),
+ ArchiveOpts =
+ reltool_utils:default_val(AppArchiveOpts, SysArchiveOpts),
Match = fun(F) -> match(element(2, F), InclArchiveDirs, ExclArchiveDirs) end,
case lists:filter(Match, Files) of
[] ->
%% Nothing to archive
[spec_create_dir(RootDir, SourceDir, Label, Files)];
ArchiveFiles ->
- OptDir =
+ OptDir =
case Files -- ArchiveFiles of
[] ->
[];
ExternalFiles ->
- [spec_create_dir(RootDir, SourceDir, Label, ExternalFiles)]
+ [spec_create_dir(RootDir,
+ SourceDir,
+ Label,
+ ExternalFiles)]
end,
- ArchiveOpts = reltool_utils:default_val(AppArchiveOpts, SysArchiveOpts),
- ArchiveDir = spec_create_dir(RootDir, SourceDir, Label, ArchiveFiles),
+ ArchiveOpts =
+ reltool_utils:default_val(AppArchiveOpts, SysArchiveOpts),
+ ArchiveDir =
+ spec_create_dir(RootDir, SourceDir, Label, ArchiveFiles),
[{archive, Label ++ ".ez", ArchiveOpts, [ArchiveDir]} | OptDir]
end.
@@ -854,15 +1059,17 @@ spec_dir(Dir) ->
case erl_prim_loader:list_dir(Dir) of
{ok, Files} ->
%% Directory
- {create_dir, Base, [spec_dir(filename:join([Dir, F])) || F <- Files]};
+ {create_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) ->
@@ -895,7 +1102,7 @@ spec_app_file(#app{name = Name,
App2 = App#app{info = Info#app_info{modules = ModNames}},
Contents = gen_app(App2),
AppIoList = io_lib:format("%% app generated at ~w ~w\n~p.\n\n",
- [date(), time(), Contents]),
+ [date(), time(), Contents]),
[{write_file, AppFilename, AppIoList}];
all ->
%% Include all included modules
@@ -904,13 +1111,14 @@ spec_app_file(#app{name = Name,
App2 = App#app{info = Info#app_info{modules = ModNames}},
Contents = gen_app(App2),
AppIoList = io_lib:format("%% app generated at ~w ~w\n~p.\n\n",
- [date(), time(), Contents]),
+ [date(), time(), Contents]),
[{write_file, AppFilename, AppIoList}]
-
+
end.
spec_opt_copy_file(DirName, BaseName) ->
- case filelib:is_regular(filename:join([DirName, BaseName]), erl_prim_loader) of
+ case filelib:is_regular(filename:join([DirName, BaseName]),
+ erl_prim_loader) of
true -> [{copy_file, BaseName}];
false -> []
end.
@@ -949,14 +1157,17 @@ eval_spec(Spec, SourceDir, TargetDir) ->
false ->
{error, TargetDir2 ++ ": " ++ file:format_error(enoent)}
end
- catch
+ catch
throw:{error, Text} ->
cleanup_spec(Spec, TargetDir2),
{error, Text}
end.
do_eval_spec(List, OrigSourceDir, SourceDir, TargetDir) when is_list(List) ->
- lists:foreach(fun(F) -> do_eval_spec(F, OrigSourceDir, SourceDir, TargetDir) end, List);
+ lists:foreach(fun(F) ->
+ do_eval_spec(F, OrigSourceDir, SourceDir, TargetDir)
+ end,
+ List);
%% do_eval_spec({source_dir, SourceDir2, Spec}, OrigSourceDir, _SourceDir, TargetDir) ->
%% %% Source dir is absolute or relative the original source dir
%% SourceDir3 = filename:join([OrigSourceDir, SourceDir2]),
@@ -966,12 +1177,18 @@ do_eval_spec({create_dir, Dir, Files}, OrigSourceDir, SourceDir, TargetDir) ->
TargetDir2 = filename:join([TargetDir, Dir]),
reltool_utils:create_dir(TargetDir2),
do_eval_spec(Files, OrigSourceDir, SourceDir2, TargetDir2);
-do_eval_spec({create_dir, Dir, OldDir, Files}, OrigSourceDir, _SourceDir, TargetDir) ->
+do_eval_spec({create_dir, Dir, OldDir, Files},
+ OrigSourceDir,
+ _SourceDir,
+ TargetDir) ->
SourceDir2 = filename:join([OrigSourceDir, OldDir]),
TargetDir2 = filename:join([TargetDir, Dir]),
reltool_utils:create_dir(TargetDir2),
do_eval_spec(Files, SourceDir2, SourceDir2, TargetDir2);
-do_eval_spec({archive, Archive, Options, Files}, OrigSourceDir, SourceDir, TargetDir) ->
+do_eval_spec({archive, Archive, Options, Files},
+ OrigSourceDir,
+ SourceDir,
+ TargetDir) ->
TmpSpec = {create_dir, "tmp", Files},
TmpDir = filename:join([TargetDir, "tmp"]),
reltool_utils:create_dir(TmpDir),
@@ -986,17 +1203,24 @@ do_eval_spec({archive, Archive, Options, Files}, OrigSourceDir, SourceDir, Targe
{ok, _} ->
ok;
{error, Reason} ->
- reltool_utils:throw_error("create archive ~s: ~p\n", [ArchiveFile, Reason])
+ reltool_utils:throw_error("create archive ~s failed: ~p",
+ [ArchiveFile, Reason])
end;
do_eval_spec({copy_file, File}, _OrigSourceDir, SourceDir, TargetDir) ->
SourceFile = filename:join([SourceDir, File]),
TargetFile = filename:join([TargetDir, File]),
reltool_utils:copy_file(SourceFile, TargetFile);
-do_eval_spec({copy_file, File, OldFile}, OrigSourceDir, _SourceDir, TargetDir) ->
+do_eval_spec({copy_file, File, OldFile},
+ OrigSourceDir,
+ _SourceDir,
+ TargetDir) ->
SourceFile = filename:join([OrigSourceDir, OldFile]),
TargetFile = filename:join([TargetDir, File]),
reltool_utils:copy_file(SourceFile, TargetFile);
-do_eval_spec({write_file, File, IoList}, _OrigSourceDir, _SourceDir, TargetDir) ->
+do_eval_spec({write_file, File, IoList},
+ _OrigSourceDir,
+ _SourceDir,
+ TargetDir) ->
TargetFile = filename:join([TargetDir, File]),
reltool_utils:write_file(TargetFile, IoList);
do_eval_spec({strip_beam, File}, _OrigSourceDir, SourceDir, TargetDir) ->
@@ -1007,7 +1231,7 @@ do_eval_spec({strip_beam, File}, _OrigSourceDir, SourceDir, TargetDir) ->
reltool_utils:write_file(TargetFile, BeamBin2).
cleanup_spec(List, TargetDir) when is_list(List) ->
- lists:foreach(fun(F)-> cleanup_spec(F, TargetDir) end, List);
+ lists:foreach(fun(F) -> cleanup_spec(F, TargetDir) end, List);
%% cleanup_spec({source_dir, _SourceDir, Spec}, TargetDir) ->
%% cleanup_spec(Spec, TargetDir);
cleanup_spec({create_dir, Dir, Files}, TargetDir) ->
@@ -1039,9 +1263,12 @@ cleanup_spec({strip_beam, File}, TargetDir) ->
filter_spec(List, InclRegexps, ExclRegexps) ->
do_filter_spec("", List, InclRegexps, ExclRegexps).
-
+
do_filter_spec(Path, List, InclRegexps, ExclRegexps) when is_list(List) ->
- lists:zf(fun(File) -> do_filter_spec(Path, File, InclRegexps, ExclRegexps) end, List);
+ lists:zf(fun(File) ->
+ do_filter_spec(Path, File, InclRegexps, ExclRegexps)
+ end,
+ List);
%% do_filter_spec(Path, {source_dir, _SourceDir, Spec}, InclRegexps, ExclRegexps) ->
%% do_filter_spec(Path, Spec, InclRegexps, ExclRegexps);
do_filter_spec(Path, {create_dir, Dir, Files}, InclRegexps, ExclRegexps) ->
@@ -1057,7 +1284,10 @@ do_filter_spec(Path, {create_dir, Dir, Files}, InclRegexps, ExclRegexps) ->
Files2 when is_list(Files2) ->
{true, {create_dir, Dir, Files2}}
end;
-do_filter_spec(Path, {create_dir, NewDir, OldDir, Files}, InclRegexps, ExclRegexps) ->
+do_filter_spec(Path,
+ {create_dir, NewDir, OldDir, Files},
+ InclRegexps,
+ ExclRegexps) ->
Path2 = opt_join(Path, NewDir),
case do_filter_spec(Path2, Files, InclRegexps, ExclRegexps) of
[] ->
@@ -1070,7 +1300,10 @@ do_filter_spec(Path, {create_dir, NewDir, OldDir, Files}, InclRegexps, ExclRegex
Files2 when is_list(Files2) ->
{true, {create_dir, NewDir, OldDir, Files2}}
end;
-do_filter_spec(Path, {archive, Archive, Options, Files}, InclRegexps, ExclRegexps) ->
+do_filter_spec(Path,
+ {archive, Archive, Options, Files},
+ InclRegexps,
+ ExclRegexps) ->
case do_filter_spec(Path, Files, InclRegexps, ExclRegexps) of
[] ->
case match(Path, InclRegexps, ExclRegexps) of
@@ -1085,7 +1318,10 @@ do_filter_spec(Path, {archive, Archive, Options, Files}, InclRegexps, ExclRegexp
do_filter_spec(Path, {copy_file, File}, InclRegexps, ExclRegexps) ->
Path2 = opt_join(Path, File),
match(Path2, InclRegexps, ExclRegexps);
-do_filter_spec(Path, {copy_file, NewFile, _OldFile}, InclRegexps, ExclRegexps) ->
+do_filter_spec(Path,
+ {copy_file, NewFile, _OldFile},
+ InclRegexps,
+ ExclRegexps) ->
Path2 = opt_join(Path, NewFile),
match(Path2, InclRegexps, ExclRegexps);
do_filter_spec(Path, {write_file, File, _IoList}, InclRegexps, ExclRegexps) ->
@@ -1101,18 +1337,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, []) ->
@@ -1131,7 +1356,7 @@ match(String, [#regexp{source = _, compiled = MP} | Regexps]) ->
install(RelName, TargetDir) ->
try
do_install(RelName, TargetDir)
- catch
+ catch
throw:{error, Text} ->
{error, Text}
end.
@@ -1148,7 +1373,8 @@ do_install(RelName, TargetDir) ->
case os:type() of
{win32, _} ->
NativeRootDir = filename:nativename(TargetDir2),
- %% NativeBinDir = filename:nativename(filename:join([BinDir, "win32"])),
+ %% NativeBinDir =
+ %% filename:nativename(filename:join([BinDir, "win32"])),
NativeBinDir = filename:nativename(BinDir),
IniData = ["[erlang]\r\n",
"Bindir=", NativeBinDir, "\r\n",
@@ -1157,25 +1383,30 @@ do_install(RelName, TargetDir) ->
IniFile = filename:join([BinDir, "erl.ini"]),
ok = file:write_file(IniFile, IniData);
_ ->
- subst_src_scripts(start_scripts(), ErtsBinDir, BinDir,
- [{"FINAL_ROOTDIR", TargetDir2}, {"EMU", "beam"}],
+ subst_src_scripts(start_scripts(),
+ ErtsBinDir,
+ BinDir,
+ [{"FINAL_ROOTDIR", TargetDir2},
+ {"EMU", "beam"}],
[preserve])
end,
RelFile = filename:join([RelDir, RelVsn, RelName ++ ".rel"]),
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) ->
- Fun = fun(Script) -> subst_src_script(Script, SrcDir, DestDir, Vars, Opts) end,
+ Fun = fun(Script) ->
+ subst_src_script(Script, SrcDir, DestDir, Vars, Opts)
+ end,
lists:foreach(Fun, Scripts).
-subst_src_script(Script, SrcDir, DestDir, Vars, Opts) ->
+subst_src_script(Script, SrcDir, DestDir, Vars, Opts) ->
subst_file(filename:join([SrcDir, Script ++ ".src"]),
filename:join([DestDir, Script]),
- Vars,
+ Vars,
Opts).
subst_file(Src, Dest, Vars, Opts) ->
@@ -1212,8 +1443,8 @@ subst([], _Vars, Result) ->
subst_var([$%| Rest], Vars, Result, VarAcc) ->
Key = lists:reverse(VarAcc),
- case lists:keysearch(Key, 1, Vars) of
- {value, {Key, Value}} ->
+ case lists:keyfind(Key, 1, Vars) of
+ {Key, Value} ->
subst(Rest, Vars, lists:reverse(Value, Result));
false ->
subst(Rest, Vars, [$% | VarAcc ++ [$% | Result]])
diff --git a/lib/reltool/src/reltool_utils.erl b/lib/reltool/src/reltool_utils.erl
index 8d52ade9be..39d057d994 100644
--- a/lib/reltool/src/reltool_utils.erl
+++ b/lib/reltool/src/reltool_utils.erl
@@ -1,25 +1,48 @@
%%
%% %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%
-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").
@@ -30,11 +53,11 @@ root_dir() ->
erl_libs() ->
case os:getenv("ERL_LIBS") of
- false ->
+ false ->
[];
LibStr ->
string:tokens(LibStr, ":;")
- end.
+ end.
lib_dirs(Dir) ->
case erl_prim_loader:list_dir(Dir) of
@@ -42,7 +65,7 @@ lib_dirs(Dir) ->
[F || F <- Files,
filelib:is_dir(filename:join([Dir, F]),
erl_prim_loader)];
- error ->
+ error ->
[]
end.
@@ -55,7 +78,7 @@ split_app_name(Name) ->
Elem >= $0, Elem =< $9 -> true;
true -> false
end
- end,
+ end,
case lists:splitwith(Pred, lists:reverse(Name)) of
{Vsn, [$- | App]} ->
{list_to_atom(lists:reverse(App)), lists:reverse(Vsn)};
@@ -103,23 +126,51 @@ 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) ->
Art = wxImageList:new(16,16),
- [wxImageList:add(Art, wxArtProvider:getBitmap(Image, [{size, {16,16}}]))
+ [wxImageList:add(Art, wxArtProvider:getBitmap(Image, [{size, {16,16}}]))
|| Image <- ["wxART_ERROR",
"wxART_WARNING",
"wxART_QUESTION",
@@ -206,7 +257,7 @@ split_app_dir(Dir) ->
ParentDir = filename:dirname(Dir),
Base = filename:basename(Dir),
{Name, Vsn} = split_app_name(Base),
- Vsn2 =
+ Vsn2 =
try
[list_to_integer(N) || N <- string:tokens(Vsn, ".")]
catch
@@ -276,7 +327,9 @@ get_selected_items(ListCtrl, PrevItem, Acc) ->
ItemNo ->
case wxListCtrl:getItemText(ListCtrl, ItemNo) of
Text when Text =/= ?MISSING_APP_TEXT ->
- get_selected_items(ListCtrl, ItemNo, [{ItemNo, Text} | Acc]);
+ get_selected_items(ListCtrl,
+ ItemNo,
+ [{ItemNo, Text} | Acc]);
_Text ->
get_selected_items(ListCtrl, ItemNo, Acc)
end
@@ -306,7 +359,8 @@ select_items(ListCtrl, OldItems, NewItems) ->
select_item(ListCtrl, NewItems);
ValidItems ->
%% Some old selections are still valid. Select them again.
- lists:foreach(fun(Item) -> select_item(ListCtrl, [Item]) end, ValidItems)
+ lists:foreach(fun(Item) -> select_item(ListCtrl, [Item]) end,
+ ValidItems)
end.
select_item(ListCtrl, [{ItemNo, Text} | Items]) ->
@@ -339,7 +393,7 @@ 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} ->
@@ -356,7 +410,7 @@ return_first_error(Status, NewError) when is_list(NewError) ->
{error, OldError} ->
{error, OldError}
end.
-
+
add_warning(Status, Warning) ->
case Status of
{ok, Warnings} ->
@@ -376,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) ->
@@ -385,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) ->
@@ -394,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) ->
@@ -403,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) ->
@@ -412,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) ->
@@ -421,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) ->
@@ -429,7 +483,8 @@ recursive_delete(Dir) ->
true ->
case file:list_dir(Dir) of
{ok, Files} ->
- Fun = fun(F) -> recursive_delete(filename:join([Dir, F])) end,
+ Fun =
+ fun(F) -> recursive_delete(filename:join([Dir, F])) end,
lists:foreach(Fun, Files),
delete(Dir, directory);
{error, enoent} ->
@@ -514,7 +569,9 @@ decode_regexps(Key, Regexps, _Old) when is_list(Regexps) ->
do_decode_regexps(Key, [Regexp | Regexps], Acc) ->
case catch re:compile(Regexp, []) of
{ok, MP} ->
- do_decode_regexps(Key, Regexps, [#regexp{source = Regexp, compiled = MP} | Acc]);
+ do_decode_regexps(Key,
+ Regexps,
+ [#regexp{source = Regexp, compiled = MP} | Acc]);
_ ->
Text = lists:flatten(io_lib:format("~p", [{Key, Regexp}])),
throw({error, "Illegal option: " ++ Text})
@@ -532,8 +589,34 @@ default_val(Val, Default) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+escript_foldl(Fun, Acc, File) ->
+ case escript:extract(File, [compile_source]) of
+ {ok, [_Shebang, _Comment, _EmuArgs, Body]} ->
+ case Body of
+ {source, BeamCode} ->
+ GetInfo = fun() -> file:read_file_info(File) end,
+ GetBin = fun() -> BeamCode end,
+ {ok, Fun(".", GetInfo, GetBin, Acc)};
+ {beam, BeamCode} ->
+ GetInfo = fun() -> file:read_file_info(File) end,
+ GetBin = fun() -> BeamCode end,
+ {ok, Fun(".", GetInfo, GetBin, Acc)};
+ {archive, ArchiveBin} ->
+ zip:foldl(Fun, Acc, {File, ArchiveBin})
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
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},
diff --git a/lib/reltool/test/Makefile b/lib/reltool/test/Makefile
index 00d2add3e5..767454b66a 100644
--- a/lib/reltool/test/Makefile
+++ b/lib/reltool/test/Makefile
@@ -1,19 +1,19 @@
#
# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2009. All Rights Reserved.
-#
+#
+# Copyright Ericsson AB 2009-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%
include $(ERL_TOP)/make/target.mk
@@ -25,6 +25,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
MODULES= \
rtt \
+ reltool_app_SUITE \
reltool_wx_SUITE \
reltool_server_SUITE \
reltool_test_lib
@@ -72,10 +73,11 @@ release_spec: opt
release_tests_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) reltool.spec $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)
- $(INSTALL_PROGRAM) rtt $(INSTALL_PROGS) $(RELSYSDIR)
-# chmod -f -R u+w $(RELSYSDIR)
-# @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DATA) reltool.spec reltool.cover $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)
+ $(INSTALL_SCRIPT) rtt $(INSTALL_PROGS) $(RELSYSDIR)
+ $(INSTALL_DATA) $(INSTALL_PROGS) $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
+ @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/reltool/test/reltool.cover b/lib/reltool/test/reltool.cover
new file mode 100644
index 0000000000..ca425b9f98
--- /dev/null
+++ b/lib/reltool/test/reltool.cover
@@ -0,0 +1,2 @@
+{incl_app,reltool,details}.
+
diff --git a/lib/reltool/test/reltool.spec b/lib/reltool/test/reltool.spec
index 252232e09d..2995720105 100644
--- a/lib/reltool/test/reltool.spec
+++ b/lib/reltool/test/reltool.spec
@@ -1,2 +1 @@
-{topcase, {dir, "../reltool_test"}}.
-
+{suites,"../reltool_test",all}.
diff --git a/lib/reltool/test/reltool_app_SUITE.erl b/lib/reltool/test/reltool_app_SUITE.erl
new file mode 100644
index 0000000000..a6e00cde08
--- /dev/null
+++ b/lib/reltool/test/reltool_app_SUITE.erl
@@ -0,0 +1,292 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-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: Verify the application specifics of the Reltool application
+%%----------------------------------------------------------------------
+-module(reltool_app_SUITE).
+
+-compile(export_all).
+
+-include("reltool_test_lib.hrl").
+
+
+t() -> reltool_test_lib:t(?MODULE).
+t(Case) -> reltool_test_lib:t({?MODULE, Case}).
+
+%% Test server callbacks
+init_per_suite(Config) ->
+ Config2 = reltool_test_lib:init_per_suite(Config),
+ case is_app(reltool) of
+ {ok, AppFile} ->
+ %% io:format("AppFile: ~n~p~n", [AppFile]),
+ [{app_file, AppFile} | Config2];
+ {error, Reason} ->
+ fail(Reason)
+ end.
+
+end_per_suite(Config) ->
+ reltool_test_lib:end_per_suite(Config).
+
+init_per_testcase(undef_funcs=Case, Config) ->
+ case test_server:is_debug() of
+ true ->
+ {skip,"Debug-compiled emulator -- far too slow"};
+ false ->
+ Config2 = [{tc_timeout, timer:minutes(10)} | Config],
+ reltool_test_lib:init_per_testcase(Case, Config2)
+ end;
+init_per_testcase(Case, Config) ->
+ reltool_test_lib:init_per_testcase(Case, Config).
+
+end_per_testcase(Func,Config) ->
+ reltool_test_lib:end_per_testcase(Func,Config).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [fields, modules, export_all, app_depend, undef_funcs].
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+is_app(App) ->
+ LibDir = code:lib_dir(App),
+ File = filename:join([LibDir, "ebin", atom_to_list(App) ++ ".app"]),
+ case file:consult(File) of
+ {ok, [{application, App, AppFile}]} ->
+ {ok, AppFile};
+ {error, {LineNo, Mod, Code}} ->
+ IoList = lists:concat([File, ":", LineNo, ": ",
+ Mod:format_error(Code)]),
+ {error, list_to_atom(lists:flatten(IoList))}
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+fields(suite) ->
+ [];
+fields(doc) ->
+ [];
+fields(Config) when is_list(Config) ->
+ AppFile = key1search(app_file, Config),
+ Fields = [vsn, description, modules, registered, applications],
+ case check_fields(Fields, AppFile, []) of
+ [] ->
+ ok;
+ Missing ->
+ fail({missing_fields, Missing})
+ end.
+
+check_fields([], _AppFile, Missing) ->
+ Missing;
+check_fields([Field|Fields], AppFile, Missing) ->
+ check_fields(Fields, AppFile, check_field(Field, AppFile, Missing)).
+
+check_field(Name, AppFile, Missing) ->
+ io:format("checking field: ~p~n", [Name]),
+ case lists:keymember(Name, 1, AppFile) of
+ true ->
+ Missing;
+ false ->
+ [Name|Missing]
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+modules(suite) ->
+ [];
+modules(doc) ->
+ [];
+modules(Config) when is_list(Config) ->
+ AppFile = key1search(app_file, Config),
+ Mods = key1search(modules, AppFile),
+ EbinList = get_ebin_mods(reltool),
+ case missing_modules(Mods, EbinList, []) of
+ [] ->
+ ok;
+ Missing ->
+ throw({error, {missing_modules, Missing}})
+ end,
+ case extra_modules(Mods, EbinList, []) of
+ [] ->
+ ok;
+ Extra ->
+ throw({error, {extra_modules, Extra}})
+ end,
+ {ok, Mods}.
+
+get_ebin_mods(App) ->
+ LibDir = code:lib_dir(App),
+ EbinDir = filename:join([LibDir,"ebin"]),
+ {ok, Files0} = file:list_dir(EbinDir),
+ Files1 = [lists:reverse(File) || File <- Files0],
+ [list_to_atom(lists:reverse(Name)) || [$m,$a,$e,$b,$.|Name] <- Files1].
+
+missing_modules([], _Ebins, Missing) ->
+ Missing;
+missing_modules([Mod|Mods], Ebins, Missing) ->
+ case lists:member(Mod, Ebins) of
+ true ->
+ missing_modules(Mods, Ebins, Missing);
+ false ->
+ io:format("missing module: ~p~n", [Mod]),
+ missing_modules(Mods, Ebins, [Mod|Missing])
+ end.
+
+
+extra_modules(_Mods, [], Extra) ->
+ Extra;
+extra_modules(Mods, [Mod|Ebins], Extra) ->
+ case lists:member(Mod, Mods) of
+ true ->
+ extra_modules(Mods, Ebins, Extra);
+ false ->
+ io:format("supefluous module: ~p~n", [Mod]),
+ extra_modules(Mods, Ebins, [Mod|Extra])
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+export_all(suite) ->
+ [];
+export_all(doc) ->
+ [];
+export_all(Config) when is_list(Config) ->
+ AppFile = key1search(app_file, Config),
+ Mods = key1search(modules, AppFile),
+ check_export_all(Mods).
+
+
+check_export_all([]) ->
+ ok;
+check_export_all([Mod|Mods]) ->
+ case (catch apply(Mod, module_info, [compile])) of
+ {'EXIT', {undef, _}} ->
+ check_export_all(Mods);
+ O ->
+ case lists:keysearch(options, 1, O) of
+ false ->
+ check_export_all(Mods);
+ {value, {options, List}} ->
+ case lists:member(export_all, List) of
+ true ->
+ throw({error, {export_all, Mod}});
+ false ->
+ check_export_all(Mods)
+ end
+ end
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+app_depend(suite) ->
+ [];
+app_depend(doc) ->
+ [];
+app_depend(Config) when is_list(Config) ->
+ AppFile = key1search(app_file, Config),
+ Apps = key1search(applications, AppFile),
+ check_apps(Apps).
+
+check_apps([]) ->
+ ok;
+check_apps([App|Apps]) ->
+ case is_app(App) of
+ {ok, _} ->
+ check_apps(Apps);
+ Error ->
+ throw({error, {missing_app, {App, Error}}})
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+undef_funcs(suite) ->
+ [];
+undef_funcs(doc) ->
+ [];
+undef_funcs(Config) when is_list(Config) ->
+ App = reltool,
+ AppFile = key1search(app_file, Config),
+ Mods = key1search(modules, AppFile),
+ Root = code:root_dir(),
+ LibDir = code:lib_dir(App),
+ EbinDir = filename:join([LibDir,"ebin"]),
+ XRefTestName = undef_funcs_make_name(App, xref_test_name),
+ {ok, XRef} = xref:start(XRefTestName),
+ ok = xref:set_default(XRef,
+ [{verbose,false},{warnings,false}]),
+ XRefName = undef_funcs_make_name(App, xref_name),
+ {ok, XRefName} = xref:add_release(XRef, Root, {name,XRefName}),
+ {ok, App} = xref:replace_application(XRef, App, EbinDir),
+ {ok, Undefs} = xref:analyze(XRef, undefined_function_calls),
+ xref:stop(XRef),
+ analyze_undefined_function_calls(Undefs, Mods, []).
+
+analyze_undefined_function_calls([], _, []) ->
+ ok;
+analyze_undefined_function_calls([], _, AppUndefs) ->
+ exit({suite_failed, {undefined_function_calls, AppUndefs}});
+analyze_undefined_function_calls([{{Mod, _F, _A}, _C} = AppUndef|Undefs],
+ AppModules, AppUndefs) ->
+ %% Check that this module is our's
+ case lists:member(Mod,AppModules) of
+ true ->
+ {Calling,Called} = AppUndef,
+ {Mod1,Func1,Ar1} = Calling,
+ {Mod2,Func2,Ar2} = Called,
+ io:format("undefined function call: "
+ "~n ~w:~w/~w calls ~w:~w/~w~n",
+ [Mod1,Func1,Ar1,Mod2,Func2,Ar2]),
+ analyze_undefined_function_calls(Undefs, AppModules,
+ [AppUndef|AppUndefs]);
+ false ->
+ io:format("dropping ~p~n", [Mod]),
+ analyze_undefined_function_calls(Undefs, AppModules, AppUndefs)
+ end.
+
+%% This function is used simply to avoid cut-and-paste errors later...
+undef_funcs_make_name(App, PostFix) ->
+ list_to_atom(atom_to_list(App) ++ "_" ++ atom_to_list(PostFix)).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+fail(Reason) ->
+ exit({suite_failed, Reason}).
+
+key1search(Key, L) ->
+ case lists:keysearch(Key, 1, L) of
+ false ->
+ fail({not_found, Key, L});
+ {value, {Key, Value}} ->
+ Value
+ end.
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index cf951191a0..9ed79e8c95 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -1,36 +1,40 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2009-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%
-module(reltool_server_SUITE).
--export([all/0, init_per_suite/1, end_per_suite/1,
- init_per_testcase/2, fin_per_testcase/2, end_per_testcase/2]).
+-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("reltool_test_lib.hrl").
+-include_lib("common_test/include/ct.hrl").
-define(NODE_NAME, '__RELTOOL__TEMPORARY_TEST__NODE__').
+-define(WORK_DIR, "reltool_work_dir").
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Initialization functions.
init_per_suite(Config) ->
+ ?ignore(file:make_dir(?WORK_DIR)),
reltool_test_lib:init_per_suite(Config).
end_per_suite(Config) ->
@@ -40,25 +44,27 @@ 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).
-fin_per_testcase(Func,Config) -> %% For test_server
- reltool_test_lib:end_per_testcase(Func,Config).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% SUITE specification
-all() ->
- all(suite).
-all(suite) ->
- [
- start_server,
- set_config,
- create_release,
- create_script,
- create_target,
- create_embedded,
- create_standalone,
- create_old_target
- ].
+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].
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
%% The test cases
@@ -106,6 +112,37 @@ set_config(_Config) ->
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 =
+ case Libs of
+ [] -> [];
+ _ -> {lib_dirs, Libs}
+ end,
+
+ Config1 = {sys,[{app_file, keep}]}, % this is the default
+ {ok, Pid1} = ?msym({ok, _}, reltool:start_server([{config, Config1}])),
+ ?m({ok, {sys,StrippedDefaultSys}}, reltool:get_config(Pid1)),
+ ?m(ok, reltool:stop(Pid1)),
+
+ Config2 = {sys,[{app_file, strip}]},
+ {ok, Pid2} = ?msym({ok, _}, reltool:start_server([{config, Config2}])),
+ ExpectedConfig2 = StrippedDefaultSys++[{app_file,strip}],
+ ?m({ok, {sys,ExpectedConfig2}}, reltool:get_config(Pid2)),
+ ?m(ok, reltool:stop(Pid2)),
+
+ Config3 = {sys,[{app_file, all}]},
+ {ok, Pid3} = ?msym({ok, _}, reltool:start_server([{config, Config3}])),
+ ExpectedConfig3 = StrippedDefaultSys++[{app_file,all}],
+ ?m({ok, {sys,ExpectedConfig3}}, reltool:get_config(Pid3)),
+ ?m(ok, reltool:stop(Pid3)),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate releases
create_release(TestInfo) when is_atom(TestInfo) ->
@@ -128,8 +165,7 @@ create_release(_Config) ->
{value, {_, _, StdlibVsn}} = lists:keysearch(stdlib, 1, Apps),
Rel = {release, {RelName, RelVsn},
{erts, ErtsVsn},
- [{kernel, KernelVsn},
- {stdlib, StdlibVsn}]},
+ [{kernel, KernelVsn}, {stdlib, StdlibVsn}]},
?m({ok, Rel}, reltool:get_rel([{config, Config}], RelName)),
ok.
@@ -159,15 +195,17 @@ create_script(_Config) ->
Rel = {release,
{RelName, RelVsn},
{erts, ErtsVsn},
- [{stdlib, StdlibVsn}, {kernel, KernelVsn}]},
+ [{kernel, KernelVsn}, {stdlib, StdlibVsn}]},
?m({ok, Rel}, reltool:get_rel(Pid, RelName)),
- RelFile = RelName ++ ".rel",
- ?m(ok, file:write_file(RelFile, io_lib:format("~p.\n", [Rel]))),
+ ?m(ok, file:write_file(filename:join([?WORK_DIR, RelName ++ ".rel"]),
+ io_lib:format("~p.\n", [Rel]))),
%% Generate script file
+ {ok, Cwd} = file:get_cwd(),
+ ?m(ok, file:set_cwd(?WORK_DIR)),
?m(ok, systools:make_script(RelName, [])),
- ScriptFile = RelName ++ ".script",
- {ok, [OrigScript]} = ?msym({ok, [_]}, file:consult(ScriptFile)),
+ {ok, [OrigScript]} = ?msym({ok, [_]}, file:consult(RelName ++ ".script")),
+ ?m(ok, file:set_cwd(Cwd)),
{ok, Script} = ?msym({ok, _}, reltool:get_script(Pid, RelName)),
%% OrigScript2 = sort_script(OrigScript),
%% Script2 = sort_script(Script),
@@ -201,9 +239,10 @@ create_target(_Config) ->
]},
%% Generate target file
- TargetDir = "reltool_target_dir_development",
+ TargetDir = filename:join([?WORK_DIR, "target_development"]),
?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)),
Erl = filename:join([TargetDir, "bin", "erl"]),
@@ -234,7 +273,7 @@ create_embedded(_Config) ->
]},
%% Generate target file
- TargetDir = "reltool_target_dir_embedded",
+ 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)),
@@ -264,7 +303,7 @@ create_standalone(_Config) ->
]},
%% Generate target file
- TargetDir = "reltool_target_dir_standalone",
+ 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)),
@@ -290,6 +329,8 @@ create_standalone(_Config) ->
create_old_target(TestInfo) when is_atom(TestInfo) ->
reltool_test_lib:tc_info(TestInfo);
create_old_target(_Config) ->
+ ?skip("Old style of target", []),
+
%% Configure the server
RelName1 = "Just testing",
RelName2 = "Just testing with SASL",
@@ -306,7 +347,7 @@ create_old_target(_Config) ->
]},
%% Generate target file
- TargetDir = "reltool_target_dir_old",
+ 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)),
@@ -321,6 +362,114 @@ create_old_target(_Config) ->
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) ->
+ DataDir = ?config(data_dir,Config),
+ LibDir = filename:join(DataDir,"otp_9229"),
+
+ %% Configure the server
+ ExclApp =
+ {sys,
+ [
+ {root_dir, code:root_dir()},
+ {lib_dirs, [LibDir]},
+ {incl_cond,exclude},
+ {app,x,[{incl_cond,include}]},
+ {app,y,[{incl_cond,exclude}]},
+ {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_excl_app"]),
+ ?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)),
+
+ Erl = filename:join([TargetDir, "bin", "erl"]),
+ {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
+
+ AbsTargetDir = filename:absname(TargetDir),
+ XArchive = "x-1.0.ez",
+ AbsXArchive = filename:join([AbsTargetDir,lib,XArchive]),
+ XEbin = ["ebin","x-1.0",XArchive],
+ YArchive = "y-1.0.ez",
+ AbsYArchive = filename:join([AbsTargetDir,lib,YArchive]),
+
+ ?m(true, filelib:is_file(AbsXArchive)),
+ ?m(XEbin, mod_path(Node,x)),
+ ?m(XEbin, mod_path(Node,mylib)),
+ ?m(false, filelib:is_file(AbsYArchive)),
+ ?m(non_existing, mod_path(Node,y)),
+
+ ?msym(ok, stop_node(Node)),
+
+ ok.
+
+%% Include both apps, but exclude common module from one app
+otp_9229_exclude_mod(Config) ->
+ DataDir = ?config(data_dir,Config),
+ LibDir = filename:join(DataDir,"otp_9229"),
+
+ %% Configure the server
+ ExclMod =
+ {sys,
+ [
+ {root_dir, code:root_dir()},
+ {lib_dirs, [LibDir]},
+ {incl_cond,exclude},
+ {app,x,[{incl_cond,include}]},
+ {app,y,[{incl_cond,include},{mod, mylib,[{incl_cond,exclude}]}]},
+ {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_excl_mod"]),
+ ?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)),
+
+ Erl = filename:join([TargetDir, "bin", "erl"]),
+ {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
+
+ AbsTargetDir = filename:absname(TargetDir),
+ XArchive = "x-1.0.ez",
+ AbsXArchive = filename:join([AbsTargetDir,lib,XArchive]),
+ XEbin = ["ebin","x-1.0",XArchive],
+ YArchive = "y-1.0.ez",
+ AbsYArchive = filename:join([AbsTargetDir,lib,YArchive]),
+ YEbin = ["ebin","y-1.0",YArchive],
+
+ ?m(true, filelib:is_file(AbsXArchive)),
+ ?m(XEbin, mod_path(Node,x)),
+ ?m(XEbin, mod_path(Node,mylib)),
+ ?m(true, filelib:is_file(AbsYArchive)),
+ ?m(YEbin, mod_path(Node,y)),
+
+ %% Remove path to XEbin and check that mylib is not located in YEbin
+ Mylib = rpc:call(Node,code,which,[mylib]),
+ rpc:call(Node,code,del_path,[filename:dirname(Mylib)]),
+ ?m(non_existing, mod_path(Node,mylib)),
+
+ ?msym(ok, stop_node(Node)),
+
+ ok.
+
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Library functions
erl_libs() ->
@@ -367,6 +516,20 @@ os_cmd(Cmd) when is_list(Cmd) ->
end
end.
+%% Returns the location (directory) of the given module. Split,
+%% reverted and relative to the lib dir.
+mod_path(Node,Mod) ->
+ case rpc:call(Node,code,which,[Mod]) of
+ Path when is_list(Path) ->
+ lists:takewhile(
+ fun("lib") -> false;
+ (_) -> true
+ end,
+ lists:reverse(filename:split(filename:dirname(Path))));
+ Other ->
+ Other
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Node handling
diff --git a/lib/reltool/test/reltool_server_SUITE_data/Makefile.src b/lib/reltool/test/reltool_server_SUITE_data/Makefile.src
new file mode 100644
index 0000000000..049e8dd6cc
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/Makefile.src
@@ -0,0 +1,19 @@
+EFLAGS=+debug_info
+
+OTP9229= \
+ otp_9229/x-1.0/ebin/x.@EMULATOR@ \
+ otp_9229/x-1.0/ebin/mylib.@EMULATOR@ \
+ otp_9229/y-1.0/ebin/y.@EMULATOR@ \
+ otp_9229/y-1.0/ebin/mylib.@EMULATOR@
+
+
+all: $(OTP9229)
+
+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
+otp_9229/x-1.0/ebin/mylib.@EMULATOR@: otp_9229/x-1.0/src/mylib.erl
+ erlc $(EFLAGS) -ootp_9229/x-1.0/ebin otp_9229/x-1.0/src/mylib.erl
+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
diff --git a/lib/reltool/test/reltool_server_SUITE_data/otp_9229/x-1.0/ebin/x.app b/lib/reltool/test/reltool_server_SUITE_data/otp_9229/x-1.0/ebin/x.app
new file mode 100644
index 0000000000..e597704b19
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/otp_9229/x-1.0/ebin/x.app
@@ -0,0 +1,7 @@
+%% -*- erlang -*-
+{application, x,
+ [{description, "X CXC 138 11"},
+ {vsn, "1.0"},
+ {modules, [x, mylib]},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.
diff --git a/lib/reltool/test/reltool_server_SUITE_data/otp_9229/x-1.0/src/mylib.erl b/lib/reltool/test/reltool_server_SUITE_data/otp_9229/x-1.0/src/mylib.erl
new file mode 100644
index 0000000000..c8603d1a8e
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/otp_9229/x-1.0/src/mylib.erl
@@ -0,0 +1,4 @@
+-module(mylib).
+-export([foo/0]).
+
+foo() -> erlang:time().
diff --git a/lib/reltool/test/reltool_server_SUITE_data/otp_9229/x-1.0/src/x.erl b/lib/reltool/test/reltool_server_SUITE_data/otp_9229/x-1.0/src/x.erl
new file mode 100644
index 0000000000..17ff84f08f
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/otp_9229/x-1.0/src/x.erl
@@ -0,0 +1,4 @@
+-module(x).
+-export([x/0]).
+
+x() ->mylib:foo().
diff --git a/lib/reltool/test/reltool_server_SUITE_data/otp_9229/y-1.0/ebin/y.app b/lib/reltool/test/reltool_server_SUITE_data/otp_9229/y-1.0/ebin/y.app
new file mode 100644
index 0000000000..5b327862e3
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/otp_9229/y-1.0/ebin/y.app
@@ -0,0 +1,7 @@
+%% -*- erlang -*-
+{application, y,
+ [{description, "Y CXC 138 11"},
+ {vsn, "1.0"},
+ {modules, [y, mylib]},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.
diff --git a/lib/reltool/test/reltool_server_SUITE_data/otp_9229/y-1.0/src/mylib.erl b/lib/reltool/test/reltool_server_SUITE_data/otp_9229/y-1.0/src/mylib.erl
new file mode 100644
index 0000000000..c8603d1a8e
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/otp_9229/y-1.0/src/mylib.erl
@@ -0,0 +1,4 @@
+-module(mylib).
+-export([foo/0]).
+
+foo() -> erlang:time().
diff --git a/lib/reltool/test/reltool_server_SUITE_data/otp_9229/y-1.0/src/y.erl b/lib/reltool/test/reltool_server_SUITE_data/otp_9229/y-1.0/src/y.erl
new file mode 100644
index 0000000000..342e7da7d5
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/otp_9229/y-1.0/src/y.erl
@@ -0,0 +1,4 @@
+-module(y).
+-export([y/0]).
+
+y() ->mylib:foo().
diff --git a/lib/reltool/test/reltool_test_lib.erl b/lib/reltool/test/reltool_test_lib.erl
index 25978294ee..b8bcbcd009 100644
--- a/lib/reltool/test/reltool_test_lib.erl
+++ b/lib/reltool/test/reltool_test_lib.erl
@@ -1,19 +1,19 @@
%%
%% %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%
-module(reltool_test_lib).
@@ -24,9 +24,11 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
init_per_suite(Config) when is_list(Config)->
+ global:register_name(reltool_global_logger, group_leader()),
incr_timetrap(Config, 5).
end_per_suite(Config) when is_list(Config)->
+ global:unregister_name(reltool_global_logger),
ok.
incr_timetrap(Config, Times) ->
@@ -95,7 +97,7 @@ wx_init_per_suite(Config) ->
exit({skipped, "Can not test on MacOSX"});
{unix, _} ->
io:format("DISPLAY ~s~n", [os:getenv("DISPLAY")]),
- case proplists:get_value(xserver, Config, none) of
+ case ct:get_config(xserver, none) of
none -> ignore;
Server -> os:putenv("DISPLAY", Server)
end;
@@ -130,11 +132,9 @@ wx_end_per_suite(Config) ->
init_per_testcase(_Func, Config) when is_list(Config) ->
set_kill_timer(Config),
- global:register_name(reltool_global_logger, group_leader()),
Config.
end_per_testcase(_Func, Config) when is_list(Config) ->
- global:unregister_name(reltool_global_logger),
reset_kill_timer(Config),
Config.
@@ -295,7 +295,7 @@ eval_test_case(Mod, Fun, Config) ->
test_case_evaluator(Mod, Fun, [Config]) ->
NewConfig = Mod:init_per_testcase(Fun, Config),
R = apply(Mod, Fun, [NewConfig]),
- Mod:fin_per_testcase(Fun, NewConfig),
+ Mod:end_per_testcase(Fun, NewConfig),
exit({test_case_ok, R}).
wait_for_evaluator(Pid, Mod, Fun, Config) ->
@@ -311,12 +311,12 @@ wait_for_evaluator(Pid, Mod, Fun, Config) ->
{'EXIT', Pid, {skipped, Reason}} ->
log("<WARNING> Test case ~w skipped, because ~p~n",
[{Mod, Fun}, Reason]),
- Mod:fin_per_testcase(Fun, Config),
+ Mod:end_per_testcase(Fun, Config),
{skip, {Mod, Fun}, Reason};
{'EXIT', Pid, Reason} ->
log("<ERROR> Eval process ~w exited, because\n\t~p~n",
[{Mod, Fun}, Reason]),
- Mod:fin_per_testcase(Fun, Config),
+ Mod:end_per_testcase(Fun, Config),
{crash, {Mod, Fun}, Reason}
end.
diff --git a/lib/reltool/test/reltool_test_lib.hrl b/lib/reltool/test/reltool_test_lib.hrl
index 93134144ea..b592ebb2f0 100644
--- a/lib/reltool/test/reltool_test_lib.hrl
+++ b/lib/reltool/test/reltool_test_lib.hrl
@@ -1,23 +1,24 @@
%%
%% %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%
-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)).
diff --git a/lib/reltool/test/reltool_wx_SUITE.erl b/lib/reltool/test/reltool_wx_SUITE.erl
index 2e2b355e07..424bc7d189 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. All Rights Reserved.
+%% Copyright Ericsson AB 2009-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
@@ -18,8 +18,9 @@
-module(reltool_wx_SUITE).
--export([all/0, init_per_suite/1, end_per_suite/1,
- init_per_testcase/2, fin_per_testcase/2, end_per_testcase/2]).
+-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).
@@ -36,16 +37,22 @@ 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).
-fin_per_testcase(Func,Config) -> %% For test_server
- reltool_test_lib:end_per_testcase(Func,Config).
%% SUITE specification
-all() ->
- all(suite).
-all(suite) ->
- [
- start_all_windows
- ].
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [start_all_windows].
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
%% The test cases
diff --git a/lib/reltool/test/rtt b/lib/reltool/test/rtt
index 2411195338..1f93396196 100755
--- a/lib/reltool/test/rtt
+++ b/lib/reltool/test/rtt
@@ -1,19 +1,19 @@
#! /bin/sh -f
# %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%
# Usage: rtt [-cerl] <args to erlang startup script>
@@ -23,7 +23,7 @@ while [ $# -gt 0 ]; do
case "$1" in
"-cerl")
shift
- emu=cerl
+ emu="$ERL_TOP/bin/cerl"
;;
*)
break
diff --git a/lib/reltool/test/rtt.erl b/lib/reltool/test/rtt.erl
index 6755b8400f..437009e26a 100644
--- a/lib/reltool/test/rtt.erl
+++ b/lib/reltool/test/rtt.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009. All Rights Reserved.
+%% 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
diff --git a/lib/reltool/vsn.mk b/lib/reltool/vsn.mk
index 118827a449..751f9bb6db 100644
--- a/lib/reltool/vsn.mk
+++ b/lib/reltool/vsn.mk
@@ -1,9 +1 @@
-RELTOOL_VSN = 0.5.3
-
-TICKETS = OTP-8057
-TICKETS_0_5_2 = OTP-8254
-TICKETS_0_5_1 = OTP-8199
-TICKETS_0_5 = OTP-7949
-TICKETS_0_2_2 = OTP-7999
-TICKETS_2_2_1 = OTP-7840
-TICKETS_0_2 = OTP-7805
+RELTOOL_VSN = 0.5.7