Ant's properties和datatypes
Ant的核心功能有两个基本概念:特性和datatypes。
1、datatypes:
可以将datatype认为是类似于java自身内建的类,他可以分发并提供任务。datatype构成了ant的构建文件如build.xml的基本结构。path和文件集是ant的两个非常重要的datatype
1)path--类似于java的classpath。其定义的方式通常如下:
<classpath>
<pathelement location="lib1/some1.jar"/>
<pathelement path="lib1\some2.jar;lib1/some3.jar:lib1/some4.jar"/>
<pathelement path="lib2"/>
......
</classpath>
注意:路径元素建的分隔符可用;也可用:,路径的分割可用\,也可用/。
如果路径结构里只有一个目录或位置,则可以用快捷方式。如:
<classpath location="lib/some.jar"/>
路径也可以包含一个文件集合:
<classpath>
<fileset dir="lib">
<include name="*.jar">
</fileset>
</classpath>
注意:路径里的文件是有序的,但是文件集里的文件是无序的。
2)文件集
文件集指的是同一个目录下的一系列文件。默认情况下,一个只指定了一个根目录的文件集包括该目录下整个目录树的所有文件,其中包含递归子目录下的所有文件。在构建的过程中,通常需要在构建文件集时包含(include)一些文件或者排除(exclude)一些文件。这就需要使用include和exclude模式。
<fileset dir="lib">
<include name="*.jar"> 注:包含该目录下所有jar文件,不包括子目录
<include name="**/*Test.java">注:包含该目录下所有以Test结尾的java文件,包括子目录
<exclude name="**/*.jsp">注:排除该目录下所有的jsp文件,包括子目录。
</fileset>
**是一种匹配一个目录结构下多个目录的模式。
默认情况下,include和exclude是大小写敏感的,但是可以通过设置casesensitive="false"来取消,默认情况下排除模式defaultexcludes是开的,这将会默认排除目录下的一些特殊文件。但是可以通过设置defaultexcludes="no"来关闭他。
3)模式集
模式集也是ant的一个datatype。模式集是与模式相匹配的文件的汇总。模式集本身并不指向任何实际的文件,除非他被嵌套入文件集,那样他就会以指定的目录为根。相当于unix的"文件匹配"。
文件集隐式包含模式集,该模式集中已经包含元素include,exclude,includesfile,excludesfile。也可以在文件集中显示的指定自定义的patternset。如:
<patternset id="pattern1">
<include name="**/*.jsp"/>
</patternset>
<include name="**/*.jsp"/>
</patternset>
<target name="copy">
<copy todir="./tjsp">
<fileset dir="./">
<patternset refid="pattern1"/>
</fileset>
</copy>
</target>
<copy todir="./tjsp">
<fileset dir="./">
<patternset refid="pattern1"/>
</fileset>
</copy>
</target>
4)过滤集
move和copy是常用的两个支持过滤机的任务。在将源文件copy或move到另一个目录时,可以对文件进行过滤操作来替换掉源文件中带标记的文件。源文件不会被改变,只有目标目录中的文件才会被改变。过滤标记通常以@开始,以@结束。如@DATE@
<tstamp/>
<copy todir="dest">
<fileset dir="src">
<filterset>
<filter token="DATE" value="${DSTAMP}"/>
</filterset>
</copy>
在本例中,文件中含有@DATE@标记的文件,@DATE@将被替换成当前日期。
5)选择器selector
选择器用来选择包含在文件集中的文件。
选择器可以被合并到选择起容器内以提供分组和逻辑表达。选择器容器包括:and,or,not,none,majority。选择器容器之间可以嵌套。
例子:
比较两个目录将只在一个目录下存在的文件复制到另一个目录下,并且选择只包含特定字符串的文件,注意text是指文件中包含的文本:
<target name="copy">
<copy todir="./tjsp">
<fileset dir="./src">
<not>
<present targetdir="./src2"/>
</not>
<target name="copy">
<copy todir="./tjsp">
<fileset dir="./src">
<not>
<present targetdir="./src2"/>
</not>
<contains text="jsp"> 注:contains是大小写敏感的,可以通过casesensitive="no"来进行修改
</fileset>
</copy>
</target>
</fileset>
</copy>
</target>
主要的选择器有:filename,depth,size,date,present,depend,contains。
6)过滤链和过滤阅读器
过滤阅读器是一种简单的过滤器,他输入文件,并在输出之前对文字进行移除和修改。过滤链是一组经过排序的一个或多个过滤阅读器。
有四个任务支持过滤链:copy,move,loadfile,loadproperties。
ant的过滤阅读器有:classconstants, expandproperties, headfilter, linecontains,linecontainsregexp, prefixlines,replacetokens,stripjavacomments,striplinebreaks,striplinecomments,tabstospaces,tailfilter.
classconstants直接操作与类.class文件,其作用是将类文件中的常量生成"name=value"行,这个FilterReader通过使用字节马引擎库BCELAPI来直接访问字节码信息,必须用bcel.jar才可以让其工作。该功能使得可以从java代码中提取实际的常量来是构建过程参数化。
例子:
//a.java
public interface a{
public static final String VERSION="1.7";
}
public static final String VERSION="1.7";
}
ant 代码
<loadproperties srcfile="./src1/a.class">
<filterchain>
<classconstants/>
<prefixlines prefix="a."/>
</filterchain>
</loadproperties>
<echo>a.VERSION = ${a.VERSION}</echo>
<filterchain>
<classconstants/>
<prefixlines prefix="a."/>
</filterchain>
</loadproperties>
<echo>a.VERSION = ${a.VERSION}</echo>
7)Mapper--映射器
用于将一批文件与另外的文件进行匹配。
映射器由uptodate,move,copy,apply及其他几种任务调用。
映射器的类型有以下几种:
(1)identity
目标文件和源文件的名称相同,默认情况下,copy任务使用identitymapper,例子:
<target name="copy1">
<copy todir="dest">
<fileset dir="src">
</fileset>
<mapper type="identity"/>
</copy>
</target>
<copy todir="dest">
<fileset dir="src">
</fileset>
<mapper type="identity"/>
</copy>
</target>
和
<target name="copy1">
<copy todir="dest">
<fileset dir="src"/>
</copy>
</target>
<copy todir="dest">
<fileset dir="src"/>
</copy>
</target>
功能是一样的。
(2)flatten
目标文件和源文件名称相同,且目标文件名中去除所有目录路径。
(3)merge
?
(4)glob
一般在对文件备份的时候使用。例子:
<copy todir="dest">
<fileset dir="src" includes="**/*"/>
<mapper type="glob" from="*" to="*.bak"/>
</copy>
<fileset dir="src" includes="**/*"/>
<mapper type="glob" from="*" to="*.bak"/>
</copy>
(5)package
源文件所在的目录之间的分隔将用"."来替代。例如:
<copy todir="packaged">
<fileset dir="packages" includes="**/*.java"/>
<mapper type="package" from="*.java" to="*.java"/>
</copy>
<fileset dir="packages" includes="**/*.java"/>
<mapper type="package" from="*.java" to="*.java"/>
</copy>
packages/a/b/test1.java文件,最后在packaged下面将形成文件a.b.test1.java
(6)regexp
非常复杂和强大,from属性指定一个正则表达式,只有符合from模式的文件才会被列入。目标文件的命名则通过from模式替换成to模式来生成。需要完全匹配用\0,\1--\9则匹配模式中括号部分。
8) zipfileset
例子:
<target name="testzip" >
<war destfile="dest/dest.war" webxml="web.xml">
<fileset dir="zipfile" />
<zipfileset dir="doc" prefix="api"/>
<zipfileset dir="html" prefix="help"/>
</war>
</target>
<war destfile="dest/dest.war" webxml="web.xml">
<fileset dir="zipfile" />
<zipfileset dir="doc" prefix="api"/>
<zipfileset dir="html" prefix="help"/>
</war>
</target>
本例中,doc目录中的文件将会被放入war包的api目录下。html目录中的文件将会放入war包的help目录下。
9)Dirset
只在javadoc和pathconvert任务中使用。
10)filelist
对文件集排序的时候很有用,支持concat,dependset,pathconvert任务。并可作为path datatype的嵌套元素。
11)classfileset
?
2、特性(property)
1)ant的内建特性
ant有一些内建的特性如:
ant.file-->构建文件如build.xml文件所在的路径
ant.home->ant的根路径
ant.java.version->java版本
ant.project.name->当前project的名字,在build.xml的开头指定
ant.version->ant版本
basedir->project的根路径,在build.xml的开头指定
<target name="echo">
<echo message="ant.file = ${ant.file}"/>
<echo message="ant.home = ${ant.home}"/>
<echo message="ant.java.version = ${ant.java.version}"/>
<echo message="ant.project.name = ${ant.project.name}"/>
<echo message="ant.version = ${ant.version}"/>
<echo message="basedir = ${basedir}"/>
</target>
<echo message="ant.file = ${ant.file}"/>
<echo message="ant.home = ${ant.home}"/>
<echo message="ant.java.version = ${ant.java.version}"/>
<echo message="ant.project.name = ${ant.project.name}"/>
<echo message="ant.version = ${ant.version}"/>
<echo message="basedir = ${basedir}"/>
</target>
所有jvm系统的特性都隐式的成为ant特性,并允许用户对一些重要信息诸如用户的主目录以及用户名称等进行修改。
例如:
<echo message="user.name = ${user.name}"/>
<echo message="user.home = ${user.home}"/>
<echo message="java.home = ${java.home}"/>
<echo message="user.home = ${user.home}"/>
<echo message="java.home = ${java.home}"/>
将得到:
[echo] user.name = lcheng
[echo] user.home = C:\Documents and Settings\lcheng
[echo] user.home = C:\Documents and Settings\lcheng
[echo] java.home = C:\Program Files\Java\jdk1.5.0_08\jre
2)用户自己设置特性
最常用的自定义特性有几种:
(1)name/value特性
其格式为<property name="..." value="..."/>
引用相对路径的特性最好使用location变量设置,如:
<property name="builddir" location=${build.dir} />
(2)从文件中载入特性集
假设我们已经有一个文件名为build.properties
<property file="build.properties"/>
(3)载入环境变量
另一个重要的property变量允许将环境变量作为特性。需要加入类似于下面这句话
<property environment="env" />
env表示环境变量的前缀,这个可以自己设置值。
那么在引用环境变量的时候输入${env.Path} ${env.CLASSPATH},注意环境变量是大小写敏感的。
(4)从xml文件中载入特性。
其格式为<xmlproperty file="${customer}.xml"/>
例如web.xml文件的内容如下:
<?xml version="1.0"?>
<customer name="lanlan">
<sex>female</sex>
<age>27</age>
</customer>
<customer name="lanlan">
<sex>female</sex>
<age>27</age>
</customer>
build.xml
<target name="testXMLimport">
<xmlproperty file="${customer}.xml" collapseAttributes="true" />
<echo message="${customer.name},${customer.sex},${customer.age}" />
</target>
<xmlproperty file="${customer}.xml" collapseAttributes="true" />
<echo message="${customer.name},${customer.sex},${customer.age}" />
</target>
运行ant testXMLimport -Dcustomer=web
得到的结果则是:lanlan,female,27
也可以通过import的方法来输入xml文件,此时xml文件的内容就像宏定义一样被嵌入。被import的xml文件必须是一个构建文件,以构建文件的格式书写。
注意:特性值一旦设定,则无论在构建文件中还是在命令行里都不能修改它的值。最先设值者设值时就固定了它的值。
例如下面这段代码
在文件build.properties中有这样一句话
build.debug=off
在构建文件中
<property file="build.properties"/>
<property name="build.debug" value="on"/>
<echo message="build.debug = ${build.debug}" />
其输出的结果是build.debug = off。
这是因为特性build.debug首先在build.properties中设定了。
我们也可以通过在命令行中首先输入一些特性来设定特性值,这样将会覆盖构建文件中所设定的特性值。
3)property用法
(1)可以用available任务来检查资源的可用性。例如某个文件是否在classpath中存在,检查某个目录或文件是否存在。
例子:
检查类文件是否存在:
<available
property = "resource.exists"
classname = "package1.test1"
classpath = "dist/project1.jar"/>
如果存在package1.test1.class文件则resource.exists将被设置为true。
property = "resource.exists"
classname = "package1.test1"
classpath = "dist/project1.jar"/>
如果存在package1.test1.class文件则resource.exists将被设置为true。
检查文件或目录是否存在:
<available
property = "resource.exists"
file = "src/test.txt"
type= "file"/>
property = "resource.exists"
file = "src/test.txt"
type= "file"/>
如果存在文件src/test.txt,则resource.exists将被设置为true。
检查资源文件是否存在:
<available
property = "resource.exists2"
resource="package1/test2.class"
classpath="dist/project1.jar"/>
property = "resource.exists2"
resource="package1/test2.class"
classpath="dist/project1.jar"/>
注意和1中的区别,在这里指定了文件的扩展名,在1中不用指定,默认为.class文件。
(2)用uptodate来检查目标文件是否最新
<uptodate property = "isuptodate" targetfile="test/a.jar">
<srcfiles dir="test" includes="**/*.txt"/>
</uptodate>
<srcfiles dir="test" includes="**/*.txt"/>
</uptodate>
如果a.jar中现有的和test目录下同名的文件相比,所有文件的修改时间均为最新,则isuptodate将被设置为true。只在源目录中存在的文件不作比较。
<uptodate property = "isuptodate" targetfile="a.jar">
<srcfiles dir="test" includes="**/*.java" />
<mapper type="glob" from="*.java" to="*.class" />
</uptodate>
<srcfiles dir="test" includes="**/*.java" />
<mapper type="glob" from="*.java" to="*.class" />
</uptodate>
看起来,uptodate不能设置targetdir只能设置targetfile。
在本例中,所有在a.jar中的.class文件如果和test下面的同名.java文件相比更新的话,则property isuptodate将被设置为true。
感觉uptodate很不好用...
(3)用condition设置测试条件
(4)命令行中也可设置特性
有两个开关-D,-propertyfile,其中-D具有更高的优先级,采用-D定义的特性,是在任何构建文件出现之前就已经定义好了的,也就是-D定义的特性值具有最高优先级。
(5)用tstamp任务设置时间戳属性
最简单的<tstamp/>将缺省设置三个属性,即DSTAMP,TSTAMP,TODAY,日期,时间,时间。
也可以利用tstamp自定义时间戳特性,例如星期特性,其格式为:
<tstamp>
<format property name="dayofweek" pattern]=“EEEE”/>
<format property="buildtime" pattern="YY-MM-DD'T'HH:mm:ss"/>
</tstamp>
<echo message="It is ${dayofweek}"/>
结果将显示 It is 星期三 , buildtime is 2007-01-10T11:28:49
时间戳可以添加前缀,如
时间戳可以添加前缀,如
<tstamp prefix="start"/>
那么在引用的时候,则应该写成start.TSTAMP,start.DSTAMP等。
(6)条件执行控制机制
通过if,unless,可以使特性控制ant的target,patternset,等。特性可以作为有条件执行的控制机制。if/unless子句中的特性无需用${}来修饰,只有特性存在与否,才是if/unless的考虑因素。
a、控制target
例子:
<target name="testifunless2" depends="testifunless">
<jar basedir="dest" jarfile="dest.jar" />
</target>
a、控制target
例子:
<target name="testifunless2" depends="testifunless">
<jar basedir="dest" jarfile="dest.jar" />
</target>
<target name="clean" depends="init" description="Removes the temporary directories used">
<delete dir="${basedir}/classes"/>
<mkdir dir="${basedir}/dist"/>
</target>
<delete dir="${basedir}/classes"/>
<mkdir dir="${basedir}/dist"/>
</target>
b、控制patternset
略
(7)引用
通过使用引用,可以重复使用在构建文件中定义的数据类型。
例如:
fileset 的refid