bee 0.10.2 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- # Copyright 2006-2010 Michel Casabianca <michel.casabianca@gmail.com>
1
+ # Copyright 2006-2011 Michel Casabianca <michel.casabianca@gmail.com>
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -12,7 +12,9 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- # Module for Bee core classes.
15
+ require 'rubygems'
16
+ require 'bee_util'
17
+
16
18
  module Bee
17
19
 
18
20
  # Class for a target. It is built from the YAML build file and manages a
@@ -50,12 +52,9 @@ module Bee
50
52
  @targets = targets
51
53
  @name = object[Target::KEY]
52
54
  error "Target name cannot be 'null'" if @name == nil
53
- @depends = object['depends']||[]
54
- @depends = Array(@depends)
55
+ @depends = Array(object['depends']||[])
55
56
  @description = object['description']
56
- @script = object['script']
57
- @script = [@script] if @script.kind_of?(String)
58
- @script = [] if not @script
57
+ @script = Array(object['script']||[])
59
58
  end
60
59
 
61
60
  # Run target.
@@ -102,10 +101,12 @@ module Bee
102
101
  # call super target
103
102
  targets.call_super(self, dry)
104
103
  else
105
- # must be a task
104
+ # bee task
106
105
  run_bee_task(task, dry)
107
106
  end
108
107
  end
108
+ else
109
+ raise "Task must be a string or a hash"
109
110
  end
110
111
  end
111
112
 
@@ -129,6 +130,8 @@ module Bee
129
130
  return if dry
130
131
  begin
131
132
  @targets.build.context.evaluate_script(script)
133
+ rescue Interrupt
134
+ raise $!
132
135
  rescue Exception
133
136
  error "Error running Ruby script: #{$!}"
134
137
  end
@@ -144,6 +147,7 @@ module Bee
144
147
 
145
148
  # Run a given construct.
146
149
  # - construct: construct to run as a Hash.
150
+ # -dry: tells if we are running in dry mode. Defaults to false.
147
151
  def run_construct(construct, dry=false)
148
152
  @listener.task(construct) if @listener
149
153
  return if dry
@@ -174,8 +178,10 @@ module Bee
174
178
  unknown_keys = task.keys - ['if', 'then', 'else']
175
179
  error "If-then-else construct may only include 'if', 'then' and 'else' entries" if
176
180
  unknown_keys.length > 0
177
- error "If entry in if-then-else construct must be a string" if
178
- not task['if'].kind_of?(String)
181
+ error "If entry in if-then-else construct must be a string, a symbol or a boolean" if
182
+ not task['if'].kind_of?(String) and
183
+ not task['if'].kind_of?(Symbol) and
184
+ not (task['if'].kind_of?(TrueClass) or task['if'].kind_of?(FalseClass))
179
185
  error "Then entry in if-then-else construct must be a list" if
180
186
  not task['then'].kind_of?(Array)
181
187
  error "Else entry in if-then-else construct must be a list" if
@@ -214,20 +220,24 @@ module Bee
214
220
  def construct_for(task, dry)
215
221
  # test entries
216
222
  error "For-in-do construct must include 'in' and 'do' entries" if
217
- not task.keys.include?('in') or not task.keys.include?('do')
223
+ not task.keys.include?('in') or
224
+ not task.keys.include?('do')
218
225
  unknown_keys = task.keys - ['for', 'in', 'do']
219
226
  error "For-in-do construct may only include 'for', 'in' and 'do' entries" if
220
227
  unknown_keys.length > 0
221
228
  error "For entry in for-in-do construct must be a string" if
222
229
  not task['for'].kind_of?(String)
223
- error "In entry in for-in-do construct must be a list or a string" if
224
- not task['in'].kind_of?(Enumerable) and not task['in'].kind_of?(String)
230
+ error "In entry in for-in-do construct must be a list, a string or a symbol" if
231
+ not task['in'].kind_of?(Enumerable) and
232
+ not task['in'].kind_of?(String) and
233
+ not task['in'].kind_of?(Symbol)
225
234
  error "Do entry in for-in-do construct must be a list" if
