一、简单介绍
1. 基本概念
Ant又叫Apache Ant, 是一款“构建”工具,即将软件编译,测试,部署等步骤联系起来并加以优化的一款工具。
形象的说,构建就是将代码从某处拿来,编译,再拷贝到另一处去的操作。
Ant可以从Apache官网直接下载得到,解压即可使用,体积小,简单方便。
之所以用ant,是因为他相比其他的组织构建工具,如Eclipse,更小且垮平台,这样更加灵活,在开展自动化测试的时候,这种灵活的方式更能发挥优势。
2. ant脚本
脚本是由一个xml文件构成的,其中核心元素如下:
project: 每个构建文件包含一个工程
depends: 每个工程包含若干个目标(target),且目标可以【依赖】其他目标
task: 目标包含一个或多个任务(task)
我们可以从后面的例子里来分析这些元素的意义和用法
3. ant项目目录结构
ant的目录结构可以很简单,如下:
工程主目录:C:\course\ant\demo
源代码目录:C:\course\ant\demo\src
编译后的class文件目录:C:\course\ant\demo\classes
打包好的jar文件目录:C:\course\ant\demo
工程配置文件目录:C:\course\ant\demo
先分析一下build.xml
一段一段的分析:
<project name="HelloWorld" default="run" basedir=".">
Ant的全部内容都要包含在<project></project>里
name: 项目名称
default:代表默认要做的事情,即如果你输入的ant命令行里没有指定操作,则他会默认执行run
basedir:工作的根目录,这里的“.”其实是xml的一个表示xpath,代表当前目录
<property name="src" value="src" />
<property name="dest" value="classes" />
<property name="hello_jar" value="hello.jar" />
property类似于程序中的变量
src:源代码的文件夹名称
dest:编译后的目标文件夹名称,用来放compile之后的class文件
hello_jar:打包后的jar文件名称
每一个target等于是我们想做的每一件事,比如这个target的名称是init,想做的事情是
mkdir dir="${dest}" 即在根目录下创建一个文件夹,根据前面定义的property,我们知道这个文件夹叫做classes
- <target name="compile" depends="init">
<javac srcdir="${src}" destdir="${dest}" />
</target>
这个target叫做compile,就是编译,他比上面一个target还多了一个属性,即depends。
depends属性是一个依赖选项,当target存在depends属性时,在执行这个target时,会优先检查他依赖的target有没有执行,如果没有,会先执行依赖的target,然后再执行这个target。
这里,依赖的target就是init。
<javac>是默认调用Ant本身的JVM编译器,里面指定了需要编译的源代码的路径(src)以及编译好后的类存放的路径(dest),而这些路径在前面已经被定义好了
- <target name="jar" depends="compile">
<jar jarfile="${hello_jar}" basedir="${dest}" />
</target>
如果我想指定jar包保存的路径,则可以加上destfile属性:
<target name="jar" depends="compile">
<jar jarfile="${hello_jar}" basedir="${dest}" destfile="${lib}/{hello_jar}" />
</target>
这里是说,我定义了一个lib文件夹,把jar文件放到lib里。
这个target叫做jar,依赖compile,也就是说,需要编译后才行执行,作用是打jar包。
也是指定了jar包的名字,jar包所需类的路径dest
- <target name="run" depends="jar">
<java classname="test.ant.HelloWorld" classpath="${hello_jar}" />
</target>
这个target叫做run,就是运行,依赖jar,即要打好包才能运行。
指定了运行的类名和jar包的路径
- <target name="clean">
<delete file="${hello_jar}" />
</target>
这个target叫做clean,即删除生成的文件
- <target name="rerun" depends="clean, run">
这个target叫做rerun,依赖项是clean和run,即run过并清除过后再run一次,里面嵌套调用了2个target
三、属性列表
1. <project>
2. <property>
前面我们说property就和变量一样,属性就是变量名和给变量赋的值。
一个project可以有很多变量,这些变量可以在buildfile中用property task来设定,也可以在ant外面设定。这就方便我们以后做参数化和数据分离。
Attribute
|
Description
|
Required
|
name
|
变量名称,可以自由定义
|
是
|
value
|
变量赋值
|
是
|
ant引用变量时的方式是这样的:${变量名称}
比如我们定义了一个property叫src,值为./src
build=“${src}/build ” 就是将./src/build这个路径值赋给build
除了我们自定义的属性之外,还有一些是内置属性,这里面包括JAVA本身的内置属性,和ANT自身的内置属性如下:
3. <target>
在例子里我们学过了name和depends,其余的几个我们在下面举实例来学习
这里还要提到的是depends,比如有这样一个依赖关系:
target A,B,C,D。project默认target是D,D依赖C,C依赖B,B依赖A,则执行顺序为A,B,C,D,且B,C,D这3个target后的depends都要定义相对于的依赖target。
也可以写成另一种形式:<target name="D" depends="C,B,A" >
最后,每一个target只能执行一次,即使是多个target依赖他,也只能执行一次。
if、unless的用法
如果你执行某个target,是由某些属性是否被设定来决定的,比如我们在windows和unix 2种系统上执行脚本,要区别不同的target,就可以像下面这样:
当命令行设定了osfamily-windows属性时,才执行这个target,而当命令行设定了osfamily-unix时,执行另一个target。
4. task
task并不是一个<task>,而是target的真正内容,即一段可执行的代码:
比如- <target name="compile" depends="init">
<javac srcdir="${src}" destdir="${dest}" />
</target>
这里面<javac srcdir="${src}" destdir="${dest}" />就是一个task,他里面也可以包含很多属性。
task一般的构造形式是:
<name attribute1=”value1” attribute2=”value2” … />
task可以自己编写task,也可以使用内置的task.
四、task
1. 设置classpath
classpath是用来指定类路径的。下面的例子用了4种方式来设置classpath
<path id="project.classpath">
<pathelement data-path="${basedir}/lib/aa.jar"/> <!--1-->
<pathelement location="aa.jar"/> <!--2, 与1的区别在于location可以去当前路径,当然也可以使用绝对路径 -->
<filelist id="file" dir="${basedir}/lib"><!--3-->
<file name="a.jar"/>
<file name="d:/lib/b.jar"/>
</filelist>
<fileset dir="d:/lib"><!--4-->
<include name="**/*.jar"/>
</fileset>
<!-- 手册上说了dirset也好用,但是我测试了还是不要用的-->
</path>
- 使用path属性设置
- 使用location属性设置
- 使用filelist设置
- 使用fileset设置
第1种,调用的需要设置绝对路径适合第三方jar包
第2种,则适合jar包和build.xml文件在同一目录下的情况,但是我觉得两个文件放在一起本身就不合理,估计是用的情况不多。这两种都是设置单个jar包
第3种,是一个文件集合适合引入不同路径的jar包,但是需要输入每个jar包的名字,比较繁琐,适合于jar包属于不同位置,比较分散但是不多的情况
第4种,是一个文件夹,可以采用匹配模式来引入,这个适合在同一个文件夹下,文件名字比较多的情况下
其实classpath就是指定当运行这个java程序的时候,那些个class的路径
2. 输出信息
输出信息使用的是echo,方法如下:
1. 输入一段话
<echo>Compile has been completed!!!</echo>
<echo message="Init has been completed!!!" />
2. 输出一段XML
...
<target name="run" depends="jar">
<java classname="test.ant.HelloWorld" classpath="${hello_jar}" />
<echoxml file="subbuild.xml">
<project default="foo">
<target name="foo">
<echo>foo</echo>
</target>
</project>
</echoxml>
</target>
...
3. 设置property
我们实际上在前面已经说到了,property即可以在xml里定义,也可以引用外部的文件。这里就做一个简单的介绍:
1. 在xml内定义
<property name="src" value="src" />
2. 读取属性文件中的属性配置
<property file="foo.properties"/>
3. 读取网络中的属性文件配置
<property url="http://www.mysite.com/bla/props/foo.properties"/>
4. 读取文件中的属性配置
<property resource="foo.properties"/>
5. 读取环境变量
<property environment="env"/>
6. 读取属性文件中的属性,并作为全局引用
<property file="/Users/antoine/.ant-global.properties"/>
4. 引入property
以属性文件为例,先建立一个属性文件,如build.properties
之前的例子里,我们的属性是这样设置的:
<property name="src" value="src" />
<property name="dest" value="classes" />
<property name="hello_jar" value="hello.jar" />
现在,我们在属性文件里对这些属性进行赋值:
src_path=src
dest_path=classes
jar_filename=helloMETOTO.jar
然后,在build.xml里就引入这个属性文件
<property file="./Config/build.properties" />
<property name="src" value="${src_path}" />
<property name="dest" value="${dest_path}" />
<property name="hello_jar" value="${jar_filename}" />
这里的./Config/build.properties" 是用xpath表示的build.properties的文件路径
下面的3个property的value都不是直接赋值,而是先赋的属性文件中的变量名的引用:${srcpath}
5. 引入XML文件(TBD)
比如说要读取XML中的属性配置
6. 复制文件与目录
file表示要复制的文件
tofile表示要复制到当前目录并重命名
todir表示复制到指定目录
dir表示当前文件夹的目录
1. 复制文件到当前文件夹,并重命名
<copy file="myfile.txt" tofile="mycopy.txt"/>
2. 复制指定路径下的文件到指定文件夹,并重命名
<copy file="./Config/build.properties" tofile="./src/build_cp1.properties" />
3. 复制指定路径下的文件到指定文件夹
<copy file="./Config/build_include.xml" todir="./src" />
4. 复制指定文件夹下的所有文件到指定目录(复制src下的所有文件去Config文件夹)
<copy todir="./Config">
<fileset dir="./src"/>
</copy>
5. 复制文件到指定文件夹(使用copyfile)
<copyfile src="test.java" dest="subdir/test.java"/>
现在copyfile已经成为废弃的task了,所以这里只做介绍,不要使用
6. 复制指定文件夹下的部分文件到指定目录
其实就是在4的基础上,加一个约束exclude
<copy todir="./src">
<fileset dir="./Config"/>
<exclude name="test.txtl"/>
<include name ="*.txt" />
</copy>
或者直接写成:
<copy todir="./src">
<fileset dir="./Config" excludes="test.txt" includes="*.txt" />
</copy>
7. 删除文件和目录
file表示要删除的文件。
dir表示要删除的目录。
includeEmptyDirs 表示指定是否要删除空目录,默认值是删除。
failonerror 表示指定当碰到错误是否停止,默认值是自动停止。
1. 删除文件
<delete file="./src/build_cp1.properties" />
2. 删除目录,包括其下的所有文件
<delete dir="${dest}" />或者
<delete dir="./classes" />
3. 删除目录下的部分文件
<delelte>
<fileset dir="./Config" excludes="test.txt" includes="*.txt" />
</delete>
<move todir="./src">
<fileset dir="./Config" excludes="test.txt" includes="*.txt" />
</move>
<>
有几种方式来调用
1)使用<ant target=”***”>调用另外一个target
<target name="rerun">
<<ant target="clean" />
</target>
2) 使用antcall调用另外一个target
<target name="default">
<antcall target="isInvoked" >
<param name="param1" value ="value" />
</target>
<target name="isInvoked">
<echo message="param1=${param1}" />
</target>