Slide 1

Slide 1 text

Apache Buildr Build like you code Øredev 2011 @ Malmö, Sweden

Slide 2

Slide 2 text

About Me

Slide 3

Slide 3 text

Alex Boisvert twitter: @boia01

Slide 4

Slide 4 text

French Canadian Live in USA

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

Java Scala Ruby Groovy Javascript ...

Slide 7

Slide 7 text

Buildr Committer [ PMC Chair ]

Slide 8

Slide 8 text

Use Buildr on daily basis

Slide 9

Slide 9 text

Contributions scala support plugins & extensibility eclipse integration many other improvements and bug fixes

Slide 10

Slide 10 text

Practical Introduction to Apache Buildr

Slide 11

Slide 11 text

Build system that doesn't suck.

Slide 12

Slide 12 text

Where it all started

Slide 13

Slide 13 text

Apache Ode Large Java Enterprise Middleware

Slide 14

Slide 14 text

15+ modules 9 databases 120+ dependencies 3 distributions tooling heavy ...

Slide 15

Slide 15 text

Maven2 5,433 lines of XML spread over 52 files (!)

Slide 16

Slide 16 text

“@&#! There's Got To Be A Better Way”

Slide 17

Slide 17 text

What We Really Wanted

Slide 18

Slide 18 text

No XML. Please!

Slide 19

Slide 19 text

Flexible Easy to customize & extend

Slide 20

Slide 20 text

DRY Code Basic abstraction and structuring mechanisms

Slide 21

Slide 21 text

In other words, a real scripting language.

Slide 22

Slide 22 text

Result?

Slide 23

Slide 23 text

Before 52 files 5,433 lines of XML. After Single file. 486 lines of Ruby.

Slide 24

Slide 24 text

Bonus! Twice as fast.

Slide 25

Slide 25 text

How did we do it?

Slide 26

Slide 26 text

Ruby awesome scripting language

Slide 27

Slide 27 text

Rake Ruby tasks, files, dependencies awesome scripting language

Slide 28

Slide 28 text

Buildr Rake Ruby projects, lifecycle, artifacts, plugins tasks, files, dependencies awesome scripting language

Slide 29

Slide 29 text

why ruby?

Slide 30

Slide 30 text

Scripting easy file manipulation native regexp, lightweight syntax exec() friendly etc.

Slide 31

Slide 31 text

Metaprogramm' great host for embedded domain-specific language

Slide 32

Slide 32 text

JVM Friendly ;) JRuby & Ruby-Java Bridge

Slide 33

Slide 33 text

Rake The Ruby Make

Slide 34

Slide 34 text

Rake The Ruby Make “Ant”

Slide 35

Slide 35 text

Your Application [ modules ]

Slide 36

Slide 36 text

[ graph of dependencies ]

Slide 37

Slide 37 text

# This is Rake code task "compile A" do # code to compile A end task "compile B" do # code to compile B end task "compile C" => ["compile A", "compile B"] do # code to compile C end task "package A,B,C" => ["compile A", "...", "compile C"] do # code to package A, B and C end task :default => “package A, B, C”

Slide 38

Slide 38 text

$ rake (in /home/buildr/example) compiling A ... compiling B ... compiling C ... packaging A,B,C ...

Slide 39

Slide 39 text

# This is Buildr code define "My application" do define "A" do package :jar end define "B" do package :jar end define "C" do compile.with projects("A", "B") package :jar end package(:war).using :libs => projects("A", "B", "C") end

Slide 40

Slide 40 text

# This is Buildr code define "My application" do define "A" do package :jar end define "B" do package :jar end define "C" do compile.with projects("A", "B") package :jar end package(:war).using :libs => projects("A", "B", "C") end Parent projects implicitly depend on children

Slide 41

Slide 41 text

my-application/ ├── A │ └── src │ ├── main │ │ ├── java │ │ └── resources │ └── test │ └── java ├── B │ └── src │ ├── main │ │ └── scala │ └── test │ └── scala ├── C │ └── src │ └── main │ └── groovy └── src └── main ├── java └── webapp Standard directory structure

Slide 42

Slide 42 text

$ buildr package (in /home/boisvert/tmp/buildr-example, development) Building buildr-example Compiling buildr-example:a into /home/boisvert/tmp/buildr- example/a/target/classes Compiling buildr-example:b into /home/boisvert/tmp/buildr- example/b/target/classes Packaging buildr-example-a-1.0.0.jar Packaging buildr-example-b-1.0.0.jar Compiling buildr-example:c into /home/boisvert/tmp/buildr- example/c/target/classes Packaging buildr-example Packaging buildr-example-c-1.0.0.jar Packaging buildr-example-1.0.0.war Running integration tests... Completed in 0.779s

Slide 43

Slide 43 text

All about tasks.

Slide 44

Slide 44 text

Standard tasks [ partial list ]

Slide 45

Slide 45 text

# Actual Rake code class FileTask < Task def needed? !File.exist?(name) || out_of_date? end private def out_of_date? @prerequisites.any? { |n| p.timestamp > timestamp} end end

Slide 46

Slide 46 text

artifacts and repositories

Slide 47

Slide 47 text

Local files (duh!) Maven2 (built-in) Ivy (plugin) Aether (plugin) or roll your own. Dependency resolution

Slide 48

Slide 48 text

# Buildfile repositories.remote << "http://www.ibiblio.org/maven2/" LOG4J = "log4j:log4j:jar:1.2.15" define 'my-library' do manifest['Copyright'] = 'Acme Inc (C) 2008' compile.options.target = '1.5' compile.with LOG4J package :jar end

Slide 49

Slide 49 text

# Buildfile repositories.remote << "http://www.ibiblio.org/maven2/" LOG4J = "log4j:log4j:jar:1.2.15" define 'my-library' do manifest['Copyright'] = 'Acme Inc (C) 2008' compile.options.target = '1.5' compile.with LOG4J package :jar end all your repos are belong to us!

Slide 50

Slide 50 text

# Buildfile repositories.remote << "http://www.ibiblio.org/maven2/" LOG4J = "log4j:log4j:jar:1.2.15" define 'my-library' do manifest['Copyright'] = 'Acme Inc (C) 2008' compile.options.target = '1.5' compile.with LOG4J package :jar end artifacts are tasks, too.

Slide 51

Slide 51 text

# Buildfile repositories.remote << "http://www.ibiblio.org/maven2/" LOG4J = "log4j:log4j:jar:1.2.15" define 'my-library' do manifest['Copyright'] = 'Acme Inc (C) 2008' compile.options.target = '1.5' compile.with LOG4J package :jar end tasks are wired implicitly

Slide 52

Slide 52 text

Languages we got 'em

Slide 53

Slide 53 text

Example: Scala plugin require 'buildr/scala' # brings in: # # - automatic detection # (src/main/scala, src/test/scala, src/spec/scala) # # - incremental compilation # # - mixed java + scala compilation # # - scaladoc generation # # - scalatest, specs and scalacheck testing # # - continuous compilation

Slide 54

Slide 54 text

# if you have Ruby installed % gem install buildr or, # JRuby all-in-one package % unzip buildr-all-in-one.zip

Slide 55

Slide 55 text

Demo Time! Java + Scala + Groovy Mixed Project

Slide 56

Slide 56 text

Ant Example: XMLBeans

Slide 57

Slide 57 text

Ant Example: XMLBeans def xmlbeans(files) do Buildr.ant "xmlbeans" do |ant| ant.taskdef \ :name => "xmlbeans", :classname => "org.apache.xmlbeans.impl.tool.XMLBean", :classpath => 'org.apache.xmlbeans:xmlbeans:jar:2.3.0' ant.xmlbeans \ :classpath => project.compile.dependencies, :srcgendir => project._('target/generated') :failonerror => "true" do files.flatten.each do |file| ant.fileset File.directory?(file) ? { :dir => file } : { :file => file } end end end

Slide 58

Slide 58 text

# Convert .pom to ivy.xml module POM_to_IVY extend self ANT = Buildr.ant('convertpom') do |ant| ant.taskdef :name => "convertpom", :classname => "org.apache.ivy.ant.IvyConvertPom" end end def convert(pom_file, ivy_file) ANT.convertpom :pomFile => pom_file, :ivyFile => ivy_file end end

Slide 59

Slide 59 text

define :webapp do # regenerate app.js when any .coffee file changes file('target/js/app.js') => Dir['src/main/coffee/*.coffee']) do sh "dependence src/main/coffee/ -t coffee -o target/js" end resources.enhance ['target/js/app.js'] end

Slide 60

Slide 60 text

# Generate SQL DDL schemas for all databases %w{ derby mysql oracle sqlserver postgres }.each do |db| db_xml = _("src/main/descriptors/persistence.#{db}.xml") partial_sql = file("target/partial.#{db}.sql"=>db_xml) do OpenJPA.mapping_tool \ :properties => db_xml, :action => "build", :sql => db.to_s, :classpath => projects("store", "dao") end # Add Apache license header header = _("src/main/scripts/license-header.sql") sql = concat(_("target/#{db}.sql") => [header, partial_sql]) build sql end

Slide 61

Slide 61 text

# Compile using all Eclipse BIRT libraries BIRT_WAR = artifact(“org.eclipse.birt:birt:war:1.4.1”) unzip_birt = unzip _("target/birt") => BIRT_WAR unzip_birt.enhance do compile.with Dir[_("target/birt/WEB-INF/lib") + "/*.jar"] end compile.enhance [unzip_birt]

Slide 62

Slide 62 text

Calling Java classes Java.classpath << [ "org.antlr:antlr:jar:3.0", "antlr:antlr:jar:2.7.7", "org.antlr:stringtemplate:jar:3.0" ] Java.org.antlr.Tool.new("-i #{input} -o #{output}").process

Slide 63

Slide 63 text

Testing Your Build # rspec code check package(:war).entry('META-INF/MANIFEST'), 'should have license' do it.should contain(/Copyright (C) 2011/) end check file('target/classes/killerapp/Code.class'), 'should exist' do it.should exist end

Slide 64

Slide 64 text

Example: Extension module GitVersion include Buildr::Extension @version = `git log -1 --pretty=format:%H` after_define do |project| project.packages.each do |jar| f = file project._("target/git-version.txt") do |f| Buildr.write f.to_s, @version end jar.enhance [f] jar.include f, :as => "META-INF/git-version.txt" end end end

Slide 65

Slide 65 text

# apply to a single project define 'my-project' do extend GitVersion end # apply to all projects class Buildr::Project include GitVersion end

Slide 66

Slide 66 text

More Stuff. layouts, profiles, code coverage, notifications more plugins, more languages + more awesome.

Slide 67

Slide 67 text

Only one thing to remember.

Slide 68

Slide 68 text

Build like you code.

Slide 69

Slide 69 text

join us! http://buildr.apache.org

Slide 70

Slide 70 text

[ Backup Slides ]

Slide 71

Slide 71 text

Caveats installation transitive dependencies pom generation ruby language more plugins no commercial support small community

Slide 72

Slide 72 text

Even more stuff! Eclipse task Download javadocs, sources Shell / REPL ActionScript, Flex, Clojure, ...