226
235
  not task['do'].kind_of?(Array)
227
236
  # iterate over list
228
- if task['in'].kind_of?(String)
229
- enumerable = evaluate(@targets.build.context.
230
- evaluate_object(task['in']))
237
+ if task['in'].kind_of?(String) or task['in'].kind_of?(Symbol)
238
+ enumerable = evaluate(task['in'])
239
+ error "In entry in for-in-do construct must result in an enumerable" if
240
+ not enumerable.kind_of?(Enumerable)
231
241
  else
232
242
  enumerable = task['in']
233
243
  end
@@ -254,13 +264,14 @@ module Bee
254
264
  error "Try entry in try-catch construct must be a list" if
255
265
  not task['try'].kind_of?(Array)
256
266
  error "Catch entry in try-catch construct must be a list" if
257
- not task['catch'].kind_of?(Array)
267
+ task['catch'] and not task['catch'].kind_of?(Array)
258
268
  # try and catch errors
259
269
  begin
260
270
  run_block(task['try'], dry)
261
271
  rescue
262
272
  @targets.build.listener.recover if @targets.build.listener
263
- run_block(task['catch'], dry)
273
+ run_block(task['catch'], dry) if task['catch']
274
+
264
275
  end
265
276
  end
266
277
 
@@ -276,7 +287,13 @@ module Bee
276
287
  # Evaluate a given expression and raise a BuildError if an error happens.
277
288
  def evaluate(expression)
278
289
  begin
279
- return @targets.build.context.evaluate_script(expression)
290
+ if expression.kind_of?(String)
291
+ return @targets.build.context.evaluate_script(expression)
292
+ elsif (expression.kind_of?(TrueClass) or expression.kind_of?(FalseClass))
293
+ return expression
294
+ else
295
+ return @targets.build.context.evaluate_object(expression)
296
+ end
280
297
  rescue
281
298
  error "Error evaluating expression: #{$!}"
282
299
  end
