1. Start Here
    1. Welcome
    2. Quick Start
    3. Installing & Running
    4. Community Wiki
  2. Using Buildr
    1. This Guide (PDF)
    2. Projects
    3. Building
    4. Artifacts
    5. Packaging
    6. Testing
    7. Releasing
    8. Settings/Profiles
    9. Languages
    10. More Stuff
    11. Extending Buildr
    12. How-Tos
  3. Reference
    1. API
    2. Rake
    3. Antwrap
    4. Troubleshooting
  4. Get Involved
    1. Download
    2. Mailing Lists
    3. Twitter
    4. Issues/Bugs
    5. CI Jobs
    6. Contributing
  5. Google Custom Search
  6. The Buildr Book

    Based on the Buildr documentation, available from Amazon and CreateSpace

More Stuff

  1. Interactive Shells (REPLs)
  2. Running Your Application
  3. Using Gems
  4. Using Java Libraries
  5. BuildrServer
  6. Notifications: Growl, Libnotify, Qube
  7. Eclipse
  8. Cobertura, Emma
  9. Checkstyle
  10. FindBugs
  11. JavaNCSS
  12. JDepend
  13. Sonar
  14. Xjc Compiler
  15. Anything Ruby Can Do

Interactive Shells (REPLs)

Many languages (including Scala and Groovy) provide an interactive shell tool which allows developers to run arbitrary expressions and see the results immediately:

$ scala
Welcome to Scala version 2.7.4.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_03-p3).
Type in expressions to have them evaluated.
Type :help for more information.

scala> 6 * 7
res0: Int = 42

scala> 

These tools are alternatively known as “REPLs” (Read, Eval, Print Loop), a term which originally comes from Lisp. This sort of interactive shell can be an invaluable asset when developing frameworks or other non-UI-oriented modules. A common use-case is running a quick, manual test to make sure that the framework is functioning properly. It is faster and easier to do this in a shell, and also averts the need for extra test cases to be developed just to check simple things during development.

Unfortunately, for such a tool to be useful in Java, Scala or Groovy development, it must have access to the CLASSPATH, not only the compiled project binaries, but also its full list of dependencies. While it is usually possible with such tools to specify the classpath upon startup (e.g. the -cp switch for the Scala shell), this can get extremely tedious for project’s with more dependencies, especially when some of these dependencies are defined using transitive artifacts.

Buildr is capable of easing this workflow by providing full support for the configuration and launch of interactive shells, the relevant shell may be launched simply by invoking the shell task:

$ buildr shell

The shell task depends upon compile, meaning that any changed source files will be recompiled prior to the shell’s launch. Tests will not be run, nor will test files be recompiled. From within the shell itself, you should have access to your project’s compilation classpath (anything specified using compile.with) as well as the compiled sources for your project.

The project classpath is determined by checking the current working directory of your system shell (the path from which the buildr shell command was invoked) and recursively finding the relevant project for that directory. Thus, if you have a parent project foo which has sub-projects bar and baz, you may invoke an interactive shell for the baz project simply by cd-ing into its project directory (or any of its sub-directories) and invoking the shell task. You may also invoke a shell against a specific project by giving its fully-qualified descriptor as a prefix to the shell task:

$ buildr foo:bar:shell

Supported Shells

By default, Buildr will open the interactive shell which corresponds to your project’s language. Thus, if your project is using Groovy, it will invoke the groovysh command, configured with the appropriate classpath. If your project is using Scala, then the shell task will invoke the scala command. Unfortunately, the Java language does not define an interactive shell of any kind, however for those projects using exclusively the Java language, Buildr will use the BeanShell console.

However, you may still wish to exploit the advantages of an interactive shell from some other JVM language even while working in Java. Alternatively, you may want to use some shell other than the default even when working in a language which has its own. There are two ways to acheive this aim. The quickest way is to explicitly specify the relevant shell at the call-site:

$ buildr foo:shell:jirb

This will open the JIRB shell (the JRuby REPL) for the foo project. Whenever you are specifying a shell explicitly in this fashion, you must fully-qualify the project name:

$ buildr shell:jirb     # wrong!!

The above will fail because of the way that Rake tasks are dispatched.

Obviously, this explicit specification is a little bit clunky. It would be much easier if we could simply say that we always want to use the JIRB shell for this particular project. This can be done by using the shell.using directive within your project definition:

define 'foo' do
  shell.using :jirb
end

With this project definition, we can now invoke the shell task and JIRB will be launched, regardless of the default for our project’s language:

$ buildr shell

Buildr supports several different shell providers, and the framework is flexible enough that additional support can be added almost trivially. The following table gives the complete list of supported shells, their corresponding shell.using descriptor and the language for which they are the default (if applicable):

Shell Name Descriptor Language
BeanShell Console :bsh Java
Clojure REPL :clj N/A
GroovySH :groovysh Groovy
JRuby IRB :jirb N/A
Scala Interpreter :scala Scala

Note that some of these shells impose certain requirements to enable use. The Groovy shell requires the GROOVY_HOME environment variable to point to the Groovy install path. The Clojure REPL makes a similar requirement of CLOJURE_HOME. The JRuby and Scala shells will use JRUBY_HOME and SCALA_HOME respectively if they are defined. However, if these environment variables are not defined, the relevant JAR files will be automatically downloaded from the appropriate Maven2 repository.

Verbosity and Tracing

By default, Buildr is moderately verbose, meaning that it attempts to give you enough context into what’s happening during the build.

It’s possible to silence Buildr if you’re inconvenienced by its default verbosity by issuing,

$ buildr --silent

On the other hand, if you want Buildr to give you more context in order to trace what’s happening, you can use the -t options:

$ buildr -t

Using -t will also display backtraces if and when they occur.

Many components can be individually configured to display more output if you’re debugging a specific area of your build. For instance, you could use --trace=javac,groovyc to enable tracing of the Java and Groovy compilers:

$ buildr --trace=javac,groovyc

If you don’t know which tracing category you need to enable or if you want a full firehose worth of traces, you can enable all traces:

$ buildr --trace=all

JavaRebel Integration

JavaRebel is a live bytecode reloading solution by Zero Turnaround. It’s a lot like the hot code reload feature found in many Java IDE debuggers (like Eclipse and IntelliJ), but capable of handling things like member addition or removal and new class definition. The tool itself is commercial and works with any JVM language, but they do offer a free license for use with Scala classes only.

If available, Buildr will use JavaRebel when configuring the launch for each interactive shell. Shells launched with JavaRebel integration will automatically receive recompiled changes on the fly without any need to restart the shell. There are some limitations to this which are specific to the shell in question, but for the most part, things Just Work.

JavaRebel auto-magical integration is done by searching for a valid JavaRebel install path in the following list of environment variables (in order):

These environment variables may point to either the JavaRebel install directory (e.g. ~/javarebel-2.0.1), or the JAR file itself (e.g. ~/javarebel-2.0.1/javarebel.jar). If the path is valid, Buildr will automatically append the appropriate JVM switches to the launch configurations of each shell:

$ buildr shell
(in ~/foo, development)
Compiling foo into ~/foo/target/classes
Running java scala.tools.nsc.MainGenericRunner

#############################################################

 ZeroTurnaround JavaRebel 2.0.1 (200905251513)
 (c) Copyright Webmedia, Ltd, 2007-2009. All rights reserved.

 This product is licensed to Daniel Spiewak
 for personal use only.

#############################################################

Welcome to Scala version 2.7.4.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_03-p3).
Type in expressions to have them evaluated.
Type :help for more information.

scala> 

Note that Buildr does not check to make sure that you have a valid JavaRebel license, so you may end up launching with JavaRebel configured but without the ability to use it (in which case, JavaRebel will print a notification).

Running Your Application

The run task lets you easily run programs from your buildfile, such as launching your own application.

In its simplest form, you simply define the main class of your Java application,

define 'my-project' do
  compile.with COMMONS_IO, HTTPCLIENT
  run.using :main => "org.example.Main"
end

And then run,

~/my-project$ buildr run

which would launch your application using the project’s compile classpath.

It’s also possible to pass arguments to the JVM using the :java_args option:

  run.using :main => "org.example.Main",
            :java_args => ["-server"]

If your application requires arguments, you can pass in an array of values for the :main option, or provide a set of system properties using :properties.

  run.using :main => ["org.example.Main", "-t", "input.txt"],
            :properties => { :debug => "true" }

The run task is a local task, which means that Buildr will automatically pick the run task matching the project in the current directory. Executing the following command:

~/my-project/subproject$ buildr run

will run the my-project:subproject:run task, assuming my-project is your top-level project.

Here is a summary of run.using options,

Option Description …
:main The java main class, e.g. “com.example.Main”. Can also be an array if the main class requires arguments.
:properties A hash of system properties to be passed to java.
:java_args An array of additional parameters to pass to java
:classpath An array of additional classpath elements (i.e. artifacts, files, etc.). By default, the run task automatically uses the compile.dependencies, test.dependencies and test.compile.target of your project.

The run task also detects and uses JavaRebel if it’s available. See the JavaRebel section for details.

Using Gems

The purpose of the buildfile is to define your projects, and the various tasks and functions used for building them. Some of these are specific to your projects, others are more general in nature, and you may want to share them across projects.

There are several mechanisms for developing extensions and build features across projects which we cover in more details in the section Extending Buildr. Here we will talk about using extensions that are distributed in the form of RubyGems.

RubyGems provides the gem command line tool that you can use to search, install, upgrade, package and distribute gems. It installs all gems into a local repository that is shared across your builds and all other Ruby applications you may have running. You can install a gem from a local file, or download and install it from any number of remote repositories.

RubyGems is preconfigured to use the RubyForge repository. You’ll find a large number of open source Ruby libraries there, including Buildr itself and all its dependencies. RubyForge provides a free account that you can use to host your projects and distribute your gems (you can use RubyForge strictly for distribution, as we do with Buildr).

You can also set up your own private repository and use it instead or in addition to RubyForge. Use the gem sources command to add repositories, and the gem server command to run a remote repository. You can see all available options by running gem help.

