ittayd-buildr 1.3.4

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