autobuild 1.19.0 → 1.22.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/lint.yml +25 -0
  3. data/.github/workflows/test.yml +30 -0
  4. data/.rubocop.yml +14 -7
  5. data/autobuild.gemspec +8 -6
  6. data/bin/autobuild +1 -1
  7. data/lib/autobuild/build_logfile.rb +1 -2
  8. data/lib/autobuild/config.rb +18 -5
  9. data/lib/autobuild/configurable.rb +3 -1
  10. data/lib/autobuild/environment.rb +28 -45
  11. data/lib/autobuild/exceptions.rb +11 -5
  12. data/lib/autobuild/import/archive.rb +31 -22
  13. data/lib/autobuild/import/cvs.rb +6 -6
  14. data/lib/autobuild/import/darcs.rb +4 -4
  15. data/lib/autobuild/import/git-lfs.rb +4 -4
  16. data/lib/autobuild/import/git.rb +149 -70
  17. data/lib/autobuild/import/hg.rb +7 -7
  18. data/lib/autobuild/import/svn.rb +15 -9
  19. data/lib/autobuild/importer.rb +38 -38
  20. data/lib/autobuild/mail_reporter.rb +5 -2
  21. data/lib/autobuild/package.rb +24 -14
  22. data/lib/autobuild/packages/autotools.rb +4 -9
  23. data/lib/autobuild/packages/cmake.rb +16 -7
  24. data/lib/autobuild/packages/dummy.rb +0 -4
  25. data/lib/autobuild/packages/gnumake.rb +1 -1
  26. data/lib/autobuild/packages/orogen.rb +11 -4
  27. data/lib/autobuild/packages/pkgconfig.rb +2 -2
  28. data/lib/autobuild/packages/python.rb +1 -2
  29. data/lib/autobuild/packages/ruby.rb +5 -5
  30. data/lib/autobuild/parallel.rb +12 -17
  31. data/lib/autobuild/pkgconfig.rb +1 -0
  32. data/lib/autobuild/progress_display.rb +130 -49
  33. data/lib/autobuild/rake_task_extension.rb +6 -0
  34. data/lib/autobuild/reporting.rb +20 -7
  35. data/lib/autobuild/subcommand.rb +24 -23
  36. data/lib/autobuild/test_utility.rb +2 -1
  37. data/lib/autobuild/timestamps.rb +3 -3
  38. data/lib/autobuild/utility.rb +29 -9
  39. data/lib/autobuild/version.rb +1 -1
  40. data/lib/autobuild.rb +0 -3
  41. metadata +42 -26
  42. data/.travis.yml +0 -19
@@ -17,9 +17,9 @@ module Autobuild
17
17
  # @option options [String] :branch (default) the branch to track
18
18
  def initialize(repository, options = {})
19
19
  hgopts, _common = Kernel.filter_options options,
20
- branch: 'default'
20
+ branch: 'default'
21
21
  sourceopts, common = Kernel.filter_options options,
22
- :repository_id, :source_id
22
+ :repository_id, :source_id
23
23
 
24
24
  super(common)
25
25
  @branch = hgopts[:branch]
@@ -48,8 +48,8 @@ module Autobuild
48
48
  def validate_importdir(package)
49
49
  unless File.directory?(File.join(package.importdir, '.hg'))
50
50
  raise ConfigException.new(package, 'import'),
51
- "while importing #{package.name}, "\
52
- "#{package.importdir} is not a hg repository"
51
+ "while importing #{package.name}, "\
52
+ "#{package.importdir} is not a hg repository"
53
53
  end
54
54
  end
55
55
 
@@ -61,9 +61,9 @@ module Autobuild
61
61
  end
62
62
  validate_importdir(package)
63
63
  package.run(:import, Autobuild.tool('hg'), 'pull',
64
- repository, retry: true, working_directory: package.importdir)
64
+ repository, retry: true, working_directory: package.importdir)
65
65
  package.run(:import, Autobuild.tool('hg'), 'update',
66
- branch, working_directory: package.importdir)
66
+ branch, working_directory: package.importdir)
67
67
  true # no easy to know if package was updated, keep previous behavior
68
68
  end
69
69
 
@@ -72,7 +72,7 @@ module Autobuild
72
72
  FileUtils.mkdir_p(base_dir) unless File.directory?(base_dir)
73
73
 
74
74
  package.run(:import, Autobuild.tool('hg'), 'clone',
75
- '-u', branch, repository, package.importdir, retry: true)
75
+ '-u', branch, repository, package.importdir, retry: true)
76
76
  end
