~ubuntu-branches/ubuntu/trusty/erlang/trusty

« back to all changes in this revision

Viewing changes to system/doc/system_principles/create_target.xml

  • Committer: Bazaar Package Importer
  • Author(s): Clint Byrum
  • Date: 2011-05-05 15:48:43 UTC
  • mfrom: (3.5.13 sid)
  • Revision ID: james.westby@ubuntu.com-20110505154843-0om6ekzg6m7ugj27
Tags: 1:14.b.2-dfsg-3ubuntu1
* Merge from debian unstable.  Remaining changes:
  - Drop libwxgtk2.8-dev build dependency. Wx isn't in main, and not
    supposed to.
  - Drop erlang-wx binary.
  - Drop erlang-wx dependency from -megaco, -common-test, and -reltool, they
    do not really need wx. Also drop it from -debugger; the GUI needs wx,
    but it apparently has CLI bits as well, and is also needed by -megaco,
    so let's keep the package for now.
  - debian/patches/series: Do what I meant, and enable build-options.patch
    instead.
* Additional changes:
  - Drop erlang-wx from -et
* Dropped Changes:
  - patches/pcre-crash.patch: CVE-2008-2371: outer level option with
    alternatives caused crash. (Applied Upstream)
  - fix for ssl certificate verification in newSSL: 
    ssl_cacertfile_fix.patch (Applied Upstream)
  - debian/patches/series: Enable native.patch again, to get stripped beam
    files and reduce the package size again. (build-options is what
    actually accomplished this)
  - Remove build-options.patch on advice from upstream and because it caused
    odd build failures.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?xml version="1.0" encoding="latin1" ?>
 
2
<!DOCTYPE chapter SYSTEM "chapter.dtd">
 
3
 
 
4
<chapter>
 
5
  <header>
 
6
    <copyright>
 
7
      <year>2002</year><year>2009</year>
 
8
      <holder>Ericsson AB. All Rights Reserved.</holder>
 
9
    </copyright>
 
10
    <legalnotice>
 
11
      The contents of this file are subject to the Erlang Public License,
 
12
      Version 1.1, (the "License"); you may not use this file except in
 
13
      compliance with the License. You should have received a copy of the
 
14
      Erlang Public License along with this software. If not, it can be
 
15
      retrieved online at http://www.erlang.org/.
 
16
    
 
17
      Software distributed under the License is distributed on an "AS IS"
 
18
      basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 
19
      the License for the specific language governing rights and limitations
 
20
      under the License.
 
21
    
 
22
    </legalnotice>
 
23
 
 
24
    <title>Creating a First Target System</title>
 
25
    <prepared>Peter H&ouml;gfeldt</prepared>
 
26
    <responsible></responsible>
 
27
    <docno></docno>
 
28
    <approved></approved>
 
29
    <checked></checked>
 
30
    <date>2002-09-17</date>
 
31
    <rev>A</rev>
 
32
    <file>create_target.xml</file>
 
33
  </header>
 
34
 
 
35
  <section>
 
36
    <title>Introduction</title>
 
37
    <p>When creating a system using Erlang/OTP, the most simple way is
 
38
      to install Erlang/OTP somewhere, install the application specific
 
39
      code somewhere else, and then start the Erlang runtime system,
 
40
      making sure the code path includes the application specific code.</p>
 
41
    <p>Often it is not desirable to use an Erlang/OTP system as is. A
 
42
      developer may create new Erlang/OTP compliant applications for a
 
43
      particular purpose, and several original Erlang/OTP applications
 
44
      may be irrelevant for the purpose in question. Thus, there is a
 
45
      need to be able to create a new system based on a given
 
46
      Erlang/OTP system, where dispensable applications are removed,
 
47
      and a set of new applications that are included in the new
 
48
      system. Documentation and source code is irrelevant and is
 
49
      therefore not included in the new system.</p>
 
50
    <p>This chapter is about creating such a system, which we call a 
 
51
      <em>target system</em>.</p>
 
52
    <p>In the following sections we consider creating target systems with
 
53
      different requirements of functionality:</p>
 
54
    <list type="bulleted">
 
55
      <item>a <em>basic target system</em> that can be started by
 
56
       calling the ordinary <c>erl</c> script, </item>
 
57
      <item>a <em>simple target system</em> where also code
 
58
       replacement in run-time can be performed, and</item>
 
59
      <item>an <em>embedded target system</em> where there is also
 
60
       support for logging output from the system to file for later
 
61
       inspection, and where the system can be started automatically
 
62
       at boot time. </item>
 
63
    </list>
 
64
    <p>We only consider the case when Erlang/OTP is running on a UNIX
 
65
      system.</p>
 
66
    <p>There is an example Erlang module <c>target_system.erl</c> that
 
67
      contains functions for creating and installing a target system.
 
68
      That module is used in the examples below. The source code of
 
69
      the module is listed at the end of this chapter.</p>
 
70
  </section>
 
71
 
 
72
  <section>
 
73
    <title>Creating a Target System</title>
 
74
    <p>It is assumed that you have a working Erlang/OTP system structured
 
75
      according to the OTP Design Principles.</p>
 
76
    <p><em>Step 1.</em> First create a <c>.rel</c> file (see
 
77
      <c>rel(4)</c>) that specifies the <c>erts</c> version
 
78
      and lists all applications that should be included in the new
 
79
      basic target system. An example is the following
 
80
      <c>mysystem.rel</c> file:</p>
 
81
    <code type="none">
 
82
%% mysystem.rel
 
83
{release,
 
84
 {"MYSYSTEM", "FIRST"},
 
85
 {erts, "5.1"},
 
86
 [{kernel, "2.7"},
 
87
  {stdlib, "1.10"},
 
88
  {sasl, "1.9.3"},
 
89
  {pea, "1.0"}]}.    </code>
 
90
    <p>The listed applications are not only original Erlang/OTP
 
91
      applications but possibly also new applications that you have
 
92
      written yourself (here examplified by the application
 
93
      <c>pea</c>). </p>
 
94
    <p><em>Step 2.</em> From the directory where the <c>mysystem.rel</c>
 
95
      file reside, start the Erlang/OTP system:</p>
 
96
    <pre>
 
97
os> <input>erl -pa /home/user/target_system/myapps/pea-1.0/ebin</input></pre>
 
98
    <p>where also the path to the <c>pea-1.0</c> ebin directory is 
 
99
      provided. </p>
 
100
    <p><em>Step 3.</em> Now create the target system: </p>
 
101
    <pre>
 
102
1> <input>target_system:create("mysystem").</input></pre>
 
103
    <p>The <c>target_system:create/1</c> function does the following:</p>
 
104
    <list type="ordered">
 
105
      <item>Reads the <c>mysystem.rel</c> file, and creates a new file
 
106
      <c>plain.rel</c> which is identical to former, except that it
 
107
       only lists the <c>kernel</c> and <c>stdlib</c> applications. </item>
 
108
      <item>From the <c>mysystem.rel</c> and <c>plain.rel</c> files
 
109
       creates the files <c>mysystem.script</c>,
 
110
      <c>mysystem.boot</c>, <c>plain.script</c>, and
 
111
      <c>plain.boot</c> through a call to
 
112
      <c>systools:make_script/2</c>.</item>
 
113
      <item>
 
114
        <p>Creates the file <c>mysystem.tar.gz</c> by a call to
 
115
          <c>systools:make_tar/2</c>. That file has the following
 
116
          contents:</p>
 
117
        <code type="none">
 
118
erts-5.1/bin/
 
119
releases/FIRST/start.boot
 
120
releases/mysystem.rel
 
121
lib/kernel-2.7/
 
122
lib/stdlib-1.10/
 
123
lib/sasl-1.9.3/
 
124
lib/pea-1.0/        </code>
 
125
        <p>The file <c>releases/FIRST/start.boot</c> is a copy of our
 
126
          <c>mysystem.boot</c>, and a copy of the original
 
127
          <c>mysystem.rel</c> has been put in the <c>releases</c>
 
128
          directory.</p>
 
129
      </item>
 
