2012年3月23日

Apache Buildr 支援 Java / Groovy / Scala 的自動化建置工具



過去不少次介紹 Gradle 這套專案建置工具,目前 Gradle 即將正式發行 1.0,不過在發行前的 milestone 階段停留很久。在等待  Gradle 1.0 的這段期間,我找了一下其它類似的工具。

Buildr 是 Apache 基金會推出的工具,它是以 Java 為基礎,但除了能夠建置 Java 專案外,它也支援 Scala、Groovy 等其它 JVM 語言。

Apache Buildr is a build system for Java-based applications, including support for Scala, Groovy and a growing number of JVM languages and tools. We wanted something that’s simple and intuitive to use, so we only need to tell it what to do, and it takes care of the rest. But also something we can easily extend for those one-off tasks, with a language that’s a joy to use. And of course, we wanted it to be fast, reliable and have outstanding dependency management.

安裝 Buildr 需要 RubyGems,這一點我認為相當有趣,通常 Java 的工具都會有「Pure Java」的設計,但 Buildr 光是在安裝這個步驟,就需要混搭 Ruby 才能完成。但我認為在開發階段,本來就必須整合各種好用的開發工具,例如 Ruby、Python、Perl 有好用的工具,就直接混搭使用,而不要重新再造輪子。可以放心的是,Buildr 最後建置出來的專案,肯定是 100% pure Java。

以 Mac OS X 為例,安裝 Buildr 只需要以下步驟:


  • sudo gem install rjb -v 1.3.3 --platform ruby
  • sudo gem update --system
  • export JAVA_HOME=/Library/Java/Home
  • sudo env JAVA_HOME=$JAVA_HOME gem install buildr
Linux 及 Windows 請安裝 Buildr http://buildr.apache.org/installing.html

由於 RubyGems 使 Buildr 支援多版本切換的設計,所以在執行 Buildr 時可以指定版本編號:

  • buildr _1.3.4_ clean
Buildr 的原始碼目錄結構和 Gradle 相同,都是放在 ./src/main,例如 Java 放在 ./src/main/java、Groovy 放在 ./src/main/groovy 而 Scala 則放在 ./src/main/scala。因此,在同一個專案中,同時使用 Buildr 及 Gradle 是有可能的(雖然不見得有理由需要這麼做)。

先來看幾個官方的範例。

首先,Buildr 的套件來源也是 Maven(Java Repository 世界幾年內可能都是以它為主了),repositories.remote 可以設定多個套件來源,也就是 Maven Repo 的 URL。這個範例可以看到 定義方式是用 define ... do ... end 指令。

repositories.remote << 'http://mirrors.ibiblio.org/maven2'

define 'killer-app' do
  project.version = '0.1.0'
  compile.with transitive('org.apache.wicket:wicket:jar:1.4-rc6')
  package :jar
end

上面的範例直到指定 Compile-time 的 dependencies 時才設定 Package,其 Package 的設定格式也和 Gradle 類似,使用 "群組:名稱:版本" 的定義。但遇到很多任務都要共用 package dependencies 時,就可以將 Package 在檔頭設定:


repositories.remote << 'http://mirrors.ibiblio.org/maven2'

WICKET = transitive('org.apache.wicket:wicket:jar:1.4-rc6')
SLF4J = 'org.slf4j:slf4j-jdk14:jar:1.5.8'

define 'killer-app' do
  project.version = '0.1.0'
  compile.with WICKET, SLF4J
  package :jar
end


接下來是 Buildr 讓我驚嘆的地方,它可以變魔術般地設定 ZIP URL,也就是說某些套件如果沒有被 Maven Repository 收錄,就可以直接找到官方的壓縮檔下載網址,作為相依套件的設定,而不必自行下載解壓縮 *.jar 到專案目錄下。例如:


DBPOOL = 'net.snaq:dbpool:jar:4.8.3'
download artifact(DBPOOL) => 'http://www.snaq.net/java/DBPool/DBPool_v4.8.3.zip'

define 'killer-app' do
  project.version '0.1.0'
  compile.with DBPool
  package :jar
end


在自動化測試的部份,Buildr 支援 JUnit4 及 TestNG,搭配 Scala 時則支援 Specs、ScalaTest,若搭配 Groovy 則支援 EasyB,這部份和 Gradle 的測試支援差不多,目錄結構也同樣是放在 ./src/test(./src/test/java、./src/test/groovy、./src/test/scala)。

Buildr 除了 test 及 compile 等常用的內建任務(Task),也可以自訂擴充新的任務,使用 task ... do ... end 語法,以下的範例定義了 run 任務,並宣告它依賴 compile 任務,所以執行 run 之前會先執行 compile,並用了 system 這個指令執行 java 程式。


define 'killer-app' do
  project.version = '0.1.0'
  package :jar

  task :run => :compile do
    system 'java -cp target/classes org.apache.killer.Main'
  end
end


建置程式必須儲存為「buildfile」或「Buildfile」,用「buildr killer-app:run」就能執行自訂的 run 任務。

雖然我暫時不會考慮在專案中加入 Buildr 的建置流程,但我覺得它仍是個值得學習參考的工具。無論如何,身為 Programmer,其實我們應該多認識每一種開發環境的自動化建置方式,例如:

  1. Makefile
  2. Ant、Maven、Gradle、Buildr
  3. Rakefile
  4. Jake (for JavaScript/Node.js)

我通常採用 Gradle 處理大部分的 Java 專案自動化建置流程,但很多時候還是搭配 Makefile,因為 Makefile 非常快、和 Shell Script 可以良好搭配,例如在執行 s3cmd 同步 S3 檔案時,直接用 Makefile 就明顯比 Gradle 執行 shell 指令的效果好得多。

使用 Java 以外的程式語言來建置 Java 專案,也許也是個值得考慮的方式,因為 Java 程式在第一次執行總是特別花費載入時間,對於每次寫完一段 code 就要跑 test 的情況來說,會耗費不少等待 Build System 載入的時間;雖然 Gradle 會提供 daemon 的模式,減少重複啟動,但至少現在還不是非常管用。

和 Java-based 的建置工具相比,Buildr 的啟動速度相當快;這種 Scripting 類型的工作,使用 Ruby/Python/Perl 本來就比較有效率。

所以,如果使用 Gradle 的開發者能熟悉 Makefile,就可以輕鬆將 Makefile+Gradle+Buildr+... 混搭,打造更敏捷的專案開發環境。

沒有留言:

張貼留言

lyhcode by lyhcode
歡迎轉載,請務必註明出處!