77
77
  end
78
78
 
@@ -14,9 +14,11 @@ module Autobuild
14
14
  # Autobuild.programs['svn'] = 'my_svn_tool'
15
15
  def initialize(svnroot, options = {})
16
16
  svnroot = [*svnroot].join("/")
17
- svnopts, common = Kernel.filter_options options,
17
+ svnopts, common = Kernel.filter_options(
18
+ options,
18
19
  :svnup => [], :svnco => [], :revision => nil,
19
20
  :repository_id => "svn:#{svnroot}"
21
+ )
20
22
  common[:repository_id] = svnopts.delete(:repository_id)
21
23
  relocate(svnroot, svnopts)
22
24
  super(common.merge(repository_id: svnopts[:repository_id]))
@@ -67,7 +69,7 @@ module Autobuild
67
69
  revision = svninfo.grep(/^Revision: /).first
68
70
  unless revision
69
71
  raise ConfigException.new(package, 'import'),
70
- "cannot get SVN information for #{package.importdir}"
72
+ "cannot get SVN information for #{package.importdir}"
71
73
  end
72
74
  revision =~ /Revision: (\d+)/
73
75
  Integer($1)
@@ -79,7 +81,9 @@ module Autobuild
79
81
  # @return [String]
80
82
  # @raises (see svn_info)
81
83
  def vcs_fingerprint(package)
82
- Digest::SHA1.hexdigest(svn_info(package).grep(/^(URL|Revision):/).sort.join("\n"))
84
+ Digest::SHA1.hexdigest(
85
+ svn_info(package).grep(/^(URL|Revision):/).sort.join("\n")
86
+ )
83
87
  end
84
88
 
85
89
  # Returns the URL of the remote SVN repository
@@ -93,7 +97,7 @@ module Autobuild
93
97
  url = svninfo.grep(/^URL: /).first
94
98
  unless url
95
99
  raise ConfigException.new(package, 'import'),
96
- "cannot get SVN information for #{package.importdir}"
100
+ "cannot get SVN information for #{package.importdir}"
97
101
  end
98
102
  url.chomp =~ /URL: (.+)/
99
103
  $1
@@ -165,8 +169,9 @@ module Autobuild
165
169
  Hash.new
166
170
  end
167
171
 
168
- options, other_options = Kernel.filter_options options,
169
- working_directory: package.importdir, retry: true
172
+ options, other_options = Kernel.filter_options(
173
+ options, working_directory: package.importdir, retry: true
174
+ )
170
175
  options = options.merge(other_options)
171
176
  package.run(:import, Autobuild.tool(:svn), *args, options, &block)
172
177
  end
@@ -203,7 +208,8 @@ module Autobuild
203
208
 
204
209
  unless svninfo.grep(/is not a working copy/).empty?
205
210
  raise ConfigException.new(package, 'import'),
206
- "#{package.importdir} does not appear to be a Subversion working copy"
211
+ "#{package.importdir} does not appear to be a "\
212
+ "Subversion working copy"
207
213
  end
208
214
  svninfo
209
215
  ensure
@@ -241,8 +247,8 @@ module Autobuild
241
247
 
242
248
  def checkout(package, _options = Hash.new) # :nodoc:
243
249
  run_svn(package, 'co', "--non-interactive", *@options_co,
244
- svnroot, package.importdir,
245
- working_directory: nil)
250
+ svnroot, package.importdir,
251
+ working_directory: nil)
246
252
  end
247
253
  end
248
254
 
@@ -107,7 +107,11 @@ module Autobuild
107
107
  # @return [Array<String>,nil]
108
108
  # @see .cache_dirs
109
109
  def self.default_cache_dirs
110
- [@default_cache_dirs] if @default_cache_dirs ||= ENV['AUTOBUILD_CACHE_DIR']
110
+ if @default_cache_dirs
111
+ @default_cache_dirs
112
+ elsif (from_env = ENV['AUTOBUILD_CACHE_DIR'])
113
+ @default_cache_dirs = [from_env]
114
+ end
111
115
  end
112
116
 
113
117
  # Sets the cache directory for a given importer type
@@ -199,7 +203,8 @@ module Autobuild
199
203
 
200
204
  patches_fingerprint_string = patches_fingerprint(package)
201
205
  if patches_fingerprint_string
202
- Digest::SHA1.hexdigest(vcs_fingerprint_string + patches_fingerprint_string)
206
+ Digest::SHA1.hexdigest(vcs_fingerprint_string +
207
+ patches_fingerprint_string)
203
208
  elsif patches.empty?
204
209
  vcs_fingerprint_string
205
210
  end
@@ -207,16 +212,19 @@ module Autobuild
207
212
 
208
213
  # basic fingerprint of the package and its dependencies
209
214
  def vcs_fingerprint(package)
210
- #each importer type should implement its own
211
- Autoproj.warn "Fingerprint in #{package.name} has not been implemented for this type of packages, results should be discarded"
212
- return nil
215
+ # each importer type should implement its own
216
+ Autoproj.warn "Fingerprint in #{package.name} has not been implemented "\
217
+ "for this type of packages, results should be discarded"
218
+ nil
213
219
  end
214
220
 
215
221
  # fingerprint for patches associated to this package
216
222
  def patches_fingerprint(package)
217
223
  cur_patches = currently_applied_patches(package)
218
- cur_patches.map(&:shift) #leave only level and source information
219
- Digest::SHA1.hexdigest(cur_patches.sort.flatten.join("")) if !patches.empty? && cur_patches
224
+ cur_patches.map(&:shift) # leave only level and source information
225
+ if !patches.empty? && cur_patches
226
+ Digest::SHA1.hexdigest(cur_patches.sort.flatten.join(""))
227
+ end
220
228
  end
221
229
 
222
230
  # Sets the number of times update / checkout should be retried before giving
@@ -310,12 +318,10 @@ module Autobuild
310
318
  end
311
319
 
312
320
  # Enumerate the post-import hooks for this importer
313
- def each_post_hook(error: false)
321
+ def each_post_hook(error: false, &block)
314
322
  return enum_for(__method__, error: false) unless block_given?
315
323
 
316
- self.class.each_post_hook(error: error) do |callback|
317
- yield(callback)
318
- end
324
+ self.class.each_post_hook(error: error, &block)
319
325
 
320
326
  post_hooks.each do |hook|
321
327
  yield(hook.callback) if hook.always || !error
@@ -353,9 +359,9 @@ module Autobuild
353
359
  raise last_error
354
360
  else raise
355
361
  end
356
- rescue ::Exception => original_error
362
+ rescue ::Exception => e
357
363
  message = Autobuild.color('update failed', :red)
358
- last_error = original_error
364
+ last_error = e
359
365
  # If the package is patched, it might be that the update
360
366
  # failed because we needed to unpatch first. Try it out
361
367
  #
@@ -374,11 +380,11 @@ module Autobuild
374
380
  rescue Interrupt
375
381
  raise
376
382
  rescue ::Exception
377
- raise original_error
383
+ raise e
378
384
  end
379
385
  end
380
386
 
381
- retry_count = update_retry_count(original_error, retry_count)
387
+ retry_count = update_retry_count(e, retry_count)
382
388
  raise unless retry_count
383
389
 
384
390
  package.message "update failed in #{package.importdir}, "\
@@ -395,20 +401,20 @@ module Autobuild
395
401
  fallback(e, package, :import, package)
396
402
  end
397
403
 
398
- def perform_checkout(package, options = Hash.new)
404
+ def perform_checkout(package, **options)
399
405
  last_error = nil
400
406
  package.progress_start "checking out %s", :done_message => 'checked out %s' do
401
407
  retry_count = 0
402
408
  begin
403
- checkout(package, options)
409
+ checkout(package, **options)
404
410
  execute_post_hooks(package)
405
411
  rescue Interrupt
406
412
  if last_error then raise last_error
407
413
  else raise
408
414
  end
409
- rescue ::Exception => original_error
410
- last_error = original_error
411
- retry_count = update_retry_count(original_error, retry_count)
415
+ rescue ::Exception => e
416
+ last_error = e
417
+ retry_count = update_retry_count(e, retry_count)
412
418
  raise unless retry_count
413
419
 
414
420
  package.message "checkout of %s failed, "\
@@ -452,31 +458,26 @@ module Autobuild
452
458
  # ID is given will, in this mode, reset the repository to the requested ID
453
459
  # (if that does not involve losing commits). Otherwise, it will only
454
460
  # ensure that the requested commit ID is present in the current HEAD.
455
- def import(package, options = Hash.new)
461
+ def import( # rubocop:disable Metrics/ParameterLists
462
+ package, *old_boolean,
463
+ ignore_errors: false, checkout_only: false, allow_interactive: true, **options
464
+ )
456
465
  # Backward compatibility
457
- unless options.kind_of?(Hash)
458
- options = options
466
+ unless old_boolean.empty?
467
+ old_boolean = old_boolean.first
459
468
  Autoproj.warn "calling #import with a boolean as second argument "\
