ittayd-buildr 1.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (171) hide show
  1. data/CHANGELOG +915 -0
  2. data/DISCLAIMER +7 -0
  3. data/LICENSE +176 -0
  4. data/NOTICE +26 -0
  5. data/README.rdoc +146 -0
  6. data/Rakefile +64 -0
  7. data/_buildr +28 -0
  8. data/addon/buildr/antlr.rb +65 -0
  9. data/addon/buildr/cobertura.rb +22 -0
  10. data/addon/buildr/drb.rb +281 -0
  11. data/addon/buildr/emma.rb +22 -0
  12. data/addon/buildr/hibernate.rb +142 -0
  13. data/addon/buildr/javacc.rb +85 -0
  14. data/addon/buildr/jdepend.rb +60 -0
  15. data/addon/buildr/jetty.rb +248 -0
  16. data/addon/buildr/jibx.rb +86 -0
  17. data/addon/buildr/nailgun.rb +221 -0
  18. data/addon/buildr/openjpa.rb +90 -0
  19. data/addon/buildr/org/apache/buildr/BuildrNail$Main.class +0 -0
  20. data/addon/buildr/org/apache/buildr/BuildrNail.class +0 -0
  21. data/addon/buildr/org/apache/buildr/BuildrNail.java +41 -0
  22. data/addon/buildr/org/apache/buildr/JettyWrapper$1.class +0 -0
  23. data/addon/buildr/org/apache/buildr/JettyWrapper$BuildrHandler.class +0 -0
  24. data/addon/buildr/org/apache/buildr/JettyWrapper.class +0 -0
  25. data/addon/buildr/org/apache/buildr/JettyWrapper.java +144 -0
  26. data/addon/buildr/path.rb +136 -0
  27. data/addon/buildr/xmlbeans.rb +93 -0
  28. data/bin/buildr +19 -0
  29. data/buildr.buildfile +53 -0
  30. data/buildr.gemspec +58 -0
  31. data/doc/css/default.css +228 -0
  32. data/doc/css/print.css +100 -0
  33. data/doc/css/syntax.css +52 -0
  34. data/doc/images/apache-incubator-logo.png +0 -0
  35. data/doc/images/buildr-hires.png +0 -0
  36. data/doc/images/buildr.png +0 -0
  37. data/doc/images/favicon.png +0 -0
  38. data/doc/images/growl-icon.tiff +0 -0
  39. data/doc/images/note.png +0 -0
  40. data/doc/images/project-structure.png +0 -0
  41. data/doc/images/tip.png +0 -0
  42. data/doc/images/zbuildr.tif +0 -0
  43. data/doc/pages/artifacts.textile +207 -0
  44. data/doc/pages/building.textile +240 -0
  45. data/doc/pages/contributing.textile +208 -0
  46. data/doc/pages/download.textile +62 -0
  47. data/doc/pages/extending.textile +175 -0
  48. data/doc/pages/getting_started.textile +273 -0
  49. data/doc/pages/index.textile +42 -0
  50. data/doc/pages/languages.textile +407 -0
  51. data/doc/pages/mailing_lists.textile +17 -0
  52. data/doc/pages/more_stuff.textile +314 -0
  53. data/doc/pages/packaging.textile +427 -0
  54. data/doc/pages/projects.textile +274 -0
  55. data/doc/pages/recipes.textile +103 -0
  56. data/doc/pages/settings_profiles.textile +274 -0
  57. data/doc/pages/testing.textile +212 -0
  58. data/doc/pages/troubleshooting.textile +103 -0
  59. data/doc/pages/whats_new.textile +323 -0
  60. data/doc/print.haml +51 -0
  61. data/doc/print.toc.yaml +29 -0
  62. data/doc/scripts/buildr-git.rb +412 -0
  63. data/doc/scripts/install-jruby.sh +44 -0
  64. data/doc/scripts/install-linux.sh +64 -0
  65. data/doc/scripts/install-osx.sh +52 -0
  66. data/doc/site.haml +56 -0
  67. data/doc/site.toc.yaml +47 -0
  68. data/etc/KEYS +151 -0
  69. data/etc/git-svn-authors +16 -0
  70. data/lib/buildr/core/application.rb +665 -0
  71. data/lib/buildr/core/build.rb +311 -0
  72. data/lib/buildr/core/checks.rb +254 -0
  73. data/lib/buildr/core/common.rb +150 -0
  74. data/lib/buildr/core/compile.rb +590 -0
  75. data/lib/buildr/core/environment.rb +117 -0
  76. data/lib/buildr/core/filter.rb +366 -0
  77. data/lib/buildr/core/generate.rb +195 -0
  78. data/lib/buildr/core/help.rb +119 -0
  79. data/lib/buildr/core/osx.rb +49 -0
  80. data/lib/buildr/core/progressbar.rb +156 -0
  81. data/lib/buildr/core/project.rb +923 -0
  82. data/lib/buildr/core/test.rb +715 -0
  83. data/lib/buildr/core/transports.rb +560 -0
  84. data/lib/buildr/core/util.rb +294 -0
  85. data/lib/buildr/core.rb +29 -0
  86. data/lib/buildr/groovy/bdd.rb +106 -0
  87. data/lib/buildr/groovy/compiler.rb +138 -0
  88. data/lib/buildr/groovy.rb +18 -0
  89. data/lib/buildr/ide/eclipse.rb +222 -0
  90. data/lib/buildr/ide/idea.ipr.template +300 -0
  91. data/lib/buildr/ide/idea.rb +190 -0
  92. data/lib/buildr/ide/idea7x.ipr.template +290 -0
  93. data/lib/buildr/ide/idea7x.rb +212 -0
  94. data/lib/buildr/ide.rb +19 -0
  95. data/lib/buildr/java/ant.rb +92 -0
  96. data/lib/buildr/java/bdd.rb +451 -0
  97. data/lib/buildr/java/cobertura.rb +236 -0
  98. data/lib/buildr/java/commands.rb +211 -0
  99. data/lib/buildr/java/compiler.rb +348 -0
  100. data/lib/buildr/java/deprecated.rb +141 -0
  101. data/lib/buildr/java/emma.rb +238 -0
  102. data/lib/buildr/java/jruby.rb +117 -0
  103. data/lib/buildr/java/jtestr_runner.rb.erb +116 -0
  104. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.class +0 -0
  105. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.java +119 -0
  106. data/lib/buildr/java/packaging.rb +717 -0
  107. data/lib/buildr/java/pom.rb +174 -0
  108. data/lib/buildr/java/rjb.rb +155 -0
  109. data/lib/buildr/java/test_result.rb +307 -0
  110. data/lib/buildr/java/tests.rb +329 -0
  111. data/lib/buildr/java/version_requirement.rb +172 -0
  112. data/lib/buildr/java.rb +23 -0
  113. data/lib/buildr/packaging/archive.rb +488 -0
  114. data/lib/buildr/packaging/artifact.rb +759 -0
  115. data/lib/buildr/packaging/artifact_namespace.rb +972 -0
  116. data/lib/buildr/packaging/artifact_search.rb +140 -0
  117. data/lib/buildr/packaging/gems.rb +102 -0
  118. data/lib/buildr/packaging/package.rb +233 -0
  119. data/lib/buildr/packaging/tar.rb +186 -0
  120. data/lib/buildr/packaging/version_requirement.rb +172 -0
  121. data/lib/buildr/packaging/zip.rb +64 -0
  122. data/lib/buildr/packaging/ziptask.rb +313 -0
  123. data/lib/buildr/packaging.rb +24 -0
  124. data/lib/buildr/resources/buildr.icns +0 -0
  125. data/lib/buildr/scala/compiler.rb +109 -0
  126. data/lib/buildr/scala/tests.rb +203 -0
  127. data/lib/buildr/scala.rb +19 -0
  128. data/lib/buildr.rb +33 -0
  129. data/rakelib/apache.rake +191 -0
  130. data/rakelib/changelog.rake +57 -0
  131. data/rakelib/doc.rake +103 -0
  132. data/rakelib/package.rake +76 -0
  133. data/rakelib/release.rake +65 -0
  134. data/rakelib/rspec.rake +83 -0
  135. data/rakelib/rubyforge.rake +56 -0
  136. data/rakelib/scm.rake +49 -0
  137. data/rakelib/setup.rake +81 -0
  138. data/rakelib/stage.rake +48 -0
  139. data/spec/addon/drb_spec.rb +328 -0
  140. data/spec/core/application_spec.rb +419 -0
  141. data/spec/core/build_spec.rb +423 -0
  142. data/spec/core/checks_spec.rb +519 -0
  143. data/spec/core/common_spec.rb +670 -0
  144. data/spec/core/compile_spec.rb +582 -0
  145. data/spec/core/generate_spec.rb +33 -0
  146. data/spec/core/project_spec.rb +776 -0
  147. data/spec/core/test_spec.rb +1098 -0
  148. data/spec/core/transport_spec.rb +500 -0
  149. data/spec/groovy/bdd_spec.rb +80 -0
  150. data/spec/groovy/compiler_spec.rb +239 -0
  151. data/spec/ide/eclipse_spec.rb +311 -0
  152. data/spec/java/ant.rb +33 -0
  153. data/spec/java/bdd_spec.rb +358 -0
  154. data/spec/java/cobertura_spec.rb +77 -0
  155. data/spec/java/compiler_spec.rb +446 -0
  156. data/spec/java/emma_spec.rb +120 -0
  157. data/spec/java/java_spec.rb +96 -0
  158. data/spec/java/packaging_spec.rb +1120 -0
  159. data/spec/java/test_coverage_spec.rb +255 -0
  160. data/spec/java/tests_spec.rb +471 -0
  161. data/spec/packaging/archive_spec.rb +503 -0
  162. data/spec/packaging/artifact_namespace_spec.rb +646 -0
  163. data/spec/packaging/artifact_spec.rb +795 -0
  164. data/spec/packaging/packaging_helper.rb +63 -0
  165. data/spec/packaging/packaging_spec.rb +589 -0
  166. data/spec/sandbox.rb +139 -0
  167. data/spec/scala/compiler_spec.rb +228 -0
  168. data/spec/scala/tests_spec.rb +215 -0
  169. data/spec/spec_helpers.rb +327 -0
  170. data/spec/version_requirement_spec.rb +123 -0
  171. metadata +377 -0
