ant在持續集成的應用


一、Ant概述

Ant是一個Apache基金會下的跨平台的構建工具,它是一個將軟件編譯、測試、部署等步驟聯系在一起加以自動化的一個工具。

在本文中,我主要讓介紹Ant的命令、構建文件、最后部分以一個實例概述在持續集成工具jenkins中的應用。

二、為什么使用ant

開發過程中,我們一般是在windows下,利用eclipse可以很輕松地實現一鍵編譯、測試、打包、部署,但是我們的應用一般是部署在linux下,我們不可能安裝一個eclipse在linux上。那linux上有沒有類似eclipse這樣的工具呢?答案是肯定的,這個工具就是Ant,使用它可以實現自動化部署。除此之外,它還有很多優點。

1、跨平台性:Ant是純Java語言編寫的,所以具有很好的跨平台性。 
2、操作簡單:Ant運行時使用一個XML文件(構建文件)。 Ant通過調用target樹,就可以執行各種task。每個task實現了特定接口對象。 
3、集成方便:使用Ant就是搭建了一個一致的配置環境,每次集成都通過Ant自動化的構建(包括編譯,發布,自動化測試)來驗證,從而盡早地發現集成錯誤。

三、安裝與配置

比較簡單,這里請參見“使用jenkins實現持續集成V2.pdf” 2.2說明,注意安裝好之后要配置下環境變量。