460
469
  "is deprecated, switch to the named argument interface instead"
461
- Autoproj.warn " e.g. call import(package, only_local: #{options})"
470
+ Autoproj.warn " e.g. call import(package, only_local: #{old_boolean})"
462
471
  Autoproj.warn " #{caller(1..1).first}"
463
- options = Hash[only_local: options]
472
+ options[:only_local] = old_boolean
464
473
  end
465
474
 
466
- options = Kernel.validate_options options,
467
- only_local: false,
468
- reset: false,
469
- checkout_only: false,
470
- ignore_errors: false,
471
- allow_interactive: true
472
- ignore_errors = options.delete(:ignore_errors)
473
-
474
475
  importdir = package.importdir
475
476
  if File.directory?(importdir)
476
477
  package.isolate_errors(mark_as_failed: false,
477
478
  ignore_errors: ignore_errors) do
478
- if !options[:checkout_only] && package.update?
479
- perform_update(package, options)
479
+ if !checkout_only && package.update?
480
+ perform_update(package, checkout_only: false, **options)
480
481
  elsif Autobuild.verbose
481
482
  package.message "%s: not updating"
482
483
  end
@@ -484,12 +485,11 @@ module Autobuild
484
485
 
485
486
  elsif File.exist?(importdir)
486
487
  raise ConfigException.new(package, 'import'),
487
- "#{importdir} exists but is not a directory"
488
+ "#{importdir} exists but is not a directory"
488
489
  else
489
490
  package.isolate_errors(mark_as_failed: true,
490
491
  ignore_errors: ignore_errors) do
491
- perform_checkout(package,
492
- allow_interactive: options[:allow_interactive])
492
+ perform_checkout(package, allow_interactive: allow_interactive)
493
493
  true
494
494
  end
495
495
  end
@@ -22,8 +22,11 @@ if Autobuild::HAS_RMAIL
22
22
  end
23
23
 
24
24
  attr_reader :from_email, :to_email, :smtp_hostname, :smtp_port,
25
- :subject, :only_errors
25
+ :subject, :only_errors
26
+
26
27
  def initialize(config)
28
+ super()
29
+
27
30
  @from_email = (config[:from] || default_mail)
28
31
  @to_email = (config[:to] || default_mail)
29
32
  @subject =
@@ -78,7 +81,7 @@ if Autobuild::HAS_RMAIL
78
81
  to_email.each do |email|
79
82
  mail.header.to = email
80
83
  smtp.send_mail(RMail::Serialize.write('', mail),
81
- from_email, email)
84
+ from_email, email)
82
85
  end
83
86
  end
84
87
 
@@ -64,7 +64,7 @@ module Autobuild
64
64
  # Some statistics about the commands that have been run
65
65
  attr_reader :statistics
66
66
 
67
- EnvOp = Struct.new :type, :name, :values
67
+ EnvOp = Struct.new :type, :name, :values # rubocop:disable Lint/StructNewOverride
68
68
 
69
69
  # List of environment values added by this package with {#env_add},
70
70
  # {#env_add_path} or {#env_set}
@@ -150,6 +150,7 @@ module Autobuild
150
150
  @imported = false
151
151
  @prepared = false
152
152
  @built = false
153
+ @disabled = nil
153
154
 
154
155
  if Hash === spec
155
156
  name, depends = spec.to_a.first
@@ -402,8 +403,8 @@ module Autobuild
402
403
  def isolate_errors(options = Hash.new)
403
404
  options = Hash[mark_as_failed: true] unless options.kind_of?(Hash)
404
405
  options = validate_options options,
405
- mark_as_failed: true,
406
- ignore_errors: Autobuild.ignore_errors
406
+ mark_as_failed: true,
407
+ ignore_errors: Autobuild.ignore_errors
407
408
 
408
409
  # Don't do anything if we already have failed
409
410
  if failed?
@@ -448,12 +449,12 @@ module Autobuild
448
449
  # be done there as well.
449
450
  #
450
451
  # (see Importer#import)
451
- def import(options = Hash.new)
452
- options = Hash[only_local: options] unless options.respond_to?(:to_hash)
452
+ def import(*old_boolean, **options)
453
+ options = { only_local: old_boolean.first } unless old_boolean.empty?
453
454
 
454
455
  @import_invoked = true
455
456
  if @importer
456
- result = @importer.import(self, options)
457
+ result = @importer.import(self, **options)
457
458
  elsif update?
