autobuild 1.17.0 → 1.21.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +107 -0
- data/.travis.yml +3 -2
- data/Gemfile +2 -1
- data/Rakefile +1 -4
- data/autobuild.gemspec +18 -13
- data/bin/autobuild +4 -3
- data/lib/autobuild.rb +4 -5
- data/lib/autobuild/build_logfile.rb +6 -4
- data/lib/autobuild/config.rb +104 -41
- data/lib/autobuild/configurable.rb +32 -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 +246 -182
- data/lib/autobuild/import/hg.rb +23 -18
- data/lib/autobuild/import/svn.rb +48 -29
- data/lib/autobuild/importer.rb +534 -499
- data/lib/autobuild/mail_reporter.rb +77 -77
- data/lib/autobuild/package.rb +200 -122
- data/lib/autobuild/packages/autotools.rb +47 -42
- data/lib/autobuild/packages/cmake.rb +77 -65
- data/lib/autobuild/packages/dummy.rb +9 -8
- data/lib/autobuild/packages/genom.rb +1 -1
- data/lib/autobuild/packages/gnumake.rb +74 -31
- 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 +12 -8
- data/lib/autobuild/packages/ruby.rb +22 -17
- data/lib/autobuild/parallel.rb +50 -46
- data/lib/autobuild/pkgconfig.rb +25 -13
- data/lib/autobuild/progress_display.rb +149 -64
- data/lib/autobuild/rake_task_extension.rb +12 -7
- data/lib/autobuild/reporting.rb +51 -26
- data/lib/autobuild/subcommand.rb +72 -65
- data/lib/autobuild/test.rb +9 -7
- data/lib/autobuild/test_utility.rb +12 -10
- data/lib/autobuild/timestamps.rb +28 -23
- data/lib/autobuild/tools.rb +17 -16
- data/lib/autobuild/utility.rb +67 -23
- data/lib/autobuild/version.rb +1 -1
- metadata +53 -37
@@ -8,100 +8,100 @@
|
|
8
8
|
|
9
9
|
## Report by mail
|
10
10
|
if Autobuild::HAS_RMAIL
|
11
|
-
module Autobuild
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
module Autobuild
|
12
|
+
class MailReporter < Reporter
|
13
|
+
def default_mail
|
14
|
+
Etc.endpwent
|
15
|
+
uname = while (pwent = Etc.getpwent)
|
16
|
+
break pwent.name if pwent.uid == Process.uid
|
17
|
+
end
|
18
18
|
|
19
|
-
|
20
|
-
"#{pwent.name}@#{Socket.gethostname}"
|
21
|
-
end
|
22
|
-
|
23
|
-
attr_reader :from_email, :to_email, :smtp_hostname, :smtp_port, :subject, :only_errors
|
24
|
-
def initialize(config)
|
25
|
-
@from_email = (config[:from] || default_mail)
|
26
|
-
@to_email = (config[:to] || default_mail)
|
27
|
-
@subject = (config[:subject] || "Build %result% on #{Socket.gethostname} at %time%")
|
28
|
-
@only_errors = config[:only_errors]
|
29
|
-
@smtp_hostname = (config[:smtp] || "localhost" )
|
30
|
-
@smtp_port = Integer(config[:port] || Socket.getservbyname('smtp'))
|
31
|
-
end
|
19
|
+
raise "FATAL: cannot find a user with uid=#{Process.uid}" unless uname
|
32
20
|
|
33
|
-
|
34
|
-
if error.mail?
|
35
|
-
send_mail("failed", error.to_s)
|
21
|
+
"#{pwent.name}@#{Socket.gethostname}"
|
36
22
|
end
|
37
|
-
end
|
38
23
|
|
39
|
-
|
40
|
-
|
41
|
-
|
24
|
+
attr_reader :from_email, :to_email, :smtp_hostname, :smtp_port,
|
25
|
+
:subject, :only_errors
|
26
|
+
def initialize(config)
|
27
|
+
@from_email = (config[:from] || default_mail)
|
28
|
+
@to_email = (config[:to] || default_mail)
|
29
|
+
@subject =
|
30
|
+
config[:subject] ||
|
31
|
+
"Build %result% on #{Socket.gethostname} at %time%"
|
32
|
+
@only_errors = config[:only_errors]
|
33
|
+
@smtp_hostname = (config[:smtp] || "localhost")
|
34
|
+
@smtp_port = Integer(config[:port] || Socket.getservbyname('smtp'))
|
42
35
|
end
|
43
|
-
end
|
44
36
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
mail.header.from = from_email
|
49
|
-
mail.header.subject = subject.
|
50
|
-
gsub('%result%', result).
|
51
|
-
gsub('%time%', Time.now.to_s).
|
52
|
-
gsub('%hostname%', Socket.gethostname)
|
53
|
-
|
54
|
-
part = RMail::Message.new
|
55
|
-
part.header.set('Content-Type', 'text/plain')
|
56
|
-
part.body = body
|
57
|
-
mail.add_part(part)
|
37
|
+
def error(error)
|
38
|
+
send_mail("failed", error.to_s) if error.mail?
|
39
|
+
end
|
58
40
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
41
|
+
def success
|
42
|
+
unless only_errors
|
43
|
+
send_mail("success", Autobuild.post_success_message || "")
|
44
|
+
end
|
63
45
|
end
|
64
46
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
47
|
+
def send_mail(result, body = "")
|
48
|
+
mail = RMail::Message.new
|
49
|
+
mail.header.date = Time.now
|
50
|
+
mail.header.from = from_email
|
51
|
+
mail.header.subject = subject.
|
52
|
+
gsub('%result%', result).
|
53
|
+
gsub('%time%', Time.now.to_s).
|
54
|
+
gsub('%hostname%', Socket.gethostname)
|
55
|
+
|
56
|
+
part = RMail::Message.new
|
57
|
+
part.header.set('Content-Type', 'text/plain')
|
58
|
+
part.body = body
|
59
|
+
mail.add_part(part)
|
60
|
+
|
61
|
+
# Attach log files
|
62
|
+
Reporting.each_log do |file|
|
63
|
+
name = file[Autobuild.logdir.size..-1]
|
64
|
+
mail.add_file(name, file)
|
71
65
|
end
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
66
|
+
|
67
|
+
# Send the mails
|
68
|
+
if smtp_hostname =~ %r{/} && File.directory?(File.dirname(smtp_hostname))
|
69
|
+
File.open(smtp_hostname, 'w') do |io|
|
70
|
+
io.puts "From: #{from_email}"
|
71
|
+
io.puts "To: #{to_email.join(' ')}"
|
72
|
+
io.write RMail::Serialize.write('', mail)
|
73
|
+
end
|
74
|
+
puts "saved notification email in #{smtp_hostname}"
|
75
|
+
else
|
76
|
+
smtp = Net::SMTP.new(smtp_hostname, smtp_port)
|
77
|
+
smtp.start do
|
78
|
+
to_email.each do |email|
|
79
|
+
mail.header.to = email
|
80
|
+
smtp.send_mail(RMail::Serialize.write('', mail),
|
81
|
+
from_email, email)
|
82
|
+
end
|
79
83
|
end
|
80
|
-
}
|
81
84
|
|
82
|
-
|
83
|
-
|
85
|
+
# Notify the sending
|
86
|
+
puts "sent notification mail to #{to_email} with source #{from_email}"
|
87
|
+
end
|
84
88
|
end
|
85
89
|
end
|
86
90
|
end
|
87
|
-
end
|
88
91
|
|
89
|
-
module RMail
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
92
|
+
module RMail
|
93
|
+
class Message
|
94
|
+
## Attachs a file to a message
|
95
|
+
def add_file(name, path, content_type = 'text/plain')
|
96
|
+
part = RMail::Message.new
|
97
|
+
part.header.set('Content-Type', content_type)
|
98
|
+
part.header.set('Content-Disposition', 'attachment', 'filename' => name)
|
99
|
+
part.body = ''
|
100
|
+
File.open(path) do |file|
|
101
|
+
part.body << file.readlines.join("")
|
102
|
+
end
|
103
|
+
add_part(part)
|
99
104
|
end
|
100
|
-
self.add_part(part)
|
101
105
|
end
|
102
106
|
end
|
103
107
|
end
|
104
|
-
end # if Autobuild::HAS_RMAIL
|
105
|
-
|
106
|
-
|
107
|
-
|
data/lib/autobuild/package.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
module Autobuild
|
2
|
-
TARGETS = %w
|
2
|
+
TARGETS = %w[import prepare build].freeze
|
3
3
|
|
4
4
|
class << self
|
5
5
|
attr_accessor :ignore_errors
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
# Basic block for the autobuilder
|
9
9
|
#
|
10
10
|
# The build is done in three phases:
|
@@ -43,14 +43,18 @@ class Package
|
|
43
43
|
# The set of utilities attached to this package
|
44
44
|
# @return [{String=>Utility}]
|
45
45
|
attr_reader :utilities
|
46
|
+
|
46
47
|
# Whether {#apply_post_install} has been called
|
47
|
-
def applied_post_install
|
48
|
-
|
48
|
+
def applied_post_install?
|
49
|
+
@applied_post_install
|
50
|
+
end
|
51
|
+
|
49
52
|
# Sets importer object for this package. Defined for backwards compatibility.
|
50
53
|
# Use the #importer attribute instead
|
51
54
|
def import=(value)
|
52
55
|
@importer = value
|
53
56
|
end
|
57
|
+
|
54
58
|
# Sets an importer object for this package
|
55
59
|
attr_accessor :importer
|
56
60
|
|
@@ -74,11 +78,20 @@ def add_stat(phase, duration)
|
|
74
78
|
end
|
75
79
|
|
76
80
|
# Absolute path to the source directory. See #srcdir=
|
77
|
-
def srcdir
|
81
|
+
def srcdir
|
82
|
+
File.expand_path(@srcdir || name, Autobuild.srcdir)
|
83
|
+
end
|
84
|
+
|
78
85
|
# Absolute path to the import directory. See #importdir=
|
79
|
-
def importdir
|
86
|
+
def importdir
|
87
|
+
File.expand_path(@importdir || srcdir, Autobuild.srcdir)
|
88
|
+
end
|
89
|
+
|
80
90
|
# Absolute path to the installation directory. See #prefix=
|
81
|
-
def prefix
|
91
|
+
def prefix
|
92
|
+
File.expand_path(@prefix || '', Autobuild.prefix)
|
93
|
+
end
|
94
|
+
|
82
95
|
# Absolute path to the log directory for this package. See #logdir=
|
83
96
|
def logdir
|
84
97
|
if @logdir
|
@@ -115,17 +128,19 @@ def update?
|
|
115
128
|
# Returns true if this package has already been updated. It will not be
|
116
129
|
# true if the importer has been called while Autobuild.do_update was
|
117
130
|
# false.
|
118
|
-
def updated
|
131
|
+
def updated?
|
132
|
+
@updated
|
133
|
+
end
|
119
134
|
|
120
135
|
def initialize(spec = Hash.new)
|
121
136
|
@srcdir = @importdir = @logdir = @prefix = nil
|
122
137
|
@updated = false
|
123
138
|
@update = nil
|
124
139
|
@failed = nil
|
125
|
-
@dependencies
|
126
|
-
@provides
|
140
|
+
@dependencies = Array.new
|
141
|
+
@provides = Array.new
|
142
|
+
@statistics = Hash.new
|
127
143
|
@parallel_build_level = nil
|
128
|
-
@statistics = Hash.new
|
129
144
|
@failures = Array.new
|
130
145
|
@post_install_blocks = Array.new
|
131
146
|
@applied_post_install = false
|
@@ -139,19 +154,23 @@ def initialize(spec = Hash.new)
|
|
139
154
|
if Hash === spec
|
140
155
|
name, depends = spec.to_a.first
|
141
156
|
else
|
142
|
-
name
|
157
|
+
name = spec
|
158
|
+
depends = nil
|
143
159
|
end
|
144
160
|
|
145
161
|
name = name.to_s
|
146
162
|
@name = name
|
147
|
-
|
163
|
+
if Autobuild::Package[name]
|
164
|
+
raise ConfigException, "package #{name} is already defined"
|
165
|
+
end
|
166
|
+
|
148
167
|
@@packages[name] = self
|
149
168
|
|
150
169
|
# Call the config block (if any)
|
151
170
|
yield(self) if block_given?
|
152
171
|
|
153
|
-
|
154
|
-
|
172
|
+
doc_utility.source_dir ||= 'doc'
|
173
|
+
doc_utility.target_dir ||= name
|
155
174
|
|
156
175
|
# Define the default tasks
|
157
176
|
task "#{name}-import" do
|
@@ -174,12 +193,10 @@ def initialize(spec = Hash.new)
|
|
174
193
|
Rake::Task["#{name}-import"].invoke
|
175
194
|
Rake::Task["#{name}-prepare"].invoke
|
176
195
|
Rake::Task["#{name}-build"].invoke
|
177
|
-
if has_doc? && Autobuild.do_doc
|
178
|
-
Rake::Task["#{name}-doc"].invoke
|
179
|
-
end
|
196
|
+
Rake::Task["#{name}-doc"].invoke if has_doc? && Autobuild.do_doc
|
180
197
|
end
|
181
198
|
task :default => name
|
182
|
-
|
199
|
+
|
183
200
|
# The dependencies will be declared in the import phase, so save
|
184
201
|
# them there for now
|
185
202
|
@spec_dependencies = depends
|
@@ -190,34 +207,29 @@ def checked_out?
|
|
190
207
|
File.directory?(srcdir)
|
191
208
|
end
|
192
209
|
|
193
|
-
def prepare_invoked?
|
194
|
-
task("#{name}-prepare").already_invoked?
|
195
|
-
end
|
196
|
-
|
197
|
-
def prepared?
|
198
|
-
@prepared
|
199
|
-
end
|
200
|
-
|
201
210
|
def import_invoked?
|
202
|
-
|
211
|
+
@import_invoked
|
203
212
|
end
|
204
213
|
|
205
214
|
def imported?
|
206
215
|
@imported
|
207
216
|
end
|
208
217
|
|
209
|
-
def
|
210
|
-
|
218
|
+
def install_invoked?
|
219
|
+
@install_invoked
|
211
220
|
end
|
212
221
|
|
213
|
-
def
|
214
|
-
@
|
222
|
+
def installed?
|
223
|
+
@installed
|
215
224
|
end
|
216
225
|
|
217
226
|
def to_s
|
218
227
|
"#<#{self.class} name=#{name}>"
|
219
228
|
end
|
220
|
-
|
229
|
+
|
230
|
+
def inspect
|
231
|
+
to_s
|
232
|
+
end
|
221
233
|
|
222
234
|
# @api private
|
223
235
|
#
|
@@ -226,8 +238,8 @@ def inspect; to_s end
|
|
226
238
|
#
|
227
239
|
# @param [EnvOp] op
|
228
240
|
# @return [void]
|
229
|
-
def add_env_op(
|
230
|
-
env <<
|
241
|
+
def add_env_op(envop)
|
242
|
+
env << envop
|
231
243
|
end
|
232
244
|
|
233
245
|
# Add value(s) to a list-based environment variable
|
@@ -300,11 +312,15 @@ class IncompatibleEnvironment < ConfigException; end
|
|
300
312
|
def apply_env(env, set = Hash.new, ops = Array.new)
|
301
313
|
self.env.each do |env_op|
|
302
314
|
next if ops.last == env_op
|
315
|
+
|
303
316
|
if env_op.type == :set
|
304
|
-
if last = set[env_op.name]
|
317
|
+
if (last = set[env_op.name])
|
305
318
|
last_pkg, last_values = *last
|
306
319
|
if last_values != env_op.values
|
307
|
-
raise IncompatibleEnvironment, "trying to reset
|
320
|
+
raise IncompatibleEnvironment, "trying to reset "\
|
321
|
+
"#{env_op.name} to #{env_op.values} in #{name} "\
|
322
|
+
"but this conflicts with #{last_pkg.name} "\
|
323
|
+
"already setting it to #{last_values}"
|
308
324
|
end
|
309
325
|
else
|
310
326
|
set[env_op.name] = [self, env_op.values]
|
@@ -356,9 +372,7 @@ def resolved_env(root = Autobuild.env)
|
|
356
372
|
# target files so that all the build phases of this package gets
|
357
373
|
# retriggered. However, it should not clean the build products.
|
358
374
|
def prepare_for_forced_build
|
359
|
-
if File.exist?(installstamp)
|
360
|
-
FileUtils.rm_f installstamp
|
361
|
-
end
|
375
|
+
FileUtils.rm_f installstamp if File.exist?(installstamp)
|
362
376
|
end
|
363
377
|
|
364
378
|
# Called when the user asked for a full rebuild. It should delete the
|
@@ -366,9 +380,7 @@ def prepare_for_forced_build
|
|
366
380
|
def prepare_for_rebuild
|
367
381
|
prepare_for_forced_build
|
368
382
|
|
369
|
-
if File.exist?(installstamp)
|
370
|
-
FileUtils.rm_f installstamp
|
371
|
-
end
|
383
|
+
FileUtils.rm_f installstamp if File.exist?(installstamp)
|
372
384
|
end
|
373
385
|
|
374
386
|
# Returns true if one of the operations applied on this package failed
|
@@ -388,18 +400,18 @@ def failed?
|
|
388
400
|
# will subsequently be a noop. I.e. if +build+ fails, +install+ will do
|
389
401
|
# nothing.
|
390
402
|
def isolate_errors(options = Hash.new)
|
391
|
-
|
392
|
-
options = Hash[mark_as_failed: true]
|
393
|
-
end
|
403
|
+
options = Hash[mark_as_failed: true] unless options.kind_of?(Hash)
|
394
404
|
options = validate_options options,
|
395
405
|
mark_as_failed: true,
|
396
406
|
ignore_errors: Autobuild.ignore_errors
|
397
407
|
|
398
408
|
# Don't do anything if we already have failed
|
399
409
|
if failed?
|
400
|
-
|
401
|
-
raise AlreadyFailedError, "attempting to do an operation
|
410
|
+
unless options[:ignore_errors]
|
411
|
+
raise AlreadyFailedError, "attempting to do an operation "\
|
412
|
+
"on a failed package"
|
402
413
|
end
|
414
|
+
|
403
415
|
return
|
404
416
|
end
|
405
417
|
|
@@ -413,18 +425,12 @@ def isolate_errors(options = Hash.new)
|
|
413
425
|
raise
|
414
426
|
rescue ::Exception => e
|
415
427
|
@failures << e
|
416
|
-
if options[:mark_as_failed]
|
417
|
-
@failed = true
|
418
|
-
end
|
428
|
+
@failed = true if options[:mark_as_failed]
|
419
429
|
|
420
430
|
if options[:ignore_errors]
|
421
431
|
lines = e.to_s.split("\n")
|
422
|
-
if lines.empty?
|
423
|
-
|
424
|
-
end
|
425
|
-
if lines.empty?
|
426
|
-
lines = ["unknown error"]
|
427
|
-
end
|
432
|
+
lines = e.message.split("\n") if lines.empty?
|
433
|
+
lines = ["unknown error"] if lines.empty?
|
428
434
|
message(lines.shift, :red, :bold)
|
429
435
|
lines.each do |line|
|
430
436
|
message(line)
|
@@ -434,9 +440,7 @@ def isolate_errors(options = Hash.new)
|
|
434
440
|
raise
|
435
441
|
end
|
436
442
|
ensure
|
437
|
-
if toplevel
|
438
|
-
Thread.current[:isolate_errors] = false
|
439
|
-
end
|
443
|
+
Thread.current[:isolate_errors] = false if toplevel
|
440
444
|
end
|
441
445
|
end
|
442
446
|
|
@@ -445,16 +449,15 @@ def isolate_errors(options = Hash.new)
|
|
445
449
|
#
|
446
450
|
# (see Importer#import)
|
447
451
|
def import(options = Hash.new)
|
448
|
-
|
449
|
-
options = Hash[only_local: options]
|
450
|
-
end
|
452
|
+
options = Hash[only_local: options] unless options.respond_to?(:to_hash)
|
451
453
|
|
454
|
+
@import_invoked = true
|
452
455
|
if @importer
|
453
456
|
result = @importer.import(self, options)
|
454
|
-
@imported = true
|
455
457
|
elsif update?
|
456
458
|
message "%s: no importer defined, doing nothing"
|
457
459
|
end
|
460
|
+
@imported = true
|
458
461
|
|
459
462
|
# Add the dependencies declared in spec
|
460
463
|
depends_on(*@spec_dependencies) if @spec_dependencies
|
@@ -470,7 +473,10 @@ def prepare
|
|
470
473
|
stamps = dependencies.map { |p| Package[p].installstamp }
|
471
474
|
|
472
475
|
file installstamp => stamps do
|
473
|
-
isolate_errors
|
476
|
+
isolate_errors do
|
477
|
+
@install_invoked = true
|
478
|
+
install
|
479
|
+
end
|
474
480
|
end
|
475
481
|
task "#{name}-build" => installstamp
|
476
482
|
|
@@ -478,7 +484,8 @@ def prepare
|
|
478
484
|
end
|
479
485
|
|
480
486
|
def process_formatting_string(msg, *prefix_style)
|
481
|
-
prefix
|
487
|
+
prefix = []
|
488
|
+
suffix = []
|
482
489
|
msg.split(" ").each do |token|
|
483
490
|
if token =~ /%s/
|
484
491
|
suffix << token.gsub(/%s/, name)
|
@@ -492,7 +499,8 @@ def process_formatting_string(msg, *prefix_style)
|
|
492
499
|
elsif prefix_style.empty?
|
493
500
|
return (prefix + suffix).join(" ")
|
494
501
|
else
|
495
|
-
|
502
|
+
colorized_prefix = Autobuild.color(prefix.join(" "), *prefix_style)
|
503
|
+
return [colorized_prefix, *suffix].join(" ")
|
496
504
|
end
|
497
505
|
end
|
498
506
|
|
@@ -511,17 +519,13 @@ def error(error_string)
|
|
511
519
|
# Display a progress message. %s in the string is replaced by the
|
512
520
|
# package name
|
513
521
|
def message(*args)
|
514
|
-
|
515
|
-
args[0] = " #{process_formatting_string(args[0])}"
|
516
|
-
end
|
522
|
+
args[0] = " #{process_formatting_string(args[0])}" unless args.empty?
|
517
523
|
Autobuild.message(*args)
|
518
524
|
end
|
519
525
|
|
520
526
|
def progress_start(*args, done_message: nil, **raw_options, &block)
|
521
527
|
args[0] = process_formatting_string(args[0], :bold)
|
522
|
-
if done_message
|
523
|
-
done_message = process_formatting_string(done_message)
|
524
|
-
end
|
528
|
+
done_message = process_formatting_string(done_message) if done_message
|
525
529
|
Autobuild.progress_start(self, *args,
|
526
530
|
done_message: done_message, **raw_options, &block)
|
527
531
|
end
|
@@ -555,22 +559,31 @@ def install
|
|
555
559
|
|
556
560
|
Autobuild.touch_stamp(installstamp)
|
557
561
|
|
558
|
-
@
|
562
|
+
@installed = true
|
559
563
|
end
|
560
564
|
|
561
565
|
def run(*args, &block)
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
566
|
+
options =
|
567
|
+
if args.last.kind_of?(Hash)
|
568
|
+
args.pop
|
569
|
+
else
|
570
|
+
Hash.new
|
571
|
+
end
|
567
572
|
options[:env] = options.delete(:resolved_env) ||
|
568
|
-
|
573
|
+
(options[:env] || Hash.new).merge(resolved_env)
|
569
574
|
Autobuild::Subprocess.run(self, *args, options, &block)
|
570
575
|
end
|
571
576
|
|
572
577
|
module TaskExtension
|
573
578
|
attr_accessor :package
|
579
|
+
|
580
|
+
def disabled?
|
581
|
+
if @disabled.nil? && package
|
582
|
+
package.disabled?
|
583
|
+
else
|
584
|
+
super
|
585
|
+
end
|
586
|
+
end
|
574
587
|
end
|
575
588
|
|
576
589
|
def source_tree(*args, &block)
|
@@ -596,17 +609,49 @@ def task(*args, &block)
|
|
596
609
|
task
|
597
610
|
end
|
598
611
|
|
599
|
-
def doc_dir=(value)
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
def
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
def
|
608
|
-
|
609
|
-
|
612
|
+
def doc_dir=(value)
|
613
|
+
doc_utility.source_dir = value
|
614
|
+
end
|
615
|
+
|
616
|
+
def doc_dir
|
617
|
+
doc_utility.source_dir
|
618
|
+
end
|
619
|
+
|
620
|
+
def doc_target_dir=(value)
|
621
|
+
doc_utility.target_dir = value
|
622
|
+
end
|
623
|
+
|
624
|
+
def doc_target_dir
|
625
|
+
doc_utility.target_dir
|
626
|
+
end
|
627
|
+
|
628
|
+
def doc_task(&block)
|
629
|
+
doc_utility.task(&block)
|
630
|
+
end
|
631
|
+
|
632
|
+
def generates_doc?
|
633
|
+
doc_utility.enabled?
|
634
|
+
end
|
635
|
+
|
636
|
+
def enable_doc
|
637
|
+
doc_utility.enabled = true
|
638
|
+
end
|
639
|
+
|
640
|
+
def disable_doc
|
641
|
+
doc_utility.enabled = false
|
642
|
+
end
|
643
|
+
|
644
|
+
def install_doc
|
645
|
+
doc_utility.install
|
646
|
+
end
|
647
|
+
|
648
|
+
def doc_disabled
|
649
|
+
doc_utility.disabled
|
650
|
+
end
|
651
|
+
|
652
|
+
def has_doc?
|
653
|
+
doc_utility.has_task?
|
654
|
+
end
|
610
655
|
|
611
656
|
def post_install(*args, &block)
|
612
657
|
if args.empty?
|
@@ -618,11 +663,43 @@ def post_install(*args, &block)
|
|
618
663
|
end
|
619
664
|
end
|
620
665
|
|
666
|
+
def self_fingerprint
|
667
|
+
importer.fingerprint(self)
|
668
|
+
end
|
669
|
+
|
670
|
+
# Returns a unique hash representing a state of the package and
|
671
|
+
# its dependencies, if any dependency can't calculate its own
|
672
|
+
# fingerprint the result will be nil
|
673
|
+
# @return [String]
|
674
|
+
def fingerprint(recursive: true, memo: {})
|
675
|
+
return memo[name] if memo.key?(name)
|
676
|
+
|
677
|
+
self_fingerprint = self.self_fingerprint
|
678
|
+
return unless self_fingerprint
|
679
|
+
if dependencies.empty?
|
680
|
+
return (memo[name] = self_fingerprint)
|
681
|
+
elsif !recursive
|
682
|
+
return self_fingerprint
|
683
|
+
end
|
684
|
+
|
685
|
+
dependency_fingerprints = dependencies.sort.map do |pkg_name|
|
686
|
+
pkg = Autobuild::Package[pkg_name]
|
687
|
+
unless (fingerprint = memo[pkg.name])
|
688
|
+
fingerprint = pkg.fingerprint(recursive: true, memo: memo)
|
689
|
+
return unless fingerprint
|
690
|
+
end
|
691
|
+
fingerprint
|
692
|
+
end
|
693
|
+
|
694
|
+
memo[name] = Digest::SHA1.hexdigest(
|
695
|
+
self_fingerprint + dependency_fingerprints.join(""))
|
696
|
+
end
|
697
|
+
|
621
698
|
# Returns the name of all the packages +self+ depends on
|
622
699
|
def all_dependencies(result = Set.new)
|
623
700
|
dependencies.each do |pkg_name|
|
624
701
|
pkg = Autobuild::Package[pkg_name]
|
625
|
-
|
702
|
+
unless result.include?(pkg.name)
|
626
703
|
result << pkg.name
|
627
704
|
pkg.all_dependencies(result)
|
628
705
|
end
|
@@ -642,18 +719,21 @@ def depends_on?(package_name)
|
|
642
719
|
def depends_on(*packages)
|
643
720
|
packages.each do |p|
|
644
721
|
p = p.name if p.respond_to?(:name)
|
645
|
-
|
722
|
+
unless p.respond_to?(:to_str)
|
723
|
+
raise ArgumentError, "#{p.inspect} should be a string"
|
724
|
+
end
|
725
|
+
|
646
726
|
p = p.to_str
|
647
727
|
next if p == name
|
648
|
-
|
649
|
-
|
728
|
+
|
729
|
+
unless (pkg = Package[p])
|
730
|
+
raise ConfigException.new(self), "package #{p}, "\
|
731
|
+
"listed as a dependency of #{name}, is not defined"
|
650
732
|
end
|
651
733
|
|
652
734
|
next if @dependencies.include?(pkg.name)
|
653
735
|
|
654
|
-
if Autobuild.verbose
|
655
|
-
Autobuild.message "#{name} depends on #{pkg.name}"
|
656
|
-
end
|
736
|
+
Autobuild.message "#{name} depends on #{pkg.name}" if Autobuild.verbose
|
657
737
|
|
658
738
|
task "#{name}-import" => "#{pkg.name}-import"
|
659
739
|
task "#{name}-prepare" => "#{pkg.name}-prepare"
|
@@ -666,16 +746,17 @@ def depends_on(*packages)
|
|
666
746
|
# listed in +packages+ are aliases for this package.
|
667
747
|
def provides(*packages)
|
668
748
|
packages.each do |p|
|
669
|
-
|
749
|
+
unless p.respond_to?(:to_str)
|
750
|
+
raise ArgumentError, "#{p.inspect} should be a string"
|
751
|
+
end
|
752
|
+
|
670
753
|
p = p.to_str
|
671
754
|
next if p == name
|
672
755
|
next if @provides.include?(name)
|
673
756
|
|
674
|
-
@@provides[p] = self
|
757
|
+
@@provides[p] = self
|
675
758
|
|
676
|
-
if Autobuild.verbose
|
677
|
-
Autobuild.message "#{name} provides #{p}"
|
678
|
-
end
|
759
|
+
Autobuild.message "#{name} provides #{p}" if Autobuild.verbose
|
679
760
|
|
680
761
|
task p => name
|
681
762
|
task "#{p}-import" => "#{name}-import"
|
@@ -688,13 +769,11 @@ def provides(*packages)
|
|
688
769
|
# Iterates on all available packages
|
689
770
|
# if with_provides is true, includes the list
|
690
771
|
# of package aliases
|
691
|
-
def self.each(with_provides = false, &
|
692
|
-
|
693
|
-
return enum_for(:each, with_provides)
|
694
|
-
end
|
772
|
+
def self.each(with_provides = false, &block)
|
773
|
+
return enum_for(:each, with_provides) unless block
|
695
774
|
|
696
|
-
@@packages.each(&
|
697
|
-
@@provides.each(&
|
775
|
+
@@packages.each(&block)
|
776
|
+
@@provides.each(&block) if with_provides
|
698
777
|
end
|
699
778
|
|
700
779
|
# Gets a package from its name
|
@@ -719,7 +798,7 @@ def parallel_build_level=(value)
|
|
719
798
|
end
|
720
799
|
|
721
800
|
# Returns the level of parallelism authorized during the build for this
|
722
|
-
# particular package. If not set, defaults to the system-wide option
|
801
|
+
# particular package. If not set, defaults to the system-wide option
|
723
802
|
# (Autobuild.parallel_build_level and Autobuild.parallel_build_level=).
|
724
803
|
#
|
725
804
|
# The default value is the number of CPUs on this system.
|
@@ -740,7 +819,6 @@ def working_directory
|
|
740
819
|
def in_dir(directory)
|
741
820
|
@in_dir_stack << directory
|
742
821
|
yield
|
743
|
-
|
744
822
|
ensure
|
745
823
|
@in_dir_stack.pop
|
746
824
|
end
|
@@ -754,35 +832,36 @@ def disable_phases(*phases)
|
|
754
832
|
phases.each do |phase|
|
755
833
|
task "#{name}-#{phase}"
|
756
834
|
t = Rake::Task["#{name}-#{phase}"]
|
757
|
-
t.disable
|
835
|
+
t.disable
|
758
836
|
end
|
759
837
|
end
|
760
838
|
|
761
839
|
# Make sure that this package will be ignored in the build
|
762
840
|
def disable(phases = Autobuild.all_phases)
|
763
841
|
@disabled = true
|
764
|
-
disable_phases(*phases)
|
765
|
-
task(installstamp)
|
766
|
-
t = Rake::Task[installstamp]
|
767
|
-
t.disable!
|
768
842
|
end
|
769
843
|
|
770
844
|
def utility(utility_name)
|
771
|
-
utilities[utility_name] ||= Autobuild.create_utility(utility_name, self)
|
845
|
+
utilities[utility_name.to_s] ||= Autobuild.create_utility(utility_name, self)
|
772
846
|
end
|
773
847
|
|
848
|
+
def respond_to_missing?(name, _include_all)
|
849
|
+
utilities.key?(name.to_s)
|
850
|
+
end
|
774
851
|
|
775
|
-
def method_missing(
|
776
|
-
case
|
852
|
+
def method_missing(name, *args, &block)
|
853
|
+
case name.to_s
|
777
854
|
when /(\w+)_utility$/
|
778
855
|
utility_name = $1
|
779
|
-
|
856
|
+
|
857
|
+
unless args.empty?
|
780
858
|
raise ArgumentError, "expected 0 arguments and got #{args.size}"
|
781
859
|
end
|
860
|
+
|
782
861
|
begin
|
783
862
|
return utility(utility_name)
|
784
863
|
rescue ArgumentError => e
|
785
|
-
raise NoMethodError.new(
|
864
|
+
raise NoMethodError.new(name), e.message, e.backtrace
|
786
865
|
end
|
787
866
|
end
|
788
867
|
super
|
@@ -797,4 +876,3 @@ def self.package_set(spec)
|
|
797
876
|
end
|
798
877
|
end
|
799
878
|
end
|
800
|
-
|