From e39c093f4cdc55084d27d378d64dd2bc464dec0b Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Fri, 25 Nov 2011 15:31:55 +0100 Subject: Rename create_target.xml to create_target.xmlsrc to prepare for codeinclude --- system/doc/system_principles/create_target.xml | 497 ---------------------- system/doc/system_principles/create_target.xmlsrc | 496 +++++++++++++++++++++ 2 files changed, 496 insertions(+), 497 deletions(-) delete mode 100644 system/doc/system_principles/create_target.xml create mode 100644 system/doc/system_principles/create_target.xmlsrc (limited to 'system/doc') diff --git a/system/doc/system_principles/create_target.xml b/system/doc/system_principles/create_target.xml deleted file mode 100644 index 7d9f4681b9..0000000000 --- a/system/doc/system_principles/create_target.xml +++ /dev/null @@ -1,497 +0,0 @@ - - - - -
- - 20022009 - Ericsson AB. 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. - - - - Creating a First Target System - Peter Högfeldt - - - - - 2002-09-17 - A - create_target.xml -
- -
- Introduction -

When creating a system using Erlang/OTP, the most simple way is - to install Erlang/OTP somewhere, install the application specific - code somewhere else, and then start the Erlang runtime system, - making sure the code path includes the application specific code.

-

Often it is not desirable to use an Erlang/OTP system as is. A - developer may create new Erlang/OTP compliant applications for a - particular purpose, and several original Erlang/OTP applications - may be irrelevant for the purpose in question. Thus, there is a - need to be able to create a new system based on a given - Erlang/OTP system, where dispensable applications are removed, - and a set of new applications that are included in the new - system. Documentation and source code is irrelevant and is - therefore not included in the new system.

-

This chapter is about creating such a system, which we call a - target system.

-

In the following sections we consider creating target systems with - different requirements of functionality:

- - a basic target system that can be started by - calling the ordinary erl script, - a simple target system where also code - replacement in run-time can be performed, and - an embedded target system where there is also - support for logging output from the system to file for later - inspection, and where the system can be started automatically - at boot time. - -

We only consider the case when Erlang/OTP is running on a UNIX - system.

-

There is an example Erlang module target_system.erl that - contains functions for creating and installing a target system. - That module is used in the examples below. The source code of - the module is listed at the end of this chapter.

-
- -
- Creating a Target System -

It is assumed that you have a working Erlang/OTP system structured - according to the OTP Design Principles.

-

Step 1. First create a .rel file (see - rel(4)) that specifies the erts version - and lists all applications that should be included in the new - basic target system. An example is the following - mysystem.rel file:

- -%% mysystem.rel -{release, - {"MYSYSTEM", "FIRST"}, - {erts, "5.1"}, - [{kernel, "2.7"}, - {stdlib, "1.10"}, - {sasl, "1.9.3"}, - {pea, "1.0"}]}. -

The listed applications are not only original Erlang/OTP - applications but possibly also new applications that you have - written yourself (here examplified by the application - pea).

-

Step 2. From the directory where the mysystem.rel - file reside, start the Erlang/OTP system:

-
-os> erl -pa /home/user/target_system/myapps/pea-1.0/ebin
-

where also the path to the pea-1.0 ebin directory is - provided.

-

Step 3. Now create the target system:

-
-1> target_system:create("mysystem").
-

The target_system:create/1 function does the following:

- - Reads the mysystem.rel file, and creates a new file - plain.rel which is identical to former, except that it - only lists the kernel and stdlib applications. - From the mysystem.rel and plain.rel files - creates the files mysystem.script, - mysystem.boot, plain.script, and - plain.boot through a call to - systools:make_script/2. - -

Creates the file mysystem.tar.gz by a call to - systools:make_tar/2. That file has the following - contents:

- -erts-5.1/bin/ -releases/FIRST/start.boot -releases/mysystem.rel -lib/kernel-2.7/ -lib/stdlib-1.10/ -lib/sasl-1.9.3/ -lib/pea-1.0/ -

The file releases/FIRST/start.boot is a copy of our - mysystem.boot, and a copy of the original - mysystem.rel has been put in the releases - directory.

-
- Creates the temporary directory tmp and extracts the tar file - mysystem.tar.gz into that directory. - Deletes the erl and start files from - tmp/erts-5.1/bin. XXX Why. - Creates the directory tmp/bin. - Copies the previously creates file plain.boot to - tmp/bin/start.boot. - Copies the files epmd, run_erl, and - to_erl from the directory tmp/erts-5.1/bin to - the directory tmp/bin. - Creates the file tmp/releases/start_erl.data with the - contents "5.1 FIRST". - - Recreates the file mysystem.tar.gz from the directories - in the directory tmp, and removes tmp. -
-
- -
- Installing a Target System -

Step 4. Install the created target system in a - suitable directory.

-
-2> target_system:install("mysystem", "/usr/local/erl-target").
-

The function target_system:install/2 does the following: -

- - Extracts the tar file mysystem.tar.gz into the target - directory /usr/local/erl-target. - In the target directory reads the file releases/start_erl.data - in order to find the Erlang runtime system version ("5.1"). - Substitutes %FINAL_ROOTDIR% and %EMU% for - /usr/local/erl-target and beam, respectively, in - the files erl.src, start.src, and - start_erl.src of the target erts-5.1/bin - directory, and puts the resulting files erl, - start, and run_erl in the target bin - directory. - Finally the target releases/RELEASES file is created - from data in the releases/mysystem.rel file. - -
- -
- Starting a Target System -

Now we have a target system that can be started in various ways.

-

We start it as a basic target system by invoking

-
-os> /usr/local/erl-target/bin/erl
-

where only the kernel and stdlib applications are - started, i.e. the system is started as an ordinary development - system. There are only two files needed for all this to work: - bin/erl file (obtained from erts-5.1/bin/erl.src) - and the bin/start.boot file (a copy of plain.boot).

-

We can also start a distributed system (requires bin/epmd).

-

To start all applications specified in the original - mysystem.rel file, use the -boot flag as follows:

-
-os> /usr/local/erl-target/bin/erl -boot /usr/local/erl-target/releases/FIRST/start
-

We start a simple target system as above. The only difference - is that also the file releases/RELEASES is present for - code replacement in run-time to work.

-

To start an embedded target system the shell script - bin/start is used. That shell script calls - bin/run_erl, which in turn calls bin/start_erl - (roughly, start_erl is an embedded variant of - erl).

-

The shell script start is only an example. You should - edit it to suite your needs. Typically it is executed when the - UNIX system boots.

-

run_erl is a wrapper that provides logging of output from - the run-time system to file. It also provides a simple mechanism - for attaching to the Erlang shell (to_erl).

-

start_erl requires the root directory - ("/usr/local/erl-target"), the releases directory - ("/usr/local/erl-target/releases"), and the location of - the start_erl.data file. It reads the run-time system - version ("5.1") and release version ("FIRST") from - the start_erl.data file, starts the run-time system of the - version found, and provides -boot flag specifying the boot - file of the release version found - ("releases/FIRST/start.boot").

-

