Class: Buildr::Project

Inherits:
Rake::Task show all
Includes:
Buildr, Ant, Apt, Assets::ProjectExtension, Build, CC, CPom::ProjectExtension, Checks, Compile, Doc, Eclipse, Eclipse::Java, Eclipse::Plugin, Eclipse::Scala, IntellijIdea::ProjectExtension, Kotlin::ProjectExtension, Package, PackageAsGem, PackageAsTestJar, Buildr::Packaging::Java, Buildr::Packaging::Scala, Run, Scala::ProjectExtension, Shell, Test, CoberturaExtension, EmmaExtension, GroovydocDefaults, JavadocDefaults, ScaladocDefaults
Defined in:
lib/buildr/shell.rb,
lib/buildr/run.rb,
lib/buildr/core/cc.rb,
lib/buildr/core/doc.rb,
lib/buildr/ide/idea.rb,
lib/buildr/java/ant.rb,
lib/buildr/java/doc.rb,
lib/buildr/core/test.rb,
lib/buildr/java/emma.rb,
lib/buildr/scala/doc.rb,
lib/buildr/core/build.rb,
lib/buildr/groovy/doc.rb,
lib/buildr/core/assets.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/scala/compiler.rb,
lib/buildr/java/custom_pom.rb,
lib/buildr/kotlin/compiler.rb,
lib/buildr/packaging/package.rb,
lib/buildr/packaging/test_jar.rb

Overview

:nodoc:

Constant Summary

Constants included from Buildr

VERSION

Constants included from Ant

Ant::VERSION

Constants included from Eclipse::Java

Eclipse::Java::BUILDER, Eclipse::Java::CONTAINER, Eclipse::Java::NATURE

Constants included from Eclipse::Scala

Eclipse::Scala::BUILDER, Eclipse::Scala::CONTAINER, Eclipse::Scala::NATURE

Constants included from Eclipse::Plugin

Eclipse::Plugin::BUILDERS, Eclipse::Plugin::CONTAINER, Eclipse::Plugin::NATURE

Instance Attribute Summary collapse

Attributes included from Package

#group, #version

Attributes included from Buildr::Packaging::Java

#manifest, #meta_inf

Class Method Summary collapse

Instance Method Summary collapse

Methods included from PackageAsTestJar

#package_as_test_jar, #package_as_test_jar_spec

Methods included from Package

#id, #package, #package_as_sources, #package_as_sources_spec, #package_as_tar, #package_as_zip, #packages

Methods included from Extension

included

Methods included from Kotlin::ProjectExtension

#kotlinc_options

Methods included from CPom::ProjectExtension

#pom

Methods included from Scala::ProjectExtension

#scalac_options

Methods included from PackageAsGem

#package_as_gem

Methods included from Buildr::Packaging::Java

#package_as_aar, #package_as_ear, #package_as_jar, #package_as_javadoc, #package_as_javadoc_spec, #package_as_war, #package_with_javadoc, #package_with_sources

Methods included from Apt

#apt

Methods included from Buildr

application, application=, #artifact, #artifact_ns, #artifacts, #concat, #download, ensure_rspec, environment, #filter, #group, #help, help, #install, #integration, options, #options, #read, #repositories, rspec_present?, settings, #struct, #transitive, #unzip, #upload, #write, #zip

Methods included from Ant

#ant, dependencies, version

Methods included from Compile

#compile, #resources

Methods included from Eclipse

#eclipse

Methods included from Checks

#check, #expectations

Methods included from Assets::ProjectExtension

#assets

Methods included from Build

#build, #clean

Methods included from Buildr::Packaging::Scala

#package_as_scaladoc, #package_as_scaladoc_spec

Methods included from Test

#integration, #test

Methods included from IntellijIdea::ProjectExtension

#iml, #iml?, #ipr, #ipr?, #no_iml, #no_ipr

Methods included from Doc

#doc, engines, #javadoc, select_by_lang, select_by_name

Methods included from CC

#cc

Methods included from Shell

define_task, providers, select_by_lang, select_by_name, #shell

Methods included from Run

#run, runners, select_by_lang, select_by_name

Methods inherited from Rake::Task

#invoke, #invoke_with_call_chain

Constructor Details

#initialize(*args) ⇒ Project

:nodoc:



