buildr 1.3.5-x86-mswin32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (186) hide show
  1. data/CHANGELOG +998 -0
  2. data/LICENSE +176 -0
  3. data/NOTICE +26 -0
  4. data/README.rdoc +134 -0
  5. data/Rakefile +45 -0
  6. data/_buildr +29 -0
  7. data/_jbuildr +29 -0
  8. data/addon/buildr/antlr.rb +65 -0
  9. data/addon/buildr/cobertura.rb +22 -0
  10. data/addon/buildr/drb.rb +281 -0
  11. data/addon/buildr/emma.rb +22 -0
  12. data/addon/buildr/hibernate.rb +142 -0
  13. data/addon/buildr/javacc.rb +85 -0
  14. data/addon/buildr/jdepend.rb +60 -0
  15. data/addon/buildr/jetty.rb +248 -0
  16. data/addon/buildr/jibx.rb +86 -0
  17. data/addon/buildr/nailgun.rb +221 -0
  18. data/addon/buildr/openjpa.rb +90 -0
  19. data/addon/buildr/org/apache/buildr/BuildrNail$Main.class +0 -0
  20. data/addon/buildr/org/apache/buildr/BuildrNail.class +0 -0
  21. data/addon/buildr/org/apache/buildr/BuildrNail.java +41 -0
  22. data/addon/buildr/org/apache/buildr/JettyWrapper$1.class +0 -0
  23. data/addon/buildr/org/apache/buildr/JettyWrapper$BuildrHandler.class +0 -0
  24. data/addon/buildr/org/apache/buildr/JettyWrapper.class +0 -0
  25. data/addon/buildr/org/apache/buildr/JettyWrapper.java +144 -0
  26. data/addon/buildr/xmlbeans.rb +93 -0
  27. data/bin/buildr +19 -0
  28. data/buildr.buildfile +58 -0
  29. data/buildr.gemspec +65 -0
  30. data/doc/_config.yml +1 -0
  31. data/doc/_layouts/default.html +88 -0
  32. data/doc/_layouts/preface.html +22 -0
  33. data/doc/artifacts.textile +211 -0
  34. data/doc/building.textile +244 -0
  35. data/doc/contributing.textile +252 -0
  36. data/doc/css/default.css +236 -0
  37. data/doc/css/print.css +101 -0
  38. data/doc/css/syntax.css +23 -0
  39. data/doc/download.textile +79 -0
  40. data/doc/extending.textile +186 -0
  41. data/doc/images/1442160941-frontcover.jpg +0 -0
  42. data/doc/images/asf-logo.gif +0 -0
  43. data/doc/images/asf-logo.png +0 -0
  44. data/doc/images/buildr-hires.png +0 -0
  45. data/doc/images/buildr.png +0 -0
  46. data/doc/images/favicon.png +0 -0
  47. data/doc/images/growl-icon.tiff +0 -0
  48. data/doc/images/note.png +0 -0
  49. data/doc/images/project-structure.png +0 -0
  50. data/doc/images/tip.png +0 -0
  51. data/doc/images/zbuildr.png +0 -0
  52. data/doc/images/zbuildr.tif +0 -0
  53. data/doc/index.textile +69 -0
  54. data/doc/installing.textile +266 -0
  55. data/doc/languages.textile +459 -0
  56. data/doc/mailing_lists.textile +25 -0
  57. data/doc/more_stuff.textile +457 -0
  58. data/doc/packaging.textile +430 -0
  59. data/doc/preface.textile +54 -0
  60. data/doc/projects.textile +271 -0
  61. data/doc/quick_start.textile +210 -0
  62. data/doc/scripts/buildr-git.rb +512 -0
  63. data/doc/scripts/gitflow.rb +296 -0
  64. data/doc/scripts/install-jruby.sh +44 -0
  65. data/doc/scripts/install-linux.sh +72 -0
  66. data/doc/scripts/install-osx.sh +52 -0
  67. data/doc/settings_profiles.textile +280 -0
  68. data/doc/testing.textile +222 -0
  69. data/etc/KEYS +151 -0
  70. data/lib/buildr.rb +36 -0
  71. data/lib/buildr/core.rb +35 -0
  72. data/lib/buildr/core/application.rb +656 -0
  73. data/lib/buildr/core/build.rb +452 -0
  74. data/lib/buildr/core/checks.rb +254 -0
  75. data/lib/buildr/core/common.rb +150 -0
  76. data/lib/buildr/core/compile.rb +608 -0
  77. data/lib/buildr/core/environment.rb +129 -0
  78. data/lib/buildr/core/filter.rb +362 -0
  79. data/lib/buildr/core/generate.rb +195 -0
  80. data/lib/buildr/core/help.rb +119 -0
  81. data/lib/buildr/core/osx.rb +46 -0
  82. data/lib/buildr/core/progressbar.rb +156 -0
  83. data/lib/buildr/core/project.rb +866 -0
  84. data/lib/buildr/core/shell.rb +198 -0
  85. data/lib/buildr/core/test.rb +723 -0
  86. data/lib/buildr/core/transports.rb +559 -0
  87. data/lib/buildr/core/util.rb +449 -0
  88. data/lib/buildr/groovy.rb +19 -0
  89. data/lib/buildr/groovy/bdd.rb +106 -0
  90. data/lib/buildr/groovy/compiler.rb +138 -0
  91. data/lib/buildr/groovy/shell.rb +48 -0
  92. data/lib/buildr/ide.rb +19 -0
  93. data/lib/buildr/ide/eclipse.rb +334 -0
  94. data/lib/buildr/ide/eclipse/java.rb +53 -0
  95. data/lib/buildr/ide/eclipse/plugin.rb +68 -0
  96. data/lib/buildr/ide/eclipse/scala.rb +66 -0
  97. data/lib/buildr/ide/idea.ipr.template +300 -0
  98. data/lib/buildr/ide/idea.rb +190 -0
  99. data/lib/buildr/ide/idea7x.ipr.template +290 -0
  100. data/lib/buildr/ide/idea7x.rb +212 -0
  101. data/lib/buildr/java.rb +23 -0
  102. data/lib/buildr/java/ant.rb +94 -0
  103. data/lib/buildr/java/bdd.rb +459 -0
  104. data/lib/buildr/java/cobertura.rb +274 -0
  105. data/lib/buildr/java/commands.rb +213 -0
  106. data/lib/buildr/java/compiler.rb +349 -0
  107. data/lib/buildr/java/deprecated.rb +141 -0
  108. data/lib/buildr/java/emma.rb +244 -0
  109. data/lib/buildr/java/jruby.rb +117 -0
  110. data/lib/buildr/java/jtestr_runner.rb.erb +116 -0
  111. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.class +0 -0
  112. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.java +137 -0
  113. data/lib/buildr/java/packaging.rb +716 -0
  114. data/lib/buildr/java/pom.rb +174 -0
  115. data/lib/buildr/java/rjb.rb +155 -0
  116. data/lib/buildr/java/test_result.rb +353 -0
  117. data/lib/buildr/java/tests.rb +333 -0
  118. data/lib/buildr/java/version_requirement.rb +172 -0
  119. data/lib/buildr/packaging.rb +24 -0
  120. data/lib/buildr/packaging/archive.rb +488 -0
  121. data/lib/buildr/packaging/artifact.rb +749 -0
  122. data/lib/buildr/packaging/artifact_namespace.rb +972 -0
  123. data/lib/buildr/packaging/artifact_search.rb +140 -0
  124. data/lib/buildr/packaging/gems.rb +102 -0
  125. data/lib/buildr/packaging/package.rb +238 -0
  126. data/lib/buildr/packaging/tar.rb +186 -0
  127. data/lib/buildr/packaging/version_requirement.rb +172 -0
  128. data/lib/buildr/packaging/zip.rb +73 -0
  129. data/lib/buildr/packaging/ziptask.rb +316 -0
  130. data/lib/buildr/resources/buildr.icns +0 -0
  131. data/lib/buildr/scala.rb +25 -0
  132. data/lib/buildr/scala/bdd.rb +109 -0
  133. data/lib/buildr/scala/compiler.rb +195 -0
  134. data/lib/buildr/scala/org/apache/buildr/SpecsSingletonRunner$.class +0 -0
  135. data/lib/buildr/scala/org/apache/buildr/SpecsSingletonRunner.class +0 -0
  136. data/lib/buildr/scala/org/apache/buildr/SpecsSingletonRunner.scala +35 -0
  137. data/lib/buildr/scala/shell.rb +55 -0
  138. data/lib/buildr/scala/tests.rb +157 -0
  139. data/lib/buildr/shell.rb +180 -0
  140. data/rakelib/checks.rake +57 -0
  141. data/rakelib/doc.rake +92 -0
  142. data/rakelib/jekylltask.rb +120 -0
  143. data/rakelib/package.rake +73 -0
  144. data/rakelib/release.rake +149 -0
  145. data/rakelib/rspec.rake +73 -0
  146. data/rakelib/setup.rake +54 -0
  147. data/rakelib/stage.rake +213 -0
  148. data/rakelib/stage.rake~ +213 -0
  149. data/spec/addon/drb_spec.rb +328 -0
  150. data/spec/core/application_spec.rb +502 -0
  151. data/spec/core/build_spec.rb +677 -0
  152. data/spec/core/checks_spec.rb +519 -0
  153. data/spec/core/common_spec.rb +670 -0
  154. data/spec/core/compile_spec.rb +583 -0
  155. data/spec/core/extension_spec.rb +93 -0
  156. data/spec/core/generate_spec.rb +33 -0
  157. data/spec/core/project_spec.rb +762 -0
  158. data/spec/core/test_spec.rb +1098 -0
  159. data/spec/core/transport_spec.rb +537 -0
  160. data/spec/core/util_spec.rb +67 -0
  161. data/spec/groovy/bdd_spec.rb +80 -0
  162. data/spec/groovy/compiler_spec.rb +240 -0
  163. data/spec/ide/eclipse_spec.rb +501 -0
  164. data/spec/ide/idea7x_spec.rb +84 -0
  165. data/spec/java/ant_spec.rb +33 -0
  166. data/spec/java/bdd_spec.rb +382 -0
  167. data/spec/java/cobertura_spec.rb +85 -0
  168. data/spec/java/compiler_spec.rb +446 -0
  169. data/spec/java/emma_spec.rb +119 -0
  170. data/spec/java/java_spec.rb +124 -0
  171. data/spec/java/packaging_spec.rb +1134 -0
  172. data/spec/java/test_coverage_helper.rb +257 -0
  173. data/spec/java/tests_spec.rb +493 -0
  174. data/spec/packaging/archive_spec.rb +527 -0
  175. data/spec/packaging/artifact_namespace_spec.rb +654 -0
  176. data/spec/packaging/artifact_spec.rb +795 -0
  177. data/spec/packaging/packaging_helper.rb +63 -0
  178. data/spec/packaging/packaging_spec.rb +684 -0
  179. data/spec/sandbox.rb +142 -0
  180. data/spec/scala/bdd_spec.rb +119 -0
  181. data/spec/scala/compiler_spec.rb +284 -0
  182. data/spec/scala/scala.rb +38 -0
  183. data/spec/scala/tests_spec.rb +261 -0
  184. data/spec/spec_helpers.rb +340 -0
  185. data/spec/version_requirement_spec.rb +129 -0
  186. metadata +383 -0
