buildr 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +151 -0
- data/LICENSE +202 -0
- data/README +0 -0
- data/lib/buildr.rb +43 -0
- data/lib/core/artifact.rb +394 -0
- data/lib/core/build.rb +108 -0
- data/lib/core/core.rb +49 -0
- data/lib/core/project.rb +313 -0
- data/lib/core/transports.rb +381 -0
- data/lib/java/compile.rb +316 -0
- data/lib/java/java.rb +117 -0
- data/lib/java/javacc.rb +88 -0
- data/lib/java/openjpa.rb +52 -0
- data/lib/java/packaging.rb +217 -0
- data/lib/java/xmlbeans.rb +64 -0
- data/lib/tasks/download.rb +38 -0
- data/lib/tasks/filter.rb +96 -0
- data/lib/tasks/zip.rb +313 -0
- metadata +134 -0
data/lib/core/build.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
module Buildr
|
2
|
+
|
3
|
+
class ReleaseTask < Rake::Task
|
4
|
+
|
5
|
+
VERSION_NUMBER_PATTERN = /VERSION_NUMBER\s*=\s*(["'])(.*)\1/
|
6
|
+
NEXT_VERSION_PATTERN = /NEXT_VERSION\s*=\s*(["'])(.*)\1/
|
7
|
+
|
8
|
+
def initialize(*args)
|
9
|
+
super
|
10
|
+
enhance do |task|
|
11
|
+
# Make sure we don't have anything uncommitted in SVN.
|
12
|
+
fail "Uncommitted SVN files violate the First Principle Of Release!" unless
|
13
|
+
svn("status").empty?
|
14
|
+
# Load the Rakefile and find the version numbers.
|
15
|
+
next_ver = update_version
|
16
|
+
# Run the deployment externally using the new version number.
|
17
|
+
sh "rake deploy"
|
18
|
+
update_next_version next_ver
|
19
|
+
tag_repository
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Change the Rakefile and update the current version number to the
|
24
|
+
# next version number (VERSION_NUMBER = NEXT_VERSION). We need this
|
25
|
+
# before making a release with the next version. Return the next version.
|
26
|
+
def update_version()
|
27
|
+
rakefile = File.read(Rake.application.rakefile)
|
28
|
+
version = rakefile.scan(VERSION_NUMBER_PATTERN)[0][1] or
|
29
|
+
fail "Looking for VERSION_NUMBER = \"...\" in your Rakefile, none found"
|
30
|
+
next_ver = rakefile.scan(NEXT_VERSION_PATTERN)[0][1] or
|
31
|
+
fail "Looking for NEXT_VERSION = \"...\" in your Rakefile, none found"
|
32
|
+
if verbose
|
33
|
+
puts "Current version: #{version}"
|
34
|
+
puts "Next version: #{next_ver}"
|
35
|
+
end
|
36
|
+
|
37
|
+
# Switch version numbers.
|
38
|
+
rakefile.gsub!(VERSION_NUMBER_PATTERN) { |ver| ver.sub(/(["']).*\1/, %Q{"#{next_ver}"}) }
|
39
|
+
File.open(Rake.application.rakefile, "w") { |file| file.write rakefile }
|
40
|
+
|
41
|
+
next_ver
|
42
|
+
end
|
43
|
+
|
44
|
+
# Change the Rakefile and update the next version number to one after
|
45
|
+
# (NEXT_VERSION = NEXT_VERSION + 1). We do this to automatically increment
|
46
|
+
# future version number after each successful release.
|
47
|
+
def update_next_version(version)
|
48
|
+
# Update to new version number.
|
49
|
+
nums = version.split(".")
|
50
|
+
nums[-1] = nums[-1].to_i + 1
|
51
|
+
next_ver = nums.join(".")
|
52
|
+
rakefile = File.read(Rake.application.rakefile)
|
53
|
+
rakefile.gsub!(NEXT_VERSION_PATTERN) { |ver| ver.sub(/(["']).*\1/, %Q{"#{next_ver}"}) }
|
54
|
+
File.open(Rake.application.rakefile, "w") { |file| file.write rakefile }
|
55
|
+
|
56
|
+
# Commit new version number.
|
57
|
+
svn "commit", "-m", "Changed release number to #{version}"
|
58
|
+
end
|
59
|
+
|
60
|
+
# Create a tag in the SVN repository.
|
61
|
+
def tag_repository()
|
62
|
+
# Copy to tag.
|
63
|
+
cur_url = svn("info").scan(/URL: (.*)/)[0][0]
|
64
|
+
new_url = cur_url.sub(/trunk$/, "tags/#{cur_ver}")
|
65
|
+
svn "copy", cur_url, new_url
|
66
|
+
end
|
67
|
+
|
68
|
+
def svn(*args)
|
69
|
+
#args << { :verbose=>Rake.application.options.trace }
|
70
|
+
stdin, stdout, stderr = Open3.popen3("svn", *args)
|
71
|
+
stdin.close
|
72
|
+
error = stderr.read
|
73
|
+
fail error unless error.empty?
|
74
|
+
stdout.read
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Handles the build and clean tasks.
|
79
|
+
desc "Clean all projects"
|
80
|
+
LocalDirectoryTask.define_task("clean")
|
81
|
+
desc "Build all projects"
|
82
|
+
LocalDirectoryTask.define_task("build")
|
83
|
+
desc "Make a release"
|
84
|
+
ReleaseTask.define_task "release"
|
85
|
+
|
86
|
+
class Project
|
87
|
+
def build(*args, &block)
|
88
|
+
returning(@build_task ||= recursive_task("build")) do |task|
|
89
|
+
task.enhance args, &block
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def clean(*args, &block)
|
94
|
+
returning(@clean_task ||= recursive_task("clean")) do |task|
|
95
|
+
task.enhance args, &block
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
Project.on_create do |project|
|
101
|
+
desc "Clean all files generated during the build process"
|
102
|
+
project.clean
|
103
|
+
|
104
|
+
desc "Build this project"
|
105
|
+
project.build
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
data/lib/core/core.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# returning(obj) and with(obj)
|
2
|
+
require "facet/kernel/with"
|
3
|
+
# &:symbol goodness.
|
4
|
+
require "facet/symbol/to_proc"
|
5
|
+
# blank? on string and nil
|
6
|
+
require "facet/string/blank"
|
7
|
+
require "facet/nilclass/blank"
|
8
|
+
# What it says.
|
9
|
+
require "facet/module/alias_method_chain"
|
10
|
+
require "highline"
|
11
|
+
|
12
|
+
|
13
|
+
module Kernel
|
14
|
+
def warn_with_color(message)
|
15
|
+
warn_without_color HighLine.new.color(message.to_s, :red)
|
16
|
+
end
|
17
|
+
alias_method_chain :warn, :color
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
module Buildr
|
22
|
+
module Attributes
|
23
|
+
|
24
|
+
def self.included(mod)
|
25
|
+
mod.extend(self)
|
26
|
+
end
|
27
|
+
|
28
|
+
# An inherited attribute gets it value from an instance variable
|
29
|
+
# with the same name. If the value is not set it will defer to the
|
30
|
+
# parent object. If there is no parent object, it will use the
|
31
|
+
# default value; with a block, it evaluates the block by calling
|
32
|
+
# instance_eval on the object.
|
33
|
+
#
|
34
|
+
# For example:
|
35
|
+
# inherited_attr :version
|
36
|
+
# inherited_attr :src_dir, "src"
|
37
|
+
# inherited_attr :java_src_dir do src_dir + "/main/java"
|
38
|
+
def inherited_attr(symbol, default = nil, &block)
|
39
|
+
block ||= proc { default }
|
40
|
+
define_method symbol do
|
41
|
+
instance_variable_get("@#{symbol}") || (parent ? parent.send(symbol) : self.instance_eval(&block))
|
42
|
+
end
|
43
|
+
define_method "#{symbol}=" do |value|
|
44
|
+
instance_variable_set("@#{symbol}", value)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
data/lib/core/project.rb
ADDED
@@ -0,0 +1,313 @@
|
|
1
|
+
module Buildr
|
2
|
+
|
3
|
+
# A project is a means to assemble multiple related tasks.
|
4
|
+
#
|
5
|
+
# A project will create its own set of internal tasks, such as
|
6
|
+
# compile, build, clean, install. These tasks are fed with project
|
7
|
+
# properties, e.g. the clean task will remove the project.target_dir
|
8
|
+
# directory, where files are created during the build process.
|
9
|
+
#
|
10
|
+
# Projects can be organized hierarchically such that sub-projects
|
11
|
+
# inherit default properties from their parent project, and
|
12
|
+
# participate in tasks executed on the parent project.
|
13
|
+
#
|
14
|
+
# For example:
|
15
|
+
# define "parent" do |project|
|
16
|
+
# project.version = "1.1"
|
17
|
+
#
|
18
|
+
# define "child1"
|
19
|
+
# define "child2"
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# This definition will work for a directory structure of:
|
23
|
+
# . -- Parent project
|
24
|
+
# |__child 1
|
25
|
+
# |__child 2
|
26
|
+
#
|
27
|
+
# The sub-projects child1 and child2 inherit the project version number
|
28
|
+
# from the parent project. In addition, for certain tasks such as build,
|
29
|
+
# running the task on the parent project will also run it on all
|
30
|
+
# sub-projects.
|
31
|
+
#
|
32
|
+
# Use the #define method to define a new project, and within the context
|
33
|
+
# of a project to define a sub-project. Use the #project method to find
|
34
|
+
# an existing project, and within the context of a project, one of its
|
35
|
+
# sub-projects.
|
36
|
+
#
|
37
|
+
# The main block in the project definition is executed during the project
|
38
|
+
# definition. Use it to set project properties, and configure tasks.
|
39
|
+
# Do not do any actual work in there.
|
40
|
+
class Project
|
41
|
+
|
42
|
+
class << self
|
43
|
+
|
44
|
+
# See Buildr#define.
|
45
|
+
def define(*args, &block)
|
46
|
+
name, properties = name_and_properties_from_args(*args)
|
47
|
+
project(name).send :_define, properties, &block
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the specified project (top-level only).
|
51
|
+
def project(name)
|
52
|
+
@projects ||= {}
|
53
|
+
name.split(":").inject(nil) do |parent, name|
|
54
|
+
if parent
|
55
|
+
@projects["#{parent.name}:#{name}"] ||= Project.new(name, parent)
|
56
|
+
else
|
57
|
+
@projects[name] ||= Project.new(name, nil)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns all project definitions, including sub-projects.
|
63
|
+
def projects()
|
64
|
+
(@projects || []).map { |name, project| project }
|
65
|
+
end
|
66
|
+
|
67
|
+
# Discard all project definitions.
|
68
|
+
def clear()
|
69
|
+
@projects.clear if @projects
|
70
|
+
end
|
71
|
+
|
72
|
+
# The Project class defines very little behavior for new process instances.
|
73
|
+
# Use #on_create to add behavior to new process instances.
|
74
|
+
#
|
75
|
+
# Every block you register with #on_create will be called with a project
|
76
|
+
# instance whenever a new project is created. You can then define tasks,
|
77
|
+
# set project properties, etc.
|
78
|
+
#
|
79
|
+
# Keep in mind that the order on which #on_create blocks are called is
|
80
|
+
# not determined. You cannot depend on tasks defined by another block to
|
81
|
+
# exist at the time your block is called. Use Project#enhance for that.
|
82
|
+
def on_create(&block)
|
83
|
+
(@on_create ||= []) << block if block
|
84
|
+
end
|
85
|
+
|
86
|
+
# :nodoc:
|
87
|
+
def name_and_properties_from_args(*args)
|
88
|
+
if Hash === args.last
|
89
|
+
properties = args.pop.clone
|
90
|
+
else
|
91
|
+
properties = {}
|
92
|
+
end
|
93
|
+
if String === args.first
|
94
|
+
name = args.shift
|
95
|
+
else
|
96
|
+
name = properties.delete(:name)
|
97
|
+
end
|
98
|
+
raise ArgumentError, "Expected project name followed by (optional) project properties." unless args.empty?
|
99
|
+
raise ArgumentError, "Missing project name." unless name
|
100
|
+
[ name, properties ]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
include Attributes
|
105
|
+
|
106
|
+
# The project name.
|
107
|
+
attr_reader :name
|
108
|
+
|
109
|
+
# The parent project if this is a sub-project.
|
110
|
+
attr_reader :parent
|
111
|
+
|
112
|
+
# The base directory of this project.
|
113
|
+
attr_reader :base_dir
|
114
|
+
|
115
|
+
# Always construct a project using Object#project or Project#project.
|
116
|
+
def initialize(name, parent)
|
117
|
+
fail "Missing project name" unless name
|
118
|
+
@name = parent ? "#{parent.name}:#{name}" : name
|
119
|
+
@parent = parent
|
120
|
+
if parent
|
121
|
+
# For sub-project, a good default is a directory in the parent's base_dir,
|
122
|
+
# using the same name as the project.
|
123
|
+
@base_dir = File.join(parent.base_dir, name)
|
124
|
+
else
|
125
|
+
# For top-level project, a good default is the directory where we found the Rakefile.
|
126
|
+
@base_dir = Dir.pwd
|
127
|
+
end
|
128
|
+
@actions = []
|
129
|
+
end
|
130
|
+
|
131
|
+
# Define a new sub-project within this project.
|
132
|
+
def define(*args, &block)
|
133
|
+
name, properties = Project.name_and_properties_from_args(*args)
|
134
|
+
Project.define("#{self.name}:#{name}", properties, &block)
|
135
|
+
end
|
136
|
+
|
137
|
+
def defined?()
|
138
|
+
@defined
|
139
|
+
end
|
140
|
+
|
141
|
+
# Returns a path made from the specified arguments. Relative paths are turned
|
142
|
+
# into absolute paths using the based directory of this project.
|
143
|
+
#
|
144
|
+
# If you pass multiple arguments, they are combined into a path using File#join.
|
145
|
+
# If one of the arguments is a symbol, it is used to retrieve that process
|
146
|
+
# property.
|
147
|
+
#
|
148
|
+
# For example:
|
149
|
+
# path_to("foo", "bar")
|
150
|
+
# path_to(:target_dir, "foo")
|
151
|
+
# path_to("/tmp")
|
152
|
+
# are equivalent to:
|
153
|
+
# File.join(base_dir, "foo", "bar")
|
154
|
+
# File.join(base_dir, project.target_dir, "foo")
|
155
|
+
# "/tmp"
|
156
|
+
def path_to(*args)
|
157
|
+
File.expand_path(File.join(args.map { |arg| Symbol === arg ? send(arg) : arg.to_s }), base_dir)
|
158
|
+
end
|
159
|
+
|
160
|
+
# Returns the specified sub-project of this project, or any of its descendant,
|
161
|
+
# or a top-level project.
|
162
|
+
#
|
163
|
+
# For example:
|
164
|
+
# bar.project("baz")
|
165
|
+
# will find the first match from:
|
166
|
+
# foo:bar:baz
|
167
|
+
# foo:baz
|
168
|
+
# baz
|
169
|
+
def project(name)
|
170
|
+
Project.project(name)
|
171
|
+
end
|
172
|
+
|
173
|
+
# Returns all sub-projects defined in this project, including their
|
174
|
+
# sub-projects.
|
175
|
+
def projects()
|
176
|
+
prefix = name + ":"
|
177
|
+
Project.projects.map { |project| project.starts_with?(prefix) }
|
178
|
+
end
|
179
|
+
|
180
|
+
# The project ID is the project name, and for a sub-project the
|
181
|
+
# parent project ID followed by the project name, separated with a
|
182
|
+
# hyphen. For example, "foo" and "foo-bar".
|
183
|
+
def id()
|
184
|
+
name.gsub(":", "-")
|
185
|
+
end
|
186
|
+
|
187
|
+
# Define a recursive task.
|
188
|
+
#
|
189
|
+
# A recursive task for a project will execute all sub-project tasks of
|
190
|
+
# the same name before it executes itself. In addition, if a task with
|
191
|
+
# the same name exists (not prefixed with a project), it will execute
|
192
|
+
# same task but only for the current project -- as determined by the
|
193
|
+
# current working directory.
|
194
|
+
#
|
195
|
+
# For example:
|
196
|
+
# rake foo:build
|
197
|
+
# Will execute foo:build, foo:bar:build and foo:baz:build
|
198
|
+
#
|
199
|
+
# Inside the bar directory:
|
200
|
+
# rake build
|
201
|
+
# Will execute foo:bar:build.
|
202
|
+
#
|
203
|
+
# Note, this method is used to define the task as recursive. It will
|
204
|
+
# also define the task if the task does not already exist. However,
|
205
|
+
# you can define the task before calling #recursive_task, e.g. to
|
206
|
+
# create a file task, or any other special purpose task.
|
207
|
+
def recursive_task(arg, &block)
|
208
|
+
name = Hash === arg ? arg.keys.first : arg
|
209
|
+
returning(task(arg)) do |task|
|
210
|
+
if parent
|
211
|
+
Rake::Task["^#{parent.name}:#{name}"].enhance([ task ])
|
212
|
+
end
|
213
|
+
task.enhance &block
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def enhance(&block)
|
218
|
+
@actions << block if block
|
219
|
+
end
|
220
|
+
|
221
|
+
protected
|
222
|
+
|
223
|
+
def _define(properties, &block)
|
224
|
+
fail "Project #{name} already defined" if @defined
|
225
|
+
@defined = true
|
226
|
+
@base_dir = properties.delete(:base_dir) if properties.has_key?(:base_dir)
|
227
|
+
# How convenient: project name is used to create compound namespace for tasks.
|
228
|
+
namespace name.split(":").last do
|
229
|
+
# On_create requires so we have attribute accessors for the properties.
|
230
|
+
(self.class.instance_variable_get(:@on_create) || []).each { |callback| callback.call self }
|
231
|
+
properties.each { |name, value| send "#{name}=", value }
|
232
|
+
if block
|
233
|
+
begin
|
234
|
+
# Evaluate in context of project, and pass project. And for that we need
|
235
|
+
# a method definition, on the singleton so we don't conflict with anyone else.
|
236
|
+
singleton = (class << self ; self ; end)
|
237
|
+
singleton.send :define_method, :__enhance__, &block
|
238
|
+
self.__enhance__ self
|
239
|
+
ensure
|
240
|
+
singleton.send :remove_method, :__enhance__
|
241
|
+
end
|
242
|
+
end
|
243
|
+
@actions.each { |callback| callback.call self }
|
244
|
+
@actions.clear
|
245
|
+
end
|
246
|
+
self
|
247
|
+
end
|
248
|
+
|
249
|
+
end
|
250
|
+
|
251
|
+
# :call-seq:
|
252
|
+
# define name { |project| ... }
|
253
|
+
# define name, properties { |project| ... }
|
254
|
+
# define properties { |project| ... }
|
255
|
+
#
|
256
|
+
# Defines a new project.
|
257
|
+
#
|
258
|
+
# The first argument is the project name. Each project must have a unique name,
|
259
|
+
# to distinguish it from other projects. The name must be unique either across
|
260
|
+
# all top-level projects, or all sub-projects belonging to the same parent.
|
261
|
+
#
|
262
|
+
# The second argument contains any number of properties that are set on the
|
263
|
+
# project at creation, before calling the block. There is no special preference
|
264
|
+
# to properties passed as arguments.
|
265
|
+
#
|
266
|
+
# The second argument is optional. You may omit the first argument, by passing
|
267
|
+
# the project name as the property :name.
|
268
|
+
#
|
269
|
+
# If a block is given, it is executed in the context of the project, and passed
|
270
|
+
# a reference to the project. These two are equivalent:
|
271
|
+
# define "foo", :version=>"1" do
|
272
|
+
# self.group = "foo-s"
|
273
|
+
# end
|
274
|
+
#
|
275
|
+
# define "foo" do |project|
|
276
|
+
# project.version = "1"
|
277
|
+
# project.group = "foo-s"
|
278
|
+
# end
|
279
|
+
def define(*args, &block)
|
280
|
+
Project.define(*args, &block)
|
281
|
+
end
|
282
|
+
|
283
|
+
# Returns a top-level project.
|
284
|
+
def project(name)
|
285
|
+
Project.project(name)
|
286
|
+
end
|
287
|
+
|
288
|
+
task "check" do |task|
|
289
|
+
# Find all projects that:
|
290
|
+
# - Are referenced but never defined.
|
291
|
+
# - Do not have a base directory.
|
292
|
+
Project.projects.each do |project|
|
293
|
+
warn "Project #{project.name} referenced but not defined" unless project.defined?
|
294
|
+
warn "Project #{project.name} does not have a base directory" unless File.exist?(project.base_dir)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
class LocalDirectoryTask < Rake::Task
|
299
|
+
|
300
|
+
def initialize(*args)
|
301
|
+
super
|
302
|
+
enhance do |task|
|
303
|
+
projects = Project.projects.select { |project| project.base_dir == Rake.application.original_dir }
|
304
|
+
if verbose && projects.empty?
|
305
|
+
warn "No projects defined for directory #{Rake.application.original_dir}"
|
306
|
+
end
|
307
|
+
projects.each { |project| task("#{project.name}:#{task.name}").invoke }
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|