buildr 1.3.0-java

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 (138) hide show
  1. data/CHANGELOG +780 -0
  2. data/DISCLAIMER +7 -0
  3. data/KEYS +151 -0
  4. data/LICENSE +176 -0
  5. data/NOTICE +31 -0
  6. data/README +173 -0
  7. data/Rakefile +63 -0
  8. data/addon/buildr/antlr.rb +65 -0
  9. data/addon/buildr/cobertura.rb +232 -0
  10. data/addon/buildr/hibernate.rb +142 -0
  11. data/addon/buildr/javacc.rb +85 -0
  12. data/addon/buildr/jdepend.rb +60 -0
  13. data/addon/buildr/jetty.rb +248 -0
  14. data/addon/buildr/nailgun.rb +892 -0
  15. data/addon/buildr/openjpa.rb +90 -0
  16. data/addon/buildr/org/apache/buildr/JettyWrapper$1.class +0 -0
  17. data/addon/buildr/org/apache/buildr/JettyWrapper$BuildrHandler.class +0 -0
  18. data/addon/buildr/org/apache/buildr/JettyWrapper.class +0 -0
  19. data/addon/buildr/org/apache/buildr/JettyWrapper.java +144 -0
  20. data/addon/buildr/xmlbeans.rb +93 -0
  21. data/bin/buildr +21 -0
  22. data/buildr.gemspec +50 -0
  23. data/doc/css/default.css +225 -0
  24. data/doc/css/print.css +95 -0
  25. data/doc/css/syntax.css +43 -0
  26. data/doc/images/apache-incubator-logo.png +0 -0
  27. data/doc/images/buildr-hires.png +0 -0
  28. data/doc/images/buildr.png +0 -0
  29. data/doc/images/note.png +0 -0
  30. data/doc/images/tip.png +0 -0
  31. data/doc/images/zbuildr.tif +0 -0
  32. data/doc/pages/artifacts.textile +317 -0
  33. data/doc/pages/building.textile +501 -0
  34. data/doc/pages/contributing.textile +178 -0
  35. data/doc/pages/download.textile +25 -0
  36. data/doc/pages/extending.textile +229 -0
  37. data/doc/pages/getting_started.textile +337 -0
  38. data/doc/pages/index.textile +63 -0
  39. data/doc/pages/mailing_lists.textile +17 -0
  40. data/doc/pages/more_stuff.textile +367 -0
  41. data/doc/pages/packaging.textile +592 -0
  42. data/doc/pages/projects.textile +449 -0
  43. data/doc/pages/recipes.textile +127 -0
  44. data/doc/pages/settings_profiles.textile +339 -0
  45. data/doc/pages/testing.textile +475 -0
  46. data/doc/pages/troubleshooting.textile +121 -0
  47. data/doc/pages/whats_new.textile +389 -0
  48. data/doc/print.haml +52 -0
  49. data/doc/print.toc.yaml +28 -0
  50. data/doc/scripts/buildr-git.rb +411 -0
  51. data/doc/scripts/install-jruby.sh +44 -0
  52. data/doc/scripts/install-linux.sh +64 -0
  53. data/doc/scripts/install-osx.sh +52 -0
  54. data/doc/site.haml +55 -0
  55. data/doc/site.toc.yaml +44 -0
  56. data/lib/buildr.rb +47 -0
  57. data/lib/buildr/core.rb +27 -0
  58. data/lib/buildr/core/application.rb +373 -0
  59. data/lib/buildr/core/application_cli.rb +134 -0
  60. data/lib/buildr/core/build.rb +262 -0
  61. data/lib/buildr/core/checks.rb +382 -0
  62. data/lib/buildr/core/common.rb +155 -0
  63. data/lib/buildr/core/compile.rb +594 -0
  64. data/lib/buildr/core/environment.rb +120 -0
  65. data/lib/buildr/core/filter.rb +258 -0
  66. data/lib/buildr/core/generate.rb +195 -0
  67. data/lib/buildr/core/help.rb +118 -0
  68. data/lib/buildr/core/progressbar.rb +156 -0
  69. data/lib/buildr/core/project.rb +890 -0
  70. data/lib/buildr/core/test.rb +690 -0
  71. data/lib/buildr/core/transports.rb +486 -0
  72. data/lib/buildr/core/util.rb +235 -0
  73. data/lib/buildr/ide.rb +19 -0
  74. data/lib/buildr/ide/eclipse.rb +181 -0
  75. data/lib/buildr/ide/idea.ipr.template +300 -0
  76. data/lib/buildr/ide/idea.rb +194 -0
  77. data/lib/buildr/ide/idea7x.ipr.template +290 -0
  78. data/lib/buildr/ide/idea7x.rb +210 -0
  79. data/lib/buildr/java.rb +26 -0
  80. data/lib/buildr/java/ant.rb +71 -0
  81. data/lib/buildr/java/bdd_frameworks.rb +267 -0
  82. data/lib/buildr/java/commands.rb +210 -0
  83. data/lib/buildr/java/compilers.rb +432 -0
  84. data/lib/buildr/java/deprecated.rb +141 -0
  85. data/lib/buildr/java/groovyc.rb +137 -0
  86. data/lib/buildr/java/jruby.rb +99 -0
  87. data/lib/buildr/java/org/apache/buildr/BuildrNail$Main.class +0 -0
  88. data/lib/buildr/java/org/apache/buildr/BuildrNail.class +0 -0
  89. data/lib/buildr/java/org/apache/buildr/BuildrNail.java +41 -0
  90. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.class +0 -0
  91. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.java +116 -0
  92. data/lib/buildr/java/packaging.rb +706 -0
  93. data/lib/buildr/java/pom.rb +178 -0
  94. data/lib/buildr/java/rjb.rb +142 -0
  95. data/lib/buildr/java/test_frameworks.rb +290 -0
  96. data/lib/buildr/java/version_requirement.rb +172 -0
  97. data/lib/buildr/packaging.rb +21 -0
  98. data/lib/buildr/packaging/artifact.rb +729 -0
  99. data/lib/buildr/packaging/artifact_namespace.rb +957 -0
  100. data/lib/buildr/packaging/artifact_search.rb +140 -0
  101. data/lib/buildr/packaging/gems.rb +102 -0
  102. data/lib/buildr/packaging/package.rb +233 -0
  103. data/lib/buildr/packaging/tar.rb +104 -0
  104. data/lib/buildr/packaging/zip.rb +719 -0
  105. data/rakelib/apache.rake +126 -0
  106. data/rakelib/changelog.rake +56 -0
  107. data/rakelib/doc.rake +103 -0
  108. data/rakelib/package.rake +44 -0
  109. data/rakelib/release.rake +53 -0
  110. data/rakelib/rspec.rake +81 -0
  111. data/rakelib/rubyforge.rake +45 -0
  112. data/rakelib/scm.rake +49 -0
  113. data/rakelib/setup.rake +59 -0
  114. data/rakelib/stage.rake +45 -0
  115. data/spec/application_spec.rb +316 -0
  116. data/spec/archive_spec.rb +494 -0
  117. data/spec/artifact_namespace_spec.rb +635 -0
  118. data/spec/artifact_spec.rb +738 -0
  119. data/spec/build_spec.rb +193 -0
  120. data/spec/checks_spec.rb +537 -0
  121. data/spec/common_spec.rb +579 -0
  122. data/spec/compile_spec.rb +561 -0
  123. data/spec/groovy_compilers_spec.rb +239 -0
  124. data/spec/java_bdd_frameworks_spec.rb +238 -0
  125. data/spec/java_compilers_spec.rb +446 -0
  126. data/spec/java_packaging_spec.rb +1042 -0
  127. data/spec/java_test_frameworks_spec.rb +414 -0
  128. data/spec/packaging_helper.rb +63 -0
  129. data/spec/packaging_spec.rb +589 -0
  130. data/spec/project_spec.rb +739 -0
  131. data/spec/sandbox.rb +116 -0
  132. data/spec/scala_compilers_spec.rb +239 -0
  133. data/spec/spec.opts +6 -0
  134. data/spec/spec_helpers.rb +283 -0
  135. data/spec/test_spec.rb +871 -0
  136. data/spec/transport_spec.rb +300 -0
  137. data/spec/version_requirement_spec.rb +115 -0
  138. metadata +324 -0
