summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFredrik Gustafsson <fredrik@erlang.org>2013-08-01 10:58:14 +0200
committerFredrik Gustafsson <fredrik@erlang.org>2013-08-01 10:58:14 +0200
commit0b2aa6e9ebe55ae84197e776a84d11ceba4c7ae4 (patch)
tree5d0cf33524f9e3b4a9a53589feffc588bdd0128d
parent630e979a7c1dbac7d69ada279e12ed4ffb3a9b4a (diff)
parentaf0c479f47c91fd1da1a0642b5176d0512e98b54 (diff)
downloaderlang-0b2aa6e9ebe55ae84197e776a84d11ceba4c7ae4.tar.gz
Merge branch 'hm/reltool_script' into pu
-rw-r--r--Makefile.in2
-rw-r--r--erts/etc/unix/Install.src1
-rw-r--r--erts/etc/win32/Install.c2
-rwxr-xr-xlib/reltool/bin/reltool289
-rwxr-xr-xlib/reltool/bin/reltool.escript249
-rw-r--r--lib/reltool/doc/man1/.gitignore0
-rw-r--r--lib/reltool/doc/src/Makefile21
-rw-r--r--lib/reltool/doc/src/files.mk4
-rw-r--r--lib/reltool/doc/src/reltool.xml4
-rw-r--r--lib/reltool/doc/src/reltool_escript.xml98
-rw-r--r--lib/reltool/src/Makefile5
-rw-r--r--lib/reltool/src/reltool.hrl6
-rw-r--r--lib/reltool/test/Makefile1
-rw-r--r--lib/reltool/test/reltool_escript_SUITE.erl657
-rw-r--r--lib/reltool/test/reltool_server_SUITE.erl1
-rw-r--r--lib/reltool/vsn.mk2
16 files changed, 1074 insertions, 268 deletions
diff --git a/Makefile.in b/Makefile.in
index d1fd64632c..85e0f3c89a 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -124,7 +124,7 @@ BINDIR = $(DESTDIR)$(EXTRA_PREFIX)$(bindir)
#
# Erlang base public files
#
-ERL_BASE_PUB_FILES=erl erlc epmd run_erl to_erl dialyzer typer escript ct_run
+ERL_BASE_PUB_FILES=erl erlc epmd run_erl to_erl dialyzer typer escript reltool ct_run
# ERLANG_INST_LIBDIR is the top directory where the Erlang installation
# will be located when running.
diff --git a/erts/etc/unix/Install.src b/erts/etc/unix/Install.src
index 0f33258a28..420d2773ca 100644
--- a/erts/etc/unix/Install.src
+++ b/erts/etc/unix/Install.src
@@ -91,6 +91,7 @@ cp -p "$ERL_ROOT/erts-%I_VSN%/bin/dialyzer" .
cp -p "$ERL_ROOT/erts-%I_VSN%/bin/typer" .
cp -p "$ERL_ROOT/erts-%I_VSN%/bin/ct_run" .
cp -p "$ERL_ROOT/erts-%I_VSN%/bin/escript" .
+cp -p "reltool" "$ERL_ROOT/erts-%I_VSN%/bin/"
#
# Set a soft link to epmd
diff --git a/erts/etc/win32/Install.c b/erts/etc/win32/Install.c
index dd02a9c111..2ccd610bb6 100644
--- a/erts/etc/win32/Install.c
+++ b/erts/etc/win32/Install.c
@@ -46,7 +46,7 @@ int main(int argc, char **argv)
HANDLE module = GetModuleHandle(NULL);
char *binaries[] = { "erl.exe", "werl.exe", "erlc.exe",
"dialyzer.exe", "typer.exe",
- "escript.exe", "ct_run.exe", NULL };
+ "escript.exe", "reltool", "ct_run.exe", NULL };
char *scripts[] = { "start_clean.boot", "start_sasl.boot", NULL };
char fromname[MAX_PATH];
char toname[MAX_PATH];
diff --git a/lib/reltool/bin/reltool b/lib/reltool/bin/reltool
new file mode 100755
index 0000000000..589185b2ed
--- /dev/null
+++ b/lib/reltool/bin/reltool
@@ -0,0 +1,289 @@
+#!/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, ReasonStr} ->
+ fatal_error(ReasonStr, 1)
+ end
+ catch
+ throw:usage ->
+ usage(),
+ safe_stop(1);
+ throw:help ->
+ usage(),
+ safe_stop(0);
+ throw:{error, ReasonStr2} ->
+ fatal_error(ReasonStr2, 1);
+ exit:Reason ->
+ ReasonStr2 = lists:flatten(io_lib:format("EXIT: ~p", [Reason])),
+ fatal_error(ReasonStr2, 2)
+ end.
+
+usage() ->
+ Usage =
+ [
+ "[Config] --gui (start GUI)",
+ "[Config] --get_config [-defaults] [-derived] [File] (retrieve config info)",
+ "[Config] --get_rel RelName [File] (retrieve release info)",
+ "[Config] --get_script RelName [File] (retrieve boot script)",
+ "[Config] --create_target TargetDir (create target system)",
+ "[Config] --get_target_spec [File] (retrieve target spec)",
+ "--eval_target_spec Spec RootDir TargetDir (evaluate target spec)",
+ "--help (display this help)"
+ ],
+ Script = script_name(),
+ Signature = lists:flatten([[Script, " ", U, "\n"] || U <- Usage]),
+ io:format("Reltool is the release management tool of Erlang/OTP\n"
+ "\n"
+ "It analyses a given Erlang/OTP installation and determines\n"
+ "various dependencies between its applications. The graphical\n"
+ "frontend depicts the dependencies and enables interactive\n"
+ "customization of a target system. The backend provides a\n"
+ "batch interface for generation of customized target systems.\n"
+ "\n"
+ "~s"
+ "\n"
+ "Config = File | 'sys()'\n"
+ "File = filename()\n"
+ "RelName = rel_name()\n"
+ "TargetDir = target_dir()\n"
+ "Spec = File | 'target_spec()'\n"
+ "RootDir = root_dir()\n"
+ "\n"
+ "Exit status:\n"
+ " 0 - OK\n"
+ " 1 - error\n"
+ " 2 - internal error\n"
+ "\n"
+ "See the User's guide and Reference manual of reltool"
+ " for more info.\n",
+ [Signature]).
+
+safe_stop(Code) ->
+ init:stop(Code),
+ timer:sleep(infinity).
+
+invoke(Options, Actions) ->
+ case Actions of
+ [["--gui"]] ->
+ start_window(Options);
+ [["--get_config" | OptArgs]] ->
+ OptArgs2 = OptArgs -- ["-defaults"],
+ OptArgs3 = OptArgs2 -- ["-derived"],
+ InclDef = OptArgs2 =/= OptArgs,
+ InclDeriv = OptArgs3 =/= OptArgs2,
+ {ok, Config} = do_invoke(Options, reltool, get_config,
+ [InclDef, InclDeriv]),
+ String = pretty("config", Config),
+ case OptArgs3 of
+ [] ->
+ format("~s", [String]);
+ [ConfigFile] ->
+ write_file(ConfigFile, String);
+ _ ->
+ throw(usage)
+ end;
+ [["--get_rel", RelName | OptArgs]] ->
+ {ok, Rel} = do_invoke(Options, reltool, get_rel, [RelName]),
+ String = pretty("rel", Rel),
+ case OptArgs of
+ [] ->
+ format("~s", [String]);
+ [RelFile] ->
+ write_file(RelFile, String);
+ _ ->
+ throw(usage)
+ end;
+ [["--get_script", RelName | OptArgs]] ->
+ {ok, Script} = do_invoke(Options, reltool, get_script, [RelName]),
+ String = pretty("script", Script),
+ case OptArgs of
+ [] ->
+ format("~s", [String]);
+ [ScriptFile] ->
+ write_file(ScriptFile, String);
+ _ ->
+ throw(usage)
+ end;
+ [["--create_target", TargetDir]] ->
+ do_invoke(Options, reltool, create_target, [TargetDir]);
+ [["--get_target_spec" | OptArgs]] ->
+ {ok, Script} = do_invoke(Options, reltool, get_target_spec, []),
+ String = pretty("target_spec", Script),
+ case OptArgs of
+ [] ->
+ format("~s", [String]);
+ [SpecFile] ->
+ write_file(SpecFile, String);
+ _ ->
+ throw(usage)
+ end;
+ [["--eval_target_spec", TargetSpec0, RootDir, TargetDir]] ->
+ {spec, TargetSpec} = read_term(TargetSpec0, spec),
+ case reltool:eval_target_spec(TargetSpec, RootDir, TargetDir) of
+ ok ->
+ ok;
+ {error, ReasonStr} ->
+ throw({error, ReasonStr})
+ end;
+ _ ->
+ throw(usage)
+ end.
+
+do_invoke(Options, M, F, A) ->
+ case reltool:start_server(Options) of
+ {ok, ServerPid} ->
+ case reltool:get_status(ServerPid) of
+ {ok, Warnings} ->
+ [io:format(standard_error,
+ "WARNING: ~s\n", [W]) || W <- Warnings],
+ Res = apply(M, F, [ServerPid | A]),
+ _StopRes = reltool:stop(ServerPid),
+ case Res of
+ {error, ReasonStr} ->
+ throw({error, ReasonStr});
+ _ ->
+ Res
+ end;
+ {error, ReasonStr} ->
+ throw({error, ReasonStr})
+ end;
+ {error, ReasonStr} ->
+ throw({error, ReasonStr})
+ 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, ReasonStr} ->
+ throw({error, ReasonStr})
+ end.
+
+read_term("-"++_, _Tag) ->
+ throw(usage);
+read_term(String, Tag) ->
+ case file:consult(String) of
+ {ok, [{Tag, _} = Term]} ->
+ Term;
+ {ok, Terms} ->
+ ReasonStr = lists:flatten(io_lib:format("Illegal ~p: ~p",
+ [Tag, Terms])),
+ throw({error, ReasonStr});
+ {error, FileReason} ->
+ try
+ {ok, Tokens, _} = erl_scan:string(String ++ ". "),
+ {ok, {Tag, _} = Term} = erl_parse:parse_term(Tokens),
+ Term
+ catch
+ error:{badmatch, _} ->
+ Text = file:format_error(FileReason),
+ throw({error, String ++ ": " ++ Text})
+ end
+ 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
+ ["--help"] ->
+ throw(help);
+ ["--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};
+ [Config0] ->
+ Sys = read_term(Config0, sys),
+ parse_args(T, [{config, Sys} | Options])
+ end;
+parse_args([], Options) ->
+ {lists:reverse(Options), []}.
diff --git a/lib/reltool/bin/reltool.escript b/lib/reltool/bin/reltool.escript
deleted file mode 100755
index 0dcd5ad1e9..0000000000
--- a/lib/reltool/bin/reltool.escript
+++ /dev/null
@@ -1,249 +0,0 @@
-#!/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/man1/.gitignore b/lib/reltool/doc/man1/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/reltool/doc/man1/.gitignore
diff --git a/lib/reltool/doc/src/Makefile b/lib/reltool/doc/src/Makefile
index 2373b5e507..ab65303978 100644
--- a/lib/reltool/doc/src/Makefile
+++ b/lib/reltool/doc/src/Makefile
@@ -40,7 +40,8 @@ include files.mk
# ----------------------------------------------------
XML_FILES = \
- $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \
+ $(BOOK_FILES) $(XML_APPLICATION_FILES) \
+ $(XML_REF1_FILES) $(XML_REF3_FILES) \
$(XML_PART_FILES) $(XML_CHAPTER_FILES)
HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
@@ -48,17 +49,17 @@ HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
INFO_FILE = ../../info
+MAN1_FILES = $(XML_REF1_FILES:%.xml=$(MAN1DIR)/%.1)
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-
# ----------------------------------------------------
-# FLAGS
+# FLAGS
# ----------------------------------------------------
-XML_FLAGS +=
+XML_FLAGS +=
# ----------------------------------------------------
# Targets
@@ -74,11 +75,12 @@ pdf: $(TOP_PDF_FILE)
html:images $(HTML_REF_MAN_FILE)
-man: $(MAN3_FILES)
+man: $(MAN1_FILES) $(MAN3_FILES)
+ mv $(MAN1DIR)/reltool_escript.1 $(MAN1DIR)/reltool.1
images: $(IMAGE_FILES:%=$(HTMLDIR)/%)
-debug opt:
+debug opt:
clean clean_docs:
for file in $(XML_FILES); do \
@@ -87,13 +89,13 @@ clean clean_docs:
fi \
done
rm -rf $(HTMLDIR)/*
- rm -f $(MAN3DIR)/*
+ rm -f $(MAN3DIR)/* $(MAN1DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
# ----------------------------------------------------
# Release Target
-# ----------------------------------------------------
+# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
@@ -103,7 +105,8 @@ release_docs_spec: docs
$(INSTALL_DATA) $(HTMLDIR)/* "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
$(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN1DIR)/* "$(RELEASE_PATH)/man/man1"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man1"
$(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
-
diff --git a/lib/reltool/doc/src/files.mk b/lib/reltool/doc/src/files.mk
index 07b52f4934..265b905456 100644
--- a/lib/reltool/doc/src/files.mk
+++ b/lib/reltool/doc/src/files.mk
@@ -23,6 +23,9 @@ XML_APPLICATION_FILES = \
XML_REF3_FILES = \
reltool.xml
+XML_REF1_FILES = \
+ reltool_escript.xml
+
XML_PART_FILES = \
part.xml
@@ -35,4 +38,3 @@ XML_CHAPTER_FILES = \
BOOK_FILES = book.xml
IMAGE_FILES =
-
diff --git a/lib/reltool/doc/src/reltool.xml b/lib/reltool/doc/src/reltool.xml
index 8437b7a623..a5b5c47d8b 100644
--- a/lib/reltool/doc/src/reltool.xml
+++ b/lib/reltool/doc/src/reltool.xml
@@ -39,7 +39,7 @@
<p><em>Reltool</em> is a release management tool. It analyses a
given Erlang/OTP installation and determines various dependencies
- between applications. The <c>graphical</c> frontend depicts the
+ between its applications. The <c>graphical</c> frontend depicts the
dependencies and enables interactive customization of a target
system. The backend provides a <c>batch</c> interface for
generation of customized target systems.</p>
@@ -697,7 +697,7 @@ target_spec() = [target_spec()]
</func>
<func>
- <name>get_script(Server, Relname) -> {ok, ScriptFile | {error, Reason}</name>
+ <name>get_script(Server, Relname) -> {ok, ScriptFile} | {error, Reason}</name>
<fsummary>Get contents of a boot script file</fsummary>
<type>
<v>Server = server()</v>
diff --git a/lib/reltool/doc/src/reltool_escript.xml b/lib/reltool/doc/src/reltool_escript.xml
new file mode 100644
index 0000000000..507f5ef125
--- /dev/null
+++ b/lib/reltool/doc/src/reltool_escript.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE comref SYSTEM "comref.dtd">
+
+<comref>
+ <header>
+ <copyright>
+ <year>2013</year>
+ <year>2013</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>erl</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>reltool_escript.xml</file>
+ </header>
+ <com>reltool</com>
+ <comsummary>Erlang/OTP release management tool</comsummary>
+ <description>
+ <p><em>Reltool</em> is a release management tool. It analyses a
+ given Erlang/OTP installation and determines various dependencies
+ between its applications. The <c>graphical</c> frontend depicts the
+ dependencies and enables interactive customization of a target
+ system. The backend provides a <c>batch</c> interface for
+ generation of customized target systems.</p>
+ </description>
+ <funcs>
+ <func>
+ <name>reltool --gui></name>
+ <fsummary>Start GUI</fsummary>
+ <desc>
+ <p>Starts the graphical user interface. See <em>reltool:start/1</em>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>reltool [Config] --get_config [-defaults] [-derived] [File]></name>
+ <fsummary>Retrieves actual config</fsummary>
+ <desc>
+ <p>See <em>reltool:get_config/3</em>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>reltool [Config] --get_rel RelName [File]></name>
+ <fsummary>Retrieves actual release info</fsummary>
+ <desc>
+ <p>See <em>reltool:get_rel/2</em>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>reltool [Config] --get_script RelName [File]></name>
+ <fsummary>Retrieves actual boot script</fsummary>
+ <desc>
+ <p>See <em>reltool:get_script/2</em>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>reltool [Config] --create_target TargetDir></name>
+ <fsummary>Generate a target system</fsummary>
+ <desc>
+ <p>See <em>reltool:create_target/2</em>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>reltool [Config] --get_target_spec [SpecFile]</name>
+ <fsummary>Retrieve spec of target system</fsummary>
+ <desc>
+ <p>See <em>reltool:get_target_spec/1</em>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>reltool --eval_target_spec Spec RootDir TargetDir</name>
+ <fsummary>Generate target system from spec</fsummary>
+ <desc>
+ <p>See <em>reltool:eval_target_spec/3</em>.</p>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>SEE ALSO</title>
+ <p><seealso marker="reltool">reltool(3)</seealso></p>
+ </section>
+</comref>
diff --git a/lib/reltool/src/Makefile b/lib/reltool/src/Makefile
index b8387fff96..b95b75f45b 100644
--- a/lib/reltool/src/Makefile
+++ b/lib/reltool/src/Makefile
@@ -52,6 +52,8 @@ APPUP_FILE = reltool.appup
APPUP_SRC = $(APPUP_FILE).src
APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
+ESCRIPT_FILE = reltool
+
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -103,6 +105,7 @@ release_spec: opt
$(INSTALL_DIR) "$(RELSYSDIR)/ebin"
$(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
$(INSTALL_DATA) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/bin"
+ $(INSTALL_PROGRAM) ../bin/$(ESCRIPT_FILE) "$(RELEASE_PATH)/bin/$(ESCRIPT_FILE)"
release_docs_spec:
-
diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl
index f0d8b38519..f38a732b0f 100644
--- a/lib/reltool/src/reltool.hrl
+++ b/lib/reltool/src/reltool.hrl
@@ -287,8 +287,8 @@
"^lib",
"^releases"]).
-define(EMBEDDED_EXCL_SYS_FILTERS,
- ["^bin/(erlc|dialyzer|typer)(|\\.exe)\$",
- "^erts.*/bin/(erlc|dialyzer|typer)(|\\.exe)\$",
+ ["^bin/(erlc|dialyzer|reltool|typer)(|\\.exe)\$",
+ "^erts.*/bin/(erlc|dialyzer|reltool|typer)(|\\.exe)\$",
"^erts.*/bin/.*(debug|pdb)"]).
-define(EMBEDDED_INCL_APP_FILTERS, ["^ebin",
"^include",
@@ -301,7 +301,7 @@
"^erts.*/bin",
"^lib\$"]).
-define(STANDALONE_EXCL_SYS_FILTERS,
- ["^erts.*/bin/(erlc|dialyzer|typer)(|\\.exe)\$",
+ ["^erts.*/bin/(erlc|dialyzer|reltool|typer)(|\\.exe)\$",
"^erts.*/bin/(start|escript|to_erl|run_erl)(|\\.exe)\$",
"^erts.*/bin/.*(debug|pdb)"]).
-define(STANDALONE_INCL_APP_FILTERS, ["^ebin",
diff --git a/lib/reltool/test/Makefile b/lib/reltool/test/Makefile
index 52cdef44da..caf36ff991 100644
--- a/lib/reltool/test/Makefile
+++ b/lib/reltool/test/Makefile
@@ -28,6 +28,7 @@ MODULES= \
reltool_app_SUITE \
reltool_wx_SUITE \
reltool_server_SUITE \
+ reltool_escript_SUITE \
reltool_manual_gui_SUITE \
reltool_test_lib
diff --git a/lib/reltool/test/reltool_escript_SUITE.erl b/lib/reltool/test/reltool_escript_SUITE.erl
new file mode 100644
index 0000000000..0e2685cd93
--- /dev/null
+++ b/lib/reltool/test/reltool_escript_SUITE.erl
@@ -0,0 +1,657 @@
+%% -*- coding: utf-8 -*-
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. 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_escript_SUITE).
+
+-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
+ init_per_suite/1, end_per_suite/1,
+ init_per_testcase/2, end_per_testcase/2]).
+
+-compile(export_all).
+
+-include_lib("reltool/src/reltool.hrl").
+-include("reltool_test_lib.hrl").
+-include_lib("common_test/include/ct.hrl").
+-include_lib("kernel/include/file.hrl").
+
+-define(NODE_NAME, '__RELTOOL__TEMPORARY_TEST__NODE__').
+-define(WORK_DIR, "reltool_work_dir").
+-define(TMP_IN_FILE, "tmp_reltool_infile").
+-define(TMP_OUT_FILE, "tmp_reltool_outfile").
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Initialization functions.
+
+init_per_suite(Config) ->
+ {ok,Cwd} = file:get_cwd(),
+ ?ignore(file:make_dir(?WORK_DIR)),
+ [{cwd,Cwd}|reltool_test_lib:init_per_suite(Config)].
+
+end_per_suite(Config) ->
+ reltool_test_lib:end_per_suite(Config).
+
+init_per_testcase(Func,Config) ->
+ Node = full_node_name(?NODE_NAME),
+ case net_adm:ping(Node) of
+ pong -> stop_node(Node);
+ pang -> ok
+ end,
+ reltool_test_lib:init_per_testcase(Func,Config).
+
+end_per_testcase(Func,Config) ->
+ ok = file:set_cwd(filename:join(?config(cwd,Config),?WORK_DIR)),
+ {ok,All} = file:list_dir("."),
+ Files = [F || F <- All, false =:= lists:prefix("save.",F)],
+ case ?config(tc_status,Config) of
+ ok ->
+ ok;
+ _Fail ->
+ SaveDir = "save."++atom_to_list(Func),
+ ok = rm_files([SaveDir]),
+ ok = file:make_dir(SaveDir),
+ save_test_result(Files,SaveDir)
+ end,
+ rm_files(Files),
+ ok = file:set_cwd(?config(cwd,Config)),
+ rm_files([?TMP_IN_FILE, ?TMP_OUT_FILE]),
+ reltool_test_lib:end_per_testcase(Func,Config).
+
+save_test_result(Files,DestDir) ->
+ Tar = "copy.tar",
+ ok = erl_tar:create(Tar, Files),
+ ok = erl_tar:extract(Tar, [{cwd,DestDir}]),
+ ok = file:delete(Tar),
+ ok.
+
+rm_files([F | Fs]) ->
+ case file:read_file_info(F) of
+ {ok,#file_info{type=directory}} ->
+ rm_dir(F);
+ {ok,_Regular} ->
+ ok = file:delete(F);
+ {error, enoent} ->
+ ok
+ end,
+ rm_files(Fs);
+rm_files([]) ->
+ ok.
+
+rm_dir(Dir) ->
+ {ok,Files} = file:list_dir(Dir),
+ rm_files([filename:join(Dir, F) || F <- Files]),
+ ok = file:del_dir(Dir).
+
+oscmd(CmdStr) ->
+ io:format("os:cmd(~p)\n", [CmdStr]),
+ Output0 = os:cmd(CmdStr ++ "; echo \";$?\""),
+ Pred = fun(Char) -> Char =/= $; end,
+ {ExitStatus, [$; | RevOutput]} =
+ lists:splitwith(Pred, lists:reverse(Output0)),
+ Output = lists:reverse(RevOutput),
+ ExitStatus2 = string:strip(ExitStatus, left, $\n),
+ {list_to_integer(ExitStatus2), Output}.
+
+-define(w,'%.*%').
+-define(f(Term), lists:flatten(io_lib:format("~p", [Term]))).
+
+reltool_plain(Cmd) ->
+ file:delete(?TMP_OUT_FILE),
+ {ExitCode, Output} = oscmd(Cmd),
+ file:write_file(?TMP_OUT_FILE, Output),
+ case file:consult(?TMP_OUT_FILE) of
+ {ok, Term} ->
+ file:delete(?TMP_OUT_FILE),
+ {ExitCode, {ok, Term}};
+ {error, _Reason} ->
+ file:delete(?TMP_OUT_FILE),
+ {ExitCode, {error, Output}}
+ end.
+
+reltool(Cmd) ->
+ Plain = reltool_plain(Cmd),
+ File = reltool_file(Cmd),
+ ?m(Plain, File).
+
+reltool_file(Cmd) ->
+ file:delete(?TMP_OUT_FILE),
+ {ExitCode, Output} = oscmd(Cmd ++ " " ++ ?TMP_OUT_FILE),
+ case file:consult(?TMP_OUT_FILE) of
+ {ok, Term} ->
+ file:delete(?TMP_OUT_FILE),
+ {ExitCode, {ok, Term}};
+ {error, _Reason} ->
+ file:delete(?TMP_OUT_FILE),
+ {ExitCode, {error, _Reason, Output}}
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SUITE specification
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [start_gui,
+ get_config,
+ create_release,
+ create_script,
+ create_target,
+ eval_target_spec
+ ].
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+%% The test cases
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% A dummy break test case which is NOT in all(), but can be run
+%% directly from the command line with ct_run. It just does a
+%% test_server:break()...
+break(_Config) ->
+ test_server:break(""),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Start the GUI
+
+start_gui(_Config) ->
+ ?m({1, {error, "reltool: noSUCHfile: no such file or directory\n"}},
+ reltool_plain("reltool noSUCHfile --gui")),
+ %% ?m({0,""}, oscmd("reltool --gui")),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Check that get_config returns the expected derivates and defaults
+%% as specified
+get_config(_Config) ->
+ KernVsn = latest(kernel),
+ StdVsn = latest(stdlib),
+ SaslVsn = latest(sasl),
+ LibDir = code:lib_dir(),
+ StdLibDir = filename:join(LibDir,"stdlib-"++StdVsn),
+ KernLibDir = filename:join(LibDir,"kernel-"++KernVsn),
+ SaslLibDir = filename:join(LibDir,"sasl-"++SaslVsn),
+
+ ?m({0, {ok, [{sys,[]}]}},
+ reltool("reltool --get_config")),
+
+ Sys = {sys,[{incl_cond, exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include},{vsn,SaslVsn}]},
+ {app,stdlib,[{incl_cond,include},{lib_dir,StdLibDir}]}]},
+ ?m(ok, file:write_file(?TMP_IN_FILE, ?f(Sys) ++ ".")),
+
+ ?m({0, {ok, [Sys]}},
+ reltool("reltool " ++ ?TMP_IN_FILE ++ " --get_config")),
+
+ %% Include derived info
+ ?msym({0,
+ {ok, [{sys,[{incl_cond, exclude},
+ {erts,[]},
+ {app,kernel,[{incl_cond,include},{mod,_,[]}|_]},
+ {app,sasl,[{incl_cond,include},{vsn,SaslVsn},{mod,_,[]}|_]},
+ {app,stdlib,[{incl_cond,include},{lib_dir,StdLibDir},
+ {mod,_,[]}|_]}]}]}},
+ reltool("reltool " ++ ?TMP_IN_FILE ++ " --get_config -derived")),
+
+ %% Include defaults
+ ?msym({0,
+ {ok, [{sys,[{root_dir,_},
+ {lib_dirs,_},
+ {mod_cond,all},
+ {incl_cond,exclude},
+ {app,kernel,[{incl_cond,include},{vsn,undefined},
+ {lib_dir,undefined}]},
+ {app,sasl,[{incl_cond,include},{vsn,SaslVsn},
+ {lib_dir,undefined}]},
+ {app,stdlib,[{incl_cond,include},{vsn,undefined},
+ {lib_dir,StdLibDir}]},
+ {boot_rel,"start_clean"},
+ {rel,"start_clean","1.0",[]},
+ {rel,"start_sasl","1.0",[sasl]},
+ {emu_name,"beam"},
+ {relocatable,true},
+ {profile,development},
+ {incl_sys_filters,[".*"]},
+ {excl_sys_filters,[]},
+ {incl_app_filters,[".*"]},
+ {excl_app_filters,[]},
+ {incl_archive_filters,[".*"]},
+ {excl_archive_filters,["^include$","^priv$"]},
+ {archive_opts,[]},
+ {rel_app_type,permanent},
+ {app_file,keep},
+ {debug_info,keep}]}]}},
+ reltool("reltool " ++ ?TMP_IN_FILE ++ " --get_config -defaults")),
+
+ %% Include both defaults and derived info
+ ?msym({0,
+ {ok, [{sys,[{root_dir,_},
+ {lib_dirs,_},
+ {mod_cond,all},
+ {incl_cond,exclude},
+ {erts,[]},
+ {app,kernel,[{incl_cond,include},{vsn,KernVsn},
+ {lib_dir,KernLibDir},{mod,_,[]}|_]},
+ {app,sasl,[{incl_cond,include},{vsn,SaslVsn},
+ {lib_dir,SaslLibDir},{mod,_,[]}|_]},
+ {app,stdlib,[{incl_cond,include},{vsn,StdVsn},
+ {lib_dir,StdLibDir},{mod,_,[]}|_]},
+ {boot_rel,"start_clean"},
+ {rel,"start_clean","1.0",[]},
+ {rel,"start_sasl","1.0",[sasl]},
+ {emu_name,"beam"},
+ {relocatable,true},
+ {profile,development},
+ {incl_sys_filters,[".*"]},
+ {excl_sys_filters,[]},
+ {incl_app_filters,[".*"]},
+ {excl_app_filters,[]},
+ {incl_archive_filters,[".*"]},
+ {excl_archive_filters,["^include$","^priv$"]},
+ {archive_opts,[]},
+ {rel_app_type,permanent},
+ {app_file,keep},
+ {debug_info,keep}]}]}},
+ reltool("reltool " ++ ?TMP_IN_FILE ++
+ " --get_config -derived -defaults")),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate releases
+
+create_release(_Config) ->
+ %% Configure the server
+ RelName = "Testing",
+ RelVsn = "1.0",
+ Sys =
+ {sys,
+ [
+ {lib_dirs, []},
+ {boot_rel, RelName},
+ {rel, RelName, RelVsn, [kernel, stdlib]}
+ ]},
+ ?m(ok, file:write_file(?TMP_IN_FILE, ?f(Sys) ++ ".")),
+
+ %% Generate release
+ ErtsVsn = erlang:system_info(version),
+ Apps = application:loaded_applications(),
+ {value, {_, _, KernelVsn}} = lists:keysearch(kernel, 1, Apps),
+ {value, {_, _, StdlibVsn}} = lists:keysearch(stdlib, 1, Apps),
+ Rel =
+ {release, {RelName, RelVsn},
+ {erts, ErtsVsn},
+ [{kernel, KernelVsn}, {stdlib, StdlibVsn}]},
+ ?m({0, {ok,[Rel]}},
+ reltool("reltool " ++ ?TMP_IN_FILE ++
+ " --get_rel " ++ RelName)),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate boot scripts
+
+create_script(_Config) ->
+ %% Configure the server
+ RelName = "TestingMore",
+ RelVsn = "1.0",
+ Sys =
+ {sys,
+ [
+ {lib_dirs, []},
+ {boot_rel, RelName},
+ {rel, RelName, RelVsn, [stdlib, kernel]}
+ ]},
+ ?m(ok, file:write_file(?TMP_IN_FILE, ?f(Sys) ++ ".")),
+
+ %% Generate release file
+ ErtsVsn = erlang:system_info(version),
+ Apps = application:loaded_applications(),
+ {value, {_, _, KernelVsn}} = lists:keysearch(kernel, 1, Apps),
+ {value, {_, _, StdlibVsn}} = lists:keysearch(stdlib, 1, Apps),
+ Rel = {release,
+ {RelName, RelVsn},
+ {erts, ErtsVsn},
+ [{kernel, KernelVsn}, {stdlib, StdlibVsn}]},
+ ?m({0,{ok, [Rel]}},
+ reltool("reltool " ++ ?TMP_IN_FILE ++
+ " --get_rel " ++ RelName)),
+
+ ?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, [])),
+ {ok, [OrigScript]} = ?msym({ok, [_]}, file:consult(RelName ++ ".script")),
+ ?m(ok, file:set_cwd(Cwd)),
+
+ {_, {ok, [Script]}} =
+ ?msym({0, {ok, [_]}},
+ reltool("reltool " ++ ?TMP_IN_FILE ++
+ " --get_script " ++ RelName)),
+
+ %% OrigScript2 = sort_script(OrigScript),
+ %% Script2 = sort_script(Script),
+ %% ?m(OrigScript2, Script2),
+
+ ?m(equal, diff_script(OrigScript, Script)),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate target system
+
+create_target(_Config) ->
+ %% Configure the server
+ RelName1 = "Testing1",
+ RelName2 = "Testing2",
+ RelVsn = "1.0",
+ Sys =
+ {sys,
+ [
+ {root_dir, code:root_dir()},
+ {lib_dirs, []},
+ {boot_rel, RelName2},
+ {rel, RelName1, RelVsn, [stdlib, kernel]},
+ {rel, RelName2, RelVsn, [sasl, stdlib, kernel]},
+ {app, sasl, [{incl_cond, include}]}
+ ]},
+ ?m(ok, file:write_file(?TMP_IN_FILE, ?f(Sys) ++ ".")),
+
+ %% Generate target file
+ TargetDir = filename:join([?WORK_DIR, "target_development"]),
+ ?m(ok, reltool_utils:recursive_delete(TargetDir)),
+ ?m(ok, file:make_dir(TargetDir)),
+
+ ?log("SPEC: ~p\n",
+ [?msym({0, {ok,[_]}},
+ reltool_plain("reltool " ++ ?TMP_IN_FILE ++
+ " --get_target_spec"))]),
+
+ ?msym({0, {ok,[_]}},
+ reltool_file("reltool " ++ ?TMP_IN_FILE ++ " --get_target_spec")),
+
+ ?msym({0, {ok,[]}},
+ reltool_plain("reltool " ++ ?TMP_IN_FILE ++
+ " --create_target " ++ TargetDir)),
+
+ BinDir = filename:join([TargetDir, "bin"]),
+ Erl = filename:join([BinDir, "erl"]),
+ {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
+ ?msym(ok, stop_node(Node)),
+
+ %% Verify that reltool is included
+ Reltool = filename:join([BinDir, "reltool"]),
+ ?m(Reltool, os:find_executable("reltool", BinDir)),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate target system with eval_target_spec/3
+
+eval_target_spec(_Config) ->
+ %% Configure the server
+ RelName1 = "Testing3",
+ RelName2 = "Testing4",
+ RelVsn = "1.0",
+ Sys =
+ {sys,
+ [
+ {root_dir, code:root_dir()},
+ {lib_dirs, []},
+ {boot_rel, RelName2},
+ {rel, RelName1, RelVsn, [stdlib, kernel]},
+ {rel, RelName2, RelVsn, [sasl, stdlib, kernel]},
+ {app, sasl, [{incl_cond, include}]}
+ ]},
+ ?m(ok, file:write_file(?TMP_IN_FILE, ?f(Sys) ++ ".")),
+
+ %% Generate target file
+ TargetDir = filename:join([?WORK_DIR, "eval_target_spec"]),
+ ?m(ok, reltool_utils:recursive_delete(TargetDir)),
+ ?m(ok, file:make_dir(TargetDir)),
+
+ {_, {ok, Spec}} =
+ ?msym({0, {ok,_}},
+ reltool_plain("reltool " ++ ?TMP_IN_FILE ++
+ " --get_target_spec")),
+ ?msym({0, {ok,_}},
+ reltool_file("reltool " ++ ?TMP_IN_FILE ++ " --get_target_spec")),
+
+ ?m(ok, file:write_file(?TMP_IN_FILE, ?f({spec, Spec}) ++ ".")),
+
+ ?msym({0, {ok,""}},
+ reltool_plain("reltool --eval_target_spec " ++ " " ++
+ ?TMP_IN_FILE ++ " " ++
+ code:root_dir() ++ " " ++
+ TargetDir)),
+
+ BinDir = filename:join([TargetDir, "bin"]),
+ Erl = filename:join([BinDir, "erl"]),
+ {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
+ ?msym(ok, stop_node(Node)),
+
+ %% Verify that reltool is included
+ Reltool = filename:join([BinDir, "reltool"]),
+ ?m(Reltool, os:find_executable("reltool", BinDir)),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Library functions
+
+erl_libs() ->
+ case os:getenv("ERL_LIBS") of
+ false -> [];
+ LibStr -> string:tokens(LibStr, ":;")
+ end.
+
+datadir(Config) ->
+ %% Removes the trailing slash...
+ filename:nativename(?config(data_dir,Config)).
+
+latest(App) ->
+ AppStr = atom_to_list(App),
+ AppDirs = filelib:wildcard(filename:join(code:lib_dir(),AppStr++"-*")),
+ [LatestAppDir|_] = lists:reverse(AppDirs),
+ [_,Vsn] = string:tokens(filename:basename(LatestAppDir),"-"),
+ Vsn.
+
+rm_missing_app(Apps) ->
+ lists:keydelete(?MISSING_APP_NAME,#app.name,Apps).
+
+diff_script(Script, Script) ->
+ equal;
+diff_script({script, Rel, Commands1}, {script, Rel, Commands2}) ->
+ diff_cmds(Commands1, Commands2);
+diff_script({script, Rel1, _}, {script, Rel2, _}) ->
+ {error, {Rel1, Rel2}}.
+
+diff_cmds([Cmd | Commands1], [Cmd | Commands2]) ->
+ diff_cmds(Commands1, Commands2);
+diff_cmds([Cmd1 | _Commands1], [Cmd2 | _Commands2]) ->
+ {diff, {expected, Cmd1}, {actual, Cmd2}};
+diff_cmds([], []) ->
+ equal.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Node handling
+
+start_node(Name, ErlPath) ->
+ start_node(Name, ErlPath, []).
+start_node(Name, ErlPath, Args0) ->
+ FullName = full_node_name(Name),
+ Args = mk_node_args(Name, Args0),
+ io:format("Starting node ~p: ~ts~n",
+ [FullName, lists:flatten([[X," "] || X <- [ErlPath|Args]])]),
+ %% io:format("open_port({spawn_executable, ~p},
+ %% [{args,~p}])~n",[ErlPath,Args]),
+ case open_port({spawn_executable, ErlPath}, [{args,Args}]) of
+ Port when is_port(Port) ->
+ %% no need to close port since node is detached (see
+ %% mk_node_args) so port will be closed anyway.
+ case ping_node(FullName, 50) of
+ ok -> {ok, FullName};
+ Other -> exit({failed_to_start_node, FullName, Other})
+ end;
+ Error ->
+ exit({failed_to_start_node, FullName, Error})
+ end.
+
+stop_node(Node) ->
+ rpc:call(Node,erlang,halt,[]),
+ wait_for_node_down(Node,50).
+
+wait_for_node_down(Node,0) ->
+ test_server:fail({cant_terminate_node,Node});
+wait_for_node_down(Node,N) ->
+ case net_adm:ping(Node) of
+ pong ->
+ timer:sleep(1000),
+ wait_for_node_down(Node,N-1);
+ pang ->
+ ok
+ end.
+
+mk_node_args(Name, Args) ->
+ Pa = filename:dirname(code:which(?MODULE)),
+ NameSw = case net_kernel:longnames() of
+ false -> "-sname";
+ true -> "-name";
+ _ -> exit(not_distributed_node)
+ end,
+ {ok, Pwd} = file:get_cwd(),
+ NameStr = atom_to_list(Name),
+ ["-detached",
+ NameSw, NameStr,
+ "-pa", Pa,
+ "-env", "ERL_CRASH_DUMP", Pwd ++ "/erl_crash_dump." ++ NameStr,
+ "-setcookie", atom_to_list(erlang:get_cookie())
+ | Args].
+
+full_node_name(PreName) ->
+ HostSuffix = lists:dropwhile(fun ($@) -> false; (_) -> true end,
+ atom_to_list(node())),
+ list_to_atom(atom_to_list(PreName) ++ HostSuffix).
+
+ping_node(_Node, 0) ->
+ {error, net_adm};
+ping_node(Node, N) when is_integer(N), N > 0 ->
+ case catch net_adm:ping(Node) of
+ pong ->
+ wait_for_process(Node, code_server, 50);
+ _ ->
+ timer:sleep(1000),
+ ping_node(Node, N-1)
+ end.
+
+wait_for_process(_Node, Name, 0) ->
+ {error, Name};
+wait_for_process(Node, Name, N) when is_integer(N), N > 0 ->
+ case rpc:call(Node, erlang, whereis, [Name]) of
+ undefined ->
+ timer:sleep(1000),
+ wait_for_process(Node, Name, N-1);
+ {badrpc, _} = Reason ->
+ erlang:error({Reason, Node});
+ Pid when is_pid(Pid) ->
+ ok
+ end.
+
+wait_for_app(_Node, Name, 0) ->
+ {error, Name};
+wait_for_app(Node, Name, N) when is_integer(N), N > 0 ->
+ case rpc:call(Node,application,which_applications,[]) of
+ {badrpc,Reason} ->
+ test_server:fail({failed_to_get_applications,Reason});
+ Apps ->
+ case lists:member(Name,Apps) of
+ false ->
+ timer:sleep(1000),
+ wait_for_app(Node, Name, N-1);
+ true ->
+ ok
+ end
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Run escript
+
+run(Dir, Script, Args) ->
+ Cmd0 = filename:rootname(Script) ++ " " ++ Args,
+ Cmd = case os:type() of
+ {win32,_} -> filename:nativename(Dir) ++ "\\" ++ Cmd0;
+ _ -> Cmd0
+ end,
+ do_run(Dir, Cmd).
+
+run(Dir, Opts, Script, Args) ->
+ Cmd0 = filename:rootname(Script) ++ " " ++ Args,
+ Cmd = case os:type() of
+ {win32,_} -> Opts ++ " " ++ filename:nativename(Dir) ++ "\\" ++ Cmd0;
+ _ -> Opts ++ " " ++ Dir ++ "/" ++ Cmd0
+ end,
+ do_run(Dir, Cmd).
+
+do_run(Dir, Cmd) ->
+ io:format("Run: ~p\n", [Cmd]),
+ Env = [{"PATH",Dir++":"++os:getenv("PATH")},
+ {"ERL_FLAGS",""}, % Make sure no flags are set that can override
+ {"ERL_ZFLAGS",""}], % any of the flags set in the escript.
+ Port = open_port({spawn,Cmd}, [exit_status,eof,in,{env,Env}]),
+ Res = get_data(Port, []),
+ receive
+ {Port,{exit_status,ExitCode}} ->
+ s2b([Res,"ExitCode:"++integer_to_list(ExitCode)])
+ end.
+
+get_data(Port, SoFar) ->
+ receive
+ {Port,{data,Bytes}} ->
+ get_data(Port, [SoFar|Bytes]);
+ {Port,eof} ->
+ erlang:port_close(Port),
+ SoFar
+ end.
+
+expected_output([data_dir|T], Data) ->
+ Slash = case os:type() of
+ {win32,_} -> "\\";
+ _ -> "/"
+ end,
+ [filename:nativename(Data)++Slash|expected_output(T, Data)];
+expected_output([H|T], Data) ->
+ [H|expected_output(T, Data)];
+expected_output([], _) ->
+ [];
+expected_output(Bin, _) when is_binary(Bin) ->
+ Bin.
+
+%% Convert the given list to a binary with the same encoding as the
+%% file name translation mode
+s2b(List) ->
+ Enc = file:native_name_encoding(),
+ unicode:characters_to_binary(List,Enc,Enc).
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index 752037042d..5df2bdc13f 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -60,6 +60,7 @@ end_per_testcase(Func,Config) ->
ok;
_Fail ->
SaveDir = "save."++atom_to_list(Func),
+ ok = rm_files([SaveDir]),
ok = file:make_dir(SaveDir),
save_test_result(Files,SaveDir)
end,
diff --git a/lib/reltool/vsn.mk b/lib/reltool/vsn.mk
index 412e78f49f..163b77dfa0 100644
--- a/lib/reltool/vsn.mk
+++ b/lib/reltool/vsn.mk
@@ -1 +1 @@
-RELTOOL_VSN = 0.6.4
+RELTOOL_VSN = 0.6.5