130
      <item>Creates the temporary directory <c>tmp</c> and extracts the tar file
 
131
      <c>mysystem.tar.gz</c> into that directory. </item>
 
132
      <item>Deletes the <c>erl</c> and <c>start</c> files from
 
133
      <c>tmp/erts-5.1/bin</c>. XXX Why.</item>
 
134
      <item>Creates the directory <c>tmp/bin</c>.</item>
 
135
      <item>Copies the previously creates file <c>plain.boot</c> to
 
136
      <c>tmp/bin/start.boot</c>.</item>
 
137
      <item>Copies the files <c>epmd</c>, <c>run_erl</c>, and
 
138
      <c>to_erl</c> from the directory <c>tmp/erts-5.1/bin</c> to
 
139
       the directory <c>tmp/bin</c>.</item>
 
140
      <item>Creates the file <c>tmp/releases/start_erl.data</c> with the 
 
141
       contents "5.1 FIRST".
 
142
      </item>
 
143
      <item>Recreates the file <c>mysystem.tar.gz</c> from the directories
 
144
       in the directory <c>tmp</c>, and removes <c>tmp</c>.</item>
 
145
    </list>
 
146
  </section>
 
147
 
 
148
  <section>
 
149
    <title>Installing a Target System</title>
 
150
    <p><em>Step 4.</em> Install the created target system in a 
 
151
      suitable directory. </p>
 
152
    <pre>
 
153
2> <input>target_system:install("mysystem", "/usr/local/erl-target").</input></pre>
 
154
    <p>The function <c>target_system:install/2</c> does the following:
 
155
      </p>
 
156
    <list type="ordered">
 
157
      <item>Extracts the tar file <c>mysystem.tar.gz</c> into the target
 
158
       directory <c>/usr/local/erl-target</c>.</item>
 
159
      <item>In the target directory reads the file <c>releases/start_erl.data</c>
 
160
       in order to find the Erlang runtime system version ("5.1").</item>
 
161
      <item>Substitutes <c>%FINAL_ROOTDIR%</c> and <c>%EMU%</c> for
 
162
      <c>/usr/local/erl-target</c> and <c>beam</c>, respectively, in
 
163
       the files <c>erl.src</c>, <c>start.src</c>, and
 
164
      <c>start_erl.src</c> of the target <c>erts-5.1/bin</c>
 
165
       directory, and puts the resulting files <c>erl</c>,
 
166
      <c>start</c>, and <c>run_erl</c> in the target <c>bin</c>
 
167
       directory.</item>
 
168
      <item>Finally the target <c>releases/RELEASES</c> file is created
 
169
       from data in the <c>releases/mysystem.rel</c> file.</item>
 
170
    </list>
 
171
  </section>
 
172
 
 
173
  <section>
 
174
    <title>Starting a Target System</title>
 
175
    <p>Now we have a target system that can be started in various ways.</p>
 
176
    <p>We start it as a <em>basic target system</em> by invoking</p>
 
177
    <pre>
 
178
os> <input>/usr/local/erl-target/bin/erl</input></pre>
 
179
    <p>where only the <c>kernel</c> and <c>stdlib</c> applications are
 
180
      started, i.e. the system is started as an ordinary development
 
181
      system. There are only two files needed for all this to work:
 
182
      <c>bin/erl</c> file (obtained from <c>erts-5.1/bin/erl.src</c>)
 
183
      and the <c>bin/start.boot</c> file (a copy of <c>plain.boot</c>).</p>
 
184
    <p>We can also start a distributed system (requires <c>bin/epmd</c>).</p>
 
185
    <p>To start all applications specified in the original
 
186
      <c>mysystem.rel</c> file, use the <c>-boot</c> flag as follows:</p>
 
187
    <pre>
 
188
os> <input>/usr/local/erl-target/bin/erl -boot /usr/local/erl-target/releases/FIRST/start</input></pre>
 
189
    <p>We start a <em>simple target system</em> as above. The only difference
 
190
      is that also the file <c>releases/RELEASES</c> is present for 
 
191
      code replacement in run-time to work.</p>
 
