autobuild 1.19.0 → 1.20.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2db3dc0a2d21505b88966e48b4019800e42f39e4a44cbd113a874a4aefad8dc8
4
- data.tar.gz: 3f19bf595f8c258899f1cfd3636257e9c58bd0ca02680a1e205d12d645cb9354
3
+ metadata.gz: 3b347c81cc5ac09e4f967df3dd5f53bca82fb3ba2a1a4a2e76b1b2d20ba19869
4
+ data.tar.gz: 6eaa54db5306f069ce5e9809b708df1bb4c5def84dc1553c953a3e38319cbf26
5
5
  SHA512:
6
- metadata.gz: ac1af6ad08365cda04b28c52e8283fdaf2b4f56ae0b320961fb8600c7126e242c7e83569d8ac8f6722b441efc5f10d18b90a576a76efee1dc53c9c442327562f
7
- data.tar.gz: e716f6c428ea5c6384465697abd8124a9e6aa739ab78025129beec71dd4ec14630e81804f0109a6707575713e69d86fbcd2d16fea4031cff1953ae6ff702fcf9
6
+ metadata.gz: ccefa69f82809031debaeee77adde985c2de4d88c738e9b439cf7e839bc511f2f4c757486625f88a91541d97c16566217a544831c35924ea76cae98920d9f59d
7
+ data.tar.gz: 9f4b9b5c38e9072104dc052c630ca7a49a915331526cdbc624d2ef725eef44987b97b97667ebcafead9afb145fcbb3cee5a921f699aed101ec99efd611c28352
@@ -33,4 +33,5 @@ Gem::Specification.new do |s|
33
33
  s.add_development_dependency "flexmock", '~> 2.0', ">= 2.0.0"
34
34
  s.add_development_dependency "minitest", "~> 5.0", ">= 5.0"
35
35
  s.add_development_dependency "simplecov"
36
+ s.add_development_dependency "timecop"
36
37
  end
@@ -352,7 +352,20 @@ def self.apply(packages, buildname = "autobuild", phases = [], options = Hash.ne
352
352
  invoker = Autobuild::RakeTaskParallelism.new(options[:parallel])
353
353
  Autobuild.parallel_task_manager = invoker
354
354
  phases.each do |phase|
355
- invoker.invoke_parallel([Rake::Task["#{buildname}-#{phase}"]])
355
+ package_tasks = packages.each_with_object({}) do |pkg_name, h|
356
+ h["#{pkg_name}-#{phase}"] = true
357
+ end
358
+ callback =
359
+ if block_given?
360
+ proc do |task|
361
+ yield(task.package, phase) if package_tasks[task.name]
362
+ end
363
+ else
364
+ proc { }
365
+ end
366
+
367
+ invoker.invoke_parallel([Rake::Task["#{buildname}-#{phase}"]],
368
+ completion_callback: callback)
356
369
  end
357
370
  ensure
358
371
  Autobuild.parallel_task_manager = nil
@@ -109,6 +109,7 @@ def prepare
109
109
 
110
110
  stamps = dependencies.map { |pkg| Autobuild::Package[pkg].installstamp }
111
111
  file configurestamp => stamps do
112
+ @install_invoked = true
112
113
  isolate_errors do
113
114
  ensure_dependencies_installed
114
115
  configure
@@ -118,6 +119,7 @@ def prepare
118
119
  task "#{name}-prepare" => configurestamp
119
120
 
120
121
  file buildstamp => [srcdir, configurestamp] do
122
+ @install_invoked = true
121
123
  isolate_errors do
122
124
  ensure_dependencies_installed
123
125
  build
@@ -132,7 +134,7 @@ def prepare
132
134
  def configure
133
135
  if File.exist?(builddir) && !File.directory?(builddir)
134
136
  raise ConfigException.new(self, 'configure'),
135
- "#{builddir} already exists but is not a directory"
137
+ "#{builddir} already exists but is not a directory"
136
138
  end
137
139
 
138
140
  FileUtils.mkdir_p builddir unless File.directory?(builddir)
@@ -1199,7 +1199,8 @@ def checkout(package, _options = Hash.new)
1199
1199
  repository, package.importdir, retry: true)
1200
1200
 
1201
1201
  update_remotes_configuration(package)
1202
- update(package, only_local: !remote_branch.start_with?("refs/"), reset: true)
1202
+ update(package, only_local: !remote_branch.start_with?("refs/"),
1203
+ reset: :force)
1203
1204
  run_git(package, "submodule", "update", '--init') if with_submodules?
1204
1205
  end
1205
1206
 
@@ -107,7 +107,11 @@ def self.cache_dirs(type)
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
@@ -663,6 +663,10 @@ def post_install(*args, &block)
663
663
  end
664
664
  end
665
665
 
666
+ def self_fingerprint
667
+ importer.fingerprint(self)
668
+ end
669
+
666
670
  # Returns a unique hash representing a state of the package and
667
671
  # its dependencies, if any dependency can't calculate its own
668
672
  # fingerprint the result will be nil
@@ -670,9 +674,13 @@ def post_install(*args, &block)
670
674
  def fingerprint(recursive: true, memo: {})
671
675
  return memo[name] if memo.key?(name)
672
676
 
673
- self_fingerprint = importer.fingerprint(self)
677
+ self_fingerprint = self.self_fingerprint
674
678
  return unless self_fingerprint
675
- return self_fingerprint if !recursive || dependencies.empty?
679
+ if dependencies.empty?
680
+ return (memo[name] = self_fingerprint)
681
+ elsif !recursive
682
+ return self_fingerprint
683
+ end
676
684
 
677
685
  dependency_fingerprints = dependencies.sort.map do |pkg_name|
678
686
  pkg = Autobuild::Package[pkg_name]
@@ -542,5 +542,11 @@ def delete_obsolete_files
542
542
  message "%s: removed #{counter} obsolete files from prefix (cmake)"
543
543
  end
544
544
  end
545
+
546
+ def self_fingerprint
547
+ return unless (base = super)
548
+ all_defines = self.class.defines.merge(self.defines).sort_by(&:first)
549
+ Digest::SHA1.hexdigest(base + all_defines.join(""))
550
+ end
545
551
  end
546
552
  end
@@ -83,8 +83,9 @@ class ProcessingState
83
83
  attr_reader :queue
84
84
  attr_reader :priorities
85
85
 
86
- def initialize(reverse_dependencies)
86
+ def initialize(reverse_dependencies, completion_callback: proc { })
87
87
  @reverse_dependencies = reverse_dependencies
88
+ @completion_callback = completion_callback
88
89
  @processed = Set.new
89
90
  @active_tasks = Set.new
90
91
  @priorities = Hash.new
@@ -143,6 +144,8 @@ def process_finished_task(task)
143
144
  push(candidate, priorities[task])
144
145
  end
145
146
  end
147
+
148
+ @completion_callback.call(task)
146
149
  end
147
150
 
148
151
  def trivial_task?(task)
@@ -153,7 +156,7 @@ def trivial_task?(task)
153
156
 
154
157
  # Invokes the provided tasks. Unlike the rake code, this is a toplevel
155
158
  # algorithm that does not use recursion
156
- def invoke_parallel(required_tasks)
159
+ def invoke_parallel(required_tasks, completion_callback: proc { })
157
160
  tasks = Set.new
158
161
  reverse_dependencies = Hash.new { |h, k| h[k] = Set.new }
159
162
  required_tasks.each do |t|
@@ -162,7 +165,8 @@ def invoke_parallel(required_tasks)
162
165
  # The queue is the set of tasks for which all prerequisites have
163
166
  # been successfully executed (or where not needed). I.e. it is the
164
167
  # set of tasks that can be queued for execution.
165
- state = ProcessingState.new(reverse_dependencies)
168
+ state = ProcessingState.new(reverse_dependencies,
169
+ completion_callback: completion_callback)
166
170
  tasks.each do |t|
167
171
  state.push(t) if state.ready?(t)
168
172
  end
@@ -9,16 +9,61 @@ def initialize(io, color: ::Autobuild.method(:color))
9
9
 
10
10
  @silent = false
11
11
  @color = color
12
- @progress_enabled = true
13
12
  @display_lock = Mutex.new
13
+
14
+ @next_progress_display = Time.at(0)
15
+ @progress_mode = :single_line
16
+ @progress_period = 0.1
17
+ end
18
+
19
+ # Set the minimum time between two progress messages
20
+ #
21
+ # @see period
22
+ def progress_period=(period)
23
+ @progress_period = Float(period)
14
24
  end
15
25
 
16
- attr_writer :silent
26
+ # Minimum time between two progress displays
27
+ #
28
+ # This does not affect normal messages
29
+ #
30
+ # @return [Float]
31
+ attr_reader :progress_period
32
+
33
+ # Valid progress modes
34
+ #
35
+ # @see progress_mode=
36
+ PROGRESS_MODES = %I[single_line newline off]
37
+
38
+ # Sets how progress messages will be displayed
39
+ #
40
+ # @param [String] the new mode. Can be either 'single_line', where a
41
+ # progress message replaces the last one, 'newline' which displays
42
+ # each on a new line or 'off' to disable progress messages altogether
43
+ def progress_mode=(mode)
44
+ mode = mode.to_sym
45
+ unless PROGRESS_MODES.include?(mode)
46
+ raise ArgumentError,
47
+ "#{mode} is not a valid mode, expected one of "\
48
+ "#{PROGRESS_MODES.join(", ")}"
49
+ end
50
+ @progress_mode = mode
51
+ end
52
+
53
+ # Return the current display mode
54
+ #
55
+ # @return [Symbol]
56
+ # @see mode=
57
+ attr_reader :progress_mode
17
58
 
18
59
  def silent?
19
60
  @silent
20
61
  end
21
62
 
63
+ def silent=(flag)
64
+ @silent = flag
65
+ end
66
+
22
67
  def silent
23
68
  silent = @silent
24
69
  @silent = true
@@ -27,10 +72,14 @@ def silent
27
72
  @silent = silent
28
73
  end
29
74
 
30
- attr_writer :progress_enabled
75
+ # @deprecated use progress_mode= instead
76
+ def progress_enabled=(flag)
77
+ self.progress_mode = flag ? :single_line : :off
78
+ end
31
79
 
80
+ # Whether progress messages will be displayed at all
32
81
  def progress_enabled?
33
- !@silent && @progress_enabled
82
+ !@silent && (@progress_mode != :off)
34
83
  end
35
84
 
36
85
  def message(message, *args, io: @io, force: false)
@@ -39,8 +88,11 @@ def message(message, *args, io: @io, force: false)
39
88
  io = args.pop if args.last.respond_to?(:to_io)
40
89
 
41
90
  @display_lock.synchronize do
42
- io.print "#{@cursor.column(1)}#{@cursor.clear_screen_down}"\
43
- "#{@color.call(message, *args)}\n"
91
+ if @progress_mode == :single_line
92
+ io.print @cursor.clear_screen_down
93
+ end
94
+ io.puts @color.call(message, *args)
95
+
44
96
  io.flush if @io != io
45
97
  display_progress
46
98
  @io.flush
@@ -54,7 +106,7 @@ def progress_start(key, *args, done_message: nil)
54
106
  @progress_messages << [key, formatted_message]
55
107
  if progress_enabled?
56
108
  @display_lock.synchronize do
57
- display_progress
109
+ display_progress(consider_period: false)
58
110
  end
59
111
  else
60
112
  message " #{formatted_message}"
@@ -113,32 +165,38 @@ def progress_done(key, display_last = true, message: nil)
113
165
  end
114
166
  end
115
167
 
116
- def display_progress
168
+ def display_progress(consider_period: true)
117
169
  return unless progress_enabled?
170
+ return if consider_period && (@next_progress_display > Time.now)
118
171
 