@@ -0,0 +1,147 @@
1
+ # Copyright 2006-2011 Michel Casabianca <michel.casabianca@gmail.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'rubygems'
16
+ require 'bee_util'
17
+ require 'bee_target'
18
+
19
+ module Bee
20
+
21
+ # Class to manage targets in a build.
22
+ class Targets
23
+
24
+ include Bee::Util::BuildErrorMixin
25
+
26
+ # The build.
27
+ attr_reader :build
28
+ # Targets hash by name.
29
+ attr_reader :hash
30
+ # List of targets that already ran.
31
+ attr_reader :already_run
32
+ # Default target.
33
+ attr_accessor :default
34
+
35
+ # Constructor.
36
+ # - build: build object.
37
+ def initialize(build)
38
+ @build = build
39
+ @hash = {}
40
+ @already_run = []
41
+ end
42
+
43
+ # Add a new target.
44
+ # - object: object tree resulting from YAML build file parsing.
45
+ def add(object)
46
+ begin
47
+ target = Target.new(object, self)
48
+ rescue
49
+ error "Error parsing target '#{object[Bee::Target::KEY]}': #{$!}"
50
+ end
51
+ error "Duplicate target definition: '#{target.name}'" if
52
+ @hash.has_key?(target.name)
53
+ @hash[target.name] = [target]
54
+ @default = target.name if !@default
55
+ end
56
+
57
+ # Extend parent targets.
58
+ # - parent: parent targets.
59
+ def extend(parent)
60
+ # set appropriate targets for targets of parent
61
+ for targets in parent.hash.values
62
+ for target in targets
63
+ target.targets = self
64
+ end
65
+ end
66
+ # insert parent targets before current ones
67
+ for name in parent.hash.keys
68
+ if @hash[name]
69
+ @hash[name] = parent.hash[name] + @hash[name]
70
+ # clean dependencies for redefined targets
71
+ for target in parent.hash[name]
72
+ target.depends.clear
73
+ end
74
+ # copy documentation of parent if target not documented
75
+ if not @hash[name].last.description
76
+ description = nil
77
+ for target in parent.hash[name]
78
+ description = target.description || description
79
+ end
80
+ @hash[name].last.description = description
81
+ end
82
+ else
83
+ @hash[name] = parent.hash[name]
84
+ end
85
+ end
86
+ # set default default target to parent one if none was set
87
+ @default = @default || parent.default
88
+ end
89
+
90
+ # Run a given target.
91
+ # - target: the target to run.
92
+ # - dry: tells if we run in dry mode. Defaults to false.
93
+ def run_target(target, dry=false)
94
+ error "Target '#{target}' not found" if not @hash[target]
95
+ if not @already_run.include?(target)
96
+ @already_run << target
97
+ @hash[target].last.run(dry)
98
+ end
99
+ end
100
+
101
+ # Run targets.
102
+ # - targets: list of target names to run.
103
+ def run(targets, dry)
104
+ error "No default target given" if (!@default and targets.length == 0)
105
+ targets = [@default] if targets.length == 0
106
+ for target in targets
107
+ run_target(target, dry)
108
+ @already_run.clear
109
+ end
110
+ end
111
+
112
+ # Call super target.
113
+ # - target: target to call super onto.
114
+ def call_super(target, dry=false)
115
+ index = @hash[target.name].index(target)
116
+ error "No super target to call for '#{target.name}'" if index == 0
117
+ index -= 1
118
+ @hash[target.name][index].run(dry)
119
+ end
120
+
121
+ # Tells if a given target is last in hierarchy.
122
+ # - target: given target.
123
+ def is_last(target)
124
+ index = @hash[target.name].index(target)
125
+ last = @hash[target.name].size - 1
126
+ return index == last
127
+ end
128
+
129
+ # Return targets description as a hash of descriptions indexed by
130
+ # target name. Dependencies are added after target description.
131
+ def description
132
+ description = {}
133
+ for name in @hash.keys
134
+ text = @hash[name].last.description
135
+ if @hash[name].last.depends and @hash[name].last.depends.length > 0
136
+ depends = ' [' + @hash[name].last.depends.join(', ') + ']'
137
+ else
138
+ depends = nil
139
+ end
140
+ description[name] = (text ? text : '') + (depends ? depends : '')
141
+ end
142
+ return description
143
+ end
144
+
145
+ end
146
+
147
+ end
@@ -1,4 +1,4 @@
1
- # Copyright 2006-2010 Michel Casabianca <michel.casabianca@gmail.com>
1
+ # Copyright 2006-2011 Michel Casabianca <michel.casabianca@gmail.com>
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -13,8 +13,8 @@
13
13
  # limitations under the License.
14
14
 
15
15
  require 'rubygems'
16
- require 'bee'
17
- require 'bee_task'
16
+ require 'bee_build'
17
+ require 'bee_task_package'
18
18
  require 'bee_util'
19
19
  require 'erb'
20
20
  require 'fileutils'
@@ -28,7 +28,7 @@ module Bee
28
28
 
29
29
  # Package for default tasks (tasks with no package).
30
30
  class Default < Package
31
-
31
+
32
32
  ######################################################################
33
33
  # MISCELLANEOUS TASKS #
34
34
  ######################################################################
@@ -141,7 +141,7 @@ module Bee
141
141
  @build.context.set_property(property, value)
142
142
  end
143
143
 
144
- # Trow a build error with a given message.
144
+ # Throw a build error with a given message.
145
145
  #
146
146
  # - message: the error message. Will be printed on the console as the
147
147
  # build failure reason.
@@ -156,6 +156,9 @@ module Bee
156
156
  error message
157
157
  end
158
158
 
159
+ # Alias for throw.
160
+ alias :raise :throw
161
+
159
162
  # Get a given URL and store its content in a given file. Parameters
160
163
  # is a Hash with following entries:
161
164
  #
@@ -171,7 +174,7 @@ module Bee
171
174
  #
172
175
  # - get:
173
176
  # url: http://rubyforge.org/frs/download.php/22185/bee-0.4.0.zip
