mguymon-buildr 1.4.5-java

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