119
- formatted = format_grouped_messages(@progress_messages.map(&:last),
120
- indent: " ")
121
- @io.print @cursor.clear_screen_down
122
- @io.print formatted.join("\n")
123
- if formatted.size > 1
124
- @io.print "#{@cursor.up(formatted.size - 1)}#{@cursor.column(0)}"
172
+ formatted = format_grouped_messages(
173
+ @progress_messages.map(&:last),
174
+ indent: " "
175
+ )
176
+ if @progress_mode == :newline
177
+ @io.print formatted.join("\n")
178
+ @io.print "\n"
125
179
  else
180
+ @io.print @cursor.clear_screen_down
181
+ @io.print formatted.join("\n")
182
+ @io.print @cursor.up(formatted.size - 1) if formatted.size > 1
126
183
  @io.print @cursor.column(0)
127
184
  end
128
185
  @io.flush
186
+ @next_progress_display = Time.now + @progress_period
129
187
  end
130
188
 
131
189
  def find_common_prefix(msg, other_msg)
132
- msg = msg.split(" ")
133
- other_msg = other_msg.split(" ")
190
+ msg = msg.split(' ')
191
+ other_msg = other_msg.split(' ')
134
192
  msg.each_with_index do |token, idx|
135
193
  if other_msg[idx] != token
136
194
  prefix = msg[0..(idx - 1)].join(" ")
137
- prefix << " " unless prefix.empty?
195
+ prefix << ' ' unless prefix.empty?
138
196
  return prefix
139
197
  end
140
198
  end
141
- msg.join(" ")
199
+ msg.join(' ')
142
200
  end
143
201
 
144
202
  def group_messages(messages)
@@ -47,10 +47,19 @@ def self.progress_display_enabled?
47
47
  @display.progress_enabled?
48
48
  end
49
49
 
50
+ # @deprecated use {progress_display_mode=} instead
50
51
  def self.progress_display_enabled=(value)
51
52
  @display.progress_enabled = value
52
53
  end
53
54
 
55
+ def self.progress_display_mode=(value)
56
+ @display.progress_mode = value
57
+ end
58
+
59
+ def self.progress_display_period=(value)
60
+ @display.progress_period = value
61
+ end
62
+
54
63
  def self.message(*args, **options)
55
64
  @display.message(*args, **options)
56
65
  end
@@ -104,16 +104,18 @@ def task(&block)
104
104
  def call_task_block
105
105
  @invoked = true
106
106
 
107
- yield if block_given?
108
- @success = true
107
+ begin
108
+ yield if block_given?
109
+ @success = true
110
+ rescue StandardError => e
111
+ install if install_on_error? && !@installed && target_dir
112
+ raise
113
+ end
109
114
 
110
115
  # Allow the user to install manually in the task
111
116
  # block
112
117
  install if !@installed && target_dir
113
- rescue Interrupt
114
- raise
115
- rescue ::Exception => e
116
- install if install_on_error? && !@installed && target_dir
118
+ rescue StandardError => e
117
119
  @success = false
118
120
 
119
121
  if Autobuild.send("pass_#{name}_errors")
@@ -1,3 +1,3 @@
1
1
  module Autobuild
2
- VERSION = "1.19.0".freeze unless defined? Autobuild::VERSION
2
+ VERSION = "1.20.0".freeze unless defined? Autobuild::VERSION
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: autobuild
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.19.0
4
+ version: 1.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sylvain Joyeux
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-03 00:00:00.000000000 Z
11
+ date: 2020-02-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pastel
@@ -180,6 +180,20 @@ dependencies:
180
180
  - - ">="
181
181
  - !ruby/object:Gem::Version
182
182
  version: '0'
183
+ - !ruby/object:Gem::Dependency
184
+ name: timecop
185
+ requirement: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - ">="
188
+ - !ruby/object:Gem::Version
189
+ version: '0'
190
+ type: :development
191
+ prerelease: false
192
+ version_requirements: !ruby/object:Gem::Requirement
193
+ requirements:
194
+ - - ">="
195
+ - !ruby/object:Gem::Version
196
+ version: '0'
183
197
  description: Collection of classes to handle build systems (CMake, autotools, ...)
184
198
  and import mechanisms (tarballs, CVS, SVN, git, ...). It also offers a Rake integration
185
199
  to import and build such software packages. It is the backbone of the autoproj (http://rock-robotics.org/autoproj)