autobuild 1.17.0 → 1.18.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +107 -0
  3. data/Gemfile +2 -1
  4. data/Rakefile +1 -4
  5. data/autobuild.gemspec +14 -11
  6. data/bin/autobuild +4 -3
  7. data/lib/autobuild.rb +4 -5
  8. data/lib/autobuild/build_logfile.rb +6 -4
  9. data/lib/autobuild/config.rb +90 -40
  10. data/lib/autobuild/configurable.rb +30 -18
  11. data/lib/autobuild/environment.rb +126 -120
  12. data/lib/autobuild/exceptions.rb +48 -31
  13. data/lib/autobuild/import/archive.rb +134 -82
  14. data/lib/autobuild/import/cvs.rb +28 -24
  15. data/lib/autobuild/import/darcs.rb +13 -16
  16. data/lib/autobuild/import/git-lfs.rb +37 -30
  17. data/lib/autobuild/import/git.rb +231 -179
  18. data/lib/autobuild/import/hg.rb +23 -18
  19. data/lib/autobuild/import/svn.rb +48 -29
  20. data/lib/autobuild/importer.rb +530 -499
  21. data/lib/autobuild/mail_reporter.rb +77 -77
  22. data/lib/autobuild/package.rb +171 -101
  23. data/lib/autobuild/packages/autotools.rb +47 -42
  24. data/lib/autobuild/packages/cmake.rb +71 -65
  25. data/lib/autobuild/packages/dummy.rb +9 -8
  26. data/lib/autobuild/packages/genom.rb +1 -1
  27. data/lib/autobuild/packages/gnumake.rb +19 -13
  28. data/lib/autobuild/packages/import.rb +2 -6
  29. data/lib/autobuild/packages/orogen.rb +32 -31
  30. data/lib/autobuild/packages/pkgconfig.rb +2 -2
  31. data/lib/autobuild/packages/python.rb +7 -2
  32. data/lib/autobuild/packages/ruby.rb +22 -17
  33. data/lib/autobuild/parallel.rb +35 -39
  34. data/lib/autobuild/pkgconfig.rb +25 -13
  35. data/lib/autobuild/progress_display.rb +23 -23
  36. data/lib/autobuild/rake_task_extension.rb +6 -6
  37. data/lib/autobuild/reporting.rb +38 -26
  38. data/lib/autobuild/subcommand.rb +72 -65
  39. data/lib/autobuild/test.rb +8 -7
  40. data/lib/autobuild/test_utility.rb +10 -9
  41. data/lib/autobuild/timestamps.rb +28 -23
  42. data/lib/autobuild/tools.rb +17 -16
  43. data/lib/autobuild/utility.rb +16 -18
  44. data/lib/autobuild/version.rb +1 -1
  45. metadata +39 -38
@@ -2,10 +2,16 @@
2
2
  class PkgConfig
3
3
  class NotFound < RuntimeError
4
4
  attr_reader :name
5
- def initialize(name); @name = name end
6
- def to_s; "#{name} is not available to pkg-config" end
5
+
6
+ def initialize(name)
7
+ @name = name
8
+ end
9
+
10
+ def to_s
11
+ "#{name} is not available to pkg-config"
12
+ end
7
13
  end
8
-
14
+
9
15
  # The module name
10
16
  attr_reader :name
11
17
  # The module version
@@ -14,30 +20,36 @@ def to_s; "#{name} is not available to pkg-config" end
14
20
  # Create a PkgConfig object for the package +name+
15
21
  # Raises PkgConfig::NotFound if the module does not exist
16
22
  def initialize(name)
17
- if !system("pkg-config --exists #{name}")
18
- raise NotFound.new(name)
23
+ unless system("pkg-config --exists #{name}")
24
+ raise NotFound.new(name), "pkg-config package '#{name}' not found"
19
25
  end
20
-
26
+
21
27
  @name = name
22
28
  @version = `pkg-config --modversion #{name}`.chomp.strip
23
29
  @actions = Hash.new
24
30
  @variables = Hash.new
25
31
  end
26
32
 
27
- ACTIONS = %w{cflags cflags-only-I cflags-only-other
28
- libs libs-only-L libs-only-l libs-only-other static}
33
+ ACTIONS = %w[cflags cflags-only-I cflags-only-other
34
+ libs libs-only-L libs-only-l libs-only-other static].freeze
29
35
  ACTIONS.each do |action|