If your build depends on other gems, you will want to specify these dependencies as part of your build and check that configuration into source control. That way you can have a specific environment that will guarantee repeatable builds, whether you’re building a particular version, moving between branches, or joining an existing project. Buildr will take care of installing all the necessary dependencies, which you can then manage with the gem command.

Use the build.yaml file to specify these dependencies (see Build Settings for more information), for example:

# This project requires the following gems
gems:
  # Suppose we want to notify developers when testcases fail.
  - buildr-twitter-notifier-addon >=1
  # we test with ruby mock objects
  - mocha
  - ci_reporter

Gems contain executable code, and for that reason Buildr will not install gems without your permission. When you run a build that includes any dependencies that are not already installed on your machine, Buildr will ask for permission before installing them. On Unix-based operating systems, you will also need sudo privileges and will be asked for your password before proceeding.

Since this step requires your input, it will only happen when running Buildr interactively from the command line. In all other cases, Buildr will fail and report the missing dependencies. If you have an automated build environment, make sure to run the build once manually to install all the necessary dependencies.

When installing a gem for the first time, Buildr will automatically look for the latest available version. You can specify a particular version number, or a set of version numbers known to work with that build. You can use equality operations to specify a range of versions, for example, 1.2.3 to install only version 1.2.3, and => 1.2.3 to install version 1.2.3 or later.

You can also specify a range up to one version bump, for example, ~> 1.2.3 is the same as >= 1.2.3 < 1.3.0, and ~> 1.2 is the same as >= 1.2.0 < 2.0.0. If necessary, you can exclude a particular version number, for example, ~> 1.2.3 != 1.2.7.

Buildr will install the latest version that matches the version requirement. To keep up with newer versions, execute the gem update command periodically. You can also use gem outdated to determine which new versions are available.

Most gems include documentation that you can access in several forms. You can use the ri command line tool to find out more about a class, module or specific method. For example:

$ ri Buildr::Jetty
$ ri Buildr::Jetty.start

You can also access documentation from a Web browser by running gem server and pointing your browser to http://localhost:8808. Note that after installing a new gem, you will need to restart the gem server to see its documentation.

Using Java Libraries

Buildr runs along side a JVM, using either RJB or JRuby. The Java module allows you to access Java classes and create Java objects.

Java classes are accessed as static methods on the Java module, for example:

str = Java.java.lang.String.new('hai!')
str.toUpperCase
=> 'HAI!'
Java.java.lang.String.isInstance(str)
=> true
Java.com.sun.tools.javac.Main.compile(args)

The classpath attribute allows Buildr to add JARs and directories to the classpath, for example, we use it to load Ant and various Ant tasks, code generators, test frameworks, and so forth.

When using an artifact specification, Buildr will automatically download and install the artifact before adding it to the classpath.

For example, Ant is loaded as follows:

Java.classpath << 'org.apache.ant:ant:jar:1.7.0'

Artifacts can only be downloaded after the Buildfile has loaded, giving it a chance to specify which remote repositories to use, so adding to classpath does not by itself load any libraries. You must call Java.load before accessing any Java classes to give Buildr a chance to load the libraries specified in the classpath.

When building an extension, make sure to follow these rules:

  1. Add to the classpath when the extension is loaded (i.e. in module or class definition), so the first call to Java.load anywhere in the code will include the libraries you specify.
  2. Call Java.load once before accessing any Java classes, allowing Buildr to set up the classpath.
  3. Only call Java.load when invoked, otherwise you may end up loading the JVM with a partial classpath, or before all remote repositories are listed.
  4. Check on a clean build with empty local repository.

BuildrServer

Buildr provides an addon that allows you start a dRuby server hosting a buildfile, so that you can later invoke tasks on it without having to load the complete buildr runtime again.

Usage:

buildr -r buildr/drb drb:start

To stop the BuildrServer simply use Ctrl+C or kill the process.

Once the server has been started you can invoke tasks using a simple script:

#!/usr/bin/env ruby
require 'rubygems'
require 'buildr/drb'
Buildr::DRbApplication.run

Save this script as dbuildr, make it executable and use it to invoke tasks.

$ dbuildr clean compile

The dbuildr command will start the BuildrServer if there isn’t one already running. Subsequent calls to dbuildr will act as the client and invoke the tasks you provide to the server. If the buildfile has been modified it will be reloaded on the BuildrServer.

Notifications: Growl, Libnotify, Qube

Buildr support sending notifications when the build completes or fails, such as displaying the outcome message in an overlaid window on top of other applications.

For OS X users, Buildr supports Growl out of the box by using the Ruby Cocoa bindings.

For Debian-based Linux users, Buildr supports notifications via the notify-send command which is part of the “libnotify-bin”:“http://packages.debian.org/search?keywords=libnotify-bin” package. Just make sure `notify-send` is installed and on your path is on your `PATH`.

For other platforms or if you want to notify the user differently, Buildr offers two extension points:

  • Buildr.application.on_completion
  • Buildr.application.on_failure

Here is an example using these extension points to send notifications using Qube:

# Send notifications using Qube
notify = lambda do |type, title, message|
  param = case type
    when 'completed'; '-i'
    when 'failed'; '-e'
    else '-i'
  end
  system "qube #{param} #{title.inspect} #{message.inspect}"
end