參見我的這篇文章:使用jenkins實現持續集成(http://www.cnblogs.com/zishengY/p/7170656.html)

四、Ant命令

Ant的構件文件是基於XML編寫的,默認build.xml就是主要的ant腳本。
ant
在當前目錄下的build.xml運行Ant,執行缺省的target。

ant -buildfile build-test.xml
在當前目錄下的build-test.xml運行Ant,執行缺省的target。

ant -buildfile build-test.xml clean
在當前目錄下的build-test.xml運行Ant,執行一個叫做clean的target。

ant -buildfile build-test.xml -Dbuild=build/classes clean
在當前目錄下的build-test.xml運行Ant,執行一個叫做clean的target,並設定build屬性的值為build/classes。

 

五、主要元素介紹。

參見“http://blog.csdn.net/D3Direct_1/article/details/53055236”

本部分主要介紹Ant構建文件(默認是是build.xml)的元素組成。

1、project 節點元素

project 元素是 Ant 構件文件的根元素, Ant 構件文件至少應該包含一個 project 元素,否則會發生錯誤。在每個 project 元素下,可包含多個 target 元素。接下來向讀者展示一下 project 元素的各屬性。 
● name 屬性:用於指定 project 元素的名稱。 
● default 屬性:用於指定 project 默認執行的target 的名稱。 
● basedir 屬性:用於指定基路徑的位置。該屬性沒有指定時,使用 Ant 的構件文件的附目錄作為基准目錄。

 

<?xml version="1.0" ?>
<project name="ant-project" default="print-dir" basedir=".">
    <target name="print-dir">
        <echo message="The base dir is: ${basedir}" />
    </target>
</project>

 

從上例可以看出,在這里定義了default 屬性的值為print-dir,即當運行ant 命令時,如果沒有指明執行的target,則將執行默認的target(print-dir)。此外,還定義了basedir 屬性的值為 “.” ,.表示當前目錄,進入當前目錄后運行ant 命令,得一下結果:

 image

2、target節點元素

target為ant的基本執行單元或是任務,它可以包含一個或多個具體的單元/任務。多個target 可以存在相互依賴關系。它有如下屬性: 
● name 屬性:指定 target 元素的名稱,這個屬性在一個 project 元素中是唯一的。我們可以通過指定 target 元素的名稱來指定某個 target 。 
● depends 屬性:用於描述 target 之間的依賴關系,若與多個 target 存在依賴關系時,需要以“,”間隔。 Ant 會依照 depends 屬性中 target 出現的順序依次執行每個 target ,被依賴的target 會先執行。 
● if 屬性:用於驗證指定的屬性是存在,若不存在,所在 target 將不會被執行。 
● unless 屬性:該屬性的功能與 if 屬性的功能正好相反,它也用於驗證指定的屬性是否存在,若不存在,所在 target 將會被執行。 
● description 屬性:該屬性是關於 target 功能的簡短描述和說明。 
示例:

 

<?xml version="1.0" ?>
<project name="ant-target" default="print">
    <target name="version" if="ant.java.version">
        <echo message="Java Version: ${ant.java.version}" />
    </target>
    <target name="print" depends="version" unless="docs">
        <description>
            a depend example!
        </description>
        <echo message="The base dir is: ${basedir}" />
    </target>
</project>

 

從以下結果后可以看到,我們運行的是名為 print的target ,由於它依賴於version這個target任務,所以 version將首先被執行,同時因為系統配置了JDK,所以 ant.java.version 屬性存在,執行了version,輸出信息:"[echo] Java Version: 1.6 ",version執行完畢后,接着執行 print,因為docs不存在,而unless屬性是在不存在時進入所在target 的,由此可知 print得以執行,輸出信息:"[echo] The base dir is:D:\Workspace\AntExample\build"。

image 

3、property屬性節點元素

property元素可看作參量或者參數的定義,project 的屬性可以通過 property 元素來設定,也可在 Ant 之外設定。若要在外部引入某文件,例如 build.properties 文件,可以通過如下內容將其引: 
<property file="build.properties"/> 
property 元素可用作 task 的屬性值。在 task 中是通過將屬性名放在${屬性名}之間,並放在 task 屬性值的位置來實現的。 
Ant 提供了一些內置的屬性,它能得到的系統屬性的列表與 Java 文檔中 System.getProperties() 方法得到的屬性一致,這些系統屬性可參考 sun 網站的說明。同時, Ant 還提供了一些它自己的內置屬性,如下: 
basedir: project 基目錄的絕對路徑;   
ant.file: buildfile的絕對路徑,上例中ant.file值為D:\Workspace\AntExample\build; 
ant.version: Ant 的版本信息,本文為1.8.1 ; 
ant.project.name: 當前指定的project的名字,即前文說到的project的name屬性值; 
ant.java.version: Ant 檢測到的JDK版本,本文為 1.6 。

舉例說明如下:

 

<project name="ant-project" default="example">
    <property name="name" value="jojo" />
    <property name="age" value="25" />
    <target name="example">
        <echo message="name: ${name}, age: ${age}" />
    </target>
</project>

 

上例中用戶設置了名為name 和age的兩個屬性,這兩個屬性設置后,在下文中可以通過 ${name} 和 ${age} 分別取得這兩個屬性值。

4、copy命令

copy主要用來對文件和目錄的復制功能。舉例如下: 
● 復制單個文件: 
<copy file="old.txt" tofile="new.txt"/>

● 對文件目錄進行復制: 
<copy todir="../dest_dir"> 
    <fileset dir="src_dir"/> 
</copy>

● 將文件復制到另外的目錄: 
<copy file="src.txt" todir="c:/base"/>

 

5、delete命令

對文件或目錄進行刪除,舉例如下:

● 刪除某個文件:    
<delete file="/res/image/cat.jpg"/>

● 刪除某個目錄:    
<delete dir="/res/image"/>

● 刪除所有的jar文件或空目錄: 
<delete includeEmptyDirs="true"> 
       <fileset dir="." includes="**/*.jar"/> 
</delete>

6、 mkdir 命令

創建目錄。 
<mkdir dir="/home/philander/build/classes"/>

7、 move 命令

移動文件或目錄,舉例如下: 
● 移動單個文件: 
<move file="sourcefile" tofile=”destfile”/>

● 移動單個文件到另一個目錄: 
<move file="sourcefile" todir=”movedir”/>

● 移動某個目錄到另一個目錄: 
<move todir="newdir"> 
    <fileset dir="olddir"/> 
</move>

8、echo 命令

該任務的作用是根據日志或監控器的級別輸出信息。它包括 message 、 file 、 append 和 level 四個屬性,舉例如下 
<echo message="ant message" file="/logs/ant.log" append="true">

9、jar 標簽節點元素

該標簽用來生成一個JAR文件,其屬性如下。 
● destfile表示JAR文件名。 
● basedir表示被歸檔的文件名。 
● includes表示別歸檔的文件模式。 
● exchudes表示被排除的文件模式。

● compress表示是否壓縮。

示例:

 

<jar destfile="${webRoot}/${ash_jar}" level="9" compress="true" encoding="utf-8" basedir="${dest}">
    <manifest>
        <attribute name="Implementation-Version" value="Version: 2.2"/>
    </manifest>
</jar>

 

上面的mainfest是jar包中的MEAT-INF中的MANIFEST.MF中的文件內容

同樣打包操作的的還有war、tgz,已經解壓操作uzip

 

<!-- 創建zip -->
<zip basedir="${basedir}\classes" zipfile="temp\output.zip"/> 
<!-- 創建tgz -->
<gzip src="classes\**\*.class" zipfile="output.class.gz"/>
<!-- 解壓zip -->
<unzip src="output.class.gz" dest="extractDir"/>
<!-- 建立war包 -->
<war destfile="${webRoot}/ash.war" basedir="${basedir}/web" webxml="${basedir}/web/WEB-INF/web.xml">
    <exclude name="WEB-INF/classes/**"/>
    <exclude name="WEB-INF/lib/**"/>
    <exclude name="WEB-INF/work/_jsp/**"/>
    <lib dir="${lib.dir}" includes="**/*.jar, **/*.so, **/*.dll">
        <exclude name="${webRoot}\${helloworld_jar}"/>
    </lib>
    <lib file="${webRoot}/${helloworld_jar}"/>
    <classes dir="${dest}" includes="**/*.xml, **/*.properites, **/*.xsd"> </classes>
</war>

 

10、javac 標簽節點元素

該標簽用於編譯一個或一組java文件,其屬性如下。 
● srcdir表示源程序的目錄。 
● destdir表示class文件的輸出目錄。 
● include表示被編譯的文件的模式。 
● excludes表示被排除的文件的模式。 
● classpath表示所使用的類路徑。 
● debug表示包含的調試信息。 
● optimize表示是否使用優化。 
● verbose 表示提供詳細的輸出信息。 
● fileonerror表示當碰到錯誤就自動停止。

示例

 

<javac srcdir="${src}" destdir="${dest}"/>
<!-- 設置jvm內存
<javac srcdir="src" fork="true"/> 
<javac srcdir="src" fork="true" executable="d:\sdk141\bin\javac" 
memoryMaximumSize="128m"/> 
-->

 

11、java 標簽節點元素

該標簽用來執行編譯生成的.class文件,其屬性如下。 
● classname 表示將執行的類名。 
● jar表示包含該類的JAR文件名。 
● classpath所表示用到的類路徑。 
● fork表示在一個新的虛擬機中運行該類。 
● failonerror表示當出現錯誤時自動停止。 
● output 表示輸出文件。 
● append表示追加或者覆蓋默認文件。

示例

 

<java classname="com.hoo.test.HelloWorld" classpath="${hello_jar}"/>

 

12、arg 數據參數元素

由Ant構建文件調用的程序,可以通過<arg>元素向其傳遞命令行參數,如apply,exec和java任務均可接受嵌套<arg>元素,可以為各自的過程調用指定參數。以下是<arg>的所有屬性。 
● values 是一個命令參數。如果參數中有空格,但又想將它作為單獨一個值,則使用此屬性。 
● file 表示一個參數的文件名。在構建文件中,此文件名相對於當前的工作目錄。 
● line 表示用空格分隔的多個參數列表。 
● 表示路徑,一個作為單個命令行變量的path-like的字符串;或作為分隔符,Ant會將其轉變為特定平台的分隔符。 
● pathref 引用的path(使用path元素節點定義path)的id 
● prefix 前綴 
● suffix 后綴

例子 
<arg value="-l -a"/> 
是一個含有空格的單個的命令行變量。 
<arg line="-l -a"/> 
是兩個空格分隔的命令行變量。 
<arg path="/dir;/dir2:\dir3"/> 
是一個命令行變量,其值在DOS系統上為\dir;\dir2;\dir3;在Unix系統上為/dir:/dir2:/dir3 。

13、ervironment 類型

由Ant構建文件調用的外部命令或程序,<env>元素制定了哪些環境變量要傳遞給正在執行的系統命令,<env>元素可以接受以下屬性。 
● file表示環境變量值的文件名。此文件名要被轉換位一個絕對路徑。 
● path表示環境變量的路徑。Ant會將它轉換為一個本地約定。 
● value 表示環境變量的一個直接變量。 
● key 表示環境變量名。 
注意 file path 或 value只能取一個。

14、filelist 文件集合列表

filelist 是一個支持命名的文件列表的數據類型,包含在一個filelist類型中的文件不一定是存在的文件。以下是其所有的屬性。 
● dir是用於計算絕對文件名的目錄。 
● files 是用逗號分隔的文件名列表。 
● refid 是對某處定義的一個<filelist>的引用。 
注意 dir 和 files 都是必要的,除非指定了refid(這種情況下,dir和files都不允許使用)。

示例

 

<filelist id="docfiles" dir="${doc.src}" files="foo.xml,bar.xml"/> 
文件集合 ${doc.src}/foo.xml和${doc.src}/bar.xml. 這些文件也許還是不存在的文件.
<filelist id="docfiles" dir="${doc.src}" files="foo.xml bar.xml"/> 
 
<filelist refid="docfiles"/> 
 
<filelist id="docfiles" dir="${doc.src}">
    <file name="foo.xml"/>
    <file name="bar.xml"/>
</filelist>

 

15、fileset 文件類型

fileset 數據類型定義了一組文件,並通常表示為<fileset>元素。不過,許多ant任務構建成了隱式的fileset,這說明他們支持所有的fileset屬性和嵌套元素。以下為fileset 的屬性列表。 
● dir表示fileset 的基目錄。 
● casesensitive的值如果為false,那么匹配文件名時,fileset不是區分大小寫的,其默認值為true. 
● defaultexcludes 用來確定是否使用默認的排除模式,默認為true。 
● excludes 是用逗號分隔的需要派出的文件模式列表。 
● excludesfile 表示每行包含一個排除模式的文件的文件名。 
● includes 是用逗號分隔的,需要包含的文件模式列表。 
● includesfile 表示每行包括一個包含模式的文件名。

示例

 

<fileset id="lib.runtime" dir="${lib.path}/runtime">
    <include name="**/*.jar"/>
    <include name="**/*.so"/>
    <include name="**/*.dll"/>
</fileset>
 
<fileset id="lib.container" dir="${lib.path}/container">
    <include name="**/*.jar"/>
</fileset>
 
<fileset id="lib.extras" dir="${lib.path}">
    <include name="test/**/*.jar"/>
</fileset>

 

16、patternset 類型

fileset 是對文件的分組,而patternset是對模式的分組,他們是緊密相關的概念。

<patternset>支持4個屬性:includes、excludex、includexfile、excludesfile,這些與fileset相同。

patternset 還允許以下嵌套元素:include,exclude,includefile 和 excludesfile.

示例

 

<!-- 黑白名單 -->
<patternset id="non.test.sources">
  <include name="**/*.java"/>
  <!-- 文件名包含Test的排除 -->
  <exclude name="**/*Test*"/>
</patternset>
 
 
<patternset id="sources">
  <include name="std/**/*.java"/>
  <!-- 判斷條件 存在professional就引入 -->
  <include name="prof/**/*.java" if="professional"/>
  <exclude name="**/*Test*"/>
</patternset>
 
<!-- 一組文件 -->
<patternset includesfile="some-file"/>
<patternset>
  <includesfile name="some-file"/> 
<patternset/>
 
<patternset>
  <includesfile name="some-file"/> 
  <includesfile name="${some-other-file}" if="some-other-file"/> 
<patternset/>

 

17、filterset 類型

filterset定義了一組過濾器,這些過濾器將在文件移動或復制時完成文件的文本替換。 
主要屬性如下: 
● begintoken 表示嵌套過濾器所搜索的記號,這是標識其開始的字符串。 
● endtoken 表示嵌套過濾器所搜索的記號這是標識其結束的字符串。 
● id 是過濾器的唯一標志符。 
● refid 是對構建文件中某處定義一個過濾器的引用。

示例

 

<!-- 將目標文件build.dir目錄中的version.txt文件內容中的@DATE@替換成TODAY當前日期的值,並把替換后的文件存放在dist.dir目錄中 -->
<copy file="${build.dir}/version.txt" toFile="${dist.dir}/version.txt">
  <filterset>
    <filter token="DATE" value="${TODAY}"/>
  </filterset>
</copy>
 
<!-- 自定義變量的格式 -->
<copy file="${build.dir}/version.txt" toFile="${dist.dir}/version.txt">
  <!-- 從version.txt中的%位置開始搜索,到*位置結束,進行替換內容中的@DATE@替換成TODAY當前日期的值-->
  <filterset begintoken="%" endtoken="*">
    <filter token="DATE" value="${TODAY}"/>
  </filterset>
</copy>
 
<!-- 使用外部的過濾定義文件 -->
<copy toDir="${dist.dir}/docs">
  <fileset dir="${build.dir}/docs">
    <include name="**/*.html">
  </fileset>
  <filterset begintoken="%" endtoken="*">
    <!-- 過來文件從外部引入,過來的屬性和值配置在dist.properties文件中 --> 
    <filtersfile file="${user.dir}/dist.properties"/>
  </filterset>
</copy>
 
<!-- 使用引用方式,重復利用過濾集 -->
<filterset id="myFilterSet" begintoken="%" endtoken="*">
  <filter token="DATE" value="${TODAY}"/>
</filterset>
 
<copy file="${build.dir}/version.txt" toFile="${dist.dir}/version.txt">
  <filterset refid="myFilterSet"/>
</copy>

 

18、path類型

path元素用來表示一個類路徑,不過它還可以用於表示其他的路徑。在用作幾個屬性時,路經中的各項用分號或冒號隔開。在構建的時候,此分隔符將代替當前平台中所有的路徑分隔符,其擁有的屬性如下。 
● location 表示一個文件或目錄。Ant在內部將此擴展為一個絕對路徑。 
● refid 是對當前構建文件中某處定義的一個path的引用。 
● path表示一個文件或路徑名列表。

示例

 

<path id="buildpath">
    <fileset refid="lib.runtime"/>
    <fileset refid="lib.container"/>
    <fileset refid="lib.extras"/>
</path>
 
<path id="src.paths">
    <fileset id="srcs" dir=".">
        <include name="src/**/*.java"/>
    </fileset>
</path>

 

 

六、ant編譯打包、運行工程

 

<?xml version="1.0" encoding="UTF-8"?>
<!-- name是當前工程的名稱,default是默認執行的任務,basedir是工作目錄(.代表當前根目錄) -->
<project name="HelloWorld" default="run" basedir=".">
    <!-- property類似於程序中定義簡單的變量 -->
    <property name="src" value="src"/>
    <property name="dest" value="classes"/>
    <property name="hello_jar" value="helloWorld.jar"/>
    <!-- 
    target是一個事件、事情、任務, name是當前事情的名稱,depends是依賴的上一件或是多件事情
    如果所依賴的事情沒有執行,ant會先運行依賴事情,然后再運行當前事情
    -->
    
    <!-- 初始化 -->
    <target name="init">
        <!-- 建立classes目錄 -->
        <mkdir dir="${dest}"/>
        <mkdir dir="temp"/>
        <mkdir dir="temp2"/>
    </target>
    
    <!-- 編譯 -->
    <target name="compile" depends="init">
        <javac srcdir="${src}" destdir="${dest}"/>
        <!-- 設置jvm內存
        <javac srcdir="src" fork="true"/> 
        <javac srcdir="src" fork="true" executable="d:\sdk141\bin\javac" 
        memoryMaximumSize="128m"/> 
        -->
    </target>
    
    <!-- 建立jar包 -->
    <target name="build" depends="compile">
        <!-- 
        <jar jarfile="${hello_jar}" basedir="${dest}"/>
        創建一個名稱是package.jar文件
        <jar destfile="package.jar" basedir="classes"/> 
        -->
        <jar destfile="${hello_jar}" basedir="classes"> 
            <!-- 向jar包中的main文件中添加內容 -->
            <manifest> 
                <attribute name="Built-By" value="${user.name}"/> 
                <attribute name="Main-class" value="package.Main"/> 
            </manifest> 
        </jar> 
        <!-- 復制jar文件  todir="復制到目錄"-->
        <copy file="${hello_jar}" tofile="${dest}\temp.jar"/> 
        <copy todir="temp"> 
            <!-- 不按照默認方式 defaultexcludes="" -->
              <fileset dir="src"> 
                <include name="**/*.java"/>
              </fileset> 
        </copy> 
        
        <copy todir="temp2"> 
            <fileset dir="src">
                <and>
                    <contains text="main"/> 
                    <size value="1" when="more"/> 
                </and>
            </fileset>
        </copy> 
        
        <!-- 移動jar文件 -->
        <move file="${dest}\temp.jar" tofile="temp\move-temp.jar"/> 
        <!-- 創建zip -->
        <zip basedir="${basedir}\classes" zipfile="temp\output.zip"/> 
        <!-- 創建tgz -->
        <gzip src="classes\**\*.class" zipfile="output.class.gz"/>
        <!-- 解壓zip -->
        <unzip src="output.class.gz" dest="extractDir"/> 
        <!--替換input.txt內容中的old為new
        <replace file="input.txt" token="old" value="new"/>
        --> 
    </target>
    
    <!-- 運行 -->
    <target name="run" depends="build">
        <java classname="com.hoo.test.HelloWorld" classpath="${hello_jar}"/>
    </target>
    
    <!-- 清除 -->
    <target name="clean">
        <!-- 刪除生成的文件 -->
        <delete dir="${dest}"/>
        <delete file="${hello_jar}"/>
    </target>
    
    <tstamp> 
       <format property="OFFSET_TIME" 
               pattern="HH:mm:ss" 
               offset="10" unit="minute"/> 
    </tstamp>
    
    <!-- 重新運行 -->
    <target name="rerun" depends="clean,run">
        <echo message="###${TSTAMP}#${TODAY}#${DSTAMP}###"/>
        <aunt target="clean"/>
        <aunt target="run"/>
    </target>
</project>

 

要說的的東西基本上就那么多,ant還有很多內容沒有提到,有興趣的可以自己去研究研究。ant不難,你用它就像是在docs控制台輸入命令行一樣,只不過ant是將命令行轉換為xml的腳本信息,可以進行重復的運行。在一定情況下,提高了效率和重復的工作。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM