autobuild 1.18.1 → 1.22.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 (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 +153 -68
  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 +45 -35
  22. data/lib/autobuild/packages/autotools.rb +3 -8
  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 +6 -8
  29. data/lib/autobuild/packages/ruby.rb +5 -5
  30. data/lib/autobuild/parallel.rb +20 -21
  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 +16 -5
  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 +54 -8
  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
@@ -207,28 +208,20 @@ module Autobuild
207
208
  File.directory?(srcdir)
208
209
  end
209
210
 
210
- def prepare_invoked?
211
- task("#{name}-prepare").already_invoked?
212
- end
213
-
214
- def prepared?
215
- @prepared
216
- end
217
-
218
211
  def import_invoked?
219
- task("#{name}-import").already_invoked?
212
+ @import_invoked
220
213
  end
221
214
 
222
215
  def imported?
223
216
  @imported
224
217
  end
225
218
 
226
- def build_invoked?
227
- task("#{name}-build").already_invoked?
219
+ def install_invoked?
220
+ @install_invoked
228
221
  end
229
222
 
230
- def built?
231
- @built
223
+ def installed?
224
+ @installed
232
225
  end
233
226
 
234
227
  def to_s
@@ -410,8 +403,8 @@ module Autobuild
410
403
  def isolate_errors(options = Hash.new)
411
404
  options = Hash[mark_as_failed: true] unless options.kind_of?(Hash)
412
405
  options = validate_options options,
413
- mark_as_failed: true,
414
- ignore_errors: Autobuild.ignore_errors
406
+ mark_as_failed: true,
407
+ ignore_errors: Autobuild.ignore_errors
415
408
 
416
409
  # Don't do anything if we already have failed
417
410
  if failed?
@@ -456,15 +449,16 @@ module Autobuild
456
449
  # be done there as well.
457
450
  #
458
451
  # (see Importer#import)
459
- def import(options = Hash.new)
460
- 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?
461
454
 
455
+ @import_invoked = true
462
456
  if @importer
463
- result = @importer.import(self, options)
464
- @imported = true
457
+ result = @importer.import(self, **options)
465
458
  elsif update?
466
459
  message "%s: no importer defined, doing nothing"
467
460
  end
461
+ @imported = true
468
462
 
469
463
  # Add the dependencies declared in spec
470
464
  depends_on(*@spec_dependencies) if @spec_dependencies
@@ -480,7 +474,10 @@ module Autobuild
480
474
  stamps = dependencies.map { |p| Package[p].installstamp }
481
475
 
482
476
  file installstamp => stamps do
483
- isolate_errors { install }
477
+ isolate_errors do
478
+ @install_invoked = true
479
+ install
480
+ end
484
481
  end
485
482
  task "#{name}-build" => installstamp
486
483
 
@@ -499,12 +496,12 @@ module Autobuild
499
496
  end
500
497
  end
501
498
  if suffix.empty?
502
- return msg
499
+ msg
503
500
  elsif prefix_style.empty?
504
- return (prefix + suffix).join(" ")
501
+ (prefix + suffix).join(" ")
505
502
  else
506
503
  colorized_prefix = Autobuild.color(prefix.join(" "), *prefix_style)
507
- return [colorized_prefix, *suffix].join(" ")
504
+ [colorized_prefix, *suffix].join(" ")
508
505
  end
509
506
  end
510
507
 
@@ -531,7 +528,7 @@ module Autobuild
531
528
  args[0] = process_formatting_string(args[0], :bold)
532
529
  done_message = process_formatting_string(done_message) if done_message
533
530
  Autobuild.progress_start(self, *args,
534
- done_message: done_message, **raw_options, &block)
531
+ done_message: done_message, **raw_options, &block)
535
532
  end
536
533
 
537
534
  def progress(*args)
@@ -563,7 +560,7 @@ module Autobuild
563
560
 
564
561
  Autobuild.touch_stamp(installstamp)
565
562
 
566
- @built = true
563
+ @installed = true
567
564
  end
568
565
 
569
566
  def run(*args, &block)
@@ -580,6 +577,14 @@ module Autobuild
580
577
 
581
578
  module TaskExtension
582
579
  attr_accessor :package
580
+
581
+ def disabled?
582
+ if @disabled.nil? && package
583
+ package.disabled?
584
+ else
585
+ super
586
+ end
587
+ end
583
588
  end
584
589
 
585
590
  def source_tree(*args, &block)
@@ -659,6 +664,10 @@ module Autobuild
659
664
  end
660
665
  end
661
666
 
667
+ def self_fingerprint
668
+ importer.fingerprint(self)
669
+ end
670
+
662
671
  # Returns a unique hash representing a state of the package and
663
672
  # its dependencies, if any dependency can't calculate its own
664
673
  # fingerprint the result will be nil
@@ -666,18 +675,23 @@ module Autobuild
666
675
  def fingerprint(recursive: true, memo: {})
667
676
  return memo[name] if memo.key?(name)
668
677
 
669
- self_fingerprint = importer.fingerprint(self)
678
+ self_fingerprint = self.self_fingerprint
670
679
  return unless self_fingerprint
671
- 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
672
685
 
673
686
  dependency_fingerprints = dependencies.sort.map do |pkg_name|
674
687
  pkg = Autobuild::Package[pkg_name]
675
688
  unless (fingerprint = memo[pkg.name])
676
689
  fingerprint = pkg.fingerprint(recursive: true, memo: memo)
677
- return unless fingerprint
690
+ break unless fingerprint
678
691
  end
679
692
  fingerprint
680
693
  end
694
+ return unless dependency_fingerprints
681
695
 
682
696
  memo[name] = Digest::SHA1.hexdigest(
683
697
  self_fingerprint + dependency_fingerprints.join(""))
@@ -820,17 +834,13 @@ module Autobuild
820
834
  phases.each do |phase|
821
835
  task "#{name}-#{phase}"
822
836
  t = Rake::Task["#{name}-#{phase}"]
823
- t.disable!
837
+ t.disable
824
838
  end
825
839
  end
826
840
 
827
841
  # Make sure that this package will be ignored in the build
828
- def disable(phases = Autobuild.all_phases)
842
+ def disable(_phases = Autobuild.all_phases)
829
843
  @disabled = true
830
- disable_phases(*phases)
831
- task(installstamp)
832
- t = Rake::Task[installstamp]
833
- t.disable!
834
844
  end
835
845
 
836
846
  def utility(utility_name)