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