458
459
  message "%s: no importer defined, doing nothing"
459
460
  end
@@ -495,12 +496,12 @@ module Autobuild
495
496
  end
496
497
  end
497
498
  if suffix.empty?
498
- return msg
499
+ msg
499
500
  elsif prefix_style.empty?
500
- return (prefix + suffix).join(" ")
501
+ (prefix + suffix).join(" ")
501
502
  else
502
503
  colorized_prefix = Autobuild.color(prefix.join(" "), *prefix_style)
503
- return [colorized_prefix, *suffix].join(" ")
504
+ [colorized_prefix, *suffix].join(" ")
504
505
  end
505
506
  end
506
507
 
@@ -527,7 +528,7 @@ module Autobuild
527
528
  args[0] = process_formatting_string(args[0], :bold)
528
529
  done_message = process_formatting_string(done_message) if done_message
529
530
  Autobuild.progress_start(self, *args,
530
- done_message: done_message, **raw_options, &block)
531
+ done_message: done_message, **raw_options, &block)
531
532
  end
532
533
 
533
534
  def progress(*args)
@@ -663,6 +664,10 @@ module Autobuild
663
664
  end
664
665
  end
665
666
 
667
+ def self_fingerprint
668
+ importer.fingerprint(self)
669
+ end
670
+
666
671
  # Returns a unique hash representing a state of the package and
667
672
  # its dependencies, if any dependency can't calculate its own
668
673
  # fingerprint the result will be nil
@@ -670,18 +675,23 @@ module Autobuild
670
675
  def fingerprint(recursive: true, memo: {})
671
676
  return memo[name] if memo.key?(name)
672
677
 
673
- self_fingerprint = importer.fingerprint(self)
678
+ self_fingerprint = self.self_fingerprint
674
679
  return unless self_fingerprint
675
- return self_fingerprint if !recursive || dependencies.empty?
680
+ if dependencies.empty?
681
+ return (memo[name] = self_fingerprint)
682
+ elsif !recursive
683
+ return self_fingerprint
684
+ end
676
685
 
677
686
  dependency_fingerprints = dependencies.sort.map do |pkg_name|
678
687
  pkg = Autobuild::Package[pkg_name]
679
688
  unless (fingerprint = memo[pkg.name])
680
689
  fingerprint = pkg.fingerprint(recursive: true, memo: memo)
681
- return unless fingerprint
690
+ break unless fingerprint
682
691
  end
683
692
  fingerprint
684
693
  end
694
+ return unless dependency_fingerprints
685
695
 
686
696
  memo[name] = Digest::SHA1.hexdigest(
687
697
  self_fingerprint + dependency_fingerprints.join(""))
@@ -829,7 +839,7 @@ module Autobuild
829
839
  end
830
840
 
831
841
  # Make sure that this package will be ignored in the build
832
- def disable(phases = Autobuild.all_phases)
842
+ def disable(_phases = Autobuild.all_phases)
833
843
  @disabled = true
834
844
  end
835
845
 
@@ -25,13 +25,8 @@ module Autobuild
25
25
  # To override this default behaviour on a per-package basis, use Autotools#use
26
26
  #
27
27
  class Autotools < Configurable
28
- attr_accessor :using
29
- attr_accessor :configureflags
30
- attr_accessor :aclocal_flags
31
- attr_accessor :autoheader_flags
32
- attr_accessor :autoconf_flags
33
- attr_accessor :automake_flags
34
- attr_accessor :bear_flags
28
+ attr_accessor :using, :configureflags, :aclocal_flags, :autoheader_flags,
29
+ :autoconf_flags, :automake_flags, :bear_flags
35
30
 
36
31
  @builddir = 'build'
37
32
  @@enable_bear_globally = false
@@ -151,7 +146,7 @@ module Autobuild
151
146
  FileUtils.rm_f configurestamp
152
147
  end
153
148
 
154
- def import(options = Hash.new)
149
+ def import(**options)
155
150
  # We force a regen after the first checkout. The issue is that
156
151
  # autotools is less robust than it should, and very often it is
157
152
  # better to generate the build system for the system on which we
@@ -278,7 +273,7 @@ module Autobuild
278
273
  file conffile => "#{conffile}#{confext}"
279
274
  elsif using[:autoconf]
280
275
  raise PackageException.new(self, 'prepare'),
281
- "neither configure.ac nor configure.in present in #{srcdir}"
276
+ "neither configure.ac nor configure.in present in #{srcdir}"
282
277
  end
283
278
 
284
279
  file conffile do