通过AntBuilder使用Ant类库

引言

Ant的最近版本包含了一种称为Antlibs的机制。这允许你定义你自己的任务、以Ant需要的适当的定义方式把它们组织在一起,以及在你的Ant环境中没有名字冲突的使用它们。名字冲突是通过使用命名空间来避免的。现在有很多Antlib可以从Apache(Ant的开发组织)和其他来源获得。在Groovy中使用这些库是相当简单的,然而你需要注意一些细节。

AntUnit

AntUnit antlib包含了预定义的<assert>任务,这相当于你想在你的生成(build)文件中做的最普通的检查。它们在Ant的代码库中普遍的被使用,从而对很多Ant任务进行测试,但是你也可以在你自己的生成文件(或者任何Groovy代码)中使用这些断言。

这里是一个使用了assertFileDoesntExist和assertFileExists检查的例子。

首先,我们考虑以命名空间的方式(在这之前你需要把antunit的jar文件放在你的classpath中——尽管在这里我们依赖于Ant对antlib的自动发现机制)使用这个antlib的传统方法:

def ant = new AntBuilder()
 
ant.'antlib:org.apache.ant.antunit:assertFileDoesntExist'(file:'copytest1.tmp')
ant.copy(file:'src/antunit.groovy', tofile:'copytest1.tmp')
ant.'antlib:org.apache.ant.antunit:assertFileExists'(file:'copytest1.tmp')
ant.delete(file:'copytest1.tmp')
ant.'antlib:org.apache.ant.antunit:assertFileDoesntExist'(file:'copytest1.tmp')

注意antunit断言全都存在与它们自己的命名空间中。目前这是没有问题的,Groovy允许在方法名中包含特殊符号,只要你把方法名包含在引号中。

我们也可以把antlib直接导入到默认的命名空间中,就像下面一样:

import org.apache.tools.ant.taskdefs.Antlib
def ant = new AntBuilder()
def url = this.class.getResource('org/apache/ant/antunit/antlib.xml')
Antlib.createAntlib(ant.antProject, url, 'antlib:org.apache.ant.antunit').execute()
 
ant.assertFileDoesntExist(file:'copytest1.tmp')
ant.copy(file:'src/antunit.groovy', tofile:'copytest1.tmp')
ant.assertFileExists(file:'copytest1.tmp')
ant.delete(file:'copytest1.tmp')
ant.assertFileDoesntExist(file:'copytest1.tmp')

这让我们的代码看起来更简单,但是需要小心使用这种方法,因为你需要避免命名冲突。首选的方法是使用NamespaceBuilder。使用它,我们的代码会变为:

import groovy.xml.NamespaceBuilder
def ant = new AntBuilder()
def antunit = NamespaceBuilder.newInstance(ant, 'antlib:org.apache.ant.antunit')
def destfile = 'copytest1.tmp'
 
antunit.assertFileDoesntExist(file:destfile)
    ant.copy(file:'src/antunit.groovy', tofile:destfile)
antunit.assertFileExists(file:destfile)
    ant.delete(file:destfile)
antunit.assertFileDoesntExist(file:destfile)

Maven Ant任务

另外一个有用的antlib是Maven Ant任务。它们允许你在Ant中使用Maven的构件(artifact)处理特征,这些特征包括:

  • 依赖管理——包括传递依赖、作用域识别和SNAPSHOT处理
  • 构件部署——基于文件和SSH部署到一个Maven仓库
  • POM处理——读取Maven 2.0.x的pom.xml文件

这里演示了怎样使用这些任务来下载一些必须的jar文件到你的本地maven仓库缓存(~/.m2目录)。

import groovy.xml.NamespaceBuilder
def ant = new AntBuilder()
 
items = [[groupId:'jfree', artifactId:'jfreechart', version:'1.0.5'],
         [groupId:'jfree', artifactId:'jcommon', version:'1.0.9']]
 
def mvn = NamespaceBuilder.newInstance(ant, 'antlib:org.apache.maven.artifact.ant')
 
// 下载构件
mvn.dependencies(filesetId:'artifacts') { items.each { dependency(it) } }
// 显示我们下载了什么
ant.fileScanner { fileset(refid:'artifacts') }.each { println it }

在运行的时候,这会产生一个关于maven ant任务的活动的日志,如:

Downloading: jfree/jfreechart/1.0.5/jfreechart-1.0.5.pom
...
Transferring 298K
C:\Users\Paul\.m2\repository\jfree\jcommon\1.0.9\jcommon-1.0.9.jar
C:\Users\Paul\.m2\repository\jfree\jfreechart\1.0.5\jfreechart-1.0.5.jar

我们可以让这个例子更进一步,并演示如何创建在用JFreeChart绘图中的JFreeChart的例子,而不需要静态的在我们的classpath中定义JFreeChart的jar文件。

首先是一个助手类:

class MavenDependency {
    static void require(params) {
        MavenDependencyHelper.getInstance().require(params)
    }
    static MavenDependencyHelper using(classLoader) {
        MavenDependencyHelper.getInstance(classLoader)
    }
}
 
private class MavenDependencyHelper {
    private classLoader
    private MavenDependencyHelper(classLoader) {
        this.classLoader = classLoader
    }
 
    static MavenDependencyHelper getInstance(classLoader) {
        return new MavenDependencyHelper(classLoader)
    }
 
    static MavenDependencyHelper getInstance() {
        return new MavenDependencyHelper(MavenDependencyHelper.classLoader)
    }
 
    MavenDependencyHelper require(params) {
        def ant = new AntBuilder()
        def mvn = groovy.xml.NamespaceBuilder.newInstance(ant, 'antlib:org.apache.maven.artifact.ant')
        mvn.dependencies(filesetId:"artifact_${params.groupId}_${params.artifactId}_${params.version}") { dependency(params) }
        ant.fileScanner { fileset(refid:"artifact_${params.groupId}_${params.artifactId}_${params.version}") }.each {
            classLoader.addClasspath(it.toString())
        }
        this
    }
}

现在,下面的代码是我们需要用来动态的下载JFreeChart的jar文件,并把它们添加到我们的classpath中,然后运行脚本:

// 不需要导入jfreechart(我们会发现它们是通过程序实现的)
import groovy.swing.SwingBuilder
import static javax.swing.WindowConstants.EXIT_ON_CLOSE
 
def classLoader = Thread.currentThread().contextClassLoader
 
// 加载jar文件和添加到classpath中
def maven = MavenDependency.using(classLoader)
maven.require(groupId:'jfree', artifactId:'jfreechart', version:'1.0.5')
maven.require(groupId:'jfree', artifactId:'jcommon', version:'1.0.9')
 
// 通过程序定义使用的类/实例
def factoryClass     = classLoader.loadClass('org.jfree.chart.ChartFactory')
def orientationClass = classLoader.loadClass('org.jfree.chart.plot.PlotOrientation')
def dataset = classLoader.loadClass('org.jfree.data.category.DefaultCategoryDataset').newInstance()
 
// 下面是普通的代码
dataset.addValue 150, "no.1", "Jan"
dataset.addValue 210, "no.1", "Feb"
dataset.addValue 390, "no.1", "Mar"
dataset.addValue 300, "no.2", "Jan"
dataset.addValue 400, "no.2", "Feb"
dataset.addValue 200, "no.2", "Mar"
 
def labels = ["Bugs", "Month", "Count"]
def options = [true, true, true]
def chart = factoryClass.createLineChart(*labels, dataset,
        orientationClass.VERTICAL, *options)
def swing = new SwingBuilder()
def frame = swing.frame(title:'Groovy LineChart',
        defaultCloseOperation:EXIT_ON_CLOSE) {
    panel(id:'canvas') { rigidArea(width:400, height:400) }
}
frame.pack()
frame.show()
chart.draw(swing.canvas.graphics, swing.canvas.bounds)

Ivy任务

我们也可以使用Ivy来下载jar文件。在这个例子中,我们使用MarkupBuilder来生成一个Ivy的retrieve任务将用到的XML文件:

import groovy.xml.NamespaceBuilder
 
def ant = new AntBuilder()
def ivyfile = 'ivy.xml' // Ivy使用的默认文
ant.delete(file:ivyfile, quiet:true)
 
new File(ivyfile).withWriter { writer ->
    def builder = new groovy.xml.MarkupBuilder(writer)
    builder.'ivy-module'(version:'1.0') {
        info(organisation:"codehaus", module:"GroovyExamples")
        dependencies {
            dependency(org:'jfree', name:'jfreechart', rev:'1.0.5')
            dependency(org:'jfree', name:'jcommon', rev:'1.0.9')
        }
    }
}
 
def ivy = NamespaceBuilder.newInstance(ant, 'antlib:org.apache.ivy.ant')
ivy.retrieve()
ivy.report(toDir:'reports') // 可选的

在运行的时候,这会导致文件被下载:

[antlib:org.apache.ivy.ant:retrieve] :: Ivy 2.0.0-alpha-1-incubating - 20070416155158
...
[antlib:org.apache.ivy.ant:retrieve] downloading http://repo1.maven.org/maven2/jfree/jfreechart/1.0.5/jfreechart-1.0.5.jar
...
[antlib:org.apache.ivy.ant:retrieve] 	[SUCCESSFUL ] [ jfree | jfreechart | 1.0.5 ]/jfreechart.jar[jar] (16735ms)
[antlib:org.apache.ivy.ant:retrieve] downloading http://repo1.maven.org/maven2/jfree/jcommon/1.0.9/jcommon-1.0.9.jar
...
[antlib:org.apache.ivy.ant:retrieve] 	[SUCCESSFUL ] [ jfree | jcommon | 1.0.9 ]/jcommon.jar[jar] (6812ms)
[antlib:org.apache.ivy.ant:retrieve] :: resolution report ::
	---------------------------------------------------------------------
	|                  |            modules            ||   artifacts   |
	|       conf       | number| search|dwnlded|evicted|| number|dwnlded|
	---------------------------------------------------------------------
	|      default     |   2   |   2   |   0   |   0   ||   2   |   2   |
	---------------------------------------------------------------------
[antlib:org.apache.ivy.ant:retrieve] :: retrieving :: [ codehaus | grails ]
[antlib:org.apache.ivy.ant:retrieve] 	confs: [default]
[antlib:org.apache.ivy.ant:retrieve] 	2 artifacts copied, 0 already retrieved

如果你包含了可选的report步骤(并从你的ant发行包中添加ant-trax.jar到我们的classpath中),然后你会得到一些额外的日志信息,并且它会产生下面的漂亮的关于依赖的报告:

 
wiki/user_guide/using_ant_libraries_with_antbuilder.txt · 最后更改: 2008-08-10 19:45 由 johnny
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki