autobuild 1.8.3 → 1.9.0.b1

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/Manifest.txt +16 -7
  3. data/Rakefile +2 -0
  4. data/lib/autobuild/config.rb +21 -6
  5. data/lib/autobuild/configurable.rb +2 -2
  6. data/lib/autobuild/environment.rb +52 -27
  7. data/lib/autobuild/exceptions.rb +48 -22
  8. data/lib/autobuild/import/archive.rb +37 -16
  9. data/lib/autobuild/import/cvs.rb +26 -28
  10. data/lib/autobuild/import/darcs.rb +9 -8
  11. data/lib/autobuild/import/git.rb +324 -217
  12. data/lib/autobuild/import/hg.rb +6 -9
  13. data/lib/autobuild/import/svn.rb +190 -47
  14. data/lib/autobuild/importer.rb +80 -35
  15. data/lib/autobuild/package.rb +16 -35
  16. data/lib/autobuild/packages/autotools.rb +8 -8
  17. data/lib/autobuild/packages/cmake.rb +18 -12
  18. data/lib/autobuild/packages/genom.rb +1 -1
  19. data/lib/autobuild/packages/gnumake.rb +11 -12
  20. data/lib/autobuild/packages/orogen.rb +1 -1
  21. data/lib/autobuild/packages/ruby.rb +9 -5
  22. data/lib/autobuild/reporting.rb +10 -6
  23. data/lib/autobuild/subcommand.rb +110 -50
  24. data/lib/autobuild/test.rb +104 -0
  25. data/lib/autobuild/timestamps.rb +3 -3
  26. data/lib/autobuild/tools.rb +1 -1
  27. data/lib/autobuild/utility.rb +22 -10
  28. data/lib/autobuild/version.rb +1 -1
  29. data/test/data/gitrepo-with-extra-commit-and-tag.tar +0 -0
  30. data/test/data/gitrepo.tar +0 -0
  31. data/test/data/gitrepo/test +0 -0
  32. data/test/data/gitrepo/test2 +0 -0
  33. data/test/data/gitrepo/test3 +0 -0
  34. data/test/data/svnroot.tar +0 -0
  35. data/test/import/test_cvs.rb +51 -0
  36. data/test/import/test_git.rb +364 -0
  37. data/test/import/test_svn.rb +144 -0
  38. data/test/import/test_tar.rb +76 -0
  39. data/test/suite.rb +7 -0
  40. data/test/test_config.rb +1 -5
  41. data/test/test_environment.rb +88 -0
  42. data/test/test_reporting.rb +2 -14
  43. data/test/test_subcommand.rb +7 -22
  44. metadata +17 -14
  45. data/test/test_import_cvs.rb +0 -59
  46. data/test/test_import_svn.rb +0 -56
  47. data/test/test_import_tar.rb +0 -83
  48. data/test/tools.rb +0 -44
@@ -127,6 +127,9 @@ module Autobuild
127
127
  def updated?; !!@updated end
128
128
 
129
129
  def initialize(spec = Hash.new)
130
+ @srcdir = @importdir = @logdir = nil
131
+ @update = nil
132
+ @failed = nil
130
133
  @dependencies = Array.new
131
134
  @provides = Array.new
132
135
  @parallel_build_level = nil
@@ -187,7 +190,7 @@ module Autobuild
187
190
  # target files so that all the build phases of this package gets
188
191
  # retriggered. However, it should not clean the build products.
189
192
  def prepare_for_forced_build
190
- if File.exists?(installstamp)
193
+ if File.exist?(installstamp)
191
194
  FileUtils.rm_f installstamp
192
195
  end
193
196
  end
@@ -197,7 +200,7 @@ module Autobuild
197
200
  def prepare_for_rebuild
198
201
  prepare_for_forced_build
199
202
 
200
- if File.exists?(installstamp)
203
+ if File.exist?(installstamp)
201
204
  FileUtils.rm_f installstamp
202
205
  end
203
206
  end
@@ -258,17 +261,22 @@ module Autobuild
258
261
  end
259
262
 
260
263
  # Call the importer if there is one. Autodetection of "provides" should
261
- # be done there as well. See the documentation of Autobuild::Package for
262
- # more information.
263
- def import(only_local=false)
264
+ # be done there as well.
265
+ #
266
+ # (see Importer#import)
267
+ def import(options = Hash.new)
268
+ if !options.respond_to?(:to_hash)
269
+ options = Hash[only_local: options]
270
+ end
271
+
264
272
  if @importer
265
- @importer.import(self,only_local)
266
- elsif Autobuild.do_update
273
+ @importer.import(self, options)
274
+ elsif update?
267
275
  message "%s: no importer defined, doing nothing"
268
276
  end
269
277
 
270
278
  # Add the dependencies declared in spec
271
- depends_on *@spec_dependencies if @spec_dependencies
279
+ depends_on(*@spec_dependencies) if @spec_dependencies
272
280
  update_environment
273
281
  end
274
282
 
@@ -404,33 +412,6 @@ module Autobuild
404
412
  task
405
413
  end
406
414
 
407
- module TaskExtension
408
- attr_accessor :package
409
- end
410
-
411
- def source_tree(*args, &block)
412
- task = Autobuild.source_tree(*args, &block)
413
- task.extend TaskExtension
414
- task.package = self
415
- task
416
- end
417
-
418
- # Calls Rake to define a file task and then extends it with TaskExtension
419
- def file(*args, &block)
420
- task = super
421
- task.extend TaskExtension
422
- task.package = self
423
- task
424
- end
425
-
426
- # Calls Rake to define a plain task and then extends it with TaskExtension
427
- def task(*args, &block)
428
- task = super
429
- task.extend TaskExtension
430
- task.package = self
431
- task
432
- end
433
-
434
415
  def doc_dir=(value); doc_utility.source_dir = value end
435
416
  def doc_dir; doc_utility.source_dir end
436
417
  def doc_target_dir=(value); doc_utility.target_dir = value end
@@ -102,9 +102,9 @@ module Autobuild
102
102
  end
103
103
 
104
104
  if !programs.kind_of?(Hash)
105
- programs = Array[*programs].inject({}) do |programs, spec|
106
- programs[spec.first] = spec.last
107
- programs
105
+ programs = Array[*programs].inject({}) do |progs, spec|
106
+ progs[spec.first] = spec.last
107
+ progs
108
108
  end
109
109
  end
110
110
  programs.each do |name, opt|
@@ -168,7 +168,7 @@ module Autobuild
168
168
  # If it is not the case, remove it to force reconfiguration
169
169
  configureflags.flatten!
170
170
  force_reconfigure = false
171
- if File.exists?(configurestamp)
171
+ if File.exist?(configurestamp)
172
172
  output = IO.popen("#{configurestamp} --version").readlines.grep(/with options/).first.chomp
173
173
  raise "invalid output of config.status --version" unless output =~ /with options "(.*)"$/
174
174
  options = Shellwords.shellwords($1)
@@ -224,11 +224,11 @@ module Autobuild
224
224
  end
225
225
  using[:aclocal] = using[:autoconf] if using[:aclocal].nil?
226
226
  if using[:automake].nil?
227
- using[:automake] = File.exists?(File.join(srcdir, 'Makefile.am'))
227
+ using[:automake] = File.exist?(File.join(srcdir, 'Makefile.am'))
228
228
  end
229
229
 
230
230
  if using[:libtool].nil?
231
- using[:libtool] = File.exists?(File.join(srcdir, 'ltmain.sh'))
231
+ using[:libtool] = File.exist?(File.join(srcdir, 'ltmain.sh'))
232
232
  end
233
233
  end
234
234
 
@@ -237,7 +237,7 @@ module Autobuild
237
237
  conffile = "#{srcdir}/configure"
238
238
  if confsource
239
239
  file conffile => confsource
240
- elsif confext = %w{.ac .in}.find { |ext| File.exists?("#{conffile}#{ext}") }
240
+ elsif confext = %w{.ac .in}.find { |ext| File.exist?("#{conffile}#{ext}") }
241
241
  file conffile => "#{conffile}#{confext}"
242
242
  else