192
    <p>To start an <em>embedded target system</em> the shell script
 
193
      <c>bin/start</c> is used. That shell script calls
 
194
      <c>bin/run_erl</c>, which in turn calls <c>bin/start_erl</c>
 
195
      (roughly, <c>start_erl</c> is an embedded variant of
 
196
      <c>erl</c>). </p>
 
197
    <p>The shell script <c>start</c> is only an example. You should
 
198
      edit it to suite your needs. Typically it is executed when the
 
199
      UNIX system boots.</p>
 
200
    <p><c>run_erl</c> is a wrapper that provides logging of output from
 
201
      the run-time system to file. It also provides a simple mechanism
 
202
      for attaching to the Erlang shell (<c>to_erl</c>).</p>
 
203
    <p><c>start_erl</c> requires the root directory
 
204
      (<c>"/usr/local/erl-target"</c>), the releases directory
 
205
      (<c>"/usr/local/erl-target/releases"</c>), and the location of
 
206
      the <c>start_erl.data</c> file. It reads the run-time system
 
207
      version (<c>"5.1"</c>) and release version (<c>"FIRST"</c>) from
 
208
      the <c>start_erl.data</c> file, starts the run-time system of the
 
209
      version found, and provides <c>-boot</c> flag specifying the boot
 
210
      file of the release version found
 
211
      (<c>"releases/FIRST/start.boot"</c>).</p>
 
212
    <p><c>start_erl</c> also assumes that there is <c>sys.config</c> in
 
