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.
- checksums.yaml +4 -4
- data/.rubocop.yml +107 -0
- data/.travis.yml +3 -2
- data/Gemfile +2 -1
- data/Rakefile +1 -4
- data/autobuild.gemspec +18 -13
- data/bin/autobuild +4 -3
- data/lib/autobuild.rb +4 -5
- data/lib/autobuild/build_logfile.rb +6 -4
- data/lib/autobuild/config.rb +104 -41
- data/lib/autobuild/configurable.rb +32 -18
- data/lib/autobuild/environment.rb +126 -120
- data/lib/autobuild/exceptions.rb +48 -31
- data/lib/autobuild/import/archive.rb +134 -82
- data/lib/autobuild/import/cvs.rb +28 -24
- data/lib/autobuild/import/darcs.rb +13 -16
- data/lib/autobuild/import/git-lfs.rb +37 -30
- data/lib/autobuild/import/git.rb +246 -182
- data/lib/autobuild/import/hg.rb +23 -18
- data/lib/autobuild/import/svn.rb +48 -29
- data/lib/autobuild/importer.rb +534 -499
- data/lib/autobuild/mail_reporter.rb +77 -77
- data/lib/autobuild/package.rb +200 -122
- data/lib/autobuild/packages/autotools.rb +47 -42
- data/lib/autobuild/packages/cmake.rb +77 -65
- data/lib/autobuild/packages/dummy.rb +9 -8
- data/lib/autobuild/packages/genom.rb +1 -1
- data/lib/autobuild/packages/gnumake.rb +74 -31
- data/lib/autobuild/packages/import.rb +2 -6
- data/lib/autobuild/packages/orogen.rb +32 -31
- data/lib/autobuild/packages/pkgconfig.rb +2 -2
- data/lib/autobuild/packages/python.rb +12 -8
- data/lib/autobuild/packages/ruby.rb +22 -17
- data/lib/autobuild/parallel.rb +50 -46
- data/lib/autobuild/pkgconfig.rb +25 -13
- data/lib/autobuild/progress_display.rb +149 -64
- data/lib/autobuild/rake_task_extension.rb +12 -7
- data/lib/autobuild/reporting.rb +51 -26
- data/lib/autobuild/subcommand.rb +72 -65
- data/lib/autobuild/test.rb +9 -7
- data/lib/autobuild/test_utility.rb +12 -10
- data/lib/autobuild/timestamps.rb +28 -23
- data/lib/autobuild/tools.rb +17 -16
- data/lib/autobuild/utility.rb +67 -23
- data/lib/autobuild/version.rb +1 -1
- metadata +53 -37
@@ -1,19 +1,24 @@
|
|
1
1
|
module Autobuild
|
2
2
|
module RakeTaskExtension
|
3
3
|
def already_invoked?
|
4
|
-
|
4
|
+
@already_invoked
|
5
5
|
end
|
6
6
|
|
7
|
-
|
8
|
-
|
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
|
-
@
|
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
|
data/lib/autobuild/reporting.rb
CHANGED
@@ -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
|
-
|
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],
|
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 |
|
116
|
+
Autobuild::Package.each do |_name, pkg|
|
100
117
|
errors.concat(pkg.failures)
|
101
118
|
end
|
102
119
|
|
103
|
-
report_finish_on_error(errors,
|
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,
|
125
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
147
|
-
|
166
|
+
else CompositeException.new(errors)
|
167
|
+
end
|
148
168
|
raise e
|
149
|
-
elsif [
|
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 [
|
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:
|
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
|
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
|
-
|
195
|
+
@reporters << reporter
|
175
196
|
end
|
176
197
|
|
177
198
|
def self.remove(reporter)
|
178
|
-
|
199
|
+
@reporters.delete(reporter)
|
179
200
|
end
|
180
201
|
|
181
202
|
def self.clear_reporters
|
182
|
-
|
203
|
+
@reporters.clear
|
183
204
|
end
|
184
205
|
|
185
206
|
def self.each_reporter(&iter)
|
186
|
-
|
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
|
-
|
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
|
data/lib/autobuild/subcommand.rb
CHANGED
@@ -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
|
-
|
56
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
143
|
+
Float::INFINITY
|
139
144
|
elsif lines.to_i > 0
|
140
|
-
|
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
|
-
|
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 =
|
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
|
-
|
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!
|
231
|
-
command.collect!
|
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(/[:]/,'_')}
|
250
|
-
|
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(
|
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
|
-
|
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
|
-
|
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
|
-
|
308
|
-
raise Failed.new(
|
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
|
-
|
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
|
-
|
337
|
+
unless input_streams.empty?
|
334
338
|
pwrite.close
|
335
339
|
$stdin.reopen(pread)
|
336
340
|
end
|
337
341
|
|
338
|
-
exec(env, *command,
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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(" "),
|
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
|