持续集成之Ant的使用

来源:互联网 发布:凸包问题的分治算法 编辑:程序博客网 时间:2024/05/18 16:14

如果项目是标准的maven结构项目,且打包无特别需求,直接执行maven打个war包,或者直接部署都是很简单的事。

但事实上,很多情况都不是那么理想的。例如,本人项目中就涉及到不同环境的配置文件处理,前后台包的处理,增量包,全量包,主干包的处理,SVN server的操作….

所有的这些,maven 是无法为您定制一套标准流程的。这时,您需要的ant. 任意的想法自行编码实现。

 

Ant 介绍

著名的打包工具。 Apache开源项目 http://ant.apache.org/它通过执行定义好的一串target流程,完成用户期望的各种任务。

具体介绍可以上官网。具体命令可以查manual. Ant在文档上还算是做得比较细致的。

 

Ant

Ant本身支持很多常用的命令,但也有一些命令不支持或支持得不好.这时可以引入一些ant库,以强大ant的功能。

本项目中引入的有: svnlib, ant-contrib, ant-props

 

此外,项目中需要js压缩,在此引入了 YUI库。

 

 

本项目的打包需求

打包:

1)       按不同的部署环境更换配置文件

2)       压缩JS

3)       删除文件

删除一些包中不需要出现的文件

(例如,有些jar包在部署的应用服务器中存在,包中不应再有;前台包不需要后台文件…)

 

4)       校验手工维护的增量文件及 svn log 的一致性

5)       打包: 增量包,全量包,主干包

6)       上传包文件到SVN 服务器

  部署

7)       部署到应用服务器

Weblogic, 增量包+主干包 或者全量包

 

 

打包实现

大致分为两个xml文件. Build.xml负责打包,提交svn Deploy.xml负责部署工作。

 

1.       Deploy.xml  调用部署脚本,部署增量/全量包

<project name=”projecctName-deploy” default=”deploy”>

<import file=”./build.xml” as=”build” />

<property name=”deployShell-incremental.dir” value=”xxxxx” />

<property name=”deployShell-full.dir” value=”yyyy” />

 

<target name=”deploy” depends=”build.packAndUpload”>

  <if>

<!—分前后台出包à

<then>

   <antcall target=”_deploy_withPackType” />

</then>

<else>

  <antcall target=”_deploy_noPackType” />

</else>

  </if>

</target>

 

 

<!—不区分前后台部署à

<target name=” _deploy_noPackType”>

  <!—全量包路径à

  <property name=”fullZip.dir”

Value=”${basedir}/${workingPath}${package.name.prefix.noType}_full.zip” />

 <!—增量包路径à

<property name=”incrementalZip.dir”

Value=”${basedir}/${workingPath}${package.name.prefix.noType}${incrementalZip.subfix}.zip” />

<!—主干包路径. (即上一版本的全量包)à

<property name=”baseline.dir”

Value=”${basedir}/${workingPath}${package.name.prefix.baseline}.zip” />

 

  <if>

     <!—如果是部署全量包à

<isset property=”deploy-full” />

 <then>

  <echo message=”deploy full zip” />

   <!—调用全量包部署脚本执行部署à

   <exec executable=”${ deployShell-full.dir}”>

     <arg value=”${fullZip.dir}” />

</exec>

 </then>

<else>

  <!—未指定为全量部署,即采用增量部署方式à

   <echo message=”deploy base+incremental” />

   <exec executable=”${ deployShell-incremental.dir}”>

     <arg value=”${baseline.dir}” />

     <arg value=”${ fullZip.dir}” />  <!—一般不需要.为方面部署脚本一并传过去à

     <arg value=”${ incrementalZip.dir}” />

</exec>

 

</else>

  </if>

</target>

 

 

<!—分前后台包部署à

<target name=”_deploy_withPackType”>

  <echo message=”deploy with type” />

 

<!—定义部署脚本à

  <if>

<isset property=”deploy-full” />

<then>

   <var name=”shell.dir” value=”${ deployShell-full.dir }” />

</then>

<else>

<var name=”shell.dir” value=” ${ deployShell-incremental.dir}” />

</else>

  </if>

 

  <property name=”baseline.dir”

  Value=” ${basedir}/${workingPath}${package.name.prefix.baseline}.zip” />

 <!—前台全量包,增量包定义à

 <property name=”F_full” Value=”..” />

<property name=”F_incremental” Value=”..” />

 

<!—后台全量包,增量包定义à

 <property name=”B_full” Value=”..” />

<property name=”B_incremental” Value=”..” />

 

 <!—调用部署脚本执行分包部署à

 <!—可能会觉得,上面脚本定义时,已经特别区分了全量/增量部署脚本,为什么这里的参数又不区分,把所有的包都传过去?其实跟前面的不分前后台部署是一样的:确认脚本可能不需要,但传过去也无妨。如果脚本需要验证包什么的,可能会用上。当然,真要觉得别扭,也可能把它们干掉à

 <exec executable=”${shell.dir}”>

   <arg value=”${ baseline.dir }” />

   <arg value=”${ F_full }” />

   <arg value=”${ F_incremental }” />

   <arg value=”${ B_full }” />

   <arg value=”${ B_incremental }” />

</exec>

 

</target>

 

可见,deploy脚本还是很清晰的,就是调用个部署脚本,传参给它。因为部署脚本分了两个分前后台部署的脚本和不分前后台部署的脚本.所以在调用脚本前,做了个判断。

 

 

2.       Build.xml 

 

因为build.xml涉及的情况较为复杂,有各种不同的设置组合。这里引入了一个properties文件

 

2.1 Build-sit.properties Build-env.properties

#sit

 

#source dir or source SVN Server Path

#目前编译直接交由maven处理.执行完后由jenkins调用ant执行后续流程,所以目前采用war路径

#src.svn=http://ip/path/trunk/....

war.dir=./projectName/target/projectName.war

 

#envirment attributes 配置文件替换目录

env.repaceconfig.foldname=sit

 

#F:front; B:back; BB:back-batch

#配置是否分前后台出包.如果部分,则直接把该属性注释掉

package.types=F,B

 

#设置打包不包括的文件清单.如不设置则不处理

#_F 存在时,打前台包优先取_F文件.如果找不到_F,则取exclude.filelist对象对应文件

exclude.filelist=./excludeFileList.txt

exclude.filelist_F=./excludeFileList_F.txt

exclude.filelist_B=./excludeFileList_B.txt

 

 

#compress js file. if "true", compress

#不设置则不压缩

js.commpress=true

 

#设置打包增量文件清单.如果是只打打全量包,不需要设置. _F,_B文件同上述exclude文件效果

incremental.filelist=./version/filelist.txt

incremental.filelist_F=./version/filelist_F.txt

incremental.filelist_B=./version/filelist_B.txt

 

#zip files upload path. if not exists, ignore upload

svn.upload.path=https://ip:port/path

svn.username=xxxx

svn.password=yyy

 

 

2.2 build.xml

 

<project name="projectName" default="packAndUpload"

xmlns:props="antlib:org.apache.ant.props">

<!-- pass by argument propFile -Dname=value -->

    <propertyfile="${buildProperty}"/>

    <propertyname="libPath"value="./lib/"/>

 

    <!--工作区设置-->

    <propertyname="buildPath"value="./pack/"/>

    <propertyname="workingPath"value="${buildPath}workspace/"/>

    <propertyname="commonPath"value="${workingPath}common/"/>

 

    <propertyname="package.name.prefix.front"value="Project_F"/>

    <propertyname="package.name.prefix.back"value="Project_B"/>

    <propertyname="package.name.prefix.back-batch"value=" Project_B_BATCH"/>

    <propertyname="package.name.prefix.noType"value="Project"/>

 

    <typedefuri="antlib:org.apache.ant.props"resource="org/apache/ant/props/antlib.xml"classpath="${libPath}ant-props-1.0Alpha.jar"/>

    <propertyhelper>

        <props:nested/>

    </propertyhelper>

 

    <taskdefresource="net/sf/antcontrib/antlib.xml">

        <classpath>

            <pathelementlocation="${libPath}ant-contrib.jar"/>

        </classpath>

    </taskdef>

 

    <taskdefresource="org/tigris/subversion/svnant/svnantlib.xml">

        <classpath>

            <filesetdir="${libPath}svnlib">

                <includename="*.jar"/>

            </fileset>

        </classpath>

    </taskdef>

 

 

<!-- 清空打包路径内容-->

    <targetname="clean">

        <echomessage="delete ${buildPath}"/>

 

        <availablefile="${buildPath}"type="dir"property="buildPathExists"/>

        <if>

            <issetproperty="buildPathExists"/>

            <then>

                <deleteincludeemptydirs="true">

                    <filesetdir="${buildPath}"/>

                </delete>

            </then>

        </if>

 

    </target>

 

    <targetname="packAndUpload">

        <antcalltarget="pack"/>

 

        <antcalltarget="upload"/>

    </target>

 

 

 

    <!--打包-->

    <targetname="pack">

        <!--1.unpack war to working dir -->

        <antcalltarget="_prepareWorkingPath"/>

 

        <!-- 2.compress js files -->

        <antcalltarget="_compressJSFiles"/>

 

        <if>

            <!--是否区分前后台出包.不设置表示不区分 -->

            <issetproperty="package.types"/>

            <then>

                <!--按前台后出包 -->

                <foreachtarget="_createZipByType"list="${package.types}"param="package.type"delimiter=","/>

            </then>

 

            <else>

                <echomessage="不区分前后台打包"/>

                <antcalltarget="_createZip"/>

 

            </else>

        </if>

 

 

    </target>

 

    <!--准备打包工作区环境-->

    <targetname="_prepareWorkingPath"depends="clean">

        <echomessage="mkdir"/>

        <mkdirdir="${commonPath}"/>

 

        <echomessage="unzip war files to working path:${commonPath}"/>

        <unzipsrc="${war.dir}"dest="${commonPath}"/>

 

    </target>

 

    <!--压缩js文件。 -->

    <targetname="_compressJSFiles">

        <if>

            <!—检查配置文件,是否有设置压缩js属性à

            <and>

                <issetproperty="js.commpress"/>

                <equalsarg1="${js.commpress}"arg2="true"/>

            </and>

            <then>

                 <!—循环js目录下的js文件,调用YUI进行压缩-->

                 <!—按代码规范,js统一放在resources/js目录下,因此未提供属性设置js目录à

                <foreachtarget="_doCompress"param="jsFile">

                    <path>

                        <filesetdir="${commonPath}/resources/js">

                            <includename="*.js"/>

                        </fileset>

                    </path>

                </foreach>

            </then>

            <else>

                <echomessage="ignore js compress"/>

            </else>

        </if>

 

 

    </target>

 

    <!--调用 yuicompressor执行js文件压缩-->

    <targetname="_doCompress">

        <echomessage="compressing ${jsFile}"/>

        <echomessage="this operation would override the originall js file"/>

        <javajar="${libPath}/yuicompressor-2.4.2.jar"dir="."fork="true"failonerror="true">

 

            <argline="${jsFile} -o ${jsFile} --charset UTF-8 --nomunge "/>

           

        </java>

    </target>

 

 

    <!--打包,不区分前后台-->

    <targetname="_createZip">

        <antcall>

            <targetname="_initProperties_NoPackageType"/>

            <targetname="_createWorkingPath_NoPackageType"/>

            <targetname="_deleteFilesIfNeeded"/>

            <targetname="_writeEnvFiles"/>

            <targetname="_fullzip"/>

            <targetname="_incrementalZip"/>

        </antcall>

    </target>

 

    <!--设置与打包环境相关的属性-->

    <targetname="_initProperties_NoPackageType">

     <!—目标项目名称à

        <varname="package.name.prefix"value="${package.name.prefix.noType}"/>

         <!—配置文件替换目录à

        <varname="propertiesReplaceFoldName"value="${env.repaceconfig.foldname}"/>

         <! – 上传svn 目录的子目录名。例如,当需要分前后台包时,可设置为FrontBack等。这里为不分前后台,故设为空-- >

        <varname="svn.packageType"value=""/>

    </target>

 

    <targetname="_createWorkingPath_NoPackageType">

        <!—war目录文件 copy处理目录.处理目录内容的文件会应打包需求修改 -->

        <movetodir="${workingPath}${package.name.prefix}">

            <filesetdir="${commonPath}"/>

        </move>

    </target>

 

    <!--根据打包类型:前台/后台/后台批量 替换配置文件并打包-->

    <targetname="_createZipByType">

        <antcall>

            <targetname="_initPropertiesByType"/>

            <targetname="_createFrontBackWorkingPath"/>

            <targetname="_deleteFilesIfNeeded"/>

            <targetname="_writeEnvFiles"/>

            <targetname="_fullzip"/>

            <targetname="_incrementalZip"/>

        </antcall>

    </target>

 

    <!--设置与打包环境,类型相关的属性-->

    <targetname="_initPropertiesByType">

        <echomessage="type = ${package.type}"/>

        <!--根据packageType准备参数-->

        <if>

            <equalsarg1="${package.type}"arg2="F"/>

            <then>

                 <!—各参数与上述参数(不分前后台打包)作用一样à

                <varname="package.name.prefix"value="${package.name.prefix.front}"/>

                <varname="propertiesReplaceFoldName"value="${env.repaceconfig.foldname}-front"/>

                <varname="svn.packageType"value="front"/>

 

            </then>

 

            <elseif>

                <equalsarg1="${package.type}"arg2="B"/>

                <then>

                    <varname="package.name.prefix"value="${package.name.prefix.back}"/>

                    <varname="propertiesReplaceFoldName"value="${env.repaceconfig.foldname}-back"/>

                    <varname="svn.packageType"value="back"/>

 

                </then>

 

            </elseif>

 

            <elseif>

                <equalsarg1="${package.type}"arg2="BB"/>

                <then>

                    <varname="package.name.prefix"value="${package.name.prefix.back-batch}"/>

                    <varname="propertiesReplaceFoldName"value="${env.repaceconfig.foldname}-back-batch"/>

                    <varname="svn.packageType"value="back-batch"/>

 

                </then>

            </elseif>

 

            <else>

                 <! – 按本项目需求,只支持F,B,BB三种类型的包。如果是其他值,则报打包类型错误à

                <echolevel="error"message="invalid package.type:${package.type} "/>

            </else>

        </if>

    </target>

 

    <! –copy文件到工作目录 à

    <targetname="_createFrontBackWorkingPath">

        <copytodir="${workingPath}/${package.name.prefix}">

            <filesetdir="${commonPath}"/>

        </copy>

    </target>

 

  <!—如有配置,删除exclude 文件 à

    <targetname="_deleteFilesIfNeeded">

        <propertyname="exclude.filelist_X"value="exclude.filelist_${package.type}"/>

        <availablefile="${exclude.filelist}"type="file"property="exclude.filelist.present"/>

        <availablefile="${${exclude.filelist_X}}"type="file"property="exclude.filelist_X.present"/>

 

        <if>

             <!—优先取前后台对应 _f或者 _B … 文件à

           <issetproperty="exclude.filelist_X.present"/>

            <then>

                <echomessage="use exclude.filelist_X: ${${exclude.filelist_X}}"/>

 

                <delete>

                    <filesetdir="${workingPath}${package.name.prefix}">

                        <includesfilename="${${exclude.filelist_X}}"/>

                    </fileset>

                </delete>

            </then>

            <elseif>

                 <! –取默认的exclude文件 -- >

                <issetproperty="exclude.filelist.present"/>

                <then>

                    <echomessage="use exclude.filelist: ${exclude.filelist}"/>

 

                    <delete>

                        <filesetdir="${workingPath}${package.name.prefix}">

                            <includesfilename="${exclude.filelist}"/>

                        </fileset>

                    </delete>

                </then>

            </elseif>

        </if>

 

    </target>

 

    <!--根据环境参数,替换文件 -->

    <targetname="_writeEnvFiles">

        <echomessage=" override properties with enviroment files:propertiesReplaceFoldName = ${propertiesReplaceFoldName}"/>

        <propertyname="propertiesReplaceBasePath"value="WEB-INF/classes/replaceconfig/"/>

        <!—替换文件 à

        <copytodir="${workingPath}${package.name.prefix}"overwrite="true">

            <filesetdir="${workingPath}${package.name.prefix}/${propertiesReplaceBasePath}${propertiesReplaceFoldName}">

            </fileset>

        </copy>

    </target>

 

    <!--打全量包 -->

    <targetname="_fullzip">

        <! –调方法获取全量包名字. (全量包名字由该方法按规则生成)à

        <antcallbacktarget="getFullZipName"return="fullZipName">

            <paramname="prefix"value="${package.name.prefix}"/>

        </antcallback>

        <echomessage="creating full package=${fullZipName}"/>

 

        <zipdestfile="${workingPath}${fullZipName}"encoding="UTF-8">

            <filesetdir="${workingPath}${package.name.prefix}">

            </fileset>

        </zip>

    </target>

 

    <!--打增量包 -->

    <targetname="_incrementalZip">

        <!--判断是否需要生成增量包 -->

        <propertyname="incremental.filelist_X"value="incremental.filelist_${package.type}"/>

        <availablefile="${incremental.filelist}"type="file"property="incremental.filelist.present"/>

        <availablefile="${${incremental.filelist_X}}"type="file"property="incremental.filelist_X.present"/>

        <if>

            <issetproperty="incremental.filelist_X.present"/>

            <then>

                <echomessage="use incremental filelist:${${incremental.filelist_X}}"/>

                <varname="incremental.filelist.working"value="${workingPath}incrementalFilelist_${package.type}.txt"/>

                <copyfile="${${incremental.filelist_X}}"tofile="${incremental.filelist.working}"overwrite="true"/>

            </then>

            <elseif>

                <issetproperty="incremental.filelist.present"/>

                <then>

                    <echomessage="use incremental filelist:${incremental.filelist}"/>

                    <varname="incremental.filelist.working"value="${workingPath}incrementalFilelist.txt"/>

                    <copyfile="${incremental.filelist}"tofile="${incremental.filelist.working}"overwrite="true"/>

                </then>

            </elseif>

            <else>

                <echomessage="incremental file list not set.ignore cremental zip"/>

            </else>

        </if>

 

 

        <if>

            <!-如果有设置增量文件à

            <or>

                <issetproperty="incremental.filelist_X.present"/>

                <issetproperty="incremental.filelist.present"/>

            </or>

            <then>

                 <!—生成增量文件名称 à

                <antcallbacktarget="getIncrementalZipName"return="incrementalZipName">

                    <paramname="prefix"value="${package.name.prefix}"/>

                </antcallback>

 

                <echomessage="creating incremental package=${incrementalZipName}"/>

 

                <!--转换增量文件列表 Pattern File list使其支持内部类-->

                <propertyname="incremental.filelist.innerclass.working"value="${workingPath}incrementalFilelist_innerclass_${package.type}.txt"/>

                <copyfile="${incremental.filelist.working}"tofile="${incremental.filelist.innerclass.working}"overwrite="true"/>

                <replacefile="${incremental.filelist.innerclass.working}"token=".class"value="$*.class"/>

 

                <zipdestfile="${workingPath}${incrementalZipName}"encoding="UTF-8"whenempty="skip">

                    <filesetdir="${workingPath}${package.name.prefix}">

                        <includesfilename="${incremental.filelist.working}"/>

                        <includesfilename="${incremental.filelist.innerclass.working}"/>

 

                        <!--

                                       *.txt   (patten,split by line)

                                       abs?ct.a?b

                                        -->

 

                    </fileset>

                </zip>

               

            </then>

        </if>

 

 

    </target>

 

    <!—上传包到svn server à

    <targetname="upload">

        <if>

            <!--是否区分前后台出包 -->

            <and>

                <issetproperty="svn.upload.path"/>

                <issetproperty="package.types"/>

            </and>

            <then>

                <!--上传前台后包 -->

                <foreachtarget="_uploadZipByPackageType"list="${package.types}"param="package.type"delimiter=","/>

 

                <!--上传common -->

                <!--

                <target name="doSvnAdd">

                    <param name="localFile" value="${workingPath}${fullZipName}" />

                    <param name="repositoryURL" value="${svn.upload.path}/${svn.packageType}/${fullZipName}" />

                </target>

                -->

            </then>

 

            <elseif>

                <issetproperty="svn.upload.path"/>

                <then>

                    <echomessage="上传包"/>

                    <targetname="_uploadZipNoType"/>

 

                </then>

            </elseif>

        </if>

 

        <if>

            <and>

                <issetproperty="svn.upload.path"/>

                <issetproperty="package.types"/>

            </and>

            <then>

 

            </then>

            <else>

                <echomessage="svn upload path does not exists. ignore..."/>

            </else>

        </if>

 

    </target>

 

    <targetname="_uploadZipNoType">

        <antcall>

            <targetname="_initProperties_NoPackageType"/>

            <targetname="_uploadZips"/>

        </antcall>

    </target>

 

    <!--上传包到SVN Server.仅针对前后台打包情况-->

    <targetname="_uploadZipByPackageType">

        <antcall>

            <targetname="_initPropertiesByType"/>

            <targetname="_uploadZips"/>

        </antcall>

    </target>

 

    <targetname="_uploadZips">

        <echomessage="svnUploadFullPath=${svn.upload.path}/${svn.packageType}"/>

        <echomessage="upload full zip"/>

        <antcallbacktarget="getFullZipName"return="fullZipName">

            <paramname="prefix"value="${package.name.prefix}"/>

        </antcallback>

        <antcalltarget="doSvnAdd">

            <paramname="localFile"value="${workingPath}${fullZipName}"/>

            <paramname="repositoryURL"value="${svn.upload.path}/${svn.packageType}/${fullZipName}"/>

        </antcall>

 

        <echomessage="upload incremental zip"/>

        <antcallbacktarget="getIncrementalZipName"return="incrementalZipName">

            <paramname="prefix"value="${package.name.prefix}"/>

        </antcallback>

 

        <availablefile="${workingPath}${incrementalZipName}"property="incrementalzip.present"/>

        <if>

            <issetproperty="incrementalzip.present"/>

            <then>

                <antcalltarget="doSvnAdd">

                    <paramname="localFile"value="${workingPath}${incrementalZipName}"/>

                    <paramname="repositoryURL"value="${svn.upload.path}/${svn.packageType}/${incrementalZipName}"/>

                </antcall>

            </then>

            <else>

                <echomessage="incremental zip does not exists. ignore upload"/>

            </else>

        </if>

 

 

    </target>

 

    <targetname="doSvnAdd">

 

        <if>

            <svnExiststarget="${repositoryURL}"/>

            <then>

                <echomessage="svn target already exists. delete+import?"/>

 

                <svnsvnkit="true"javahl="false"username="${svn.username}"password="${svn.password}"failonerror="true">

                    <deleteurl="${repositoryURL}"message="To replace this file with the following import operation."/>

                    <importpath="${localFile}"url="${repositoryURL}"message=" build zip script"/>

                </svn>

            </then>

            <else>

                <echomessage="svn target does not exists, use import."/>

                <svnsvnkit="true"javahl="false"username="${svn.username}"password="${svn.password}"failonerror="true">

                    <importpath="${localFile}"url="${repositoryURL}"message=" build zip script"/>

                </svn>

            </else>

        </if>

 

    </target>

 

    <targetname="getIncrementalZipName">

        <propertyname="incrementalZipName"value="${prefix}_incremental.zip"/>

    </target>

 

    <targetname="getFullZipName">

        <propertyname="fullZipName"value="${prefix}_full.zip"/>

    </target>

 

</project>

原创粉丝点击