Buildr.application.on_completion do |title, message|
  notify['completed', title, message]
end
Buildr.application.on_failure do |title, message, ex|
  notify['failed', title, message]
end

You can place this code inside buildr.rb in the .buildr directory under your home directory.

Eclipse

Use Apache Buildr to create Eclipse projects

If you’re using Eclipse, you can generate .classpath and .project from your Buildfile and use them to create a project in your workspace:

$ buildr eclipse

The eclipse task will generate a .classpath and .project file for each of projects (and sub-project) that compiles source code. It will not generate files for other projects, for examples, projects you use strictly for packaging a distribution, or creating command line scripts, etc.

If you add a new project, change the dependencies, or make any other change to your Buildfile, just run the eclipse task again to re-generate the Eclipse project files. To have your libraries’ source code available in Eclipse, run the artifacts:sources task.

You may explicitly specify the nature of your project, for example if you are developing an Eclipse plugin:

define 'my-plugin' do
  eclipse.natures :plugin
end

The currently supported natures are :java, :scala and :plugin. Buildr will attempts to auto-detect your project type and apply the most relevant settings by default. If it doesn’t or you need something special, you may also explicitly set the nature, container and builders of your project by doing:

define 'custom-plugin' do
  eclipse.natures 'org.eclipse.pde.PluginNature'
  eclipse.classpath_containers 'org.eclipse.pde.core.requiredPlugins'
  eclipse.builders ['org.eclipse.pde.ManifestBuilder', 'org.eclipse.pde.SchemaBuilder']
end

One more thing; these settings are inherited hierarchically so you may set them on a parent project if you want to share them across different projects.

Use Apache Buildr to create a buildfile from an Eclipse workspace

If you’re using Eclipse, you can generate a buildfile from a directory which contains one (or more) Eclipse projects somewhere in its sub-directories.

$ buildr --generate /path/to/my_project

This creates a basic buildfile with a main project called ‘my_project’. The buildfile contains a skeleton for compiling the Eclipse projects. If you want to automate dependency tracking via OSGi have a look at the buildr4osgi project. Support for building Eclipse RCP applications, running PDE tests and P2-sites is currently lacking in Buildr.

IntelliJ IDEA

If you use IntelliJ IDEA, you can generate project files by issuing:

$ buildr idea

This task will generate a .iml file for every project (or subproject) and a .ipr that you can directly open for the root project.

The generated project files can be removed by issuing:

$ buildr idea:clean

The idea task generates the project files based on the settings of each project and idea extension specific settings. The main and test source trees are added to the .iml file for each project as are the respective resource directories. The target and report directories are excluded from the project. If the project files exist on the file system the extension will replace specific component sections in the xml with the generated component configurations.

Dependencies come in two forms. Dependencies on other projects and dependencies on external jars. Dependencies on other projects are added as module dependencies in the .iml while jars are added as regular file dependencies. Dependencies are exported from the .iml file if they are compile dependencies. If a artifact that matches dependency but has a classifier of ‘sources’ is present then it is configured as the source for the dependency. Note: Use “buildr artifacts:sources” to download the source for dependencies.

Idea Specific Directives

The extension specific settings of sub-projects inherit the parent projects settings unless overwritten.

Project file naming

The extension will use the last element of the projects name when generating the .ipr and .iml files. i.e. A project named “foo” will generate “foo.iml” and “foo.ipr” while a project named “foo:bar” will generate “bar/bar.iml” and no ipr. (The .ipr project files are only generated for the base project). The name can be modified by setting the “ipr.suffix” or “iml.suffix” settings which specifies the suffix appended to the file names. The user can also override the name completely by setting “ipr.id” or “iml.id”.

Example: Setting id
define "foo" do
  ipr.id = "beep"
  define "bar" do
    iml.id = "baz"
  end
end

Will generate:

beep.ipr
foo.iml
bar/baz.iml
Example: Setting suffix
define "foo" do
  ipr.suffix = "-suffix1"
  iml.suffix = "-suffix2"
  define "bar"
end

Will generate:

foo-suffix1.ipr
foo-suffix2.iml
bar/bar-suffix2.iml

Disabling project file generation

The extension will not generate an iml file for a project if the “project.no_iml” method is invoked. Generation of ipr files can be disabled by invoking the method “project.no_ipr”.

Example
define "foo" do
  project.no_ipr
  define "bar" do
    project.no_iml
  end
end

Will generate:

foo.iml

Disabling generation of content section in .iml file

The extension will not generate a content section in an iml file if the “iml.skip_content!” method is invoked. This can be useful if a project is just exporting dependencies and has no associated source code. This may also be of use in scenarios where the build is repackaging an existing jar with more meta-data or the project is just a container for other projects.

Example
define "foo" do
  iml.skip_content!
end

VCS Integration

The extension will attempt to guess the VCS type of the project by looking for a .svn or .git directory in the base projects directory. If either of these are set it will configure the component as appropriate. Otherwise the user will need to manually specify the project to one of either ‘Git’ or ‘svn’ using the ipr.vcs setting.

Example
define "foo" do
  ipr.vcs = 'Git'
end

Adding main, test or exclude paths to the .iml file

The extension allows you to add source paths, test source paths or add paths to the excluded set by modifying the “iml.main_source_directories”, “iml.test_source_directories” or “iml.excluded_directories” settings respectively. This is only needed when the defaults inherited from project.compile or project.test are not sufficient.

Example
define "foo" do
  # Add path for generated resources to .iml file
  iml.main_source_directories << _("generated/main/resources")

  # Add path for generated test resources to .iml file
  iml.test_source_directories << _("generated/test/resources")

  # Exclude the temp directory created during testing
  iml.excluded_directories << _("tmp")

  ...
end

Adding main or test dependencies to the .iml file

The extension allows you to add main or test dependencies by modifying the “iml.main_dependencies” or “iml.test_dependencies” settings respectively. This is only needed when the defaults inherited from project.compile or project.test are not sufficient. Note: These dependencies are not included on compile path when running buildr.

Example
define "foo" do
  # Add idea specific jar dependency to .iml file
  iml.main_dependencies << 'group:id:jar:1.0'

  # Add idea specific test jar dependency to .iml file
  iml.test_dependencies << 'group:id:jar:1.0'
  ...
end

Dependency generation

A file dependency that exists in the local maven 2 repository is stored in the IML file relative to the $MAVEN_REPOSITORY$ environment variable (that defaults to ~/.m2/repository). The user can override the environment variable by setting the “iml.local_repository_env_override” setting. If the dependency does not exist in to maven repository or the “iml.local_repository_env_override” setting is set to nil, then the path stored in the IML is relative to the IML file.

Example: Setting local_repository_env_override
define "foo" do
  iml.local_repository_env_override = nil
  compile.with 'group:id:jar:1.0'
end

Will generate a dependency with a path like:

jar:///home/peter/.m2/repository/group/id/1.0/id-1.0.jar!/

rather than the default

jar://$MAVEN_REPOSITORY$/group/id/1.0/id-1.0.jar!/
Example: A dependency outside the maven repository
define "foo" do
  compile.with _("foos-dep.jar")
end

Will generate a dependency with a path like:

jar://$MODULE_DIR$/foo-dep.jar!/

Module Facets

Facets are IDEAs mechanism for adding support for languages, tools and frameworks other than core java. A facet can be added to a project so that it can be deployed as a web application or a hibernate application. A facet can also be used t provide support for other languages such as ruby and scala. The extension makes it possible to generate .iml with the appropriate facets via the “iml.add_facet” method. It should be noted that facets are NOT inherited by sub-projects.

Example

This example adds the web facet to a project.

define "foo" do
  iml.add_facet("Web","web") do |facet|
    facet.configuration do |conf|
      conf.descriptors do |desc|
        desc.deploymentDescriptor :name => 'web.xml',
          :url => "file://$MODULE_DIR$/src/main/webapp/WEB-INF/web.xml",
          :optional => "false", :version => "2.4"
      end
      conf.webroots do |webroots|
        webroots.root :url => "file://$MODULE_DIR$/src/main/webapp", :relative => "/"
      end
    end
  end
end

Project Configurations

Configurations are IDEAs mechanism for running or debugging the project. Shared configurations are stored in the project file. The extension makes it possible to generate an .ipr with specific configurations via the “ipr.add_configuration” method.

Example

This example adds a configuration to invoke a GWT application.

define "foo" do
  ...
  ipr.add_configuration("Run Contacts.html", "GWT.ConfigurationType", "GWT Configuration") do |xml|
    xml.module(:name => project.iml.id)
    xml.option(:name => "RUN_PAGE", :value => "Contacts.html")
    xml.option(:name => "compilerParameters", :value => "-draftCompile -localWorkers 2")
    xml.option(:name => "compilerMaxHeapSize", :value => "512")

    xml.RunnerSettings(:RunnerId => "Run")
    xml.ConfigurationWrapper(:RunnerId => "Run")
    xml.method()
  end
end

Project Artifacts

IDEA can build artifacts such as jars and wars. The artifact configuration is stored in the project file. The extension makes it possible to generate an .ipr with specific artifacts via the “ipr.add_artifact” method.

Example

This example adds a jar artifact to the project.

define "foo" do
  ...
  ipr.add_artifact("MyFancy.jar", "jar") do |xml|
    xml.tag!('output-path', project._(:artifacts, "MyFancy.jar"))
    xml.element :id => "module-output", :name => "foo"
  end
end

Custom Component Sections

If the extension does not provide capability to generate configuration for a particular IDEA plugin the user can provide their own configuration data via the “ipr.add_component” or “iml.add_component” methods.

Example: Adding .ipr specific component

This example changes the compiler configuration for project.

define "foo" do
  ipr.add_component("CompilerConfiguration") do |component|
    component.option :name => 'DEFAULT_COMPILER', :value => 'Javac'
    component.option :name => 'DEPLOY_AFTER_MAKE', :value => '0'
    component.resourceExtensions do |xml|
      xml.entry :name => '.+\.nonexistent'
    end
    component.wildcardResourceExtensions do |xml|
      xml.entry :name => '?*.nonexistent'
    end
  end
end
Example: Adding .iml specific component

This example adds the web facet to a project. Note: This overrides the facets defined by the “iml.add_facet” method.

define "foo" do
  iml.add_component("FacetManager") do |component|
    component.facet :type => 'web', :name => 'Web' do |facet|
      facet.configuration do |conf|
        conf.descriptors do |desc|
          desc.deploymentDescriptor :name => 'web.xml',
            :url => "file://$MODULE_DIR$/src/main/webapp/WEB-INF/web.xml",
            :optional => "false", :version => "2.4"
        end
        conf.webroots do |webroots|
          webroots.root :url => "file://$MODULE_DIR$/src/main/webapp", :relative => "/"
        end
      end
    end
  end
end

Templates

The underlying project files are xml the contain elements for a number of “components”. The extension will load any existing project files and replace or add any component elements that are generated by the extension. The extension also allows the user to specify a template with either “ipr.template” or “iml.template” settings. If a template is specified it will be loaded and any component elements in these documents will be merged into the base document prior to merging in generated sections. Templates are useful if you want to enforce certain configuration options (i.e. project specific code style).

Example
define "foo" do
  ipr.template = 'project.ipr.template'
  iml.template = 'module.iml.template'
end

Groups

IDEA provides the facility to organise modules into groups. By default the extension does not do this but it can be enabled by “iml.group” setting. If that setting is set to true then the .iml file will be placed in a group based on the parent projects name. If the setting is a string then that is used as the name of the group.

Example
define "foo" do
  iml.group = true
  define 'bar' do
    define 'baz'
  end
  define 'rab' do
    iml.group = "MyGroup"
  end
end

Will place the generated .imls in the following groups:

foo.iml                => ''
bar/bar.iml            => 'foo'
bar/baz/baz.iml        => 'foo/bar'
rab/rab.iml            => 'MyGroup'

Add Extra .iml files to .ipr

The ‘ipr.extra_modules’ setting makes it possible to add extra modules to the generated iml file. The setting is an array of file names relative to the base project directory.

Example
define "foo" do
  ipr.extra_modules << 'other.iml'
  ipr.extra_modules << 'other_other.iml'
end

Will add the ‘other.iml’ and ‘other_other.iml’ files to the .ipr project files.

Buildr plugin for IDEA

Also, check out the Buildr plugin for IDEA (IDEA 7 and later). Once installed, open your project with IDEA. If IDEA finds that you have Buildr installed and finds a buildfile in the project’s directory, it will show all the tasks available for that project. To run a task, double-click it. When the task completes, IDEA will show the results in the Buildr Output window.

Cobertura, Emma

You can use Cobertura or Emma to instrument your code, run the tests and create a test coverage report in either HTML or XML format.

There are two main tasks for each tool, both of which generate a test coverage report in the reports/cobertura (respectively reports/emma) directory. For example:

$ buildr test cobertura:html

As you can guess, the other tasks are cobertura:xml, emma:html and emma:xml.

If you want to generate a test coverage report only for a specific project, you can do so by using the project name as prefix to the tasks.

$ buildr subModule:cobertura:html

Each project can specify which classes to include or exclude from cobertura instrumentation by giving a class-name regexp to the cobertura.include or cobertura.exclude methods:

define 'someModule' do
  cobertura.include 'some.package.==*=='
  cobertura.include /some.(foo|bar).==*==/
  cobertura.exclude 'some.foo.util.SimpleUtil'
  cobertura.exclude /==*==.Const(ants)?/i
end

Emma has include and exclude methods too, but they take glob patterns instead of regexps.

Cobertura also provides a cobertura:check task. This task is intended to be used as a dependency for other tasks (such as deploy) which might wish to fail if coverage is unacceptable. The respective thresholds for task failure may be defined using the cobertura.check configuration namespace. For example:

define 'someModule' do
  cobertura.check.branch_rate = 75
  cobertura.check.line_rate = 100
  cobertura.check.total_line_rate = 98

  task(:deploy).enhance 'cobertura:check'
end

The cobertura:check task supports all of the configuration parameters allowed by the cobertura-check Ant task (as documented here). Configuration parameters are “Ruby-ized” (as demonstrated in the example above).

We want Buildr to load fast, and not everyone cares for these tasks, so we don’t include them by default. If you want to use one of them, you need to require it explicitly. The proper way to do it in Ruby:

require 'buildr/java/cobertura'
require 'buildr/java/emma'

You may want to add those to the Buildfile. Alternatively, you can use these tasks for all your projects without modifying the Buildfile. One convenient method is to add these lines to the buildr.rb file in the .buildr directory under your home directory.

Another option is to require it from the command line (--require or -r), for example:

$ buildr -rbuildr/java/cobertura cobertura:html

Checkstyle

Checkstyle is integrated into Buildr through an extension. The extension adds the “checkstyle:xml” task that generates an xml report listing checkstyle violations and may add a “checkstyle:html” task if an appropriate xsl is present. A typical project that uses the extension may look something like;

require 'buildr/checkstyle'

define "foo" do
  project.version = "1.0.0"

  define "bar" do ... end

  checkstyle.config_directory = _('etc/checkstyle')
  checkstyle.source_paths << project('bar')._(:source, :main, :java)
  checkstyle.extra_dependencies << :javax_servlet

end

By default checkstyle will look for all configuration files in the src/main/etc/checkstyle directory but this can be overriden by the setting the “checkstyle.config_directory” parameter. The “checkstyle:xml” task will be defined if the checkstyle rules file is found. The rules file is typically named “checks.xml” but can be overridden by setting the “checkstyle.configuration_file” parameter. If a suppressions file or import control file is included in the directory, these will also be used by the extension. These names of these files will default to “suppressions.xml” and “import-control.xml” but these can be overriden by the parameters “checkstyle.suppressions_file” and “checkstyle.import_control_file”.

The extension will include the source and test directories of the project aswell as the compile and test dependencies when invoking the checkstyle tool. These can be added to by the parameters “checkstyle.source_paths” and “checkstyle.extra_dependencies” as appropriate.

If the xsl file named “checkstyle-report.xsl” is present in the configuration directory then a “checkstyle:html” task will be defined. The name of the xsl file can be overridden by the parameter “checkstyle.style_file”.

FindBugs

FindBugs is integrated into Buildr through an extension. The extension adds the “findbugs:xml” task that generates an xml report listing findbugs violations and may add a “findbugs:html” task if an appropriate xsl is present. A typical project that uses the extension may look something like;

require 'buildr/findbugs'

define "foo" do
  project.version = "1.0.0"

  define "bar" do ... end

  findbugs.config_directory = _('etc/findbugs')
  findbugs.source_paths << project('bar')._(:source, :main, :java)
  findbugs.analyze_paths << project('bar').compile.target
  findbugs.extra_dependencies << project('bar').compile.dependencies

end

By default findbugs will look for all configuration files in the src/main/etc/findbugs directory but this can be overriden by the setting the “findbugs.config_directory” parameter. The “findbugs:xml” task will past FindBugs a filter xml if a file named “filter.xml” is present in the configuration directory. This can be overridden by setting the “findbugs.filter_file” parameter.

The extension will include the source and test directories of the project aswell as the compile and test dependencies when invoking the findbugs tool. These can be added to by the parameters “findbugs.source_paths” and “findbugs.extra_dependencies” as appropriate. The actual analysis is run across compiled artifacts ad this will default to the target directory of the project but this can be overriden by the “findbugs.analyze_paths” parameter.

If the xsl file named “findbugs-report.xsl” is present in the configuration directory then a “findbugs:html” task will be defined. The name of the xsl file can be overridden by the parameter “findbugs.style_file”.

JavaNCSS

JavaNCSS is integrated into Buildr through an extension. The extension adds the “javancss:xml” task that generates an xml report and may add a “javancss:html” task if an appropriate xsl is present. A typical project that uses the extension may look something like;

require 'buildr/javancss'

define "foo" do
  project.version = "1.0.0"

  define "bar" do ... end

  javancss.enabled = true
  javancss.config_directory = _('etc/javancss')
  javancss.source_paths << project('bar')._(:source, :main, :java)

end

The extension will include the source and test directories of the project when invoking the javancss tool. These can be added to by the parameters “javancss.source_paths”.

By default javancss will look for all configuration files in the src/main/etc/javancss directory but this can be overriden by the setting the “javancss.config_directory” parameter. The “javancss:xml” task will be defined if the “javancss.enabled” property is set to true. If the xsl file named “javancss2html.xsl” is present in the configuration directory then a “javancss:html” task will be defined. The name of the xsl file can be overridden by the parameter “javancss.style_file”.

JDepend

JDepend is integrated into Buildr through an extension. The extension adds the “jdepend:xml” task that generates an xml report, “jdepend:swing” that shows a Swing UI, and may add a “jdepend:html” task if an appropriate xsl is present. A typical project that uses the extension may look something like;

require 'buildr/jdepend'

define "foo" do
  project.version = "1.0.0"

  define "bar" do ... end

  jdepend.enabled = true
  jdepend.config_directory = _('etc/jdepend')
  jdepend.target_paths << project('bar').compile.target

end

The extension will include the compiled source and test directories of the project when invoking the JDepend tool. These can be added to by the parameters “jdepend.target_paths”.

By default JDepend will look for all configuration files in the src/main/etc/jdepend directory but this can be overriden by the setting the “jdepend.config_directory” parameter. The “jdepend:xml” and “jdepend:swing” task will be defined if the “jdepend.enabled” property is set to true. If a “jdepend.properties” is included in the configuration directory then jdepend will load it during the analysis. If the xsl file named “jdepend.xsl” is present in the configuration directory then a “jdepend:html” task will be defined. The name of the xsl file can be overridden by the parameter “jdepend.style_file”.

PMD

PMD is integrated into Buildr through an extension. The extension adds the “pmd:rule:xml” and “pmd:rule:html” tasks. A typical project that uses the extension may look something like;

require 'buildr/javancss'

define "foo" do
  project.version = "1.0.0"

  define "bar" do ... end

  pmd.enabled = true
  pmd.rule_set_paths = _('etc/pmd') + "/"
  pmd.source_paths << project('bar')._(:source, :main, :java)
  pmd.rule_set_files = ['basic','imports','unusedcode','logging-java','finalizers']

end

