ivy4r 0.9.14 → 0.9.15
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/History.txt +0 -7
- data/lib/buildr/ivy_extension.rb +703 -701
- data/lib/ivy4r.rb +1 -1
- metadata +2 -2
data/History.txt
CHANGED
@@ -1,10 +1,3 @@
|
|
1
|
-
=== 0.9.14 / 2010-03-16
|
2
|
-
|
3
|
-
* Fix for circular build dependency errors in buildr thanks to Pepijn Van Eeckhoudt for the patch.
|
4
|
-
The culprit is the call to Buildr.projects in add_copy_tasks_for_publish. This can cause a call
|
5
|
-
to project.invoke on the project being defined itself. Buildr.projects should not be called from
|
6
|
-
before/after define callbacks as Pepijn found out from the Buildr developers.
|
7
|
-
|
8
1
|
=== 0.9.13 / 2010-02-16
|
9
2
|
|
10
3
|
* Fix problems with Facets and ActiveSupport. We now only include the required core extensions,
|
data/lib/buildr/ivy_extension.rb
CHANGED
@@ -1,701 +1,703 @@
|
|
1
|
-
require 'ivy4r'
|
2
|
-
|
3
|
-
module Buildr
|
4
|
-
module Ivy
|
5
|
-
|
6
|
-
class << self
|
7
|
-
def setting(*keys)
|
8
|
-
setting = Buildr.settings.build['ivy']
|
9
|
-
keys.each { |key| setting = setting[key] unless setting.nil? }
|
10
|
-
setting
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
class IvyConfig
|
15
|
-
TARGETS = [:compile, :test, :package]
|
16
|
-
TYPES = [:conf, :type, :include, :exclude]
|
17
|
-
|
18
|
-
attr_accessor :extension_dir, :resolved
|
19
|
-
|
20
|
-
attr_reader :post_resolve_task_list
|
21
|
-
|
22
|
-
# Hash of all artifacts to publish with mapping from artifact name to ivy publish name
|
23
|
-
attr_reader :publish_mappings
|
24
|
-
|
25
|
-
# Store the current project and initialize ivy ant wrapper
|
26
|
-
def initialize(project)
|
27
|
-
@project = project
|
28
|
-
if project.parent.nil?
|
29
|
-
@extension_dir = @project.base_dir
|
30
|
-
@post_resolve_task_list = []
|
31
|
-
else
|
32
|
-
@extension_dir = @project.parent.ivy.extension_dir
|
33
|
-
@base_ivy = @project.parent.ivy unless own_file?
|
34
|
-
end
|
35
|
-
@target_config = Hash.new do
|
36
|
-
|hash, key| hash[key] = {}
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def enabled?
|
41
|
-
@enabled ||= Ivy.setting('enabled') || true
|
42
|
-
end
|
43
|
-
|
44
|
-
def own_file?
|
45
|
-
@own_file ||= File.exists?(@project.path_to(file))
|
46
|
-
end
|
47
|
-
|
48
|
-
# Returns the correct ivy4r instance to use, if project has its own ivy file uses the ivy file
|
49
|
-
# of project, if not uses the ivy file of parent project.
|
50
|
-
# Use this for low-level access to ivy functions as needed, i.e. in +post_resolve+
|
51
|
-
def ivy4r
|
52
|
-
unless @ivy4r
|
53
|
-
if own_file?
|
54
|
-
@ivy4r = ::Ivy4r.new(@project.ant('ivy'))
|
55
|
-
@ivy4r.lib_dir = lib_dir if lib_dir
|
56
|
-
@ivy4r.project_dir = @extension_dir
|
57
|
-
else
|
58
|
-
@ivy4r = @project.parent.ivy.ivy4r
|
59
|
-
end
|
60
|
-
end
|
61
|
-
@ivy4r
|
62
|
-
end
|
63
|
-
|
64
|
-
# Returns name of the project the ivy file belongs to.
|
65
|
-
def file_project
|
66
|
-
own_file? ? @project : @base_ivy.file_project
|
67
|
-
end
|
68
|
-
|
69
|
-
# Returns the artifacts for given configurations as array
|
70
|
-
# this is a post resolve task.
|
71
|
-
# the arguments are checked for the following:
|
72
|
-
# 1. if an Hash is given :conf is used for confs and :type is used for types
|
73
|
-
# 2. if exactly two arrays are given args[0] is used for confs and args[1] is used for types
|
74
|
-
# 3. if not exactly two arrays all args are used as confs
|
75
|
-
def deps(*args)
|
76
|
-
if args.size == 1 && args[0].kind_of?(Hash)
|
77
|
-
confs, types = [args[0][:conf]].flatten, [args[0][:type]].flatten
|
78
|
-
elsif args.size == 2 && args[0].kind_of?(Array) && args[1].kind_of?(Array)
|
79
|
-
confs, types = args[0], args[1]
|
80
|
-
else
|
81
|
-
confs, types = args.flatten, []
|
82
|
-
end
|
83
|
-
|
84
|
-
[confs, types].each do |t|
|
85
|
-
t.reject! {|c| c.nil? || c.blank? }
|
86
|
-
end
|
87
|
-
|
88
|
-
unless confs.empty?
|
89
|
-
pathid = "ivy.deps." + confs.join('.') + '.' + types.join('.')
|
90
|
-
params = {:conf => confs.join(','), :pathid => pathid}
|
91
|
-
params[:type] = types.join(',') unless types.nil? || types.size == 0
|
92
|
-
|
93
|
-
ivy4r.cachepath params
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
# Returns ivy info for configured ivy file using a new ivy4r instance.
|
98
|
-
def info
|
99
|
-
if @base_ivy
|
100
|
-
@base_ivy.info
|
101
|
-
else
|
102
|
-
ivy4r.settings :id => 'ivy.info.settingsref'
|
103
|
-
result = ivy4r.info :file => file, :settingsRef => 'ivy.info.settingsref'
|
104
|
-
@ivy4r = nil
|
105
|
-
result
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
# Configures the ivy instance with additional properties and loading the settings file if it was provided
|
110
|
-
def configure
|
111
|
-
if @base_ivy
|
112
|
-
@base_ivy.configure
|
113
|
-
else
|
114
|
-
unless @configured
|
115
|
-
ivy4r.property['ivy.status'] = status
|
116
|
-
ivy4r.property['ivy.home'] = home
|
117
|
-
properties.each {|key, value| ivy4r.property[key.to_s] = value }
|
118
|
-
@configured = ivy4r.settings :file => settings if settings
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
# Resolves the configured file once.
|
124
|
-
def __resolve__
|
125
|
-
if @base_ivy
|
126
|
-
@base_ivy.__resolve__
|
127
|
-
else
|
128
|
-
unless @resolved
|
129
|
-
@resolved = ivy4r.resolve :file => file
|
130
|
-
@project.send(:info, "Calling '#{post_resolve_tasks.size}' post_resolve tasks for '#{@project.name}'")
|
131
|
-
post_resolve_tasks.each { |p| p.call(self) }
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
# Returns the additional infos for the manifest file.
|
137
|
-
def manifest
|
138
|
-
if @base_ivy
|
139
|
-
@base_ivy.manifest
|
140
|
-
else
|
141
|
-
{
|
142
|
-
'organisation' => @resolved['ivy.organisation'],
|
143
|
-
'module' => @resolved['ivy.organisation'],
|
144
|
-
'revision' => revision
|
145
|
-
}
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
# Creates the standard ivy dependency report
|
150
|
-
def report
|
151
|
-
ivy4r.report :todir => report_dir
|
152
|
-
end
|
153
|
-
|
154
|
-
# Cleans the ivy cache
|
155
|
-
def cleancache
|
156
|
-
ivy4r.cleancache
|
157
|
-
end
|
158
|
-
|
159
|
-
|
160
|
-
# Publishs the project as defined in ivy file if it has not been published already
|
161
|
-
def __publish__
|
162
|
-
if @base_ivy
|
163
|
-
@base_ivy.__publish__
|
164
|
-
else
|
165
|
-
unless @published
|
166
|
-
options = {:status => status, :pubrevision => revision, :artifactspattern => "#{publish_from}/[artifact].[ext]"}
|
167
|
-
options = publish_options * options
|
168
|
-
ivy4r.publish options
|
169
|
-
@published = true
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
def home
|
175
|
-
@ivy_home_dir ||= Ivy.setting('home.dir') || "#{@extension_dir}/ivy-home"
|
176
|
-
end
|
177
|
-
|
178
|
-
def lib_dir
|
179
|
-
@lib_dir ||= Ivy.setting('lib.dir')
|
180
|
-
end
|
181
|
-
|
182
|
-
def settings
|
183
|
-
@settings ||= Ivy.setting('settings.file') || "#{@extension_dir}/ant-scripts/ivysettings.xml"
|
184
|
-
end
|
185
|
-
|
186
|
-
def file
|
187
|
-
@ivy_file ||= Ivy.setting('ivy.file') || 'ivy.xml'
|
188
|
-
end
|
189
|
-
|
190
|
-
# Sets the revision to use for the project, this is useful for development revisions that
|
191
|
-
# have an appended timestamp or any other dynamic revisioning.
|
192
|
-
#
|
193
|
-
# To set a different revision this method can be used in different ways.
|
194
|
-
# 1. project.ivy.revision(revision) to set the revision directly
|
195
|
-
# 2. project.ivy.revision { |ivy| [calculate revision] } use the block for dynamic
|
196
|
-
# calculation of the revision. You can access ivy4r via <tt>ivy.ivy4r.[method]</tt>
|
197
|
-
def revision(*revision, &block)
|
198
|
-
raise "Invalid call with parameters and block!" if revision.size > 0 && block
|
199
|
-
if revision.empty? && block.nil?
|
200
|
-
if @revision_calc
|
201
|
-
@revision ||= @revision_calc.call(self)
|
202
|
-
else
|
203
|
-
@revision ||= @project.version
|
204
|
-
end
|
205
|
-
elsif block.nil?
|
206
|
-
raise "revision value invalid #{revision.join(', ')}" unless revision.size == 1
|
207
|
-
@revision = revision[0]
|
208
|
-
self
|
209
|
-
else
|
210
|
-
@revision_calc = block
|
211
|
-
self
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
# Sets the status to use for the project, this is useful for custom status handling
|
216
|
-
# like integration, alpha, gold.
|
217
|
-
#
|
218
|
-
# To set a different status this method can be used in different ways.
|
219
|
-
# 1. project.ivy.status(status) to set the status directly
|
220
|
-
# 2. project.ivy.status { |ivy| [calculate status] } use the block for dynamic
|
221
|
-
# calculation of the status. You can access ivy4r via <tt>ivy.ivy4r.[method]</tt>
|
222
|
-
def status(*status, &block)
|
223
|
-
raise "Invalid call with parameters and block!" if status.size > 0 && block
|
224
|
-
if status.empty? && block.nil?
|
225
|
-
if @status_calc
|
226
|
-
@status ||= @status_calc.call(self)
|
227
|
-
else
|
228
|
-
@status ||= Ivy.setting('status') || 'integration'
|
229
|
-
end
|
230
|
-
elsif status.empty? && block.nil?
|
231
|
-
raise "status value invalid #{status.join(', ')}" unless status.size == 1
|
232
|
-
@status = status[0]
|
233
|
-
self
|
234
|
-
else
|
235
|
-
@status_calc = block
|
236
|
-
self
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
# Sets the publish options to use for the project. The options are merged with the default
|
241
|
-
# options including value set via #publish_from and overwrite all of them.
|
242
|
-
#
|
243
|
-
# To set the options this method can be used in different ways.
|
244
|
-
# 1. project.ivy.publish_options(options) to set the options directly
|
245
|
-
# 2. project.ivy.publish_options { |ivy| [calculate options] } use the block for dynamic
|
246
|
-
# calculation of options. You can access ivy4r via <tt>ivy.ivy4r.[method]</tt>
|
247
|
-
def publish_options(*options, &block)
|
248
|
-
raise "Invalid call with parameters and block!" if options.size > 0 && block
|
249
|
-
if options.empty? && block.nil?
|
250
|
-
if @publish_options_calc
|
251
|
-
@publish_options ||= @publish_options_calc.call(self)
|
252
|
-
else
|
253
|
-
@publish_options ||= Ivy.setting('publish.options')
|
254
|
-
end
|
255
|
-
else
|
256
|
-
raise "Could not set 'publish_options' for '#{@project.name}' without own ivy file!" unless own_file?
|
257
|
-
if options.size > 0 && block.nil?
|
258
|
-
raise "publish options value invalid #{options.join(', ')}" unless options.size == 1
|
259
|
-
@publish_options = options[0]
|
260
|
-
self
|
261
|
-
else
|
262
|
-
@publish_options_calc = block
|
263
|
-
self
|
264
|
-
end
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
# Sets the additional properties for the ivy process use a Hash with the properties to set.
|
269
|
-
def properties(*properties)
|
270
|
-
if properties.empty?
|
271
|
-
@properties ||= {}
|
272
|
-
else
|
273
|
-
raise "properties value invalid #{properties.join(', ')}" unless properties.size == 1
|
274
|
-
@properties = properties[0]
|
275
|
-
self
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
# Sets the local repository for ivy files
|
280
|
-
def local_repository(*local_repository)
|
281
|
-
if local_repository.empty?
|
282
|
-
if own_file?
|
283
|
-
@local_repository ||= Ivy.setting('local.repository.dir') || "#{home}/repository"
|
284
|
-
else
|
285
|
-
@project.parent.ivy.local_repository
|
286
|
-
end
|
287
|
-
else
|
288
|
-
raise "Could not set 'local_repository' for '#{@project.name}' without own ivy file!" unless own_file?
|
289
|
-
raise "local_repository value invalid #{local_repository.join(', ')}" unless local_repository.size == 1
|
290
|
-
@local_repository = local_repository[0]
|
291
|
-
self
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
|
-
# :call-seq:
|
296
|
-
# ivy.publish(package(:jar) => 'new_name_without_version_number.jar')
|
297
|
-
# #deprecated! ivy.name(package(:jar) => 'new_name_without_version_number.jar')
|
298
|
-
#
|
299
|
-
# Maps a package to a different name for publishing. This name is used instead of the default name
|
300
|
-
# for publishing use a hash with the +package+ as key and the newly mapped name as value. I.e.
|
301
|
-
# <tt>ivy.name(package(:jar) => 'new_name_without_version_number.jar')</tt>
|
302
|
-
# Note that this method is additive, a second call adds the names to the first.
|
303
|
-
def publish(*publish_mappings)
|
304
|
-
if publish_mappings.empty?
|
305
|
-
@publish_mappings ||= {}
|
306
|
-
else
|
307
|
-
raise "publish_mappings value invalid #{publish_mappings.join(', ')}" unless publish_mappings.size == 1
|
308
|
-
@publish_mappings = @publish_mappings ? @publish_mappings + publish_mappings[0] : publish_mappings[0].dup
|
309
|
-
self
|
310
|
-
end
|
311
|
-
end
|
312
|
-
|
313
|
-
def name(*args)
|
314
|
-
puts "name(*args) is deprecated use publish(*args)!"
|
315
|
-
publish(*args)
|
316
|
-
end
|
317
|
-
|
318
|
-
# Sets the directory to publish artifacts from.
|
319
|
-
def publish_from(*publish_dir)
|
320
|
-
if publish_dir.empty?
|
321
|
-
if own_file?
|
322
|
-
@publish_from ||= Ivy.setting('publish.from') || @project.path_to(:target)
|
323
|
-
else
|
324
|
-
@project.parent.ivy.publish_from
|
325
|
-
end
|
326
|
-
else
|
327
|
-
raise "Could not set 'publish_from' for '#{@project.name}' without own ivy file!" unless own_file?
|
328
|
-
raise "publish_from value invalid #{publish_dir.join(', ')}" unless publish_dir.size == 1
|
329
|
-
@publish_from = publish_dir[0]
|
330
|
-
self
|
331
|
-
end
|
332
|
-
end
|
333
|
-
|
334
|
-
# Sets the directory to create dependency reports in.
|
335
|
-
def report_dir(*report_dir)
|
336
|
-
if report_dir.empty?
|
337
|
-
if own_file?
|
338
|
-
@report_dir ||= Ivy.setting('report.dir') || @project.path_to(:reports, 'ivy')
|
339
|
-
else
|
340
|
-
@project.parent.ivy.report_dir
|
341
|
-
end
|
342
|
-
else
|
343
|
-
raise "Could not set 'report_dir' for '#{@project.name}' without own ivy file!" unless own_file?
|
344
|
-
raise "publish_from value invalid #{report_dir.join(', ')}" unless report_dir.size == 1
|
345
|
-
@report_dir = report_dir[0]
|
346
|
-
self
|
347
|
-
end
|
348
|
-
end
|
349
|
-
|
350
|
-
# Adds given block as post resolve action that is executed directly after #resolve has been called.
|
351
|
-
# Yields this ivy config object into block.
|
352
|
-
# <tt>project.ivy.post_resolve { |ivy| p "all deps:" + ivy.deps('all').join(", ") }</tt>
|
353
|
-
def post_resolve(&block)
|
354
|
-
post_resolve_tasks << block if block
|
355
|
-
end
|
356
|
-
|
357
|
-
# Filter artifacts for given configuration with provided filter values, this is a post resolve
|
358
|
-
# task like #deps.
|
359
|
-
# <tt>project.ivy.filter('server', 'client', :include => /b.*.jar/, :exclude => [/a\.jar/, /other.*\.jar/])</tt>
|
360
|
-
def filter(*confs)
|
361
|
-
filter = confs.last.kind_of?(Hash) ? confs.pop : {}
|
362
|
-
unless (filter.keys - (TYPES - [:conf])).empty?
|
363
|
-
raise ArgumentError, "Invalid filter use :include and/or :exclude only: given #{filter.keys.inspect}"
|
364
|
-
end
|
365
|
-
includes, excludes, types = filter[:include] || [], filter[:exclude] || [], filter[:type] || []
|
366
|
-
|
367
|
-
artifacts = deps(confs.flatten, types.flatten)
|
368
|
-
if artifacts
|
369
|
-
artifacts = artifacts.find_all do |lib|
|
370
|
-
lib = File.basename(lib)
|
371
|
-
includes = includes.reject {|i| i.nil? || i.blank? }
|
372
|
-
should_include = includes.empty? || includes.any? {|include| include === lib }
|
373
|
-
should_include && !excludes.any? {|exclude| exclude === lib}
|
374
|
-
end
|
375
|
-
end
|
376
|
-
|
377
|
-
artifacts
|
378
|
-
end
|
379
|
-
|
380
|
-
# :call-seq:
|
381
|
-
# for types:
|
382
|
-
# project.ivy.include(:compile => [/\.jar/, /\.gz/], :package => 'cglib.jar')
|
383
|
-
# project.ivy.exclude(:test => 'cglib.jar')
|
384
|
-
# project.ivy.conf(:compile => 'compile', :test => 'test', :package => 'prod')
|
385
|
-
# for targets:
|
386
|
-
# project.ivy.compile(:conf => 'compile', :exclude => /cglib.jar/)
|
387
|
-
# project.ivy.test(:conf => 'test')
|
388
|
-
# project.ivy.package(:conf => 'prod', :include => /.*.jar/, :exclude => /cglib.jar/)
|
389
|
-
# or verbose:
|
390
|
-
# project.ivy.compile_conf or project.ivy.conf_compile
|
391
|
-
# project.ivy.compile_include or project.ivy.include_compile
|
392
|
-
# the same for the other possible options.
|
393
|
-
#
|
394
|
-
# Uses #method_missing to handle the options.
|
395
|
-
# Generic handling of settings for +target+ and +type+. All calls in the form
|
396
|
-
# <tt>target_type({})</tt> or <tt>type_target({})</tt> are handled via this method see
|
397
|
-
# #TARGETS #TYPES for more information about valid targets and types.
|
398
|
-
def method_missing(methodname, *args, &block)
|
399
|
-
if block.nil? && valid_config_call?(methodname)
|
400
|
-
target, type = target(methodname), type(methodname)
|
401
|
-
if target && type
|
402
|
-
handle_variable(target, type, *args)
|
403
|
-
elsif target && args.size == 1 && args.last.kind_of?(Hash)
|
404
|
-
args[0].each { |type, value| handle_variable(target, type, *value) }
|
405
|
-
self
|
406
|
-
elsif type && args.size == 1 && args.last.kind_of?(Hash)
|
407
|
-
args[0].each { |target, value| handle_variable(target, type, *value) }
|
408
|
-
self
|
409
|
-
else
|
410
|
-
raise "Could not recognize config call for method '#{methodname}', args=#{args.inspect}"
|
411
|
-
end
|
412
|
-
else
|
413
|
-
super.method_missing(methodname, *args, &block)
|
414
|
-
end
|
415
|
-
end
|
416
|
-
|
417
|
-
private
|
418
|
-
def target(targets)
|
419
|
-
t = targets.to_s.split('_').find { |target| TARGETS.member? target.to_sym }
|
420
|
-
t ? t.to_sym : nil
|
421
|
-
end
|
422
|
-
|
423
|
-
def type(types)
|
424
|
-
t = types.to_s.split('_').find { |type| TYPES.member? type.to_sym }
|
425
|
-
t ? t.to_sym : nil
|
426
|
-
end
|
427
|
-
|
428
|
-
def valid_config_call?(method_name)
|
429
|
-
valid_calls = []
|
430
|
-
TYPES.each do|type|
|
431
|
-
TARGETS.each do|target|
|
432
|
-
valid_calls << type.to_s << target.to_s << "#{type}_#{target}" << "#{target}_#{type}"
|
433
|
-
end
|
434
|
-
end
|
435
|
-
valid_calls.member? method_name.to_s
|
436
|
-
end
|
437
|
-
|
438
|
-
# Sets a variable for given basename and type to given values. If values are empty returns the
|
439
|
-
# current value.
|
440
|
-
# I.e. <tt>handle_variable(:package, :include, /blua.*\.jar/, /da.*\.jar/)</tt>
|
441
|
-
def handle_variable(target, type, *values)
|
442
|
-
unless TARGETS.member?(target) && TYPES.member?(type)
|
443
|
-
raise ArgumentError, "Unknown config value for target #{target.inspect} and type #{type.inspect}"
|
444
|
-
end
|
445
|
-
if values.empty?
|
446
|
-
@target_config[target][type] ||= [Ivy.setting("#{target.to_s}.#{type.to_s}") || ''].flatten.uniq
|
447
|
-
else
|
448
|
-
@target_config[target][type] = [values].flatten.uniq
|
449
|
-
self
|
450
|
-
end
|
451
|
-
end
|
452
|
-
|
453
|
-
def post_resolve_tasks
|
454
|
-
@base_ivy ? @base_ivy.post_resolve_task_list : post_resolve_task_list
|
455
|
-
end
|
456
|
-
end
|
457
|
-
|
458
|
-
=begin rdoc
|
459
|
-
The Ivy Buildr extension adding the new tasks for ivy.
|
460
|
-
|
461
|
-
To use ivy in a +buildfile+ do something like:
|
462
|
-
ENV['BUILDR_EXT_DIR'] ||= '../Ivy'
|
463
|
-
require 'buildr/ivy_extension'
|
464
|
-
define 'ivy_project' do
|
465
|
-
[...]
|
466
|
-
ivy.compile_conf('compile').test_conf('test').package_conf('prod', 'server')
|
467
|
-
[...]
|
468
|
-
end
|
469
|
-
|
470
|
-
- This will add the +compile+ configuration to compile and test tasks
|
471
|
-
- Add the +test+ configuration to test compilation and execution
|
472
|
-
- include the artifacts from +prod+ and +server+ to any generated war or ear
|
473
|
-
- The ENV variable is needed to automatically configure the load path for ivy libs.
|
474
|
-
It assumes that you have the following dir structure <tt>[BUILDR_EXT_DIR]/ivy-home/jars</tt>
|
475
|
-
|
476
|
-
For more configuration options see IvyConfig.
|
477
|
-
=end
|
478
|
-
module IvyExtension
|
479
|
-
include Buildr::Extension
|
480
|
-
|
481
|
-
class << self
|
482
|
-
|
483
|
-
def add_ivy_deps_to_java_tasks(project)
|
484
|
-
resolve_target = project.ivy.file_project.task('ivy:resolve')
|
485
|
-
project.task :compiledeps => resolve_target do
|
486
|
-
includes = project.ivy.compile_include
|
487
|
-
excludes = project.ivy.compile_exclude
|
488
|
-
types = project.ivy.compile_type
|
489
|
-
confs = [project.ivy.compile_conf].flatten
|
490
|
-
if deps = project.ivy.filter(confs, :type => types, :include => includes, :exclude => excludes)
|
491
|
-
project.compile.with [deps, project.compile.dependencies].flatten
|
492
|
-
sort_dependencies(project.compile.dependencies, deps, project.path_to(''))
|
493
|
-
info "Ivy adding compile dependencies '#{confs.join(', ')}' to project '#{project.name}'"
|
494
|
-
end
|
495
|
-
end
|
496
|
-
|
497
|
-
project.task :compile => "#{project.name}:compiledeps"
|
498
|
-
|
499
|
-
project.task :testdeps => resolve_target do
|
500
|
-
includes = project.ivy.test_include
|
501
|
-
excludes = project.ivy.test_exclude
|
502
|
-
types = project.ivy.test_type
|
503
|
-
confs = [project.ivy.test_conf, project.ivy.compile_conf].flatten.uniq
|
504
|
-
if deps = project.ivy.filter(confs, :type => types, :include => includes, :exclude => excludes)
|
505
|
-
project.test.with [deps, project.test.dependencies].flatten
|
506
|
-
sort_dependencies(project.test.dependencies, deps, project.path_to(''))
|
507
|
-
sort_dependencies(project.test.compile.dependencies, deps, project.path_to(''))
|
508
|
-
info "Ivy adding test dependencies '#{confs.join(', ')}' to project '#{project.name}'"
|
509
|
-
end
|
510
|
-
end
|
511
|
-
project.task "test:compile" => "#{project.name}:testdeps"
|
512
|
-
|
513
|
-
project.task :javadocdeps => resolve_target do
|
514
|
-
confs = [project.ivy.test_conf, project.ivy.compile_conf].flatten.uniq
|
515
|
-
if deps = project.ivy.deps(confs)
|
516
|
-
project.javadoc.with deps
|
517
|
-
info "Ivy adding javadoc dependencies '#{confs.join(', ')}' to project '#{project.name}'"
|
518
|
-
end
|
519
|
-
end
|
520
|
-
project.task :javadoc => "#{project.name}:javadocdeps"
|
521
|
-
|
522
|
-
[project.task(:eclipse), project.task(:idea), project.task(:idea7x)].each do |task|
|
523
|
-
task.prerequisites.each{|p| p.enhance ["#{project.name}:compiledeps", "#{project.name}:testdeps"]}
|
524
|
-
end
|
525
|
-
end
|
526
|
-
|
527
|
-
# Sorts the dependencies in #deps replacing the old order.
|
528
|
-
# Sorting is done as follows:
|
529
|
-
# 1. all dependencies that belong to the project identified by #project_path,
|
530
|
-
# .i.e. instrumented-classes, resources in the order the are contained in the array
|
531
|
-
# 2. all ivy dependencies identified by #ivy_deps
|
532
|
-
# 3. all dependencies added automatically by buildr
|
533
|
-
def sort_dependencies(deps, ivy_deps, project_path)
|
534
|
-
old_deps = deps.dup
|
535
|
-
belongs_to_project = /#{project_path}/
|
536
|
-
deps.sort! do |a, b|
|
537
|
-
a_belongs_to_project = belongs_to_project.match(a.to_s)
|
538
|
-
b_belongs_to_project = belongs_to_project.match(b.to_s)
|
539
|
-
a_ivy = ivy_deps.member? a
|
540
|
-
b_ivy = ivy_deps.member? b
|
541
|
-
|
542
|
-
if a_belongs_to_project && !b_belongs_to_project
|
543
|
-
-1
|
544
|
-
elsif !a_belongs_to_project && b_belongs_to_project
|
545
|
-
1
|
546
|
-
elsif a_ivy && !b_ivy
|
547
|
-
-1
|
548
|
-
elsif !a_ivy && b_ivy
|
549
|
-
1
|
550
|
-
else
|
551
|
-
old_deps.index(a) <=> old_deps.index(b)
|
552
|
-
end
|
553
|
-
end
|
554
|
-
end
|
555
|
-
|
556
|
-
def add_manifest_to_distributeables(project)
|
557
|
-
pkgs = project.packages.find_all { |pkg| ['jar', 'war', 'ear'].member? pkg.type.to_s }
|
558
|
-
pkgs.each do |pkg|
|
559
|
-
name = "#{pkg.name}manifest"
|
560
|
-
task = project.task name => project.ivy.file_project.task('ivy:resolve') do
|
561
|
-
pkg.with :manifest => pkg.manifest.merge(project.manifest.merge(project.ivy.manifest))
|
562
|
-
info "Adding manifest entries to package '#{pkg.name}'"
|
563
|
-
end
|
564
|
-
project.task :build => task
|
565
|
-
end
|
566
|
-
end
|
567
|
-
|
568
|
-
def add_prod_libs_to_distributeables(project)
|
569
|
-
pkgs = project.packages.find_all { |pkg| ['war'].member? pkg.type.to_s }
|
570
|
-
pkgs.each do |pkg|
|
571
|
-
task = project.task "#{pkg.name}deps" => project.ivy.file_project.task('ivy:resolve') do
|
572
|
-
includes = project.ivy.package_include
|
573
|
-
excludes = project.ivy.package_exclude
|
574
|
-
types = project.ivy.package_type
|
575
|
-
confs = project.ivy.package_conf
|
576
|
-
if deps = project.ivy.filter(confs, :type => types, :include => includes, :exclude => excludes)
|
577
|
-
pkg.with :libs => [deps, pkg.libs].flatten
|
578
|
-
info "Adding production libs from conf '#{confs.join(', ')}' to WAR '#{pkg.name}' in project '#{project.name}'"
|
579
|
-
end
|
580
|
-
end
|
581
|
-
project.task :build => task
|
582
|
-
end
|
583
|
-
|
584
|
-
pkgs = project.packages.find_all { |pkg| ['ear'].member? pkg.type.to_s }
|
585
|
-
pkgs.each do |pkg|
|
586
|
-
task = project.task "#{pkg.name}deps" => project.ivy.file_project.task('ivy:resolve') do
|
587
|
-
includes = project.ivy.package_include
|
588
|
-
excludes = project.ivy.package_exclude
|
589
|
-
types = project.ivy.package_type
|
590
|
-
confs = project.ivy.package_conf
|
591
|
-
if deps = project.ivy.filter(confs, :type => types, :include => includes, :exclude => excludes)
|
592
|
-
pkg.add deps, :type => :lib, :path => ''
|
593
|
-
info "Adding production libs from conf '#{confs.join(', ')}' to EAR '#{pkg.name}' in project '#{project.name}'"
|
594
|
-
end
|
595
|
-
end
|
596
|
-
project.task :build => task
|
597
|
-
end
|
598
|
-
end
|
599
|
-
|
600
|
-
def add_copy_tasks_for_publish(project)
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
IvyExtension.
|
645
|
-
IvyExtension.
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
end
|
1
|
+
require 'ivy4r'
|
2
|
+
|
3
|
+
module Buildr
|
4
|
+
module Ivy
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def setting(*keys)
|
8
|
+
setting = Buildr.settings.build['ivy']
|
9
|
+
keys.each { |key| setting = setting[key] unless setting.nil? }
|
10
|
+
setting
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class IvyConfig
|
15
|
+
TARGETS = [:compile, :test, :package]
|
16
|
+
TYPES = [:conf, :type, :include, :exclude]
|
17
|
+
|
18
|
+
attr_accessor :extension_dir, :resolved
|
19
|
+
|
20
|
+
attr_reader :post_resolve_task_list
|
21
|
+
|
22
|
+
# Hash of all artifacts to publish with mapping from artifact name to ivy publish name
|
23
|
+
attr_reader :publish_mappings
|
24
|
+
|
25
|
+
# Store the current project and initialize ivy ant wrapper
|
26
|
+
def initialize(project)
|
27
|
+
@project = project
|
28
|
+
if project.parent.nil?
|
29
|
+
@extension_dir = @project.base_dir
|
30
|
+
@post_resolve_task_list = []
|
31
|
+
else
|
32
|
+
@extension_dir = @project.parent.ivy.extension_dir
|
33
|
+
@base_ivy = @project.parent.ivy unless own_file?
|
34
|
+
end
|
35
|
+
@target_config = Hash.new do
|
36
|
+
|hash, key| hash[key] = {}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def enabled?
|
41
|
+
@enabled ||= Ivy.setting('enabled') || true
|
42
|
+
end
|
43
|
+
|
44
|
+
def own_file?
|
45
|
+
@own_file ||= File.exists?(@project.path_to(file))
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns the correct ivy4r instance to use, if project has its own ivy file uses the ivy file
|
49
|
+
# of project, if not uses the ivy file of parent project.
|
50
|
+
# Use this for low-level access to ivy functions as needed, i.e. in +post_resolve+
|
51
|
+
def ivy4r
|
52
|
+
unless @ivy4r
|
53
|
+
if own_file?
|
54
|
+
@ivy4r = ::Ivy4r.new(@project.ant('ivy'))
|
55
|
+
@ivy4r.lib_dir = lib_dir if lib_dir
|
56
|
+
@ivy4r.project_dir = @extension_dir
|
57
|
+
else
|
58
|
+
@ivy4r = @project.parent.ivy.ivy4r
|
59
|
+
end
|
60
|
+
end
|
61
|
+
@ivy4r
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns name of the project the ivy file belongs to.
|
65
|
+
def file_project
|
66
|
+
own_file? ? @project : @base_ivy.file_project
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns the artifacts for given configurations as array
|
70
|
+
# this is a post resolve task.
|
71
|
+
# the arguments are checked for the following:
|
72
|
+
# 1. if an Hash is given :conf is used for confs and :type is used for types
|
73
|
+
# 2. if exactly two arrays are given args[0] is used for confs and args[1] is used for types
|
74
|
+
# 3. if not exactly two arrays all args are used as confs
|
75
|
+
def deps(*args)
|
76
|
+
if args.size == 1 && args[0].kind_of?(Hash)
|
77
|
+
confs, types = [args[0][:conf]].flatten, [args[0][:type]].flatten
|
78
|
+
elsif args.size == 2 && args[0].kind_of?(Array) && args[1].kind_of?(Array)
|
79
|
+
confs, types = args[0], args[1]
|
80
|
+
else
|
81
|
+
confs, types = args.flatten, []
|
82
|
+
end
|
83
|
+
|
84
|
+
[confs, types].each do |t|
|
85
|
+
t.reject! {|c| c.nil? || c.blank? }
|
86
|
+
end
|
87
|
+
|
88
|
+
unless confs.empty?
|
89
|
+
pathid = "ivy.deps." + confs.join('.') + '.' + types.join('.')
|
90
|
+
params = {:conf => confs.join(','), :pathid => pathid}
|
91
|
+
params[:type] = types.join(',') unless types.nil? || types.size == 0
|
92
|
+
|
93
|
+
ivy4r.cachepath params
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns ivy info for configured ivy file using a new ivy4r instance.
|
98
|
+
def info
|
99
|
+
if @base_ivy
|
100
|
+
@base_ivy.info
|
101
|
+
else
|
102
|
+
ivy4r.settings :id => 'ivy.info.settingsref'
|
103
|
+
result = ivy4r.info :file => file, :settingsRef => 'ivy.info.settingsref'
|
104
|
+
@ivy4r = nil
|
105
|
+
result
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Configures the ivy instance with additional properties and loading the settings file if it was provided
|
110
|
+
def configure
|
111
|
+
if @base_ivy
|
112
|
+
@base_ivy.configure
|
113
|
+
else
|
114
|
+
unless @configured
|
115
|
+
ivy4r.property['ivy.status'] = status
|
116
|
+
ivy4r.property['ivy.home'] = home
|
117
|
+
properties.each {|key, value| ivy4r.property[key.to_s] = value }
|
118
|
+
@configured = ivy4r.settings :file => settings if settings
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Resolves the configured file once.
|
124
|
+
def __resolve__
|
125
|
+
if @base_ivy
|
126
|
+
@base_ivy.__resolve__
|
127
|
+
else
|
128
|
+
unless @resolved
|
129
|
+
@resolved = ivy4r.resolve :file => file
|
130
|
+
@project.send(:info, "Calling '#{post_resolve_tasks.size}' post_resolve tasks for '#{@project.name}'")
|
131
|
+
post_resolve_tasks.each { |p| p.call(self) }
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Returns the additional infos for the manifest file.
|
137
|
+
def manifest
|
138
|
+
if @base_ivy
|
139
|
+
@base_ivy.manifest
|
140
|
+
else
|
141
|
+
{
|
142
|
+
'organisation' => @resolved['ivy.organisation'],
|
143
|
+
'module' => @resolved['ivy.organisation'],
|
144
|
+
'revision' => revision
|
145
|
+
}
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# Creates the standard ivy dependency report
|
150
|
+
def report
|
151
|
+
ivy4r.report :todir => report_dir
|
152
|
+
end
|
153
|
+
|
154
|
+
# Cleans the ivy cache
|
155
|
+
def cleancache
|
156
|
+
ivy4r.cleancache
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
# Publishs the project as defined in ivy file if it has not been published already
|
161
|
+
def __publish__
|
162
|
+
if @base_ivy
|
163
|
+
@base_ivy.__publish__
|
164
|
+
else
|
165
|
+
unless @published
|
166
|
+
options = {:status => status, :pubrevision => revision, :artifactspattern => "#{publish_from}/[artifact].[ext]"}
|
167
|
+
options = publish_options * options
|
168
|
+
ivy4r.publish options
|
169
|
+
@published = true
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def home
|
175
|
+
@ivy_home_dir ||= Ivy.setting('home.dir') || "#{@extension_dir}/ivy-home"
|
176
|
+
end
|
177
|
+
|
178
|
+
def lib_dir
|
179
|
+
@lib_dir ||= Ivy.setting('lib.dir')
|
180
|
+
end
|
181
|
+
|
182
|
+
def settings
|
183
|
+
@settings ||= Ivy.setting('settings.file') || "#{@extension_dir}/ant-scripts/ivysettings.xml"
|
184
|
+
end
|
185
|
+
|
186
|
+
def file
|
187
|
+
@ivy_file ||= Ivy.setting('ivy.file') || 'ivy.xml'
|
188
|
+
end
|
189
|
+
|
190
|
+
# Sets the revision to use for the project, this is useful for development revisions that
|
191
|
+
# have an appended timestamp or any other dynamic revisioning.
|
192
|
+
#
|
193
|
+
# To set a different revision this method can be used in different ways.
|
194
|
+
# 1. project.ivy.revision(revision) to set the revision directly
|
195
|
+
# 2. project.ivy.revision { |ivy| [calculate revision] } use the block for dynamic
|
196
|
+
# calculation of the revision. You can access ivy4r via <tt>ivy.ivy4r.[method]</tt>
|
197
|
+
def revision(*revision, &block)
|
198
|
+
raise "Invalid call with parameters and block!" if revision.size > 0 && block
|
199
|
+
if revision.empty? && block.nil?
|
200
|
+
if @revision_calc
|
201
|
+
@revision ||= @revision_calc.call(self)
|
202
|
+
else
|
203
|
+
@revision ||= @project.version
|
204
|
+
end
|
205
|
+
elsif block.nil?
|
206
|
+
raise "revision value invalid #{revision.join(', ')}" unless revision.size == 1
|
207
|
+
@revision = revision[0]
|
208
|
+
self
|
209
|
+
else
|
210
|
+
@revision_calc = block
|
211
|
+
self
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# Sets the status to use for the project, this is useful for custom status handling
|
216
|
+
# like integration, alpha, gold.
|
217
|
+
#
|
218
|
+
# To set a different status this method can be used in different ways.
|
219
|
+
# 1. project.ivy.status(status) to set the status directly
|
220
|
+
# 2. project.ivy.status { |ivy| [calculate status] } use the block for dynamic
|
221
|
+
# calculation of the status. You can access ivy4r via <tt>ivy.ivy4r.[method]</tt>
|
222
|
+
def status(*status, &block)
|
223
|
+
raise "Invalid call with parameters and block!" if status.size > 0 && block
|
224
|
+
if status.empty? && block.nil?
|
225
|
+
if @status_calc
|
226
|
+
@status ||= @status_calc.call(self)
|
227
|
+
else
|
228
|
+
@status ||= Ivy.setting('status') || 'integration'
|
229
|
+
end
|
230
|
+
elsif status.empty? && block.nil?
|
231
|
+
raise "status value invalid #{status.join(', ')}" unless status.size == 1
|
232
|
+
@status = status[0]
|
233
|
+
self
|
234
|
+
else
|
235
|
+
@status_calc = block
|
236
|
+
self
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
# Sets the publish options to use for the project. The options are merged with the default
|
241
|
+
# options including value set via #publish_from and overwrite all of them.
|
242
|
+
#
|
243
|
+
# To set the options this method can be used in different ways.
|
244
|
+
# 1. project.ivy.publish_options(options) to set the options directly
|
245
|
+
# 2. project.ivy.publish_options { |ivy| [calculate options] } use the block for dynamic
|
246
|
+
# calculation of options. You can access ivy4r via <tt>ivy.ivy4r.[method]</tt>
|
247
|
+
def publish_options(*options, &block)
|
248
|
+
raise "Invalid call with parameters and block!" if options.size > 0 && block
|
249
|
+
if options.empty? && block.nil?
|
250
|
+
if @publish_options_calc
|
251
|
+
@publish_options ||= @publish_options_calc.call(self)
|
252
|
+
else
|
253
|
+
@publish_options ||= Ivy.setting('publish.options')
|
254
|
+
end
|
255
|
+
else
|
256
|
+
raise "Could not set 'publish_options' for '#{@project.name}' without own ivy file!" unless own_file?
|
257
|
+
if options.size > 0 && block.nil?
|
258
|
+
raise "publish options value invalid #{options.join(', ')}" unless options.size == 1
|
259
|
+
@publish_options = options[0]
|
260
|
+
self
|
261
|
+
else
|
262
|
+
@publish_options_calc = block
|
263
|
+
self
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
# Sets the additional properties for the ivy process use a Hash with the properties to set.
|
269
|
+
def properties(*properties)
|
270
|
+
if properties.empty?
|
271
|
+
@properties ||= {}
|
272
|
+
else
|
273
|
+
raise "properties value invalid #{properties.join(', ')}" unless properties.size == 1
|
274
|
+
@properties = properties[0]
|
275
|
+
self
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# Sets the local repository for ivy files
|
280
|
+
def local_repository(*local_repository)
|
281
|
+
if local_repository.empty?
|
282
|
+
if own_file?
|
283
|
+
@local_repository ||= Ivy.setting('local.repository.dir') || "#{home}/repository"
|
284
|
+
else
|
285
|
+
@project.parent.ivy.local_repository
|
286
|
+
end
|
287
|
+
else
|
288
|
+
raise "Could not set 'local_repository' for '#{@project.name}' without own ivy file!" unless own_file?
|
289
|
+
raise "local_repository value invalid #{local_repository.join(', ')}" unless local_repository.size == 1
|
290
|
+
@local_repository = local_repository[0]
|
291
|
+
self
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
# :call-seq:
|
296
|
+
# ivy.publish(package(:jar) => 'new_name_without_version_number.jar')
|
297
|
+
# #deprecated! ivy.name(package(:jar) => 'new_name_without_version_number.jar')
|
298
|
+
#
|
299
|
+
# Maps a package to a different name for publishing. This name is used instead of the default name
|
300
|
+
# for publishing use a hash with the +package+ as key and the newly mapped name as value. I.e.
|
301
|
+
# <tt>ivy.name(package(:jar) => 'new_name_without_version_number.jar')</tt>
|
302
|
+
# Note that this method is additive, a second call adds the names to the first.
|
303
|
+
def publish(*publish_mappings)
|
304
|
+
if publish_mappings.empty?
|
305
|
+
@publish_mappings ||= {}
|
306
|
+
else
|
307
|
+
raise "publish_mappings value invalid #{publish_mappings.join(', ')}" unless publish_mappings.size == 1
|
308
|
+
@publish_mappings = @publish_mappings ? @publish_mappings + publish_mappings[0] : publish_mappings[0].dup
|
309
|
+
self
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
def name(*args)
|
314
|
+
puts "name(*args) is deprecated use publish(*args)!"
|
315
|
+
publish(*args)
|
316
|
+
end
|
317
|
+
|
318
|
+
# Sets the directory to publish artifacts from.
|
319
|
+
def publish_from(*publish_dir)
|
320
|
+
if publish_dir.empty?
|
321
|
+
if own_file?
|
322
|
+
@publish_from ||= Ivy.setting('publish.from') || @project.path_to(:target)
|
323
|
+
else
|
324
|
+
@project.parent.ivy.publish_from
|
325
|
+
end
|
326
|
+
else
|
327
|
+
raise "Could not set 'publish_from' for '#{@project.name}' without own ivy file!" unless own_file?
|
328
|
+
raise "publish_from value invalid #{publish_dir.join(', ')}" unless publish_dir.size == 1
|
329
|
+
@publish_from = publish_dir[0]
|
330
|
+
self
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
# Sets the directory to create dependency reports in.
|
335
|
+
def report_dir(*report_dir)
|
336
|
+
if report_dir.empty?
|
337
|
+
if own_file?
|
338
|
+
@report_dir ||= Ivy.setting('report.dir') || @project.path_to(:reports, 'ivy')
|
339
|
+
else
|
340
|
+
@project.parent.ivy.report_dir
|
341
|
+
end
|
342
|
+
else
|
343
|
+
raise "Could not set 'report_dir' for '#{@project.name}' without own ivy file!" unless own_file?
|
344
|
+
raise "publish_from value invalid #{report_dir.join(', ')}" unless report_dir.size == 1
|
345
|
+
@report_dir = report_dir[0]
|
346
|
+
self
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
# Adds given block as post resolve action that is executed directly after #resolve has been called.
|
351
|
+
# Yields this ivy config object into block.
|
352
|
+
# <tt>project.ivy.post_resolve { |ivy| p "all deps:" + ivy.deps('all').join(", ") }</tt>
|
353
|
+
def post_resolve(&block)
|
354
|
+
post_resolve_tasks << block if block
|
355
|
+
end
|
356
|
+
|
357
|
+
# Filter artifacts for given configuration with provided filter values, this is a post resolve
|
358
|
+
# task like #deps.
|
359
|
+
# <tt>project.ivy.filter('server', 'client', :include => /b.*.jar/, :exclude => [/a\.jar/, /other.*\.jar/])</tt>
|
360
|
+
def filter(*confs)
|
361
|
+
filter = confs.last.kind_of?(Hash) ? confs.pop : {}
|
362
|
+
unless (filter.keys - (TYPES - [:conf])).empty?
|
363
|
+
raise ArgumentError, "Invalid filter use :include and/or :exclude only: given #{filter.keys.inspect}"
|
364
|
+
end
|
365
|
+
includes, excludes, types = filter[:include] || [], filter[:exclude] || [], filter[:type] || []
|
366
|
+
|
367
|
+
artifacts = deps(confs.flatten, types.flatten)
|
368
|
+
if artifacts
|
369
|
+
artifacts = artifacts.find_all do |lib|
|
370
|
+
lib = File.basename(lib)
|
371
|
+
includes = includes.reject {|i| i.nil? || i.blank? }
|
372
|
+
should_include = includes.empty? || includes.any? {|include| include === lib }
|
373
|
+
should_include && !excludes.any? {|exclude| exclude === lib}
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
artifacts
|
378
|
+
end
|
379
|
+
|
380
|
+
# :call-seq:
|
381
|
+
# for types:
|
382
|
+
# project.ivy.include(:compile => [/\.jar/, /\.gz/], :package => 'cglib.jar')
|
383
|
+
# project.ivy.exclude(:test => 'cglib.jar')
|
384
|
+
# project.ivy.conf(:compile => 'compile', :test => 'test', :package => 'prod')
|
385
|
+
# for targets:
|
386
|
+
# project.ivy.compile(:conf => 'compile', :exclude => /cglib.jar/)
|
387
|
+
# project.ivy.test(:conf => 'test')
|
388
|
+
# project.ivy.package(:conf => 'prod', :include => /.*.jar/, :exclude => /cglib.jar/)
|
389
|
+
# or verbose:
|
390
|
+
# project.ivy.compile_conf or project.ivy.conf_compile
|
391
|
+
# project.ivy.compile_include or project.ivy.include_compile
|
392
|
+
# the same for the other possible options.
|
393
|
+
#
|
394
|
+
# Uses #method_missing to handle the options.
|
395
|
+
# Generic handling of settings for +target+ and +type+. All calls in the form
|
396
|
+
# <tt>target_type({})</tt> or <tt>type_target({})</tt> are handled via this method see
|
397
|
+
# #TARGETS #TYPES for more information about valid targets and types.
|
398
|
+
def method_missing(methodname, *args, &block)
|
399
|
+
if block.nil? && valid_config_call?(methodname)
|
400
|
+
target, type = target(methodname), type(methodname)
|
401
|
+
if target && type
|
402
|
+
handle_variable(target, type, *args)
|
403
|
+
elsif target && args.size == 1 && args.last.kind_of?(Hash)
|
404
|
+
args[0].each { |type, value| handle_variable(target, type, *value) }
|
405
|
+
self
|
406
|
+
elsif type && args.size == 1 && args.last.kind_of?(Hash)
|
407
|
+
args[0].each { |target, value| handle_variable(target, type, *value) }
|
408
|
+
self
|
409
|
+
else
|
410
|
+
raise "Could not recognize config call for method '#{methodname}', args=#{args.inspect}"
|
411
|
+
end
|
412
|
+
else
|
413
|
+
super.method_missing(methodname, *args, &block)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
private
|
418
|
+
def target(targets)
|
419
|
+
t = targets.to_s.split('_').find { |target| TARGETS.member? target.to_sym }
|
420
|
+
t ? t.to_sym : nil
|
421
|
+
end
|
422
|
+
|
423
|
+
def type(types)
|
424
|
+
t = types.to_s.split('_').find { |type| TYPES.member? type.to_sym }
|
425
|
+
t ? t.to_sym : nil
|
426
|
+
end
|
427
|
+
|
428
|
+
def valid_config_call?(method_name)
|
429
|
+
valid_calls = []
|
430
|
+
TYPES.each do|type|
|
431
|
+
TARGETS.each do|target|
|
432
|
+
valid_calls << type.to_s << target.to_s << "#{type}_#{target}" << "#{target}_#{type}"
|
433
|
+
end
|
434
|
+
end
|
435
|
+
valid_calls.member? method_name.to_s
|
436
|
+
end
|
437
|
+
|
438
|
+
# Sets a variable for given basename and type to given values. If values are empty returns the
|
439
|
+
# current value.
|
440
|
+
# I.e. <tt>handle_variable(:package, :include, /blua.*\.jar/, /da.*\.jar/)</tt>
|
441
|
+
def handle_variable(target, type, *values)
|
442
|
+
unless TARGETS.member?(target) && TYPES.member?(type)
|
443
|
+
raise ArgumentError, "Unknown config value for target #{target.inspect} and type #{type.inspect}"
|
444
|
+
end
|
445
|
+
if values.empty?
|
446
|
+
@target_config[target][type] ||= [Ivy.setting("#{target.to_s}.#{type.to_s}") || ''].flatten.uniq
|
447
|
+
else
|
448
|
+
@target_config[target][type] = [values].flatten.uniq
|
449
|
+
self
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
def post_resolve_tasks
|
454
|
+
@base_ivy ? @base_ivy.post_resolve_task_list : post_resolve_task_list
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
=begin rdoc
|
459
|
+
The Ivy Buildr extension adding the new tasks for ivy.
|
460
|
+
|
461
|
+
To use ivy in a +buildfile+ do something like:
|
462
|
+
ENV['BUILDR_EXT_DIR'] ||= '../Ivy'
|
463
|
+
require 'buildr/ivy_extension'
|
464
|
+
define 'ivy_project' do
|
465
|
+
[...]
|
466
|
+
ivy.compile_conf('compile').test_conf('test').package_conf('prod', 'server')
|
467
|
+
[...]
|
468
|
+
end
|
469
|
+
|
470
|
+
- This will add the +compile+ configuration to compile and test tasks
|
471
|
+
- Add the +test+ configuration to test compilation and execution
|
472
|
+
- include the artifacts from +prod+ and +server+ to any generated war or ear
|
473
|
+
- The ENV variable is needed to automatically configure the load path for ivy libs.
|
474
|
+
It assumes that you have the following dir structure <tt>[BUILDR_EXT_DIR]/ivy-home/jars</tt>
|
475
|
+
|
476
|
+
For more configuration options see IvyConfig.
|
477
|
+
=end
|
478
|
+
module IvyExtension
|
479
|
+
include Buildr::Extension
|
480
|
+
|
481
|
+
class << self
|
482
|
+
|
483
|
+
def add_ivy_deps_to_java_tasks(project)
|
484
|
+
resolve_target = project.ivy.file_project.task('ivy:resolve')
|
485
|
+
project.task :compiledeps => resolve_target do
|
486
|
+
includes = project.ivy.compile_include
|
487
|
+
excludes = project.ivy.compile_exclude
|
488
|
+
types = project.ivy.compile_type
|
489
|
+
confs = [project.ivy.compile_conf].flatten
|
490
|
+
if deps = project.ivy.filter(confs, :type => types, :include => includes, :exclude => excludes)
|
491
|
+
project.compile.with [deps, project.compile.dependencies].flatten
|
492
|
+
sort_dependencies(project.compile.dependencies, deps, project.path_to(''))
|
493
|
+
info "Ivy adding compile dependencies '#{confs.join(', ')}' to project '#{project.name}'"
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
project.task :compile => "#{project.name}:compiledeps"
|
498
|
+
|
499
|
+
project.task :testdeps => resolve_target do
|
500
|
+
includes = project.ivy.test_include
|
501
|
+
excludes = project.ivy.test_exclude
|
502
|
+
types = project.ivy.test_type
|
503
|
+
confs = [project.ivy.test_conf, project.ivy.compile_conf].flatten.uniq
|
504
|
+
if deps = project.ivy.filter(confs, :type => types, :include => includes, :exclude => excludes)
|
505
|
+
project.test.with [deps, project.test.dependencies].flatten
|
506
|
+
sort_dependencies(project.test.dependencies, deps, project.path_to(''))
|
507
|
+
sort_dependencies(project.test.compile.dependencies, deps, project.path_to(''))
|
508
|
+
info "Ivy adding test dependencies '#{confs.join(', ')}' to project '#{project.name}'"
|
509
|
+
end
|
510
|
+
end
|
511
|
+
project.task "test:compile" => "#{project.name}:testdeps"
|
512
|
+
|
513
|
+
project.task :javadocdeps => resolve_target do
|
514
|
+
confs = [project.ivy.test_conf, project.ivy.compile_conf].flatten.uniq
|
515
|
+
if deps = project.ivy.deps(confs)
|
516
|
+
project.javadoc.with deps
|
517
|
+
info "Ivy adding javadoc dependencies '#{confs.join(', ')}' to project '#{project.name}'"
|
518
|
+
end
|
519
|
+
end
|
520
|
+
project.task :javadoc => "#{project.name}:javadocdeps"
|
521
|
+
|
522
|
+
[project.task(:eclipse), project.task(:idea), project.task(:idea7x)].each do |task|
|
523
|
+
task.prerequisites.each{|p| p.enhance ["#{project.name}:compiledeps", "#{project.name}:testdeps"]}
|
524
|
+
end
|
525
|
+
end
|
526
|
+
|
527
|
+
# Sorts the dependencies in #deps replacing the old order.
|
528
|
+
# Sorting is done as follows:
|
529
|
+
# 1. all dependencies that belong to the project identified by #project_path,
|
530
|
+
# .i.e. instrumented-classes, resources in the order the are contained in the array
|
531
|
+
# 2. all ivy dependencies identified by #ivy_deps
|
532
|
+
# 3. all dependencies added automatically by buildr
|
533
|
+
def sort_dependencies(deps, ivy_deps, project_path)
|
534
|
+
old_deps = deps.dup
|
535
|
+
belongs_to_project = /#{project_path}/
|
536
|
+
deps.sort! do |a, b|
|
537
|
+
a_belongs_to_project = belongs_to_project.match(a.to_s)
|
538
|
+
b_belongs_to_project = belongs_to_project.match(b.to_s)
|
539
|
+
a_ivy = ivy_deps.member? a
|
540
|
+
b_ivy = ivy_deps.member? b
|
541
|
+
|
542
|
+
if a_belongs_to_project && !b_belongs_to_project
|
543
|
+
-1
|
544
|
+
elsif !a_belongs_to_project && b_belongs_to_project
|
545
|
+
1
|
546
|
+
elsif a_ivy && !b_ivy
|
547
|
+
-1
|
548
|
+
elsif !a_ivy && b_ivy
|
549
|
+
1
|
550
|
+
else
|
551
|
+
old_deps.index(a) <=> old_deps.index(b)
|
552
|
+
end
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
def add_manifest_to_distributeables(project)
|
557
|
+
pkgs = project.packages.find_all { |pkg| ['jar', 'war', 'ear'].member? pkg.type.to_s }
|
558
|
+
pkgs.each do |pkg|
|
559
|
+
name = "#{pkg.name}manifest"
|
560
|
+
task = project.task name => project.ivy.file_project.task('ivy:resolve') do
|
561
|
+
pkg.with :manifest => pkg.manifest.merge(project.manifest.merge(project.ivy.manifest))
|
562
|
+
info "Adding manifest entries to package '#{pkg.name}'"
|
563
|
+
end
|
564
|
+
project.task :build => task
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
def add_prod_libs_to_distributeables(project)
|
569
|
+
pkgs = project.packages.find_all { |pkg| ['war'].member? pkg.type.to_s }
|
570
|
+
pkgs.each do |pkg|
|
571
|
+
task = project.task "#{pkg.name}deps" => project.ivy.file_project.task('ivy:resolve') do
|
572
|
+
includes = project.ivy.package_include
|
573
|
+
excludes = project.ivy.package_exclude
|
574
|
+
types = project.ivy.package_type
|
575
|
+
confs = project.ivy.package_conf
|
576
|
+
if deps = project.ivy.filter(confs, :type => types, :include => includes, :exclude => excludes)
|
577
|
+
pkg.with :libs => [deps, pkg.libs].flatten
|
578
|
+
info "Adding production libs from conf '#{confs.join(', ')}' to WAR '#{pkg.name}' in project '#{project.name}'"
|
579
|
+
end
|
580
|
+
end
|
581
|
+
project.task :build => task
|
582
|
+
end
|
583
|
+
|
584
|
+
pkgs = project.packages.find_all { |pkg| ['ear'].member? pkg.type.to_s }
|
585
|
+
pkgs.each do |pkg|
|
586
|
+
task = project.task "#{pkg.name}deps" => project.ivy.file_project.task('ivy:resolve') do
|
587
|
+
includes = project.ivy.package_include
|
588
|
+
excludes = project.ivy.package_exclude
|
589
|
+
types = project.ivy.package_type
|
590
|
+
confs = project.ivy.package_conf
|
591
|
+
if deps = project.ivy.filter(confs, :type => types, :include => includes, :exclude => excludes)
|
592
|
+
pkg.add deps, :type => :lib, :path => ''
|
593
|
+
info "Adding production libs from conf '#{confs.join(', ')}' to EAR '#{pkg.name}' in project '#{project.name}'"
|
594
|
+
end
|
595
|
+
end
|
596
|
+
project.task :build => task
|
597
|
+
end
|
598
|
+
end
|
599
|
+
|
600
|
+
def add_copy_tasks_for_publish(project)
|
601
|
+
if project.ivy.own_file?
|
602
|
+
Buildr.projects.each do |current|
|
603
|
+
current.packages.each do |pkg|
|
604
|
+
target_file = current.ivy.name[pkg] || File.basename(pkg.name).gsub(/-#{project.version}/, '')
|
605
|
+
taskname = current.path_to(project.ivy.publish_from, target_file)
|
606
|
+
if taskname != pkg.name
|
607
|
+
project.file taskname => pkg.name do
|
608
|
+
verbose "Ivy copying '#{pkg.name}' to '#{taskname}' for publishing"
|
609
|
+
FileUtils.mkdir File.dirname(taskname) unless File.directory?(File.dirname(taskname))
|
610
|
+
FileUtils.cp pkg.name, taskname
|
611
|
+
end
|
612
|
+
end
|
613
|
+
project.task 'ivy:publish' => taskname
|
614
|
+
end
|
615
|
+
end
|
616
|
+
end
|
617
|
+
end
|
618
|
+
end
|
619
|
+
|
620
|
+
# Returns the +ivy+ configuration for the project. Use this to configure Ivy.
|
621
|
+
# see IvyConfig for more details about configuration options.
|
622
|
+
def ivy
|
623
|
+
@ivy_config ||= IvyConfig.new(self)
|
624
|
+
end
|
625
|
+
|
626
|
+
first_time do
|
627
|
+
namespace 'ivy' do
|
628
|
+
desc 'Resolves the ivy dependencies'
|
629
|
+
task :resolve
|
630
|
+
|
631
|
+
desc 'Publish the artifacts to ivy repository as defined by environment'
|
632
|
+
task :publish
|
633
|
+
|
634
|
+
desc 'Creates a dependency report for the project'
|
635
|
+
task :report
|
636
|
+
|
637
|
+
desc 'Clean the local Ivy cache and the local ivy repository'
|
638
|
+
task :clean
|
639
|
+
end
|
640
|
+
end
|
641
|
+
|
642
|
+
after_define do |project|
|
643
|
+
if project.ivy.enabled?
|
644
|
+
IvyExtension.add_ivy_deps_to_java_tasks(project)
|
645
|
+
IvyExtension.add_manifest_to_distributeables(project)
|
646
|
+
IvyExtension.add_prod_libs_to_distributeables(project)
|
647
|
+
IvyExtension.add_copy_tasks_for_publish(project)
|
648
|
+
|
649
|
+
namespace 'ivy' do
|
650
|
+
task :configure do
|
651
|
+
project.ivy.configure
|
652
|
+
end
|
653
|
+
|
654
|
+
task :clean => :configure do
|
655
|
+
# TODO This is redundant, refactor ivy_ant_wrap and this to use a single config object
|
656
|
+
rm_rf project.path_to(:reports, 'ivy')
|
657
|
+
project.ivy.cleancache
|
658
|
+
end
|
659
|
+
|
660
|
+
task :resolve => "#{project.name}:ivy:configure" do
|
661
|
+
project.ivy.__resolve__
|
662
|
+
end
|
663
|
+
|
664
|
+
task :report => "#{project.name}:ivy:resolve" do
|
665
|
+
project.ivy.report
|
666
|
+
end
|
667
|
+
|
668
|
+
task :publish => "#{project.name}:ivy:resolve" do
|
669
|
+
project.ivy.__publish__
|
670
|
+
end
|
671
|
+
end
|
672
|
+
end
|
673
|
+
end
|
674
|
+
end
|
675
|
+
|
676
|
+
# Global targets that are not bound to a project
|
677
|
+
namespace 'ivy' do
|
678
|
+
task :clean do
|
679
|
+
Buildr.projects.find_all{ |p| p.ivy.own_file? }.each do |project|
|
680
|
+
project.task('ivy:clean').invoke
|
681
|
+
end
|
682
|
+
end
|
683
|
+
|
684
|
+
task :resolve do
|
685
|
+
info "Resolving all distinct ivy files"
|
686
|
+
Buildr.projects.find_all{ |p| p.ivy.own_file? }.each do |project|
|
687
|
+
project.task('ivy:resolve').invoke
|
688
|
+
end
|
689
|
+
end
|
690
|
+
|
691
|
+
task :publish => :package do
|
692
|
+
info "Publishing all distinct ivy files"
|
693
|
+
Buildr.projects.find_all{ |p| p.ivy.own_file? }.each do |project|
|
694
|
+
project.task('ivy:publish').invoke
|
695
|
+
end
|
696
|
+
end
|
697
|
+
end
|
698
|
+
|
699
|
+
class Buildr::Project # :nodoc:
|
700
|
+
include IvyExtension
|
701
|
+
end
|
702
|
+
end
|
703
|
+
end
|