realityforge-buildr 1.5.9
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE +176 -0
- data/NOTICE +26 -0
- data/README.md +3 -0
- data/Rakefile +50 -0
- data/addon/buildr/checkstyle-report.xsl +104 -0
- data/addon/buildr/checkstyle.rb +254 -0
- data/addon/buildr/git_auto_version.rb +36 -0
- data/addon/buildr/gpg.rb +90 -0
- data/addon/buildr/gwt.rb +413 -0
- data/addon/buildr/jacoco.rb +161 -0
- data/addon/buildr/pmd.rb +185 -0
- data/addon/buildr/single_intermediate_layout.rb +71 -0
- data/addon/buildr/spotbugs.rb +265 -0
- data/addon/buildr/top_level_generate_dir.rb +37 -0
- data/addon/buildr/wsgen.rb +192 -0
- data/bin/buildr +20 -0
- data/buildr.gemspec +61 -0
- data/lib/buildr.rb +86 -0
- data/lib/buildr/core/application.rb +705 -0
- data/lib/buildr/core/assets.rb +96 -0
- data/lib/buildr/core/build.rb +587 -0
- data/lib/buildr/core/common.rb +167 -0
- data/lib/buildr/core/compile.rb +599 -0
- data/lib/buildr/core/console.rb +124 -0
- data/lib/buildr/core/doc.rb +275 -0
- data/lib/buildr/core/environment.rb +128 -0
- data/lib/buildr/core/filter.rb +405 -0
- data/lib/buildr/core/help.rb +114 -0
- data/lib/buildr/core/progressbar.rb +161 -0
- data/lib/buildr/core/project.rb +994 -0
- data/lib/buildr/core/test.rb +776 -0
- data/lib/buildr/core/transports.rb +456 -0
- data/lib/buildr/core/util.rb +77 -0
- data/lib/buildr/ide/idea.rb +1664 -0
- data/lib/buildr/java/commands.rb +230 -0
- data/lib/buildr/java/compiler.rb +85 -0
- data/lib/buildr/java/custom_pom.rb +300 -0
- data/lib/buildr/java/doc.rb +62 -0
- data/lib/buildr/java/packaging.rb +393 -0
- data/lib/buildr/java/pom.rb +191 -0
- data/lib/buildr/java/test_result.rb +54 -0
- data/lib/buildr/java/tests.rb +111 -0
- data/lib/buildr/packaging/archive.rb +586 -0
- data/lib/buildr/packaging/artifact.rb +1113 -0
- data/lib/buildr/packaging/artifact_namespace.rb +1010 -0
- data/lib/buildr/packaging/artifact_search.rb +138 -0
- data/lib/buildr/packaging/package.rb +237 -0
- data/lib/buildr/packaging/version_requirement.rb +189 -0
- data/lib/buildr/packaging/zip.rb +189 -0
- data/lib/buildr/packaging/ziptask.rb +387 -0
- data/lib/buildr/version.rb +18 -0
- data/rakelib/release.rake +99 -0
- data/spec/addon/checkstyle_spec.rb +58 -0
- data/spec/core/application_spec.rb +576 -0
- data/spec/core/build_spec.rb +922 -0
- data/spec/core/common_spec.rb +670 -0
- data/spec/core/compile_spec.rb +656 -0
- data/spec/core/console_spec.rb +65 -0
- data/spec/core/doc_spec.rb +194 -0
- data/spec/core/extension_spec.rb +200 -0
- data/spec/core/project_spec.rb +736 -0
- data/spec/core/test_spec.rb +1131 -0
- data/spec/core/transport_spec.rb +452 -0
- data/spec/core/util_spec.rb +154 -0
- data/spec/ide/idea_spec.rb +1952 -0
- data/spec/java/commands_spec.rb +79 -0
- data/spec/java/compiler_spec.rb +274 -0
- data/spec/java/custom_pom_spec.rb +165 -0
- data/spec/java/doc_spec.rb +55 -0
- data/spec/java/packaging_spec.rb +786 -0
- data/spec/java/pom_spec.rb +162 -0
- data/spec/java/test_coverage_helper.rb +257 -0
- data/spec/java/tests_spec.rb +224 -0
- data/spec/packaging/archive_spec.rb +686 -0
- data/spec/packaging/artifact_namespace_spec.rb +757 -0
- data/spec/packaging/artifact_spec.rb +1351 -0
- data/spec/packaging/packaging_helper.rb +63 -0
- data/spec/packaging/packaging_spec.rb +690 -0
- data/spec/sandbox.rb +166 -0
- data/spec/spec_helpers.rb +420 -0
- data/spec/version_requirement_spec.rb +145 -0
- data/spec/xpath_matchers.rb +123 -0
- metadata +295 -0
@@ -0,0 +1,1113 @@
|
|
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
|
+
module Buildr #:nodoc:
|
17
|
+
|
18
|
+
desc 'Download all artifacts'
|
19
|
+
task 'artifacts'
|
20
|
+
|
21
|
+
desc "Download all artifacts' sources"
|
22
|
+
task 'artifacts:sources'
|
23
|
+
|
24
|
+
desc "Download all artifacts' external annotations"
|
25
|
+
task 'artifacts:annotations'
|
26
|
+
|
27
|
+
desc "Download all artifacts' javadoc"
|
28
|
+
task 'artifacts:javadoc'
|
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
|
+
MAVEN_METADATA = 'maven-metadata.xml'
|
42
|
+
|
43
|
+
class << self
|
44
|
+
private
|
45
|
+
|
46
|
+
# :stopdoc:
|
47
|
+
def included(mod)
|
48
|
+
mod.extend self
|
49
|
+
end
|
50
|
+
|
51
|
+
def extend_object(base)
|
52
|
+
base.instance_eval { alias :install_old :install } if base.respond_to? :install
|
53
|
+
base.instance_eval { alias :uninstall_old :uninstall } if base.respond_to? :uninstall
|
54
|
+
base.instance_eval { alias :upload_old :upload } if base.respond_to? :upload
|
55
|
+
super
|
56
|
+
end
|
57
|
+
|
58
|
+
def extended(base)
|
59
|
+
#We try to keep the previous instance methods defined on the base instance if there were ones.
|
60
|
+
base.instance_eval { alias :install :install_old } if base.respond_to? :install_old
|
61
|
+
base.instance_eval { alias :uninstall :uninstall_old } if base.respond_to? :uninstall_old
|
62
|
+
base.instance_eval { alias :upload :upload_old } if base.respond_to? :upload_old
|
63
|
+
end
|
64
|
+
|
65
|
+
# :startdoc:
|
66
|
+
end
|
67
|
+
|
68
|
+
# The artifact identifier.
|
69
|
+
attr_reader :id
|
70
|
+
# The group identifier.
|
71
|
+
attr_reader :group
|
72
|
+
# The file type. (Symbol)
|
73
|
+
attr_reader :type
|
74
|
+
# The version number.
|
75
|
+
attr_reader :version
|
76
|
+
# Optional artifact classifier.
|
77
|
+
attr_reader :classifier
|
78
|
+
|
79
|
+
attr_accessor :buildr_project
|
80
|
+
|
81
|
+
def snapshot?
|
82
|
+
version =~ /-SNAPSHOT$/
|
83
|
+
end
|
84
|
+
|
85
|
+
def final_version
|
86
|
+
return version unless snapshot?
|
87
|
+
Time.now.strftime("%Y%m%d.%H%M%S")
|
88
|
+
end
|
89
|
+
|
90
|
+
# :call-seq:
|
91
|
+
# to_spec_hash => Hash
|
92
|
+
#
|
93
|
+
# Returns the artifact specification as a hash. For example:
|
94
|
+
# com.example:app:jar:1.2
|
95
|
+
# becomes:
|
96
|
+
# { :group=>'com.example',
|
97
|
+
# :id=>'app',
|
98
|
+
# :type=>:jar,
|
99
|
+
# :version=>'1.2' }
|
100
|
+
def to_spec_hash
|
101
|
+
base = { :group=>group, :id=>id, :type=>type, :version=>version }
|
102
|
+
classifier ? base.merge(:classifier=>classifier) : base
|
103
|
+
end
|
104
|
+
alias_method :to_hash, :to_spec_hash
|
105
|
+
|
106
|
+
# :call-seq:
|
107
|
+
# to_spec => String
|
108
|
+
#
|
109
|
+
# Returns the artifact specification, in the structure:
|
110
|
+
# <group>:<artifact>:<type>:<version>
|
111
|
+
# or
|
112
|
+
# <group>:<artifact>:<type>:<classifier>:<version>
|
113
|
+
def to_spec
|
114
|
+
classifier ? "#{group}:#{id}:#{type}:#{classifier}:#{version}" : "#{group}:#{id}:#{type}:#{version}"
|
115
|
+
end
|
116
|
+
|
117
|
+
# :call-seq:
|
118
|
+
# pom => Artifact
|
119
|
+
#
|
120
|
+
# Convenience method that returns a POM artifact.
|
121
|
+
def pom
|
122
|
+
return self if type == :pom
|
123
|
+
Buildr.artifact(:group=>group, :id=>id, :version=>version, :type=>:pom)
|
124
|
+
end
|
125
|
+
|
126
|
+
# :call-seq:
|
127
|
+
# sources_artifact => Artifact
|
128
|
+
#
|
129
|
+
# Convenience method that returns a sources artifact.
|
130
|
+
def sources_artifact
|
131
|
+
sources_spec = to_spec_hash.merge(:classifier=>'sources')
|
132
|
+
sources_task = OptionalArtifact.define_task(Buildr.repositories.locate(sources_spec))
|
133
|
+
sources_task.send :apply_spec, sources_spec
|
134
|
+
sources_task
|
135
|
+
end
|
136
|
+
|
137
|
+
# :call-seq:
|
138
|
+
# javadoc_artifact => Artifact
|
139
|
+
#
|
140
|
+
# Convenience method that returns the associated javadoc artifact
|
141
|
+
def javadoc_artifact
|
142
|
+
javadoc_spec = to_spec_hash.merge(:classifier=>'javadoc')
|
143
|
+
javadoc_task = OptionalArtifact.define_task(Buildr.repositories.locate(javadoc_spec))
|
144
|
+
javadoc_task.send :apply_spec, javadoc_spec
|
145
|
+
javadoc_task
|
146
|
+
end
|
147
|
+
|
148
|
+
# :call-seq:
|
149
|
+
# annotations_artifact => Artifact
|
150
|
+
#
|
151
|
+
# Convenience method that returns an annotations artifact. The annotations artifact is used by
|
152
|
+
# Intellij IDEA as a source of external annotations.
|
153
|
+
def annotations_artifact
|
154
|
+
annotations_spec = to_spec_hash.merge(:classifier=>'annotations')
|
155
|
+
annotations_task = OptionalArtifact.define_task(Buildr.repositories.locate(annotations_spec))
|
156
|
+
annotations_task.send :apply_spec, annotations_spec
|
157
|
+
annotations_task
|
158
|
+
end
|
159
|
+
|
160
|
+
# :call-seq:
|
161
|
+
# pom_xml => string
|
162
|
+
#
|
163
|
+
# Creates POM XML for this artifact.
|
164
|
+
def pom_xml
|
165
|
+
if self.buildr_project
|
166
|
+
Buildr::CustomPom.pom_xml(self.buildr_project, self)
|
167
|
+
else
|
168
|
+
Proc.new do
|
169
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
170
|
+
xml.instruct!
|
171
|
+
xml.project do
|
172
|
+
xml.modelVersion '4.0.0'
|
173
|
+
xml.groupId group
|
174
|
+
xml.artifactId id
|
175
|
+
xml.version version
|
176
|
+
xml.classifier classifier if classifier
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# :call-seq:
|
183
|
+
# maven_metadata_xml => string
|
184
|
+
#
|
185
|
+
# Creates Maven Metadata XML content for this artifact.
|
186
|
+
def maven_metadata_xml
|
187
|
+
xml = Builder::XmlMarkup.new(:indent=>2)
|
188
|
+
xml.instruct!
|
189
|
+
xml.metadata do
|
190
|
+
xml.groupId group
|
191
|
+
xml.artifactId id
|
192
|
+
xml.version version
|
193
|
+
xml.versioning do
|
194
|
+
xml.snapshot do
|
195
|
+
xml.timestamp final_version
|
196
|
+
xml.buildNumber 1
|
197
|
+
end
|
198
|
+
xml.lastupdated Time.now.strftime("%Y%m%d%H%M%S")
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def install
|
204
|
+
invoke
|
205
|
+
in_local_repository = Buildr.repositories.locate(self)
|
206
|
+
if pom && pom != self && classifier.nil?
|
207
|
+
pom.invoke
|
208
|
+
pom.install
|
209
|
+
end
|
210
|
+
if name != in_local_repository
|
211
|
+
mkpath File.dirname(in_local_repository)
|
212
|
+
cp name, in_local_repository, :preserve => false
|
213
|
+
info "Installed #{name} to #{in_local_repository}"
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def uninstall
|
218
|
+
installed = Buildr.repositories.locate(self)
|
219
|
+
rm installed if File.exist?(installed)
|
220
|
+
pom.uninstall if pom && pom != self && classifier.nil?
|
221
|
+
end
|
222
|
+
|
223
|
+
# :call-seq:
|
224
|
+
# upload
|
225
|
+
# upload(url)
|
226
|
+
# upload(options)
|
227
|
+
#
|
228
|
+
# Uploads the artifact, its POM and digital signatures to remote server.
|
229
|
+
#
|
230
|
+
# In the first form, uses the upload options specified by repositories.release_to
|
231
|
+
# or repositories.snapshot_to if the subject is a snapshot artifact.
|
232
|
+
# In the second form, uses a URL that includes all the relevant information.
|
233
|
+
# In the third form, uses a hash with the options :url, :username, :password,
|
234
|
+
# and :permissions. All but :url are optional.
|
235
|
+
def upload(upload_to = nil)
|
236
|
+
upload_task(upload_to).invoke
|
237
|
+
end
|
238
|
+
|
239
|
+
def upload_task(upload_to = nil)
|
240
|
+
upload_to ||= Buildr.repositories.snapshot_to if snapshot? && Buildr.repositories.snapshot_to != nil && Buildr.repositories.snapshot_to[:url] != nil
|
241
|
+
upload_to ||= Buildr.repositories.release_to
|
242
|
+
upload_to = { :url=>upload_to } unless Hash === upload_to
|
243
|
+
raise ArgumentError, 'Don\'t know where to upload, perhaps you forgot to set repositories.release_to' unless upload_to[:url]
|
244
|
+
|
245
|
+
# Set the upload URI, including mandatory slash (we expect it to be the base directory).
|
246
|
+
# Username/password may be part of URI, or separate entities.
|
247
|
+
uri = URI.parse(upload_to[:url].clone)
|
248
|
+
uri.path = uri.path + '/' unless uri.path[-1] == '/'
|
249
|
+
to_escape = "!\"\#$%&'()*+,-./:;<=>?@{}|~`'"
|
250
|
+
uri.user = URI.encode(upload_to[:username], to_escape) if upload_to[:username]
|
251
|
+
uri.password = URI.encode(upload_to[:password], to_escape) if upload_to[:password]
|
252
|
+
|
253
|
+
path = group.gsub('.', '/') + "/#{id}/#{version}/#{upload_name}"
|
254
|
+
|
255
|
+
unless task = Buildr.application.lookup(uri+path)
|
256
|
+
deps = [self]
|
257
|
+
deps << pom.upload_task( upload_to ) if pom && pom != self && classifier.nil?
|
258
|
+
|
259
|
+
task = Rake::Task.define_task uri + path => deps do
|
260
|
+
# Upload artifact relative to base URL, need to create path before uploading.
|
261
|
+
options = upload_to[:options] || {:permissions => upload_to[:permissions]}
|
262
|
+
info "Deploying #{to_spec}"
|
263
|
+
URI.upload uri + path, name, options
|
264
|
+
if snapshot? && pom != self
|
265
|
+
maven_metadata = group.gsub('.', '/') + "/#{id}/#{version}/#{MAVEN_METADATA}"
|
266
|
+
URI.write uri + maven_metadata, maven_metadata_xml, :permissions => upload_to[:permissions]
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
task
|
271
|
+
end
|
272
|
+
|
273
|
+
protected
|
274
|
+
|
275
|
+
# Apply specification to this artifact.
|
276
|
+
def apply_spec(spec)
|
277
|
+
spec = Artifact.to_hash(spec)
|
278
|
+
ARTIFACT_ATTRIBUTES.each { |key| instance_variable_set("@#{key}", spec[key]) }
|
279
|
+
self
|
280
|
+
end
|
281
|
+
|
282
|
+
def group_path
|
283
|
+
group.gsub('.', '/')
|
284
|
+
end
|
285
|
+
|
286
|
+
def upload_name
|
287
|
+
return File.basename(name) unless snapshot?
|
288
|
+
return File.basename(name).gsub(/SNAPSHOT/, "#{final_version}-1")
|
289
|
+
end
|
290
|
+
|
291
|
+
def extract_type(type)
|
292
|
+
return :jar if type == :bundle
|
293
|
+
type
|
294
|
+
end
|
295
|
+
|
296
|
+
end
|
297
|
+
|
298
|
+
|
299
|
+
# A file task referencing an artifact in the local repository.
|
300
|
+
#
|
301
|
+
# This task includes all the artifact attributes (group, id, version, etc). It points
|
302
|
+
# to the artifact's path in the local repository. When invoked, it will download the
|
303
|
+
# artifact into the local repository if the artifact does not already exist.
|
304
|
+
#
|
305
|
+
# Note: You can enhance this task to create the artifact yourself, e.g. download it from
|
306
|
+
# a site that doesn't have a remote repository structure, copy it from a different disk, etc.
|
307
|
+
class Artifact < Rake::FileTask
|
308
|
+
|
309
|
+
# The default artifact type.
|
310
|
+
DEFAULT_TYPE = :jar
|
311
|
+
|
312
|
+
include ActsAsArtifact, Buildr
|
313
|
+
|
314
|
+
class << self
|
315
|
+
|
316
|
+
# :call-seq:
|
317
|
+
# lookup(spec) => Artifact
|
318
|
+
#
|
319
|
+
# Lookup a previously registered artifact task based on its specification (String or Hash).
|
320
|
+
def lookup(spec)
|
321
|
+
@artifacts ||= {}
|
322
|
+
@artifacts[to_spec(spec)]
|
323
|
+
end
|
324
|
+
|
325
|
+
# :call-seq:
|
326
|
+
# list => specs
|
327
|
+
#
|
328
|
+
# Returns an array of specs for all the registered artifacts. (Anything created from artifact, or package).
|
329
|
+
def list
|
330
|
+
@artifacts ||= {}
|
331
|
+
@artifacts.keys
|
332
|
+
end
|
333
|
+
|
334
|
+
# :call-seq:
|
335
|
+
# register(artifacts) => artifacts
|
336
|
+
#
|
337
|
+
# Register an artifact task(s) for later lookup (see #lookup).
|
338
|
+
def register(*tasks)
|
339
|
+
@artifacts ||= {}
|
340
|
+
fail 'You can only register an artifact task, one of the arguments is not a Task that responds to to_spec' unless
|
341
|
+
tasks.all? { |task| task.respond_to?(:to_spec) && task.respond_to?(:invoke) }
|
342
|
+
tasks.each { |task| @artifacts[task.to_spec] = task }
|
343
|
+
tasks
|
344
|
+
end
|
345
|
+
|
346
|
+
# :call-seq:
|
347
|
+
# to_hash(spec_hash) => spec_hash
|
348
|
+
# to_hash(spec_string) => spec_hash
|
349
|
+
# to_hash(artifact) => spec_hash
|
350
|
+
#
|
351
|
+
# Turn a spec into a hash. This method accepts a String, Hash or any object that responds to
|
352
|
+
# the method to_spec. There are several reasons to use this method:
|
353
|
+
# * You can pass anything that could possibly be a spec, and get a hash.
|
354
|
+
# * It will check that the spec includes the group identifier, artifact
|
355
|
+
# identifier and version number and set the file type, if missing.
|
356
|
+
# * It will always return a new specs hash.
|
357
|
+
def to_hash(spec)
|
358
|
+
if spec.respond_to?(:to_spec)
|
359
|
+
to_hash spec.to_spec
|
360
|
+
elsif Hash === spec
|
361
|
+
rake_check_options spec, :id, :group, :type, :classifier, :version, :scope
|
362
|
+
# Sanitize the hash and check it's valid.
|
363
|
+
spec = ARTIFACT_ATTRIBUTES.inject({}) { |h, k| h[k] = spec[k].to_s if spec[k] ; h }
|
364
|
+
fail "Missing group identifier for #{spec.inspect}" unless spec[:group]
|
365
|
+
fail "Missing artifact identifier for #{spec.inspect}" unless spec[:id]
|
366
|
+
fail "Missing version for #{spec.inspect}" unless spec[:version]
|
367
|
+
spec[:type] = (spec[:type] || DEFAULT_TYPE).to_sym
|
368
|
+
spec
|
369
|
+
elsif String === spec
|
370
|
+
group, id, type, version, *rest = spec.split(':').map { |part| part.empty? ? nil : part }
|
371
|
+
unless rest.empty?
|
372
|
+
# Optional classifier comes before version.
|
373
|
+
classifier, version = version, rest.shift
|
374
|
+
fail "Expecting <group:id:type:version> or <group:id:type:classifier:version>, found <#{spec}>" unless rest.empty?
|
375
|
+
end
|
376
|
+
to_hash :group=>group, :id=>id, :type=>type, :version=>version, :classifier=>classifier
|
377
|
+
else
|
378
|
+
fail 'Expecting a String, Hash or object that responds to to_spec'
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
# :call-seq:
|
383
|
+
# to_spec(spec_hash) => spec_string
|
384
|
+
#
|
385
|
+
# Convert a hash back to a spec string. This method accepts
|
386
|
+
# a string, hash or any object that responds to to_spec.
|
387
|
+
def to_spec(hash)
|
388
|
+
hash = to_hash(hash) unless Hash === hash
|
389
|
+
version = ":#{hash[:version]}" if hash[:version]
|
390
|
+
classifier = ":#{hash[:classifier]}" if hash[:classifier]
|
391
|
+
"#{hash[:group]}:#{hash[:id]}:#{hash[:type] || DEFAULT_TYPE}#{classifier}#{version}"
|
392
|
+
end
|
393
|
+
|
394
|
+
# :call-seq:
|
395
|
+
# hash_to_file_name(spec_hash) => file_name
|
396
|
+
#
|
397
|
+
# Convert a hash spec to a file name.
|
398
|
+
def hash_to_file_name(hash)
|
399
|
+
version = "-#{hash[:version]}" if hash[:version]
|
400
|
+
classifier = "-#{hash[:classifier]}" if hash[:classifier]
|
401
|
+
"#{hash[:id]}#{version}#{classifier}.#{extract_type(hash[:type]) || DEFAULT_TYPE}"
|
402
|
+
end
|
403
|
+
|
404
|
+
end
|
405
|
+
|
406
|
+
def initialize(*args) #:nodoc:
|
407
|
+
super
|
408
|
+
enhance do |task|
|
409
|
+
# Default behavior: download the artifact from one of the remote repositories
|
410
|
+
# if the file does not exist. But this default behavior is counter productive
|
411
|
+
# if the artifact knows how to build itself (e.g. download from a different location),
|
412
|
+
# so don't perform it if the task found a different way to create the artifact.
|
413
|
+
task.enhance do
|
414
|
+
if download_needed? task
|
415
|
+
info "Downloading #{to_spec}"
|
416
|
+
download
|
417
|
+
pom.invoke rescue nil if pom && pom != self && classifier.nil?
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
# :call-seq:
|
424
|
+
# from(path) => self
|
425
|
+
#
|
426
|
+
# Use this when you want to install or upload an artifact from a given file, for example:
|
427
|
+
# test = artifact('group:id:jar:1.0').from('test.jar')
|
428
|
+
# install test
|
429
|
+
# See also Buildr#install and Buildr#upload.
|
430
|
+
def from(path)
|
431
|
+
@from = path.is_a?(Rake::Task) ? path : File.expand_path(path.to_s)
|
432
|
+
enhance [@from] do
|
433
|
+
mkpath File.dirname(name)
|
434
|
+
cp @from.to_s, name
|
435
|
+
end
|
436
|
+
pom.content pom_xml unless pom == self || pom.has_content?
|
437
|
+
self
|
438
|
+
end
|
439
|
+
|
440
|
+
# :call-seq:
|
441
|
+
# content(string) => self
|
442
|
+
# content(Proc) => self
|
443
|
+
#
|
444
|
+
# Use this when you want to install or upload an artifact from a given content, for example:
|
445
|
+
# readme = artifact('com.example:readme:txt:1.0').content(<<-EOF
|
446
|
+
# Please visit our website at http://example.com/readme
|
447
|
+
# <<EOF
|
448
|
+
# install readme
|
449
|
+
#
|
450
|
+
# If the argument is a Proc the it will be called when the artifact is written out. If the result is not a proc
|
451
|
+
# and not a string, it will be converted to a string using to_s
|
452
|
+
def content(string = nil)
|
453
|
+
unless string
|
454
|
+
@content = @content.call if @content.is_a?(Proc)
|
455
|
+
return @content
|
456
|
+
end
|
457
|
+
|
458
|
+
unless @content
|
459
|
+
enhance do
|
460
|
+
write name, self.content
|
461
|
+
end
|
462
|
+
|
463
|
+
class << self
|
464
|
+
# Force overwriting target since we don't have source file
|
465
|
+
# to check for timestamp modification
|
466
|
+
def needed?
|
467
|
+
true
|
468
|
+
end
|
469
|
+
end
|
470
|
+
end
|
471
|
+
@content = string
|
472
|
+
pom.content pom_xml unless pom == self || pom.has_content?
|
473
|
+
self
|
474
|
+
end
|
475
|
+
|
476
|
+
protected
|
477
|
+
|
478
|
+
def has_content?
|
479
|
+
@from || @content
|
480
|
+
end
|
481
|
+
|
482
|
+
# :call-seq:
|
483
|
+
# download
|
484
|
+
#
|
485
|
+
# Downloads an artifact from one of the remote repositories, and stores it in the local
|
486
|
+
# repository. Raises an exception if the artifact is not found.
|
487
|
+
#
|
488
|
+
# This method attempts to download the artifact from each repository in the order in
|
489
|
+
# which they are returned from #remote, until successful.
|
490
|
+
def download
|
491
|
+
trace "Downloading #{to_spec}"
|
492
|
+
remote = Buildr.repositories.remote_uri
|
493
|
+
remote = remote.each { |repo_url| repo_url.path += '/' unless repo_url.path[-1] == '/' }
|
494
|
+
fail "Unable to download #{to_spec}. No remote repositories defined." if remote.empty?
|
495
|
+
exact_success = remote.find do |repo_url|
|
496
|
+
begin
|
497
|
+
path = "#{group_path}/#{id}/#{version}/#{File.basename(name)}"
|
498
|
+
download_artifact(repo_url + path)
|
499
|
+
true
|
500
|
+
rescue URI::NotFoundError
|
501
|
+
false
|
502
|
+
rescue Exception=>error
|
503
|
+
info error
|
504
|
+
trace error.backtrace.join("\n")
|
505
|
+
false
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
if exact_success
|
510
|
+
return
|
511
|
+
elsif snapshot?
|
512
|
+
download_m2_snapshot(remote)
|
513
|
+
else
|
514
|
+
fail_download(remote)
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
def download_m2_snapshot(remote_uris)
|
519
|
+
remote_uris.find do |repo_url|
|
520
|
+
snapshot_url = current_snapshot_repo_url(repo_url)
|
521
|
+
if snapshot_url
|
522
|
+
begin
|
523
|
+
download_artifact snapshot_url
|
524
|
+
true
|
525
|
+
rescue URI::NotFoundError
|
526
|
+
false
|
527
|
+
end
|
528
|
+
else
|
529
|
+
false
|
530
|
+
end
|
531
|
+
end or fail_download(remote_uris)
|
532
|
+
end
|
533
|
+
|
534
|
+
def current_snapshot_repo_url(repo_url)
|
535
|
+
begin
|
536
|
+
metadata_path = "#{group_path}/#{id}/#{version}/maven-metadata.xml"
|
537
|
+
metadata_xml = StringIO.new
|
538
|
+
URI.download repo_url + metadata_path, metadata_xml
|
539
|
+
metadata = REXML::Document.new(metadata_xml.string).root
|
540
|
+
timestamp = REXML::XPath.first(metadata, '//timestamp')
|
541
|
+
build_number = REXML::XPath.first(metadata, '//buildNumber')
|
542
|
+
error "No timestamp provided for the snapshot #{to_spec}" if timestamp.nil?
|
543
|
+
error "No build number provided for the snapshot #{to_spec}" if build_number.nil?
|
544
|
+
return nil if timestamp.nil? || build_number.nil?
|
545
|
+
snapshot_of = version[0, version.size - 9]
|
546
|
+
classifier_snippet = (classifier != nil) ? "-#{classifier}" : ""
|
547
|
+
repo_url + "#{group_path}/#{id}/#{version}/#{id}-#{snapshot_of}-#{timestamp.text}-#{build_number.text}#{classifier_snippet}.#{type}"
|
548
|
+
rescue URI::NotFoundError
|
549
|
+
nil
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
def fail_download(remote_uris)
|
554
|
+
fail "Failed to download #{to_spec}, tried the following repositories:\n#{remote_uris.join("\n")}"
|
555
|
+
end
|
556
|
+
|
557
|
+
protected
|
558
|
+
|
559
|
+
# :call-seq:
|
560
|
+
# needed?
|
561
|
+
#
|
562
|
+
# Validates whether artifact is required to be downloaded from repository
|
563
|
+
def needed?
|
564
|
+
return true if snapshot? && File.exist?(name) && (update_snapshot? || old?)
|
565
|
+
super
|
566
|
+
end
|
567
|
+
|
568
|
+
private
|
569
|
+
|
570
|
+
# :call-seq:
|
571
|
+
# download_artifact
|
572
|
+
#
|
573
|
+
# Downloads artifact from given repository,
|
574
|
+
# supports downloading snapshot artifact with relocation on succeed to local repository
|
575
|
+
def download_artifact(path)
|
576
|
+
download_file = "#{name}.#{Time.new.to_i}"
|
577
|
+
begin
|
578
|
+
URI.download path, download_file
|
579
|
+
if File.exist?(download_file)
|
580
|
+
FileUtils.mkdir_p(File.dirname(name))
|
581
|
+
FileUtils.mv(download_file, name)
|
582
|
+
end
|
583
|
+
ensure
|
584
|
+
File.delete(download_file) if File.exist?(download_file)
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
# :call-seq:
|
589
|
+
# :download_needed?
|
590
|
+
#
|
591
|
+
# Validates whether artifact is required to be downloaded from repository
|
592
|
+
def download_needed?(task)
|
593
|
+
return true if !File.exist?(name)
|
594
|
+
|
595
|
+
if snapshot?
|
596
|
+
return false if offline? && File.exist?(name)
|
597
|
+
return true if update_snapshot? || old?
|
598
|
+
end
|
599
|
+
|
600
|
+
return false
|
601
|
+
end
|
602
|
+
|
603
|
+
def update_snapshot?
|
604
|
+
Buildr.application.options.update_snapshots
|
605
|
+
end
|
606
|
+
|
607
|
+
def offline?
|
608
|
+
Buildr.application.options.work_offline
|
609
|
+
end
|
610
|
+
|
611
|
+
# :call-seq:
|
612
|
+
# old?
|
613
|
+
#
|
614
|
+
# Checks whether existing artifact is older than period from build settings or one day
|
615
|
+
def old?
|
616
|
+
settings = Buildr.application.settings
|
617
|
+
time_to_be_old = settings.user[:expire_time] || settings.build[:expire_time] || 60 * 60 * 24
|
618
|
+
File.mtime(name).to_i < (Time.new.to_i - time_to_be_old)
|
619
|
+
end
|
620
|
+
|
621
|
+
end
|
622
|
+
|
623
|
+
|
624
|
+
# An artifact that is optional.
|
625
|
+
# If downloading fails, the user will be informed but it will not raise an exception.
|
626
|
+
class OptionalArtifact < Artifact
|
627
|
+
|
628
|
+
protected
|
629
|
+
|
630
|
+
# If downloading fails, the user will be informed but it will not raise an exception.
|
631
|
+
def download
|
632
|
+
super
|
633
|
+
rescue
|
634
|
+
info "Failed to download #{to_spec}. Skipping it."
|
635
|
+
end
|
636
|
+
|
637
|
+
end
|
638
|
+
|
639
|
+
|
640
|
+
# Holds the path to the local repository, URLs for remote repositories, and settings for release server.
|
641
|
+
#
|
642
|
+
# You can access this object from the #repositories method. For example:
|
643
|
+
# repositories.remote << 'http://example.com/repo'
|
644
|
+
class Repositories
|
645
|
+
include Singleton
|
646
|
+
|
647
|
+
# :call-seq:
|
648
|
+
# local => path
|
649
|
+
#
|
650
|
+
# Returns the path to the local repository.
|
651
|
+
#
|
652
|
+
# The default path is .m2/repository relative to the home directory.
|
653
|
+
# You can set this using the M2_REPO environment variable or the repositories/local
|
654
|
+
# value in your settings.yaml file.
|
655
|
+
def local
|
656
|
+
@local ||= File.expand_path(ENV['M2_REPO'] || ENV['local_repo'] ||
|
657
|
+
(Buildr.settings.user['repositories'] && Buildr.settings.user['repositories']['local']) ||
|
658
|
+
File.join(ENV['HOME'], '.m2/repository'))
|
659
|
+
end
|
660
|
+
|
661
|
+
# :call-seq:
|
662
|
+
# local = path
|
663
|
+
#
|
664
|
+
# Sets the path to the local repository.
|
665
|
+
#
|
666
|
+
# The best place to set the local repository path is from a buildr.rb file
|
667
|
+
# located in the .buildr directory under your home directory. That way all
|
668
|
+
# your projects will share the same path, without affecting other developers
|
669
|
+
# collaborating on these projects.
|
670
|
+
def local=(dir)
|
671
|
+
@local = dir ? File.expand_path(dir) : nil
|
672
|
+
end
|
673
|
+
|
674
|
+
# :call-seq:
|
675
|
+
# locate(spec) => path
|
676
|
+
#
|
677
|
+
# Locates an artifact in the local repository based on its specification, and returns
|
678
|
+
# a file path.
|
679
|
+
#
|
680
|
+
# For example:
|
681
|
+
# locate :group=>'log4j', :id=>'log4j', :version=>'1.1'
|
682
|
+
# => ~/.m2/repository/log4j/log4j/1.1/log4j-1.1.jar
|
683
|
+
def locate(spec)
|
684
|
+
spec = Artifact.to_hash(spec)
|
685
|
+
File.join(local, spec[:group].split('.'), spec[:id], spec[:version], Artifact.hash_to_file_name(spec))
|
686
|
+
end
|
687
|
+
|
688
|
+
# :call-seq:
|
689
|
+
# mirrors => Array
|
690
|
+
#
|
691
|
+
# Returns an array of all the mirror repository URLs.
|
692
|
+
#
|
693
|
+
# Mirrors override remote repositories defined in the project.
|
694
|
+
# The best way is to add repositories to the user settings file under '$HOME/.buildr/settings.yaml'.
|
695
|
+
# For example:
|
696
|
+
# repositories:
|
697
|
+
# mirrors:
|
698
|
+
# - http://example.com/repository
|
699
|
+
def mirrors
|
700
|
+
unless @mirrors
|
701
|
+
@mirrors = [Buildr.settings.user, Buildr.settings.build].inject([]) { |repos, hash|
|
702
|
+
repos | Array(hash['repositories'] && hash['repositories']['mirrors'])
|
703
|
+
}
|
704
|
+
end
|
705
|
+
@mirrors
|
706
|
+
end
|
707
|
+
|
708
|
+
# :call-seq:
|
709
|
+
# remote = Array
|
710
|
+
# remote = url
|
711
|
+
# remote = nil
|
712
|
+
#
|
713
|
+
# With a String argument, clears the array and set it to that single URL.
|
714
|
+
#
|
715
|
+
# With an Array argument, clears the array and set it to these specific URLs.
|
716
|
+
#
|
717
|
+
# With nil, clears the array.
|
718
|
+
def mirrors=(urls)
|
719
|
+
case urls
|
720
|
+
when nil then @mirrors = nil
|
721
|
+
when Array then @mirrors = urls.dup
|
722
|
+
else @mirrors = [urls.to_s]
|
723
|
+
end
|
724
|
+
end
|
725
|
+
|
726
|
+
# :call-seq:
|
727
|
+
# remote => Array
|
728
|
+
#
|
729
|
+
# Returns an array of all the remote repository URLs.
|
730
|
+
#
|
731
|
+
# When downloading artifacts, repositories are accessed in the order in which they appear here.
|
732
|
+
# The best way is to add repositories individually, for example:
|
733
|
+
# repositories.remote << 'http://example.com/repo'
|
734
|
+
#
|
735
|
+
# You can also specify remote repositories in the settings.yaml (per user) and build.yaml (per build)
|
736
|
+
# files. Both sets of URLs are loaded by default into this array, URLs from the personal setting
|
737
|
+
# showing first.
|
738
|
+
#
|
739
|
+
# For example:
|
740
|
+
# repositories:
|
741
|
+
# remote:
|
742
|
+
# - http://example.com/repo
|
743
|
+
# - http://elsewhere.com/repo
|
744
|
+
def remote
|
745
|
+
unless mirrors.empty?
|
746
|
+
info "Remote repositories overridden by mirrors #{mirrors.map(&:to_s).join(", ")}"
|
747
|
+
mirrors
|
748
|
+
end
|
749
|
+
unless @remote
|
750
|
+
@remote = [Buildr.settings.user, Buildr.settings.build].inject([]) { |repos, hash|
|
751
|
+
repos | Array(hash['repositories'] && hash['repositories']['remote'])
|
752
|
+
}
|
753
|
+
end
|
754
|
+
@remote
|
755
|
+
end
|
756
|
+
|
757
|
+
# :call-seq:
|
758
|
+
# remote_uri => Array
|
759
|
+
#
|
760
|
+
# Returns an array of all the remote repositories as instances of URI
|
761
|
+
#
|
762
|
+
# Supports
|
763
|
+
# * String urls: "http://example.com/repo"
|
764
|
+
# * URI: URI.parse( "http://example.com/repo" )
|
765
|
+
# * Hash: { :url => "http://example.com/repo", :user => "user", :pass => "pass" }
|
766
|
+
#
|
767
|
+
def remote_uri
|
768
|
+
remote
|
769
|
+
|
770
|
+
uris = []
|
771
|
+
@remote.each do |repo|
|
772
|
+
case repo
|
773
|
+
when nil then
|
774
|
+
# ignore nil
|
775
|
+
when URI then
|
776
|
+
uris << repo
|
777
|
+
when Hash then
|
778
|
+
url = (repo[:url] || repo['url'] )
|
779
|
+
if url
|
780
|
+
uri = URI.parse(url)
|
781
|
+
if ( username = (repo[:username] || repo['username'] || repo[:user] || repo['user']) )
|
782
|
+
uri.user = username
|
783
|
+
end
|
784
|
+
|
785
|
+
if ( password = (repo[:password] || repo['password'] || repo[:pass] || repo['pass']) )
|
786
|
+
uri.password = password
|
787
|
+
end
|
788
|
+
uris << uri
|
789
|
+
else
|
790
|
+
fail( "Repository Hash format missing url: #{repo}" )
|
791
|
+
end
|
792
|
+
|
793
|
+
when String then
|
794
|
+
uris << URI.parse(repo)
|
795
|
+
else
|
796
|
+
fail( "Unsupported Repository format: #{repo}" )
|
797
|
+
end
|
798
|
+
end
|
799
|
+
|
800
|
+
uris
|
801
|
+
end
|
802
|
+
|
803
|
+
# :call-seq:
|
804
|
+
# remote = Array
|
805
|
+
# remote = url
|
806
|
+
# remote = nil
|
807
|
+
#
|
808
|
+
# With a String argument, clears the array and set it to that single URL.
|
809
|
+
#
|
810
|
+
# With an Array argument, clears the array and set it to these specific URLs.
|
811
|
+
#
|
812
|
+
# With nil, clears the array.
|
813
|
+
def remote=(urls)
|
814
|
+
case urls
|
815
|
+
when nil then @remote = nil
|
816
|
+
when Array then @remote = urls.dup
|
817
|
+
else @remote = [urls.to_s]
|
818
|
+
end
|
819
|
+
end
|
820
|
+
|
821
|
+
# :call-seq:
|
822
|
+
# release_to = url
|
823
|
+
# release_to = hash
|
824
|
+
#
|
825
|
+
# Specifies the release server. Accepts a Hash with different repository settings
|
826
|
+
# (e.g. url, username, password), or a String to only set the repository URL.
|
827
|
+
#
|
828
|
+
# Besides the URL, all other settings depend on the transport protocol in use.
|
829
|
+
#
|
830
|
+
# For example:
|
831
|
+
# repositories.release_to = { :url=>'https://example.com/var/www/repo/',
|
832
|
+
# :username='john', :password=>'secret' }
|
833
|
+
# Or in the settings.yaml file:
|
834
|
+
# repositories:
|
835
|
+
# release_to: https://john:secret@example.com/var/www/repo/
|
836
|
+
#
|
837
|
+
# repositories:
|
838
|
+
# release_to:
|
839
|
+
# url: https://example.com/var/www/repo/
|
840
|
+
# username: john
|
841
|
+
# password: secret
|
842
|
+
def release_to=(options)
|
843
|
+
options = { :url=>options } unless Hash === options
|
844
|
+
@release_to = options
|
845
|
+
end
|
846
|
+
|
847
|
+
# :call-seq:
|
848
|
+
# release_to => hash
|
849
|
+
#
|
850
|
+
# Returns the current release server setting as a Hash. This is a more convenient way to
|
851
|
+
# configure the settings, as it allows you to specify the settings progressively.
|
852
|
+
#
|
853
|
+
# For example, the Buildfile will contain the repository URL used by all developers:
|
854
|
+
# repositories.release_to[:url] ||= 'https://example.com/var/www/repo'
|
855
|
+
# Your private buildr.rb will contain your credentials:
|
856
|
+
# repositories.release_to[:username] = 'john'
|
857
|
+
# repositories.release_to[:password] = 'secret'
|
858
|
+
def release_to
|
859
|
+
unless @release_to
|
860
|
+
value = (Buildr.settings.user['repositories'] && Buildr.settings.user['repositories']['release_to']) \
|
861
|
+
|| (Buildr.settings.build['repositories'] && Buildr.settings.build['repositories']['release_to'])
|
862
|
+
@release_to = Hash === value ? value.inject({}) { |hash, (key, value)| hash.update(key.to_sym=>value) } : { :url=>Array(value).first }
|
863
|
+
end
|
864
|
+
@release_to
|
865
|
+
end
|
866
|
+
|
867
|
+
# :call-seq:
|
868
|
+
# snapshot_to = url
|
869
|
+
# snapshot_to = hash
|
870
|
+
#
|
871
|
+
# Specifies the release server. Accepts a Hash with different repository settings
|
872
|
+
# (e.g. url, username, password), or a String to only set the repository URL.
|
873
|
+
#
|
874
|
+
# Besides the URL, all other settings depend on the transport protocol in use.
|
875
|
+
#
|
876
|
+
# For example:
|
877
|
+
# repositories.snapshot_to = 'https://john:secret@example.com/var/www/repo/'
|
878
|
+
#
|
879
|
+
# repositories.snapshot_to = { :url=>'https://example.com/var/www/repo/',
|
880
|
+
# :username='john', :password=>'secret' }
|
881
|
+
# Or in the settings.yaml file:
|
882
|
+
# repositories:
|
883
|
+
# snapshot_to: https://john:secret@example.com/var/www/repo/
|
884
|
+
#
|
885
|
+
# repositories:
|
886
|
+
# snapshot_to:
|
887
|
+
# url: https://example.com/var/www/repo/
|
888
|
+
# username: john
|
889
|
+
# password: secret
|
890
|
+
def snapshot_to=(options)
|
891
|
+
options = { :url=>options } unless Hash === options
|
892
|
+
@snapshot_to = options
|
893
|
+
end
|
894
|
+
|
895
|
+
# :call-seq:
|
896
|
+
# snapshot_to => hash
|
897
|
+
#
|
898
|
+
# Returns the current snapshot release server setting as a Hash. This is a more convenient way to
|
899
|
+
# configure the settings, as it allows you to specify the settings progressively.
|
900
|
+
#
|
901
|
+
# For example, the Buildfile will contain the repository URL used by all developers:
|
902
|
+
# repositories.snapshot_to[:url] ||= 'https://example.com/var/www/repo'
|
903
|
+
# Your private buildr.rb will contain your credentials:
|
904
|
+
# repositories.snapshot_to[:username] = 'john'
|
905
|
+
# repositories.snapshot_to[:password] = 'secret'
|
906
|
+
def snapshot_to
|
907
|
+
unless @snapshot_to
|
908
|
+
value = (Buildr.settings.user['repositories'] && Buildr.settings.user['repositories']['snapshot_to']) \
|
909
|
+
|| (Buildr.settings.build['repositories'] && Buildr.settings.build['repositories']['snapshot_to'])
|
910
|
+
@snapshot_to = Hash === value ? value.inject({}) { |hash, (key, value)| hash.update(key.to_sym=>value) } : { :url=>Array(value).first }
|
911
|
+
end
|
912
|
+
@snapshot_to
|
913
|
+
end
|
914
|
+
|
915
|
+
end
|
916
|
+
|
917
|
+
# :call-seq:
|
918
|
+
# repositories => Repositories
|
919
|
+
#
|
920
|
+
# Returns an object you can use for setting the local repository path, remote repositories
|
921
|
+
# URL and release server settings.
|
922
|
+
#
|
923
|
+
# See Repositories.
|
924
|
+
def repositories
|
925
|
+
Repositories.instance
|
926
|
+
end
|
927
|
+
|
928
|
+
# :call-seq:
|
929
|
+
# artifact(spec) => Artifact
|
930
|
+
# artifact(spec) { |task| ... } => Artifact
|
931
|
+
#
|
932
|
+
# Creates a file task to download and install the specified artifact in the local repository.
|
933
|
+
#
|
934
|
+
# You can use a String or a Hash for the artifact specification. The file task will point at
|
935
|
+
# the artifact's path inside the local repository. You can then use this tasks as a prerequisite
|
936
|
+
# for other tasks.
|
937
|
+
#
|
938
|
+
# This task will download and install the artifact only once. In fact, it will download and
|
939
|
+
# install the artifact if the artifact does not already exist. You can enhance it if you have
|
940
|
+
# a different way of creating the artifact in the local repository. See Artifact for more details.
|
941
|
+
#
|
942
|
+
# For example, to specify an artifact:
|
943
|
+
# artifact('log4j:log4j:jar:1.1')
|
944
|
+
#
|
945
|
+
# To use the artifact in a task:
|
946
|
+
# compile.with artifact('log4j:log4j:jar:1.1')
|
947
|
+
#
|
948
|
+
# To specify an artifact and the means for creating it:
|
949
|
+
# download(artifact('dojo:dojo-widget:zip:2.0')=>
|
950
|
+
# 'http://download.dojotoolkit.org/release-2.0/dojo-2.0-widget.zip')
|
951
|
+
def artifact(spec, path = nil, &block) #:yields:task
|
952
|
+
spec = artifact_ns.fetch(spec) if spec.kind_of?(Symbol)
|
953
|
+
spec = Artifact.to_hash(spec)
|
954
|
+
unless task = Artifact.lookup(spec)
|
955
|
+
task = Artifact.define_task(path || repositories.locate(spec))
|
956
|
+
task.send :apply_spec, spec
|
957
|
+
Rake::Task['rake:artifacts'].enhance [task]
|
958
|
+
Artifact.register(task)
|
959
|
+
unless spec[:type] == :pom
|
960
|
+
Rake::Task['artifacts:sources'].enhance [task.sources_artifact]
|
961
|
+
Rake::Task['artifacts:javadoc'].enhance [task.javadoc_artifact]
|
962
|
+
Rake::Task['artifacts:annotations'].enhance [task.annotations_artifact]
|
963
|
+
end
|
964
|
+
end
|
965
|
+
task.enhance &block
|
966
|
+
end
|
967
|
+
|
968
|
+
# :call-seq:
|
969
|
+
# artifacts(*spec) => artifacts
|
970
|
+
#
|
971
|
+
# Handles multiple artifacts at a time. This method is the plural equivalent of
|
972
|
+
# #artifact, but can do more things.
|
973
|
+
#
|
974
|
+
# Returns an array of artifacts built using the supplied
|
975
|
+
# specifications, each of which can be:
|
976
|
+
# * An artifact specification (String or Hash). Returns the appropriate Artifact task.
|
977
|
+
# * An artifact of any other task. Returns the task as is.
|
978
|
+
# * A project. Returns all artifacts created (packaged) by that project.
|
979
|
+
# * A string. Returns that string, assumed to be a file name.
|
980
|
+
# * An array of artifacts or a Struct.
|
981
|
+
# * A symbol. Returns the named artifact from the current ArtifactNamespace
|
982
|
+
#
|
983
|
+
# For example, handling a collection of artifacts:
|
984
|
+
# xml = [ xerces, xalan, jaxp ]
|
985
|
+
# ws = [ axis, jax-ws, jaxb ]
|
986
|
+
# db = [ jpa, mysql, sqltools ]
|
987
|
+
# artifacts(xml, ws, db)
|
988
|
+
#
|
989
|
+
# Using artifacts created by a project:
|
990
|
+
# artifacts project('my-app') # All packages
|
991
|
+
# artifacts project('my-app').package(:war) # Only the WAR
|
992
|
+
def artifacts(*specs, &block)
|
993
|
+
specs.flatten.inject([]) do |set, spec|
|
994
|
+
case spec
|
995
|
+
when ArtifactNamespace
|
996
|
+
set |= spec.artifacts
|
997
|
+
when Symbol, Hash
|
998
|
+
set |= [artifact(spec)]
|
999
|
+
when /([^:]+:){2,4}/ # A spec as opposed to a file name.
|
1000
|
+
set |= [artifact(spec)]
|
1001
|
+
when String # Must always expand path.
|
1002
|
+
set |= [File.expand_path(spec)]
|
1003
|
+
when Project
|
1004
|
+
set |= artifacts(spec.packages)
|
1005
|
+
when Rake::Task
|
1006
|
+
set |= [spec]
|
1007
|
+
when Struct
|
1008
|
+
set |= artifacts(spec.values)
|
1009
|
+
else
|
1010
|
+
if spec.respond_to? :to_spec
|
1011
|
+
set |= artifacts(spec.to_spec)
|
1012
|
+
else
|
1013
|
+
fail "Invalid artifact specification in #{specs.inspect}"
|
1014
|
+
end
|
1015
|
+
end
|
1016
|
+
end
|
1017
|
+
end
|
1018
|
+
|
1019
|
+
def transitive(*args)
|
1020
|
+
options = Hash === args.last ? args.pop : {}
|
1021
|
+
dep_opts = {
|
1022
|
+
:scopes => options[:scopes] || [nil, "compile", "runtime"],
|
1023
|
+
:optional => options[:optional]
|
1024
|
+
}
|
1025
|
+
specs = args.flatten
|
1026
|
+
specs.inject([]) do |set, spec|
|
1027
|
+
case spec
|
1028
|
+
when /([^:]+:){2,4}/ # A spec as opposed to a file name.
|
1029
|
+
artifact = artifact(spec)
|
1030
|
+
set |= [artifact] unless artifact.type == :pom
|
1031
|
+
set |= POM.load(artifact.pom).dependencies(dep_opts).map { |spec| artifact(spec) }
|
1032
|
+
when Hash
|
1033
|
+
set |= [transitive(spec, options)]
|
1034
|
+
when String # Must always expand path.
|
1035
|
+
set |= transitive(file(File.expand_path(spec)), options)
|
1036
|
+
when Project
|
1037
|
+
set |= transitive(spec.packages, options)
|
1038
|
+
when Rake::Task
|
1039
|
+
set |= spec.respond_to?(:to_spec) ? transitive(spec.to_spec, options) : [spec]
|
1040
|
+
when Struct
|
1041
|
+
set |= transitive(spec.values, options)
|
1042
|
+
else
|
1043
|
+
fail "Invalid artifact specification in: #{specs.to_s}"
|
1044
|
+
end
|
1045
|
+
end
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
# :call-seq:
|
1049
|
+
# group(ids, :under=>group_name, :version=>number) => artifacts
|
1050
|
+
#
|
1051
|
+
# Convenience method for defining multiple artifacts that belong to the same group, type and version.
|
1052
|
+
# Accepts multiple artifact identifiers followed by two or three hash values:
|
1053
|
+
# * :under -- The group identifier
|
1054
|
+
# * :version -- The version number
|
1055
|
+
# * :type -- The artifact type (optional)
|
1056
|
+
# * :classifier -- The artifact classifier (optional)
|
1057
|
+
#
|
1058
|
+
# For example:
|
1059
|
+
# group 'xbean', 'xbean_xpath', 'xmlpublic', :under=>'xmlbeans', :version=>'2.1.0'
|
1060
|
+
# Or:
|
1061
|
+
# group %w{xbean xbean_xpath xmlpublic}, :under=>'xmlbeans', :version=>'2.1.0'
|
1062
|
+
def group(*args)
|
1063
|
+
hash = args.pop
|
1064
|
+
args.flatten.map do |id|
|
1065
|
+
artifact :group => hash[:under],
|
1066
|
+
:type => hash[:type],
|
1067
|
+
:version => hash[:version],
|
1068
|
+
:classifier => hash[:classifier],
|
1069
|
+
:id => id
|
1070
|
+
end
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
# :call-seq:
|
1074
|
+
# install(artifacts) => install_task
|
1075
|
+
#
|
1076
|
+
# Installs the specified artifacts in the local repository as part of the install task.
|
1077
|
+
#
|
1078
|
+
# You can use this to install various files in the local repository, for example:
|
1079
|
+
# install artifact('group:id:jar:1.0').from('some_jar.jar')
|
1080
|
+
# $ buildr install
|
1081
|
+
def install(*args, &block)
|
1082
|
+
artifacts = artifacts(args).uniq
|
1083
|
+
raise ArgumentError, 'This method can only install artifacts' unless artifacts.all? { |f| f.respond_to?(:to_spec) }
|
1084
|
+
task('install').tap do |install|
|
1085
|
+
install.enhance(artifacts) do
|
1086
|
+
artifacts.each(&:install)
|
1087
|
+
end
|
1088
|
+
install.enhance &block if block
|
1089
|
+
task('uninstall') do
|
1090
|
+
artifacts.map(&:to_s ).each { |file| rm file if File.exist?(file) }
|
1091
|
+
end
|
1092
|
+
end
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
# :call-seq:
|
1096
|
+
# upload(artifacts)
|
1097
|
+
#
|
1098
|
+
# Uploads the specified artifacts to the release server as part of the upload task.
|
1099
|
+
#
|
1100
|
+
# You can use this to upload various files to the release server, for example:
|
1101
|
+
# upload artifact('group:id:jar:1.0').from('some_jar.jar')
|
1102
|
+
# $ buildr upload
|
1103
|
+
def upload(*args, &block)
|
1104
|
+
artifacts = artifacts(args)
|
1105
|
+
raise ArgumentError, 'This method can only upload artifacts' unless artifacts.all? { |f| f.respond_to?(:to_spec) }
|
1106
|
+
upload_artifacts_tasks = artifacts.map { |artifact| artifact.upload_task }
|
1107
|
+
task('upload').tap do |task|
|
1108
|
+
task.enhance &block if block
|
1109
|
+
task.enhance upload_artifacts_tasks
|
1110
|
+
end
|
1111
|
+
end
|
1112
|
+
|
1113
|
+
end
|