start_erl also assumes that there is sys.config in - release version directory ("releases/FIRST/sys.config). That - is the topic of the next section (see below).

-

The start_erl shell script should normally not be - altered by the user.

-
- -
- System Configuration Parameters -

As was pointed out above start_erl requires a - sys.config in the release version directory - ("releases/FIRST/sys.config"). If there is no such a - file, the system start will fail. Hence such a file has to - added as well.

-

-

If you have system configuration data that are neither file - location dependent nor site dependent, it may be convenient to - create the sys.config early, so that it becomes a part of - the target system tar file created by - target_system:create/1. In fact, if you create, in the - current directory, not only the mysystem.rel file, but - also a sys.config file, that latter file will be tacitly - put in the apropriate directory.

-
- -
- Differences from the Install Script -

The above install/2 procedure differs somewhat from that - of the ordinary Install shell script. In fact, create/1 - makes the release package as complete as possible, and leave to the - install/2 procedure to finish by only considering location - dependent files.

-
- -
- Listing of target_system.erl - - RelFile = RelFileName ++ ".rel", - io:fwrite("Reading file: \"~s\" ...~n", [RelFile]), - {ok, [RelSpec]} = file:consult(RelFile), - io:fwrite("Creating file: \"~s\" from \"~s\" ...~n", - ["plain.rel", RelFile]), - {release, - {RelName, RelVsn}, - {erts, ErtsVsn}, - AppVsns} = RelSpec, - PlainRelSpec = {release, - {RelName, RelVsn}, - {erts, ErtsVsn}, - lists:filter(fun({kernel, _}) -> - true; - ({stdlib, _}) -> - true; - (_) -> - false - end, AppVsns) - }, - {ok, Fd} = file:open("plain.rel", [write]), - io:fwrite(Fd, "~p.~n", [PlainRelSpec]), - file:close(Fd), - - io:fwrite("Making \"plain.script\" and \"plain.boot\" files ...~n"), - make_script("plain"), - - io:fwrite("Making \"~s.script\" and \"~s.boot\" files ...~n", - [RelFileName, RelFileName]), - make_script(RelFileName), - - TarFileName = io_lib:fwrite("~s.tar.gz", [RelFileName]), - io:fwrite("Creating tar file \"~s\" ...~n", [TarFileName]), - make_tar(RelFileName), - - io:fwrite("Creating directory \"tmp\" ...~n"), - file:make_dir("tmp"), - - io:fwrite("Extracting \"~s\" into directory \"tmp\" ...~n", [TarFileName]), - extract_tar(TarFileName, "tmp"), - - TmpBinDir = filename:join(["tmp", "bin"]), - ErtsBinDir = filename:join(["tmp", "erts-" ++ ErtsVsn, "bin"]), - io:fwrite("Deleting \"erl\" and \"start\" in directory \"~s\" ...~n", - [ErtsBinDir]), - file:delete(filename:join([ErtsBinDir, "erl"])), - file:delete(filename:join([ErtsBinDir, "start"])), - - io:fwrite("Creating temporary directory \"~s\" ...~n", [TmpBinDir]), - file:make_dir(TmpBinDir), - - io:fwrite("Copying file \"plain.boot\" to \"~s\" ...~n", - [filename:join([TmpBinDir, "start.boot"])]), - copy_file("plain.boot", filename:join([TmpBinDir, "start.boot"])), - - io:fwrite("Copying files \"epmd\", \"run_erl\" and \"to_erl\" from \n" - "\"~s\" to \"~s\" ...~n", - [ErtsBinDir, TmpBinDir]), - copy_file(filename:join([ErtsBinDir, "epmd"]), - filename:join([TmpBinDir, "epmd"]), [preserve]), - copy_file(filename:join([ErtsBinDir, "run_erl"]), - filename:join([TmpBinDir, "run_erl"]), [preserve]), - copy_file(filename:join([ErtsBinDir, "to_erl"]), - filename:join([TmpBinDir, "to_erl"]), [preserve]), - - StartErlDataFile = filename:join(["tmp", "releases", "start_erl.data"]), - io:fwrite("Creating \"~s\" ...~n", [StartErlDataFile]), - StartErlData = io_lib:fwrite("~s ~s~n", [ErtsVsn, RelVsn]), - write_file(StartErlDataFile, StartErlData), - - io:fwrite("Recreating tar file \"~s\" from contents in directory " - "\"tmp\" ...~n", [TarFileName]), - {ok, Tar} = erl_tar:open(TarFileName, [write, compressed]), - {ok, Cwd} = file:get_cwd(), - file:set_cwd("tmp"), - erl_tar:add(Tar, "bin", []), - erl_tar:add(Tar, "erts-" ++ ErtsVsn, []), - erl_tar:add(Tar, "releases", []), - erl_tar:add(Tar, "lib", []), - erl_tar:close(Tar), - file:set_cwd(Cwd), - io:fwrite("Removing directory \"tmp\" ...~n"), - remove_dir_tree("tmp"), - ok. - - -install(RelFileName, RootDir) -> - TarFile = RelFileName ++ ".tar.gz", - io:fwrite("Extracting ~s ...~n", [TarFile]), - extract_tar(TarFile, RootDir), - StartErlDataFile = filename:join([RootDir, "releases", "start_erl.data"]), - {ok, StartErlData} = read_txt_file(StartErlDataFile), - [ErlVsn, RelVsn| _] = string:tokens(StartErlData, " \n"), - ErtsBinDir = filename:join([RootDir, "erts-" ++ ErlVsn, "bin"]), - BinDir = filename:join([RootDir, "bin"]), - io:fwrite("Substituting in erl.src, start.src and start_erl.src to\n" - "form erl, start and start_erl ...\n"), - subst_src_scripts(["erl", "start", "start_erl"], ErtsBinDir, BinDir, - [{"FINAL_ROOTDIR", RootDir}, {"EMU", "beam"}], - [preserve]), - io:fwrite("Creating the RELEASES file ...\n"), - create_RELEASES(RootDir, - filename:join([RootDir, "releases", RelFileName])). - -%% LOCALS - -%% make_script(RelFileName) -%% -make_script(RelFileName) -> - Opts = [no_module_tests], - systools:make_script(RelFileName, Opts). - -%% make_tar(RelFileName) -%% -make_tar(RelFileName) -> - RootDir = code:root_dir(), - systools:make_tar(RelFileName, [{erts, RootDir}]). - -%% extract_tar(TarFile, DestDir) -%% -extract_tar(TarFile, DestDir) -> - erl_tar:extract(TarFile, [{cwd, DestDir}, compressed]). - -create_RELEASES(DestDir, RelFileName) -> - release_handler:create_RELEASES(DestDir, RelFileName ++ ".rel"). - -subst_src_scripts(Scripts, SrcDir, DestDir, Vars, Opts) -> - lists:foreach(fun(Script) -> - subst_src_script(Script, SrcDir, DestDir, - Vars, Opts) - end, Scripts). - -subst_src_script(Script, SrcDir, DestDir, Vars, Opts) -> - subst_file(filename:join([SrcDir, Script ++ ".src"]), - filename:join([DestDir, Script]), - Vars, Opts). - -subst_file(Src, Dest, Vars, Opts) -> - {ok, Conts} = read_txt_file(Src), - NConts = subst(Conts, Vars), - write_file(Dest, NConts), - case lists:member(preserve, Opts) of - true -> - {ok, FileInfo} = file:read_file_info(Src), - file:write_file_info(Dest, FileInfo); - false -> - ok - end. - -%% subst(Str, Vars) -%% Vars = [{Var, Val}] -%% Var = Val = string() -%% Substitute all occurrences of %Var% for Val in Str, using the list -%% of variables in Vars. -%% -subst(Str, Vars) -> - subst(Str, Vars, []). - -subst([$%, C| Rest], Vars, Result) when $A =< C, C =< $Z -> - subst_var([C| Rest], Vars, Result, []); -subst([$%, C| Rest], Vars, Result) when $a =< C, C =< $z -> - subst_var([C| Rest], Vars, Result, []); -subst([$%, C| Rest], Vars, Result) when C == $_ -> - subst_var([C| Rest], Vars, Result, []); -subst([C| Rest], Vars, Result) -> - subst(Rest, Vars, [C| Result]); -subst([], _Vars, Result) -> - lists:reverse(Result). - -subst_var([$%| Rest], Vars, Result, VarAcc) -> - Key = lists:reverse(VarAcc), - case lists:keysearch(Key, 1, Vars) of - {value, {Key, Value}} -> - subst(Rest, Vars, lists:reverse(Value, Result)); - false -> - subst(Rest, Vars, [$%| VarAcc ++ [$%| Result]]) - end; -subst_var([C| Rest], Vars, Result, VarAcc) -> - subst_var(Rest, Vars, Result, [C| VarAcc]); -subst_var([], Vars, Result, VarAcc) -> - subst([], Vars, [VarAcc ++ [$%| Result]]). - -copy_file(Src, Dest) -> - copy_file(Src, Dest, []). - -copy_file(Src, Dest, Opts) -> - {ok, InFd} = file:open(Src, [raw, binary, read]), - {ok, OutFd} = file:open(Dest, [raw, binary, write]), - do_copy_file(InFd, OutFd), - file:close(InFd), - file:close(OutFd), - case lists:member(preserve, Opts) of - true -> - {ok, FileInfo} = file:read_file_info(Src), - file:write_file_info(Dest, FileInfo); - false -> - ok - end. - -do_copy_file(InFd, OutFd) -> - case file:read(InFd, ?BUFSIZE) of - {ok, Bin} -> - file:write(OutFd, Bin), - do_copy_file(InFd, OutFd); - eof -> - ok - end. - -write_file(FName, Conts) -> - {ok, Fd} = file:open(FName, [write]), - file:write(Fd, Conts), - file:close(Fd). - -read_txt_file(File) -> - {ok, Bin} = file:read_file(File), - {ok, binary_to_list(Bin)}. - -remove_dir_tree(Dir) -> - remove_all_files(".", [Dir]). - -remove_all_files(Dir, Files) -> - lists:foreach(fun(File) -> - FilePath = filename:join([Dir, File]), - {ok, FileInfo} = file:read_file_info(FilePath), - case FileInfo#file_info.type of - directory -> - {ok, DirFiles} = file:list_dir(FilePath), - remove_all_files(FilePath, DirFiles), - file:del_dir(FilePath); - _ -> - file:delete(FilePath) - end - end, Files). - ]]> -
-
- diff --git a/system/doc/system_principles/create_target.xmlsrc b/system/doc/system_principles/create_target.xmlsrc new file mode 100644 index 0000000000..1564423e00 --- /dev/null +++ b/system/doc/system_principles/create_target.xmlsrc @@ -0,0 +1,496 @@ + + + + +
+ + 20022011 + Ericsson AB. 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. + + + + Creating a First Target System + Peter Högfeldt + + + + + 2002-09-17 + A + create_target.xml +
+ +
+ Introduction +

When creating a system using Erlang/OTP, the most simple way is + to install Erlang/OTP somewhere, install the application specific + code somewhere else, and then start the Erlang runtime system, + making sure the code path includes the application specific code.

+

Often it is not desirable to use an Erlang/OTP system as is. A + developer may create new Erlang/OTP compliant applications for a + particular purpose, and several original Erlang/OTP applications + may be irrelevant for the purpose in question. Thus, there is a + need to be able to create a new system based on a given + Erlang/OTP system, where dispensable applications are removed, + and a set of new applications that are included in the new + system. Documentation and source code is irrelevant and is + therefore not included in the new system.

+

This chapter is about creating such a system, which we call a + target system.

+

In the following sections we consider creating target systems with + different requirements of functionality:

+ + a basic target system that can be started by + calling the ordinary erl script, + a simple target system where also code + replacement in run-time can be performed, and + an embedded target system where there is also + support for logging output from the system to file for later + inspection, and where the system can be started automatically + at boot time. + +

We only consider the case when Erlang/OTP is running on a UNIX + system.

+

There is an example Erlang module target_system.erl that + contains functions for creating and installing a target system. + That module is used in the examples below. The source code of + the module is listed at the end of this chapter.

+
+ +
+ Creating a Target System +

It is assumed that you have a working Erlang/OTP system structured + according to the OTP Design Principles.

+

Step 1. First create a .rel file (see + rel(4)) that specifies the erts version + and lists all applications that should be included in the new + basic target system. An example is the following + mysystem.rel file:

+ +%% mysystem.rel +{release, + {"MYSYSTEM", "FIRST"}, + {erts, "5.1"}, + [{kernel, "2.7"}, + {stdlib, "1.10"}, + {sasl, "1.9.3"}, + {pea, "1.0"}]}. +

The listed applications are not only original Erlang/OTP + applications but possibly also new applications that you have + written yourself (here examplified by the application + pea).

+

Step 2. From the directory where the mysystem.rel + file reside, start the Erlang/OTP system:

+
+os> erl -pa /home/user/target_system/myapps/pea-1.0/ebin
+

where also the path to the pea-1.0 ebin directory is + provided.

+

Step 3. Now create the target system:

+
+1> target_system:create("mysystem").
+

The target_system:create/1 function does the following:

+ + Reads the mysystem.rel file, and creates a new file + plain.rel which is identical to former, except that it + only lists the kernel and stdlib applications. + From the mysystem.rel and plain.rel files + creates the files mysystem.script, + mysystem.boot, plain.script, and + plain.boot through a call to + systools:make_script/2. + +

Creates the file mysystem.tar.gz by a call to + systools:make_tar/2. That file has the following + contents:

+ +erts-5.1/bin/ +releases/FIRST/start.boot +releases/mysystem.rel +lib/kernel-2.7/ +lib/stdlib-1.10/ +lib/sasl-1.9.3/ +lib/pea-1.0/ +

The file releases/FIRST/start.boot is a copy of our + mysystem.boot, and a copy of the original + mysystem.rel has been put in the releases + directory.

+
+ Creates the temporary directory tmp and extracts the tar file + mysystem.tar.gz into that directory. + Deletes the erl and start files from + tmp/erts-5.1/bin. XXX Why. + Creates the directory tmp/bin. + Copies the previously creates file plain.boot to + tmp/bin/start.boot. + Copies the files epmd, run_erl, and + to_erl from the directory tmp/erts-5.1/bin to + the directory tmp/bin. + Creates the file tmp/releases/start_erl.data with the + contents "5.1 FIRST". + + Recreates the file mysystem.tar.gz from the directories + in the directory tmp, and removes tmp. +
+
+ +
+ Installing a Target System +

Step 4. Install the created target system in a + suitable directory.

+
+2> target_system:install("mysystem", "/usr/local/erl-target").
+

The function target_system:install/2 does the following: +

+ + Extracts the tar file mysystem.tar.gz into the target + directory /usr/local/erl-target. + In the target directory reads the file releases/start_erl.data + in order to find the Erlang runtime system version ("5.1"). + Substitutes %FINAL_ROOTDIR% and %EMU% for + /usr/local/erl-target and beam, respectively, in + the files erl.src, start.src, and + start_erl.src of the target erts-5.1/bin + directory, and puts the resulting files erl, + start, and run_erl in the target bin + directory. + Finally the target releases/RELEASES file is created + from data in the releases/mysystem.rel file. + +
+ +
+ Starting a Target System +

Now we have a target system that can be started in various ways.

+

We start it as a basic target system by invoking

+
+os> /usr/local/erl-target/bin/erl
+

where only the kernel and stdlib applications are + started, i.e. the system is started as an ordinary development + system. There are only two files needed for all this to work: + bin/erl file (obtained from erts-5.1/bin/erl.src) + and the bin/start.boot file (a copy of plain.boot).

+

We can also start a distributed system (requires bin/epmd).

+

To start all applications specified in the original + mysystem.rel file, use the -boot flag as follows:

+
+os> /usr/local/erl-target/bin/erl -boot /usr/local/erl-target/releases/FIRST/start
+

We start a simple target system as above. The only difference + is that also the file releases/RELEASES is present for + code replacement in run-time to work.

+

To start an embedded target system the shell script + bin/start is used. That shell script calls + bin/run_erl, which in turn calls bin/start_erl + (roughly, start_erl is an embedded variant of + erl).

+

The shell script start is only an example. You should + edit it to suite your needs. Typically it is executed when the + UNIX system boots.

+

run_erl is a wrapper that provides logging of output from + the run-time system to file. It also provides a simple mechanism + for attaching to the Erlang shell (to_erl).

+

start_erl requires the root directory + ("/usr/local/erl-target"), the releases directory + ("/usr/local/erl-target/releases"), and the location of + the start_erl.data file. It reads the run-time system + version ("5.1") and release version ("FIRST") from + the start_erl.data file, starts the run-time system of the + version found, and provides -boot flag specifying the boot + file of the release version found + ("releases/FIRST/start.boot").

+

start_erl also assumes that there is sys.config in + release version directory ("releases/FIRST/sys.config). That + is the topic of the next section (see below).

+

The start_erl shell script should normally not be + altered by the user.

+
+ +
+ System Configuration Parameters +

As was pointed out above start_erl requires a + sys.config in the release version directory + ("releases/FIRST/sys.config"). If there is no such a + file, the system start will fail. Hence such a file has to + added as well.

+

+

If you have system configuration data that are neither file + location dependent nor site dependent, it may be convenient to + create the sys.config early, so that it becomes a part of + the target system tar file created by + target_system:create/1. In fact, if you create, in the + current directory, not only the mysystem.rel file, but + also a sys.config file, that latter file will be tacitly + put in the apropriate directory.

+
+ +
+ Differences from the Install Script +

The above install/2 procedure differs somewhat from that + of the ordinary Install shell script. In fact, create/1 + makes the release package as complete as possible, and leave to the + install/2 procedure to finish by only considering location + dependent files.

+
+ +
+ Listing of target_system.erl + + RelFile = RelFileName ++ ".rel", + io:fwrite("Reading file: \"~s\" ...~n", [RelFile]), + {ok, [RelSpec]} = file:consult(RelFile), + io:fwrite("Creating file: \"~s\" from \"~s\" ...~n", + ["plain.rel", RelFile]), + {release, + {RelName, RelVsn}, + {erts, ErtsVsn}, + AppVsns} = RelSpec, + PlainRelSpec = {release, + {RelName, RelVsn}, + {erts, ErtsVsn}, + lists:filter(fun({kernel, _}) -> + true; + ({stdlib, _}) -> + true; + (_) -> + false + end, AppVsns) + }, + {ok, Fd} = file:open("plain.rel", [write]), + io:fwrite(Fd, "~p.~n", [PlainRelSpec]), + file:close(Fd), + + io:fwrite("Making \"plain.script\" and \"plain.boot\" files ...~n"), + make_script("plain"), + + io:fwrite("Making \"~s.script\" and \"~s.boot\" files ...~n", + [RelFileName, RelFileName]), + make_script(RelFileName), + + TarFileName = io_lib:fwrite("~s.tar.gz", [RelFileName]), + io:fwrite("Creating tar file \"~s\" ...~n", [TarFileName]), + make_tar(RelFileName), + + io:fwrite("Creating directory \"tmp\" ...~n"), + file:make_dir("tmp"), + + io:fwrite("Extracting \"~s\" into directory \"tmp\" ...~n", [TarFileName]), + extract_tar(TarFileName, "tmp"), + + TmpBinDir = filename:join(["tmp", "bin"]), + ErtsBinDir = filename:join(["tmp", "erts-" ++ ErtsVsn, "bin"]), + io:fwrite("Deleting \"erl\" and \"start\" in directory \"~s\" ...~n", + [ErtsBinDir]), + file:delete(filename:join([ErtsBinDir, "erl"])), + file:delete(filename:join([ErtsBinDir, "start"])), + + io:fwrite("Creating temporary directory \"~s\" ...~n", [TmpBinDir]), + file:make_dir(TmpBinDir), + + io:fwrite("Copying file \"plain.boot\" to \"~s\" ...~n", + [filename:join([TmpBinDir, "start.boot"])]), + copy_file("plain.boot", filename:join([TmpBinDir, "start.boot"])), + + io:fwrite("Copying files \"epmd\", \"run_erl\" and \"to_erl\" from \n" + "\"~s\" to \"~s\" ...~n", + [ErtsBinDir, TmpBinDir]), + copy_file(filename:join([ErtsBinDir, "epmd"]), + filename:join([TmpBinDir, "epmd"]), [preserve]), + copy_file(filename:join([ErtsBinDir, "run_erl"]), + filename:join([TmpBinDir, "run_erl"]), [preserve]), + copy_file(filename:join([ErtsBinDir, "to_erl"]), + filename:join([TmpBinDir, "to_erl"]), [preserve]), + + StartErlDataFile = filename:join(["tmp", "releases", "start_erl.data"]), + io:fwrite("Creating \"~s\" ...~n", [StartErlDataFile]), + StartErlData = io_lib:fwrite("~s ~s~n", [ErtsVsn, RelVsn]), + write_file(StartErlDataFile, StartErlData), + + io:fwrite("Recreating tar file \"~s\" from contents in directory " + "\"tmp\" ...~n", [TarFileName]), + {ok, Tar} = erl_tar:open(TarFileName, [write, compressed]), + {ok, Cwd} = file:get_cwd(), + file:set_cwd("tmp"), + erl_tar:add(Tar, "bin", []), + erl_tar:add(Tar, "erts-" ++ ErtsVsn, []), + erl_tar:add(Tar, "releases", []), + erl_tar:add(Tar, "lib", []), + erl_tar:close(Tar), + file:set_cwd(Cwd), + io:fwrite("Removing directory \"tmp\" ...~n"), + remove_dir_tree("tmp"), + ok. + + +install(RelFileName, RootDir) -> + TarFile = RelFileName ++ ".tar.gz", + io:fwrite("Extracting ~s ...~n", [TarFile]), + extract_tar(TarFile, RootDir), + StartErlDataFile = filename:join([RootDir, "releases", "start_erl.data"]), + {ok, StartErlData} = read_txt_file(StartErlDataFile), + [ErlVsn, RelVsn| _] = string:tokens(StartErlData, " \n"), + ErtsBinDir = filename:join([RootDir, "erts-" ++ ErlVsn, "bin"]), + BinDir = filename:join([RootDir, "bin"]), + io:fwrite("Substituting in erl.src, start.src and start_erl.src to\n" + "form erl, start and start_erl ...\n"), + subst_src_scripts(["erl", "start", "start_erl"], ErtsBinDir, BinDir, + [{"FINAL_ROOTDIR", RootDir}, {"EMU", "beam"}], + [preserve]), + io:fwrite("Creating the RELEASES file ...\n"), + create_RELEASES(RootDir, + filename:join([RootDir, "releases", RelFileName])). + +%% LOCALS + +%% make_script(RelFileName) +%% +make_script(RelFileName) -> + Opts = [no_module_tests], + systools:make_script(RelFileName, Opts). + +%% make_tar(RelFileName) +%% +make_tar(RelFileName) -> + RootDir = code:root_dir(), + systools:make_tar(RelFileName, [{erts, RootDir}]). + +%% extract_tar(TarFile, DestDir) +%% +extract_tar(TarFile, DestDir) -> + erl_tar:extract(TarFile, [{cwd, DestDir}, compressed]). + +create_RELEASES(DestDir, RelFileName) -> + release_handler:create_RELEASES(DestDir, RelFileName ++ ".rel"). + +subst_src_scripts(Scripts, SrcDir, DestDir, Vars, Opts) -> + lists:foreach(fun(Script) -> + subst_src_script(Script, SrcDir, DestDir, + Vars, Opts) + end, Scripts). + +subst_src_script(Script, SrcDir, DestDir, Vars, Opts) -> + subst_file(filename:join([SrcDir, Script ++ ".src"]), + filename:join([DestDir, Script]), + Vars, Opts). + +subst_file(Src, Dest, Vars, Opts) -> + {ok, Conts} = read_txt_file(Src), + NConts = subst(Conts, Vars), + write_file(Dest, NConts), + case lists:member(preserve, Opts) of + true -> + {ok, FileInfo} = file:read_file_info(Src), + file:write_file_info(Dest, FileInfo); + false -> + ok + end. + +%% subst(Str, Vars) +%% Vars = [{Var, Val}] +%% Var = Val = string() +%% Substitute all occurrences of %Var% for Val in Str, using the list +%% of variables in Vars. +%% +subst(Str, Vars) -> + subst(Str, Vars, []). + +subst([$%, C| Rest], Vars, Result) when $A =< C, C =< $Z -> + subst_var([C| Rest], Vars, Result, []); +subst([$%, C| Rest], Vars, Result) when $a =< C, C =< $z -> + subst_var([C| Rest], Vars, Result, []); +subst([$%, C| Rest], Vars, Result) when C == $_ -> + subst_var([C| Rest], Vars, Result, []); +subst([C| Rest], Vars, Result) -> + subst(Rest, Vars, [C| Result]); +subst([], _Vars, Result) -> + lists:reverse(Result). + +subst_var([$%| Rest], Vars, Result, VarAcc) -> + Key = lists:reverse(VarAcc), + case lists:keysearch(Key, 1, Vars) of + {value, {Key, Value}} -> + subst(Rest, Vars, lists:reverse(Value, Result)); + false -> + subst(Rest, Vars, [$%| VarAcc ++ [$%| Result]]) + end; +subst_var([C| Rest], Vars, Result, VarAcc) -> + subst_var(Rest, Vars, Result, [C| VarAcc]); +subst_var([], Vars, Result, VarAcc) -> + subst([], Vars, [VarAcc ++ [$%| Result]]). + +copy_file(Src, Dest) -> + copy_file(Src, Dest, []). + +copy_file(Src, Dest, Opts) -> + {ok, InFd} = file:open(Src, [raw, binary, read]), + {ok, OutFd} = file:open(Dest, [raw, binary, write]), + do_copy_file(InFd, OutFd), + file:close(InFd), + file:close(OutFd), + case lists:member(preserve, Opts) of + true -> + {ok, FileInfo} = file:read_file_info(Src), + file:write_file_info(Dest, FileInfo); + false -> + ok + end. + +do_copy_file(InFd, OutFd) -> + case file:read(InFd, ?BUFSIZE) of + {ok, Bin} -> + file:write(OutFd, Bin), + do_copy_file(InFd, OutFd); + eof -> + ok + end. + +write_file(FName, Conts) -> + {ok, Fd} = file:open(FName, [write]), + file:write(Fd, Conts), + file:close(Fd). + +read_txt_file(File) -> + {ok, Bin} = file:read_file(File), + {ok, binary_to_list(Bin)}. + +remove_dir_tree(Dir) -> + remove_all_files(".", [Dir]). + +remove_all_files(Dir, Files) -> + lists:foreach(fun(File) -> + FilePath = filename:join([Dir, File]), + {ok, FileInfo} = file:read_file_info(FilePath), + case FileInfo#file_info.type of + directory -> + {ok, DirFiles} = file:list_dir(FilePath), + remove_all_files(FilePath, DirFiles), + file:del_dir(FilePath); + _ -> + file:delete(FilePath) + end + end, Files). + ]]> +
+
-- cgit v1.2.3