Class: Buildr::Project
- Inherits:
-
Rake::Task
- Object
- Rake::Task
- Buildr::Project
- Includes:
- Buildr, Ant, Apt, Build, Checks, Compile, Eclipse, Idea, Idea7x, Javadoc, Package, PackageAsGem, Buildr::Packaging::Java, Test, CoberturaExtension, EmmaExtension
- Defined in:
- lib/buildr/ide/idea7x.rb,
lib/buildr/ide/idea.rb,
lib/buildr/java/ant.rb,
lib/buildr/core/test.rb,
lib/buildr/java/emma.rb,
lib/buildr/core/build.rb,
lib/buildr/core/checks.rb,
lib/buildr/ide/eclipse.rb,
lib/buildr/core/compile.rb,
lib/buildr/core/project.rb,
lib/buildr/java/compiler.rb,
lib/buildr/java/cobertura.rb,
lib/buildr/java/packaging.rb,
lib/buildr/packaging/gems.rb,
lib/buildr/packaging/package.rb
Overview
A project definition is where you define all the tasks associated with the project you’re building.
The project itself will define several life cycle tasks for you. For example, it automatically creates a compile task that will compile all the source files found in src/main/java into target/classes, a test task that will compile source files from src/test/java and run all the JUnit tests found there, and a build task to compile and then run the tests.
You use the project definition to enhance these tasks, for example, telling the compile task which class path dependencies to use. Or telling the project how to package an artifact, e.g. creating a JAR using package :jar.
You can also define additional tasks that are executed by project tasks, or invoked from rake.
Tasks created by the project are all prefixed with the project name, e.g. the project foo creates the task foo:compile. If foo contains a sub-project bar, the later will define the task foo:bar:compile. Since the compile task is recursive, compiling foo will also compile foo:bar.
If you run:
buildr compile
from the command line, it will execute the compile task of the current project.
Projects and sub-projects follow a directory heirarchy. The Buildfile is assumed to reside in the same directory as the top-level project, and each sub-project is contained in a sub-directory in the same name. For example:
/home/foo
|__ Buildfile
|__ src/main/java
|__ foo
|__ src/main/java
The default structure of each project is assumed to be:
src
|__main
| |__java <-- Source files to compile
| |__resources <-- Resources to copy
| |__webapp <-- For WARs
|__test
| |__java <-- Source files to compile (tests)
| |__resources <-- Resources to copy (tests)
|__target <-- Packages created here
| |__classes <-- Generated when compiling
| |__resources <-- Copied (and filtered) from resources
| |__test/classes <-- Generated when compiling tests
| |__test/resources <-- Copied (and filtered) from resources
|__reports <-- Test, coverage and other reports
You can change the project layout by passing a new Layout to the project definition.
You can only define a project once using #define. Afterwards, you can obtain the project definition using #project. The order in which you define projects is not important, project definitions are evaluated when you ask for them. Circular dependencies will not work. Rake tasks are only created after the project is evaluated, so if you need to access a task (e.g. compile) use project('foo').compile instead of task('foo:compile').
For example:
define 'myapp', :version=>'1.1' do
define 'wepapp' do
compile.with project('myapp:beans')
package :war
end
define 'beans' do
compile.with DEPENDS
package :jar
end
end
puts projects.map(&:name)
=> [ 'myapp', 'myapp:beans', 'myapp:webapp' ]
puts project('myapp:webapp').parent.name
=> 'myapp'
puts project('myapp:webapp').compile.classpath.map(&:to_spec)
=> 'myapp:myapp-beans:jar:1.1'
Defined Under Namespace
Modules: RecursiveTask Classes: NoSuchProject
Constant Summary
Constants included from Buildr
ScalaCheck, ScalaSpecs, ScalaTest, VERSION
Constants included from Ant
Constants included from Idea7x
Idea7x::CLASSIFIER, Idea7x::FILE_PATH_PREFIX, Idea7x::IML_SUFFIX, Idea7x::IPR_TEMPLATE, Idea7x::MODULE_DIR, Idea7x::MODULE_DIR_URL, Idea7x::PROJECT_DIR, Idea7x::PROJECT_DIR_URL
Instance Attribute Summary collapse
-
#name ⇒ Object
readonly
The project name.
-
#parent ⇒ Object
readonly
The parent project if this is a sub-project.
Attributes included from Package
Attributes included from Buildr::Packaging::Java
Class Method Summary collapse
-
.callbacks ⇒ Object
Callback classes.
-
.clear ⇒ Object
:call-seq: clear.
-
.define(name, properties, &block) ⇒ Object
:call-seq: define(name, properties?) { |project| … } => project.
-
.find_local_projects(dir, projects) ⇒ Object
limitation: dir must match exactly the base dir (not a sub dir).
-
.local_projects(dir = nil, &block) ⇒ Object
:nodoc:.
-
.local_task(args, &block) ⇒ Object
:call-seq: local_task(name) local_task(name) { |name| … }.
-
.on_define(&block) ⇒ Object
Deprecated Check the Extension module to see how extensions are handled.
-
.parent_task(task_name) ⇒ Object
:call-seq: parent_task(task_name) => task_name or nil.
-
.project(*args) ⇒ Object
:call-seq: project(name) => project.
-
.project_from_task(task) ⇒ Object
:call-seq: project_from_task(task) => project.
-
.projects(*names) ⇒ Object
:call-seq: projects(*names, options?) => projects.
-
.scope_name(scope, task_name) ⇒ Object
:nodoc:.
Instance Method Summary collapse
-
#base_dir ⇒ Object
:call-seq: base_dir => path.
-
#file(*args, &block) ⇒ Object
:call-seq: file(path) => Task file(path=>prereqs) => Task file(path) { |task| … } => Task.
-
#initialize(*args) ⇒ Project
constructor
:nodoc:.
-
#inspect ⇒ Object
:nodoc:.
-
#layout ⇒ Object
Returns the layout associated with this project.
-
#path_to(*names) ⇒ Object
(also: #_)
:call-seq: path_to(*names) => path.
-
#project(*args) ⇒ Object
:call-seq: project(name) => project project => self.
-
#projects(*args) ⇒ Object
:call-seq: projects(*names) => projects.
-
#recursive_task(*args, &block) ⇒ Object
:call-seq: recursive_task(name=>prereqs) { |task| … }.
-
#task(*args, &block) ⇒ Object
:call-seq: task(name) => Task task(name=>prereqs) => Task task(name) { |task| … } => Task.
Methods included from Package
Methods included from Extension
Methods included from PackageAsGem
Methods included from Buildr::Packaging::Java
#package_with_javadoc, #package_with_sources
Methods included from Apt
Methods included from Javadoc
Methods included from Buildr
application, application=, #artifact, #artifact_ns, #artifacts, #concat, #download, environment, #filter, #group, #help, help, #install, #integration, options, #options, #read, #repositories, settings, #struct, #transitive, #unzip, #upload, #write, #zip
Methods included from Ant
Methods included from Compile
Methods included from Checks
Methods included from Idea7x
generate_compile_output, generate_content, generate_ipr, generate_module_libs, generate_order_entries
Methods included from Build
#build, #clean, #reports, #reports=, #target, #target=
Methods included from Test
Methods inherited from Rake::Task
#invoke, #invoke_with_call_chain
Constructor Details
#initialize(*args) ⇒ Project
:nodoc:
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 |
# File 'lib/buildr/core/project.rb', line 426 def initialize(*args) #:nodoc: super split = name.split(':') if split.size > 1 # Get parent project, but do not invoke it's definition to prevent circular # dependencies (it's being invoked right now, so calling project will fail). @parent = task(split[0...-1].join(':')) raise "No parent project #{split[0...-1].join(':')}" unless @parent && Project === parent end callbacks = Project.callbacks.uniq.map(&:new) @callbacks = [:before_define, :after_define].inject({}) do |hash, state| methods = callbacks.select { |callback| callback.respond_to?(state) }.map { |callback| callback.method(state) } hash.update(state=>methods) end end |
Instance Attribute Details
#name ⇒ Object (readonly)
The project name. For example, ‘foo’ for the top-level project, and ‘foo:bar’ for its sub-project.
421 422 423 |
# File 'lib/buildr/core/project.rb', line 421 def name @name end |
#parent ⇒ Object (readonly)
The parent project if this is a sub-project.
424 425 426 |
# File 'lib/buildr/core/project.rb', line 424 def parent @parent end |
Class Method Details
.callbacks ⇒ Object
Callback classes.
409 410 411 |
# File 'lib/buildr/core/project.rb', line 409 def callbacks #:nodoc: @callbacks ||= [] end |
.clear ⇒ Object
:call-seq:
clear
Discard all project definitions.
316 317 318 |
# File 'lib/buildr/core/project.rb', line 316 def clear @projects.clear if @projects end |
.define(name, properties, &block) ⇒ Object
:call-seq:
define(name, properties?) { |project| ... } => project
See Buildr#define.
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/buildr/core/project.rb', line 209 def define(name, properties, &block) #:nodoc: # Make sure a sub-project is only defined within the parent project, # to prevent silly mistakes that lead to inconsistencies (e.g. # namespaces will be all out of whack). Buildr.application.current_scope == name.split(':')[0...-1] or raise "You can only define a sub project (#{name}) within the definition of its parent project" @projects ||= {} raise "You cannot define the same project (#{name}) more than once" if @projects[name] # Projects with names like: compile, test, build are invalid, so we have # to make sure the project has not the name of an already defined task raise "Invalid project name: #{name.inspect} is already used for a task" if Buildr.application.lookup(name) Project.define_task(name).tap do |project| # Define the project to prevent duplicate definition. @projects[name] = project # Set the project properties first, actions may use them. properties.each { |name, value| project.send "#{name}=", value } if properties # Instantiate callbacks for this project, and setup to call before/after define. # Don't cache list of callbacks, since project may add new callbacks. project.enhance do |project| project.send :call_callbacks, :before_define project.enhance do |project| project.send :call_callbacks, :after_define end end project.enhance do |project| @on_define.each { |callback| callback[project] } end if @on_define # Enhance the project using the definition block. project.enhance {|project| project.instance_eval &block } if block # Top-level project? Invoke the project definition. Sub-project? We don't invoke # the project definiton yet (allow project calls to establish order of evaluation), # but must do so before the parent project's definition is done. ### project.parent.enhance { project.invoke } if project.parent end end |
.find_local_projects(dir, projects) ⇒ Object
limitation: dir must match exactly the base dir (not a sub dir)
379 380 381 382 383 384 385 |
# File 'lib/buildr/core/project.rb', line 379 def find_local_projects(dir, projects) projects = projects.select{|p| dir.index(p.base_dir) == 0} result = projects.select {|p| p.base_dir == dir} sub_projects = projects.map {|p| p.projects(:immediate => true, :no_invoke => true)}.flatten result |= find_local_projects(dir, sub_projects) unless sub_projects.empty? result end |
.local_projects(dir = nil, &block) ⇒ Object
:nodoc:
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 |
# File 'lib/buildr/core/project.rb', line 361 def local_projects(dir = nil, &block) #:nodoc: dir = File.(dir || Buildr.application.original_dir) projects = @projects ? @projects.values : [] projects = find_local_projects(dir, projects) if projects.empty? && dir != Dir.pwd && File.dirname(dir) != dir local_projects(File.dirname(dir), &block) elsif block if projects.empty? warn "No projects defined for directory #{Buildr.application.original_dir}" else projects.each { |project| block[project] } end else projects end end |
.local_task(args, &block) ⇒ Object
:call-seq:
local_task(name)
local_task(name) { |name| ... }
Defines a local task with an optional execution message.
A local task is a task that executes a task with the same name, defined in the current project, the project’s with a base directory that is the same as the current directory.
Complicated? Try this:
buildr build
is the same as:
buildr foo:build
But:
cd
buildr build
is the same as:
buildr foo:bar:build
The optional block is called with the project name when the task executes and returns a message that, for example “Building project ##name”.
342 343 344 345 346 347 348 349 |
# File 'lib/buildr/core/project.rb', line 342 def local_task(args, &block) task args do |task| local_projects do |project| info block.call(project.name) if block task("#{project.name}:#{task.name}").invoke end end end |
.on_define(&block) ⇒ Object
Deprecated Check the Extension module to see how extensions are handled.
352 353 354 355 |
# File 'lib/buildr/core/project.rb', line 352 def on_define(&block) Buildr.application.deprecated 'This method is deprecated, see Extension' (@on_define ||= []) << block if block end |
.parent_task(task_name) ⇒ Object
:call-seq:
parent_task(task_name) => task_name or nil
Returns a parent task, basically a task in a higher namespace. For example, the parent of ‘foo:test:compile’ is ‘foo:compile’ and the parent of ‘foo:compile’ is ‘compile’.
392 393 394 395 396 397 |
# File 'lib/buildr/core/project.rb', line 392 def parent_task(task_name) #:nodoc: namespace = task_name.split(':') last_name = namespace.pop namespace.pop Buildr.application.lookup((namespace + [last_name]).join(':'), []) unless namespace.empty? end |
.project(*args) ⇒ Object
:call-seq:
project(name) => project
See Buildr#project.
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
# File 'lib/buildr/core/project.rb', line 252 def project(*args) #:nodoc: = Hash === args.last ? args.pop : {} , :scope, :no_invoke if raise ArgumentError, 'Only one project name at a time' unless args.size == 1 @projects ||= {} name = args.first.to_s parent_name = name.sub(/:?[^:]*$/, '') unless parent_name.empty? begin project(parent_name, ) rescue NoSuchProject => detail raise NoSuchProject.new(name) end end if && [:scope] # We assume parent project is evaluated. project = [:scope].to_s.split(':').inject([[]]) { |scopes, scope| scopes << (scopes.last + [scope]) }. map { |scope| @projects[(scope + [name]).join(':')] }. select { |project| project }.last end project ||= @projects[name] # Not found in scope. raise NoSuchProject.new(name) unless project project.invoke unless [:no_invoke] project end |
.project_from_task(task) ⇒ Object
:call-seq:
project_from_task(task) => project
Figure out project associated to this task and return it.
403 404 405 406 |
# File 'lib/buildr/core/project.rb', line 403 def project_from_task(task) #:nodoc: project = Buildr.application.lookup('rake:' + task.to_s.gsub(/:[^:]*$/, '')) project if Project === project end |
.projects(*names) ⇒ Object
:call-seq:
projects(*names, ) => projects
options:
:scope - name of project from which name can be relative
:immediate - only return immediate children
:no_invoke - do not invoke the projects. only applicable if :immediate is true
See Buildr#projects.
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
# File 'lib/buildr/core/project.rb', line 286 def projects(*names) #:nodoc: = Hash === names.last ? names.pop : {} , :scope, :immediate, :no_invoke if @projects ||= {} names = names.flatten if && [:scope] if names.empty? # must invoke the parent. if the project is the one currently being invoked, then don't reinvoke parent = [:scope].tap{|p| p.invoke unless Thread.current[:rake_chain].instance_variable_get(:@value) == p} projects = @projects.values.select { |project| project.parent == parent } projects.each { |project| project.invoke } unless [:immediate] and [:no_invoke] projects = projects.map { |project| [project] + projects(.merge({:scope=>project})) }.flatten.sort_by(&:name) unless [:immediate] projects else names.uniq.map { |name| project(name, ) } end elsif names.empty? # Parent project(s) not evaluated so we don't know all the projects yet. @projects.keys.map { |name| project(name, ) or raise NoSuchProject.new(name) }. map {|project| [project] + ([:immediate] ? [] : project.projects())}.flatten.sort_by(&:name) else # Parent project(s) not evaluated, for the sub-projects we may need to find. names.uniq.map { |name| project(name) or raise NoSuchProject.new(name) }.sort_by(&:name) end end |
.scope_name(scope, task_name) ⇒ Object
:nodoc:
357 358 359 |
# File 'lib/buildr/core/project.rb', line 357 def scope_name(scope, task_name) #:nodoc: task_name end |
Instance Method Details
#base_dir ⇒ Object
:call-seq:
base_dir => path
Returns the project’s base directory.
The Buildfile defines top-level project, so it’s logical that the top-level project’s base directory is the one in which we find the Buildfile. And each sub-project has a base directory that is one level down, with the same name as the sub-project.
For example:
/home/foo/ <-- base_directory of project 'foo'
/home/foo/Buildfile <-- builds 'foo'
/home/foo/ <-- sub-project 'foo:bar'
455 456 457 458 459 460 461 462 463 464 465 466 467 |
# File 'lib/buildr/core/project.rb', line 455 def base_dir if @base_dir.nil? if parent # For sub-project, a good default is a directory in the parent's base_dir, # using the same name as the project. @base_dir = File.(name.split(':').last, parent.base_dir) else # For top-level project, a good default is the directory where we found the Buildfile. @base_dir = Dir.pwd end end @base_dir end |
#file(*args, &block) ⇒ Object
:call-seq:
file(path) => Task
file(path=>prereqs) => Task
file(path) { |task| ... } => Task
Creates and returns a new file task in the project. Similar to calling Rake’s file method, but the path is expanded relative to the project’s base directory, and the task executes in the project’s base directory.
For example:
define 'foo' do
define 'bar' do
file('src') { ... }
end
end
puts project('foo:bar').file('src').to_s
=> '/home/foo/bar/src'
517 518 519 520 521 522 |
# File 'lib/buildr/core/project.rb', line 517 def file(*args, &block) task_name, arg_names, deps = Buildr.application.resolve_args(args) task = Rake::FileTask.define_task(path_to(task_name)) task.set_arg_names(arg_names) unless arg_names.empty? task.enhance Array(deps), &block end |
#inspect ⇒ Object
:nodoc:
618 619 620 |
# File 'lib/buildr/core/project.rb', line 618 def inspect #:nodoc: %Q{project(#{name.inspect})} end |
#layout ⇒ Object
Returns the layout associated with this project.
470 471 472 |
# File 'lib/buildr/core/project.rb', line 470 def layout @layout ||= (parent ? parent.layout : Layout.default).clone end |
#path_to(*names) ⇒ Object Also known as: _
:call-seq:
path_to(*names) => path
Returns a path from a combination of name, relative to the project’s base directory. Essentially, joins all the supplied names and expands the path relative to #base_dir. Symbol arguments are converted to paths based on the layout, so whenever possible stick to these. For example:
path_to(:source, :main, :java)
=> 'src/main/java'
Keep in mind that all tasks are defined and executed relative to the Buildfile directory, so you want to use #path_to to get the actual path within the project as a matter of practice.
For example:
path_to('foo', 'bar')
=> foo/
path_to('/tmp')
=> /tmp
path_to(:base_dir, 'foo') # same as path_to('foo")
=> /home/project1/foo
494 495 496 |
# File 'lib/buildr/core/project.rb', line 494 def path_to(*names) File.(layout.(*names), base_dir) end |
#project(*args) ⇒ Object
:call-seq:
project(name) => project
project => self
Same as Buildr#project. This method is called on a project, so a relative name is sufficient to find a sub-project.
When called on a project without a name, returns the project itself. You can use that when setting project properties, for example:
define 'foo' do
project.version = '1.0'
end
591 592 593 594 595 596 597 598 599 600 601 602 |
# File 'lib/buildr/core/project.rb', line 591 def project(*args) if Hash === args.last = args.pop else = {} end if args.empty? self else Project.project *(args + [{ :scope=>self }.merge()]) end end |
#projects(*args) ⇒ Object
:call-seq:
projects(*names) => projects
Same as Buildr#projects. This method is called on a project, so relative names are sufficient to find sub-projects.
609 610 611 612 613 614 615 616 |
# File 'lib/buildr/core/project.rb', line 609 def projects(*args) if Hash === args.last = args.pop else = {} end Project.projects *(args + [{ :scope=>self }.merge()]) end |
#recursive_task(*args, &block) ⇒ Object
:call-seq:
recursive_task(name=>prereqs) { |task| ... }
Define a recursive task. A recursive task executes itself and the same task in all the sub-projects.
569 570 571 572 573 574 575 576 577 |
# File 'lib/buildr/core/project.rb', line 569 def recursive_task(*args, &block) task_name, arg_names, deps = Buildr.application.resolve_args(args) task = Buildr..parallel ? multitask(task_name) : task(task_name) task.set_arg_names(arg_names) unless arg_names.empty? task.enhance Array(deps), &block task.extend RecursiveTask task.project = self task.task_name = task_name end |
#task(*args, &block) ⇒ Object
:call-seq:
task(name) => Task
task(name=>prereqs) => Task
task(name) { |task| ... } => Task
Creates and returns a new task in the project. Similar to calling Rake’s task method, but prefixes the task name with the project name and executes the task in the project’s base directory.
For example:
define 'foo' do
task 'doda'
end
puts project('foo').task('doda').name
=> 'foo:doda'
When called from within the project definition, creates a new task if the task does not already exist. If called from outside the project definition, returns the named task and raises an exception if the task is not defined.
As with Rake’s task method, calling this method enhances the task with the prerequisites and optional block.
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 |
# File 'lib/buildr/core/project.rb', line 547 def task(*args, &block) task_name, arg_names, deps = Buildr.application.resolve_args(args) if task_name =~ /^:/ task = Buildr.application.switch_to_namespace [] do Rake::Task.define_task(task_name[1..-1]) end elsif Buildr.application.current_scope == name.split(':') task = Rake::Task.define_task(task_name) else unless task = Buildr.application.lookup(task_name, name.split(':')) raise "You cannot define a project task outside the project definition, and no task #{name}:#{task_name} defined in the project" end end task.set_arg_names(arg_names) unless arg_names.empty? task.enhance Array(deps), &block end |