autobuild 1.17.0 → 1.18.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +107 -0
- data/Gemfile +2 -1
- data/Rakefile +1 -4
- data/autobuild.gemspec +14 -11
- data/bin/autobuild +4 -3
- data/lib/autobuild.rb +4 -5
- data/lib/autobuild/build_logfile.rb +6 -4
- data/lib/autobuild/config.rb +90 -40
- data/lib/autobuild/configurable.rb +30 -18
- data/lib/autobuild/environment.rb +126 -120
- data/lib/autobuild/exceptions.rb +48 -31
- data/lib/autobuild/import/archive.rb +134 -82
- data/lib/autobuild/import/cvs.rb +28 -24
- data/lib/autobuild/import/darcs.rb +13 -16
- data/lib/autobuild/import/git-lfs.rb +37 -30
- data/lib/autobuild/import/git.rb +231 -179
- data/lib/autobuild/import/hg.rb +23 -18
- data/lib/autobuild/import/svn.rb +48 -29
- data/lib/autobuild/importer.rb +530 -499
- data/lib/autobuild/mail_reporter.rb +77 -77
- data/lib/autobuild/package.rb +171 -101
- data/lib/autobuild/packages/autotools.rb +47 -42
- data/lib/autobuild/packages/cmake.rb +71 -65
- data/lib/autobuild/packages/dummy.rb +9 -8
- data/lib/autobuild/packages/genom.rb +1 -1
- data/lib/autobuild/packages/gnumake.rb +19 -13
- data/lib/autobuild/packages/import.rb +2 -6
- data/lib/autobuild/packages/orogen.rb +32 -31
- data/lib/autobuild/packages/pkgconfig.rb +2 -2
- data/lib/autobuild/packages/python.rb +7 -2
- data/lib/autobuild/packages/ruby.rb +22 -17
- data/lib/autobuild/parallel.rb +35 -39
- data/lib/autobuild/pkgconfig.rb +25 -13
- data/lib/autobuild/progress_display.rb +23 -23
- data/lib/autobuild/rake_task_extension.rb +6 -6
- data/lib/autobuild/reporting.rb +38 -26
- data/lib/autobuild/subcommand.rb +72 -65
- data/lib/autobuild/test.rb +8 -7
- data/lib/autobuild/test_utility.rb +10 -9
- data/lib/autobuild/timestamps.rb +28 -23
- data/lib/autobuild/tools.rb +17 -16
- data/lib/autobuild/utility.rb +16 -18
- data/lib/autobuild/version.rb +1 -1
- metadata +39 -38
@@ -7,27 +7,28 @@ class DummyPackage < Package
|
|
7
7
|
def installstamp
|
8
8
|
"#{srcdir}/#{STAMPFILE}"
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
def initialize(*args)
|
12
12
|
super
|
13
13
|
end
|
14
14
|
|
15
|
-
def import(options = Hash.new)
|
16
|
-
end
|
15
|
+
def import(options = Hash.new); end
|
17
16
|
|
18
17
|
def prepare
|
19
|
-
%w
|
18
|
+
%w[import prepare build doc].each do |phase|
|
20
19
|
task "#{name}-#{phase}"
|
21
20
|
t = Rake::Task["#{name}-#{phase}"]
|
22
|
-
def t.needed
|
21
|
+
def t.needed?
|
22
|
+
false
|
23
|
+
end
|
23
24
|
end
|
24
25
|
task(installstamp)
|
25
26
|
t = Rake::Task[installstamp]
|
26
|
-
def t.needed
|
27
|
+
def t.needed?
|
28
|
+
false
|
29
|
+
end
|
27
30
|
|
28
31
|
super
|
29
32
|
end
|
30
33
|
end
|
31
34
|
end
|
32
|
-
|
33
|
-
|
@@ -74,7 +74,7 @@ def get_requires
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
-
# Alias this package to the ones defined in the EXTRA_PKGCONFIG
|
77
|
+
# Alias this package to the ones defined in the EXTRA_PKGCONFIG
|
78
78
|
# flag in configure.ac.user
|
79
79
|
def get_provides
|
80
80
|
configure_ac_user = File.join(srcdir, 'configure.ac.user')
|
@@ -4,13 +4,13 @@ module Autobuild
|
|
4
4
|
def self.make_is_gnumake?(pkg, path = Autobuild.tool(:make))
|
5
5
|
@make_is_gnumake ||= Hash.new
|
6
6
|
@gnumake_version ||= Hash.new
|
7
|
-
if @make_is_gnumake.
|
7
|
+
if @make_is_gnumake.key?(path)
|
8
8
|
@make_is_gnumake[path]
|
9
9
|
else
|
10
10
|
begin
|
11
11
|
result = pkg.run('prepare', path, '--version')
|
12
12
|
@make_is_gnumake[path] = (result.first =~ /GNU Make/)
|
13
|
-
@gnumake_version[path] = result.first.scan(/[\d.]+/)[0]
|
13
|
+
@gnumake_version[path] = Gem::Version.new(result.first.scan(/[\d.]+/)[0])
|
14
14
|
rescue Autobuild::SubcommandFailed
|
15
15
|
@make_is_gnumake[path] = false
|
16
16
|
end
|
@@ -28,31 +28,37 @@ def self.make_has_gnumake_jobserver?(pkg, path = Autobuild.tool(:make))
|
|
28
28
|
def self.invoke_make_parallel(pkg, cmd_path = Autobuild.tool(:make))
|
29
29
|
reserved = nil
|
30
30
|
if make_has_j_option?(pkg, cmd_path) && pkg.parallel_build_level != 1
|
31
|
-
if manager = Autobuild.parallel_task_manager
|
31
|
+
if (manager = Autobuild.parallel_task_manager)
|
32
32
|
job_server = manager.job_server
|
33
|
-
|
33
|
+
|
34
|
+
specific_parallel_level = (pkg.parallel_build_level !=
|
35
|
+
Autobuild.parallel_build_level)
|
36
|
+
if !make_has_gnumake_jobserver?(pkg, cmd_path) || specific_parallel_level
|
34
37
|
reserved = pkg.parallel_build_level
|
35
|
-
|
38
|
+
# Account for the one token autobuild uses
|
39
|
+
job_server.get(reserved - 1)
|
36
40
|
yield("-j#{pkg.parallel_build_level}")
|
37
41
|
end
|
38
|
-
|
39
|
-
|
42
|
+
|
43
|
+
jobserver_fds_arg = "#{job_server.rio.fileno},#{job_server.wio.fileno}"
|
44
|
+
|
45
|
+
if @gnumake_version[cmd_path] >= Gem::Version.new("4.2.0")
|
46
|
+
yield("--jobserver-auth=#{jobserver_fds_arg}", "-j")
|
40
47
|
else
|
41
|
-
yield("--jobserver-fds=#{
|
48
|
+
yield("--jobserver-fds=#{jobserver_fds_arg}", "-j")
|
42
49
|
end
|
43
50
|
end
|
44
51
|
yield("-j#{pkg.parallel_build_level}")
|
45
52
|
else yield
|
46
53
|
end
|
47
54
|
ensure
|
48
|
-
if reserved
|
49
|
-
job_server.put(reserved)
|
50
|
-
end
|
55
|
+
job_server.put(reserved) if reserved
|
51
56
|
end
|
52
|
-
|
57
|
+
|
53
58
|
def self.make_subcommand(pkg, phase, *options, &block)
|
54
59
|
invoke_make_parallel(pkg, Autobuild.tool(:make)) do |*make_parallel_options|
|
55
|
-
pkg.run(phase, Autobuild.tool(:make),
|
60
|
+
pkg.run(phase, Autobuild.tool(:make),
|
61
|
+
*make_parallel_options, *options, &block)
|
56
62
|
end
|
57
63
|
end
|
58
64
|
end
|
@@ -5,7 +5,7 @@ module Autobuild
|
|
5
5
|
def self.import(spec, &proc)
|
6
6
|
ImporterPackage.new(spec, &proc)
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
class ImporterPackage < Package
|
10
10
|
attr_reader :exclude
|
11
11
|
|
@@ -19,9 +19,7 @@ def prepare
|
|
19
19
|
|
20
20
|
exclude = self.exclude.dup
|
21
21
|
exclude << Regexp.new("^#{Regexp.quote(installstamp)}")
|
22
|
-
if doc_dir
|
23
|
-
exclude << Regexp.new("^#{Regexp.quote(doc_dir)}")
|
24
|
-
end
|
22
|
+
exclude << Regexp.new("^#{Regexp.quote(doc_dir)}") if doc_dir
|
25
23
|
|
26
24
|
source_tree(srcdir) do |pkg|
|
27
25
|
pkg.exclude.concat exclude
|
@@ -32,5 +30,3 @@ def prepare
|
|
32
30
|
end
|
33
31
|
end
|
34
32
|
end
|
35
|
-
|
36
|
-
|
@@ -41,7 +41,7 @@ class << self
|
|
41
41
|
# This is still considered experimental. Use
|
42
42
|
# Orogen.always_regenerate= to set it
|
43
43
|
def always_regenerate?
|
44
|
-
|
44
|
+
@always_regenerate
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
@@ -63,14 +63,15 @@ def self.orocos_target
|
|
63
63
|
|
64
64
|
class << self
|
65
65
|
attr_accessor :default_type_export_policy
|
66
|
-
# The list of enabled transports as an array of strings (default:
|
66
|
+
# The list of enabled transports as an array of strings (default:
|
67
|
+
# typelib, corba)
|
67
68
|
attr_reader :transports
|
68
69
|
|
69
70
|
attr_reader :orogen_options
|
70
71
|
end
|
71
72
|
@orogen_options = []
|
72
73
|
@default_type_export_policy = :used
|
73
|
-
@transports = %w
|
74
|
+
@transports = %w[corba typelib mqueue]
|
74
75
|
@rtt_scripting = true
|
75
76
|
|
76
77
|
attr_reader :orogen_options
|
@@ -121,12 +122,13 @@ def orogen_file
|
|
121
122
|
if @orogen_file
|
122
123
|
@orogen_file
|
123
124
|
else
|
124
|
-
return
|
125
|
-
|
125
|
+
return unless File.directory?(srcdir)
|
126
|
+
|
126
127
|
Dir.glob(File.join(srcdir, '*.orogen')) do |path|
|
127
128
|
return File.basename(path)
|
128
129
|
end
|
129
|
-
raise ArgumentError,
|
130
|
+
raise ArgumentError,
|
131
|
+
"cannot find an oroGen specification file in #{srcdir}"
|
130
132
|
end
|
131
133
|
end
|
132
134
|
|
@@ -141,7 +143,7 @@ def initialize(*args, &config)
|
|
141
143
|
|
142
144
|
def prepare_for_forced_build
|
143
145
|
super
|
144
|
-
FileUtils.rm_f genstamp
|
146
|
+
FileUtils.rm_f genstamp
|
145
147
|
end
|
146
148
|
|
147
149
|
def update_environment
|
@@ -158,9 +160,7 @@ def orogen_version
|
|
158
160
|
if !@orogen_version && (root = orogen_root)
|
159
161
|
version_file = File.join(root, 'lib', 'orogen', 'version.rb')
|
160
162
|
version_line = File.readlines(version_file).grep(/VERSION\s*=\s*"/).first
|
161
|
-
if version_line =~ /.*=\s+"(.+)"$/
|
162
|
-
@orogen_version = $1
|
163
|
-
end
|
163
|
+
@orogen_version = $1 if version_line =~ /.*=\s+"(.+)"$/
|
164
164
|
end
|
165
165
|
@orogen_version
|
166
166
|
end
|
@@ -168,9 +168,7 @@ def orogen_version
|
|
168
168
|
def orogen_root
|
169
169
|
if orogen_tool_path
|
170
170
|
root = File.expand_path(File.join('..', '..'), orogen_tool_path)
|
171
|
-
if File.directory?(File.join(root, 'lib', 'orogen'))
|
172
|
-
root
|
173
|
-
end
|
171
|
+
root if File.directory?(File.join(root, 'lib', 'orogen'))
|
174
172
|
end
|
175
173
|
end
|
176
174
|
|
@@ -187,7 +185,9 @@ def prepare
|
|
187
185
|
super
|
188
186
|
end
|
189
187
|
|
190
|
-
def genstamp
|
188
|
+
def genstamp
|
189
|
+
File.join(srcdir, '.orogen', 'orogen-stamp')
|
190
|
+
end
|
191
191
|
|
192
192
|
def add_cmd_to_cmdline(cmd, cmdline)
|
193
193
|
if cmd =~ /^([\w-]+)$/
|
@@ -210,31 +210,30 @@ def regen
|
|
210
210
|
cmdline << '--corba' if corba
|
211
211
|
|
212
212
|
ext_states = extended_states
|
213
|
-
|
213
|
+
unless ext_states.nil?
|
214
214
|
cmdline.delete_if { |str| str =~ /extended-states/ }
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
215
|
+
cmdline <<
|
216
|
+
if ext_states
|
217
|
+
'--extended-states'
|
218
|
+
else
|
219
|
+
'--no-extended-states'
|
220
|
+
end
|
220
221
|
end
|
221
222
|
|
222
|
-
@orogen_tool_path = find_in_path
|
223
|
-
if !orogen_tool_path
|
223
|
+
unless (@orogen_tool_path = find_in_path('orogen'))
|
224
224
|
raise ArgumentError, "cannot find 'orogen' in #{resolved_env['PATH']}"
|
225
225
|
end
|
226
226
|
|
227
|
-
version = orogen_version
|
228
|
-
if !version
|
227
|
+
unless (version = orogen_version)
|
229
228
|
raise ArgumentError, "cannot determine the orogen version"
|
230
229
|
end
|
231
230
|
|
232
|
-
if
|
231
|
+
if version >= "1.0" # rubocop:disable Style/IfUnlessModifier
|
233
232
|
cmdline << "--parallel-build=#{parallel_build_level}"
|
234
233
|
end
|
235
|
-
if
|
234
|
+
if version >= "1.1"
|
236
235
|
cmdline << "--type-export-policy=#{Orogen.default_type_export_policy}"
|
237
|
-
cmdline << "--transports=#{Orogen.transports.sort.uniq.join(
|
236
|
+
cmdline << "--transports=#{Orogen.transports.sort.uniq.join(',')}"
|
238
237
|
end
|
239
238
|
|
240
239
|
# Now, add raw options
|
@@ -269,9 +268,11 @@ def regen
|
|
269
268
|
needs_regen ||= !generation_uptodate?
|
270
269
|
|
271
270
|
if needs_regen
|
272
|
-
progress_start "generating oroGen %s",
|
271
|
+
progress_start "generating oroGen %s",
|
272
|
+
done_message: 'generated oroGen %s' do
|
273
273
|
in_dir(srcdir) do
|
274
|
-
run 'orogen', Autobuild.tool('ruby'), '-S',
|
274
|
+
run 'orogen', Autobuild.tool('ruby'), '-S',
|
275
|
+
orogen_tool_path, *cmdline
|
275
276
|
File.open(genstamp, 'w') do |io|
|
276
277
|
io.print cmdline.join("\n")
|
277
278
|
end
|
@@ -287,11 +288,11 @@ def generation_uptodate?
|
|
287
288
|
if !File.file?(genstamp)
|
288
289
|
true
|
289
290
|
elsif File.file?(File.join(builddir, 'Makefile'))
|
290
|
-
|
291
|
+
make = Autobuild.tool('make')
|
292
|
+
system("#{make} -C #{builddir} check-uptodate > /dev/null 2>&1")
|
291
293
|
else
|
292
294
|
true
|
293
295
|
end
|
294
296
|
end
|
295
297
|
end
|
296
298
|
end
|
297
|
-
|
@@ -16,9 +16,10 @@ def installstamp
|
|
16
16
|
return std_stamp if File.file?(std_stamp)
|
17
17
|
|
18
18
|
pcfile = File.join(pkgconfig.prefix, "lib", "pkgconfig", "#{name}.pc")
|
19
|
-
|
19
|
+
unless File.file?(pcfile)
|
20
20
|
raise "cannot find the .pc file for #{name}, tried #{pcfile}"
|
21
21
|
end
|
22
|
+
|
22
23
|
pcfile
|
23
24
|
end
|
24
25
|
end
|
@@ -26,4 +27,3 @@ def self.installed_pkgconfig(name, &block)
|
|
26
27
|
InstalledPkgConfig.new(name, &block)
|
27
28
|
end
|
28
29
|
end
|
29
|
-
|
@@ -56,13 +56,17 @@ def python_path
|
|
56
56
|
raise "Unable to set PYTHONPATH: #{e.message}"
|
57
57
|
end
|
58
58
|
|
59
|
-
|
60
|
-
|
59
|
+
if ret.value.success?
|
60
|
+
output.read.chomp
|
61
|
+
else
|
62
|
+
raise 'Unable to set PYTHONPATH: user site directory disabled?'
|
63
|
+
end
|
61
64
|
end
|
62
65
|
|
63
66
|
# Do the build in builddir
|
64
67
|
def build
|
65
68
|
return unless @install_mode
|
69
|
+
|
66
70
|
command = generate_build_command
|
67
71
|
command << '--force' if @forced
|
68
72
|
progress_start 'building %s [progress not available]',
|
@@ -75,6 +79,7 @@ def build
|
|
75
79
|
# Install the result in prefix
|
76
80
|
def install
|
77
81
|
return unless @install_mode
|
82
|
+
|
78
83
|
command = generate_install_command
|
79
84
|
command << '--force' if @forced
|
80
85
|
progress_start 'installing %s',
|
@@ -22,7 +22,7 @@ class Ruby < ImporterPackage
|
|
22
22
|
def initialize(*args)
|
23
23
|
self.rake_setup_task = "default"
|
24
24
|
self.rake_doc_task = "redocs"
|
25
|
-
self.rake_clean_task
|
25
|
+
self.rake_clean_task = "clean"
|
26
26
|
self.rake_test_task = "test"
|
27
27
|
self.rake_test_options = []
|
28
28
|
|
@@ -36,19 +36,23 @@ def initialize(*args)
|
|
36
36
|
|
37
37
|
def with_doc
|
38
38
|
doc_task do
|
39
|
-
progress_start "generating documentation for %s",
|
39
|
+
progress_start "generating documentation for %s",
|
40
|
+
done_message: 'generated documentation for %s' do
|
40
41
|
run 'doc',
|
41
|
-
Autobuild.tool_in_path('ruby'), '-S',
|
42
|
-
|
42
|
+
Autobuild.tool_in_path('ruby'), '-S',
|
43
|
+
Autobuild.tool('rake'), rake_doc_task,
|
44
|
+
working_directory: srcdir
|
43
45
|
end
|
44
46
|
end
|
45
47
|
end
|
46
48
|
|
47
49
|
def with_tests
|
48
50
|
test_utility.task do
|
49
|
-
progress_start "running tests for %s",
|
51
|
+
progress_start "running tests for %s",
|
52
|
+
done_message: 'tests passed for %s' do
|
50
53
|
run 'test',
|
51
|
-
Autobuild.tool_in_path('ruby'), '-S',
|
54
|
+
Autobuild.tool_in_path('ruby'), '-S',
|
55
|
+
Autobuild.tool('rake'), rake_test_task, *rake_test_options,
|
52
56
|
working_directory: srcdir
|
53
57
|
end
|
54
58
|
end
|
@@ -57,13 +61,15 @@ def with_tests
|
|
57
61
|
def invoke_rake(setup_task = rake_setup_task)
|
58
62
|
if setup_task && File.file?(File.join(srcdir, 'Rakefile'))
|
59
63
|
run 'post-install',
|
60
|
-
Autobuild.tool_in_path('ruby'), '-S',
|
61
|
-
|
64
|
+
Autobuild.tool_in_path('ruby'), '-S',
|
65
|
+
Autobuild.tool('rake'), setup_task,
|
66
|
+
working_directory: srcdir
|
62
67
|
end
|
63
68
|
end
|
64
69
|
|
65
70
|
def install
|
66
|
-
progress_start "setting up Ruby package %s",
|
71
|
+
progress_start "setting up Ruby package %s",
|
72
|
+
done_message: 'set up Ruby package %s' do
|
67
73
|
invoke_rake
|
68
74
|
end
|
69
75
|
super
|
@@ -71,10 +77,11 @@ def install
|
|
71
77
|
|
72
78
|
def prepare_for_forced_build # :nodoc:
|
73
79
|
super
|
74
|
-
%w
|
80
|
+
%w[ext tmp].each do |extdir|
|
75
81
|
if File.directory?(extdir)
|
76
82
|
Find.find(extdir) do |file|
|
77
83
|
next if file !~ /\<Makefile\>|\<CMakeCache.txt\>$/
|
84
|
+
|
78
85
|
FileUtils.rm_rf file
|
79
86
|
end
|
80
87
|
end
|
@@ -86,10 +93,11 @@ def prepare_for_rebuild # :nodoc:
|
|
86
93
|
if rake_clean_task && File.file?(File.join(srcdir, 'Rakefile'))
|
87
94
|
begin
|
88
95
|
run 'clean',
|
89
|
-
Autobuild.tool_in_path('ruby'), '-S',
|
90
|
-
|
96
|
+
Autobuild.tool_in_path('ruby'), '-S',
|
97
|
+
Autobuild.tool('rake'), rake_clean_task,
|
98
|
+
working_directory: srcdir
|
91
99
|
rescue Autobuild::SubcommandFailed => e
|
92
|
-
warn "%s:
|
100
|
+
warn "%s: clean failed. If this package does not need a clean target,"
|
93
101
|
warn "%s: set pkg.rake_clean_task = nil in the package definition."
|
94
102
|
warn "%s: see #{e.logfile} for more details"
|
95
103
|
end
|
@@ -99,9 +107,7 @@ def prepare_for_rebuild # :nodoc:
|
|
99
107
|
def update_environment
|
100
108
|
env_add_prefix srcdir
|
101
109
|
libdir = File.join(srcdir, 'lib')
|
102
|
-
if File.directory?(libdir)
|
103
|
-
env_add_path 'RUBYLIB', libdir
|
104
|
-
end
|
110
|
+
env_add_path 'RUBYLIB', libdir if File.directory?(libdir)
|
105
111
|
end
|
106
112
|
end
|
107
113
|
|
@@ -109,4 +115,3 @@ def self.ruby(spec, &proc)
|
|
109
115
|
Ruby.new(spec, &proc)
|
110
116
|
end
|
111
117
|
end
|
112
|
-
|
data/lib/autobuild/parallel.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'thread'
|
2
|
-
|
3
1
|
module Autobuild
|
4
2
|
# This is a rewrite of the Rake task invocation code to use parallelism
|
5
3
|
#
|
@@ -23,9 +21,11 @@ def initialize(level)
|
|
23
21
|
wio.fcntl(Fcntl::F_SETFD, 0)
|
24
22
|
put(level)
|
25
23
|
end
|
24
|
+
|
26
25
|
def get(token_count = 1)
|
27
26
|
@rio.read(token_count)
|
28
27
|
end
|
28
|
+
|
29
29
|
def put(token_count = 1)
|
30
30
|
@wio.write(" " * token_count)
|
31
31
|
end
|
@@ -36,7 +36,6 @@ def initialize(level = Autobuild.parallel_build_level)
|
|
36
36
|
@available_workers = Array.new
|
37
37
|
@finished_workers = Queue.new
|
38
38
|
@workers = Array.new
|
39
|
-
|
40
39
|
end
|
41
40
|
|
42
41
|
def wait_for_worker_to_end(state)
|
@@ -46,9 +45,12 @@ def wait_for_worker_to_end(state)
|
|
46
45
|
if error
|
47
46
|
if available_workers.size != workers.size
|
48
47
|
if finished_task.respond_to?(:package) && finished_task.package
|
49
|
-
Autobuild.error "got an error processing
|
48
|
+
Autobuild.error "got an error processing "\
|
49
|
+
"#{finished_task.package.name}, "\
|
50
|
+
"waiting for pending jobs to end"
|
50
51
|
else
|
51
|
-
Autobuild.error "got an error doing parallel processing,
|
52
|
+
Autobuild.error "got an error doing parallel processing, "\
|
53
|
+
"waiting for pending jobs to end"
|
52
54
|
end
|
53
55
|
end
|
54
56
|
begin
|
@@ -61,16 +63,14 @@ def wait_for_worker_to_end(state)
|
|
61
63
|
state.process_finished_task(finished_task)
|
62
64
|
end
|
63
65
|
|
64
|
-
def discover_dependencies(all_tasks, reverse_dependencies,
|
65
|
-
if
|
66
|
-
|
67
|
-
end
|
66
|
+
def discover_dependencies(all_tasks, reverse_dependencies, task)
|
67
|
+
return if task.already_invoked?
|
68
|
+
return if all_tasks.include?(task) # already discovered or being discovered
|
68
69
|
|
69
|
-
|
70
|
-
all_tasks << t
|
70
|
+
all_tasks << task
|
71
71
|
|
72
|
-
|
73
|
-
reverse_dependencies[dep_t] <<
|
72
|
+
task.prerequisite_tasks.each do |dep_t|
|
73
|
+
reverse_dependencies[dep_t] << task
|
74
74
|
discover_dependencies(all_tasks, reverse_dependencies, dep_t)
|
75
75
|
end
|
76
76
|
end
|
@@ -101,7 +101,7 @@ def push(task, base_priority = 1)
|
|
101
101
|
end
|
102
102
|
|
103
103
|
def find_task
|
104
|
-
if task = queue.
|
104
|
+
if (task = queue.min_by { |_t, p| p })
|
105
105
|
priorities[task.first] = task.last
|
106
106
|
task.first
|
107
107
|
end
|
@@ -146,7 +146,8 @@ def process_finished_task(task)
|
|
146
146
|
end
|
147
147
|
|
148
148
|
def trivial_task?(task)
|
149
|
-
(task.kind_of?(Autobuild::SourceTreeTask) ||
|
149
|
+
(task.kind_of?(Autobuild::SourceTreeTask) ||
|
150
|
+
task.kind_of?(Rake::FileTask)) && task.actions.empty?
|
150
151
|
end
|
151
152
|
end
|
152
153
|
|
@@ -163,11 +164,9 @@ def invoke_parallel(required_tasks)
|
|
163
164
|
# set of tasks that can be queued for execution.
|
164
165
|
state = ProcessingState.new(reverse_dependencies)
|
165
166
|
tasks.each do |t|
|
166
|
-
if state.ready?(t)
|
167
|
-
state.push(t)
|
168
|
-
end
|
167
|
+
state.push(t) if state.ready?(t)
|
169
168
|
end
|
170
|
-
|
169
|
+
|
171
170
|
# Build a reverse dependency graph (i.e. a mapping from a task to
|
172
171
|
# the tasks that depend on it)
|
173
172
|
|
@@ -175,9 +174,9 @@ def invoke_parallel(required_tasks)
|
|
175
174
|
# topological sort since we would then have to scan all tasks each
|
176
175
|
# time for tasks that have no currently running prerequisites
|
177
176
|
|
178
|
-
|
177
|
+
loop do
|
179
178
|
pending_task = state.pop
|
180
|
-
|
179
|
+
unless pending_task
|
181
180
|
# If we have pending workers, wait for one to be finished
|
182
181
|
# until either they are all finished or the queue is not
|
183
182
|
# empty anymore
|
@@ -186,9 +185,7 @@ def invoke_parallel(required_tasks)
|
|
186
185
|
pending_task = state.pop
|
187
186
|
end
|
188
187
|
|
189
|
-
if !pending_task && available_workers.size == workers.size
|
190
|
-
break
|
191
|
-
end
|
188
|
+
break if !pending_task && available_workers.size == workers.size
|
192
189
|
end
|
193
190
|
|
194
191
|
if state.trivial_task?(pending_task)
|
@@ -204,9 +201,7 @@ def invoke_parallel(required_tasks)
|
|
204
201
|
# Get a job server token
|
205
202
|
job_server.get
|
206
203
|
|
207
|
-
|
208
|
-
wait_for_worker_to_end(state)
|
209
|
-
end
|
204
|
+
wait_for_worker_to_end(state) until finished_workers.empty?
|
210
205
|
|
211
206
|
# We do have a job server token, so we are allowed to allocate a
|
212
207
|
# new worker if none are available
|
@@ -222,9 +217,9 @@ def invoke_parallel(required_tasks)
|
|
222
217
|
end
|
223
218
|
|
224
219
|
not_processed = tasks.find_all { |t| !t.already_invoked? }
|
225
|
-
|
220
|
+
unless not_processed.empty?
|
226
221
|
cycle = resolve_cycle(tasks, not_processed, reverse_dependencies)
|
227
|
-
raise "cycle in task graph: #{cycle.map(&:name).sort.join(
|
222
|
+
raise "cycle in task graph: #{cycle.map(&:name).sort.join(', ')}"
|
228
223
|
end
|
229
224
|
end
|
230
225
|
|
@@ -232,7 +227,7 @@ def resolve_cycle(all_tasks, tasks, reverse_dependencies)
|
|
232
227
|
cycle = tasks.dup
|
233
228
|
chain = []
|
234
229
|
next_task = tasks.first
|
235
|
-
|
230
|
+
loop do
|
236
231
|
task = next_task
|
237
232
|
chain << task
|
238
233
|
tasks.delete(next_task)
|
@@ -244,10 +239,12 @@ def resolve_cycle(all_tasks, tasks, reverse_dependencies)
|
|
244
239
|
true
|
245
240
|
end
|
246
241
|
end
|
247
|
-
|
248
|
-
Autobuild.fatal "parallel processing stopped prematurely,
|
249
|
-
|
250
|
-
Autobuild.fatal "
|
242
|
+
unless next_task
|
243
|
+
Autobuild.fatal "parallel processing stopped prematurely, "\
|
244
|
+
"but no cycle is present in the remaining tasks"
|
245
|
+
Autobuild.fatal "remaining tasks: #{cycle.map(&:name).join(', ')}"
|
246
|
+
Autobuild.fatal "known dependencies at initialization time that "\
|
247
|
+
"could block the processing of the remaining tasks"
|
251
248
|
reverse_dependencies.each do |parent_task, parents|
|
252
249
|
if cycle.include?(parent_task)
|
253
250
|
parents.each do |p|
|
@@ -255,13 +252,14 @@ def resolve_cycle(all_tasks, tasks, reverse_dependencies)
|
|
255
252
|
end
|
256
253
|
end
|
257
254
|
end
|
258
|
-
Autobuild.fatal "known dependencies right now that could block
|
255
|
+
Autobuild.fatal "known dependencies right now that could block "\
|
256
|
+
"the processing of the remaining tasks"
|
259
257
|
all_tasks.each do |p|
|
260
258
|
(cycle & p.prerequisite_tasks).each do |t|
|
261
259
|
Autobuild.fatal " #{p}: #{t}"
|
262
260
|
end
|
263
261
|
end
|
264
|
-
raise "failed to resolve cycle in #{cycle.map(&:name).join(
|
262
|
+
raise "failed to resolve cycle in #{cycle.map(&:name).join(', ')}"
|
265
263
|
end
|
266
264
|
end
|
267
265
|
chain
|
@@ -301,7 +299,7 @@ def do_task(task)
|
|
301
299
|
end
|
302
300
|
|
303
301
|
def last_result
|
304
|
-
|
302
|
+
[@last_finished_task, @last_error]
|
305
303
|
end
|
306
304
|
|
307
305
|
def queue(task)
|
@@ -321,5 +319,3 @@ class << self
|
|
321
319
|
attr_accessor :parallel_task_manager
|
322
320
|
end
|
323
321
|
end
|
324
|
-
|
325
|
-
|