--- layout: default title: More Stuff --- h2(#shell). 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: {% highlight sh %} $ buildr shell {% endhighlight %} 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: {% highlight sh %} $ buildr foo:bar:shell {% endhighlight %} h3. 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":http://www.beanshell.org/manual/quickstart.html#The_BeanShell_GUI 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: {% highlight sh %} $ buildr foo:shell:jirb {% endhighlight %} 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: {% highlight sh %} $ buildr shell:jirb # wrong!! {% endhighlight %} 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: {% highlight ruby %} define 'foo' do shell.using :jirb end {% endhighlight %} 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: {% highlight sh %} $ buildr shell {% endhighlight %} 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. h3. 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, {% highlight sh %} $ buildr --silent {% endhighlight %} 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: {% highlight sh %} $ buildr -t {% endhighlight %} 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: {% highlight sh %} $ buildr --trace=javac,groovyc {% endhighlight %} 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: {% highlight sh %} $ buildr --trace=all {% endhighlight %} h3(#javarebel). JavaRebel Integration "JavaRebel":http://www.zeroturnaround.com/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): * @REBEL_HOME@ * @JAVA_REBEL@ * @JAVAREBEL@ * @JAVAREBEL_HOME@ 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). h2(#run). 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, {% highlight ruby %} define 'my-project' do compile.with COMMONS_IO, HTTPCLIENT run.using :main => "org.example.Main" end {% endhighlight %} And then run, {% highlight ruby %} ~/my-project$ buildr run {% endhighlight %} 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: {% highlight ruby %} run.using :main => "org.example.Main", :java_args => ["-server"] {% endhighlight %} 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@. {% highlight ruby %} run.using :main => ["org.example.Main", "-t", "input.txt"], :properties => { :debug => "true" } {% endhighlight %} 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: {% highlight ruby %} ~/my-project/subproject$ buildr run {% endhighlight %} 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. | p(note). The @run@ task also detects and uses JavaRebel if it's available. See the "JavaRebel":#javarebel section for details. h2(#gems). 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":extending.html. Here we will talk about using extensions that are distributed in the form of RubyGems. "RubyGems":http://rubygems.rubyforge.org 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":http://rubyforge.org 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":settings_profiles.html#build for more information), for example: {% highlight yaml %} # 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 {% endhighlight %} 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: {% highlight sh %} $ ri Buildr::Jetty $ ri Buildr::Jetty.start {% endhighlight %} You can also access documentation from a Web browser by running @gem server@ and pointing your browser to "http://localhost:8808":http://localhost:8808. Note that after installing a new gem, you will need to restart the gem server to see its documentation. h2(#java). 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: {% highlight ruby %} 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) {% endhighlight %} 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: {% highlight ruby %} Java.classpath << 'org.apache.ant:ant:jar:1.7.0' {% endhighlight %} 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: # 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. # Call @Java.load@ once before accessing any Java classes, allowing Buildr to set up the classpath. # 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. # Check on a clean build with empty local repository. h2(#buildr-server). BuildrServer Buildr provides an addon that allows you start a "dRuby":http://www.ruby-doc.org/stdlib/libdoc/drb/rdoc/index.html server hosting a buildfile, so that you can later invoke tasks on it without having to load the complete buildr runtime again. Usage: {% highlight sh %} buildr -r buildr/drb drb:start {% endhighlight %} 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: {% highlight ruby %} #!/usr/bin/env ruby require 'rubygems' require 'buildr/drb' Buildr::DRbApplication.run {% endhighlight %} Save this script as @dbuildr@, make it executable and use it to invoke tasks. {% highlight sh %} $ dbuildr clean compile {% endhighlight %} 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. h2(#growl). Growl, Qube For OS X users, Buildr supports "Growl":http://growl.info/ out of the box to send "completed" and "failed" notifications to the user. 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":http://launchpad.net/qube: {% highlight ruby %} # 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 {% endhighlight %} You can place this code inside @buildr.rb@ in the @.buildr@ directory under your home directory. h2(#eclipse). Eclipse If you're using Eclipse, you can generate @.classpath@ and @.project@ from your Buildfile and use them to create a project in your workspace: {% highlight sh %} $ buildr eclipse {% endhighlight %} 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: {% highlight ruby %} define 'my-plugin' do eclipse.natures :plugin end {% endhighlight %} 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: {% highlight ruby %} 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 {% endhighlight %} 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. h2(#idea). IntelliJ IDEA If you use IntelliJ IDEA, you can generate project files by issuing: {% highlight sh %} $ buildr idea {% endhighlight %} It will generate a @.iml@ file for every project (or subproject) and a @.ipr@ that you can directly open for the root project. To allow IntelliJ Idea to resolve external dependencies properly, you will need to add a @M2_REPO@ variable pointing to your Maven2 repository directory (@Settings / Path Variables@). If you're using IDEA 7 or later, use the @buildr idea7x@ task instead. This task creates the proper @.ipr@ and @.iml@ files for IDEA version 7. It includes the @-7x@ suffix in the generated files, so you can use the @idea@ and @idea7x@ tasks side by side on the same project. Also, check out the "Buildr plugin for IDEA":http://www.digitalsanctum.com/buildr-plug-in/ (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. h2(#cobertura_emma_jdepend). Cobertura, Emma, JDepend You can use "Cobertura":http://cobertura.sourceforge.net/ or "Emma":http://emma.sourceforge.net/ 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: {% highlight sh %} $ buildr test cobertura:html {% endhighlight %} 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. {% highlight sh %} $ buildr subModule:cobertura:html {% endhighlight %} 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: {% highlight ruby %} define 'someModule' do cobertura.include 'some.package.==*==' cobertura.include /some.(foo|bar).==*==/ cobertura.exclude 'some.foo.util.SimpleUtil' cobertura.exclude /==*==.Const(ants)?/i end {% endhighlight %} 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: {% highlight ruby %} 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 {% endhighlight %} The @cobertura:check@ task supports all of the configuration parameters allowed by the @cobertura-check@ Ant task (as "documented here":http://cobertura.sourceforge.net/anttaskreference.html). Configuration parameters are "Ruby-ized" (as demonstrated in the example above). You can use "JDepend":http://clarkware.com/software/JDepend.html on to generate design quality metrics. There are three tasks this time, the eye candy one: {% highlight sh %} $ buildr jdepend:swing {% endhighlight %} The other two tasks are @jdepend:text@ and @jdepend:xml@. 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: {% highlight ruby %} require 'buildr/java/cobertura' require 'buildr/java/emma' require 'buildr/jdepend' {% endhighlight %} 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: {% highlight sh %} $ buildr --require buildr/jdepend jdepend:swing $ buildr -rbuildr/java/cobertura cobertura:html {% endhighlight %} h2(#anything_ruby). 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: {% highlight ruby %} 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 {% endhighlight %} 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: {% highlight ruby %} 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 {% endhighlight %} And then use it in the project definition: {% highlight ruby %} define 'distro-axis2' do parent.distro(self, "#{parent.id}-war") { |zip| zip.include project('ode:axis2-war').package(:war), :as=>'ode.war' } end {% endhighlight %} 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: {% highlight ruby %} 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" {% endhighlight %}