mguymon-buildr 1.4.5-java

Sign up to get free protection for your applications and to get access to all the features.
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