@@ -0,0 +1,706 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one or more
2
+ # contributor license agreements. See the NOTICE file distributed with this
3
+ # work for additional information regarding copyright ownership. The ASF
4
+ # licenses this file to you under the Apache License, Version 2.0 (the
5
+ # "License"); you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations under
14
+ # the License.
15
+
16
+
17
+ require 'buildr/packaging'
18
+
19
+
20
+ module Buildr
21
+ module Packaging
22
+
23
+ # Adds packaging for Java projects: JAR, WAR, AAR, EAR, Javadoc.
24
+ module Java
25
+
26
+ class Manifest
27
+
28
+ STANDARD_HEADER = "Manifest-Version: 1.0\nCreated-By: Buildr\n"
29
+ LINE_SEPARATOR = /\r\n|\n|\r[^\n]/ #:nodoc:
30
+ SECTION_SEPARATOR = /(#{LINE_SEPARATOR}){2}/ #:nodoc:
31
+
32
+ class << self
33
+
34
+ # :call_seq:
35
+ # parse(str) => manifest
36
+ #
37
+ # Parse a string in MANIFEST.MF format and return a new Manifest.
38
+ def parse(str)
39
+ sections = str.split(SECTION_SEPARATOR).reject { |s| s.strip.empty? }
40
+ new sections.map { |section|
41
+ lines = section.split(LINE_SEPARATOR).inject([]) { |merged, line|
42
+ if line[0] == 32
43
+ merged.last << line[1..-1]
44
+ else
45
+ merged << line
46
+ end
47
+ merged
48
+ }
49
+ lines.map { |line| line.scan(/(.*?):\s*(.*)/).first }.
50
+ inject({}) { |map, (key, value)| map.merge(key=>value) }
51
+ }
52
+ end
53
+
54
+ # :call_seq:
55
+ # from_zip(file) => manifest
56
+ #
57
+ # Parse the MANIFEST.MF entry of a ZIP (or JAR) file and return a new Manifest.
58
+ def from_zip(file)
59
+ Zip::ZipFile.open(file.to_s) do |zip|
60
+ return Manifest.new unless zip.get_entry('META-INF/MANIFEST.MF')
61
+ Manifest.parse zip.read('META-INF/MANIFEST.MF')
62
+ end
63
+ end
64
+
65
+ # :call_seq:
66
+ # update_manifest(file) { |manifest| ... }
67
+ #
68
+ # Updates the MANIFEST.MF entry of a ZIP (or JAR) file. Reads the MANIFEST.MF,
69
+ # yields to the block with the Manifest object, and writes the modified object
70
+ # back to the file.
71
+ def update_manifest(file)
72
+ manifest = from_zip(file)
73
+ result = yield manifest
74
+ Zip::ZipFile.open(file.to_s) do |zip|
75
+ zip.get_output_stream('META-INF/MANIFEST.MF') do |out|
76
+ out.write manifest.to_s
77
+ out.write "\n"
78
+ end
79
+ end
80
+ result
81
+ end
82
+
83
+ end
84
+
85
+ # Returns a new Manifest object based on the argument:
86
+ # * nil -- Empty Manifest.
87
+ # * Hash -- Manifest with main section using the hash name/value pairs.
88
+ # * Array -- Manifest with one section from each entry (must be hashes).
89
+ # * String -- Parse (see Manifest#parse).
90
+ # * Proc/Method -- New Manifest from result of calling proc/method.
91
+ def initialize(arg = nil)
92
+ case arg
93
+ when nil, Hash then @sections = [arg || {}]
94
+ when Array then @sections = arg
95
+ when String then @sections = Manifest.parse(arg).sections
96
+ when Proc, Method then @sections = Manifest.new(arg.call).sections
97
+ else
98
+ fail 'Invalid manifest, expecting Hash, Array, file name/task or proc/method.'
99
+ end
100
+ end
101
+
102
+ # The sections of this manifest.
103
+ attr_reader :sections
104
+
105
+ # The main (first) section of this manifest.
106
+ def main
107
+ sections.first
108
+ end
109
+
110
+ include Enumerable
111
+
112
+ # Iterate over each section and yield to block.
113
+ def each(&block)
114
+ @sections.each(&block)
115
+ end
116
+
117
+ # Convert to MANIFEST.MF format.
118
+ def to_s
119
+ @sections.map { |section|
120
+ keys = section.keys
121
+ keys.unshift('Name') if keys.delete('Name')
122
+ lines = keys.map { |key| manifest_wrap_at_72("#{key}: #{section[key]}") }
123
+ lines + ['']
124
+ }.flatten.join("\n")
125
+ end
126
+
127
+ private
128
+
129
+ def manifest_wrap_at_72(line)
130
+ return [line] if line.size < 72
131
+ [ line[0..70] ] + manifest_wrap_at_72(' ' + line[71..-1])
132
+ end
133
+
134
+ end
135
+
136
+
137
+ # Adds support for MANIFEST.MF and other META-INF files.
138
+ module WithManifest #:nodoc:
139
+
140
+ class << self
141
+ def included(base)
142
+ base.class_eval do
143
+ alias :initialize_without_manifest :initialize
144
+ alias :initialize :initialize_with_manifest
145
+ end
146
+ end
147
+
148
+ end
149
+
150
+ # Specifies how to create the manifest file.
151
+ attr_accessor :manifest
152
+
153
+ # Specifies files to include in the META-INF directory.
154
+ attr_accessor :meta_inf
155
+
156
+ def initialize_with_manifest(*args) #:nodoc:
157
+ initialize_without_manifest *args
158
+ @manifest = false
159
+ @meta_inf = []
160
+ @dependencies = FileList[]
161
+
162
+ prepare do
163
+ @prerequisites << manifest if String === manifest || Rake::Task === manifest
164
+ [meta_inf].flatten.map { |file| file.to_s }.uniq.each { |file| path('META-INF').include file }
165
+ end
166
+
167
+ enhance do
168
+ if manifest
169
+ # Tempfiles gets deleted on garbage collection, so we're going to hold on to it
170
+ # through instance variable not closure variable.
171
+ Tempfile.open 'MANIFEST.MF' do |@manifest_tmp|
172
+ self.manifest = File.read(manifest.to_s) if String === manifest || Rake::Task === manifest
173
+ self.manifest = Manifest.new(manifest) unless Manifest === manifest
174
+ @manifest_tmp.write Manifest::STANDARD_HEADER
175
+ @manifest_tmp.write manifest.to_s
176
+ @manifest_tmp.write "\n"
177
+ path('META-INF').include @manifest_tmp.path, :as=>'MANIFEST.MF'
178
+ end
179
+ end
180
+ end
181
+ end
182
+
183
+ end
184
+
185
+ class ::Buildr::ZipTask
186
+ include WithManifest
187
+ end
188
+
189
+
190
+ # Extends the ZipTask to create a JAR file.
191
+ #
192
+ # This task supports two additional attributes: manifest and meta-inf.
193
+ #
194
+ # The manifest attribute specifies how to create the MANIFEST.MF file.
195
+ # * A hash of manifest properties (name/value pairs).
196
+ # * An array of hashes, one for each section of the manifest.
197
+ # * A string providing the name of an existing manifest file.
198
+ # * A file task can be used the same way.
199
+ # * Proc or method called to return the contents of the manifest file.
200
+ # * False to not generate a manifest file.
201
+ #
202
+ # The meta-inf attribute lists one or more files that should be copied into
203
+ # the META-INF directory.
204
+ #
205
+ # For example:
206
+ # package(:jar).with(:manifest=>'src/MANIFEST.MF')
207
+ # package(:jar).meta_inf << file('README')
208
+ class JarTask < ZipTask
209
+
210
+ def initialize(*args) #:nodoc:
211
+ super
212
+ end
213
+
214
+ # :call-seq:
215
+ # with(options) => self
216
+ #
217
+ # Additional
218
+ # Pass options to the task. Returns self. ZipTask itself does not support any options,
219
+ # but other tasks (e.g. JarTask, WarTask) do.
220
+ #
221
+ # For example:
222
+ # package(:jar).with(:manifest=>'MANIFEST_MF')
223
+ def with(*args)
224
+ super args.pop if Hash === args.last
225
+ include :from=>args
226
+ self
227
+ end
228
+
229
+ end
230
+
231
+
232
+ # Extends the JarTask to create a WAR file.
233
+ #
234
+ # Supports all the same options as JarTask, in additon to these two options:
235
+ # * :libs -- An array of files, tasks, artifact specifications, etc that will be added
236
+ # to the WEB-INF/lib directory.
237
+ # * :classes -- A directory containing class files for inclusion in the WEB-INF/classes
238
+ # directory.
239
+ #
240
+ # For example:
241
+ # package(:war).with(:libs=>'log4j:log4j:jar:1.1')
242
+ class WarTask < JarTask
243
+
244
+ # Directories with class files to include under WEB-INF/classes.
245
+ attr_accessor :classes
246
+
247
+ # Artifacts to include under WEB-INF/libs.
248
+ attr_accessor :libs
249
+
250
+ def initialize(*args) #:nodoc:
251
+ super
252
+ @classes = []
253
+ @libs = []
254
+ prepare do
255
+ @classes.to_a.flatten.each { |classes| path('WEB-INF/classes').include classes, :as=>'.' }
256
+ path('WEB-INF/lib').include Buildr.artifacts(@libs) unless @libs.nil? || @libs.empty?
257
+ end
258
+ end
259
+
260
+ def libs=(value) #:nodoc:
261
+ @libs = Buildr.artifacts(value)
262
+ end
263
+
264
+ def classes=(value) #:nodoc:
265
+ @classes = [value].flatten.map { |dir| file(dir.to_s) }
266
+ end
267
+
268
+ end
269
+
270
+
271
+ # Extends the JarTask to create an AAR file (Axis2 service archive).
272
+ #
273
+ # Supports all the same options as JarTask, with the addition of :wsdls, :services_xml and :libs.
274
+ #
275
+ # * :wsdls -- WSDL files to include (under META-INF). By default packaging will include all WSDL
276
+ # files found under src/main/axis2.
277
+ # * :services_xml -- Location of services.xml file (included under META-INF). By default packaging
278
+ # takes this from src/main/axis2/services.xml. Use a different path if you genereate the services.xml
279
+ # file as part of the build.
280
+ # * :libs -- Array of files, tasks, artifact specifications, etc that will be added to the /lib directory.
281
+ #
282
+ # For example:
283
+ # package(:aar).with(:libs=>'log4j:log4j:jar:1.1')
284
+ #
285
+ # filter.from('src/main/axis2').into('target').include('services.xml', '*.wsdl').using('http_port'=>'8080')
286
+ # package(:aar).wsdls.clear
287
+ # package(:aar).with(:services_xml=>_('target/services.xml'), :wsdls=>_('target/*.wsdl'))
288
+ class AarTask < JarTask
289
+ # Artifacts to include under /lib.
290
+ attr_accessor :libs
291
+ # WSDLs to include under META-INF (defaults to all WSDLs under src/main/axis2).
292
+ attr_accessor :wsdls
293
+ # Location of services.xml file (defaults to src/main/axis2/services.xml).
294
+ attr_accessor :services_xml
295
+
296
+ def initialize(*args) #:nodoc:
297
+ super
298
+ @libs = []
299
+ @wsdls = []
300
+ prepare do
301
+ path('META-INF').include @wsdls
302
+ path('META-INF').include @services_xml, :as=>['services.xml'] if @services_xml
303
+ path('lib').include Buildr.artifacts(@libs) unless @libs.nil? || @libs.empty?
304
+ end
305
+ end
306
+
307
+ def libs=(value) #:nodoc:
308
+ @libs = Buildr.artifacts(value)
309
+ end
310
+
311
+ def wsdls=(value) #:nodoc:
312
+ @wsdls |= Array(value)
313
+ end
314
+ end
315
+
316
+
317
+ # Extend the JarTask to create an EAR file.
318
+ #
319
+ # The following component types are supported by the EARTask:
320
+ #
321
+ # * :war -- A J2EE Web Application
322
+ # * :ejb -- An Enterprise Java Bean
323
+ # * :jar -- A J2EE Application Client.[1]
324
+ # * :lib -- An ear scoped shared library[2] (for things like logging,
325
+ # spring, etc) common to the ear components
326
+ #
327
+ # The EarTask uses the "Mechanism 2: Bundled Optional Classes" as described on [2].
328
+ # All specified libraries are added to the EAR archive and the Class-Path manifiest entry is
329
+ # modified for each EAR component. Special care is taken with WebApplications, as they can
330
+ # contain libraries on their WEB-INF/lib directory, libraries already included in a war file
331
+ # are not referenced by the Class-Path entry of the war in order to avoid class collisions
332
+ #
333
+ # EarTask supports all the same options as JarTask, in additon to these two options:
334
+ #
335
+ # * :display_name -- The displayname to for this ear on application.xml
336
+ #
337
+ # * :map -- A Hash used to map component type to paths within the EAR.
338
+ # By default each component type is mapped to a directory with the same name,
339
+ # for example, EJBs are stored in the /ejb path. To customize:
340
+ # package(:ear).map[:war] = 'web-applications'
341
+ # package(:ear).map[:lib] = nil # store shared libraries on root of archive
342
+ #
343
+ # EAR components are added by means of the EarTask#add, EarTask#<<, EarTask#push methods
344
+ # Component type is determined from the artifact's type.
345
+ #
346
+ # package(:ear) << project('coolWebService').package(:war)
347
+ #
348
+ # The << method is just an alias for push, with the later you can add multiple components
349
+ # at the same time. For example..
350
+ #
351
+ # package(:ear).push 'org.springframework:spring:jar:2.6',
352
+ # projects('reflectUtils', 'springUtils'),
353
+ # project('coolerWebService').package(:war)
354
+ #
355
+ # The add method takes a single component with an optional hash. You can use it to override
356
+ # some component attributes.
357
+ #
358
+ # You can override the component type for a particular artifact. The following example
359
+ # shows how you can tell the EarTask to treat a JAR file as an EJB:
360
+ #
361
+ # # will add an ejb entry for the-cool-ejb-2.5.jar in application.xml
362
+ # package(:ear).add 'org.coolguys:the-cool-ejb:jar:2.5', :type=>:ejb
363
+ # # A better syntax for this is:
364
+ # package(:ear).add :ejb=>'org.coolguys:the-cool-ejb:jar:2.5'
365
+ #
366
+ # By default, every JAR package is assumed to be a library component, so you need to specify
367
+ # the type when including an EJB (:ejb) or Application Client JAR (:jar).
368
+ #
369
+ # For WebApplications (:war)s, you can customize the context-root that appears in application.xml.
370
+ # The following example also specifies a different directory inside the EAR where to store the webapp.
371
+ #
372
+ # package(:ear).add project(:remoteService).package(:war),
373
+ # :path=>'web-services', :context_root=>'/Some/URL/Path'
374
+ #
375
+ # [1] http://java.sun.com/j2ee/sdk_1.2.1/techdocs/guides/ejb/html/Overview5.html#10106
376
+ # [2] http://java.sun.com/j2ee/verified/packaging.html
377
+ class EarTask < JarTask
378
+
379
+ SUPPORTED_TYPES = [:war, :ejb, :jar, :rar, :lib]
380
+
381
+ # The display-name entry for application.xml
382
+ attr_accessor :display_name
383
+ # Map from component type to path inside the EAR.
384
+ attr_accessor :dirs
385
+
386
+ def initialize(*args)
387
+ super
388
+ @dirs = Hash.new { |h, k| k.to_s }
389
+ @libs, @components = [], []
390
+ prepare do
391
+ @components.each do |component|
392
+ path(component[:path]).include(component[:clone] || component[:artifact])
393
+ end
394
+ path('META-INF').include(descriptor)
395
+ end
396
+ end
397
+
398
+ # Add an artifact to this EAR.
399
+ def add(*args)
400
+ options = Hash === args.last ? args.pop.clone : {}
401
+ args.flatten!
402
+ args.map! do |pkg|
403
+ case pkg
404
+ when Project
405
+ pkg.packages.select { |pp| JarTask === pp && SUPPORTED_TYPES.include?(pp.type) }
406
+ when Rake::FileTask
407
+ pkg # add the explicitly provided file
408
+ when Hash
409
+ Buildr.artifact(pkg)
410
+ when String
411
+ begin
412
+ Buildr.artifact(pkg)
413
+ rescue # not an artifact spec, it must me a filename
414
+ file(pkg)
415
+ end
416
+ else
417
+ raise "Invalid EAR component #{pkg.class}: #{pkg}"
418
+ end
419
+ end
420
+ args.flatten!
421
+ args.compact!
422
+ if args.empty?
423
+ raise ":type must not be specified for type=>component argument style" if options.key?(:type)
424
+ raise ":as must not be specified for type=>component argument style" if options.key?(:as)
425
+ comps = {}
426
+ options.delete_if { |k, v| comps[k] = v if SUPPORTED_TYPES.include?(k) }
427
+ raise "You must specify at least one valid component to add" if comps.empty?
428
+ comps.each { |k, v| add(v, {:as => k}.merge(options)) }
429
+ else
430
+ args.each do |artifact|
431
+ type = options[:as] || options[:type]
432
+ unless type
433
+ type = artifact.respond_to?(:type) ? artifact.type : artifact.to_s.pathmap('%x').to_sym
434
+ type = :lib if type == :jar
435
+ end
436
+ raise "Unknown EAR component type: #{type}. Perhaps you may explicity tell what component type to use." unless
437
+ SUPPORTED_TYPES.include?(type)
438
+ component = options.merge(:artifact => artifact, :type => type,
439
+ :id=>artifact.respond_to?(:to_spec) ? artifact.id : artifact.to_s.pathmap('%n'),
440
+ :path=>options[:path] || dirs[type].to_s)
441
+ component[:clone] = component_clone(component) unless :lib == type
442
+ # update_classpath(component) unless :lib == type || Artifact === artifact
443
+ @components << component
444
+ end
445
+ end
446
+ self
447
+ end
448
+
449
+ alias_method :push, :add
450
+ alias_method :<<, :push
451
+
452
+ protected
453
+
454
+ def component_clone(component)
455
+ file(path_to(component[:path], component[:artifact].to_s.pathmap('%f')) => component[:artifact]) do |task|
456
+ mkpath task.to_s.pathmap('%d'), :verbose => false
457
+ cp component[:artifact].to_s, task.to_s, :verbose => false
458
+ Manifest.update_manifest(task) do |manifest|
459
+ class_path = manifest.main['Class-Path'].to_s.split
460
+ included_libs = class_path.map { |fn| fn.pathmap('%f') }
461
+ Zip::ZipFile.foreach(task.to_s) do |entry|
462
+ included_libs << entry.name.pathmap('%f') if entry.file? && entry.name =~ /^WEB-INF\/lib\/[^\/]+$/
463
+ end
464
+ # Include all other libraries in the classpath.
465
+ class_path += libs_classpath(component).reject { |path| included_libs.include?(File.basename(path)) }
466
+ manifest.main['Class-Path'] = class_path.join(' ')
467
+ end
468
+ end
469
+ end
470
+
471
+ def associate(project)
472
+ @project = project
473
+ end
474
+
475
+ def path_to(*args) #:nodoc:
476
+ @project.path_to(:target, :ear, name.pathmap('%n'), *args)
477
+ end
478
+ alias_method :_, :path_to
479
+
480
+ def update_classpath(component)
481
+ package = file(component[:artifact].to_s)
482
+ package.manifest = (package.manifest || {}).dup # avoid mofifying parent projects manifest
483
+ package.prepare do
484
+ header = case package.manifest
485
+ when Hash then package.manifest
486
+ when Array then package.manifest.first
487
+ end
488
+ if header
489
+ # Determine which libraries are already included.
490
+ class_path = header['Class-Path'].to_s.split
491
+ included_libs = class_path.map { |fn| File.basename(fn) }
492
+ included_libs += package.path('WEB-INF/lib').sources.map { |fn| File.basename(fn) }
493
+ # Include all other libraries in the classpath.
494
+ class_path += libs_classpath(component).reject { |path| included_libs.include?(File.basename(path)) }
495
+ header['Class-Path'] = class_path.join(' ')
496
+ end
497
+ end
498
+ end
499
+
500
+ private
501
+
502
+ # Classpath of all packages included as libraries (type :lib).
503
+ def libs_classpath(component)
504
+ from = component[:path]
505
+ @classpath = @components.select { |comp| comp[:type] == :lib }.
506
+ map do |lib|
507
+ basename = lib[:artifact].to_s.pathmap('%f')
508
+ full_path = lib[:path].empty? ? basename : File.join(lib[:path], basename)
509
+ Util.relative_path(full_path, from)
510
+ end
511
+ end
512
+
513
+ def descriptor_xml
514
+ buffer = ""
515
+ xml = Builder::XmlMarkup.new(:target=>buffer, :indent => 2)
516
+ xml.declare! :DOCTYPE, :application, :PUBLIC,
517
+ "-//Sun Microsystems, Inc.//DTD J2EE Application 1.2//EN",
518
+ "http://java.sun.com/j2ee/dtds/application_1_2.dtd"
519
+ xml.application do
520
+ xml.tag! 'display-name', display_name
521
+ @components.each do |comp|
522
+ basename = comp[:artifact].to_s.pathmap('%f')
523
+ uri = comp[:path].empty? ? basename : File.join(comp[:path], basename)
524
+ case comp[:type]
525
+ when :war
526
+ xml.module :id=>comp[:id] do
527
+ xml.web do
528
+ xml.tag! 'web-uri', uri
529
+ xml.tag! 'context-root', File.join('', (comp[:context_root] || comp[:id])) unless comp[:context_root] == false
530
+ end
531
+ end
532
+ when :ejb
533
+ xml.module :id=>comp[:id] do
534
+ xml.ejb uri
535
+ end
536
+ when :jar
537
+ xml.jar uri
538
+ end
539
+ end
540
+ end
541
+ buffer
542
+ end
543
+
544
+ # return a FileTask to build the ear application.xml file
545
+ def descriptor
546
+ return @descriptor if @descriptor
547
+ descriptor_path = path_to('META-INF/application.xml')
548
+ @descriptor = file(descriptor_path) do |task|
549
+ puts "Creating EAR Descriptor: #{task.to_s}" if Buildr.application.options.trace
550
+ mkpath File.dirname(task.name), :verbose=>false
551
+ File.open(task.name, 'w') { |file| file.print task.xml }
552
+ end
553
+ class << @descriptor
554
+ attr_accessor :ear
555
+
556
+ def xml
557
+ @xml ||= ear.send :descriptor_xml
558
+ end
559
+
560
+ def needed?
561
+ super || xml != File.read(self.to_s) rescue true
562
+ end
563
+ end
564
+ @descriptor.ear = self
565
+ @descriptor
566
+ end
567
+
568
+ end
569
+
570
+
571
+ include Extension
572
+
573
+ before_define do |project|
574
+ ::Java.load
575
+ project.manifest ||= project.parent && project.parent.manifest ||
576
+ { 'Build-By'=>ENV['USER'], 'Build-Jdk'=>ENV_JAVA['java.version'],
577
+ 'Implementation-Title'=>project.comment || project.name,
578
+ 'Implementation-Version'=>project.version }
579
+ project.meta_inf ||= project.parent && project.parent.meta_inf ||
580
+ [project.file('LICENSE')].select { |file| File.exist?(file.to_s) }
581
+ end
582
+
583
+
584
+ # Manifest used for packaging. Inherited from parent project. The default value is a hash that includes
585
+ # the Build-By, Build-Jdk, Implementation-Title and Implementation-Version values.
586
+ # The later are taken from the project's comment (or name) and version number.
587
+ attr_accessor :manifest
588
+
589
+ # Files to always include in the package META-INF directory. The default value include
590
+ # the LICENSE file if one exists in the project's base directory.
591
+ attr_accessor :meta_inf
592
+
593
+ # :call-seq:
594
+ # package_with_sources(options?)
595
+ #
596
+ # Call this when you want the project (and all its sub-projects) to create a source distribution.
597
+ # You can use the source distribution in an IDE when debugging.
598
+ #
599
+ # A source distribution is a ZIP package with the classifier 'sources', which includes all the
600
+ # sources used by the compile task.
601
+ #
602
+ # Packages use the project's manifest and meta_inf properties, which you can override by passing
603
+ # different values (e.g. false to exclude the manifest) in the options.
604
+ #
605
+ # To create source distributions only for specific projects, use the :only and :except options,
606
+ # for example:
607
+ # package_with_sources :only=>['foo:bar', 'foo:baz']
608
+ #
609
+ # (Same as calling package :sources on each project/sub-project that has source directories.)
610
+ def package_with_sources(options = nil)
611
+ options ||= {}
612
+ enhance do
613
+ selected = options[:only] ? projects(options[:only]) :
614
+ options[:except] ? ([self] + projects - projects(options[:except])) :
615
+ [self] + projects
616
+ selected.reject { |project| project.compile.sources.empty? }.
617
+ each { |project| project.package(:sources) }
618
+ end
619
+ end
620
+
621
+ # :call-seq:
622
+ # package_with_javadoc(options?)
623
+ #
624
+ # Call this when you want the project (and all its sub-projects) to create a JavaDoc distribution.
625
+ # You can use the JavaDoc distribution in an IDE when coding against the API.
626
+ #
627
+ # A JavaDoc distribution is a ZIP package with the classifier 'javadoc', which includes all the
628
+ # sources used by the compile task.
629
+ #
630
+ # Packages use the project's manifest and meta_inf properties, which you can override by passing
631
+ # different values (e.g. false to exclude the manifest) in the options.
632
+ #
633
+ # To create JavaDoc distributions only for specific projects, use the :only and :except options,
634
+ # for example:
635
+ # package_with_javadoc :only=>['foo:bar', 'foo:baz']
636
+ #
637
+ # (Same as calling package :javadoc on each project/sub-project that has source directories.)
638
+ def package_with_javadoc(options = nil)
639
+ options ||= {}
640
+ enhance do
641
+ selected = options[:only] ? projects(options[:only]) :
642
+ options[:except] ? ([self] + projects - projects(options[:except])) :
643
+ [self] + projects
644
+ selected.reject { |project| project.compile.sources.empty? }.
645
+ each { |project| project.package(:javadoc) }
646
+ end
647
+ end
648
+
649
+ protected
650
+
651
+ def package_as_jar(file_name) #:nodoc:
652
+ Java::JarTask.define_task(file_name).tap do |jar|
653
+ jar.with :manifest=>manifest, :meta_inf=>meta_inf
654
+ jar.with [compile.target, resources.target].compact
655
+ end
656
+ end
657
+
658
+ def package_as_war(file_name) #:nodoc:
659
+ Java::WarTask.define_task(file_name).tap do |war|
660
+ war.with :manifest=>manifest, :meta_inf=>meta_inf
661
+ # Add libraries in WEB-INF lib, and classes in WEB-INF classes
662
+ war.with :classes=>[compile.target, resources.target].compact
663
+ war.with :libs=>compile.dependencies
664
+ # Add included files, or the webapp directory.
665
+ webapp = path_to(:source, :main, :webapp)
666
+ war.with webapp if File.exist?(webapp)
667
+ end
668
+ end
669
+
670
+ def package_as_aar(file_name) #:nodoc:
671
+ Java::AarTask.define_task(file_name).tap do |aar|
672
+ aar.with :manifest=>manifest, :meta_inf=>meta_inf
673
+ aar.with :wsdls=>path_to(:source, :main, :axis2, '*.wsdl')
674
+ aar.with :services_xml=>path_to(:source, :main, :axis2, 'services.xml')
675
+ aar.with [compile.target, resources.target].compact
676
+ aar.with :libs=>compile.dependencies
677
+ end
678
+ end
679
+
680
+ def package_as_ear(file_name) #:nodoc:
681
+ Java::EarTask.define_task(file_name).tap do |ear|
682
+ ear.send :associate, self
683
+ ear.with :display_name=>id, :manifest=>manifest, :meta_inf=>meta_inf
684
+ end
685
+ end
686
+
687
+ def package_as_javadoc_spec(spec) #:nodoc:
688
+ spec.merge(:type=>:zip, :classifier=>'javadoc')
689
+ end
690
+
691
+ def package_as_javadoc(file_name) #:nodoc:
692
+ ZipTask.define_task(file_name).tap do |zip|
693
+ zip.include :from=>javadoc.target
694
+ javadoc.options[:windowtitle] ||= project.comment || project.name
695
+ end
696
+ end
697
+
698
+ end
699
+
700
+ end
701
+ end
702
+
703
+
704
+ class Buildr::Project
705
+ include Buildr::Packaging::Java
706
+ end