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