174
- def get(parameters)
177
+ def http_get(parameters)
175
178
  params_desc = {
176
179
  :url => { :mandatory => true, :type => :string },
177
180
  :dest => { :mandatory => false, :type => :string },
@@ -211,7 +214,6 @@ module Bee
211
214
  @build.context.set_property(prop, content)
212
215
  end
213
216
  end
214
-
215
217
 
216
218
  # Send an email using SMTP.
217
219
  #
@@ -342,7 +344,7 @@ EOF
342
344
  puts "Linking #{files.length} file(s) to '#{new}'"
343
345
  begin
344
346
  FileUtils.ln_s(files, new)
345
- rescue
347
+ rescue Exception
346
348
  error "Error making the link: #{$!}"
347
349
  end
348
350
  end
@@ -389,7 +391,7 @@ EOF
389
391
  else
390
392
  FileUtils.chmod(mode, files)
391
393
  end
392
- rescue
394
+ rescue Exception
393
395
  error "Error changing permissions: #{$!}"
394
396
  end
395
397
  end
@@ -439,10 +441,10 @@ EOF
439
441
  else
440
442
  FileUtils.chown(user, group, files)
441
443
  end
442
- rescue
444
+ rescue Exception
443
445
  error "Error changing owner: #{$!}"
444
446
  end
445
- end
447
+ end
446
448
  end
447
449
 
448
450
  # Make a directory, and parent directories if necessary. Doesn't
@@ -462,7 +464,7 @@ EOF
462
464
  puts "Creating directory '#{dir}'"
463
465
  begin
464
466
  FileUtils.makedirs(dir)
465
- rescue
467
+ rescue Exception
466
468
  error "Error creating directory '#{dir}': #{$!}"
467
469
  end
468
470
  end
@@ -498,7 +500,7 @@ EOF
498
500
  puts "Copying #{nb_copies} file(s) to '#{dest}'"
499
501
  begin
500
502
  FileUtils.cp_r(src, dest)
501
- rescue
503
+ rescue Exception
502
504
  error "Error copying file(s): #{$!}"
503
505
  end
504
506
  end
@@ -533,7 +535,7 @@ EOF
533
535
  puts "Moving #{nb_moves} file(s) to '#{dest}'"
534
536
  begin
535
537
  FileUtils.mv(src, dest)
536
- rescue
538
+ rescue Exception
537
539
  error "Error moving file(s): #{$!}"
538
540
  end
539
541
  end
@@ -725,7 +727,7 @@ EOF
725
727
  for file in files
726
728
  begin
727
729
  FileUtils.rm(file)
728
- rescue
730
+ rescue Exception
729
731
  error "Error deleting files: #{$!}"
730
732
  end
731
733
  end
@@ -751,7 +753,7 @@ EOF
751
753
  for dir in dirs
752
754
  begin
753
755
  FileUtils.rm_rf(dir)
754
- rescue
756
+ rescue Exception
755
757
  error "Error deleting directory(ies): #{$!}"
756
758
  end
757
759
  end
@@ -788,7 +790,7 @@ EOF
788
790
  puts "Touching #{size} file(s)" if size > 0
789
791
  begin
790
792
  FileUtils.touch(files)
791
- rescue
793
+ rescue Exception
792
794
  error "Error touching file(s): #{$!}"
793
795
  end
794
796
  end
@@ -844,27 +846,27 @@ EOF
844
846
 
845
847
  # Load a YAML file in a given property.
846
848
  #
847
- # - prop: the property name to set with YAML parsed content.
848
849
  # - file: the YAML file name to load.
850
+ # - prop: the property name to set with YAML parsed content.
849
851
  #
850
852
  # Example
851
853
  #
852
854
  # - yaml_load:
853
- # prop: "my_list"
854
855
  # file: "my_list.yml"
856
+ # prop: "my_list"
855
857
  def yaml_load(params)
856
858
  params_desc = {
859
+ :file => { :mandatory => true, :type => :string },
857
860
  :prop => { :mandatory => true, :type => :string },
858
- :file => { :mandatory => true, :type => :string }
859
861
  }
860
862
  check_parameters(params, params_desc)
861
- prop = params[:prop]
862
863
  file = params[:file]
864
+ prop = params[:prop]
863
865
  error "YAML file '#{file}' not found" if not File.exists?(file)
864
866
  script = "#{prop} = YAML.load(File.read('#{file}'))"
865
867
  begin
866
868
  @build.context.evaluate_script(script)
867
- rescue
869
+ rescue Exception
868
870
  error "Error loading YAML file '#{file}': #{$!}"
869
871
  end
870
872
  end
@@ -890,7 +892,7 @@ EOF
890
892
  script = "File.open('#{file}', 'w') {|f| f.write(YAML.dump(#{prop}))}"
891
893
  begin
892
894
  @build.context.evaluate_script(script)
893
- rescue
895
+ rescue Exception
894
896
  error "Error dumping YAML file '#{file}': #{$!}"
895
897
  end
896
898
  end
@@ -958,7 +960,8 @@ EOF
958
960
  def test(params)
959
961
  require 'test/unit'
960
962
  params_desc = {
961
- :root => { :mandatory => false, :type => :string },
963
+ :root => { :mandatory => false, :type => :string,
964
+ :default => '.' },
962
965
  :includes => { :mandatory => true, :type => :string },
963
966
  :excludes => { :mandatory => false, :type => :string },
964
967
  :dotmatch => { :mandatory => false, :type => :boolean,
@@ -975,8 +978,9 @@ EOF
975
978
  error "Test directory '#{dir}' not found" if
976
979
  not (File.exists?(dir) and File.directory?(dir))
977
980
  files = filter_files(includes, excludes, root, dotmatch)
981
+ files.map! { |file| File.expand_path(File.join(root, file)) }
978
982
  for file in files
979
- load File.join(root || '.', file)
983
+ load file
980
984
  end
981
985
  size = (files.kind_of?(Array) ? files.size : 1)
982
986
  puts "Running #{size} unit test(s)"
@@ -1051,15 +1055,15 @@ EOF
1051
1055
  end
1052
1056
  begin
1053
1057
  result = template.result(@build.context.context_binding)
1054
- rescue
1058
+ rescue Exception
1055
1059
  error "Error processing ERB: #{$!}"
1056
1060
  end
1057
1061
  # write result in file or set property
1058
1062
  if dest
1059
1063
  begin
1060
1064
  File.open(dest, 'w') { |file| file.write(result) }
1061
- rescue
1062
- error "Error writing ERB processing result in file: #{$!}"
1065
+ rescue Exception
1066
+ error "Error writing ERB result in file: #{$!}"
1063
1067
  end
1064
1068
  else
1065
1069
  @build.context.set_property(property, result)
@@ -1111,7 +1115,7 @@ EOF
1111
1115
  begin
1112
1116
  rdoc = RDoc::RDoc.new
1113
1117
  rdoc.document(command_line)
1114
- rescue
1118
+ rescue Exception
1115
1119
  error "Error generating RDoc: #{$!}"
1116
1120
  end
1117
1121
  end
@@ -1172,7 +1176,7 @@ EOF
1172
1176
  begin
1173
1177
  build = Bee::Build.load(file, false, props)
1174
1178
  build.run(target, @build.listener.clone)
1175
- rescue
1179
+ rescue Exception
1176
1180
  error "Error invoking build file '#{file}': #{$!}"
1177
1181
  end
1178
1182
  end
@@ -1227,16 +1231,16 @@ EOF
1227
1231
  # build the archive
1228
1232
  puts "Building ZIP archive '#{dest}'"
1229
1233
  begin
1230
- zipfile = Zip::ZipFile.open(dest, Zip::ZipFile::CREATE) do |zip|
1234
+ Zip::ZipFile.open(dest, Zip::ZipFile::CREATE) do |zip|
1231
1235
  for file in files
1232
1236
  path = (root == nil ? file : File.join(root, file))
1233
1237
  entry = prefix ? File.join(prefix, file) : file
1234
- puts "Adding '#{entry}'" if @build.listener.verbose
1238
+ puts "Adding '#{entry}'" if @verbose
1235
1239
  zip.add(entry, path)
1236
1240
  end
1237
1241
  zip.close
1238
1242
  end
1239
- rescue
1243
+ rescue Exception
1240
1244
  error "Error building ZIP archive: #{$!}"
1241
1245
  end
1242
1246
  end
@@ -1269,7 +1273,7 @@ EOF
1269
1273
  puts "Extracting ZIP file '#{src}' to '#{dest}'"
1270
1274
  begin
1271
1275
  Zip::ZipFile.foreach(src) do |entry|
1272
- puts "Writing '#{entry}'" if @build.listener.verbose
1276
+ puts "Writing '#{entry}'" if @verbose
1273
1277
  tofile = File.join(dest, entry.name)
1274
1278
  if entry.file?
1275
1279
  dir = File.dirname(tofile)
@@ -1279,7 +1283,7 @@ EOF
1279
1283
  FileUtils.makedirs(tofile)
1280
1284
  end
1281
1285
  end
1282
- rescue
1286
+ rescue Exception
1283
1287
  error "Error extracting ZIP archive: #{$!}"
1284
1288
  end
1285
1289
  end
@@ -1331,7 +1335,7 @@ EOF
1331
1335
  Dir.chdir(root) if root
1332
1336
  Archive::Tar::Minitar::Output.open(abs_dest) do |tarfile|
1333
1337
  for file in files
1334
- puts "Adding '#{file}'" if @build.listener.verbose
1338
+ puts "Adding '#{file}'" if @verbose
1335
1339
  Archive::Tar::Minitar.pack_file(file, tarfile)
1336
1340
  end
1337
1341
  end
@@ -1373,7 +1377,7 @@ EOF
1373
1377
  output.write(input.read)
1374
1378
  output.close
1375
1379
  end
1376
- rescue
1380
+ rescue Exception
1377
1381
  error "Error generating GZIP archive: #{$!}"
1378
1382
  end
1379
1383
  end
@@ -1422,7 +1426,7 @@ EOF
1422
1426
  output.write(input.read)
1423
1427
  output.close
1424
1428
  end
1425
- rescue
1429
+ rescue Exception
1426
1430
  error "Error expanding GZIP archive: #{$!}"
1427
1431
  end
1428
1432
  end
@@ -1478,11 +1482,11 @@ EOF
1478
1482
  Archive::Tar::Minitar::Output.
1479
1483
  open(Zlib::GzipWriter.new(File.open(abs_dest, 'wb'))) do |tgz|
1480
1484
  for file in files
1481
- puts "Adding '#{file}'" if @build.listener.verbose
1485
+ puts "Adding '#{file}'" if @verbose
1482
1486
  Archive::Tar::Minitar.pack_file(file, tgz)
1483
1487
  end
1484
1488
  end
1485
- rescue
1489
+ rescue Exception
1486
1490
  error "Error generating TARGZ archive: #{$!}"
1487
1491
  ensure
1488
1492
  Dir.chdir(current_dir)
@@ -1524,7 +1528,7 @@ EOF
1524
1528
  else
1525
1529
  Archive::Tar::Minitar.unpack(src, dest)
1526
1530
  end
1527
- rescue
1531
+ rescue Exception
1528
1532
  error "Error extracting TAR archive: #{$!}"
1529
1533
  end
1530
1534
  end
@@ -1563,7 +1567,7 @@ EOF
1563
1567
  ftp.close
1564
1568
  end
1565
1569
  puts "Connection to FTP host '#{host}' sucessful"
1566
- rescue
1570
+ rescue Exception
1567
1571
  error "Error connecting to FTP host: #{$!}"
1568
1572
  end
1569
1573
  end
@@ -1615,7 +1619,7 @@ EOF
1615
1619
  end
1616
1620
  ftp.close
1617
1621
  end
1618
- rescue
1622
+ rescue Exception
1619
1623
  error "Error getting file '#{basename}': #{$!}"
1620
1624
  end
1621
1625
  end
@@ -1667,7 +1671,7 @@ EOF
1667
1671
  end
1668
1672
  ftp.close
1669
1673
  end
1670
- rescue
1674
+ rescue Exception
1671
1675
  error "Error putting file '#{basename}': #{$!}"
1672
1676
  end
1673
1677
  end
@@ -1707,7 +1711,7 @@ EOF
1707
1711
  ftp.mkdir(dir)
1708
1712
  ftp.close
1709
1713
  end
1710
- rescue
1714
+ rescue Exception
1711
1715
  error "Error making directory '#{basename}': #{$!}"
1712
1716
  end
1713
1717
  end
@@ -1719,18 +1723,19 @@ EOF
1719
1723
  # If construct will evaluate the expression in the 'if' entry and run
1720
1724
  # block in the 'then' entry or 'else' entry accordingly.
1721
1725
  #
1722
- # - if: the condition to evaluate. This is a Ruby expression evaluated
1723
- # in the build context.
1724
- # - then: block that is evaluated if confition in if is true.
1725
- # - else: block that is evaluated if confition in if is false.
1726
+ # - if: the condition to evaluate. This is a Ruby expression (thus a
1727
+ # string) evaluated in the build context, a symbol that refers to a
1728
+ # property or a boolean.
1729
+ # - then: block that is evaluated if condition in if is true.
1730
+ # - else: block that is evaluated if condition in if is false.
1726
1731
  #
1727
1732
  # Example
1728
1733
  #
1729
1734
  # - if: RUBY_PLATFORM =~ /darwin/
1730
1735
  # then:
1731
- # - print: Hello, I'm a Mac
1736
+ # - print: Hello, I'm a Mac
1732
1737
  # else:
1733
- # - print: Hello, I'm a PC
1738
+ # - print: Hello, I'm a PC
1734
1739
  def if
1735
1740
  end
1736
1741
 
@@ -1745,8 +1750,8 @@ EOF
1745
1750
  #
1746
1751
  # - while: i > 0
1747
1752
  # do:
1748
- # - print: :i
1749
- # - rb: i -= 1
1753
+ # - print: :i
1754
+ # - rb: i -= 1
1750
1755
  def while
1751
1756
  end
1752
1757
 
@@ -1754,10 +1759,11 @@ EOF
1754
1759
  # a property which name is in the 'for' entry and running the block in
1755
1760
  # the 'do' entry for each value.
1756
1761
  #
1757
- # - for: the name of the property which receives values of the iteration.
1758
- # - in: a list on which to iterate. This can be a list or a ruby
1759
- # expression to evaluate in the context of the build to obtain the
1760
- # Enumerable on which to iterate.
1762
+ # - for: the name of the property which receives values of the iteration,
1763
+ # as a string.
1764
+ # - in: a list on which to iterate. This can be a list, a ruby expression
1765
+ # to evaluate in the context of the build to obtain the Enumerable on
1766
+ # which to iterate or a symbol that refers to a property that is a list.
1761
1767
  # - do: the block to run at each iteration.
1762
1768
  #
1763
1769
  # Example
@@ -1768,6 +1774,18 @@ EOF
1768
1774
  # - print: "Creating #{file}..."
1769
1775
  # - touch: :file
1770
1776
  #
1777
+ # The same using a reference to a property that is a list:
1778
+ #
1779
+ # - properties:
1780
+ # list: ['foo', 'bar']
1781
+ #
1782
+ # - target: test
1783
+ # script:
1784
+ # - for: name
1785
+ # in: :list
1786
+ # do:
1787
+ # - print: "Hi #{name}!"
1788
+ #
1771
1789
  # To iterate five times, we could write (using a Ruby Range):
1772
1790
  #
1773
1791
  # - for: i
@@ -1793,10 +1811,10 @@ EOF
1793
1811
  # Example:
1794
1812
  #
1795
1813
  # - try:
1796
- # - print: "In the try block"
1797
- # - throw: "Something went terribly wrong!"
1814
+ # - print: "In the try block"
1815
+ # - throw: "Something went terribly wrong!"
1798
1816
  # catch:
1799
- # - print: "An error occured"
1817
+ # - print: "An error occured"
1800
1818
  def try
1801
1819
  end
1802
1820