The “pmd:rule:xml” task will be defined if the “pmd.enabled” property is set to true.

The extension will include the source and test directories of the project when invoking the pmd tool. These can be added to by the parameters “pmd.source_paths”.

By default the pmd rule files ‘basic’,‘imports’ and ‘unusedcode’ will be evaluated but this can be overriden by the “pmd.rule_set_files” parameter. The rule sets will be loaded from the classpath and this can be added to by modifying the “pmd.rule_set_paths” parameter.

Sonar

Sonar is “an open platform to manage code quality”. It is integrated into Buildr through an extension. The extension adds the “sonar” task. A typical project that uses the extension may look something like;

require 'buildr/sonar'

define "foo" do
  project.version = "1.0.0"

  define "bar" do ... end

  sonar.enabled = true
  sonar.project_name = 'Foo-Project'
  sonar.key = 'foo:project'
  sonar.jdbc_url = 'jdbc:jtds:sqlserver://example.org/SONAR;instance=MyInstance;SelectMethod=Cursor'
  sonar.jdbc_driver_class_name = 'net.sourceforge.jtds.jdbc.Driver'
  sonar.jdbc_username = 'sonar'
  sonar.jdbc_password = 'secret'
  sonar.host_url = 'http://127.0.0.1:9000'
  sonar.sources << project('foo:bar')._(:source, :main, :java)
  sonar.binaries << project('foo:bar').compile.target
  sonar.libraries << project('foo:bar').compile.dependencies

end

The “sonar” task will be defined if the “sonar.enabled” property is set to true.

Defaults exist for the “project_name”, “key”, “sources”, “binaries” and “libraries” parameters but the others should be set explicitly. The extension will include the source and test directories of the project as sources by default, the target directory as a binary and the dependencies as libraries.

JAXB Xjc Compiler

Buildr includes an extension that provides the ability to invoke jaxb xjc binding compiler. A typical project that uses the extension may look something like;

require 'buildr/jaxb_xjc'

define "foo" do
  project.version = "1.0.0"
  compile.from compile_jaxb(_('src/schemas/wildfire-1.3.xsd'),
                            "-quiet",
                            :package => "org.foo.api")
  package :jar
end

The method compile_jaxb accepts either an array of files or a single file as the first parameter. It then accepts 0 or more arguments that are passed to the underlying XJC compiler. The arguments are documented on the jaxb site. If the last argument is an options hash then the extension handles the options hash specially. The supported options include:

  • :directory: The directory to which source is generated. Defaults to _(:target, :generated, :jaxb)
  • :keep_content: By default the generated directory will be deleted. If true is specified for this parameter the directory will not be deleted.
  • :package: The package in which the source is generated.

Anything Ruby Can Do

Buildr is Ruby code. That’s an implementation detail for some, but a useful features for others. You can use Ruby to keep your build scripts simple and DRY, tackle ad hoc tasks and write reusable features without the complexity of “plugins”.

We already showed you one example where Ruby could help. You can use Ruby to manage dependency by setting constants and reusing them, grouping related dependencies into arrays and structures.

You can use Ruby to perform ad hoc tasks. For example, Buildr doesn’t have any pre-canned task for setting file permissions. But Ruby has a method for that, so it’s just a matter of writing a task:

bins = file('target/bin'=>FileList[_('src/main/dist/bin/==*==')]) do |task|
  mkpath task.name
  cp task.prerequisites, task.name
  chmod 0755, FileList[task.name + '/==*==.sh'], :verbose=>false
end

You can use functions to keep your code simple. For example, in the ODE project we create two binary distributions, both of which contain a common set of files, and one additional file unique to each distribution. We use a method to define the common distribution:

def distro(project, id)
  project.package(:zip, :id=>id).path("#{id}-#{version}").tap do |zip|
    zip.include meta_inf + ['RELEASE_NOTES', 'README'].map { |f| path_to(f) }
    zip.path('examples').include project.path_to('src/examples'), :as=>'.'
    zip.merge project('ode:tools-bin').package(:zip)
    zip.path('lib').include artifacts(COMMONS.logging, COMMONS.codec,
      COMMONS.httpclient, COMMONS.pool, COMMONS.collections, JAXEN, SAXON,
      LOG4J, WSDL4J, XALAN, XERCES)
    project('ode').projects('utils', 'tools', 'bpel-compiler', 'bpel-api',
      'bpel-obj', 'bpel-schemas').map(&:packages).flatten.each do |pkg|
        zip.include(pkg.to_s, :as=>"#{pkg.id}.#{pkg.type}", :path=>'lib')
      end
    yield zip
  end
end

And then use it in the project definition:

define 'distro-axis2' do
  parent.distro(self, "#{parent.id}-war") { |zip|
    zip.include project('ode:axis2-war').package(:war), :as=>'ode.war' }
end

Ruby’s functional style and blocks make some task extremely easy. For example, let’s say we wanted to count how many source files we have, and total number of lines:

sources = projects.map { |prj| prj.compile.sources.
  map { |src| FileList["#{src}/**/*.java"] } }.flatten
puts "There are #{source.size} source files"
lines = sources.inject(0) { |lines, src| lines += File.readlines(src).size }
puts "That contain #{lines} lines"