论坛首页 编程语言技术论坛

When ANT is not enough, JRuby to the rescue!

浏览 4728 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-06-18  

随着项目越来越大,你的ANT脚本变得越来越臃肿,越来越依赖antcontrib来实现构建逻辑?不想放弃对构建过程和产出做精细的控制?恨不得自己写ANT Task?
等一等,在你考虑转向Maven或者真正卷起袖子开始研究ANT Task的API之前,先听我向你推荐Ruby/JRuby。相信我,也许这才是你真正需要的。

在我看来构建脚本最主要的要求是表达能力和控制能力,表达能力是我们应该能够很方便的告诉它我们要它做什么,而控制能力是我们告诉它如何去做,除了必要的构建命令的参数、依赖关系之外,它应该能够理解我们其他一些特殊要求。在项目相对简单时,ANT的XML格式的"脚本语言"能够比较好的表达构建者的要求,至少比纯Java的方式更加简单清晰,于是几乎从它诞生之日就成为Java领域当仁不让的头号构建工具。但是ANT也有它不够用的时候,尤其在控制能力上,为了实现实际使用中越来越复杂越来越精细的对构建过程和产出的要求,ANT的使用者们开始对ANT进行扩展,最具影响力的"非官方"扩展可能就是antcontrib了,很多实际Java项目的构建文件中我们都能够找到它的影子。但是一堆taskdef和<for><if><variable><substring><stringutil><length><math>之类的夹杂在ANT脚本里,怎么看怎么觉得别扭,也严重影响构建脚本的可读性。

我发现我需要的是一个具有完整功能脚本语言来写我的构建逻辑:一方面它要足够简单,我需要清晰的表达我的意图,另一方面当我需要的时候它要足够强大来帮我实现精细的控制。我自然而然想到Ruby。

由于Ruby是一个功能完整的工具,完全自己写Ruby脚本来调用Java自己的构建工具如javac、jar等等并非不可能,但是既然已经有人做了轮子,我们拿来用就是了,大不了自己再改装一下,也少走些弯路。时下比较流行的解决方案有Buildr、Raven、Rant和Antwrap,它们各有特点,大家可以根据需要进行选择。

我最终选了其中最"轻量"的Antwrap,原因嘛,我不想学新的API,我已经熟悉ANT常用的Task,而且我希望尽可能多的自己控制构建的过程和产出。Antwrap最能够满足我的需要。而前不久JRuby刚刚发布了1.0版,这样一来Ruby和Java的跨界引用变得更加容易,Ruby的实现自然就选择了JRuby。

安装JRuby和Antwrap相当容易,只要把下载的jruby-bin-1.0.tar.gz/.zip解压到本地,确保JAVA_HOME和CLASSPATH的配置,然后gem install Antwrap (选择Java版) 即可。为了顺利加载Antwrap,需要在CLASSPATH中包含ANT的ant.jar和ant-launcher.jar。(当然,如果想更加方便的share你的成果,可以把ant的文件拷贝到jruby目录下,在jruby的启动脚本加入必要的export/set命令,然后打包,这样别人只要从你提供的zip包解压出来即可使用。)

为了给大家一个直观的感觉,举个简单的例子:
ruby 代码
 
  1. require 'rubygems'  
  2. gem 'Antwrap'  
  3. require 'antwrap'  
  4.   
  5. @ant=AntProject.new(:name=>"SampleAntwrapBuild":basedir=>".")  
  6. @cvsroot=":pserver:cvsuser:password@10.10.10.1/cvsrepo/SampleProduct"  
  7.   
  8. def cvscheckout  
  9.     @ant.cvs(  
  10.         :cvsroot=>"#{@cvsroot}",   
  11.         :command=>"checkout -A",   
  12.         :package=>".",   
  13.         :dest=>"cvsoriginal",   
  14.         :compressionlevel=>"9")  
  15. end  
  16.   
  17. def cvsupdate  
  18.     @ant.cvs(  
  19.         :cvsroot=>"#{@cvsroot}",   
  20.         :command=>"update -A -d",   
  21.         :package=>".",   
  22.         :dest=>"cvsoriginal",   
  23.         :compressionlevel=>"9")  
  24. end  
  25.   
  26. def compile(project_name)  
  27.     @ant.javac(  
  28.         :srcdir=>"cvsoriginal/#{project_name}/src",   
  29.         :destdir=>"cvsoriginal/#{project_name}",   
  30.         :target=>"1.5",   
  31.         :encoding=>"GBK")  
  32.     @ant.copy(  :todir=>"cvsoriginal/#{project_name}"do  
  33.         fileset(:dir=>"cvsoriginal/#{project_name}/src"do  
  34.             exclude(:name=>"**/*.java")  
  35.         end  
  36.     end  
  37.     @ant.jar(  
  38.         :destfile=>"build/#{project_name}.jar",   
  39.         :basedir=>"cvsoriginal/#{project_name}",   
  40.         :manifest=>"MANIFEST.MF"do  
  41.         exclude(:name=>"src/**")  
  42.     end  
  43. end  
  44.   
  45. # to actually call your target  
  46. if ARGV.empty?  
  47.     puts "Usage: jruby #{$0} [target]"  
  48. else  
  49.     eval ARGV[0]  
  50. end  

可以看到几乎都是我们熟悉的ANT Task,只是更加紧凑更加灵活,一旦掌握了最最基本的Ruby语法,用它写出功能强大的构建脚本可以说是分分钟搞定。
   发表时间:2007-06-18  
觉得只是作为ANT的另一种语法选择,并不觉得有比XML方式强大,灵活
0 请登录后投票
   发表时间:2007-06-18  
呵呵,举的例子本来就只是为了消除不熟悉Ruby语法的朋友的一些疑虑,因为你几乎能够重用你在ANT上的所有投资,其实包括antcontrib也能够以这样的方式使用,只是有了Ruby和直接调用Java API的功能之后,antcontrib我个人觉得没什么用武之地了,例子中并没有出现特别Rubyish的东东。

当你面对的数十个除了路径和项目名称本质上类似,但需要动态的创建manifest、jnlp,动态读取项目中某些信息影响最终产出的jar文件名(比如在文件名中显示版本号)时,单纯的ANT或者加上antcontrib的ANT就会变得异常臃肿。

当然也有一个基本的前提,我向大家推荐JRuby/Antwrap,并非说ANT有什么事情做不到,只是我觉得JRuby/Antwrap能够让我比ANT更加清晰高效的表达对构建过程和产出的具体要求。
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics