autobuild 1.6.5 → 1.7.0.rc1
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.
- data/Rakefile +2 -2
- data/lib/autobuild/configurable.rb +1 -1
- data/lib/autobuild/environment.rb +156 -23
- data/lib/autobuild/import/archive.rb +62 -3
- data/lib/autobuild/importer.rb +46 -17
- data/lib/autobuild/package.rb +69 -7
- data/lib/autobuild/packages/autotools.rb +10 -6
- data/lib/autobuild/packages/cmake.rb +28 -5
- data/lib/autobuild/packages/genom.rb +4 -4
- data/lib/autobuild/packages/import.rb +1 -1
- data/lib/autobuild/packages/orogen.rb +3 -3
- data/lib/autobuild/parallel.rb +79 -34
- data/lib/autobuild/reporting.rb +95 -18
- data/lib/autobuild/subcommand.rb +25 -2
- data/lib/autobuild/version.rb +1 -1
- data/test/test_reporting.rb +55 -0
- metadata +19 -17
data/lib/autobuild/package.rb
CHANGED
@@ -267,10 +267,23 @@ module Autobuild
|
|
267
267
|
task "#{name}-build" => installstamp
|
268
268
|
end
|
269
269
|
|
270
|
-
def process_formatting_string(msg)
|
271
|
-
|
272
|
-
|
273
|
-
|
270
|
+
def process_formatting_string(msg, *prefix_style)
|
271
|
+
prefix, suffix = [], []
|
272
|
+
msg.split(" ").each do |token|
|
273
|
+
if token =~ /%s/
|
274
|
+
suffix << token.gsub(/%s/, name)
|
275
|
+
elsif suffix.empty?
|
276
|
+
prefix << token
|
277
|
+
else suffix << token
|
278
|
+
end
|
279
|
+
end
|
280
|
+
if suffix.empty?
|
281
|
+
return msg
|
282
|
+
elsif prefix_style.empty?
|
283
|
+
return (prefix + suffix).join(" ")
|
284
|
+
else
|
285
|
+
return [Autobuild.color(prefix.join(" "), *prefix_style), *suffix].join(" ")
|
286
|
+
end
|
274
287
|
end
|
275
288
|
|
276
289
|
# Display a progress message. %s in the string is replaced by the
|
@@ -295,7 +308,7 @@ module Autobuild
|
|
295
308
|
end
|
296
309
|
|
297
310
|
def progress_start(*args, &block)
|
298
|
-
args[0] = process_formatting_string(args[0])
|
311
|
+
args[0] = process_formatting_string(args[0], :bold)
|
299
312
|
if args.last.kind_of?(Hash)
|
300
313
|
options, raw_options = Kernel.filter_options args.last, :done_message
|
301
314
|
if options[:done_message]
|
@@ -308,11 +321,14 @@ module Autobuild
|
|
308
321
|
end
|
309
322
|
|
310
323
|
def progress(*args)
|
311
|
-
args[0] = process_formatting_string(args[0])
|
324
|
+
args[0] = process_formatting_string(args[0], :bold)
|
312
325
|
Autobuild.progress(self, *args)
|
313
326
|
end
|
314
327
|
|
315
|
-
def progress_done
|
328
|
+
def progress_done(done_message = nil)
|
329
|
+
if done_message
|
330
|
+
progress(process_formatting_string(done_message))
|
331
|
+
end
|
316
332
|
Autobuild.progress_done(self)
|
317
333
|
end
|
318
334
|
|
@@ -363,6 +379,33 @@ module Autobuild
|
|
363
379
|
end
|
364
380
|
end
|
365
381
|
|
382
|
+
module TaskExtension
|
383
|
+
attr_accessor :package
|
384
|
+
end
|
385
|
+
|
386
|
+
def source_tree(*args, &block)
|
387
|
+
task = Autobuild.source_tree(*args, &block)
|
388
|
+
task.extend TaskExtension
|
389
|
+
task.package = self
|
390
|
+
task
|
391
|
+
end
|
392
|
+
|
393
|
+
# Calls Rake to define a file task and then extends it with TaskExtension
|
394
|
+
def file(*args, &block)
|
395
|
+
task = super
|
396
|
+
task.extend TaskExtension
|
397
|
+
task.package = self
|
398
|
+
task
|
399
|
+
end
|
400
|
+
|
401
|
+
# Calls Rake to define a plain task and then extends it with TaskExtension
|
402
|
+
def task(*args, &block)
|
403
|
+
task = super
|
404
|
+
task.extend TaskExtension
|
405
|
+
task.package = self
|
406
|
+
task
|
407
|
+
end
|
408
|
+
|
366
409
|
# Defines a documentation generation task. The documentation is first
|
367
410
|
# generated by the given block, and then installed. The local attribute
|
368
411
|
# #doc_dir defines where the documentation is generated by the
|
@@ -594,6 +637,25 @@ module Autobuild
|
|
594
637
|
ensure
|
595
638
|
@in_dir_stack.pop
|
596
639
|
end
|
640
|
+
|
641
|
+
def disabled?
|
642
|
+
@disabled
|
643
|
+
end
|
644
|
+
|
645
|
+
# Make sure that this package will be ignored in the build
|
646
|
+
def disable
|
647
|
+
@disabled = true
|
648
|
+
%w{import prepare build doc}.each do |phase|
|
649
|
+
task "#{name}-#{phase}"
|
650
|
+
t = Rake::Task["#{name}-#{phase}"]
|
651
|
+
def t.needed?; false end
|
652
|
+
t.instance_variable_set :@already_invoked, true
|
653
|
+
end
|
654
|
+
task(installstamp)
|
655
|
+
t = Rake::Task[installstamp]
|
656
|
+
def t.needed?; false end
|
657
|
+
t.instance_variable_set :@already_invoked, true
|
658
|
+
end
|
597
659
|
end
|
598
660
|
|
599
661
|
def self.package_set(spec)
|
@@ -11,6 +11,10 @@ module Autobuild
|
|
11
11
|
Autotools.new(opts, &proc)
|
12
12
|
end
|
13
13
|
|
14
|
+
if Autobuild.macos?
|
15
|
+
Autobuild.programs['libtoolize'] = "glibtoolize"
|
16
|
+
end
|
17
|
+
|
14
18
|
#
|
15
19
|
# ==== Handles autotools-based packages
|
16
20
|
#
|
@@ -32,7 +36,7 @@ module Autobuild
|
|
32
36
|
def initialize(options)
|
33
37
|
@using = Hash.new
|
34
38
|
@configureflags = []
|
35
|
-
|
39
|
+
|
36
40
|
super
|
37
41
|
end
|
38
42
|
|
@@ -40,7 +44,7 @@ module Autobuild
|
|
40
44
|
def with_doc(target = 'doc')
|
41
45
|
task "#{name}-doc" => configurestamp
|
42
46
|
doc_task do
|
43
|
-
progress_start "generating documentation for %s" do
|
47
|
+
progress_start "generating documentation for %s", :done_message => 'generated_documentation for %s' do
|
44
48
|
Subprocess.run(self, 'doc', Autobuild.tool(:make), "-j#{parallel_build_level}", target, :working_directory => builddir)
|
45
49
|
end
|
46
50
|
yield if block_given?
|
@@ -220,7 +224,7 @@ module Autobuild
|
|
220
224
|
|
221
225
|
autodetect_needed_stages
|
222
226
|
|
223
|
-
progress_start "generating
|
227
|
+
progress_start "generating autotools for %s", :done_message => 'generated autotools for %s' do
|
224
228
|
if using[:libtool]
|
225
229
|
Subprocess.run(self, 'configure', Autobuild.tool('libtoolize'), '--copy')
|
226
230
|
end
|
@@ -257,7 +261,7 @@ module Autobuild
|
|
257
261
|
command << "--prefix=#{prefix}"
|
258
262
|
command += Array[*configureflags]
|
259
263
|
|
260
|
-
progress_start "configuring
|
264
|
+
progress_start "configuring autotools for %s", :done_message => 'configured autotools for %s' do
|
261
265
|
Subprocess.run(self, 'configure', *command)
|
262
266
|
end
|
263
267
|
end
|
@@ -267,7 +271,7 @@ module Autobuild
|
|
267
271
|
# Do the build in builddir
|
268
272
|
def build
|
269
273
|
in_dir(builddir) do
|
270
|
-
progress_start "building %s [progress not available]" do
|
274
|
+
progress_start "building %s [progress not available]", :done_message => 'built %s' do
|
271
275
|
if force_config_status
|
272
276
|
Subprocess.run(self, 'build', './config.status')
|
273
277
|
end
|
@@ -280,7 +284,7 @@ module Autobuild
|
|
280
284
|
# Install the result in prefix
|
281
285
|
def install
|
282
286
|
in_dir(builddir) do
|
283
|
-
progress_start "installing %s" do
|
287
|
+
progress_start "installing %s", :done_message => 'installed %s' do
|
284
288
|
Subprocess.run(self, 'install', Autobuild.tool(:make), 'install')
|
285
289
|
end
|
286
290
|
end
|
@@ -203,7 +203,7 @@ module Autobuild
|
|
203
203
|
def with_doc(target = 'doc')
|
204
204
|
doc_task do
|
205
205
|
in_dir(builddir) do
|
206
|
-
progress_start "generating documentation for %s" do
|
206
|
+
progress_start "generating documentation for %s", :done_message => 'generated documentation for %s' do
|
207
207
|
if internal_doxygen_mode?
|
208
208
|
run_doxygen
|
209
209
|
else
|
@@ -303,6 +303,11 @@ module Autobuild
|
|
303
303
|
|
304
304
|
command = [ "cmake", "-DCMAKE_INSTALL_PREFIX=#{prefix}", "-DCMAKE_MODULE_PATH=#{CMake.module_path.join(";")}" ]
|
305
305
|
|
306
|
+
if(RbConfig::CONFIG["host_os"] =~%r!(msdos|mswin|djgpp|mingw|[Ww]indows)!)
|
307
|
+
command << '-G'
|
308
|
+
command << "MSYS Makefiles"
|
309
|
+
end
|
310
|
+
|
306
311
|
defines.each do |name, value|
|
307
312
|
command << "-D#{name}=#{value}"
|
308
313
|
end
|
@@ -311,7 +316,7 @@ module Autobuild
|
|
311
316
|
end
|
312
317
|
command << srcdir
|
313
318
|
|
314
|
-
progress_start "configuring CMake
|
319
|
+
progress_start "configuring CMake for %s", :done_message => "configured CMake for %s" do
|
315
320
|
if full_reconfigures?
|
316
321
|
FileUtils.rm_f cmake_cache
|
317
322
|
end
|
@@ -324,14 +329,32 @@ module Autobuild
|
|
324
329
|
# Do the build in builddir
|
325
330
|
def build
|
326
331
|
in_dir(builddir) do
|
327
|
-
progress_start "building %s", :done_message => "
|
332
|
+
progress_start "building %s", :done_message => "built %s" do
|
328
333
|
if always_reconfigure || !File.file?('Makefile')
|
329
334
|
Subprocess.run(self, 'build', Autobuild.tool(:cmake), '.')
|
330
335
|
end
|
331
336
|
|
332
337
|
Autobuild.make_subcommand(self, 'build') do |line|
|
333
338
|
if line =~ /\[\s+(\d+)%\]/
|
334
|
-
progress "building %s (#{Integer($1)}
|
339
|
+
progress "building %s (#{Integer($1)}%)"
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
warning = String.new
|
344
|
+
Autobuild.make_subcommand(self, 'build') do |line|
|
345
|
+
iswarning = false
|
346
|
+
if line =~ /\[\s*(\d+)%\]/
|
347
|
+
progress "building %s (#{Integer($1)}%)"
|
348
|
+
elsif (line =~
|
349
|
+
/^(Linking)|^(Scanning)|^(Building)|^(Built)/) == nil
|
350
|
+
warning += line
|
351
|
+
iswarning = true
|
352
|
+
end
|
353
|
+
if(!iswarning && !warning.empty?)
|
354
|
+
warning.split("\n").each do |l|
|
355
|
+
message "%s: #{l}", :magenta
|
356
|
+
end
|
357
|
+
warning = ""
|
335
358
|
end
|
336
359
|
end
|
337
360
|
end
|
@@ -342,7 +365,7 @@ module Autobuild
|
|
342
365
|
# Install the result in prefix
|
343
366
|
def install
|
344
367
|
in_dir(builddir) do
|
345
|
-
progress_start "installing %s" do
|
368
|
+
progress_start "installing %s", :done_message => 'installed %s' do
|
346
369
|
Subprocess.run(self, 'install', Autobuild.tool(:make), "-j#{parallel_build_level}", 'install')
|
347
370
|
end
|
348
371
|
end
|
@@ -100,10 +100,10 @@ module Autobuild
|
|
100
100
|
genom_pkg = PkgConfig.new('genom')
|
101
101
|
|
102
102
|
includedir = File.join(genom_pkg.includedir, 'genom')
|
103
|
-
|
103
|
+
source_tree includedir
|
104
104
|
|
105
105
|
canvasdir = File.join(genom_pkg.prefix, "share", "genom", genom_pkg.version);;
|
106
|
-
|
106
|
+
source_tree canvasdir
|
107
107
|
|
108
108
|
binary = File.join(genom_pkg.exec_prefix, "bin", "genom")
|
109
109
|
file binary
|
@@ -133,7 +133,7 @@ module Autobuild
|
|
133
133
|
file genomstamp => srcdir do
|
134
134
|
isolate_errors do
|
135
135
|
in_dir(srcdir) do
|
136
|
-
progress_start "generating GenoM
|
136
|
+
progress_start "generating GenoM for %s", :done_message => 'generated GenoM for %s' do
|
137
137
|
Subprocess.run(self, 'genom', *cmdline)
|
138
138
|
end
|
139
139
|
end
|
@@ -146,7 +146,7 @@ module Autobuild
|
|
146
146
|
# configure does not depend on the .gen file
|
147
147
|
# since the generation takes care of rebuilding configure
|
148
148
|
# if .gen has changed
|
149
|
-
progress_start "generating
|
149
|
+
progress_start "generating autotools for %s", :done_message => 'generated autotools for %s' do
|
150
150
|
in_dir(srcdir) { Subprocess.run(self, 'genom', File.expand_path('autogen', srcdir)) }
|
151
151
|
end
|
152
152
|
end
|
@@ -206,7 +206,7 @@ module Autobuild
|
|
206
206
|
# Find out where orogen is, and make sure the configurestamp depend
|
207
207
|
# on it. Ignore if orogen is too old to have a --base-dir option
|
208
208
|
if orogen_root = self.class.orogen_root
|
209
|
-
orogen_tree =
|
209
|
+
orogen_tree = source_tree(orogen_root)
|
210
210
|
end
|
211
211
|
|
212
212
|
# Check if there is an orogen package registered. If it is the case,
|
@@ -222,7 +222,7 @@ module Autobuild
|
|
222
222
|
# Cache the orogen file name
|
223
223
|
@orogen_file ||= self.orogen_file
|
224
224
|
|
225
|
-
file genstamp =>
|
225
|
+
file genstamp => source_tree(srcdir) do
|
226
226
|
needs_regen = true
|
227
227
|
if File.file?(genstamp)
|
228
228
|
genstamp_mtime = File.stat(genstamp).mtime
|
@@ -333,7 +333,7 @@ module Autobuild
|
|
333
333
|
needs_regen ||= (Rake::Task[Orogen.orogen_root].timestamp > Rake::Task[genstamp].timestamp)
|
334
334
|
|
335
335
|
if needs_regen
|
336
|
-
progress_start "generating oroGen
|
336
|
+
progress_start "generating oroGen %s", :done_message => 'generated oroGen %s' do
|
337
337
|
in_dir(srcdir) do
|
338
338
|
Subprocess.run self, 'orogen', guess_ruby_name, self.class.orogen_bin, *cmdline
|
339
339
|
File.open(genstamp, 'w') do |io|
|
data/lib/autobuild/parallel.rb
CHANGED
@@ -12,10 +12,6 @@ module Autobuild
|
|
12
12
|
|
13
13
|
attr_reader :job_server
|
14
14
|
|
15
|
-
attr_reader :roots
|
16
|
-
attr_reader :tasks
|
17
|
-
attr_reader :reverse_dependencies
|
18
|
-
|
19
15
|
class JobServer
|
20
16
|
attr_reader :rio
|
21
17
|
attr_reader :wio
|
@@ -40,49 +36,97 @@ module Autobuild
|
|
40
36
|
|
41
37
|
end
|
42
38
|
|
43
|
-
def
|
44
|
-
processed << task
|
45
|
-
reverse_dependencies[task].each do |candidate|
|
46
|
-
if candidate.prerequisite_tasks.all? { |t| processed.include?(t) }
|
47
|
-
queue << candidate
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def wait_for_worker_to_end(processed, queue)
|
39
|
+
def wait_for_worker_to_end(state)
|
53
40
|
w = finished_workers.pop
|
54
41
|
finished_task, error = w.last_result
|
55
42
|
available_workers << w
|
56
43
|
if error
|
57
44
|
if available_workers.size != workers.size
|
58
|
-
Autobuild.
|
45
|
+
Autobuild.error "got an error doing parallel processing, waiting for pending jobs to end"
|
59
46
|
end
|
60
47
|
finish_pending_work
|
61
48
|
raise error
|
62
49
|
end
|
63
50
|
|
64
|
-
process_finished_task(finished_task
|
51
|
+
state.process_finished_task(finished_task)
|
65
52
|
end
|
66
53
|
|
67
|
-
def discover_dependencies(t)
|
68
|
-
return if
|
69
|
-
|
54
|
+
def discover_dependencies(all_tasks, reverse_dependencies, t)
|
55
|
+
return if all_tasks.include?(t) # already discovered or being discovered
|
56
|
+
all_tasks << t
|
70
57
|
|
71
58
|
t.prerequisite_tasks.each do |dep_t|
|
72
59
|
reverse_dependencies[dep_t] << t
|
73
|
-
discover_dependencies(dep_t)
|
60
|
+
discover_dependencies(all_tasks, reverse_dependencies, dep_t)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class ProcessingState
|
65
|
+
attr_reader :reverse_dependencies
|
66
|
+
attr_reader :processed
|
67
|
+
attr_reader :started_packages
|
68
|
+
attr_reader :active_packages
|
69
|
+
attr_reader :queue
|
70
|
+
|
71
|
+
def initialize(reverse_dependencies, initial_queue = Array.new)
|
72
|
+
@reverse_dependencies = reverse_dependencies
|
73
|
+
@processed = Set.new
|
74
|
+
@active_packages = Set.new
|
75
|
+
@started_packages = Set.new
|
76
|
+
@queue = initial_queue.to_set
|
77
|
+
end
|
78
|
+
|
79
|
+
def find_task
|
80
|
+
possible_task = nil
|
81
|
+
queue.each do |task|
|
82
|
+
if task.respond_to?(:package)
|
83
|
+
if !active_packages.include?(task.package)
|
84
|
+
if started_packages.include?(task.package)
|
85
|
+
return task
|
86
|
+
end
|
87
|
+
possible_task ||= task
|
88
|
+
end
|
89
|
+
else possible_task ||= task
|
90
|
+
end
|
91
|
+
end
|
92
|
+
possible_task
|
93
|
+
end
|
94
|
+
|
95
|
+
def pop
|
96
|
+
candidate = find_task
|
97
|
+
queue.delete(candidate)
|
98
|
+
candidate
|
99
|
+
end
|
100
|
+
|
101
|
+
def mark_as_active(pending_task)
|
102
|
+
if pending_task.respond_to?(:package)
|
103
|
+
active_packages << pending_task.package
|
104
|
+
started_packages << pending_task.package
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def process_finished_task(task)
|
109
|
+
if task.respond_to?(:package)
|
110
|
+
active_packages.delete(task.package)
|
111
|
+
end
|
112
|
+
processed << task
|
113
|
+
reverse_dependencies[task].each do |candidate|
|
114
|
+
if candidate.prerequisite_tasks.all? { |t| processed.include?(t) }
|
115
|
+
queue << candidate
|
116
|
+
end
|
117
|
+
end
|
74
118
|
end
|
75
119
|
end
|
76
120
|
|
77
121
|
# Invokes the provided tasks. Unlike the rake code, this is a toplevel
|
78
122
|
# algorithm that does not use recursion
|
79
123
|
def invoke_parallel(required_tasks)
|
80
|
-
|
81
|
-
|
124
|
+
tasks = Set.new
|
125
|
+
reverse_dependencies = Hash.new { |h, k| h[k] = Set.new }
|
82
126
|
required_tasks.each do |t|
|
83
|
-
discover_dependencies(t)
|
127
|
+
discover_dependencies(tasks, reverse_dependencies, t)
|
84
128
|
end
|
85
|
-
|
129
|
+
roots = tasks.find_all { |t| t.prerequisite_tasks.empty? }.to_set
|
86
130
|
|
87
131
|
# Build a reverse dependency graph (i.e. a mapping from a task to
|
88
132
|
# the tasks that depend on it)
|
@@ -94,25 +138,25 @@ module Autobuild
|
|
94
138
|
# The queue is the set of tasks for which all prerequisites have
|
95
139
|
# been successfully executed (or where not needed). I.e. it is the
|
96
140
|
# set of tasks that can be queued for execution.
|
97
|
-
|
98
|
-
processed = Set.new
|
141
|
+
state = ProcessingState.new(reverse_dependencies, roots.to_a)
|
99
142
|
while true
|
100
|
-
|
143
|
+
pending_task = state.pop
|
144
|
+
if !pending_task
|
101
145
|
# If we have pending workers, wait for one to be finished
|
102
146
|
# until either they are all finished or the queue is not
|
103
147
|
# empty anymore
|
104
|
-
while
|
105
|
-
wait_for_worker_to_end(
|
148
|
+
while !pending_task && available_workers.size != workers.size
|
149
|
+
wait_for_worker_to_end(state)
|
150
|
+
pending_task = state.pop
|
106
151
|
end
|
107
152
|
|
108
|
-
if
|
153
|
+
if !pending_task && available_workers.size == workers.size
|
109
154
|
break
|
110
155
|
end
|
111
156
|
end
|
112
157
|
|
113
|
-
pending_task = queue.pop
|
114
158
|
if pending_task.instance_variable_get(:@already_invoked) || !pending_task.needed?
|
115
|
-
process_finished_task(pending_task
|
159
|
+
state.process_finished_task(pending_task)
|
116
160
|
next
|
117
161
|
end
|
118
162
|
|
@@ -120,7 +164,7 @@ module Autobuild
|
|
120
164
|
job_server.get
|
121
165
|
|
122
166
|
while !finished_workers.empty?
|
123
|
-
wait_for_worker_to_end(
|
167
|
+
wait_for_worker_to_end(state)
|
124
168
|
end
|
125
169
|
|
126
170
|
# We do have a job server token, so we are allowed to allocate a
|
@@ -132,10 +176,11 @@ module Autobuild
|
|
132
176
|
end
|
133
177
|
|
134
178
|
worker = available_workers.pop
|
179
|
+
state.mark_as_active(pending_task)
|
135
180
|
worker.queue(pending_task)
|
136
181
|
end
|
137
182
|
|
138
|
-
if processed.size != tasks.size
|
183
|
+
if state.processed.size != tasks.size
|
139
184
|
with_cycle = tasks.to_set
|
140
185
|
raise "cycle in task graph: #{with_cycle.map(&:name).sort.join(", ")}"
|
141
186
|
end
|