pepijnve-ivy4r 0.12.11

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.
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