404
405
406
407
408
409
410
411
412
413
414
415
# File 'lib/buildr/core/project.rb', line 404

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
  # Inherit all global callbacks
  @callbacks = Project.global_callbacks.dup
end

Instance Attribute Details

#nameObject (readonly)

The project name. For example, ‘foo’ for the top-level project, and ‘foo:bar’ for its sub-project.



399
400
401
# File 'lib/buildr/core/project.rb', line 399

def name
  @name
end

#parentObject (readonly)

The parent project if this is a sub-project.



402
403
404
# File 'lib/buildr/core/project.rb', line 402

def parent
  @parent
end

Class Method Details

.clearObject

:call-seq:

clear

Discard all project definitions.



298
299
300
# File 'lib/buildr/core/project.rb', line 298

def clear
  @projects.clear if @projects
end

.define(name, properties, &block) ⇒ Object

:call-seq:

define(name, properties?) { |project| ... } => project

See Buildr#define.



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/buildr/core/project.rb', line 191

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
    # Setup to call before/after define extension callbacks
    # Don't cache list of extensions, since project may add new extensions.
    project.enhance do |project|
      project.send :call_callbacks, :before_define
      project.enhance do |project|
        project.send :call_callbacks, :after_define
      end
    end
    # Enhance the project using the definition block.
    project.enhance { project.instance_exec project, &block } if block

    # Mark the project as defined
    project.enhance do |project|
      project.send :define!
    end

    # 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

.extension_modulesObject

Loaded extension modules.



383
384
385
# File 'lib/buildr/core/project.rb', line 383

def extension_modules #:nodoc:
  @extension_modules ||= []
end

.global_callbacksObject

Extension callbacks that apply to all projects



388
389
390
# File 'lib/buildr/core/project.rb', line 388

def global_callbacks #:nodoc:
  @global_callbacks ||= []
end

.local_projects(dir = nil, &block) ⇒ Object

:nodoc:



344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
# File 'lib/buildr/core/project.rb', line 344

def local_projects(dir = nil, &block) #:nodoc:
  dir = File.expand_path(dir || Buildr.application.original_dir)
  projects = @projects ? @projects.values : []
  projects = projects.select { |project| project.base_dir == dir }
  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 bar
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”.



324
325
326
327
328
329
330
331
332
# File 'lib/buildr/core/project.rb', line 324

def local_task(*args, &block)
  task *args do |task, args|
    args = task.arg_names.map {|n| args[n]}
    local_projects do |project|
      info block.call(project.name) if block
      task("#{project.name}:#{task.name}").invoke *args
    end
  end
end

.on_define(&block) ⇒ Object

Deprecated Check the Extension module to see how extensions are handled.



335
336
337
338
# File 'lib/buildr/core/project.rb', line 335

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’.



366
367
368
369
370
371
# File 'lib/buildr/core/project.rb', line 366

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, &block) ⇒ Object

:call-seq:

project(name) => project

See Buildr#project.

Raises:

  • (ArgumentError)


236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/buildr/core/project.rb', line 236

def project(*args, &block) #:nodoc:
  options = args.pop if Hash === args.last
  return define(args.first, options, &block) if block
  rake_check_options options, :scope, :no_invoke if options
  no_invoke = options && options[:no_invoke]

  raise ArgumentError, 'Only one project name at a time' unless args.size == 1
  @projects ||= {}
  name = args.first.to_s
  # Make sure parent project is evaluated (e.g. if looking for foo:bar, find foo first)
  unless @projects[name]
    parts = name.split(':')
    project(parts.first, options || {}) if parts.size > 1
  end
  if options && options[:scope]
    # We assume parent project is evaluated.
    project = options[:scope].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 "No such project #{name}" unless project
  project.invoke unless  project.defined? || no_invoke || Buildr.application.current_scope.join(":").to_s == project.name.to_s
  project
end

.project_from_task(task) ⇒ Object

:call-seq:

project_from_task(task) => project

Figure out project associated to this task and return it.



377
378
379
380
# File 'lib/buildr/core/project.rb', line 377

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

See Buildr#projects.



266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/buildr/core/project.rb', line 266

