pepijnve-ivy4r 0.12.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/.autotest +14 -0
  2. data/.gitignore +7 -0
  3. data/.project +17 -0
  4. data/.rspec +2 -0
  5. data/CHANGELOG +280 -0
  6. data/Gemfile +5 -0
  7. data/README.txt +124 -0
  8. data/Rakefile +36 -0
  9. data/autotest/discover.rb +1 -0
  10. data/ivy4r.gemspec +30 -0
  11. data/lib/buildr/ivy_extension.rb +808 -0
  12. data/lib/ivy/artifactproperty.rb +34 -0
  13. data/lib/ivy/artifactreport.rb +24 -0
  14. data/lib/ivy/buildlist.rb +37 -0
  15. data/lib/ivy/buildnumber.rb +34 -0
  16. data/lib/ivy/cachepath.rb +30 -0
  17. data/lib/ivy/cleancache.rb +20 -0
  18. data/lib/ivy/configure.rb +29 -0
  19. data/lib/ivy/findrevision.rb +34 -0
  20. data/lib/ivy/info.rb +36 -0
  21. data/lib/ivy/install.rb +33 -0
  22. data/lib/ivy/java/all_version_matcher.rb +31 -0
  23. data/lib/ivy/java/java_object_wrapper.rb +160 -0
  24. data/lib/ivy/listmodules.rb +35 -0
  25. data/lib/ivy/makepom.rb +30 -0
  26. data/lib/ivy/publish.rb +37 -0
  27. data/lib/ivy/report.rb +33 -0
  28. data/lib/ivy/resolve.rb +44 -0
  29. data/lib/ivy/retrieve.rb +27 -0
  30. data/lib/ivy/settings.rb +15 -0
  31. data/lib/ivy/target.rb +162 -0
  32. data/lib/ivy/targets.rb +50 -0
  33. data/lib/ivy4r.rb +252 -0
  34. data/lib/ivy4r/version.rb +3 -0
  35. data/lib/ivy4r_java_extensions.rb +42 -0
  36. data/lib/rake/ivy_extension.rb +349 -0
  37. data/spec/ivy/target_spec.rb +86 -0
  38. data/spec/ivy/targets_spec.rb +27 -0
  39. data/spec/ivy4r_spec.rb +50 -0
  40. data/spec/spec_helper.rb +10 -0
  41. data/spec_files/buildlist/p1/buildfile +0 -0
  42. data/spec_files/buildlist/p1/ivy.xml +7 -0
  43. data/spec_files/buildlist/sub/p2/buildfile +0 -0
  44. data/spec_files/buildlist/sub/p2/ivy.xml +11 -0
  45. data/spec_files/buildlist/sub/p3/buildfile +0 -0
  46. data/spec_files/buildlist/sub/p3/ivy.xml +11 -0
  47. data/spec_files/ivy.xml +18 -0
  48. data/spec_files/ivysettings.xml +11 -0
  49. data/spec_functional/ivy4r_spec.rb +131 -0
  50. metadata +214 -0
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ require "rubygems"
2
+ require "bundler"
3
+ require "rake"
4
+ require "rake/testtask"
5
+ Bundler.require(:default, :development)
6
+
7
+ $:.unshift File.join(File.dirname(__FILE__),'lib')
8
+ require "ivy4r"
9
+
10
+ # Todo
11
+ require "rspec/core/rake_task"
12
+ RSpec::Core::RakeTask.new(:spec){|spec| spec.pattern='spec*/**/*spec*.rb'}
13
+ task :default => :spec
14
+
15
+ task :build do
16
+ system "gem build ivy4r.gemspec"
17
+ end
18
+
19
+ task :release => :build do
20
+ system "gem push ivy4r-#{Ivy4r::VERSION}.gem"
21
+ end
22
+
23
+ # Todo
24
+ begin
25
+ require "hanna/rdoctask"
26
+
27
+ Rake::RDocTask.new do |t|
28
+ t.title = "Ivy4r - Ruby interface to Apache Ivy dependency management with integration for Buildr and Rake"
29
+ t.rdoc_dir = "doc"
30
+ t.rdoc_files.include("**/*.rdoc").include("lib/**/*.rb")
31
+ t.options << "--line-numbers"
32
+ t.options << "--webcvs=http://github.com/pepijnve/ivy4r/tree/master/"
33
+ end
34
+ rescue LoadError
35
+ puts "'gem install hanna' to generate documentation"
36
+ end
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { "rspec2" }
data/ivy4r.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "ivy4r/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "pepijnve-ivy4r"
7
+ s.version = Ivy4r::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Klaas Reineke", "Pepijn Van Eeckhoudt"]
10
+ s.email = ["klaas.reineke@googlemail.com"]
11
+ s.homepage = "http://github.com/pepijnve/ivy4r"
12
+ s.summary = %q{Ivy4r Apache Ivy dependency management for Ruby}
13
+ s.description = %q{Ivy4r is a Ruby interface for Apache Ivy dependency management library. Offers support for using Ivy with Buildr and Rake.}
14
+
15
+ s.rubyforge_project = "ivy4r"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ #s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency 'atoulme-Antwrap', '~> 0.7.4'
23
+ s.add_dependency 'ivy4r-jars', '~> 1.2.0'
24
+
25
+ s.add_development_dependency 'rake', '~> 10.3.2'
26
+ s.add_development_dependency 'autotest', '~> 4.4.6'
27
+ s.add_development_dependency 'ZenTest', '~> 4.4.2'
28
+ s.add_development_dependency 'rspec', '~> 2.4.0'
29
+ s.add_development_dependency 'rr', '~> 1.0.2'
30
+ end
@@ -0,0 +1,808 @@
1
+ require 'ivy4r'
2
+
3
+ module Buildr
4
+ module Ivy
5
+
6
+ class << self
7
+ def setting(*keys)
8
+ find_setting(Buildr.settings.build['ivy'], *keys)
9
+ end
10
+
11
+ def user_setting(*keys)
12
+ find_setting(Buildr.settings.user['ivy'], *keys)
13
+ end
14
+
15
+ private
16
+ def find_setting(setting, *keys)
17
+ keys.each { |key| setting = setting[key] unless setting.nil? }
18
+ setting
19
+ end
20
+ end
21
+
22
+ class IvyConfig
23
+ TARGETS = [:compile, :test, :package]
24
+ TYPES = [:conf, :type, :include, :exclude]
25
+
26
+ attr_accessor :extension_dir, :resolved
27
+
28
+ attr_reader :post_resolve_task_list
29
+
30
+ attr_reader :project
31
+
32
+ # Hash of all artifacts to publish with mapping from artifact name to ivy publish name
33
+ attr_reader :publish_mappings
34
+
35
+ # Store the current project and initialize ivy ant wrapper
36
+ def initialize(project)
37
+ @project = project
38
+ @post_resolve_task_list = []
39
+ @extension_dir = project.parent.nil? ? @project.base_dir : @project.parent.ivy.extension_dir
40
+ @base_ivy = @project.parent.ivy unless own_file?
41
+ @target_config = Hash.new do
42
+ |hash, key| hash[key] = {}
43
+ end
44
+
45
+ end
46
+
47
+ def enabled?
48
+ setting = Ivy.setting('enabled')
49
+ @enabled ||= setting.nil? ? true : setting
50
+ end
51
+
52
+ def own_file?
53
+ @own_file ||= File.exists?(file)
54
+ end
55
+
56
+ # Returns the correct ivy4r instance to use, if project has its own ivy file uses the ivy file
57
+ # of project, if not uses the ivy file of parent project.
58
+ # Use this for low-level access to ivy functions as needed, i.e. in +post_resolve+
59
+ def ivy4r
60
+ unless @ivy4r
61
+ if own_file?
62
+ @ivy4r = ::Ivy4r.new do |i|
63
+ i.ant = @project.ant('ivy')
64
+ if caching_enabled?
65
+ i.cache_dir = result_cache_dir
66
+ @project.send(:info, "Using IVY result caching in dir '#{i.cache_dir}'")
67
+ end
68
+ end
69
+ @ivy4r.lib_dir = lib_dir if lib_dir
70
+ @ivy4r.project_dir = @extension_dir
71
+ else
72
+ @ivy4r = @project.parent.ivy.ivy4r
73
+ end
74
+ end
75
+ @ivy4r
76
+ end
77
+
78
+ # Returns if ivy result caching is enabled via build or user properties or by existence of the
79
+ # marker file.
80
+ def caching_enabled?
81
+ Ivy.user_setting('caching.enabled') || Ivy.setting('caching.enabled') || File.exists?(caching_marker)
82
+ end
83
+
84
+ # Returns the use ivy result caching marker file
85
+ def caching_marker
86
+ @project.path_to('use_ivy_caching')
87
+ end
88
+
89
+ # Returns the dir to store ivy caching results in.
90
+ def result_cache_dir
91
+ dir = @project.path_to('target', 'ivycaching')
92
+ FileUtils.mkdir_p dir
93
+ dir
94
+ end
95
+
96
+ # Returns name of the project the ivy file belongs to.
97
+ def file_project
98
+ own_file? ? @project : @base_ivy.file_project
99
+ end
100
+
101
+ # Returns the artifacts for given configurations as array
102
+ # this is a post resolve task.
103
+ # the arguments are checked for the following:
104
+ # 1. if an Hash is given :conf is used for confs and :type is used for types
105
+ # 2. if exactly two arrays are given args[0] is used for confs and args[1] is used for types
106
+ # 3. if not exactly two arrays all args are used as confs
107
+ def deps(*args)
108
+ if args.size == 1 && args[0].kind_of?(Hash)
109
+ confs, types = [args[0][:conf]].flatten, [args[0][:type]].flatten
110
+ elsif args.size == 2 && args[0].kind_of?(Array) && args[1].kind_of?(Array)
111
+ confs, types = args[0], args[1]
112
+ else
113
+ confs, types = args.flatten, []
114
+ end
115
+
116
+ [confs, types].each do |t|
117
+ t.reject! {|c| c.nil? || c.empty? }
118
+ end
119
+
120
+ unless confs.empty?
121
+ pathid = "ivy.deps." + confs.join('.') + '.' + types.join('.')
122
+ params = {:conf => confs.join(','), :pathid => pathid}
123
+ params[:type] = types.join(',') unless types.nil? || types.size == 0
124
+
125
+ ivy4r.cachepath params
126
+ end
127
+ end
128
+
129
+ # Returns ivy info for configured ivy file using a new ivy4r instance.
130
+ def info
131
+ if @base_ivy
132
+ @base_ivy.info
133
+ else
134
+ configure
135
+ ivy4r.info :file => file
136
+ end
137
+ end
138
+
139
+ # Configures the ivy instance with additional properties and loading the settings file if it was provided
140
+ def configure
141
+ if @base_ivy
142
+ @base_ivy.configure
143
+ else
144
+ unless @configured
145
+ ivy4r.property['ivy.status'] = status if status
146
+ ivy4r.property['ivy.home'] = home if home
147
+ properties.each {|key, value| ivy4r.property[key.to_s] = value }
148
+ @configured = ivy4r.settings :file => settings if settings
149
+ end
150
+ end
151
+ end
152
+
153
+ # Resolves the configured file once.
154
+ def __resolve__
155
+ if @base_ivy
156
+ @base_ivy.__resolve__
157
+ else
158
+ unless @resolved
159
+ @resolved = ivy4r.resolve :file => file
160
+ @project.send(:info, "Calling '#{post_resolve_tasks.size}' post_resolve tasks for '#{@project.name}'")
161
+ post_resolve_tasks.each { |p| p.call(self) }
162
+ end
163
+ end
164
+ end
165
+
166
+ # Returns the additional infos for the manifest file.
167
+ def manifest
168
+ if @base_ivy
169
+ @base_ivy.manifest
170
+ else
171
+ {
172
+ 'organisation' => @resolved['ivy.organisation'],
173
+ 'module' => @resolved['ivy.module'],
174
+ 'revision' => revision
175
+ }
176
+ end
177
+ end
178
+
179
+ # Creates the standard ivy dependency report
180
+ def report
181
+ ivy4r.report :todir => report_dir
182
+ end
183
+
184
+ # Cleans the ivy cache
185
+ def cleancache
186
+ ivy4r.cleancache
187
+ end
188
+
189
+ # Simple call to makepom with projects ivy.xml as input.
190
+ # The filename in target folder can be changed with the optional filename parameter
191
+ def makepom(filename = 'pom.xml')
192
+ ivy4r.makepom :ivyfile => file, :pomfile => project.path_to(:target, filename)
193
+ end
194
+
195
+
196
+ # Publishs the project as defined in ivy file if it has not been published already
197
+ def __publish__
198
+ if @base_ivy
199
+ @base_ivy.__publish__
200
+ else
201
+ unless @published
202
+ base_options = {:pubrevision => revision, :artifactspattern => "#{publish_from}/[artifact].[ext]"}
203
+ base_options[:status] = status if status
204
+ options = publish_options * base_options
205
+ ivy4r.publish options
206
+ @published = true
207
+ end
208
+ end
209
+ end
210
+
211
+ def home
212
+ @ivy_home_dir ||= Ivy.setting('home.dir')
213
+ end
214
+
215
+ def lib_dir
216
+ @lib_dir ||= Ivy.setting('lib.dir')
217
+ end
218
+
219
+ def settings
220
+ @settings ||= Ivy.setting('settings.file') || "#{@extension_dir}/ivysettings.xml"
221
+ end
222
+
223
+ # The basic file name to use in project dir as ivy.xml file. Normally this should be __ivy.xml__
224
+ # If the file resides in a sub directory the relative path from project can be set with this method
225
+ def ivy_xml_filename
226
+ @ivy_file ||= Ivy.setting('ivy.file') || 'ivy.xml'
227
+ end
228
+
229
+ # Returns the absolute ivy file path to use
230
+ def file
231
+ @project.path_to(ivy_xml_filename)
232
+ end
233
+
234
+ # Sets the revision to use for the project, this is useful for development revisions that
235
+ # have an appended timestamp or any other dynamic revisioning.
236
+ #
237
+ # To set a different revision this method can be used in different ways.
238
+ # 1. project.ivy.revision(revision) to set the revision directly
239
+ # 2. project.ivy.revision { |ivy| [calculate revision] } use the block for dynamic
240
+ # calculation of the revision. You can access ivy4r via <tt>ivy.ivy4r.[method]</tt>
241
+ def revision(*revision, &block)
242
+ raise "Invalid call with parameters and block!" if revision.size > 0 && block
243
+ if revision.empty? && block.nil?
244
+ if @revision_calc
245
+ @revision ||= @revision_calc.call(self)
246
+ else
247
+ @revision ||= @project.version
248
+ end
249
+ elsif block.nil?
250
+ raise "revision value invalid #{revision.join(', ')}" unless revision.size == 1
251
+ @revision = revision[0]
252
+ self
253
+ else
254
+ @revision_calc = block
255
+ self
256
+ end
257
+ end
258
+
259
+ # Sets the status to use for the project, this is useful for custom status handling
260
+ # like integration, alpha, gold.
261
+ #
262
+ # To set a different status this method can be used in different ways.
263
+ # 1. project.ivy.status(status) to set the status directly
264
+ # 2. project.ivy.status { |ivy| [calculate status] } use the block for dynamic
265
+ # calculation of the status. You can access ivy4r via <tt>ivy.ivy4r.[method]</tt>
266
+ def status(*status, &block)
267
+ raise "Invalid call with parameters and block!" if status.size > 0 && block
268
+ if status.empty? && block.nil?
269
+ if @status_calc
270
+ @status ||= @status_calc.call(self)
271
+ else
272
+ @status
273
+ end
274
+ elsif status.empty? && block.nil?
275
+ raise "status value invalid #{status.join(', ')}" unless status.size == 1
276
+ @status = status[0]
277
+ self
278
+ else
279
+ @status_calc = block
280
+ self
281
+ end
282
+ end
283
+
284
+ # Sets the publish options to use for the project. The options are merged with the default
285
+ # options including value set via #publish_from and overwrite all of them.
286
+ #
287
+ # To set the options this method can be used in different ways.
288
+ # 1. project.ivy.publish_options(options) to set the options directly
289
+ # 2. project.ivy.publish_options { |ivy| [calculate options] } use the block for dynamic
290
+ # calculation of options. You can access ivy4r via <tt>ivy.ivy4r.[method]</tt>
291
+ def publish_options(*options, &block)
292
+ raise "Invalid call with parameters and block!" if options.size > 0 && block
293
+ if options.empty? && block.nil?
294
+ if @publish_options_calc
295
+ @publish_options ||= @publish_options_calc.call(self)
296
+ else
297
+ @publish_options ||= Ivy.setting('publish.options') || {}
298
+ end
299
+ else
300
+ raise "Could not set 'publish_options' for '#{@project.name}' without own ivy file!" unless own_file?
301
+ if options.size > 0 && block.nil?
302
+ raise "publish options value invalid #{options.join(', ')}" unless options.size == 1
303
+ @publish_options = options[0]
304
+ self
305
+ else
306
+ @publish_options_calc = block
307
+ self
308
+ end
309
+ end
310
+ end
311
+
312
+ # Sets the additional properties for the ivy process use a Hash with the properties to set.
313
+ def properties(*properties)
314
+ if properties.empty?
315
+ @properties ||= {}
316
+ else
317
+ raise "properties value invalid #{properties.join(', ')}" unless properties.size == 1
318
+ @properties = properties[0]
319
+ self
320
+ end
321
+ end
322
+
323
+ # Sets the local repository for ivy files
324
+ def local_repository(*local_repository)
325
+ if local_repository.empty?
326
+ if own_file?
327
+ @local_repository ||= Ivy.setting('local.repository.dir') || "#{home}/repository"
328
+ else
329
+ @project.parent.ivy.local_repository
330
+ end
331
+ else
332
+ raise "Could not set 'local_repository' for '#{@project.name}' without own ivy file!" unless own_file?
333
+ raise "local_repository value invalid #{local_repository.join(', ')}" unless local_repository.size == 1
334
+ @local_repository = local_repository[0]
335
+ self
336
+ end
337
+ end
338
+
339
+ # :call-seq:
340
+ # ivy.publish(package(:jar) => 'new_name_without_version_number.jar')
341
+ # #deprecated! ivy.name(package(:jar) => 'new_name_without_version_number.jar')
342
+ #
343
+ # Maps a package to a different name for publishing. This name is used instead of the default name
344
+ # for publishing use a hash with the +package+ as key and the newly mapped name as value. I.e.
345
+ # <tt>ivy.name(package(:jar) => 'new_name_without_version_number.jar')</tt>
346
+ # Note that this method is additive, a second call adds the names to the first.
347
+ def publish(*publish_mappings)
348
+ if publish_mappings.empty?
349
+ @publish_mappings ||= {}
350
+ else
351
+ raise "publish_mappings value invalid #{publish_mappings.join(', ')}" unless publish_mappings.size == 1
352
+ @publish_mappings = @publish_mappings ? @publish_mappings + publish_mappings[0] : publish_mappings[0].dup
353
+ self
354
+ end
355
+ end
356
+
357
+ def name(*args)
358
+ puts "name(*args) is deprecated use publish(*args)!"
359
+ publish(*args)
360
+ end
361
+
362
+ # Sets the directory to publish artifacts from.
363
+ def publish_from(*publish_dir)
364
+ if publish_dir.empty?
365
+ if own_file?
366
+ @publish_from ||= Ivy.setting('publish.from') || @project.path_to(:target)
367
+ else
368
+ @project.parent.ivy.publish_from
369
+ end
370
+ else
371
+ raise "Could not set 'publish_from' for '#{@project.name}' without own ivy file!" unless own_file?
372
+ raise "publish_from value invalid #{publish_dir.join(', ')}" unless publish_dir.size == 1
373
+ @publish_from = publish_dir[0]
374
+ self
375
+ end
376
+ end
377
+
378
+ # Sets the directory to create dependency reports in.
379
+ def report_dir(*report_dir)
380
+ if report_dir.empty?
381
+ if own_file?
382
+ @report_dir ||= Ivy.setting('report.dir') || @project.path_to(:reports, 'ivy')
383
+ else
384
+ @project.parent.ivy.report_dir
385
+ end
386
+ else
387
+ raise "Could not set 'report_dir' for '#{@project.name}' without own ivy file!" unless own_file?
388
+ raise "publish_from value invalid #{report_dir.join(', ')}" unless report_dir.size == 1
389
+ @report_dir = report_dir[0]
390
+ self
391
+ end
392
+ end
393
+
394
+ # Adds given block as post resolve action that is executed directly after #resolve has been called.
395
+ # Yields this ivy config object into block.
396
+ # <tt>project.ivy.post_resolve { |ivy| p "all deps:" + ivy.deps('all').join(", ") }</tt>
397
+ def post_resolve(&block)
398
+ post_resolve_tasks << block if block
399
+ end
400
+
401
+ # Filter artifacts for given configuration with provided filter values, this is a post resolve
402
+ # task like #deps.
403
+ # <tt>project.ivy.filter('server', 'client', :include => /b.*.jar/, :exclude => [/a\.jar/, /other.*\.jar/])</tt>
404
+ def filter(*confs)
405
+ filter = confs.last.kind_of?(Hash) ? confs.pop : {}
406
+ unless (filter.keys - (TYPES - [:conf])).empty?
407
+ raise ArgumentError, "Invalid filter use :include and/or :exclude only: given #{filter.keys.inspect}"
408
+ end
409
+ includes, excludes, types = filter[:include] || [], filter[:exclude] || [], filter[:type] || []
410
+
411
+ artifacts = deps(confs.flatten, types.flatten)
412
+ if artifacts
413
+ artifacts = artifacts.find_all do |lib|
414
+ lib = File.basename(lib)
415
+ includes = includes.reject {|i| i.nil? || (i.respond_to?(:empty?) && i.empty?) || (i.respond_to?(:source) && i.source.empty?) }
416
+ should_include = includes.empty? || includes.any? {|include| include === lib }
417
+ should_include && !excludes.any? {|exclude| exclude === lib}
418
+ end
419
+ end
420
+
421
+ artifacts
422
+ end
423
+
424
+ # :call-seq:
425
+ # for types:
426
+ # project.ivy.include(:compile => [/\.jar/, /\.gz/], :package => 'cglib.jar')
427
+ # project.ivy.exclude(:test => 'cglib.jar')
428
+ # project.ivy.conf(:compile => 'compile', :test => 'test', :package => 'prod')
429
+ # for targets:
430
+ # project.ivy.compile(:conf => 'compile', :exclude => /cglib.jar/)
431
+ # project.ivy.test(:conf => 'test')
432
+ # project.ivy.package(:conf => 'prod', :include => /.*.jar/, :exclude => /cglib.jar/)
433
+ # or verbose:
434
+ # project.ivy.compile_conf or project.ivy.conf_compile
435
+ # project.ivy.compile_include or project.ivy.include_compile
436
+ # the same for the other possible options.
437
+ #
438
+ # Uses #method_missing to handle the options.
439
+ # Generic handling of settings for +target+ and +type+. All calls in the form
440
+ # <tt>target_type({})</tt> or <tt>type_target({})</tt> are handled via this method see
441
+ # #TARGETS #TYPES for more information about valid targets and types.
442
+ def method_missing(methodname, *args, &block)
443
+ if block.nil? && valid_config_call?(methodname)
444
+ target, type = target(methodname), type(methodname)
445
+ if target && type
446
+ handle_variable(target, type, *args)
447
+ elsif target && args.size == 1 && args.last.kind_of?(Hash)
448
+ args[0].each { |type, value| handle_variable(target, type, *value) }
449
+ self
450
+ elsif type && args.size == 1 && args.last.kind_of?(Hash)
451
+ args[0].each { |target, value| handle_variable(target, type, *value) }
452
+ self
453
+ else
454
+ raise "Could not recognize config call for method '#{methodname}', args=#{args.inspect}"
455
+ end
456
+ else
457
+ super.method_missing(methodname, *args, &block)
458
+ end
459
+ end
460
+
461
+ private
462
+ def target(targets)
463
+ t = targets.to_s.split('_').find { |target| TARGETS.member? target.to_sym }
464
+ t ? t.to_sym : nil
465
+ end
466
+
467
+ def type(types)
468
+ t = types.to_s.split('_').find { |type| TYPES.member? type.to_sym }
469
+ t ? t.to_sym : nil
470
+ end
471
+
472
+ def valid_config_call?(method_name)
473
+ valid_calls = []
474
+ TYPES.each do|type|
475
+ TARGETS.each do|target|
476
+ valid_calls << type.to_s << target.to_s << "#{type}_#{target}" << "#{target}_#{type}"
477
+ end
478
+ end
479
+ valid_calls.member? method_name.to_s
480
+ end
481
+
482
+ # Sets a variable for given basename and type to given values. If values are empty returns the
483
+ # current value.
484
+ # I.e. <tt>handle_variable(:package, :include, /blua.*\.jar/, /da.*\.jar/)</tt>
485
+ def handle_variable(target, type, *values)
486
+ unless TARGETS.member?(target) && TYPES.member?(type)
487
+ raise ArgumentError, "Unknown config value for target #{target.inspect} and type #{type.inspect}"
488
+ end
489
+ if values.empty?
490
+ @target_config[target][type] ||= [Ivy.setting("#{target.to_s}.#{type.to_s}") || ''].flatten.uniq
491
+ else
492
+ @target_config[target][type] = [values].flatten.uniq
493
+ self
494
+ end
495
+ end
496
+
497
+ def post_resolve_tasks
498
+ @base_ivy ? @base_ivy.post_resolve_task_list : post_resolve_task_list
499
+ end
500
+ end
501
+
502
+ =begin rdoc
503
+ The Ivy Buildr extension adding the new tasks for ivy.
504
+
505
+ To use ivy in a +buildfile+ do something like:
506
+ ENV['BUILDR_EXT_DIR'] ||= '../Ivy'
507
+ require 'buildr/ivy_extension'
508
+ define 'ivy_project' do
509
+ [...]
510
+ ivy.compile_conf('compile').test_conf('test').package_conf('prod', 'server')
511
+ [...]
512
+ end
513
+
514
+ - This will add the +compile+ configuration to compile and test tasks
515
+ - Add the +test+ configuration to test compilation and execution
516
+ - include the artifacts from +prod+ and +server+ to any generated war or ear
517
+ - The ENV variable is needed to automatically configure the load path for ivy libs.
518
+ It assumes that you have the following dir structure <tt>[BUILDR_EXT_DIR]/ivy-home/jars</tt>
519
+
520
+ For more configuration options see IvyConfig.
521
+ =end
522
+ module IvyExtension
523
+ include Buildr::Extension
524
+
525
+ class << self
526
+
527
+ def add_ivy_deps_to_java_tasks(project)
528
+ resolve_target = project.ivy.file_project.task('ivy:resolve')
529
+ project.task :compiledeps => resolve_target do
530
+ includes = project.ivy.compile_include
531
+ excludes = project.ivy.compile_exclude
532
+ types = project.ivy.compile_type
533
+ confs = [project.ivy.compile_conf].flatten
534
+ if deps = project.ivy.filter(confs, :type => types, :include => includes, :exclude => excludes)
535
+ project.compile.with [deps, project.compile.dependencies].flatten
536
+ sort_dependencies(project.compile.dependencies, deps, project.path_to(''))
537
+ info "Ivy adding compile dependencies '#{confs.join(', ')}' to project '#{project.name}'"
538
+ end
539
+ end
540
+
541
+ project.task :compile => "#{project.name}:compiledeps"
542
+
543
+ project.task :testdeps => resolve_target do
544
+ includes = project.ivy.test_include
545
+ excludes = project.ivy.test_exclude
546
+ types = project.ivy.test_type
547
+ confs = [project.ivy.test_conf, project.ivy.compile_conf].flatten.uniq
548
+ if deps = project.ivy.filter(confs, :type => types, :include => includes, :exclude => excludes)
549
+ project.test.with [deps, project.test.dependencies].flatten
550
+ sort_dependencies(project.test.dependencies, deps, project.path_to(''))
551
+ sort_dependencies(project.test.compile.dependencies, deps, project.path_to(''))
552
+ info "Ivy adding test dependencies '#{confs.join(', ')}' to project '#{project.name}'"
553
+ end
554
+ end
555
+ project.task "test:compile" => "#{project.name}:testdeps"
556
+
557
+ project.task :docdeps => resolve_target do
558
+ confs = [project.ivy.test_conf, project.ivy.compile_conf].flatten.uniq
559
+ if deps = project.ivy.deps(confs)
560
+ project.doc.with deps
561
+ info "Ivy adding doc dependencies '#{confs.join(', ')}' to project '#{project.name}'"
562
+ end
563
+ end
564
+ project.doc.enhance( ["#{project.name}:docdeps"] )
565
+
566
+ [project.task(:eclipse), project.task(:idea), project.task(:idea7x)].each do |task|
567
+ [task, task.prerequisites].flatten.each{|p| p.enhance ["#{project.name}:compiledeps", "#{project.name}:testdeps"]}
568
+ end
569
+ end
570
+
571
+ # Sorts the dependencies in #deps replacing the old order.
572
+ # Sorting is done as follows:
573
+ # 1. all dependencies that belong to the project identified by #project_path,
574
+ # .i.e. instrumented-classes, resources in the order the are contained in the array
575
+ # 2. all ivy dependencies identified by #ivy_deps
576
+ # 3. all dependencies added automatically by buildr
577
+ def sort_dependencies(deps, ivy_deps, project_path)
578
+ old_deps = deps.dup
579
+ belongs_to_project = /#{project_path}/
580
+ deps.sort! do |a, b|
581
+ a_belongs_to_project = belongs_to_project.match(a.to_s)
582
+ b_belongs_to_project = belongs_to_project.match(b.to_s)
583
+ a_ivy = ivy_deps.member? a
584
+ b_ivy = ivy_deps.member? b
585
+
586
+ if a_belongs_to_project && !b_belongs_to_project
587
+ -1
588
+ elsif !a_belongs_to_project && b_belongs_to_project
589
+ 1
590
+ elsif a_ivy && !b_ivy
591
+ -1
592
+ elsif !a_ivy && b_ivy
593
+ 1
594
+ else
595
+ old_deps.index(a) <=> old_deps.index(b)
596
+ end
597
+ end
598
+ end
599
+
600
+ def add_manifest_to_distributeables(project)
601
+ pkgs = project.packages.find_all { |pkg| ['jar', 'war', 'ear'].member? pkg.type.to_s }
602
+ pkgs.each do |pkg|
603
+ name = "#{pkg.name}manifest"
604
+ task = project.task name => project.ivy.file_project.task('ivy:resolve') do
605
+ if pkg.manifest # source jars have no manifest, only add to existing manifest files
606
+ pkg.with :manifest => pkg.manifest.merge(project.manifest.merge(project.ivy.manifest))
607
+ info "Adding manifest entries to package '#{pkg.name}'"
608
+ else
609
+ info "Could not merge info to package '#{pkg.to_s}' it has no manifest!"
610
+ end
611
+ end
612
+ project.task :build => task
613
+ end
614
+ end
615
+
616
+ def add_prod_libs_to_distributeables(project)
617
+ pkgs = project.packages.find_all { |pkg| ['war'].member? pkg.type.to_s }
618
+ pkgs.each do |pkg|
619
+ task = project.task "#{pkg.name}deps" => project.ivy.file_project.task('ivy:resolve') do
620
+ includes = project.ivy.package_include
621
+ excludes = project.ivy.package_exclude
622
+ types = project.ivy.package_type
623
+ confs = project.ivy.package_conf
624
+ if deps = project.ivy.filter(confs, :type => types, :include => includes, :exclude => excludes)
625
+ pkg.with :libs => [deps, pkg.libs].flatten
626
+ info "Adding production libs from conf '#{confs.join(', ')}' to WAR '#{pkg.name}' in project '#{project.name}'"
627
+ end
628
+ end
629
+ project.task :build => task
630
+ end
631
+
632
+ pkgs = project.packages.find_all { |pkg| ['ear'].member? pkg.type.to_s }
633
+ pkgs.each do |pkg|
634
+ task = project.task "#{pkg.name}deps" => project.ivy.file_project.task('ivy:resolve') do
635
+ includes = project.ivy.package_include
636
+ excludes = project.ivy.package_exclude
637
+ types = project.ivy.package_type
638
+ confs = project.ivy.package_conf
639
+ if deps = project.ivy.filter(confs, :type => types, :include => includes, :exclude => excludes)
640
+ pkg.add deps, :type => :lib, :path => ''
641
+ info "Adding production libs from conf '#{confs.join(', ')}' to EAR '#{pkg.name}' in project '#{project.name}'"
642
+ end
643
+ end
644
+ project.task :build => task
645
+ end
646
+ end
647
+
648
+ def add_copy_tasks_for_publish(project)
649
+ ivy_project = project
650
+ until ivy_project.ivy.own_file?
651
+ ivy_project = ivy_project.parent
652
+ end
653
+ project.packages.each do |pkg|
654
+ target_file = project.ivy.publish[pkg] || File.basename(pkg.name).gsub(/-#{project.version}/, '')
655
+ taskname = ivy_project.path_to(ivy_project.ivy.publish_from, target_file)
656
+ if taskname != pkg.name
657
+ project.file taskname => pkg.name do
658
+ verbose "Ivy copying '#{pkg.name}' to '#{taskname}' for publishing"
659
+ FileUtils.mkdir_p File.dirname(taskname) unless File.directory?(File.dirname(taskname))
660
+ FileUtils.cp pkg.name, taskname
661
+ end
662
+ end
663
+
664
+ ivy_project.task 'ivy:publish' => taskname
665
+ end
666
+ end
667
+ end
668
+
669
+ # Returns the +ivy+ configuration for the project. Use this to configure Ivy.
670
+ # see IvyConfig for more details about configuration options.
671
+ def ivy
672
+ @ivy_config ||= IvyConfig.new(self)
673
+ end
674
+
675
+ first_time do
676
+ namespace 'ivy' do
677
+ desc 'Resolves the ivy dependencies'
678
+ task :resolve
679
+
680
+ desc 'Publish the artifacts to ivy repository as defined by environment'
681
+ task :publish
682
+
683
+ desc 'Creates a dependency report for the project'
684
+ task :report
685
+
686
+ desc 'Clean the local Ivy cache and the local ivy repository'
687
+ task :clean
688
+
689
+ desc 'Creates default Maven POM for project from ivy.xml'
690
+ task :makepom
691
+
692
+ desc 'Clean the local Ivy result cache to force execution of ivy targets'
693
+ task :clean_result_cache
694
+
695
+ desc 'Enable the local Ivy result cache by creating the marker file'
696
+ task :enable_result_cache
697
+
698
+ desc 'Disable the local Ivy result cache by removing the marker file'
699
+ task :disable_result_cache
700
+ end
701
+ end
702
+
703
+ after_define :ivy do |project|
704
+ if project.ivy.enabled?
705
+ IvyExtension.add_ivy_deps_to_java_tasks(project)
706
+ IvyExtension.add_manifest_to_distributeables(project)
707
+ IvyExtension.add_prod_libs_to_distributeables(project)
708
+ IvyExtension.add_copy_tasks_for_publish(project)
709
+
710
+ namespace 'ivy' do
711
+ task :configure do
712
+ project.ivy.configure
713
+ end
714
+
715
+ task :clean => :configure do
716
+ # TODO This is redundant, refactor ivy_ant_wrap and this to use a single config object
717
+ rm_rf project.path_to(:reports, 'ivy')
718
+ project.ivy.cleancache
719
+ end
720
+
721
+ task :clean_result_cache do
722
+ project.send(:info, "Deleting IVY result cache dir '#{project.ivy.result_cache_dir}'")
723
+ rm_rf project.ivy.result_cache_dir
724
+ end
725
+
726
+ task :enable_result_cache do
727
+ project.send(:info, "Creating IVY caching marker file '#{project.ivy.caching_marker}'")
728
+ touch project.ivy.caching_marker
729
+ end
730
+
731
+ task :disable_result_cache do
732
+ project.send(:info, "Deleting IVY caching marker file '#{project.ivy.caching_marker}'")
733
+ rm_f project.ivy.caching_marker
734
+ end
735
+
736
+ task :resolve => "#{project.name}:ivy:configure" do
737
+ project.ivy.__resolve__
738
+ end
739
+
740
+ task :report => "#{project.name}:ivy:resolve" do
741
+ project.ivy.report
742
+ end
743
+
744
+ task :publish => "#{project.name}:ivy:resolve" do
745
+ project.ivy.__publish__
746
+ end
747
+
748
+ task :makepom => "#{project.name}:ivy:resolve" do
749
+ project.ivy.makepom
750
+ end
751
+ end
752
+ end
753
+ end
754
+ end
755
+
756
+ # Global targets that are not bound to a project
757
+ namespace 'ivy' do
758
+ task :clean do
759
+ Buildr.projects.find_all{ |p| p.ivy.own_file? }.each do |project|
760
+ project.task('ivy:clean').invoke
761
+ end
762
+ end
763
+
764
+ task :clean_result_cache do
765
+ Buildr.projects.find_all{ |p| p.ivy.own_file? }.each do |project|
766
+ project.task('ivy:clean_result_cache').invoke
767
+ end
768
+ end
769
+
770
+ task :enable_result_cache do
771
+ Buildr.projects.find_all{ |p| p.ivy.own_file? }.each do |project|
772
+ project.task('ivy:enable_result_cache').invoke
773
+ end
774
+ end
775
+
776
+ task :disable_result_cache do
777
+ Buildr.projects.find_all{ |p| p.ivy.own_file? }.each do |project|
778
+ project.task('ivy:disable_result_cache').invoke
779
+ end
780
+ end
781
+
782
+ task :resolve do
783
+ info "Resolving all distinct ivy files"
784
+ Buildr.projects.find_all{ |p| p.ivy.own_file? }.each do |project|
785
+ project.task('ivy:resolve').invoke
786
+ end
787
+ end
788
+
789
+ task :publish => :package do
790
+ info "Publishing all distinct ivy files"
791
+ Buildr.projects.find_all{ |p| p.ivy.own_file? }.each do |project|
792
+ project.task('ivy:publish').invoke
793
+ end
794
+ end
795
+
796
+ task :makepom => :resolve do
797
+ info "Create Maven POMs for all projects with distinct ivy files"
798
+ Buildr.projects.find_all{ |p| p.ivy.own_file? }.each do |project|
799
+ project.task('ivy:makepom').invoke
800
+ end
801
+ end
802
+ end
803
+
804
+ class Buildr::Project # :nodoc:
805
+ include IvyExtension
806
+ end
807
+ end
808
+ end