@@ -0,0 +1,749 @@
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/core/project'
18
+ require 'buildr/core/transports'
19
+ require 'buildr/packaging/artifact_namespace'
20
+
21
+
22
+ module Buildr
23
+
24
+ desc 'Download all artifacts'
25
+ task 'artifacts'
26
+
27
+ desc "Download all artifacts' sources"
28
+ task 'artifacts:sources'
29
+
30
+ # Mixin with a task to make it behave like an artifact. Implemented by the packaging tasks.
31
+ #
32
+ # An artifact has an identifier, group identifier, type, version number and
33
+ # optional classifier. All can be used to locate it in the local repository,
34
+ # download from or upload to a remote repository.
35
+ #
36
+ # The #to_spec and #to_hash methods allow it to be used everywhere an artifact is
37
+ # accepted.
38
+ module ActsAsArtifact
39
+
40
+ ARTIFACT_ATTRIBUTES = [:group, :id, :type, :classifier, :version]
41
+
42
+ class << self
43
+ private
44
+ def included(mod)
45
+ mod.extend self
46
+ end
47
+ end
48
+
49
+ # The artifact identifier.
50
+ attr_reader :id
51
+ # The group identifier.
52
+ attr_reader :group
53
+ # The file type. (Symbol)
54
+ attr_reader :type
55
+ # The version number.
56
+ attr_reader :version
57
+ # Optional artifact classifier.
58
+ attr_reader :classifier
59
+
60
+ def snapshot?
61
+ version =~ /-SNAPSHOT$/
62
+ end
63
+
64
+ # :call-seq:
65
+ # to_spec_hash => Hash
66
+ #
67
+ # Returns the artifact specification as a hash. For example:
68
+ # com.example:app:jar:1.2
69
+ # becomes:
70
+ # { :group=>'com.example',
71
+ # :id=>'app',
72
+ # :type=>:jar,
73
+ # :version=>'1.2' }
74
+ def to_spec_hash
75
+ base = { :group=>group, :id=>id, :type=>type, :version=>version }
76
+ classifier ? base.merge(:classifier=>classifier) : base
77
+ end
78
+ alias_method :to_hash, :to_spec_hash
79
+
80
+ # :call-seq:
81
+ # to_spec => String
82
+ #
83
+ # Returns the artifact specification, in the structure:
84
+ # <group>:<artifact>:<type>:<version>
85
+ # or
86
+ # <group>:<artifact>:<type>:<classifier>:<version>
87
+ def to_spec
88
+ classifier ? "#{group}:#{id}:#{type}:#{classifier}:#{version}" : "#{group}:#{id}:#{type}:#{version}"
89
+ end
90
+
91
+ # :call-seq:
92
+ # pom => Artifact
93
+ #
94
+ # Convenience method that returns a POM artifact.
95
+ def pom
96
+ return self if type == :pom
97
+ Buildr.artifact(:group=>group, :id=>id, :version=>version, :type=>:pom)
98
+ end
99
+
100
+ # :call-seq:
101
+ # sources_artifact => Artifact
102
+ #
103
+ # Convenience method that returns a sources artifact.
104
+ def sources_artifact
105
+ sources_spec = to_spec_hash.merge(:classifier=>'sources')
106
+ sources_task = OptionalArtifact.define_task(Buildr.repositories.locate(sources_spec))
107
+ sources_task.send :apply_spec, sources_spec
108
+ sources_task
109
+ end
110
+
111
+ # :call-seq:
112
+ # pom_xml => string
113
+ #
114
+ # Creates POM XML for this artifact.
115
+ def pom_xml
116
+ xml = Builder::XmlMarkup.new(:indent=>2)
117
+ xml.instruct!
118
+ xml.project do
119
+ xml.modelVersion '4.0.0'
120
+ xml.groupId group
121
+ xml.artifactId id
122
+ xml.version version
123
+ xml.classifier classifier if classifier
124
+ end
125
+ end
126
+
127
+ def install
128
+ pom.install if pom && pom != self
129
+ invoke
130
+ installed = Buildr.repositories.locate(self)
131
+ unless installed == name # If not already in local repository.
132
+ mkpath File.dirname(installed)
133
+ cp name, installed
134
+ info "Installed #{installed}"
135
+ end
136
+ end
137
+
138
+ def uninstall
139
+ installed = Buildr.repositories.locate(self)
140
+ rm installed if File.exist?(installed)
141
+ pom.uninstall if pom && pom != self
142
+ end
143
+
144
+ # :call-seq:
145
+ # upload
146
+ # upload(url)
147
+ # upload(options)
148
+ #
149
+ # Uploads the artifact, its POM and digital signatures to remote server.
150
+ #
151
+ # In the first form, uses the upload options specified by repositories.release_to.
152
+ # In the second form, uses a URL that includes all the relevant information.
153
+ # In the third form, uses a hash with the options :url, :username, :password,
154
+ # and :permissions. All but :url are optional.
155
+ def upload(upload_to = nil)
156
+ # Where do we release to?
157
+ upload_to ||= Buildr.repositories.release_to
158
+ upload_to = { :url=>upload_to } unless Hash === upload_to
159
+ raise ArgumentError, 'Don\'t know where to upload, perhaps you forgot to set repositories.release_to' unless upload_to[:url]
160
+ invoke # Make sure we exist.
161
+
162
+ # Upload POM ahead of package, so we don't fail and find POM-less package (the horror!)
163
+ pom.upload(upload_to) if pom && pom != self
164
+
165
+ # Set the upload URI, including mandatory slash (we expect it to be the base directory).
166
+ # Username/password may be part of URI, or separate entities.
167
+ uri = URI.parse(upload_to[:url].clone)
168
+ uri.path = uri.path + '/' unless uri.path[-1] == '/'
169
+ uri.user = upload_to[:username] if upload_to[:username]
170
+ uri.password = upload_to[:password] if upload_to[:password]
171
+
172
+ # Upload artifact relative to base URL, need to create path before uploading.
173
+ info "Deploying #{to_spec}"
174
+ path = group.gsub('.', '/') + "/#{id}/#{version}/#{File.basename(name)}"
175
+ URI.upload uri + path, name, :permissions=>upload_to[:permissions]
176
+ end
177
+
178
+ protected
179
+
180
+ # Apply specification to this artifact.
181
+ def apply_spec(spec)
182
+ spec = Artifact.to_hash(spec)
183
+ ARTIFACT_ATTRIBUTES.each { |key| instance_variable_set("@#{key}", spec[key]) }
184
+ self
185
+ end
186
+
187
+ def group_path
188
+ group.gsub('.', '/')
189
+ end
190
+
191
+ end
192
+
193
+
194
+ # A file task referencing an artifact in the local repository.
195
+ #
196
+ # This task includes all the artifact attributes (group, id, version, etc). It points
197
+ # to the artifact's path in the local repository. When invoked, it will download the
198
+ # artifact into the local repository if the artifact does not already exist.
199
+ #
200
+ # Note: You can enhance this task to create the artifact yourself, e.g. download it from
201
+ # a site that doesn't have a remote repository structure, copy it from a different disk, etc.
202
+ class Artifact < Rake::FileCreationTask
203
+
204
+ # The default artifact type.
205
+ DEFAULT_TYPE = :jar
206
+
207
+ include ActsAsArtifact
208
+
209
+ class << self
210
+
211
+ # :call-seq:
212
+ # lookup(spec) => Artifact
213
+ #
214
+ # Lookup a previously registered artifact task based on its specification (String or Hash).
215
+ def lookup(spec)
216
+ @artifacts ||= {}
217
+ @artifacts[to_spec(spec)]
218
+ end
219
+
220
+ # :call-seq:
221
+ # list => specs
222
+ #
223
+ # Returns an array of specs for all the registered artifacts. (Anything created from artifact, or package).
224
+ def list
225
+ @artifacts ||= {}
226
+ @artifacts.keys
227
+ end
228
+
229
+ # :call-seq:
230
+ # register(artifacts) => artifacts
231
+ #
232
+ # Register an artifact task(s) for later lookup (see #lookup).
233
+ def register(*tasks)
234
+ @artifacts ||= {}
235
+ fail 'You can only register an artifact task, one of the arguments is not a Task that responds to to_spec' unless
236
+ tasks.all? { |task| task.respond_to?(:to_spec) && task.respond_to?(:invoke) }
237
+ tasks.each { |task| @artifacts[task.to_spec] = task }
238
+ tasks
239
+ end
240
+
241
+ # :call-seq:
242
+ # to_hash(spec_hash) => spec_hash
243
+ # to_hash(spec_string) => spec_hash
244
+ # to_hash(artifact) => spec_hash
245
+ #
246
+ # Turn a spec into a hash. This method accepts a String, Hash or any object that responds to
247
+ # the method to_spec. There are several reasons to use this method:
248
+ # * You can pass anything that could possibly be a spec, and get a hash.
249
+ # * It will check that the spec includes the group identifier, artifact
250
+ # identifier and version number and set the file type, if missing.
251
+ # * It will always return a new specs hash.
252
+ def to_hash(spec)
253
+ if spec.respond_to?(:to_spec)
254
+ to_hash spec.to_spec
255
+ elsif Hash === spec
256
+ rake_check_options spec, :id, :group, :type, :classifier, :version
257
+ # Sanitize the hash and check it's valid.
258
+ spec = ARTIFACT_ATTRIBUTES.inject({}) { |h, k| h[k] = spec[k].to_s if spec[k] ; h }
259
+ fail "Missing group identifier for #{spec.inspect}" unless spec[:group]
260
+ fail "Missing artifact identifier for #{spec.inspect}" unless spec[:id]
261
+ fail "Missing version for #{spec.inspect}" unless spec[:version]
262
+ spec[:type] = (spec[:type] || DEFAULT_TYPE).to_sym
263
+ spec
264
+ elsif String === spec
265
+ group, id, type, version, *rest = spec.split(':').map { |part| part.empty? ? nil : part }
266
+ unless rest.empty?
267
+ # Optional classifier comes before version.
268
+ classifier, version = version, rest.shift
269
+ fail "Expecting <group:id:type:version> or <group:id:type:classifier:version>, found <#{spec}>" unless rest.empty?
270
+ end
271
+ to_hash :group=>group, :id=>id, :type=>type, :version=>version, :classifier=>classifier
272
+ else
273
+ fail 'Expecting a String, Hash or object that responds to to_spec'
274
+ end
275
+ end
276
+
277
+ # :call-seq:
278
+ # to_spec(spec_hash) => spec_string
279
+ #
280
+ # Convert a hash back to a spec string. This method accepts
281
+ # a string, hash or any object that responds to to_spec.
282
+ def to_spec(hash)
283
+ hash = to_hash(hash) unless Hash === hash
284
+ version = ":#{hash[:version]}" if hash[:version]
285
+ classifier = ":#{hash[:classifier]}" if hash[:classifier]
286
+ "#{hash[:group]}:#{hash[:id]}:#{hash[:type] || DEFAULT_TYPE}#{classifier}#{version}"
287
+ end
288
+
289
+ # :call-seq:
290
+ # hash_to_file_name(spec_hash) => file_name
291
+ #
292
+ # Convert a hash spec to a file name.
293
+ def hash_to_file_name(hash)
294
+ version = "-#{hash[:version]}" if hash[:version]
295
+ classifier = "-#{hash[:classifier]}" if hash[:classifier]
296
+ "#{hash[:id]}#{version}#{classifier}.#{hash[:type] || DEFAULT_TYPE}"
297
+ end
298
+
299
+ end
300
+
301
+ def initialize(*args) #:nodoc:
302
+ super
303
+ enhance do |task|
304
+ # Default behavior: download the artifact from one of the remote repositories
305
+ # if the file does not exist. But this default behavior is counter productive
306
+ # if the artifact knows how to build itself (e.g. download from a different location),
307
+ # so don't perform it if the task found a different way to create the artifact.
308
+ task.enhance do
309
+ unless File.exist?(name)
310
+ info "Downloading #{to_spec}"
311
+ download
312
+ pom.invoke rescue nil if pom && pom != self
313
+ end
314
+ end
315
+ end
316
+ end
317
+
318
+ # :call-seq:
319
+ # from(path) => self
320
+ #
321
+ # Use this when you want to install or upload an artifact from a given file, for example:
322
+ # test = artifact('group:id:jar:1.0').from('test.jar')
323
+ # install test
324
+ # See also Buildr#install and Buildr#upload.
325
+ def from(path)
326
+ path = File.expand_path(path.to_s)
327
+ enhance [path] do
328
+ mkpath File.dirname(name)
329
+ pom.invoke unless type == :pom
330
+ cp path, name
331
+ info "Installed #{path} as #{to_spec}"
332
+ end
333
+ unless type == :pom
334
+ pom.enhance do
335
+ mkpath File.dirname(pom.name)
336
+ File.open(pom.name, 'w') { |file| file.write pom.pom_xml }
337
+ end
338
+ end
339
+ self
340
+ end
341
+
342
+ protected
343
+
344
+ # :call-seq:
345
+ # download
346
+ #
347
+ # Downloads an artifact from one of the remote repositories, and stores it in the local
348
+ # repository. Raises an exception if the artifact is not found.
349
+ #
350
+ # This method attempts to download the artifact from each repository in the order in
351
+ # which they are returned from #remote, until successful.
352
+ def download
353
+ trace "Downloading #{to_spec}"
354
+ remote = Buildr.repositories.remote.map { |repo_url| URI === repo_url ? repo_url : URI.parse(repo_url) }
355
+ remote = remote.each { |repo_url| repo_url.path += '/' unless repo_url.path[-1] == '/' }
356
+ fail 'No remote repositories defined!' if remote.empty?
357
+ exact_success = remote.find do |repo_url|
358
+ begin
359
+ path = "#{group_path}/#{id}/#{version}/#{File.basename(name)}"
360
+ URI.download repo_url + path, name
361
+ true
362
+ rescue URI::NotFoundError
363
+ false
364
+ rescue Exception=>error
365
+ info error
366
+ trace error.backtrace.join("\n")
367
+ false
368
+ end
369
+ end
370
+
371
+ if exact_success
372
+ return
373
+ elsif snapshot?
374
+ download_m2_snapshot(remote)
375
+ else
376
+ fail_download(remote)
377
+ end
378
+ end
379
+
380
+ def download_m2_snapshot(remote_uris)
381
+ remote_uris.find do |repo_url|
382
+ snapshot_url = current_snapshot_repo_url(repo_url)
383
+ if snapshot_url
384
+ begin
385
+ URI.download snapshot_url, name
386
+ rescue URI::NotFoundError
387
+ false
388
+ end
389
+ else
390
+ false
391
+ end
392
+ end or fail_download(remote_uris)
393
+ end
394
+
395
+ def current_snapshot_repo_url(repo_url)
396
+ begin
397
+ metadata_path = "#{group_path}/#{id}/#{version}/maven-metadata.xml"
398
+ metadata_xml = StringIO.new
399
+ URI.download repo_url + metadata_path, metadata_xml
400
+ metadata = REXML::Document.new(metadata_xml.string).root
401
+ timestamp = REXML::XPath.first(metadata, '//timestamp').text
402
+ build_number = REXML::XPath.first(metadata, '//buildNumber').text
403
+ snapshot_of = version[0, version.size - 9]
404
+ repo_url + "#{group_path}/#{id}/#{version}/#{id}-#{snapshot_of}-#{timestamp}-#{build_number}.#{type}"
405
+ rescue URI::NotFoundError
406
+ nil
407
+ end
408
+ end
409
+
410
+ def fail_download(remote_uris)
411
+ fail "Failed to download #{to_spec}, tried the following repositories:\n#{remote_uris.join("\n")}"
412
+ end
413
+ end
414
+
415
+
416
+ # An artifact that is optional.
417
+ # If downloading fails, the user will be informed but it will not raise an exception.
418
+ class OptionalArtifact < Artifact
419
+
420
+ protected
421
+
422
+ # If downloading fails, the user will be informed but it will not raise an exception.
423
+ def download
424
+ super
425
+ rescue
426
+ info "Failed to download #{to_spec}. Skipping it."
427
+ end
428
+
429
+ end
430
+
431
+
432
+ # Holds the path to the local repository, URLs for remote repositories, and settings for release server.
433
+ #
434
+ # You can access this object from the #repositories method. For example:
435
+ # puts repositories.local
436
+ # repositories.remote << 'http://example.com/repo'
437
+ # repositories.release_to = 'sftp://example.com/var/www/public/repo'
438
+ class Repositories
439
+ include Singleton
440
+
441
+ # :call-seq:
442
+ # local => path
443
+ #
444
+ # Returns the path to the local repository.
445
+ #
446
+ # The default path is .m2/repository relative to the home directory.
447
+ # You can set this using the M2_REPO environment variable or the repositories/local
448
+ # value in your settings.yaml file.
449
+ def local
450
+ @local ||= File.expand_path(ENV['M2_REPO'] || ENV['local_repo'] ||
451
+ (Buildr.settings.user['repositories'] && Buildr.settings.user['repositories']['local']) ||
452
+ File.join(ENV['HOME'], '.m2/repository'))
453
+ end
454
+
455
+ # :call-seq:
456
+ # local = path
457
+ #
458
+ # Sets the path to the local repository.
459
+ #
460
+ # The best place to set the local repository path is from a buildr.rb file
461
+ # located in your home directory. That way all your projects will share the same
462
+ # path, without affecting other developers collaborating on these projects.
463
+ def local=(dir)
464
+ @local = dir ? File.expand_path(dir) : nil
465
+ end
466
+
467
+ # :call-seq:
468
+ # locate(spec) => path
469
+ #
470
+ # Locates an artifact in the local repository based on its specification, and returns
471
+ # a file path.
472
+ #
473
+ # For example:
474
+ # locate :group=>'log4j', :id=>'log4j', :version=>'1.1'
475
+ # => ~/.m2/repository/log4j/log4j/1.1/log4j-1.1.jar
476
+ def locate(spec)
477
+ spec = Artifact.to_hash(spec)
478
+ File.join(local, spec[:group].split('.'), spec[:id], spec[:version], Artifact.hash_to_file_name(spec))
479
+ end
480
+
481
+ # :call-seq:
482
+ # remote => Array
483
+ #
484
+ # Returns an array of all the remote repository URLs.
485
+ #
486
+ # When downloading artifacts, repositories are accessed in the order in which they appear here.
487
+ # The best way is to add repositories individually, for example:
488
+ # repositories.remote << 'http://example.com/repo'
489
+ #
490
+ # You can also specify remote repositories in the settings.yaml (per user) and build.yaml (per build)
491
+ # files. Both sets of URLs are loaded by default into this array, URLs from the personal setting
492
+ # showing first.
493
+ #
494
+ # For example:
495
+ # repositories:
496
+ # remote:
497
+ # - http://example.com/repo
498
+ # - http://elsewhere.com/repo
499
+ def remote
500
+ unless @remote
501
+ @remote = [Buildr.settings.user, Buildr.settings.build].inject([]) { |repos, hash|
502
+ repos | Array(hash['repositories'] && hash['repositories']['remote'])
503
+ }
504
+ end
505
+ @remote
506
+ end
507
+
508
+ # :call-seq:
509
+ # remote = Array
510
+ # remote = url
511
+ # remote = nil
512
+ #
513
+ # With a String argument, clears the array and set it to that single URL.
514
+ #
515
+ # With an Array argument, clears the array and set it to these specific URLs.
516
+ #
517
+ # With nil, clears the array.
518
+ def remote=(urls)
519
+ case urls
520
+ when nil then @remote = nil
521
+ when Array then @remote = urls.dup
522
+ else @remote = [urls.to_s]
523
+ end
524
+ end
525
+
526
+ # :call-seq:
527
+ # release_to = url
528
+ # release_to = hash
529
+ #
530
+ # Specifies the release server. Accepts a Hash with different repository settings
531
+ # (e.g. url, username, password), or a String to only set the repository URL.
532
+ #
533
+ # Besides the URL, all other settings depend on the transport protocol in use.
534
+ #
535
+ # For example:
536
+ # repositories.release_to = 'sftp://john:secret@example.com/var/www/repo/'
537
+ #
538
+ # repositories.release_to = { :url=>'sftp://example.com/var/www/repo/',
539
+ # :username='john', :password=>'secret' }
540
+ # Or in the settings.yaml file:
541
+ # repositories:
542
+ # release_to: sftp://john:secret@example.com/var/www/repo/
543
+ #
544
+ # repositories:
545
+ # release_to:
546
+ # url: sftp://example.com/var/www/repo/
547
+ # username: john
548
+ # password: secret
549
+ def release_to=(options)
550
+ options = { :url=>options } unless Hash === options
551
+ @release_to = options
552
+ end
553
+
554
+ # :call-seq:
555
+ # release_to => hash
556
+ #
557
+ # Returns the current release server setting as a Hash. This is a more convenient way to
558
+ # configure the settings, as it allows you to specify the settings progressively.
559
+ #
560
+ # For example, the Buildfile will contain the repository URL used by all developers:
561
+ # repositories.release_to[:url] ||= 'sftp://example.com/var/www/repo'
562
+ # Your private buildr.rb will contain your credentials:
563
+ # repositories.release_to[:username] = 'john'
564
+ # repositories.release_to[:password] = 'secret'
565
+ def release_to
566
+ unless @release_to
567
+ value = Buildr.settings.user['repositories'] && Buildr.settings.user['repositories']['release_to']
568
+ @release_to = Hash === value ? value.inject({}) { |hash, (key, value)| hash.update(key.to_sym=>value) } : { :url=>Array(value).first }
569
+ end
570
+ @release_to
571
+ end
572
+
573
+ end
574
+
575
+ # :call-seq:
576
+ # repositories => Repositories
577
+ #
578
+ # Returns an object you can use for setting the local repository path, remote repositories
579
+ # URL and release server settings.
580
+ #
581
+ # See Repositories.
582
+ def repositories
583
+ Repositories.instance
584
+ end
585
+
586
+ # :call-seq:
587
+ # artifact(spec) => Artifact
588
+ # artifact(spec) { |task| ... } => Artifact
589
+ #
590
+ # Creates a file task to download and install the specified artifact in the local repository.
591
+ #
592
+ # You can use a String or a Hash for the artifact specification. The file task will point at
593
+ # the artifact's path inside the local repository. You can then use this tasks as a prerequisite
594
+ # for other tasks.
595
+ #
596
+ # This task will download and install the artifact only once. In fact, it will download and
597
+ # install the artifact if the artifact does not already exist. You can enhance it if you have
598
+ # a different way of creating the artifact in the local repository. See Artifact for more details.
599
+ #
600
+ # For example, to specify an artifact:
601
+ # artifact('log4j:log4j:jar:1.1')
602
+ #
603
+ # To use the artifact in a task:
604
+ # compile.with artifact('log4j:log4j:jar:1.1')
605
+ #
606
+ # To specify an artifact and the means for creating it:
607
+ # download(artifact('dojo:dojo-widget:zip:2.0')=>
608
+ # 'http://download.dojotoolkit.org/release-2.0/dojo-2.0-widget.zip')
609
+ def artifact(spec, &block) #:yields:task
610
+ spec = artifact_ns.fetch(spec) if spec.kind_of?(Symbol)
611
+ spec = Artifact.to_hash(spec)
612
+ unless task = Artifact.lookup(spec)
613
+ task = Artifact.define_task(repositories.locate(spec))
614
+ task.send :apply_spec, spec
615
+ Rake::Task['rake:artifacts'].enhance [task]
616
+ Artifact.register(task)
617
+ Rake::Task['artifacts:sources'].enhance [task.sources_artifact] unless spec[:type] == :pom
618
+ end
619
+ task.enhance &block
620
+ end
621
+
622
+ # :call-seq:
623
+ # artifacts(*spec) => artifacts
624
+ #
625
+ # Handles multiple artifacts at a time. This method is the plural equivalent of
626
+ # #artifact, but can do more things.
627
+ #
628
+ # Returns an array of artifacts built using the supplied
629
+ # specifications, each of which can be:
630
+ # * An artifact specification (String or Hash). Returns the appropriate Artifact task.
631
+ # * An artifact of any other task. Returns the task as is.
632
+ # * A project. Returns all artifacts created (packaged) by that project.
633
+ # * A string. Returns that string, assumed to be a file name.
634
+ # * An array of artifacts or a Struct.
635
+ # * A symbol. Returns the named artifact from the current ArtifactNamespace
636
+ #
637
+ # For example, handling a collection of artifacts:
638
+ # xml = [ xerces, xalan, jaxp ]
639
+ # ws = [ axis, jax-ws, jaxb ]
640
+ # db = [ jpa, mysql, sqltools ]
641
+ # artifacts(xml, ws, db)
642
+ #
643
+ # Using artifacts created by a project:
644
+ # artifacts project('my-app') # All packages
645
+ # artifacts project('my-app').package(:war) # Only the WAR
646
+ def artifacts(*specs, &block)
647
+ specs.flatten.inject([]) do |set, spec|
648
+ case spec
649
+ when ArtifactNamespace
650
+ set |= spec.artifacts
651
+ when Symbol, Hash
652
+ set |= [artifact(spec)]
653
+ when /([^:]+:){2,4}/ # A spec as opposed to a file name.
654
+ set |= [artifact(spec)]
655
+ when String # Must always expand path.
656
+ set |= [File.expand_path(spec)]
657
+ when Project
658
+ set |= artifacts(spec.packages)
659
+ when Rake::Task
660
+ set |= [spec]
661
+ when Struct
662
+ set |= artifacts(spec.values)
663
+ else
664
+ fail "Invalid artifact specification in #{specs.inspect}"
665
+ end
666
+ end
667
+ end
668
+
669
+ def transitive(*specs)
670
+ specs.flatten.inject([]) do |set, spec|
671
+ case spec
672
+ when /([^:]+:){2,4}/ # A spec as opposed to a file name.
673
+ artifact = artifact(spec)
674
+ set |= [artifact] unless artifact.type == :pom
675
+ set |= POM.load(artifact.pom).dependencies.map { |spec| artifact(spec) }
676
+ when Hash
677
+ set |= [transitive(spec)]
678
+ when String # Must always expand path.
679
+ set |= transitive(file(File.expand_path(spec)))
680
+ when Project
681
+ set |= transitive(spec.packages)
682
+ when Rake::Task
683
+ set |= spec.respond_to?(:to_spec) ? transitive(spec.to_spec) : [spec]
684
+ when Struct
685
+ set |= transitive(spec.values)
686
+ else
687
+ fail "Invalid artifact specification in: #{specs.to_s}"
688
+ end
689
+ end
690
+ end
691
+
692
+ # :call-seq:
693
+ # group(ids, :under=>group_name, :version=>number) => artifacts
694
+ #
695
+ # Convenience method for defining multiple artifacts that belong to the same group, type and version.
696
+ # Accepts multiple artifact identifiers followed by two or three hash values:
697
+ # * :under -- The group identifier
698
+ # * :version -- The version number
699
+ # * :type -- The artifact type (optional)
700
+ #
701
+ # For example:
702
+ # group 'xbean', 'xbean_xpath', 'xmlpublic', :under=>'xmlbeans', :version=>'2.1.0'
703
+ # Or:
704
+ # group %w{xbean xbean_xpath xmlpublic}, :under=>'xmlbeans', :version=>'2.1.0'
705
+ def group(*args)
706
+ hash = args.pop
707
+ args.flatten.map { |id| artifact :group=>hash[:under], :type=>hash[:type], :version=>hash[:version], :id=>id }
708
+ end
709
+
710
+ # :call-seq:
711
+ # install(artifacts)
712
+ #
713
+ # Installs the specified artifacts in the local repository as part of the install task.
714
+ #
715
+ # You can use this to install various files in the local repository, for example:
716
+ # install artifact('group:id:jar:1.0').from('some_jar.jar')
717
+ # $ buildr install
718
+ def install(*args, &block)
719
+ artifacts = artifacts(args)
720
+ raise ArgumentError, 'This method can only install artifacts' unless artifacts.all? { |f| f.respond_to?(:to_spec) }
721
+ all = (artifacts + artifacts.map { |artifact| artifact.pom }).uniq
722
+ task('install').tap do |task|
723
+ task.enhance all, &block
724
+ task 'uninstall' do
725
+ all.map(&:to_s ).each { |file| rm file if File.exist?(file) }
726
+ end
727
+ end
728
+ end
729
+
730
+ # :call-seq:
731
+ # upload(artifacts)
732
+ #
733
+ # Uploads the specified artifacts to the release server as part of the upload task.
734
+ #
735
+ # You can use this to upload various files to the release server, for example:
736
+ # upload artifact('group:id:jar:1.0').from('some_jar.jar')
737
+ # $ buildr upload
738
+ def upload(*args, &block)
739
+ artifacts = artifacts(args)
740
+ raise ArgumentError, 'This method can only upload artifacts' unless artifacts.all? { |f| f.respond_to?(:to_spec) }
741
+ task('upload').tap do |task|
742
+ task.enhance &block if block
743
+ task.enhance artifacts do
744
+ artifacts.each { |artifact| artifact.upload }
745
+ end
746
+ end
747
+ end
748
+
749
+ end