30
- define_method(action.gsub(/-/, '_')) do
36
+ define_method(action.tr('-', '_')) do
31
37
  @actions[action] ||= `pkg-config --#{action} #{name}`.chomp.strip
32
38
  end
33
39
  end
34
40
 
41
+ def respond_to_missing?(varname, _include_all)
42
+ varname =~ /^\w+$/
43
+ end
44
+
35
45
  def method_missing(varname, *args, &proc)
36
46
  if args.empty?
37
- @variables[varname] ||= `pkg-config --variable=#{varname} #{name}`.chomp.strip
38
- else
39
- super(varname, *args, &proc)
47
+ unless (value = @variables[varname])
48
+ value = `pkg-config --variable=#{varname} #{name}`.chomp.strip
49
+ @variables[varname] = value
50
+ end
51
+ return value
40
52
  end
53
+ super
41
54
  end
42
55
  end
43
-
@@ -3,7 +3,6 @@ module Autobuild
3
3
  class ProgressDisplay
4
4
  def initialize(io, color: ::Autobuild.method(:color))
5
5
  @io = io
6
- #@cursor = Blank.new
7
6
  @cursor = TTY::Cursor
8
7
  @last_formatted_progress = []
9
8
  @progress_messages = []
@@ -21,7 +20,8 @@ def silent?
21
20
  end
22
21
 
23
22
  def silent
24
- @silent, silent = true, @silent
23
+ @silent = true
24
+ silent = @silent
25
25
  yield
26
26
  ensure
27
27
  @silent = silent
@@ -36,12 +36,11 @@ def progress_enabled?
36
36
  def message(message, *args, io: @io, force: false)
37
37
  return if silent? && !force
38
38
 
39
- if args.last.respond_to?(:to_io)
40
- io = args.pop
41
- end
39
+ io = args.pop if args.last.respond_to?(:to_io)
42
40
 
43
41
  @display_lock.synchronize do
44
- io.print "#{@cursor.column(1)}#{@cursor.clear_screen_down}#{@color.call(message, *args)}\n"
42
+ io.print "#{@cursor.column(1)}#{@cursor.clear_screen_down}"\
43
+ "#{@color.call(message, *args)}\n"
45
44
  io.flush if @io != io
46
45
  display_progress
47
46
  @io.flush
@@ -94,9 +93,7 @@ def progress_done(key, display_last = true, message: nil)
94
93
  current_size = @progress_messages.size
95
94
  @progress_messages.delete_if do |msg_key, msg|
96
95
  if msg_key == key
97
- if display_last && !message
98
- message = msg
99
- end
96
+ message = msg if display_last && !message
100
97
  true
101
98
  end
102
99
  end
@@ -116,11 +113,11 @@ def progress_done(key, display_last = true, message: nil)
116
113
  end
117
114
  end
118
115
 
119
-
120
116
  def display_progress
121
117
  return unless progress_enabled?
122
118
 
123
- formatted = format_grouped_messages(@progress_messages.map(&:last), indent: " ")
119
+ formatted = format_grouped_messages(@progress_messages.map(&:last),
120
+ indent: " ")
124
121
  @io.print @cursor.clear_screen_down
125
122
  @io.print formatted.join("\n")
126
123
  if formatted.size > 1
@@ -137,13 +134,11 @@ def find_common_prefix(msg, other_msg)
137
134
  msg.each_with_index do |token, idx|
138
135
  if other_msg[idx] != token
139
136
  prefix = msg[0..(idx - 1)].join(" ")
140
- if !prefix.empty?
141
- prefix << " "
142
- end
137
+ prefix << " " unless prefix.empty?
143
138
  return prefix
144
139
  end
145
140
  end
146
- return msg.join(" ")
141
+ msg.join(" ")
147
142
  end
148
143
 
149
144
  def group_messages(messages)
@@ -152,19 +147,22 @@ def group_messages(messages)
152
147
  groups = Array.new
153
148
  groups << ["", (0...messages.size)]
154
149
  messages.each_with_index do |msg, idx|
155
- prefix, grouping = nil, false
150
+ prefix = nil
151
+ grouping = false
156
152
  messages[(idx + 1)..-1].each_with_index do |other_msg, other_idx|
157
153
  other_idx += idx + 1
158
154
  prefix ||= find_common_prefix(msg, other_msg)
159
- break if !other_msg.start_with?(prefix)
155
+ break unless other_msg.start_with?(prefix)
160
156
 
