autobuild 1.17.0 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +107 -0
  3. data/.travis.yml +3 -2
  4. data/Gemfile +2 -1
  5. data/Rakefile +1 -4
  6. data/autobuild.gemspec +18 -13
  7. data/bin/autobuild +4 -3
  8. data/lib/autobuild.rb +4 -5
  9. data/lib/autobuild/build_logfile.rb +6 -4
  10. data/lib/autobuild/config.rb +104 -41
  11. data/lib/autobuild/configurable.rb +32 -18
  12. data/lib/autobuild/environment.rb +126 -120
  13. data/lib/autobuild/exceptions.rb +48 -31
  14. data/lib/autobuild/import/archive.rb +134 -82
  15. data/lib/autobuild/import/cvs.rb +28 -24
  16. data/lib/autobuild/import/darcs.rb +13 -16
  17. data/lib/autobuild/import/git-lfs.rb +37 -30
  18. data/lib/autobuild/import/git.rb +246 -182
  19. data/lib/autobuild/import/hg.rb +23 -18
  20. data/lib/autobuild/import/svn.rb +48 -29
  21. data/lib/autobuild/importer.rb +534 -499
  22. data/lib/autobuild/mail_reporter.rb +77 -77
  23. data/lib/autobuild/package.rb +200 -122
  24. data/lib/autobuild/packages/autotools.rb +47 -42
  25. data/lib/autobuild/packages/cmake.rb +77 -65
  26. data/lib/autobuild/packages/dummy.rb +9 -8
  27. data/lib/autobuild/packages/genom.rb +1 -1
  28. data/lib/autobuild/packages/gnumake.rb +74 -31
  29. data/lib/autobuild/packages/import.rb +2 -6
  30. data/lib/autobuild/packages/orogen.rb +32 -31
  31. data/lib/autobuild/packages/pkgconfig.rb +2 -2
  32. data/lib/autobuild/packages/python.rb +12 -8
  33. data/lib/autobuild/packages/ruby.rb +22 -17
  34. data/lib/autobuild/parallel.rb +50 -46
  35. data/lib/autobuild/pkgconfig.rb +25 -13
  36. data/lib/autobuild/progress_display.rb +149 -64
  37. data/lib/autobuild/rake_task_extension.rb +12 -7
  38. data/lib/autobuild/reporting.rb +51 -26
  39. data/lib/autobuild/subcommand.rb +72 -65
  40. data/lib/autobuild/test.rb +9 -7
  41. data/lib/autobuild/test_utility.rb +12 -10
  42. data/lib/autobuild/timestamps.rb +28 -23
  43. data/lib/autobuild/tools.rb +17 -16
  44. data/lib/autobuild/utility.rb +67 -23
  45. data/lib/autobuild/version.rb +1 -1
  46. metadata +53 -37
@@ -1,19 +1,24 @@
1
1
  module Autobuild
2
2
  module RakeTaskExtension
3
3
  def already_invoked?
4
- !!@already_invoked
4
+ @already_invoked
5
5
  end
6
6
 
7
- def already_invoked=(value)
8
- @already_invoked = value
7
+ attr_writer :already_invoked
8
+
9
+ def disabled?
10
+ @disabled
11
+ end
12
+
13
+ def disabled!
14
+ disable
9
15
  end
10
16
 
11
- def disable!
12
- @already_invoked = true
13
- def self.needed?; false end
17
+ def disable
18
+ @disabled = true
14
19
  end
15
20
  end
16
21
  end
17
- class Rake::Task
22
+ class Rake::Task # rubocop:disable Style/ClassAndModuleChildren
18
23
  include Autobuild::RakeTaskExtension
19
24
  end
@@ -16,6 +16,7 @@ def color=(flag)
16
16
  def color?
17
17
  @colorizer.enabled?
18
18
  end
19
+
19
20
  def color(message, *style)
20
21
  @colorizer.decorate(message, *style)
21
22
  end
@@ -31,6 +32,7 @@ class << self
31
32
  def silent?
32
33
  @display.silent?
33
34
  end
35
+
34
36
  def silent=(flag)
35
37
  @display.silent = flag
36
38
  end
@@ -45,10 +47,23 @@ def self.progress_display_enabled?
45
47
  @display.progress_enabled?
46
48
  end
47
49
 
50
+ def self.progress_display_synchronize(&block)
51
+ @display.synchronize(&block)
52
+ end
53
+
54
+ # @deprecated use {progress_display_mode=} instead
48
55
  def self.progress_display_enabled=(value)
49
56
  @display.progress_enabled = value
50
57
  end
51
58
 
59
+ def self.progress_display_mode=(value)
60
+ @display.progress_mode = value
61
+ end
62
+
63
+ def self.progress_display_period=(value)
64
+ @display.progress_period = value
65
+ end
66
+
52
67
  def self.message(*args, **options)
53
68
  @display.message(*args, **options)
54
69
  end
@@ -80,7 +95,7 @@ def self.progress_done(key, display_last = true, message: nil)
80
95
  #
81
96
  # It does not use a logging framework like Log4r, but it should ;-)
82
97
  module Reporting
83
- @@reporters = Array.new
98
+ @reporters = Array.new
84
99
 
85
100
  ## Run a block and report known exception
86
101
  # If an exception is fatal, the program is terminated using exit()
@@ -89,18 +104,22 @@ def self.report(on_package_failures: default_report_on_package_failures)
89
104
  rescue Interrupt => e
90
105
  interrupted = e
91
106
  rescue Autobuild::Exception => e
92
- return report_finish_on_error([e], on_package_failures: on_package_failures, interrupted_by: interrupted)
107
+ return report_finish_on_error([e],
108
+ on_package_failures: on_package_failures,
109
+ interrupted_by: interrupted)
93
110
  end
94
111
 
95
112
  # If ignore_erorrs is true, check if some packages have failed
96
113
  # on the way. If so, raise an exception to inform the user about
97
114
  # it
98
115
  errors = []
99
- Autobuild::Package.each do |name, pkg|
116
+ Autobuild::Package.each do |_name, pkg|
100
117
  errors.concat(pkg.failures)
101
118
  end
102
119
 
103
- report_finish_on_error(errors, on_package_failures: on_package_failures, interrupted_by: interrupted)
120
+ report_finish_on_error(errors,
121
+ on_package_failures: on_package_failures,
122
+ interrupted_by: interrupted)
104
123
  end
105
124
 
106
125
  # @api private
@@ -121,15 +140,18 @@ def self.default_report_on_package_failures
121
140
  #
122
141
  # @param [Symbol] on_package_failures how does the reporting should behave.
123
142
  #
124
- def self.report_finish_on_error(errors, on_package_failures: default_report_on_package_failures, interrupted_by: nil)
125
- if not_package_error = errors.find { |e| !e.respond_to?(:fatal?) }
143
+ def self.report_finish_on_error(errors,
144
+ on_package_failures: default_report_on_package_failures, interrupted_by: nil)
145
+ if (not_package_error = errors.find { |e| !e.respond_to?(:fatal?) })
126
146
  raise not_package_error
127
147
  end
128
- if ![:raise, :report_silent, :exit_silent].include?(on_package_failures)
148
+
149
+ unless %i[raise report_silent exit_silent].include?(on_package_failures)
129
150
  errors.each { |e| error(e) }
130
151
  end
152
+
131
153
  fatal = errors.any?(&:fatal?)
132
- if !fatal
154
+ unless fatal
133
155
  if interrupted_by
134
156
  raise interrupted_by
135
157
  else
@@ -138,30 +160,29 @@ def self.report_finish_on_error(errors, on_package_failures: default_report_on_p
138
160
  end
139
161
 
140
162
  if on_package_failures == :raise
141
- if interrupted_by
142
- raise interrupted_by
143
- end
163
+ raise interrupted_by if interrupted_by
144
164
 
145
165
  e = if errors.size == 1 then errors.first
146
- else CompositeException.new(errors)
147
- end
166
+ else CompositeException.new(errors)
167
+ end
148
168
  raise e
149
- elsif [:report_silent, :report].include?(on_package_failures)
169
+ elsif %i[report_silent report].include?(on_package_failures)
150
170
  if interrupted_by
151
171
  raise interrupted_by
152
172
  else
153
173
  return errors
154
174
  end
155
- elsif [:exit, :exit_silent].include?(on_package_failures)
175
+ elsif %i[exit exit_silent].include?(on_package_failures)
156
176
  exit 1
157
177
  else
158
- raise ArgumentError, "unexpected value for on_package_failures: #{on_package_failures}"
178
+ raise ArgumentError, "unexpected value for on_package_failures: "\
179
+ "#{on_package_failures}"
159
180
  end
160
181
  end
161
182
 
162
183
  ## Reports a successful build to the user
163
184
  def self.success
164
- each_reporter { |rep| rep.success }
185
+ each_reporter(&:success)
165
186
  end
166
187
 
167
188
  ## Reports that the build failed to the user
@@ -171,19 +192,19 @@ def self.error(error)
171
192
 
172
193
  ## Add a new reporter
173
194
  def self.<<(reporter)
174
- @@reporters << reporter
195
+ @reporters << reporter
175
196
  end
176
197
 
177
198
  def self.remove(reporter)
178
- @@reporters.delete(reporter)
199
+ @reporters.delete(reporter)
179
200
  end
180
201
 
181
202
  def self.clear_reporters
182
- @@reporters.clear
203
+ @reporters.clear
183
204
  end
184
205
 
185
206
  def self.each_reporter(&iter)
186
- @@reporters.each(&iter)
207
+ @reporters.each(&iter)
187
208
  end
188
209
 
189
210
  ## Iterate on all log files
@@ -195,6 +216,7 @@ def self.each_log(&block)
195
216
  ## Base class for reporters
196
217
  class Reporter
197
218
  def error(error); end
219
+
198
220
  def success; end
199
221
  end
200
222
 
@@ -203,11 +225,10 @@ class StdoutReporter < Reporter
203
225
  def error(error)
204
226
  STDERR.puts "Build failed: #{error}"
205
227
  end
228
+
206
229
  def success
207
230
  puts "Build finished successfully at #{Time.now}"
208
- if Autobuild.post_success_message
209
- puts Autobuild.post_success_message
210
- end
231
+ puts Autobuild.post_success_message if Autobuild.post_success_message
211
232
  end
212
233
  end
213
234
 
@@ -216,12 +237,16 @@ def success
216
237
  [1_000_000.0, "M"],
217
238
  [1_000.0, "k"],
218
239
  [1.0, ""]
219
- ]
240
+ ].freeze
220
241
 
221
242
  def self.human_readable_size(size)
222
243
  HUMAN_READABLE_SIZES.each do |scale, name|
223
244
  scaled_size = (size / scale)
224
- return format("%3.1f%s", scaled_size, name) if scaled_size > 1
245
+ if scaled_size > 1
246
+ return format("%3.1<scaled>f%<scale_name>s",
247
+ scaled: scaled_size,
248
+ scale_name: name)
249
+ end
225
250
  end
226
251
  end
227
252
  end
@@ -2,6 +2,7 @@
2
2
  require 'autobuild/exceptions'
3
3
  require 'autobuild/reporting'
4
4
  require 'fcntl'
5
+ require 'English'
5
6
 
6
7
  module Autobuild
7
8
  @logfiles = Set.new
@@ -24,9 +25,11 @@ def self.registered_logfile?(logfile)
24
25
  def self.statistics
25
26
  @statistics
26
27
  end
28
+
27
29
  def self.reset_statistics
28
30
  @statistics = Hash.new
29
31
  end
32
+
30
33
  def self.add_stat(package, phase, duration)
31
34
  if !@statistics[package]
32
35
  @statistics[package] = { phase => duration }
@@ -36,6 +39,7 @@ def self.add_stat(package, phase, duration)
36
39
  @statistics[package][phase] += duration
37
40
  end
38
41
  end
42
+
39
43
  reset_statistics
40
44
 
41
45
  @parallel_build_level = nil
@@ -52,9 +56,8 @@ class << self
52
56
  def displayed_error_line_count=(value)
53
57
  @displayed_error_line_count = validate_displayed_error_line_count(value)
54
58
  end
55
- def displayed_error_line_count
56
- @displayed_error_line_count
57
- end
59
+
60
+ attr_reader :displayed_error_line_count
58
61
 
59
62
  # Returns the number of processes that can run in parallel during the
60
63
  # build. This is a system-wide value that can be overriden in a
@@ -78,13 +81,13 @@ def parallel_build_level
78
81
 
79
82
  # Returns the number of CPUs present on this system
80
83
  def self.autodetect_processor_count
81
- if @processor_count
82
- return @processor_count
83
- end
84
+ return @processor_count if @processor_count
84
85
 
85
86
  if File.file?('/proc/cpuinfo')
86
87
  cpuinfo = File.readlines('/proc/cpuinfo')
87
- physical_ids, core_count, processor_ids = [], [], []
88
+ physical_ids = []
89
+ core_count = []
90
+ processor_ids = []
88
91
  cpuinfo.each do |line|
89
92
  case line
90
93
  when /^processor\s+:\s+(\d+)$/
@@ -99,7 +102,10 @@ def self.autodetect_processor_count
99
102
  # Try to count the number of physical cores, not the number of
100
103
  # logical ones. If the info is not available, fallback to the
101
104
  # logical count
102
- if (physical_ids.size == core_count.size) && (physical_ids.size == processor_ids.size)
105
+ has_consistent_info =
106
+ (physical_ids.size == core_count.size) &&
107
+ (physical_ids.size == processor_ids.size)
108
+ if has_consistent_info
103
109
  info = Array.new
104
110
  while (id = physical_ids.shift)
105
111
  info[id] = core_count.shift
@@ -112,18 +118,17 @@ def self.autodetect_processor_count
112
118
  result = Open3.popen3("sysctl", "-n", "hw.ncpu") do |_, io, _|
113
119
  io.read
114
120
  end
115
- if !result.empty?
116
- @processor_count = Integer(result.chomp.strip)
117
- end
121
+ @processor_count = Integer(result.chomp.strip) unless result.empty?
118
122
  end
119
123
 
120
124
  # The format of the cpuinfo file is ... let's say not very standardized.
121
125
  # If the cpuinfo detection fails, inform the user and set it to 1
122
- if !@processor_count
126
+ unless @processor_count
123
127
  # Hug... What kind of system is it ?
124
128
  Autobuild.message "INFO: cannot autodetect the number of CPUs on this sytem"
125
129
  Autobuild.message "INFO: turning parallel builds off"
126
- Autobuild.message "INFO: you can manually set the number of parallel build processes to N"
130
+ Autobuild.message "INFO: you can manually set the number of parallel build "\
131
+ "processes to N"
127
132
  Autobuild.message "INFO: (and therefore turn this message off)"
128
133
  Autobuild.message "INFO: with"
129
134
  Autobuild.message " Autobuild.parallel_build_level = N"
@@ -135,20 +140,24 @@ def self.autodetect_processor_count
135
140
 
136
141
  def self.validate_displayed_error_line_count(lines)
137
142
  if lines == 'ALL'
138
- return Float::INFINITY
143
+ Float::INFINITY
139
144
  elsif lines.to_i > 0
140
- return lines.to_i
145
+ lines.to_i
146
+ else
147
+ raise ConfigException.new, 'Autobuild.displayed_error_line_count can only "\
148
+ "be a positive integer or \'ALL\''
141
149
  end
142
- raise ConfigException.new, 'Autobuild.displayed_error_line_count can only be a positive integer or \'ALL\''
143
150
  end
144
151
  end
145
152
 
146
-
147
- module Autobuild::Subprocess
148
- class Failed < Exception
149
- def retry?; @retry end
153
+ module Autobuild::Subprocess # rubocop:disable Style/ClassAndModuleChildren
154
+ class Failed < RuntimeError
150
155
  attr_reader :status
151
156
 
157
+ def retry?
158
+ @retry
159
+ end
160
+
152
161
  def initialize(status, do_retry)
153
162
  @status = status
154
163
  @retry = do_retry
@@ -206,7 +215,11 @@ def self.run(target, phase, *command)
206
215
  STDOUT.sync = true
207
216
 
208
217
  input_streams = []
209
- options = Hash[retry: false, env: ENV.to_hash, env_inherit: true, encoding: 'BINARY']
218
+ options = {
219
+ retry: false, encoding: 'BINARY',
220
+ env: ENV.to_hash, env_inherit: true
221
+ }
222
+
210
223
  if command.last.kind_of?(Hash)
211
224
  options = command.pop
212
225
  options = Kernel.validate_options options,
@@ -216,19 +229,15 @@ def self.run(target, phase, *command)
216
229
  env_inherit: true,
217
230
  encoding: 'BINARY'
218
231
 
219
- if options[:input]
220
- input_streams << File.open(options[:input])
221
- end
222
- if options[:input_streams]
223
- input_streams += options[:input_streams]
224
- end
232
+ input_streams << File.open(options[:input]) if options[:input]
233
+ input_streams.concat(options[:input_streams]) if options[:input_streams]
225
234
  end
226
235
 
227
236
  start_time = Time.now
228
237
 
229
238
  # Filter nil and empty? in command
230
- command.reject! { |o| o.nil? || (o.respond_to?(:empty?) && o.empty?) }
231
- command.collect! { |o| o.to_s }
239
+ command.reject! { |o| o.nil? || (o.respond_to?(:empty?) && o.empty?) }
240
+ command.collect!(&:to_s)
232
241
 
233
242
  if target.respond_to?(:name)
234
243
  target_name = target.name
@@ -246,13 +255,15 @@ def self.run(target, phase, *command)
246
255
  options[:working_directory] ||= target.working_directory
247
256
  end
248
257
 
249
- logname = File.join(logdir, "#{target_name.gsub(/[:]/,'_')}-#{phase.to_s.gsub(/[:]/,'_')}.log")
250
- if !File.directory?(File.dirname(logname))
258
+ logname = File.join(logdir, "#{target_name.gsub(/[:]/, '_')}-"\
259
+ "#{phase.to_s.gsub(/[:]/, '_')}.log")
260
+ unless File.directory?(File.dirname(logname))
251
261
  FileUtils.mkdir_p File.dirname(logname)
252
262
  end
253
263
 
254
264
  if Autobuild.verbose
255
- Autobuild.message "#{target_name}: running #{command.join(" ")}\n (output goes to #{logname})"
265
+ Autobuild.message "#{target_name}: running #{command.join(' ')}\n"\
266
+ " (output goes to #{logname})"
256
267
  end
257
268
 
258
269
  open_flag = if Autobuild.keep_oldlogs then 'a'
@@ -267,32 +278,28 @@ def self.run(target, phase, *command)
267
278
  env = options[:env].dup
268
279
  if options[:env_inherit]
269
280
  ENV.each do |k, v|
270
- if !env.has_key?(k)
271
- env[k] = v
272
- end
281
+ env[k] = v unless env.key?(k)
273
282
  end
274
283
  end
275
284
 
276
285
  status = File.open(logname, open_flag) do |logfile|
277
- if Autobuild.keep_oldlogs
278
- logfile.puts
279
- end
286
+ logfile.puts if Autobuild.keep_oldlogs
280
287
  logfile.puts
281
288
  logfile.puts "#{Time.now}: running"
282
- logfile.puts " #{command.join(" ")}"
289
+ logfile.puts " #{command.join(' ')}"
283
290
  logfile.puts "with environment:"
284
291
  env.keys.sort.each do |key|
285
- if value = env[key]
292
+ if (value = env[key])
286
293
  logfile.puts " '#{key}'='#{value}'"
287
294
  end
288
295
  end
289
296
  logfile.puts
290
297
  logfile.puts "#{Time.now}: running"
291
- logfile.puts " #{command.join(" ")}"
298
+ logfile.puts " #{command.join(' ')}"
292
299
  logfile.flush
293
300
  logfile.sync = true
294
301
 
295
- if !input_streams.empty?
302
+ unless input_streams.empty?
296
303
  pread, pwrite = IO.pipe # to feed subprocess stdin
297
304
  end
298
305
 
@@ -304,22 +311,19 @@ def self.run(target, phase, *command)
304
311
 
305
312
  if Autobuild.windows?
306
313
  Dir.chdir(options[:working_directory]) do
307
- if !system(*command)
308
- raise Failed.new($?.exitstatus, nil),
314
+ unless system(*command)
315
+ raise Failed.new($CHILD_STATUS.exitstatus, nil),
309
316
  "'#{command.join(' ')}' returned status #{status.exitstatus}"
310
317
  end
311
318
  end
312
- return
319
+ return # rubocop:disable Lint/NonLocalExitFromIterator
313
320
  end
314
321
 
315
322
  cwrite.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
316
323
 
317
324
  pid = fork do
318
325
  begin
319
- if options[:working_directory] && (options[:working_directory] != Dir.pwd)
320
- Dir.chdir(options[:working_directory])
321
- end
322
- logfile.puts "in directory #{Dir.pwd}"
326
+ logfile.puts "in directory #{options[:working_directory] || Dir.pwd}"
323
327
 
324
328
  cwrite.sync = true
325
329
  if Autobuild.nice
@@ -330,19 +334,23 @@ def self.run(target, phase, *command)
330
334
  $stderr.reopen(outwrite.dup)
331
335
  $stdout.reopen(outwrite.dup)
332
336
 
333
- if !input_streams.empty?
337
+ unless input_streams.empty?
334
338
  pwrite.close
335
339
  $stdin.reopen(pread)
336
340
  end
337
341
 
338
- exec(env, *command, close_others: false)
342
+ exec(env, *command,
343
+ chdir: options[:working_directory] || Dir.pwd,
344
+ close_others: false)
339
345
  rescue Errno::ENOENT
340
346
  cwrite.write([CONTROL_COMMAND_NOT_FOUND].pack('I'))
341
347
  exit(100)
342
348
  rescue Interrupt
343
349
  cwrite.write([CONTROL_INTERRUPT].pack('I'))
344
350
  exit(100)
345
- rescue ::Exception
351
+ rescue ::Exception => e
352
+ STDERR.puts e
353
+ STDERR.puts e.backtrace.join("\n ")
346
354
  cwrite.write([CONTROL_UNEXPECTED].pack('I'))
347
355
  exit(100)
348
356
  end
@@ -351,12 +359,14 @@ def self.run(target, phase, *command)
351
359
  readbuffer = StringIO.new
352
360
 
353
361
  # Feed the input
354
- if !input_streams.empty?
362
+ unless input_streams.empty?
355
363
  pread.close
356
364
  begin
357
365
  input_streams.each do |instream|
358
366
  instream.each_line do |line|
359
- readbuffer.write(outread.readpartial(128)) while IO.select([outread], nil, nil, 0)
367
+ while IO.select([outread], nil, nil, 0)
368
+ readbuffer.write(outread.readpartial(128))
369
+ end
360
370
  pwrite.write(line)
361
371
  end
362
372
  end
@@ -385,15 +395,13 @@ def self.run(target, phase, *command)
385
395
  end
386
396
 
387
397
  transparent_prefix = "#{target_name}:#{phase}: "
388
- if target_type
389
- transparent_prefix = "#{target_type}:#{transparent_prefix}"
390
- end
398
+ transparent_prefix = "#{target_type}:#{transparent_prefix}" if target_type
391
399
 
392
400
  # If the caller asked for process output, provide it to him
393
401
  # line-by-line.
394
402
  outwrite.close
395
403
 
396
- if !input_streams.empty?
404
+ unless input_streams.empty?
397
405
  readbuffer.write(outread.read)
398
406
  readbuffer.seek(0)
399
407
  outread.close
@@ -428,6 +436,7 @@ def self.run(target, phase, *command)
428
436
  if status.termsig == 2 # SIGINT == 2
429
437
  raise Interrupt, "subcommand #{command.join(' ')} interrupted"
430
438
  end
439
+
431
440
  if status.termsig
432
441
  raise Failed.new(status.exitstatus, nil),
433
442
  "'#{command.join(' ')}' terminated by signal #{status.termsig}"
@@ -441,21 +450,19 @@ def self.run(target, phase, *command)
441
450
  Autobuild.add_stat(target, phase, duration)
442
451
  FileUtils.mkdir_p(Autobuild.logdir)
443
452
  File.open(File.join(Autobuild.logdir, "stats.log"), 'a') do |io|
444
- formatted_time = "#{start_time.strftime('%F %H:%M:%S')}.#{'%.03i' % [start_time.tv_usec / 1000]}"
453
+ formatted_msec = format('%.03i', start_time.tv_usec / 1000)
454
+ formatted_time = "#{start_time.strftime('%F %H:%M:%S')}.#{formatted_msec}"
445
455
  io.puts "#{formatted_time} #{target_name} #{phase} #{duration}"
446
456
  end
447
- if target.respond_to?(:add_stat)
448
- target.add_stat(phase, duration)
449
- end
457
+ target.add_stat(phase, duration) if target.respond_to?(:add_stat)
450
458
  subcommand_output
451
-
452
459
  rescue Failed => e
453
- error = Autobuild::SubcommandFailed.new(target, command.join(" "), logname, e.status, subcommand_output)
460
+ error = Autobuild::SubcommandFailed.new(target, command.join(" "),
461
+ logname, e.status, subcommand_output)
454
462
  error.retry = if e.retry?.nil? then options[:retry]
455
463
  else e.retry?
456
464
  end
457
465
  error.phase = phase
458
466
  raise error, e.message
459
467
  end
460
-
461
468
  end