autobuild 1.8.3 → 1.9.0.b1

Sign up to get free protection for your applications and to get access to all the features.
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
-