161
157
  if grouping
162
158
  break if prefix != groups.last[0]
159
+
163
160
  groups.last[1] << other_idx
164
161
  else
165
162
  current_prefix, current_group = groups.last
166
- if prefix.size > current_prefix.size # create a new group from there
167
- groups.last[1] = (current_group.first..[idx-1,current_group.last].min)
163
+ if prefix.size > current_prefix.size # create a new group
164
+ group_end_index = [idx - 1, current_group.last].min
165
+ groups.last[1] = (current_group.first..group_end_index)
168
166
  groups << [prefix, [idx, other_idx]]
169
167
  grouping = true
170
168
  else break
@@ -179,13 +177,14 @@ def group_messages(messages)
179
177
  groups.map do |prefix, indexes|
180
178
  indexes = indexes.to_a
181
179
  next if indexes.empty?
180
+
182
181
  range = (prefix.size)..-1
183
182
  [prefix, indexes.map { |i| messages[i][range] }]
184
183
  end.compact
185
184
  end
186
185
 
187
- def format_grouped_messages(messages, indent: " ", width: TTY::Screen.width)
188
- groups = group_messages(messages)
186
+ def format_grouped_messages(raw_messages, indent: " ", width: TTY::Screen.width)
187
+ groups = group_messages(raw_messages)
189
188
  groups.each_with_object([]) do |(prefix, messages), lines|
190
189
  if prefix.empty?
191
190
  lines.concat(messages.map { |m| "#{indent}#{m.strip}" })
@@ -197,10 +196,11 @@ def format_grouped_messages(messages, indent: " ", width: TTY::Screen.width)
197
196
  msg = messages.shift.strip
198
197
  margin = messages.empty? ? 1 : 2
199
198
  if lines.last.size + margin + msg.size > width
200
- lines << "".dup
199
+ lines.last << ","
200
+ lines << +""
201
201
  lines.last << indent << indent << msg
202
202
  else
203
- lines.last << " " << msg
203
+ lines.last << ", " << msg
204
204
  end
205
205
  end
206
206
  lines.last << "," unless messages.empty?
@@ -1,19 +1,19 @@
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
9
- end
7
+ attr_writer :already_invoked
10
8
 
11
9
  def disable!
12
10
  @already_invoked = true
13
- def self.needed?; false end
11
+ singleton_class.class_eval do
12
+ define_method(:needed?) { false }
13
+ end
14
14
  end
15
15
  end
16
16
  end
17
- class Rake::Task
17
+ class Rake::Task # rubocop:disable Style/ClassAndModuleChildren
18
18
  include Autobuild::RakeTaskExtension
19
19
  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
@@ -80,7 +82,7 @@ def self.progress_done(key, display_last = true, message: nil)
80
82
  #
81
83
  # It does not use a logging framework like Log4r, but it should ;-)
82
84
  module Reporting
83
- @@reporters = Array.new
85
+ @reporters = Array.new
84
86
 
85
87
  ## Run a block and report known exception
86
88
  # If an exception is fatal, the program is terminated using exit()
@@ -89,18 +91,22 @@ def self.report(on_package_failures: default_report_on_package_failures)
89
91
  rescue Interrupt => e
90
92
  interrupted = e
91
93
  rescue Autobuild::Exception => e
92
- return report_finish_on_error([e], on_package_failures: on_package_failures, interrupted_by: interrupted)
94
+ return report_finish_on_error([e],
95
+ on_package_failures: on_package_failures,
96
+ interrupted_by: interrupted)
93
97
  end
94
98
 
95
99
  # If ignore_erorrs is true, check if some packages have failed
96
100
  # on the way. If so, raise an exception to inform the user about
97
101
  # it
98
102
  errors = []
99
- Autobuild::Package.each do |name, pkg|
103
+ Autobuild::Package.each do |_name, pkg|
100
104
  errors.concat(pkg.failures)
101
105
  end
102
106
 
103
- report_finish_on_error(errors, on_package_failures: on_package_failures, interrupted_by: interrupted)
107
+ report_finish_on_error(errors,
108
+ on_package_failures: on_package_failures,
109
+ interrupted_by: interrupted)
104
110
  end
105
111
 
106
112
  # @api private
@@ -121,15 +127,18 @@ def self.default_report_on_package_failures
121
127
  #
122
128
  # @param [Symbol] on_package_failures how does the reporting should behave.