def projects(*names) #:nodoc:
  options = names.pop if Hash === names.last
  rake_check_options options, :scope, :no_invoke if options

  no_invoke = options && options[:no_invoke]

  @projects ||= {}
  names = names.flatten
  if options && options[:scope]
    # We assume parent project is evaluated.
    if names.empty?
      parent = @projects[options[:scope].to_s] or raise "No such project #{options[:scope]}"
      @projects.values.select { |project| project.parent == parent }.each { |project| project.invoke unless no_invoke }.
        map { |project| [project] + projects(:scope => project, :no_invoke => no_invoke) }.flatten.sort_by(&:name)
    else
      names.uniq.map { |name| project(name, :scope => options[:scope], :no_invoke => no_invoke) }
    end
  elsif names.empty?
    # Parent project(s) not evaluated so we don't know all the projects yet.
    @projects.values.each { |project| project.invoke unless no_invoke }
    @projects.keys.map { |name| project(name, :no_invoke => no_invoke) or raise "No such project #{name}" }.sort_by(&:name)
  else
    # Parent project(s) not evaluated, for the sub-projects we may need to find.
    names.map { |name| name.split(':') }.select { |name| name.size > 1 }.map(&:first).uniq.each { |name| project(name, :no_invoke => no_invoke) }
    names.uniq.map { |name| project(name, :no_invoke => no_invoke) or raise "No such project #{name}" }.sort_by(&:name)
  end
end

.scope_name(scope, task_name) ⇒ Object

:nodoc:



340
341
342
# File 'lib/buildr/core/project.rb', line 340

def scope_name(scope, task_name) #:nodoc:
  task_name
end

Instance Method Details

#base_dirObject

: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/bar       <-- sub-project 'foo:bar'


444
445
446
447
448
449
450
451
452
453
454
455
456
# File 'lib/buildr/core/project.rb', line 444

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.expand_path(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

#callbacksObject

:nodoc:



609
610
611
612
# File 'lib/buildr/core/project.rb', line 609

def callbacks #:nodoc:
  # global + project_local callbacks for this project
  @callbacks ||= []
end

#calledbackObject

:nodoc:



614
615
616
617
# File 'lib/buildr/core/project.rb', line 614

def calledback #:nodoc:
  # project-local callbacks that have been called
  @calledback ||= {}
end

#defined?Boolean

Returns:

  • (Boolean)


619
620
621
# File 'lib/buildr/core/project.rb', line 619

def defined?
  @defined
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'


506
507
508
509
510
511
# File 'lib/buildr/core/project.rb', line 506

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

#inspectObject

:nodoc:



605
606
607
# File 'lib/buildr/core/project.rb', line 605

def inspect #:nodoc:
  %Q{project(#{name.inspect})}
end

#layoutObject

Returns the layout associated with this project.



459
460
461
# File 'lib/buildr/core/project.rb', line 459

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/bar
path_to('/tmp')
=> /tmp
path_to(:base_dir, 'foo') # same as path_to('foo")
=> /home/project1/foo


483
484
485
# File 'lib/buildr/core/project.rb', line 483

def path_to(*names)
  File.expand_path(layout.expand(*names), base_dir)
end

#project(*args, &block) ⇒ 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


578
579
580
581
582
583
584
585
586
587
588
589
# File 'lib/buildr/core/project.rb', line 578

def project(*args, &block)
  if Hash === args.last
    options = args.pop
  else
    options = {}
  end
  if args.empty?
    self
  else
    Project.project *(args + [{ :scope=>self.name }.merge(options)]), &block
  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.



596
597
598
599
600
601
602
603
# File 'lib/buildr/core/project.rb', line 596

def projects(*args)
  if Hash === args.last
    options = args.pop
  else
    options = {}
  end
  Project.projects *(args + [{ :scope=>self.name }.merge(options)])
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.



558
559
560
561
562
563
564
# File 'lib/buildr/core/project.rb', line 558

def recursive_task(*args, &block)
  task_name, arg_names, deps = Buildr.application.resolve_args(args)
  task = Buildr.options.parallel ? multitask(task_name) : task(task_name)
  parent.task(task_name).enhance [task] if parent
  task.set_arg_names(arg_names) unless arg_names.empty?
  task.enhance Array(deps), &block
end

#root_projectObject

Returns the root project for this project.

If this project is a subproject it will find the top level project and return it, else it will return itself.



423
424
425
426
427
428
429
# File 'lib/buildr/core/project.rb', line 423

def root_project
  p = project
  while p.parent
    p = p.parent
  end
  p
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.



536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
# File 'lib/buildr/core/project.rb', line 536

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