213
      release version directory (<c>"releases/FIRST/sys.config</c>). That
 
214
      is the topic of the next section (see below).</p>
 
215
    <p>The <c>start_erl</c> shell script should normally not be
 
216
      altered by the user.</p>
 
217
  </section>
 
218
 
 
219
  <section>
 
220
    <title>System Configuration Parameters</title>
 
221
    <p>As was pointed out above <c>start_erl</c> requires a
 
222
      <c>sys.config</c> in the release version directory
 
223
      (<c>"releases/FIRST/sys.config"</c>). If there is no such a
 
224
      file, the system start will fail. Hence such a file has to
 
225
      added as well.</p>
 
226
    <p></p>
 
227
    <p>If you have system configuration data that are neither file
 
228
      location dependent nor site dependent, it may be convenient to
 
229
      create the <c>sys.config</c> early, so that it becomes a part of
 
230
      the target system tar file created by
 
231
      <c>target_system:create/1</c>. In fact, if you create, in the
 
232
      current directory, not only the <c>mysystem.rel</c> file, but
 
233
      also a <c>sys.config</c> file, that latter file will be tacitly
 
234
      put in the apropriate directory.</p>
 
235
  </section>
 
236
 
 
237
  <section>
 
238
    <title>Differences from the Install Script</title>
 
239
    <p>The above <c>install/2</c> procedure differs somewhat from that
 
240
      of the ordinary <c>Install</c> shell script. In fact, <c>create/1</c>
 
241
      makes the release package as complete as possible, and leave to the
 
242
      <c>install/2</c> procedure to finish by only considering location
 
243
      dependent files.</p>
 
244
  </section>
 
245
 
 
246
  <section>
 
247
    <title>Listing of target_system.erl</title>
 
248
    <code type="none"><![CDATA[
 
249
-module(target_system).
 
250
-include_lib("kernel/include/file.hrl").
 
251
-export([create/1, install/2]).
 
252
-define(BUFSIZE, 8192).
 
253
 
 
254
%% Note: RelFileName below is the *stem* without trailing .rel,
 
255
%% .script etc.
 
256
%%
 
257
 
 
258
%% create(RelFileName)
 
259
%%
 
260
create(RelFileName) ->
 
261
    RelFile = RelFileName ++ ".rel", 
 
262
    io:fwrite("Reading file: \"~s\" ...~n", [RelFile]),
 
263
    {ok, [RelSpec]} = file:consult(RelFile),
 
264
    io:fwrite("Creating file: \"~s\" from \"~s\" ...~n", 
 
265
              ["plain.rel", RelFile]),
 
266
    {release,
 
267
     {RelName, RelVsn},
 
268
     {erts, ErtsVsn},
 
269
     AppVsns} = RelSpec,
 
270
    PlainRelSpec = {release, 
 
271
                    {RelName, RelVsn},
 
272
                    {erts, ErtsVsn},
 
273
                    lists:filter(fun({kernel, _}) -> 
 
274
                                         true;
 
275
                                    ({stdlib, _}) ->
 
276
                                         true;
 
277
                                    (_) ->
 
278
                                         false
 
279
                                 end, AppVsns)
 
280
                   },
 
281
    {ok, Fd} = file:open("plain.rel", [write]),
 
282
    io:fwrite(Fd, "~p.~n", [PlainRelSpec]),
 
283
    file:close(Fd),
 
284
 
 
285
    io:fwrite("Making \"plain.script\" and \"plain.boot\" files ...~n"),
 
286
    make_script("plain"),
 
287
 
 
288
    io:fwrite("Making \"~s.script\" and \"~s.boot\" files ...~n", 
 
289
              [RelFileName, RelFileName]),
 
290
    make_script(RelFileName),
 
291
 
 
292
    TarFileName = io_lib:fwrite("~s.tar.gz", [RelFileName]),
 
293
    io:fwrite("Creating tar file \"~s\" ...~n", [TarFileName]),
 
294
    make_tar(RelFileName),
 
295
 
 
296
    io:fwrite("Creating directory \"tmp\" ...~n"),
 
297
    file:make_dir("tmp"), 
 
298
 
 
299
    io:fwrite("Extracting \"~s\" into directory \"tmp\" ...~n", [TarFileName]),
 
300
    extract_tar(TarFileName, "tmp"),
 
301
 
 
302
    TmpBinDir = filename:join(["tmp", "bin"]),
 
303
    ErtsBinDir = filename:join(["tmp", "erts-" ++ ErtsVsn, "bin"]),
 
304
    io:fwrite("Deleting \"erl\" and \"start\" in directory \"~s\" ...~n", 
 
305
              [ErtsBinDir]),
 
306
    file:delete(filename:join([ErtsBinDir, "erl"])),
 
307
    file:delete(filename:join([ErtsBinDir, "start"])),
 
308
 
 
309
    io:fwrite("Creating temporary directory \"~s\" ...~n", [TmpBinDir]),
 
310
    file:make_dir(TmpBinDir),
 
311
 
 
312
    io:fwrite("Copying file \"plain.boot\" to \"~s\" ...~n", 
 
313
              [filename:join([TmpBinDir, "start.boot"])]),
 
314
    copy_file("plain.boot", filename:join([TmpBinDir, "start.boot"])),
 
315
 
 
316
    io:fwrite("Copying files \"epmd\", \"run_erl\" and \"to_erl\" from \n"
 
317
              "\"~s\" to \"~s\" ...~n", 
 
318
              [ErtsBinDir, TmpBinDir]),
 
319
    copy_file(filename:join([ErtsBinDir, "epmd"]), 
 
320
              filename:join([TmpBinDir, "epmd"]), [preserve]),
 
321
    copy_file(filename:join([ErtsBinDir, "run_erl"]), 
 
322
              filename:join([TmpBinDir, "run_erl"]), [preserve]),
 
323
    copy_file(filename:join([ErtsBinDir, "to_erl"]), 
 
324
              filename:join([TmpBinDir, "to_erl"]), [preserve]),
 
325
 
 
326
    StartErlDataFile = filename:join(["tmp", "releases", "start_erl.data"]),
 
327
    io:fwrite("Creating \"~s\" ...~n", [StartErlDataFile]),
 
328
    StartErlData = io_lib:fwrite("~s ~s~n", [ErtsVsn, RelVsn]),
 
329
    write_file(StartErlDataFile, StartErlData),
 
330
    
 
331
    io:fwrite("Recreating tar file \"~s\" from contents in directory "
 
332
              "\"tmp\" ...~n", [TarFileName]),
 
333
    {ok, Tar} = erl_tar:open(TarFileName, [write, compressed]),
 
334
    {ok, Cwd} = file:get_cwd(),
 
335
    file:set_cwd("tmp"),
 
336
    erl_tar:add(Tar, "bin", []),
 
337
    erl_tar:add(Tar, "erts-" ++ ErtsVsn, []),
 
338
    erl_tar:add(Tar, "releases", []),
 
339
    erl_tar:add(Tar, "lib", []),
 
340
    erl_tar:close(Tar),
 
341
    file:set_cwd(Cwd),
 
342
    io:fwrite("Removing directory \"tmp\" ...~n"),
 
343
    remove_dir_tree("tmp"),
 
344
    ok.
 
345
 
 
346
 
 
347
install(RelFileName, RootDir) ->
 
348
    TarFile = RelFileName ++ ".tar.gz", 
 
349
    io:fwrite("Extracting ~s ...~n", [TarFile]),
 
350
    extract_tar(TarFile, RootDir),
 
351
    StartErlDataFile = filename:join([RootDir, "releases", "start_erl.data"]),
 
352
    {ok, StartErlData} = read_txt_file(StartErlDataFile),
 
353
    [ErlVsn, RelVsn| _] = string:tokens(StartErlData, " \n"),
 
354
    ErtsBinDir = filename:join([RootDir, "erts-" ++ ErlVsn, "bin"]),
 
355
    BinDir = filename:join([RootDir, "bin"]),
 
356
    io:fwrite("Substituting in erl.src, start.src and start_erl.src to\n"
 
357
              "form erl, start and start_erl ...\n"),
 
358
    subst_src_scripts(["erl", "start", "start_erl"], ErtsBinDir, BinDir, 
 
359
                      [{"FINAL_ROOTDIR", RootDir}, {"EMU", "beam"}],
 
360
                      [preserve]),
 
361
    io:fwrite("Creating the RELEASES file ...\n"),
 
362
    create_RELEASES(RootDir, 
 
363
                    filename:join([RootDir, "releases", RelFileName])).
 
364
 
 
365
%% LOCALS 
 
366
 
 
367
%% make_script(RelFileName)
 
368
%%
 
369
make_script(RelFileName) ->
 
370
    Opts = [no_module_tests],
 
371
    systools:make_script(RelFileName, Opts).
 
372
 
 
373
%% make_tar(RelFileName)
 
374
%%
 
375
make_tar(RelFileName) ->
 
376
    RootDir = code:root_dir(),
 
377
    systools:make_tar(RelFileName, [{erts, RootDir}]).
 
378
 
 
379
%% extract_tar(TarFile, DestDir)
 
380
%%
 
381
extract_tar(TarFile, DestDir) ->
 
382
    erl_tar:extract(TarFile, [{cwd, DestDir}, compressed]).
 
383
 
 
384
create_RELEASES(DestDir, RelFileName) ->
 
385
    release_handler:create_RELEASES(DestDir, RelFileName ++ ".rel").
 
386
 
 
387
subst_src_scripts(Scripts, SrcDir, DestDir, Vars, Opts) -> 
 
388
    lists:foreach(fun(Script) ->
 
389
                          subst_src_script(Script, SrcDir, DestDir, 
 
390
                                           Vars, Opts)
 
391
                  end, Scripts).
 
392
 
 
393
subst_src_script(Script, SrcDir, DestDir, Vars, Opts) -> 
 
394
    subst_file(filename:join([SrcDir, Script ++ ".src"]),
 
395
               filename:join([DestDir, Script]),
 
396
               Vars, Opts).
 
397
 
 
398
subst_file(Src, Dest, Vars, Opts) ->
 
399
    {ok, Conts} = read_txt_file(Src),
 
400
    NConts = subst(Conts, Vars),
 
401
    write_file(Dest, NConts),
 
402
    case lists:member(preserve, Opts) of
 
403
        true ->
 
404
            {ok, FileInfo} = file:read_file_info(Src),
 
405
            file:write_file_info(Dest, FileInfo);
 
406
        false ->
 
407
            ok
 
408
    end.
 
409
 
 
410
%% subst(Str, Vars)
 
411
%% Vars = [{Var, Val}]
 
412
%% Var = Val = string()
 
413
%% Substitute all occurrences of %Var% for Val in Str, using the list
 
414
%% of variables in Vars.
 
415
%%
 
416
subst(Str, Vars) ->
 
417
    subst(Str, Vars, []).
 
418
 
 
419
subst([$%, C| Rest], Vars, Result) when $A =< C, C =< $Z ->
 
420
    subst_var([C| Rest], Vars, Result, []);
 
421
subst([$%, C| Rest], Vars, Result) when $a =< C, C =< $z ->
 
422
    subst_var([C| Rest], Vars, Result, []);
 
423
subst([$%, C| Rest], Vars, Result) when  C == $_ ->
 
424
    subst_var([C| Rest], Vars, Result, []);
 
425
subst([C| Rest], Vars, Result) ->
 
426
    subst(Rest, Vars, [C| Result]);
 
427
subst([], _Vars, Result) ->
 
428
    lists:reverse(Result).
 
429
 
 
430
subst_var([$%| Rest], Vars, Result, VarAcc) ->
 
431
    Key = lists:reverse(VarAcc),
 
432
    case lists:keysearch(Key, 1, Vars) of
 
433
        {value, {Key, Value}} ->
 
434
            subst(Rest, Vars, lists:reverse(Value, Result));
 
435
        false ->
 
436
            subst(Rest, Vars, [$%| VarAcc ++ [$%| Result]])
 
437
    end;
 
438
subst_var([C| Rest], Vars, Result, VarAcc) ->
 
439
    subst_var(Rest, Vars, Result, [C| VarAcc]);
 
440
subst_var([], Vars, Result, VarAcc) ->
 
441
    subst([], Vars, [VarAcc ++ [$%| Result]]).
 
442
 
 
443
copy_file(Src, Dest) ->
 
444
    copy_file(Src, Dest, []).
 
445
 
 
446
copy_file(Src, Dest, Opts) ->
 
447
    {ok, InFd} = file:open(Src, [raw, binary, read]),
 
448
    {ok, OutFd} = file:open(Dest, [raw, binary, write]),
 
449
    do_copy_file(InFd, OutFd),
 
450
    file:close(InFd),
 
451
    file:close(OutFd),
 
452
    case lists:member(preserve, Opts) of
 
453
        true ->
 
454
            {ok, FileInfo} = file:read_file_info(Src),
 
455
            file:write_file_info(Dest, FileInfo);
 
456
        false ->
 
457
            ok
 
458
    end.
 
459
 
 
460
do_copy_file(InFd, OutFd) ->
 
461
    case file:read(InFd, ?BUFSIZE) of
 
462
        {ok, Bin} ->
 
463
            file:write(OutFd, Bin),
 
464
            do_copy_file(InFd, OutFd);
 
465
        eof  ->
 
466
            ok
 
467
    end.
 
468
       
 
469
write_file(FName, Conts) ->
 
470
    {ok, Fd} = file:open(FName, [write]),
 
471
    file:write(Fd, Conts),
 
472
    file:close(Fd).
 
473
 
 
474
read_txt_file(File) ->
 
475
    {ok, Bin} = file:read_file(File),
 
476
    {ok, binary_to_list(Bin)}.
 
477
 
 
478
remove_dir_tree(Dir) ->
 
479
    remove_all_files(".", [Dir]).
 
480
 
 
481
remove_all_files(Dir, Files) ->
 
482
    lists:foreach(fun(File) ->
 
483
                          FilePath = filename:join([Dir, File]),
 
484
                          {ok, FileInfo} = file:read_file_info(FilePath),
 
485
                          case FileInfo#file_info.type of
 
486
                              directory ->
 
487
                                  {ok, DirFiles} = file:list_dir(FilePath), 
 
488
                                  remove_all_files(FilePath, DirFiles),
 
489
                                  file:del_dir(FilePath);
 
490
                              _ ->
 
491
                                  file:delete(FilePath)
 
492
                          end
 
493
                  end, Files).
 
494
    ]]></code>
 
495
  </section>
 
496
</chapter>
 
497