123
129
  #
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?) }
130
+ def self.report_finish_on_error(errors,
131
+ on_package_failures: default_report_on_package_failures, interrupted_by: nil)
132
+ if (not_package_error = errors.find { |e| !e.respond_to?(:fatal?) })
126
133
  raise not_package_error
127
134
  end
128
- if ![:raise, :report_silent, :exit_silent].include?(on_package_failures)
135
+
136
+ unless %i[raise report_silent exit_silent].include?(on_package_failures)
129
137
  errors.each { |e| error(e) }
130
138
  end
139
+
131
140
  fatal = errors.any?(&:fatal?)
132
- if !fatal
141
+ unless fatal
133
142
  if interrupted_by
134
143
  raise interrupted_by
135
144
  else
@@ -138,30 +147,29 @@ def self.report_finish_on_error(errors, on_package_failures: default_report_on_p
138
147
  end
139
148
 
140
149
  if on_package_failures == :raise
141
- if interrupted_by
142
- raise interrupted_by
143
- end
150
+ raise interrupted_by if interrupted_by
144
151
 
145
152
  e = if errors.size == 1 then errors.first
146
- else CompositeException.new(errors)
147
- end
153
+ else CompositeException.new(errors)
154
+ end
148
155
  raise e
149
- elsif [:report_silent, :report].include?(on_package_failures)
156
+ elsif %i[report_silent report].include?(on_package_failures)
150
157
  if interrupted_by
151
158
  raise interrupted_by
152
159
  else
153
160
  return errors
154
161
  end
155
- elsif [:exit, :exit_silent].include?(on_package_failures)
162
+ elsif %i[exit exit_silent].include?(on_package_failures)
156
163
  exit 1
157
164
  else
158
- raise ArgumentError, "unexpected value for on_package_failures: #{on_package_failures}"
165
+ raise ArgumentError, "unexpected value for on_package_failures: "\
166
+ "#{on_package_failures}"
159
167
  end
160
168
  end
161
169
 
162
170
  ## Reports a successful build to the user
163
171
  def self.success
164
- each_reporter { |rep| rep.success }
172
+ each_reporter(&:success)
165
173
  end
166
174
 
167
175
  ## Reports that the build failed to the user
@@ -171,19 +179,19 @@ def self.error(error)
171
179
 
172
180
  ## Add a new reporter
173
181
  def self.<<(reporter)
174
- @@reporters << reporter
182
+ @reporters << reporter
175
183
  end
176
184
 
177
185
  def self.remove(reporter)
178
- @@reporters.delete(reporter)
186
+ @reporters.delete(reporter)
179
187
  end
180
188
 
181
189
  def self.clear_reporters
182
- @@reporters.clear
190
+ @reporters.clear
183
191
  end
184
192
 
185
193
  def self.each_reporter(&iter)
186
- @@reporters.each(&iter)
194
+ @reporters.each(&iter)
187
195
  end
188
196
 
189
197
  ## Iterate on all log files
@@ -195,6 +203,7 @@ def self.each_log(&block)
195
203
  ## Base class for reporters
196
204
  class Reporter
197
205
  def error(error); end
206
+
198
207
  def success; end
199
208
  end
200
209
 
@@ -203,11 +212,10 @@ class StdoutReporter < Reporter
203
212
  def error(error)
204
213
  STDERR.puts "Build failed: #{error}"
205
214
  end
215
+
206
216
  def success
207
217
  puts "Build finished successfully at #{Time.now}"
208
- if Autobuild.post_success_message
209
- puts Autobuild.post_success_message
210
- end
218
+ puts Autobuild.post_success_message if Autobuild.post_success_message
211
219
  end
212
220
  end
213
221
 
@@ -216,12 +224,16 @@ def success
216
224
  [1_000_000.0, "M"],
217
225
  [1_000.0, "k"],
218
226
  [1.0, ""]
219
- ]
227
+ ].freeze
220
228
 
221
229
  def self.human_readable_size(size)
222
230
  HUMAN_READABLE_SIZES.each do |scale, name|
223
231
  scaled_size = (size / scale)
224
- return format("%3.1f%s", scaled_size, name) if scaled_size > 1
232
+ if scaled_size > 1
233
+ return format("%3.1<scaled>f%<scale_name>s",
234
+ scaled: scaled_size,
235
+ scale_name: name)
236
+ end
225
237
  end
226
238
  end
227
239
  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