243
243
  raise PackageException.new(self, 'prepare'), "neither configure.ac nor configure.in present in #{srcdir}"
@@ -247,7 +247,7 @@ module Autobuild
247
247
  isolate_errors do
248
248
  in_dir(srcdir) do
249
249
  if using[:autogen].nil?
250
- using[:autogen] = %w{autogen autogen.sh}.find { |f| File.exists?(File.join(srcdir, f)) }
250
+ using[:autogen] = %w{autogen autogen.sh}.find { |f| File.exist?(File.join(srcdir, f)) }
251
251
  end
252
252
 
253
253
  autodetect_needed_stages
@@ -76,13 +76,14 @@ module Autobuild
76
76
  end
77
77
 
78
78
  def define(name, value)
79
- @defines[name] = value
80
- end
81
-
82
- def doc_dir
83
- if @doc_dir
84
- File.expand_path(@doc_dir, builddir)
85
- end
79
+ @defines[name] =
80
+ if value.respond_to?(:to_str)
81
+ value.to_str
82
+ elsif value
83
+ 'ON'
84
+ else
85
+ 'OFF'
86
+ end
86
87
  end
87
88
 
88
89
  DOXYGEN_ACCEPTED_VARIABLES = {
@@ -265,13 +266,13 @@ module Autobuild
265
266
  # but no Makefile.
266
267
  #
267
268
  # Delete the CMakeCache to force reconfiguration
268
- if !File.exists?( File.join(builddir, 'Makefile') )
269
+ if !File.exist?( File.join(builddir, 'Makefile') )
269
270
  FileUtils.rm_f cmake_cache
270
271
  end
271
272
 
272
273
  doc_utility.source_ref_dir = builddir
273
274
 
274
- if File.exists?(cmake_cache)
275
+ if File.exist?(cmake_cache)
275
276
  all_defines = defines.dup
276
277
  all_defines['CMAKE_INSTALL_PREFIX'] = prefix
277
278
  all_defines['CMAKE_MODULE_PATH'] = "#{CMake.module_path.join(";")}"
@@ -361,24 +362,24 @@ module Autobuild
361
362
 
362
363
  # Do the build in builddir
363
364
  def build
365
+ current_message = String.new
364
366
  in_dir(builddir) do
365
367
  progress_start "building %s" do
366
368
  if always_reconfigure || !File.file?('Makefile')
367
369
  Subprocess.run(self, 'build', Autobuild.tool(:cmake), '.')
368
370
  end
369
371
 
370
- current_message = String.new
371
372
  warning_count = 0
372
373
  Autobuild.make_subcommand(self, 'build') do |line|
373
374
  needs_display = false
374
375
  if line =~ /\[\s*(\d+)%\]/
375
376
  progress "building %s (#{Integer($1)}%)"
376
- elsif line !~ /^(?:Linking|Scanning|Building|Built)/
377
+ elsif line !~ /^(?:Generating|Linking|Scanning|Building|Built)/
377
378
  if line =~ /warning/
378
379
  warning_count += 1
379
380
  end
380
381
  if show_make_messages?
381
- current_message += line
382
+ current_message += line + "\n"
382
383
  needs_display = true
383
384
  end
384
385
  end
@@ -400,6 +401,11 @@ module Autobuild
400
401
  end
401
402
  end
402
403
  Autobuild.touch_stamp(buildstamp)
404
+ rescue ::Exception
405
+ current_message.split("\n").each do |l|
406
+ message "%s: #{l}", :magenta
407
+ end
408
+ raise
403
409
  end
404
410
 
405
411
  # Install the result in prefix
@@ -117,7 +117,7 @@ module Autobuild
117
117
 
118
118
  # Check that the module has been generated with the same flags
119
119
  genom_mk = "#{srcdir}/autoconf/genom.mk"
120
- if File.exists?(genom_mk)
120
+ if File.exist?(genom_mk)
121
121
  contents = File.open(genom_mk).readlines
122
122
  old_file = contents.find { |l| l =~ /^GENFILE/ }.gsub('GENFILE=', '').strip
123
123
  old_flags = Shellwords.shellwords(
@@ -18,31 +18,30 @@ module Autobuild
18
18
  make_is_gnumake?(path)
19
19
  end
20
20
 
21
- def self.make_subcommand(pkg, phase, *options, &block)
21
+ def self.invoke_make_parallel(pkg, cmd_path = Autobuild.tool(:make))
22
22
  reserved = nil
23
- cmd_path = Autobuild.tool(:make)
24
- cmd = [cmd_path]
25
23
  if make_has_j_option?(cmd_path) && pkg.parallel_build_level != 1
26
24
  if manager = Autobuild.parallel_task_manager
27
25
  job_server = manager.job_server
28
26
  if !make_has_gnumake_jobserver?(cmd_path) || (pkg.parallel_build_level != Autobuild.parallel_build_level)
29
27
  reserved = pkg.parallel_build_level
30
28
  job_server.get(reserved - 1) # We already have one token taken by autobuild itself
31
- cmd << "-j#{pkg.parallel_build_level}"
32
- else
33
- cmd << "--jobserver-fds=#{job_server.rio.fileno},#{job_server.wio.fileno}" << "-j"
29
+ yield("-j#{pkg.parallel_build_level}")
34
30
  end
35
- else
36
- cmd << "-j#{pkg.parallel_build_level}"
31
+ yield("--jobserver-fds=#{job_server.rio.fileno},#{job_server.wio.fileno}", "-j")
37
32
  end
33
+ yield("-j#{pkg.parallel_build_level}")
34
+ else yield
38
35
  end
39
-
40
- cmd.concat(options)
41
- Subprocess.run(pkg, phase, *cmd, &block)
42
-
43
36
  ensure
44
37
  if reserved
45
38
  job_server.put(reserved)
46
39
  end
47
40
  end
41
+
42
+ def self.make_subcommand(pkg, phase, *options, &block)
43
+ invoke_make_parallel(pkg, Autobuild.tool(:make)) do |*make_parallel_options|
44
+ Subprocess.run(pkg, phase, Autobuild.tool(:make), *make_parallel_options, *options, &block)
45
+ end
46
+ end
48
47
  end
@@ -318,7 +318,7 @@ module Autobuild
318
318
  #
319
319
  # First, check if the command line changed
320
320
  needs_regen ||=
321
- if File.exists?(genstamp)
321
+ if File.exist?(genstamp)
322
322
  last_cmdline = File.read(genstamp).split("\n")
323
323
  last_cmdline != cmdline
324
324
  else
@@ -47,6 +47,14 @@ module Autobuild
47
47
  end
48
48
  end
49
49
 
50
+ def invoke_rake(setup_task = rake_setup_task)
51
+ if setup_task && File.file?(File.join(srcdir, 'Rakefile'))
52
+ Autobuild::Subprocess.run self, 'post-install',
53
+ Autobuild.tool_in_path('ruby'), '-S', Autobuild.tool('rake'), setup_task,
54
+ :working_directory => srcdir
55
+ end
56
+ end
57
+
50
58
  def install
51
59
  progress_start "setting up Ruby package %s", :done_message => 'set up Ruby package %s' do
52
60
  Autobuild.update_environment srcdir
@@ -57,11 +65,7 @@ module Autobuild
57
65
  Autobuild.env_add_path 'RUBYLIB', libdir
58
66
  end
59
67
 
60
- if rake_setup_task && File.file?(File.join(srcdir, 'Rakefile'))
61
- Autobuild::Subprocess.run self, 'post-install',
62
- Autobuild.tool_in_path('ruby'), '-S', Autobuild.tool('rake'), rake_setup_task,
63
- :working_directory => srcdir
64
- end
68
+ invoke_rake
65
69
  end
66
70
  super
67
71
  end
@@ -34,13 +34,17 @@ module Autobuild
34
34
  end
35
35
 
36
36
  def self.display_message(*args)
37
+ io = STDOUT
38
+ if args.last.kind_of?(IO)
39
+ io = args.pop
40
+ end
37
41
  msg =
38
42
  if args.empty? then ""
39
43
  else "#{color(*args)}"
40
44
  end
41
45
 
42
46
  if !Autobuild.progress_display_enabled?
43
- puts msg
47
+ io.puts msg
44
48
  return
45
49
  end
46
50
 
@@ -50,7 +54,7 @@ module Autobuild
50
54
  end
51
55
 
52
56
  if !silent?
53
- puts "\r#{msg}#{" " * [size - msg.size, 0].max}"
57
+ io.puts "\r#{msg}#{" " * [size - msg.size, 0].max}"
54
58
  if @last_progress_msg
55
59
  print "#{@last_progress_msg}"
56
60
  end
@@ -64,12 +68,12 @@ module Autobuild
64
68
 
65
69
  # Displays an error message
66
70
  def self.error(message = "")
67
- message(" ERROR: #{message}", :red, :bold)
71
+ message(" ERROR: #{message}", :red, :bold, STDERR)
68
72
  end
69
73
 
70
74
  # Displays a warning message
71
75
  def self.warn(message = "", *style)
72
- message(" WARN: #{message}", :magenta, *style)
76
+ message(" WARN: #{message}", :magenta, *style, STDERR)
73
77
  end
74
78
 
75
79
  # @return [Boolean] true if there is some progress messages for the given
@@ -102,7 +106,7 @@ module Autobuild
102
106
  progress(key, *options[:done_message])
103
107
  end
104
108
  progress_done(key, true)
105
- rescue Exception => e
109
+ rescue Exception
106
110
  progress_done(key, false)
107
111
  raise
108
112
  end
@@ -335,7 +339,7 @@ module Autobuild
335
339
  ## Display using stdout
336
340
  class StdoutReporter < Reporter
337
341
  def error(error)
338
- puts "Build failed: #{error}"
342
+ STDERR.puts "Build failed: #{error}"
339
343
  end
340
344
  def success
341
345
  puts "Build finished successfully at #{Time.now}"
@@ -39,11 +39,22 @@ module Autobuild
39
39
  reset_statistics
40
40
 
41
41
  @parallel_build_level = nil
42
+ @displayed_error_line_count = 10
42
43
  class << self
43
44
  # Sets the level of parallelism during the build
44
45
  #
45
46
  # See #parallel_build_level for detailed information
46
47
  attr_writer :parallel_build_level
48
+
49
+ # set/get a value how much log lines should be displayed on errors
50
+ # this may be an integer or 'ALL' (which will be translated to -1)
51
+ # this is not using an attr_accessor to be able to validate the values
52
+ def displayed_error_line_count=(value)
53
+ @displayed_error_line_count = validate_displayed_error_line_count(value)
54
+ end
55
+ def displayed_error_line_count
56
+ @displayed_error_line_count
57
+ end
47
58
 
48
59
  # Returns the number of processes that can run in parallel during the
49
60
  # build. This is a system-wide value that can be overriden in a
@@ -121,31 +132,82 @@ module Autobuild
121
132
 
122
133
  @processor_count
123
134
  end
135
+
136
+ def self.validate_displayed_error_line_count(lines)
137
+ if lines == 'ALL'
138
+ return Float::INFINITY
139
+ elsif lines.to_i > 0
140
+ return lines.to_i
141
+ end
142
+ raise ConfigError, 'Autobuild.displayed_error_line_count can only be a positive integer or \'ALL\''
143
+ end
144
+
124
145
  end
125
146
 
126
147
 
127
148
  module Autobuild::Subprocess
128
149
  class Failed < Exception
150
+ def retry?; @retry end
129
151
  attr_reader :status
130
- def initialize(status = nil)
152
+
153
+ def initialize(status, do_retry)
131
154
  @status = status
155
+ @retry = do_retry
132
156
  end
133
157
  end
134
158
 
135
159
  CONTROL_COMMAND_NOT_FOUND = 1
136
160
  CONTROL_UNEXPECTED = 2
137
161
  CONTROL_INTERRUPT = 3
162
+
163
+ # Run a subcommand and return its standard output
164
+ #
165
+ # The command's standard and error outputs, as well as the full command line
166
+ # and an environment dump are saved in a log file in either the valure
167
+ # returned by target#logdir, or Autobuild.logdir if the target does not
168
+ # respond to #logdir.
169
+ #
170
+ # The subprocess priority is controlled by Autobuild.nice
171
+ #
172
+ # @param [String,(#name,#logdir,#working_directory)] target the target we
173
+ # run the subcommand for. In general, it will be a Package object (run from
174
+ # Package#run)
175
+ # @param [String] phase in which build phase this subcommand is executed
176
+ # @param [Array<String>] the command itself
177
+ # @yieldparam [String] line if a block is given, each output line from the
178
+ # command's standard output are yield to it. This is meant for progress
179
+ # display, and is disabled if Autobuild.verbose is set.
180
+ # @param [Hash] options
181
+ # @option options [String] :working_directory the directory in which the
182
+ # command should be started. If nil, runs in the current directory. The
183
+ # default is to either use the value returned by #working_directory on
184
+ # {target} if it responds to it, or nil.
185
+ # @option options [Boolean] :retry (false) controls whether a failure to
186
+ # execute this command should be retried by autobuild retry mechanisms (i.e.
187
+ # in the importers) or not. {run} will not retry the command by itself, it
188
+ # is passed as a hint for error handling clauses about whether the error
189
+ # should be retried or not
190
+ # @option options [Array<IO>] :input_streams list of input streams that
191
+ # should be fed to the command standard input. If a file needs to be given,
192
+ # the :input argument can be used as well as a shortcut
193
+ # @option options [String] :input the path to a file whose content should be
194
+ # fed to the command standard input
195
+ # @return [String] the command standard output
138
196
  def self.run(target, phase, *command)
139
197
  STDOUT.sync = true
140
198
 
141
199
  input_streams = []
142
- options = Hash.new
200
+ options = Hash[retry: false]
143
201
  if command.last.kind_of?(Hash)
144
202
  options = command.pop
145
203
  options = Kernel.validate_options options,
146
- :input => nil, :working_directory => nil
204
+ input: nil, working_directory: nil, retry: false,
205
+ input_streams: []
147
206
  if options[:input]
148
- input_streams = [options[:input]]
207
+ input_streams << File.open(options[:input])
208
+ end
209
+ if options[:input_streams]
210
+ input_streams += options[:input_streams]
149
211
  end
150
212
  end
151
213
 
@@ -186,6 +248,7 @@ module Autobuild::Subprocess
186
248
  end
187
249
 
188
250
  Autobuild.register_logfile(logname)
251
+ subcommand_output = Array.new
189
252
 
190
253
  status = File.open(logname, open_flag) do |logfile|
191
254
  if Autobuild.keep_oldlogs
@@ -207,26 +270,20 @@ module Autobuild::Subprocess
207
270
  if !input_streams.empty?
208
271
  pread, pwrite = IO.pipe # to feed subprocess stdin
209
272
  end
210
- if Autobuild.verbose || block_given? # the caller wants the stdout/stderr stream of the process, git it to him
211
- outread, outwrite = IO.pipe
212
- outread.sync = true
213
- outwrite.sync = true
214
- end
273
+
274
+ outread, outwrite = IO.pipe
275
+ outread.sync = true
276
+ outwrite.sync = true
277
+
215
278
  cread, cwrite = IO.pipe # to control that exec goes well
216
279
 
217
280
  if Autobuild.windows?
218
- olddir = Dir.pwd
219
- if options[:working_directory] && (options[:working_directory] != Dir.pwd)
220
- Dir.chdir(options[:working_directory])
221
- end
222
- system(*command)
223
- result=$?.success?
224
- if(!result)
225
- error = Autobuild::SubcommandFailed.new(target, command.join(" "), logname, "Systemcall")
226
- error.phase = phase
227
- raise error
281
+ Dir.chdir(options[:working_directory]) do
282
+ if !system(*command)
283
+ raise Failed.new($?.exitstatus, nil),
284
+ "'#{command.join(' ')}' returned status #{status.exitstatus}"
285
+ end
228
286
  end
229
- Dir.chdir(olddir)
230
287
  return
231
288
  end
232
289
 
@@ -278,13 +335,12 @@ module Autobuild::Subprocess
278
335
  if !input_streams.empty?
279
336
  pread.close
280
337
  begin
281
- input_streams.each do |infile|
282
- File.open(infile) do |instream|
283
- instream.each_line { |line| pwrite.write(line) }
284
- end
338
+ input_streams.each do |instream|
339
+ instream.each_line { |line| pwrite.write(line) }
285
340
  end
286
341
  rescue Errno::ENOENT => e
287
- raise Failed.new, "cannot open input files: #{e.message}"
342
+ raise Failed.new(nil, false),
343
+ "cannot open input files: #{e.message}", retry: false
288
344
  end
289
345
  pwrite.close
290
346
  end
@@ -296,43 +352,45 @@ module Autobuild::Subprocess
296
352
  # An error occured
297
353
  value = value.unpack('I').first
298
354
  if value == CONTROL_COMMAND_NOT_FOUND
299
- raise Failed.new, "command '#{command.first}' not found"
355
+ raise Failed.new(nil, false),
356
+ "command '#{command.first}' not found"
300
357
  elsif value == CONTROL_INTERRUPT
301
358
  raise Interrupt, "command '#{command.first}': interrupted by user"
302
359
  else
303
- raise Failed.new, "something unexpected happened"
360
+ raise Failed.new(nil, false),
361
+ "something unexpected happened"
304
362
  end
305
363
  end
306
364
 
307
365
  # If the caller asked for process output, provide it to him
308
366
  # line-by-line.
309
- if outread
310
- outwrite.close
311
- outread.each_line do |line|
312
- if line.respond_to?(:force_encoding)
313
- line.force_encoding('BINARY')
314
- end
315
- if Autobuild.verbose
316
- STDOUT.print line
317
- end
318
- logfile.puts line
319
- # Do not yield the line if Autobuild.verbose is true, as it
320
- # would mix the progress output with the actual command
321
- # output. Assume that if the user wants the command output,
322
- # the autobuild progress output is unnecessary
323
- if !Autobuild.verbose && block_given?
324
- yield(line)
325
- end
367
+ outwrite.close
368
+ outread.each_line do |line|
369
+ line.force_encoding('BINARY')
370
+ line = line.chomp
371
+ subcommand_output << line
372
+
373
+ if Autobuild.verbose
374
+ STDOUT.puts line
375
+ end
376
+ logfile.puts line
377
+ # Do not yield the line if Autobuild.verbose is true, as it
378
+ # would mix the progress output with the actual command
379
+ # output. Assume that if the user wants the command output,
380
+ # the autobuild progress output is unnecessary
381
+ if !Autobuild.verbose && block_given?
382
+ yield(line)
326
383
  end
327
- outread.close
328
384
  end
385
+ outread.close
329
386
 
330
- childpid, childstatus = Process.wait2(pid)
387
+ _, childstatus = Process.wait2(pid)
331
388
  childstatus
332
389
  end
333
390
 
334
391
  if !status.exitstatus || status.exitstatus > 0
335
- raise Failed.new(status.exitstatus), "'#{command.join(' ')}' returned status #{status.exitstatus}"
392
+ raise Failed.new(status.exitstatus, nil),
393
+ "'#{command.join(' ')}' returned status #{status.exitstatus}"
336
394
  end
337
395
 
338
396
  duration = Time.now - start_time
@@ -345,14 +403,16 @@ module Autobuild::Subprocess
345
403
  if target.respond_to?(:add_stat)
346
404
  target.add_stat(phase, duration)
347
405
  end
406
+ subcommand_output
348
407
 
349
408
  rescue Failed => e
350
- error = Autobuild::SubcommandFailed.new(target, command.join(" "), logname, e.status)
409
+ error = Autobuild::SubcommandFailed.new(target, command.join(" "), logname, e.status, subcommand_output)
410
+ error.retry = if e.retry?.nil? then options[:retry]
411
+ else e.retry?
412
+ end
351
413
  error.phase = phase
352
414
  raise error, e.message
353
415
  end
354
416
 
355
417
  end
356
418
 
357
-
358
-