buildr 0.18.0 → 0.19.0
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.
- data/CHANGELOG +62 -4
- data/LICENSE +1 -1
- data/README +64 -1
- data/lib/buildr.rb +27 -28
- data/lib/core/build.rb +39 -30
- data/lib/core/project.rb +323 -247
- data/lib/core/rake_ext.rb +116 -0
- data/lib/core/transports.rb +81 -36
- data/lib/java/ant.rb +78 -0
- data/lib/{core → java}/artifact.rb +212 -109
- data/lib/java/compile.rb +158 -78
- data/lib/java/eclipse.rb +27 -12
- data/lib/java/java.rb +269 -111
- data/lib/java/javacc.rb +53 -69
- data/lib/java/jetty.rb +203 -92
- data/lib/java/jetty/JettyWrapper$BuildrHandler.class +0 -0
- data/lib/java/jetty/JettyWrapper.class +0 -0
- data/lib/java/jetty/JettyWrapper.java +69 -20
- data/lib/java/openjpa.rb +57 -45
- data/lib/java/packaging.rb +248 -116
- data/lib/java/test.rb +261 -128
- data/lib/java/xmlbeans.rb +55 -49
- data/lib/tasks/concat.rb +34 -0
- data/lib/tasks/download.rb +5 -0
- data/lib/tasks/filter.rb +107 -55
- data/lib/tasks/zip.rb +283 -155
- metadata +25 -5
- data/lib/core/core.rb +0 -155
@@ -0,0 +1,116 @@
|
|
1
|
+
module Rake #:nodoc:
|
2
|
+
class Task
|
3
|
+
|
4
|
+
# Access the base directory. The base directory is set when the class
|
5
|
+
# is defined from the current directory. The current directory is set
|
6
|
+
# to the base directory when the class is executed.
|
7
|
+
attr_accessor :base_dir
|
8
|
+
|
9
|
+
def initialize_with_base_dir(*args) #:nodoc:
|
10
|
+
@base_dir = Dir.pwd
|
11
|
+
initialize_without_base_dir *args
|
12
|
+
end
|
13
|
+
alias_method_chain :initialize, :base_dir
|
14
|
+
|
15
|
+
def invoke #:nodoc:
|
16
|
+
tasks = (Thread.current[:tasks] || [])
|
17
|
+
if tasks.include?(name)
|
18
|
+
fail "Circular dependency " + (tasks + [name]).join("=>")
|
19
|
+
end
|
20
|
+
@lock.synchronize do
|
21
|
+
if application.options.trace
|
22
|
+
puts "** Invoke #{name} #{format_trace_flags}"
|
23
|
+
end
|
24
|
+
return if @already_invoked
|
25
|
+
begin
|
26
|
+
Thread.current[:tasks] = tasks + [name]
|
27
|
+
@already_invoked = true
|
28
|
+
Dir.chdir(@base_dir || Dir.pwd) do
|
29
|
+
invoke_prerequisites
|
30
|
+
execute if needed?
|
31
|
+
end
|
32
|
+
ensure
|
33
|
+
Thread.current[:tasks] = tasks
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def invoke_prerequisites() #:nodoc:
|
39
|
+
prerequisites.each { |n| application[n, @scope].invoke }
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
class Application #:nodoc:
|
45
|
+
|
46
|
+
def in_namespace_with_global_scope(name, &block)
|
47
|
+
if name =~ /^:/
|
48
|
+
begin
|
49
|
+
scope, @scope = @scope, name.split(":")[1...-1]
|
50
|
+
in_namespace_without_global_scope name.split(":").last, &block
|
51
|
+
ensure
|
52
|
+
@scope = scope
|
53
|
+
end
|
54
|
+
else
|
55
|
+
in_namespace_without_global_scope name, &block
|
56
|
+
end
|
57
|
+
end
|
58
|
+
alias_method_chain :in_namespace, :global_scope
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
class CheckTask < Rake::Task
|
63
|
+
|
64
|
+
def execute()
|
65
|
+
@warnings = []
|
66
|
+
super
|
67
|
+
report if verbose
|
68
|
+
end
|
69
|
+
|
70
|
+
def note(*msg)
|
71
|
+
@warnings += msg
|
72
|
+
end
|
73
|
+
|
74
|
+
def report()
|
75
|
+
if @warnings.empty?
|
76
|
+
puts HighLine.new.color("No warnings", :green)
|
77
|
+
else
|
78
|
+
warn "These are possible problems with your Rakefile"
|
79
|
+
@warnings.each { |msg| warn " #{msg}" }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
desc "Check your Rakefile for common errors"
|
87
|
+
CheckTask.define_task "check"
|
88
|
+
|
89
|
+
# Check for circular dependencies
|
90
|
+
task "check" do
|
91
|
+
# Keep track of tasks we already checked, to avoid death circles.
|
92
|
+
checked = {}
|
93
|
+
# The stack keeps track of all the tasks we visit, so we can display the tasks
|
94
|
+
# involved in the circular dependency.
|
95
|
+
expand = lambda do |stack, task|
|
96
|
+
# Already been here, no need to check again, but make sure we're not seeing
|
97
|
+
# the same task twice due to a circular dependency.
|
98
|
+
fail "Circular " + (stack + [task]).join("=>") if stack.include?(task)
|
99
|
+
unless checked[task]
|
100
|
+
checked[task] = true
|
101
|
+
# Variable task may be a Task, but may also be a task name. In the later
|
102
|
+
# case, we need to resolve it into a Task. But it may also be a filename,
|
103
|
+
# pointing to a file that may exist, just not during the check, so we need
|
104
|
+
# this check to avoid dying on "Don't know how to build ..."
|
105
|
+
if real_task = Rake.application.lookup(task, [])
|
106
|
+
one_deeper = stack + [task.to_s]
|
107
|
+
real_task.prerequisites.each { |prereq| expand[one_deeper, prereq.to_s] }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
Rake.application.tasks.each do |task|
|
112
|
+
expand[ [], task.to_s ]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
data/lib/core/transports.rb
CHANGED
@@ -12,46 +12,81 @@ require "highline"
|
|
12
12
|
# Monkeypatching: SFTP never defines the mkdir method on its session or the underlying
|
13
13
|
# driver, it just redirect calls through method_missing. Rake, on the other hand, decides
|
14
14
|
# to define mkdir on Object, and so routes our calls to FileUtils.
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
module Net #:nodoc:all
|
16
|
+
class Session
|
17
|
+
def mkdir(path, attrs = {})
|
18
|
+
method_missing :mkdir, path, attrs
|
19
|
+
end
|
18
20
|
end
|
19
|
-
end
|
20
21
|
|
21
|
-
class
|
22
|
-
|
23
|
-
|
22
|
+
class SFTP::Protocol::Driver
|
23
|
+
def mkdir(first, path, attrs = {})
|
24
|
+
method_missing :mkdir, first, path, attrs
|
25
|
+
end
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
27
29
|
|
28
30
|
module Buildr
|
31
|
+
|
32
|
+
# Transports are used for downloading artifacts from remote repositories, uploading
|
33
|
+
# artifacts to deployment repositories, and anything else you need to move around.
|
34
|
+
#
|
35
|
+
# The HTTP transport is used for all URLs with the scheme http or https. You can only
|
36
|
+
# use the HTTP transport to download artifacts.
|
37
|
+
#
|
38
|
+
# The SFTP transport is used for all URLs with the schema sftp. You can only use the
|
39
|
+
# SFTP transport to upload artifacts.
|
40
|
+
#
|
41
|
+
# The SFTP transport supports the following options:
|
42
|
+
# * :username -- The username.
|
43
|
+
# * :password -- A password. If unspecified, you will be prompted to enter a password.
|
44
|
+
# * :permissions -- Permissions to set on the uploaded file.
|
45
|
+
# You can also pass the username/password in the URL.
|
46
|
+
#
|
47
|
+
# The SFTP transport will automatically create MD5 and SHA1 digest files for each file
|
48
|
+
# it uploads.
|
29
49
|
module Transports
|
30
50
|
|
51
|
+
# Indicates the requested resource was not found.
|
31
52
|
class NotFound < Exception
|
32
53
|
end
|
33
54
|
|
34
|
-
|
35
|
-
# specified URL. For examples, see Transport#download and Transport#upload.
|
36
|
-
def self.perform(url, options = nil, &block)
|
37
|
-
uri = URI.parse(url.to_s)
|
38
|
-
const_get(uri.scheme.upcase).perform(uri, options, &block)
|
39
|
-
end
|
55
|
+
class << self
|
40
56
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
57
|
+
# :call-seq:
|
58
|
+
# perform(url, options?) { |transport| ... }
|
59
|
+
#
|
60
|
+
# Perform one or more operations using an open connection to the
|
61
|
+
# specified URL. For examples, see Transport#download and Transport#upload.
|
62
|
+
def perform(url, options = nil, &block)
|
63
|
+
uri = URI.parse(url.to_s)
|
64
|
+
const_get(uri.scheme.upcase).perform(uri, options, &block)
|
48
65
|
end
|
66
|
+
|
67
|
+
# :call-seq:
|
68
|
+
# download(url, target, options?)
|
69
|
+
#
|
70
|
+
# Convenience method for downloading a single file from the specified
|
71
|
+
# URL to the target file.
|
72
|
+
def download(url, target, options = nil)
|
73
|
+
uri = URI.parse(url.to_s)
|
74
|
+
path, uri.path = uri.path, ""
|
75
|
+
const_get(uri.scheme.upcase).perform(uri, options) do |transport|
|
76
|
+
transport.download(path, target)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
49
80
|
end
|
50
81
|
|
82
|
+
# Extend this class if you are implementing a new transport.
|
51
83
|
class Transport
|
52
84
|
|
53
85
|
class << self
|
54
86
|
|
87
|
+
# :call-seq:
|
88
|
+
# perform(url, options?) { |transport| ... }
|
89
|
+
#
|
55
90
|
# Perform one or more operations using an open connection to the
|
56
91
|
# specified URL. For examples, see #download and #upload.
|
57
92
|
def perform(url, options = nil)
|
@@ -71,6 +106,7 @@ module Buildr
|
|
71
106
|
# Options passed during construction.
|
72
107
|
attr_reader :options
|
73
108
|
|
109
|
+
# Initialize the transport with the specified URL and options.
|
74
110
|
def initialize(url, options)
|
75
111
|
@uri = URI.parse(url.to_s)
|
76
112
|
@base_path = @uri.path || "/"
|
@@ -138,10 +174,10 @@ module Buildr
|
|
138
174
|
end
|
139
175
|
progress_bar.format = "#{truncated}: %3d%% %s %s/%s %s"
|
140
176
|
progress_bar.format = "%3d%% %s %s/%s %s"
|
141
|
-
progress_bar.format_arguments = [:percentage, :bar, :bytes, :total, :stat]
|
177
|
+
progress_bar.format_arguments = [:percentage, :bar, :bytes, :total, :stat]
|
142
178
|
progress_bar.bar_mark = "."
|
143
179
|
|
144
|
-
|
180
|
+
|
145
181
|
begin
|
146
182
|
class << progress_bar
|
147
183
|
def <<(bytes)
|
@@ -194,7 +230,7 @@ module Buildr
|
|
194
230
|
digester.to_hash
|
195
231
|
end
|
196
232
|
|
197
|
-
class Digester
|
233
|
+
class Digester #:nodoc:
|
198
234
|
|
199
235
|
def initialize(types)
|
200
236
|
types ||= [ "md5", "sha1" ]
|
@@ -210,7 +246,7 @@ module Buildr
|
|
210
246
|
end
|
211
247
|
|
212
248
|
# Iterate over all the digests calling the block with two arguments:
|
213
|
-
# the digest type (e.g. "md5") and the hexadecimal digest value.
|
249
|
+
# the digest type (e.g. "md5") and the hexadecimal digest value.
|
214
250
|
def each()
|
215
251
|
@digests.each { |type, digest| yield type, digest.hexdigest }
|
216
252
|
end
|
@@ -228,7 +264,7 @@ module Buildr
|
|
228
264
|
end
|
229
265
|
|
230
266
|
|
231
|
-
class HTTP < Transport
|
267
|
+
class HTTP < Transport #:nodoc:
|
232
268
|
|
233
269
|
def initialize(url, options)
|
234
270
|
super
|
@@ -254,7 +290,7 @@ module Buildr
|
|
254
290
|
response.read_body do |chunk|
|
255
291
|
write[chunk]
|
256
292
|
digester << chunk
|
257
|
-
progress << chunk
|
293
|
+
progress << chunk
|
258
294
|
end
|
259
295
|
# Check server digests before approving the download.
|
260
296
|
digester.each do |type, hexdigest|
|
@@ -267,7 +303,7 @@ module Buildr
|
|
267
303
|
end
|
268
304
|
end
|
269
305
|
end
|
270
|
-
|
306
|
+
|
271
307
|
if target
|
272
308
|
# If download breaks we end up with a partial file which is
|
273
309
|
# worse than not having a file at all, so download to temporary
|
@@ -297,8 +333,11 @@ module Buildr
|
|
297
333
|
|
298
334
|
end
|
299
335
|
|
336
|
+
# Use the HTTP transport for HTTPS connections.
|
337
|
+
HTTPS = HTTP #:nodoc:
|
300
338
|
|
301
|
-
|
339
|
+
|
340
|
+
class SFTP < Transport #:nodoc:
|
302
341
|
|
303
342
|
class << self
|
304
343
|
def passwords()
|
@@ -310,6 +349,7 @@ module Buildr
|
|
310
349
|
|
311
350
|
def initialize(url, options)
|
312
351
|
super
|
352
|
+
@permissions = options.delete :permissions
|
313
353
|
# SSH options are based on the username/password from the URI.
|
314
354
|
ssh_options = { :port=>@uri.port, :username=>@uri.user }.merge(options || {})
|
315
355
|
ssh_options[:password] ||= SFTP.passwords[@uri.host]
|
@@ -334,30 +374,34 @@ module Buildr
|
|
334
374
|
File.open(source) do |file|
|
335
375
|
with_progress_bar path.split("/").last, File.size(source) do |progress|
|
336
376
|
with_digests(@options[:digests]) do |digester|
|
337
|
-
|
338
|
-
|
377
|
+
target_path = "#{@base_path}#{path}"
|
378
|
+
puts "Uploading to #{target_path}" if Rake.application.options.trace
|
379
|
+
@sftp.open_handle(target_path, "w") do |handle|
|
339
380
|
# Writing in chunks gives us the benefit of a progress bar,
|
340
381
|
# but also require that we maintain a position in the file,
|
341
382
|
# since write() with two arguments always writes at position 0.
|
342
383
|
pos = 0
|
343
|
-
while chunk = file.read(32 * 4096)
|
384
|
+
while chunk = file.read(32 * 4096)
|
344
385
|
@sftp.write(handle, chunk, pos)
|
345
386
|
pos += chunk.size
|
346
387
|
digester << chunk
|
347
388
|
progress << chunk
|
348
389
|
end
|
349
390
|
end
|
391
|
+
@sftp.setstat(target_path, :permissions => @permissions) if @permissions
|
350
392
|
|
351
393
|
# Upload all the digests.
|
352
394
|
digester.each do |type, hexdigest|
|
353
|
-
|
354
|
-
|
395
|
+
digest_file = "#{@base_path}#{path}.#{type}"
|
396
|
+
puts "Uploading signature to #{digest_file}" if Rake.application.options.trace
|
397
|
+
@sftp.open_handle(digest_file, "w") do |handle|
|
355
398
|
@sftp.write(handle, "#{hexdigest} #{path}")
|
356
399
|
end
|
400
|
+
@sftp.setstat(digest_file, :permissions => @permissions) if @permissions
|
357
401
|
end
|
358
402
|
end
|
359
403
|
|
360
|
-
end
|
404
|
+
end
|
361
405
|
end
|
362
406
|
end
|
363
407
|
|
@@ -367,8 +411,9 @@ module Buildr
|
|
367
411
|
# otherwise mkdir fails.
|
368
412
|
puts "Creating path #{@base_path}" if Rake.application.options.trace
|
369
413
|
path.split("/").inject(@base_path) do |base, part|
|
370
|
-
|
371
|
-
|
414
|
+
combined = base + part
|
415
|
+
@sftp.realpath combined rescue @sftp.mkdir combined, {}
|
416
|
+
"#{combined}/"
|
372
417
|
end
|
373
418
|
end
|
374
419
|
|
data/lib/java/ant.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require "core/project"
|
2
|
+
require "java/java"
|
3
|
+
|
4
|
+
module Buildr
|
5
|
+
module Java
|
6
|
+
module Ant
|
7
|
+
|
8
|
+
# Libraries used by #ant.
|
9
|
+
REQUIRES = [ "ant:ant:jar:1.6.5", "ant:ant-launcher:jar:1.6.5", "xerces:xercesImpl:jar:2.6.2" ]
|
10
|
+
|
11
|
+
# Make sure Ant and friends show on the classpath. Antwrap must only be loaded after RJB.
|
12
|
+
Java.rjb.classpath += REQUIRES
|
13
|
+
Java.rjb.onload { require "antwrap" }
|
14
|
+
|
15
|
+
class << self
|
16
|
+
|
17
|
+
# :call-seq:
|
18
|
+
# declarative(name, options?) => AntProject
|
19
|
+
# declarative(name, options?) { |AntProject| ... } => AntProject
|
20
|
+
#
|
21
|
+
# Returns a declarative AntProject with the specified name. Ant tasks created in this project
|
22
|
+
# are not executed until you tell them to.
|
23
|
+
#
|
24
|
+
# See #ant for more information about options and the block.
|
25
|
+
def declarative(name, options = nil, &block)
|
26
|
+
options ||= {}
|
27
|
+
options = (options || {}).merge(:name=>name, :base_dir=>Dir.pwd, :declarative=>false)
|
28
|
+
Java.rjb { AntProject.new(options).tap { |project| yield project if block_given? } }
|
29
|
+
end
|
30
|
+
|
31
|
+
# :call-seq:
|
32
|
+
# executable(name, options?) => AntProject
|
33
|
+
# executable(name, options?) { |AntProject| ... } => AntProject
|
34
|
+
#
|
35
|
+
# Returns an executable AntProject with the specified name. Ant tasks created in this project
|
36
|
+
# are executed immediately.
|
37
|
+
#
|
38
|
+
# See #ant for more information about options and the block.
|
39
|
+
def executable(name, options = nil, &block)
|
40
|
+
options ||= {}
|
41
|
+
options = (options || {}).merge(:name=>name, :base_dir=>Dir.pwd, :declarative=>true)
|
42
|
+
Java.rjb { AntProject.new(options).tap { |project| yield project if block_given? } }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# :call-seq:
|
47
|
+
# ant(name, options?) => AntProject
|
48
|
+
# ant(name, options?) { |AntProject| ... } => AntProject
|
49
|
+
#
|
50
|
+
# Returns a new AntProject with the specified name. Ant tasks created in this project are
|
51
|
+
# executed immediately.
|
52
|
+
#
|
53
|
+
# The options hash is passed to the Ant project definition, along with the current directory.
|
54
|
+
# When used in a Buildr project, the Ant project will have the same base directory.
|
55
|
+
# If you pass a block, yields to the block with the Ant project.
|
56
|
+
#
|
57
|
+
# For example:
|
58
|
+
# ant("hibernatedoclet") do |doclet|
|
59
|
+
# doclet.taskdef :name=>"hibernatedoclet",
|
60
|
+
# :classname=>"xdoclet.modules.hibernate.HibernateDocletTask", :classpath=>DOCLET
|
61
|
+
# doclet.hibernatedoclet :destdir=>dest_dir, :force=>"true" do
|
62
|
+
# hibernate :version=>"3.0"
|
63
|
+
# fileset :dir=>source, :includes=>"**/*.java"
|
64
|
+
# end
|
65
|
+
# end
|
66
|
+
def ant(name, options=nil, &block)
|
67
|
+
Java::Ant.executable(name, options, &block)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
class Project
|
75
|
+
include Java::Ant
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -1,16 +1,25 @@
|
|
1
|
+
require "core/project"
|
2
|
+
require "core/transports"
|
3
|
+
|
1
4
|
module Buildr
|
2
5
|
|
3
6
|
desc "Download all artifacts"
|
4
7
|
task "artifacts"
|
5
8
|
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
+
# Mixin with a task to make it behave like an artifact. Implemented by the packaging tasks.
|
10
|
+
#
|
11
|
+
# An artifact has an identifier, group identifier, type, version number and
|
12
|
+
# optional classifier. All can be used to locate it in the local repository,
|
13
|
+
# download from or upload to a remote repository.
|
14
|
+
#
|
15
|
+
# The #to_spec and #to_hash methods allow it to be used everywhere an artifact is
|
16
|
+
# accepted.
|
9
17
|
module ActsAsArtifact
|
10
18
|
|
11
19
|
ARTIFACT_ATTRIBUTES = [:group, :id, :type, :classifier, :version]
|
12
20
|
|
13
21
|
class << self
|
22
|
+
private
|
14
23
|
def included(mod)
|
15
24
|
mod.extend self
|
16
25
|
end
|
@@ -27,21 +36,44 @@ module Buildr
|
|
27
36
|
# Optional artifact classifier.
|
28
37
|
attr_reader :classifier
|
29
38
|
|
30
|
-
#
|
39
|
+
# :call-seq:
|
40
|
+
# to_spec_hash() => Hash
|
41
|
+
#
|
42
|
+
# Returns the artifact specification as a hash. For example:
|
43
|
+
# com.example:app:jar:1.2
|
44
|
+
# becomes:
|
45
|
+
# { :group=>"com.example",
|
46
|
+
# :id=>"app",
|
47
|
+
# :type=>"jar",
|
48
|
+
# :version=>"1.2" }
|
31
49
|
def to_spec_hash()
|
32
50
|
base = { :group=>group, :id=>id, :type=>type, :version=>version }
|
33
51
|
classifier.blank? ? base : base.merge(:classifier=>classifier)
|
34
52
|
end
|
35
53
|
alias_method :to_hash, :to_spec_hash
|
36
54
|
|
55
|
+
# :call-seq:
|
56
|
+
# to_spec() => String
|
57
|
+
#
|
37
58
|
# Returns the artifact specification, in the structure:
|
38
59
|
# <group>:<artifact>:<type>:<version>
|
39
60
|
# or
|
40
|
-
# <group>:<artifact>:<type>:<classifier
|
61
|
+
# <group>:<artifact>:<type>:<classifier><:version>
|
41
62
|
def to_spec()
|
42
63
|
classifier.blank? ? "#{group}:#{id}:#{type}:#{version}" : "#{group}:#{id}:#{type}:#{classifier}:#{version}"
|
43
64
|
end
|
44
65
|
|
66
|
+
# :call-seq:
|
67
|
+
# pom() => Artifact
|
68
|
+
#
|
69
|
+
# Convenience method that returns a POM artifact.
|
70
|
+
def pom()
|
71
|
+
return self if type.to_s == "pom"
|
72
|
+
artifact(:group=>group, :id=>id, :version=>version, :type=>"pom", :classifier=>classifier)
|
73
|
+
end
|
74
|
+
|
75
|
+
protected
|
76
|
+
|
45
77
|
# Apply specification to this artifact.
|
46
78
|
def apply_spec(spec)
|
47
79
|
spec = Artifact.to_hash(spec)
|
@@ -49,20 +81,17 @@ module Buildr
|
|
49
81
|
self
|
50
82
|
end
|
51
83
|
|
52
|
-
# Convenience method that returns a POM artifact.
|
53
|
-
def pom()
|
54
|
-
return self if type.to_s == "pom"
|
55
|
-
artifact(:group=>group, :id=>id, :version=>version, :type=>"pom", :classifier=>classifier)
|
56
|
-
end
|
57
|
-
|
58
84
|
end
|
59
85
|
|
60
|
-
|
61
|
-
#
|
62
|
-
#
|
86
|
+
|
87
|
+
# A file task referencing an artifact in the local repository.
|
88
|
+
#
|
89
|
+
# This task includes all the artifact attributes (group, id, version, etc). It points
|
90
|
+
# to the artifact's path in the local repository. When invoked, it will download the
|
91
|
+
# artifact into the local repository if the artifact does not already exist.
|
63
92
|
#
|
64
|
-
#
|
65
|
-
#
|
93
|
+
# Note: You can enhance this task to create the artifact yourself, e.g. download it from
|
94
|
+
# a site that doesn't have a remote repository structure, copy it from a different disk, etc.
|
66
95
|
class Artifact < Rake::FileCreationTask
|
67
96
|
|
68
97
|
# The default file type for artifacts, if not specified.
|
@@ -72,37 +101,44 @@ module Buildr
|
|
72
101
|
|
73
102
|
class << self
|
74
103
|
|
75
|
-
#
|
76
|
-
#
|
104
|
+
# :call-seq:
|
105
|
+
# lookup(spec) => Artifact
|
106
|
+
#
|
107
|
+
# Lookup a previously registered artifact task based on its specification (String or Hash).
|
77
108
|
def lookup(spec)
|
78
109
|
@artifacts ||= {}
|
79
110
|
@artifacts[to_spec(spec)]
|
80
111
|
end
|
81
112
|
|
113
|
+
# :call-seq:
|
114
|
+
# register(artifacts) => artifacts
|
115
|
+
#
|
82
116
|
# Register an artifact task(s) for later lookup (see #lookup).
|
83
117
|
def register(*tasks)
|
84
118
|
@artifacts ||= {}
|
85
|
-
fail "You can only register an artifact task,
|
119
|
+
fail "You can only register an artifact task, one of the arguments is not a Task that responds to to_spec()" unless
|
86
120
|
tasks.all? { |task| task.respond_to?(:to_spec) && task.respond_to?(:invoke) }
|
87
121
|
tasks.each { |task| @artifacts[task.to_spec] = task }
|
88
122
|
tasks
|
89
123
|
end
|
90
124
|
|
91
|
-
#
|
92
|
-
#
|
93
|
-
#
|
125
|
+
# :call-seq:
|
126
|
+
# to_hash(spec_hash) => spec_hash
|
127
|
+
# to_hash(spec_string) => spec_hash
|
128
|
+
# to_hash(artifact) => spec_hash
|
129
|
+
#
|
130
|
+
# Turn a spec into a hash. This method accepts a String, Hash or any object that responds to
|
131
|
+
# the method to_spec. There are several reasons to use this method:
|
94
132
|
# * You can pass anything that could possibly be a spec, and get a hash.
|
95
133
|
# * It will check that the spec includes the group identifier, artifact
|
96
134
|
# identifier and version number and set the file type, if missing.
|
97
135
|
# * It will always return a new specs hash.
|
98
|
-
#
|
99
|
-
# :nodoc:
|
100
136
|
def to_hash(spec)
|
101
137
|
if spec.respond_to?(:to_spec)
|
102
138
|
to_hash spec.to_spec
|
103
139
|
elsif Hash === spec
|
104
140
|
# Sanitize the hash and check it's valid.
|
105
|
-
spec = ARTIFACT_ATTRIBUTES.inject({}) { |h, k| h[k] = spec[k] ; h }
|
141
|
+
spec = ARTIFACT_ATTRIBUTES.inject({}) { |h, k| h[k] = spec[k].to_s if spec[k] ; h }
|
106
142
|
fail "Missing group identifier for #{spec.inspect}" if spec[:group].blank?
|
107
143
|
fail "Missing artifact identifier for #{spec.inspect}" if spec[:id].blank?
|
108
144
|
fail "Missing version for #{spec.inspect}" if spec[:version].blank?
|
@@ -121,9 +157,11 @@ module Buildr
|
|
121
157
|
end
|
122
158
|
end
|
123
159
|
|
160
|
+
# :call-seq:
|
161
|
+
# to_spec(spec_hash) => spec_string
|
162
|
+
#
|
124
163
|
# Convert a hash back to a spec string. This method accepts
|
125
164
|
# a string, hash or any object that responds to to_spec.
|
126
|
-
# :nodoc:
|
127
165
|
def to_spec(hash)
|
128
166
|
hash = to_hash(hash) unless Hash === hash
|
129
167
|
version = ":#{hash[:version]}" unless hash[:version].blank?
|
@@ -131,8 +169,10 @@ module Buildr
|
|
131
169
|
"#{hash[:group]}:#{hash[:id]}:#{hash[:type] || DEFAULT_FILE_TYPE}#{classifier}#{version}"
|
132
170
|
end
|
133
171
|
|
134
|
-
#
|
135
|
-
#
|
172
|
+
# :call-seq:
|
173
|
+
# hash_to_file_name(spec_hash) => file_name
|
174
|
+
#
|
175
|
+
# Convert a hash spec to a file name.
|
136
176
|
def hash_to_file_name(hash)
|
137
177
|
version = "-#{hash[:version]}" unless hash[:version].blank?
|
138
178
|
classifier = "-#{hash[:classifier]}" unless hash[:classifier].blank?
|
@@ -141,15 +181,20 @@ module Buildr
|
|
141
181
|
|
142
182
|
end
|
143
183
|
|
144
|
-
def
|
145
|
-
# Default behavior: download the artifact from one of the remote
|
146
|
-
# repositories if the file does not exist. But this default behavior
|
147
|
-
# is counter useful if the artifact knows how to build itself
|
148
|
-
# (e.g. download from a different location), so don't perform it
|
149
|
-
# if the task found a different way to create the artifact.
|
184
|
+
def initialize(*args) #:nodoc:
|
150
185
|
super
|
151
|
-
|
152
|
-
|
186
|
+
enhance do |task|
|
187
|
+
# Default behavior: download the artifact from one of the remote
|
188
|
+
# repositories if the file does not exist. But this default behavior
|
189
|
+
# is counter useful if the artifact knows how to build itself
|
190
|
+
# (e.g. download from a different location), so don't perform it
|
191
|
+
# if the task found a different way to create the artifact.
|
192
|
+
# For that, we need to be the last piece of code run by the task.
|
193
|
+
task.enhance do
|
194
|
+
unless Rake.application.options.dryrun || File.exist?(name)
|
195
|
+
repositories.download(to_spec)
|
196
|
+
end
|
197
|
+
end
|
153
198
|
end
|
154
199
|
end
|
155
200
|
|
@@ -158,25 +203,41 @@ module Buildr
|
|
158
203
|
|
159
204
|
# Holds the path to the local repository, URLs for remote repositories, and
|
160
205
|
# settings for the deployment repository.
|
206
|
+
#
|
207
|
+
# You can access this object from the #repositories method. For example:
|
208
|
+
# puts repositories.local
|
209
|
+
# repositories.remote << "http://example.com/repo"
|
210
|
+
# repositories.deploy_to = "sftp://example.com/var/www/public/repo"
|
161
211
|
class Repositories
|
162
212
|
include Singleton
|
163
213
|
|
214
|
+
# :call-seq:
|
215
|
+
# local() => path
|
216
|
+
#
|
164
217
|
# Returns the path to the local repository.
|
165
218
|
#
|
166
219
|
# The default path is .m2/repository relative to the home directory.
|
167
|
-
# You can change the location of the local repository by using a symbol
|
168
|
-
# link or by setting a different path. If you set a different path, do it
|
169
|
-
# in the buildr.rb file instead of the Rakefile.
|
170
220
|
def local()
|
171
|
-
@local ||= ENV["local_repo"] || File.join(ENV["HOME"], ".m2
|
221
|
+
@local ||= ENV["local_repo"] || File.join(ENV["HOME"], ".m2/repository")
|
172
222
|
end
|
173
223
|
|
224
|
+
# :call-seq:
|
225
|
+
# local = path
|
226
|
+
#
|
174
227
|
# Sets the path to the local repository.
|
228
|
+
#
|
229
|
+
# The best place to set the local repository path is from a buildr.rb file
|
230
|
+
# located in your home directory. That way all your projects will share the same
|
231
|
+
# path, without affecting other developers collaborating on these projects.
|
175
232
|
def local=(dir)
|
176
233
|
@local = dir ? File.expand_path(dir) : nil
|
177
234
|
end
|
178
235
|
|
179
|
-
#
|
236
|
+
# :call-seq:
|
237
|
+
# locate(spec) => path
|
238
|
+
#
|
239
|
+
# Locates an artifact in the local repository based on its specification, and returns
|
240
|
+
# a file path.
|
180
241
|
#
|
181
242
|
# For example:
|
182
243
|
# locate :group=>"log4j", :id=>"log4j", :version=>"1.1"
|
@@ -186,16 +247,28 @@ module Buildr
|
|
186
247
|
File.join(local, spec[:group].split("."), spec[:id], spec[:version], Artifact.hash_to_file_name(spec))
|
187
248
|
end
|
188
249
|
|
189
|
-
#
|
190
|
-
#
|
191
|
-
#
|
250
|
+
# :call-seq:
|
251
|
+
# remote() => Array
|
252
|
+
#
|
253
|
+
# Returns an array of all the remote repository URLs.
|
254
|
+
#
|
255
|
+
# When downloading artifacts, repositories are accessed in the order in which they appear here.
|
256
|
+
# The best way is to add repositories individually, for example:
|
257
|
+
# repositories.remote << "http://example.com/repo"
|
192
258
|
def remote()
|
193
259
|
@remote ||= []
|
194
260
|
end
|
195
261
|
|
196
|
-
#
|
197
|
-
#
|
198
|
-
#
|
262
|
+
# :call-seq:
|
263
|
+
# remote = Array
|
264
|
+
# remote = url
|
265
|
+
# remote = nil
|
266
|
+
#
|
267
|
+
# With a String argument, clears the array and set it to that single URL.
|
268
|
+
#
|
269
|
+
# With an Array argument, clears the array and set it to these specific URLs.
|
270
|
+
#
|
271
|
+
# With nil, clears the array.
|
199
272
|
def remote=(urls)
|
200
273
|
case urls
|
201
274
|
when nil
|
@@ -207,9 +280,18 @@ module Buildr
|
|
207
280
|
end
|
208
281
|
end
|
209
282
|
|
210
|
-
|
211
|
-
#
|
212
|
-
#
|
283
|
+
|
284
|
+
# :call-seq:
|
285
|
+
# download(spec) => boolean
|
286
|
+
#
|
287
|
+
# Downloads an artifact from one of the remote repositories, and stores it in the local
|
288
|
+
# repository. Accepts a String or Hash artifact specification, and returns a path to the
|
289
|
+
# artifact in the local repository. Raises an exception if the artifact is not found.
|
290
|
+
#
|
291
|
+
# This method attempts to download the artifact from each repository in the order in
|
292
|
+
# which they are returned from #remote, until successful. If you want to download an
|
293
|
+
# artifact only if not already installed in the local repository, create an #artifact
|
294
|
+
# task and invoke it directly.
|
213
295
|
def download(spec)
|
214
296
|
spec = Artifact.to_hash(spec) unless Hash === spec
|
215
297
|
path = locate(spec)
|
@@ -236,27 +318,38 @@ module Buildr
|
|
236
318
|
fail "Failed to download #{Artifact.to_spec(spec)}, tried the following repositories:\n#{repositories.remote.join("\n")}"
|
237
319
|
end
|
238
320
|
|
239
|
-
#
|
240
|
-
#
|
241
|
-
#
|
321
|
+
# :call-seq:
|
322
|
+
# deploy_to = url
|
323
|
+
# deploy_to = hash
|
324
|
+
#
|
325
|
+
# Specifies the deployment repository. Accepts a Hash with different repository settings
|
326
|
+
# (e.g. url, username, password), or a String to only set the repository URL.
|
327
|
+
#
|
328
|
+
# Besides the URL, all other settings depend on the transport protocol in use. See #Transports
|
329
|
+
# for more details. Common settings include username and password.
|
242
330
|
#
|
243
331
|
# For example:
|
244
|
-
# repositories.deploy_to = { :url=>"sftp://example.com/var/www/
|
332
|
+
# repositories.deploy_to = { :url=>"sftp://example.com/var/www/repo/",
|
245
333
|
# :username="john", :password=>"secret" }
|
246
334
|
# or:
|
247
|
-
# repositories.deploy_to = "sftp://john:secret@example.com/var/www/
|
335
|
+
# repositories.deploy_to = "sftp://john:secret@example.com/var/www/repo/"
|
248
336
|
def deploy_to=(options)
|
249
337
|
options = { :url=>options } unless Hash === options
|
250
338
|
@deploy_to = options
|
251
339
|
end
|
252
340
|
|
253
|
-
#
|
254
|
-
#
|
255
|
-
#
|
256
|
-
#
|
257
|
-
#
|
258
|
-
#
|
259
|
-
#
|
341
|
+
# :call-seq:
|
342
|
+
# deploy_to() => hash
|
343
|
+
#
|
344
|
+
# Returns the current deployment repository setting as a Hash. This is a more convenient
|
345
|
+
# way to specify the deployment repository, as it allows you to specify the settings
|
346
|
+
# progressively.
|
347
|
+
#
|
348
|
+
# For example, the Rakefile will contain the repository URL used by all developers:
|
349
|
+
# repositories.deploy_to[:url] ||= "sftp://example.com/var/www/repo"
|
350
|
+
# Your private buildr.rb will contain your credentials:
|
351
|
+
# repositories.deploy_to[:username] = "john"
|
352
|
+
# repositories.deploy_to[:password] = "secret"
|
260
353
|
def deploy_to()
|
261
354
|
@deploy_to ||= {}
|
262
355
|
end
|
@@ -264,94 +357,99 @@ module Buildr
|
|
264
357
|
end
|
265
358
|
|
266
359
|
|
267
|
-
#
|
360
|
+
# :call-seq:
|
361
|
+
# repositories() => Repositories
|
362
|
+
#
|
363
|
+
# Returns an object you can use for setting the local repository path, remote repositories
|
364
|
+
# URL and deployment repository settings.
|
365
|
+
#
|
268
366
|
# See Repositories.
|
269
367
|
def repositories()
|
270
368
|
Repositories.instance
|
271
369
|
end
|
272
370
|
|
273
|
-
#
|
371
|
+
# :call-seq:
|
372
|
+
# artifact(spec) => Artifact
|
373
|
+
# artifact(spec) { |task| ... } => Artifact
|
374
|
+
#
|
375
|
+
# Creates a file task to download and install the specified artifact in the local repository.
|
274
376
|
#
|
275
|
-
#
|
276
|
-
#
|
377
|
+
# You can use a String or a Hash for the artifact specification. The file task will point at
|
378
|
+
# the artifact's path inside the local repository. You can then use this tasks as a prerequisite
|
379
|
+
# for other tasks.
|
277
380
|
#
|
278
|
-
#
|
279
|
-
#
|
381
|
+
# This task will download and install the artifact only once. In fact, it will download and
|
382
|
+
# install the artifact if the artifact does not already exist. You can enhance it if you have
|
383
|
+
# a different way of creating the artifact in the local repository. See Artifact for more details.
|
280
384
|
#
|
281
385
|
# For example, to specify an artifact:
|
282
386
|
# artifact("log4j:log4j:jar:1.1")
|
283
387
|
#
|
284
388
|
# To use the artifact in a task:
|
285
|
-
#
|
389
|
+
# compile.with artifact("log4j:log4j:jar:1.1")
|
286
390
|
#
|
287
391
|
# To specify an artifact and the means for creating it:
|
288
392
|
# download(artifact("dojo:dojo-widget:zip:2.0")=>
|
289
393
|
# "http://download.dojotoolkit.org/release-2.0/dojo-2.0-widget.zip")
|
290
|
-
def artifact(spec, &block)
|
394
|
+
def artifact(spec, &block) #:yields:task
|
291
395
|
spec = Artifact.to_hash(spec)
|
292
396
|
unless task = Artifact.lookup(spec)
|
293
397
|
task = Artifact.define_task(repositories.locate(spec))
|
398
|
+
task.send :apply_spec, spec
|
294
399
|
Rake::Task["rake:artifacts"].enhance [ task ]
|
295
400
|
Artifact.register(task)
|
296
401
|
end
|
297
|
-
task.apply_spec spec
|
298
402
|
task.enhance &block
|
299
403
|
end
|
300
404
|
|
301
|
-
#
|
302
|
-
#
|
405
|
+
# :call-seq:
|
406
|
+
# artifacts(*spec) => artifacts
|
407
|
+
#
|
408
|
+
# Handles multiple artifacts at a time. This method is the plural equivalent of
|
409
|
+
# #artifacts, but can do more things.
|
303
410
|
#
|
304
411
|
# You can pass any number of arguments, each of which can be:
|
305
|
-
# * An artifact specification
|
306
|
-
#
|
307
|
-
# *
|
308
|
-
# * A
|
309
|
-
# * An array of artifacts.
|
412
|
+
# * An artifact specification (String or Hash). Returns the appropriate Artifact task.
|
413
|
+
# * An artifact of any other task. Returns the task as is.
|
414
|
+
# * A project. Returns all artifacts created (packaged) by that project.
|
415
|
+
# * A string. Returns that string, assumed to be a file name.
|
416
|
+
# * An array of artifacts. Calls #artifacts on the array, flattens the result.
|
310
417
|
#
|
311
|
-
#
|
312
|
-
# to help in managing large combinations of artifacts. For example:
|
418
|
+
# For example, handling a collection of artifacts:
|
313
419
|
# xml = [ xerces, xalan, jaxp ]
|
314
420
|
# ws = [ axis, jax-ws, jaxb ]
|
315
421
|
# db = [ jpa, mysql, sqltools ]
|
316
|
-
#
|
317
|
-
# artifacts(base, models, services)
|
318
|
-
#
|
319
|
-
# You can also pass tasks and project. This is particularly useful for
|
320
|
-
# dealing with dependencies between projects that are part of the same
|
321
|
-
# build.
|
322
|
-
#
|
323
|
-
# For example:
|
324
|
-
# artifacts(base, models, services, module1, module2)
|
422
|
+
# artifacts(xml, ws, db)
|
325
423
|
#
|
326
|
-
#
|
327
|
-
#
|
328
|
-
#
|
329
|
-
# project, without installing them in the local repository.
|
424
|
+
# Using artifacts created by a project:
|
425
|
+
# artifact project("my-app") # All packages
|
426
|
+
# artifact project("mu-app").package(:war) # Only the WAR
|
330
427
|
def artifacts(*specs)
|
331
428
|
specs.inject([]) do |set, spec|
|
332
429
|
case spec
|
430
|
+
when Array
|
431
|
+
set |= artifacts(*spec)
|
333
432
|
when Hash
|
334
433
|
set |= [artifact(spec)]
|
335
|
-
when
|
434
|
+
when /([^:]+:){2,4}/ # A spec as opposed to a file name.
|
336
435
|
set |= [artifact(spec)]
|
337
|
-
when String
|
436
|
+
when String # Must always expand path.
|
338
437
|
set |= [File.expand_path(spec)]
|
339
438
|
when Project
|
340
439
|
set |= artifacts(spec.packages)
|
341
440
|
when Rake::Task
|
342
441
|
set |= [spec]
|
343
|
-
when Array
|
344
|
-
set |= artifacts(*spec)
|
345
442
|
else
|
346
|
-
fail "Invalid artifact specification: #{
|
443
|
+
fail "Invalid artifact specification in: #{specs.inspect}"
|
347
444
|
end
|
348
|
-
set
|
349
445
|
end
|
350
446
|
end
|
351
447
|
|
352
|
-
#
|
353
|
-
#
|
354
|
-
#
|
448
|
+
# :call-seq:
|
449
|
+
# groups(ids, :under=>group_name, :version=>number) => artifacts
|
450
|
+
#
|
451
|
+
# Convenience method for defining multiple artifacts that belong to the same group and version.
|
452
|
+
# Accepts multiple artifact identifiers follows by two hash values:
|
355
453
|
# * :under -- The group identifier
|
356
454
|
# * :version -- The version number
|
357
455
|
#
|
@@ -364,27 +462,32 @@ module Buildr
|
|
364
462
|
args.flatten.map { |id| artifact :group=>hash[:under], :version=>hash[:version], :id=>id }
|
365
463
|
end
|
366
464
|
|
367
|
-
#
|
368
|
-
#
|
369
|
-
#
|
465
|
+
# :call-seq:
|
466
|
+
# deploy(*files)
|
467
|
+
# deploy(*files, deploy_options)
|
468
|
+
#
|
469
|
+
# Deploys all the specified artifacts/files. If the last argument is a Hash, it is used to
|
470
|
+
# specify the deployment repository. Otherwise, obtains the deployment repository by calling
|
471
|
+
# Repositories#deploy_to.
|
370
472
|
#
|
371
473
|
# For example:
|
372
|
-
# deploy(
|
474
|
+
# deploy(foo.packages, :url=>"sftp://example.com/var/www/repo")
|
373
475
|
def deploy(*args)
|
374
476
|
# Where do we release to?
|
375
477
|
if Hash === args.last
|
376
478
|
options = args.pop
|
377
479
|
else
|
378
|
-
options = repositories.deploy_to
|
480
|
+
options = repositories.deploy_to.clone
|
379
481
|
options = { :url=>options.to_s } unless Hash === options
|
380
482
|
end
|
483
|
+
# Strip all options since the transport requires them separately from the URL.
|
381
484
|
url = options[:url]
|
382
485
|
options = options.reject { |k,v| k === :url }
|
383
486
|
fail "Don't know where to deploy, perhaps you forgot to set repositories.deploy_to" if url.blank?
|
384
487
|
|
385
|
-
args.each { |arg| arg.invoke if arg.respond_to?(:invoke) }
|
488
|
+
args.flatten.each { |arg| arg.invoke if arg.respond_to?(:invoke) }
|
386
489
|
Transports.perform url, options do |session|
|
387
|
-
args.each do |artifact|
|
490
|
+
args.flatten.each do |artifact|
|
388
491
|
if artifact.respond_to?(:to_spec)
|
389
492
|
# Upload artifact relative to base URL, need to create path before uploading.
|
390
493
|
puts "Deploying #{artifact.to_spec}" if verbose
|