@@ -0,0 +1,923 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one or more
2
+ # contributor license agreements. See the NOTICE file distributed with this
3
+ # work for additional information regarding copyright ownership. The ASF
4
+ # licenses this file to you under the Apache License, Version 2.0 (the
5
+ # "License"); you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations under
14
+ # the License.
15
+
16
+
17
+ require 'buildr/core/util'
18
+
19
+
20
+ module Buildr
21
+
22
+ # Symbolic mapping for directory layout. Used for both the default and custom layouts.
23
+ #
24
+ # For example, the default layout maps [:source, :main, :java] to 'src/main/java', and
25
+ # [:target, :main, :classes] to 'target/classes'. You can use this to change the layout
26
+ # of your projects.
27
+ #
28
+ # To map [:source, :main] into the 'sources' directory:
29
+ # my_layout = Layout.new
30
+ # my_layout[:source, :main] = 'sources'
31
+ #
32
+ # define 'foo', :layout=>my_layout do
33
+ # ...
34
+ # end
35
+ #
36
+ # To map [:source, :main, :java] to 'java/main':
37
+ # class MainLast < Layout
38
+ # def expand(*args)
39
+ # if args[0..1] == [:source, :main]
40
+ # super args[2], :main, *args[3,]
41
+ # else
42
+ # super
43
+ # end
44
+ # end
45
+ # end
46
+ #
47
+ # define 'foo', :layout=>MainLast do
48
+ # ...
49
+ # end
50
+ class Layout
51
+
52
+ class << self
53
+
54
+ # Default layout used by new projects.
55
+ attr_accessor :default
56
+
57
+ end
58
+
59
+ def initialize #:nodoc:
60
+ @mapping = {}
61
+ end
62
+
63
+ # Expands list of symbols and path names into a full path, for example:
64
+ # puts default.expand(:source, :main, :java)
65
+ # => "src/main/java"
66
+ def expand(*args)
67
+ args = args.compact.reject { |s| s.to_s.empty? }.map(&:to_sym)
68
+ return '' if args.empty?
69
+ @mapping[args] ||= File.join(*[expand(*args[0..-2]), args.last.to_s].reject(&:empty?)) if args.size > 1
70
+ return @mapping[args] || args.first.to_s
71
+ end
72
+
73
+ # Resolves a list of symbols into a path.
74
+ def [](*args)
75
+ @mapping[args.map(&:to_sym)]
76
+ end
77
+
78
+ # Specifies the path resolved from a list of symbols.
79
+ def []=(*args)
80
+ @mapping[args[0...-1].map(&:to_sym)] = args.last
81
+ end
82
+
83
+ def initialize_copy(copy)
84
+ copy.instance_variable_set :@mapping, @mapping.clone
85
+ end
86
+
87
+ # Default layout has the following properties:
88
+ # * :source maps to the 'src' directory.
89
+ # * Anything under :source maps verbatim (e.g. :source, :main becomes 'src/main')
90
+ # * :target maps to the 'target' directory.
91
+ # * :target, :main maps to the 'target' directory as well.
92
+ # * Anything under :target, :main maps verbatim (e.g. :target, :main, :classes becomes 'target/classes')
93
+ # * Anything else under :target also maps verbatim (e.g. :target, :test becomes 'target/test')
94
+ class Default < Layout
95
+
96
+ def initialize
97
+ super
98
+ self[:source] = 'src'
99
+ self[:target, :main] = 'target'
100
+ end
101
+
102
+ end
103
+
104
+ self.default = Default.new
105
+
106
+ end
107
+
108
+ # A project definition is where you define all the tasks associated with
109
+ # the project you're building.
110
+ #
111
+ # The project itself will define several life cycle tasks for you. For example,
112
+ # it automatically creates a compile task that will compile all the source files
113
+ # found in src/main/java into target/classes, a test task that will compile source
114
+ # files from src/test/java and run all the JUnit tests found there, and a build
115
+ # task to compile and then run the tests.
116
+ #
117
+ # You use the project definition to enhance these tasks, for example, telling the
118
+ # compile task which class path dependencies to use. Or telling the project how
119
+ # to package an artifact, e.g. creating a JAR using <tt>package :jar</tt>.
120
+ #
121
+ # You can also define additional tasks that are executed by project tasks,
122
+ # or invoked from rake.
123
+ #
124
+ # Tasks created by the project are all prefixed with the project name, e.g.
125
+ # the project foo creates the task foo:compile. If foo contains a sub-project bar,
126
+ # the later will define the task foo:bar:compile. Since the compile task is
127
+ # recursive, compiling foo will also compile foo:bar.
128
+ #
129
+ # If you run:
130
+ # buildr compile
131
+ # from the command line, it will execute the compile task of the current project.
132
+ #
133
+ # Projects and sub-projects follow a directory heirarchy. The Buildfile is assumed to
134
+ # reside in the same directory as the top-level project, and each sub-project is
135
+ # contained in a sub-directory in the same name. For example:
136
+ # /home/foo
137
+ # |__ Buildfile
138
+ # |__ src/main/java
139
+ # |__ foo
140
+ # |__ src/main/java
141
+ #
142
+ # The default structure of each project is assumed to be:
143
+ # src
144
+ # |__main
145
+ # | |__java <-- Source files to compile
146
+ # | |__resources <-- Resources to copy
147
+ # | |__webapp <-- For WARs
148
+ # |__test
149
+ # | |__java <-- Source files to compile (tests)
150
+ # | |__resources <-- Resources to copy (tests)
151
+ # |__target <-- Packages created here
152
+ # | |__classes <-- Generated when compiling
153
+ # | |__resources <-- Copied (and filtered) from resources
154
+ # | |__test/classes <-- Generated when compiling tests
155
+ # | |__test/resources <-- Copied (and filtered) from resources
156
+ # |__reports <-- Test, coverage and other reports
157
+ #
158
+ # You can change the project layout by passing a new Layout to the project definition.
159
+ #
160
+ # You can only define a project once using #define. Afterwards, you can obtain the project
161
+ # definition using #project. The order in which you define projects is not important,
162
+ # project definitions are evaluated when you ask for them. Circular dependencies will not
163
+ # work. Rake tasks are only created after the project is evaluated, so if you need to access
164
+ # a task (e.g. compile) use <code>project('foo').compile</code> instead of <code>task('foo:compile')</code>.
165
+ #
166
+ # For example:
167
+ # define 'myapp', :version=>'1.1' do
168
+ #
169
+ # define 'wepapp' do
170
+ # compile.with project('myapp:beans')
171
+ # package :war
172
+ # end
173
+ #
174
+ # define 'beans' do
175
+ # compile.with DEPENDS
176
+ # package :jar
177
+ # end
178
+ # end
179
+ #
180
+ # puts projects.map(&:name)
181
+ # => [ 'myapp', 'myapp:beans', 'myapp:webapp' ]
182
+ # puts project('myapp:webapp').parent.name
183
+ # => 'myapp'
184
+ # puts project('myapp:webapp').compile.classpath.map(&:to_spec)
185
+ # => 'myapp:myapp-beans:jar:1.1'
186
+ class Project < Rake::Task
187
+ module RecursiveTask
188
+ attr_accessor :project, :task_name
189
+ def invoke_prerequisites(*args)
190
+ @prerequisites |= @project.projects(:immediate => true).map {|project| project.task(@task_name)}
191
+ super
192
+ end
193
+ end
194
+
195
+ class NoSuchProject < ArgumentError
196
+ attr :name
197
+ def initialize(name)
198
+ super "No such project #{name}"
199
+ @name = name
200
+ end
201
+ end
202
+
203
+ class << self
204
+
205
+ # :call-seq:
206
+ # define(name, properties?) { |project| ... } => project
207
+ #
208
+ # See Buildr#define.
209
+ def define(name, properties, &block) #:nodoc:
210
+ # Make sure a sub-project is only defined within the parent project,
211
+ # to prevent silly mistakes that lead to inconsistencies (e.g.
212
+ # namespaces will be all out of whack).
213
+ Buildr.application.current_scope == name.split(':')[0...-1] or
214
+ raise "You can only define a sub project (#{name}) within the definition of its parent project"
215
+
216
+ @projects ||= {}
217
+ raise "You cannot define the same project (#{name}) more than once" if @projects[name]
218
+ # Projects with names like: compile, test, build are invalid, so we have
219
+ # to make sure the project has not the name of an already defined task
220
+ raise "Invalid project name: #{name.inspect} is already used for a task" if Buildr.application.lookup(name)
221
+
222
+ Project.define_task(name).tap do |project|
223
+ # Define the project to prevent duplicate definition.
224
+ @projects[name] = project
225
+ # Set the project properties first, actions may use them.
226
+ properties.each { |name, value| project.send "#{name}=", value } if properties
227
+ # Instantiate callbacks for this project, and setup to call before/after define.
228
+ # Don't cache list of callbacks, since project may add new callbacks.
229
+ project.enhance do |project|
230
+ project.send :call_callbacks, :before_define
231
+ project.enhance do |project|
232
+ project.send :call_callbacks, :after_define
233
+ end
234
+ end
235
+ project.enhance do |project|
236
+ @on_define.each { |callback| callback[project] }
237
+ end if @on_define
238
+ # Enhance the project using the definition block.
239
+ project.enhance {|project| project.instance_eval &block } if block
240
+
241
+ # Top-level project? Invoke the project definition. Sub-project? We don't invoke
242
+ # the project definiton yet (allow project calls to establish order of evaluation),
243
+ # but must do so before the parent project's definition is done.
244
+ ### project.parent.enhance { project.invoke } if project.parent
245
+ end
246
+ end
247
+
248
+ # :call-seq:
249
+ # project(name) => project
250
+ #
251
+ # See Buildr#project.
252
+ def project(*args) #:nodoc:
253
+ options = Hash === args.last ? args.pop : {}
254
+ rake_check_options options, :scope, :no_invoke if options
255
+ raise ArgumentError, 'Only one project name at a time' unless args.size == 1
256
+ @projects ||= {}
257
+ name = args.first.to_s
258
+ parent_name = name.sub(/:?[^:]*$/, '')
259
+ unless parent_name.empty?
260
+ begin
261
+ project(parent_name, options)
262
+ rescue NoSuchProject => detail
263
+ raise NoSuchProject.new(name)
264
+ end
265
+ end
266
+ if options && options[:scope]
267
+ # We assume parent project is evaluated.
268
+ project = options[:scope].to_s.split(':').inject([[]]) { |scopes, scope| scopes << (scopes.last + [scope]) }.
269
+ map { |scope| @projects[(scope + [name]).join(':')] }.
270
+ select { |project| project }.last
271
+ end
272
+ project ||= @projects[name] # Not found in scope.
273
+ raise NoSuchProject.new(name) unless project
274
+ project.invoke unless options[:no_invoke]
275
+ project
276
+ end
277
+
278
+ # :call-seq:
279
+ # projects(*names, options?) => projects
280
+ #
281
+ # options:
282
+ # :scope - name of project from which name can be relative
283
+ # :immediate - only return immediate children
284
+ # :no_invoke - do not invoke the projects. only applicable if :immediate is true
285
+ # See Buildr#projects.
286
+ def projects(*names) #:nodoc:
287
+ options = Hash === names.last ? names.pop : {}
288
+ rake_check_options options, :scope, :immediate, :no_invoke if options
289
+ @projects ||= {}
290
+ names = names.flatten
291
+ if options && options[:scope]
292
+ if names.empty?
293
+ # must invoke the parent. if the project is the one currently being invoked, then don't reinvoke
294
+ parent = options[:scope].tap{|p| p.invoke unless Thread.current[:rake_chain].instance_variable_get(:@value) == p}
295
+ projects = @projects.values.select { |project| project.parent == parent }
296
+ projects.each { |project| project.invoke } unless options[:immediate] and options[:no_invoke]
297
+ projects = projects.map { |project| [project] + projects(options.merge({:scope=>project})) }.flatten.sort_by(&:name) unless options[:immediate]
298
+ projects
299
+ else
300
+ names.uniq.map { |name| project(name, options) }
301
+ end
302
+ elsif names.empty?
303
+ # Parent project(s) not evaluated so we don't know all the projects yet.
304
+ @projects.keys.map { |name| project(name, options) or raise NoSuchProject.new(name) }.
305
+ map {|project| [project] + (options[:immediate] ? [] : project.projects(options))}.flatten.sort_by(&:name)
306
+ else
307
+ # Parent project(s) not evaluated, for the sub-projects we may need to find.
308
+ names.uniq.map { |name| project(name) or raise NoSuchProject.new(name) }.sort_by(&:name)
309
+ end
310
+ end
311
+
312
+ # :call-seq:
313
+ # clear
314
+ #
315
+ # Discard all project definitions.
316
+ def clear
317
+ @projects.clear if @projects
318
+ end
319
+
320
+ # :call-seq:
321
+ # local_task(name)
322
+ # local_task(name) { |name| ... }
323
+ #
324
+ # Defines a local task with an optional execution message.
325
+ #
326
+ # A local task is a task that executes a task with the same name, defined in the
327
+ # current project, the project's with a base directory that is the same as the
328
+ # current directory.
329
+ #
330
+ # Complicated? Try this:
331
+ # buildr build
332
+ # is the same as:
333
+ # buildr foo:build
334
+ # But:
335
+ # cd bar
336
+ # buildr build
337
+ # is the same as:
338
+ # buildr foo:bar:build
339
+ #
340
+ # The optional block is called with the project name when the task executes
341
+ # and returns a message that, for example "Building project #{name}".
342
+ def local_task(args, &block)
343
+ task args do |task|
344
+ local_projects do |project|
345
+ info block.call(project.name) if block
346
+ task("#{project.name}:#{task.name}").invoke
347
+ end
348
+ end
349
+ end
350
+
351
+ # *Deprecated* Check the Extension module to see how extensions are handled.
352
+ def on_define(&block)
353
+ Buildr.application.deprecated 'This method is deprecated, see Extension'
354
+ (@on_define ||= []) << block if block
355
+ end
356
+
357
+ def scope_name(scope, task_name) #:nodoc:
358
+ task_name
359
+ end
360
+
361
+ def local_projects(dir = nil, &block) #:nodoc:
362
+ dir = File.expand_path(dir || Buildr.application.original_dir)
363
+ projects = @projects ? @projects.values : []
364
+ projects = find_local_projects(dir, projects)
365
+ if projects.empty? && dir != Dir.pwd && File.dirname(dir) != dir
366
+ local_projects(File.dirname(dir), &block)
367
+ elsif block
368
+ if projects.empty?
369
+ warn "No projects defined for directory #{Buildr.application.original_dir}"
370
+ else
371
+ projects.each { |project| block[project] }
372
+ end
373
+ else
374
+ projects
375
+ end
376
+ end
377
+
378
+ # limitation: dir must match exactly the base dir (not a sub dir)
379
+ def find_local_projects(dir, projects)
380
+ projects = projects.select{|p| dir.index(p.base_dir) == 0}
381
+ result = projects.select {|p| p.base_dir == dir}
382
+ sub_projects = projects.map {|p| p.projects(:immediate => true, :no_invoke => true)}.flatten
383
+ result |= find_local_projects(dir, sub_projects) unless sub_projects.empty?
384
+ result
385
+ end
386
+
387
+ # :call-seq:
388
+ # parent_task(task_name) => task_name or nil
389
+ #
390
+ # Returns a parent task, basically a task in a higher namespace. For example, the parent
391
+ # of 'foo:test:compile' is 'foo:compile' and the parent of 'foo:compile' is 'compile'.
392
+ def parent_task(task_name) #:nodoc:
393
+ namespace = task_name.split(':')
394
+ last_name = namespace.pop
395
+ namespace.pop
396
+ Buildr.application.lookup((namespace + [last_name]).join(':'), []) unless namespace.empty?
397
+ end
398
+
399
+ # :call-seq:
400
+ # project_from_task(task) => project
401
+ #
402
+ # Figure out project associated to this task and return it.
403
+ def project_from_task(task) #:nodoc:
404
+ project = Buildr.application.lookup('rake:' + task.to_s.gsub(/:[^:]*$/, ''))
405
+ project if Project === project
406
+ end
407
+
408
+ # Callback classes.
409
+ def callbacks #:nodoc:
410
+ @callbacks ||= []
411
+ end
412
+
413
+ end
414
+
415
+
416
+ # Project has visibility to everything in the Buildr namespace.
417
+ include Buildr
418
+
419
+ # The project name. For example, 'foo' for the top-level project, and 'foo:bar'
420
+ # for its sub-project.
421
+ attr_reader :name
422
+
423
+ # The parent project if this is a sub-project.
424
+ attr_reader :parent
425
+
426
+ def initialize(*args) #:nodoc:
427
+ super
428
+ split = name.split(':')
429
+ if split.size > 1
430
+ # Get parent project, but do not invoke it's definition to prevent circular
431
+ # dependencies (it's being invoked right now, so calling project will fail).
432
+ @parent = task(split[0...-1].join(':'))
433
+ raise "No parent project #{split[0...-1].join(':')}" unless @parent && Project === parent
434
+ end
435
+ callbacks = Project.callbacks.uniq.map(&:new)
436
+ @callbacks = [:before_define, :after_define].inject({}) do |hash, state|
437
+ methods = callbacks.select { |callback| callback.respond_to?(state) }.map { |callback| callback.method(state) }
438
+ hash.update(state=>methods)
439
+ end
440
+ end
441
+
442
+ # :call-seq:
443
+ # base_dir => path
444
+ #
445
+ # Returns the project's base directory.
446
+ #
447
+ # The Buildfile defines top-level project, so it's logical that the top-level project's
448
+ # base directory is the one in which we find the Buildfile. And each sub-project has
449
+ # a base directory that is one level down, with the same name as the sub-project.
450
+ #
451
+ # For example:
452
+ # /home/foo/ <-- base_directory of project 'foo'
453
+ # /home/foo/Buildfile <-- builds 'foo'
454
+ # /home/foo/bar <-- sub-project 'foo:bar'
455
+ def base_dir
456
+ if @base_dir.nil?
457
+ if parent
458
+ # For sub-project, a good default is a directory in the parent's base_dir,
459
+ # using the same name as the project.
460
+ @base_dir = File.expand_path(name.split(':').last, parent.base_dir)
461
+ else
462
+ # For top-level project, a good default is the directory where we found the Buildfile.
463
+ @base_dir = Dir.pwd
464
+ end
465
+ end
466
+ @base_dir
467
+ end
468
+
469
+ # Returns the layout associated with this project.
470
+ def layout
471
+ @layout ||= (parent ? parent.layout : Layout.default).clone
472
+ end
473
+
474
+ # :call-seq:
475
+ # path_to(*names) => path
476
+ #
477
+ # Returns a path from a combination of name, relative to the project's base directory.
478
+ # Essentially, joins all the supplied names and expands the path relative to #base_dir.
479
+ # Symbol arguments are converted to paths based on the layout, so whenever possible stick
480
+ # to these. For example:
481
+ # path_to(:source, :main, :java)
482
+ # => 'src/main/java'
483
+ #
484
+ # Keep in mind that all tasks are defined and executed relative to the Buildfile directory,
485
+ # so you want to use #path_to to get the actual path within the project as a matter of practice.
486
+ #
487
+ # For example:
488
+ # path_to('foo', 'bar')
489
+ # => foo/bar
490
+ # path_to('/tmp')
491
+ # => /tmp
492
+ # path_to(:base_dir, 'foo') # same as path_to('foo")
493
+ # => /home/project1/foo
494
+ def path_to(*names)
495
+ File.expand_path(layout.expand(*names), base_dir)
496
+ end
497
+ alias :_ :path_to
498
+
499
+ # :call-seq:
500
+ # file(path) => Task
501
+ # file(path=>prereqs) => Task
502
+ # file(path) { |task| ... } => Task
503
+ #
504
+ # Creates and returns a new file task in the project. Similar to calling Rake's
505
+ # file method, but the path is expanded relative to the project's base directory,
506
+ # and the task executes in the project's base directory.
507
+ #
508
+ # For example:
509
+ # define 'foo' do
510
+ # define 'bar' do
511
+ # file('src') { ... }
512
+ # end
513
+ # end
514
+ #
515
+ # puts project('foo:bar').file('src').to_s
516
+ # => '/home/foo/bar/src'
517
+ def file(*args, &block)
518
+ task_name, arg_names, deps = Buildr.application.resolve_args(args)
519
+ task = Rake::FileTask.define_task(path_to(task_name))
520
+ task.set_arg_names(arg_names) unless arg_names.empty?
521
+ task.enhance Array(deps), &block
522
+ end
523
+
524
+ # :call-seq:
525
+ # task(name) => Task
526
+ # task(name=>prereqs) => Task
527
+ # task(name) { |task| ... } => Task
528
+ #
529
+ # Creates and returns a new task in the project. Similar to calling Rake's task
530
+ # method, but prefixes the task name with the project name and executes the task
531
+ # in the project's base directory.
532
+ #
533
+ # For example:
534
+ # define 'foo' do
535
+ # task 'doda'
536
+ # end
537
+ #
538
+ # puts project('foo').task('doda').name
539
+ # => 'foo:doda'
540
+ #
541
+ # When called from within the project definition, creates a new task if the task
542
+ # does not already exist. If called from outside the project definition, returns
543
+ # the named task and raises an exception if the task is not defined.
544
+ #
545
+ # As with Rake's task method, calling this method enhances the task with the
546
+ # prerequisites and optional block.
547
+ def task(*args, &block)
548
+ task_name, arg_names, deps = Buildr.application.resolve_args(args)
549
+ if task_name =~ /^:/
550
+ task = Buildr.application.switch_to_namespace [] do
551
+ Rake::Task.define_task(task_name[1..-1])
552
+ end
553
+ elsif Buildr.application.current_scope == name.split(':')
554
+ task = Rake::Task.define_task(task_name)
555
+ else
556
+ unless task = Buildr.application.lookup(task_name, name.split(':'))
557
+ raise "You cannot define a project task outside the project definition, and no task #{name}:#{task_name} defined in the project"
558
+ end
559
+ end
560
+ task.set_arg_names(arg_names) unless arg_names.empty?
561
+ task.enhance Array(deps), &block
562
+ end
563
+
564
+ # :call-seq:
565
+ # recursive_task(name=>prereqs) { |task| ... }
566
+ #
567
+ # Define a recursive task. A recursive task executes itself and the same task
568
+ # in all the sub-projects.
569
+ def recursive_task(*args, &block)
570
+ task_name, arg_names, deps = Buildr.application.resolve_args(args)
571
+ task = Buildr.options.parallel ? multitask(task_name) : task(task_name)
572
+ task.set_arg_names(arg_names) unless arg_names.empty?
573
+ task.enhance Array(deps), &block
574
+ task.extend RecursiveTask
575
+ task.project = self
576
+ task.task_name = task_name
577
+ end
578
+
579
+ # :call-seq:
580
+ # project(name) => project
581
+ # project => self
582
+ #
583
+ # Same as Buildr#project. This method is called on a project, so a relative name is
584
+ # sufficient to find a sub-project.
585
+ #
586
+ # When called on a project without a name, returns the project itself. You can use that when
587
+ # setting project properties, for example:
588
+ # define 'foo' do
589
+ # project.version = '1.0'
590
+ # end
591
+ def project(*args)
592
+ if Hash === args.last
593
+ options = args.pop
594
+ else
595
+ options = {}
596
+ end
597
+ if args.empty?
598
+ self
599
+ else
600
+ Project.project *(args + [{ :scope=>self }.merge(options)])
601
+ end
602
+ end
603
+
604
+ # :call-seq:
605
+ # projects(*names) => projects
606
+ #
607
+ # Same as Buildr#projects. This method is called on a project, so relative names are
608
+ # sufficient to find sub-projects.
609
+ def projects(*args)
610
+ if Hash === args.last
611
+ options = args.pop
612
+ else
613
+ options = {}
614
+ end
615
+ Project.projects *(args + [{ :scope=>self }.merge(options)])
616
+ end
617
+
618
+ def inspect #:nodoc:
619
+ %Q{project(#{name.inspect})}
620
+ end
621
+
622
+ protected
623
+
624
+ # :call-seq:
625
+ # base_dir = dir
626
+ #
627
+ # Sets the project's base directory. Allows you to specify a base directory by calling
628
+ # this accessor, or with the :base_dir property when calling #define.
629
+ #
630
+ # You can only set the base directory once for a given project, and only before accessing
631
+ # the base directory (for example, by calling #file or #path_to).
632
+ # Set the base directory. Note: you can only do this once for a project,
633
+ # and only before accessing the base directory. If you try reading the
634
+ # value with #base_dir, the base directory cannot be set again.
635
+ def base_dir=(dir)
636
+ raise 'Cannot set base directory twice, or after reading its value' if @base_dir
637
+ @base_dir = File.expand_path(dir)
638
+ end
639
+
640
+ # Sets the project layout. Accepts Layout object or class (or for that matter, anything
641
+ # that can expand).
642
+ def layout=(layout)
643
+ raise 'Cannot set directory layout twice, or after reading its value' if @layout
644
+ @layout = layout.is_a?(Class) ? layout.new : layout
645
+ end
646
+
647
+ # :call-seq:
648
+ # define(name, properties?) { |project| ... } => project
649
+ #
650
+ # Define a new sub-project within this project. See Buildr#define.
651
+ def define(name, properties = nil, &block)
652
+ Project.define "#{self.name}:#{name}", properties, &block
653
+ end
654
+
655
+ def execute(args) #:nodoc:
656
+ Buildr.application.switch_to_namespace name.split(':') do
657
+ super
658
+ end
659
+ end
660
+
661
+ # Call all callbacks for a particular state, e.g. :before_define, :after_define.
662
+ def call_callbacks(state) #:nodoc:
663
+ methods = @callbacks.delete(state) || []
664
+ methods.each { |method| method.call(project) }
665
+ end
666
+
667
+ def add_callback(callback)
668
+ @callbacks[:after_define] << callback.method(:after_define) if callback.respond_to?(:after_define)
669
+ end
670
+
671
+ end
672
+
673
+
674
+ # The basic mechanism for extending projects in Buildr are Ruby modules. In fact,
675
+ # base features like compiling and testing are all developed in the form of modules,
676
+ # and then added to the core Project class.
677
+ #
678
+ # A module defines instance methods that are then mixed into the project and become
679
+ # instance methods of the project. There are two general ways for extending projects.
680
+ # You can extend all projects by including the module in Project:
681
+ # class Project
682
+ # include MyExtension
683
+ # end
684
+ # You can also extend a given project instance and only that instance by extending
685
+ # it with the module:
686
+ # define 'foo' do
687
+ # extend MyExtension
688
+ # end
689
+ #
690
+ # Some extensions require tighter integration with the project, specifically for
691
+ # setting up tasks and properties, or for configuring tasks based on the project
692
+ # definition. You can do that by adding callbacks to the process.
693
+ #
694
+ # The easiest way to add callbacks is by incorporating the Extension module in your
695
+ # own extension, and using the various class methods to define callback behavior:
696
+ # * first_time -- This block will be called once for any particular extension.
697
+ # You can use this to setup top-level and local tasks.
698
+ # * before_define -- This block is called once for the project with the project
699
+ # instance, right before running the project definition. You can use this
700
+ # to add tasks and set properties that will be used in the project definition.
701
+ # * after_define -- This block is called once for the project with the project
702
+ # instance, right after running the project definition. You can use this to
703
+ # do any post-processing that depends on the project definition.
704
+ #
705
+ # This example illustrates how to write a simple extension:
706
+ # module LinesOfCode
707
+ # include Extension
708
+ #
709
+ # first_time do
710
+ # # Define task not specific to any projet.
711
+ # desc 'Count lines of code in current project'
712
+ # Project.local_task('loc')
713
+ # end
714
+ #
715
+ # before_define do |project|
716
+ # # Define the loc task for this particular project.
717
+ # Rake::Task.define_task 'loc' do |task|
718
+ # lines = task.prerequisites.map { |path| Dir['#{path}/**/*'] }.flatten.uniq.
719
+ # inject(0) { |total, file| total + File.readlines(file).count }
720
+ # puts "Project #{project.name} has #{lines} lines of code"
721
+ # end
722
+ # end
723
+ #
724
+ # after_define do |project|
725
+ # # Now that we know all the source directories, add them.
726
+ # task('loc'=>compile.sources + compile.test.sources)
727
+ # end
728
+ #
729
+ # # To use this method in your project:
730
+ # # loc path_1, path_2
731
+ # def loc(*paths)
732
+ # task('loc'=>paths)
733
+ # end
734
+ #
735
+ # end
736
+ #
737
+ # class Buildr::Project
738
+ # include LinesOfCode
739
+ # end
740
+ module Extension
741
+
742
+ def self.included(base) #:nodoc:
743
+ base.extend ClassMethods
744
+ end
745
+
746
+ # Methods added to the extension module when including Extension.
747
+ module ClassMethods
748
+
749
+ def included(base) #:nodoc:
750
+ # When included in Project, add callback and call first_time.
751
+ if Project == base && !base.callbacks.include?(callbacks)
752
+ base.callbacks << callbacks
753
+ callbacks.first_time if callbacks.respond_to?(:first_time)
754
+ end
755
+ end
756
+
757
+ def extended(base) #:nodoc:
758
+ # When extending project, add instance and call before_define.
759
+ if Project === base
760
+ callbacks = self.send(:callbacks).new
761
+ callbacks.before_define(base) if callbacks.respond_to?(:before_define)
762
+ base.send :add_callback, callbacks
763
+ end
764
+ end
765
+
766
+ # This block will be called once for any particular extension.
767
+ # You can use this to setup top-level and local tasks.
768
+ def first_time(&block)
769
+ meta = class << callbacks ; self ; end
770
+ meta.send :define_method, :first_time, &block
771
+ end
772
+
773
+ # This block is called once for the project with the project instance,
774
+ # right before running the project definition. You can use this to add
775
+ # tasks and set properties that will be used in the project definition.
776
+ def before_define(&block)
777
+ callbacks.send :define_method, :before_define, &block
778
+ end
779
+
780
+ # This block is called once for the project with the project instance,
781
+ # right after running the project definition. You can use this to do
782
+ # any post-processing that depends on the project definition.
783
+ def after_define(&block)
784
+ callbacks.send :define_method, :after_define, &block
785
+ end
786
+
787
+ private
788
+
789
+ def callbacks
790
+ const_get('Callbacks') rescue const_set('Callbacks', Class.new)
791
+ end
792
+
793
+ end
794
+
795
+ end
796
+
797
+
798
+ # :call-seq:
799
+ # define(name, properties?) { |project| ... } => project
800
+ #
801
+ # Defines a new project.
802
+ #
803
+ # The first argument is the project name. Each project must have a unique name.
804
+ # For a sub-project, the actual project name is created by prefixing the parent
805
+ # project's name.
806
+ #
807
+ # The second argument is optional and contains a hash or properties that are set
808
+ # on the project. You can only use properties that are supported by the project
809
+ # definition, e.g. :group and :version. You can also set these properties from the
810
+ # project definition.
811
+ #
812
+ # You pass a block that is executed in the context of the project definition.
813
+ # This block is used to define the project and tasks that are part of the project.
814
+ # Do not perform any work inside the project itself, as it will execute each time
815
+ # the Buildfile is loaded. Instead, use it to create and extend tasks that are
816
+ # related to the project.
817
+ #
818
+ # For example:
819
+ # define 'foo', :version=>'1.0' do
820
+ #
821
+ # define 'bar' do
822
+ # compile.with 'org.apache.axis2:axis2:jar:1.1'
823
+ # end
824
+ # end
825
+ #
826
+ # puts project('foo').version
827
+ # => '1.0'
828
+ # puts project('foo:bar').compile.classpath.map(&:to_spec)
829
+ # => 'org.apache.axis2:axis2:jar:1.1'
830
+ # % buildr build
831
+ # => Compiling 14 source files in foo:bar
832
+ def define(name, properties = nil, &block) #:yields:project
833
+ Project.define(name, properties, &block)
834
+ end
835
+
836
+ # :call-seq:
837
+ # project(name) => project
838
+ #
839
+ # Returns a project definition.
840
+ #
841
+ # When called from outside a project definition, must reference the project by its
842
+ # full name, e.g. 'foo:bar' to access the sub-project 'bar' in 'foo'. When called
843
+ # from inside a project, relative names are sufficient, e.g. <code>project('foo').project('bar')</code>
844
+ # will find the sub-project 'bar' in 'foo'.
845
+ #
846
+ # You cannot reference a project before the project is defined. When working with
847
+ # sub-projects, the project definition is stored by calling #define, and evaluated
848
+ # before a call to the parent project's #define method returns.
849
+ #
850
+ # However, if you call #project with the name of another sub-project, its definition
851
+ # is evaluated immediately. So the returned project definition is always complete,
852
+ # and you can access its definition (e.g. to find files relative to the base directory,
853
+ # or packages created by that project).
854
+ #
855
+ # For example:
856
+ # define 'myapp' do
857
+ # self.version = '1.1'
858
+ #
859
+ # define 'webapp' do
860
+ # # webapp is defined first, but beans is evaluated first
861
+ # compile.with project('beans')
862
+ # package :war
863
+ # end
864
+ #
865
+ # define 'beans' do
866
+ # package :jar
867
+ # end
868
+ # end
869
+ #
870
+ # puts project('myapp:beans').version
871
+ def project(*args)
872
+ Project.project *args
873
+ end
874
+
875
+ # :call-seq:
876
+ # projects(*names) => projects
877
+ #
878
+ # With no arguments, returns a list of all projects defined so far. When called on a project,
879
+ # returns all its sub-projects (direct descendants).
880
+ #
881
+ # With arguments, returns a list of named projects, fails on any name that does not exist.
882
+ # As with #project, you can use relative names when calling this method on a project.
883
+ #
884
+ # Like #project, this method evaluates the definition of each project before returning it.
885
+ # Be advised of circular dependencies.
886
+ #
887
+ # For example:
888
+ # files = projects.map { |prj| FileList[prj.path_to('src/**/*.java') }.flatten
889
+ # puts "There are #{files.size} source files in #{projects.size} projects"
890
+ #
891
+ # puts projects('myapp:beans', 'myapp:webapp').map(&:name)
892
+ # Same as:
893
+ # puts project('myapp').projects.map(&:name)
894
+ def projects(*args)
895
+ Project.projects *args
896
+ end
897
+
898
+ # Forces all the projects to be evaluated before executing any other task.
899
+ # If we don't do that, we don't get to have tasks available when running Rake.
900
+ namespace 'buildr' do
901
+
902
+ desc "Freeze the Buildfile so it always uses Buildr version #{Buildr::VERSION}"
903
+ task 'freeze' do
904
+ puts "Freezing the Buildfile so it always uses Buildr version #{Buildr::VERSION}"
905
+ original = File.read(Buildr.application.buildfile)
906
+ if original =~ /gem\s*(["'])buildr\1/
907
+ modified = original.sub(/gem\s*(["'])buildr\1\s*,\s*(["']).*\2/, %{gem "buildr", "#{Buildr::VERSION}"})
908
+ else
909
+ modified = %{gem "buildr", "#{Buildr::VERSION}"\n} + original
910
+ end
911
+ File.open(Buildr.application.buildfile, "w") { |file| file.write modified }
912
+ end
913
+
914
+ desc 'Unfreeze the Buildfile to use the latest version of Buildr'
915
+ task 'unfreeze' do
916
+ puts 'Unfreezing the Buildfile to use the latest version of Buildr from your Gems repository.'
917
+ modified = File.read(Buildr.application.buildfile).sub(/^\s*gem\s*(["'])buildr\1.*\n/, "")
918
+ File.open(Buildr.application.buildfile, "w") { |file| file.write modified }
919
+ end
920
+ end
921
+
922
+
923
+ end