autobuild 1.17.0 → 1.18.0

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