持续集成之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 目录的子目录名。例如,当需要分前后台包时,可设置为Front,Back等。这里为不分前后台,故设为空-- >
<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>
- 持续集成之Ant的使用
- 持续集成工具Sonar的使用(二)[ant+sonar]
- 使用CruiseControl+SVN+ANT实现持续集成之二环境搭建和配置介绍
- 使用CruiseControl+SVN+ANT实现持续集成之三构建操作及监视
- 使用SVN+CruiseControl+ANT实现持续集成之二----环境搭建和配置介绍
- 使用SVN+CruiseControl+ANT实现持续集成之三----构建操作及监视
- Jmeter接口持续集成之ANT执行Jmeter脚本
- 使用SVN+CruiseControl+ANT实现持续集成之一----持续集成概念及CC原理介绍
- 使用SVN+CruiseControl+ANT实现持续集成之一持续集成概念及CC原理介绍
- 使用SVN+CruiseControl+ANT实现持续集成之一----持续集成概念及CC原理介绍
- cruisecontrol、ant、svn持续集成
- CruiseContinue+ANT持续集成错误
- Jenkins+Ant+Jmeter持续集成
- Jenkins+Ant+Git持续集成
- jmeter持续集成+ant+jenkins
- Ant、Jmeter Jenkins持续集成
- Jenkins构建Android项目持续集成之findbugs的使用
- Jenkins构建Android项目持续集成之findbugs的使用
- 【基础】Linux文件系统(总结)
- Python正则表达式操作指南
- 02-JavaWeb-XML-xml语法-DTD语法
- DeviceIOcontrol 实战 1
- test
- 持续集成之Ant的使用
- SUG-UAP项目中配置文件解析
- uva 10085 The most distant state(八数码)
- 内存热插拔
- poj 1195 Mobile phones
- Tree.js
- 多态性复习
- URAL 1931 Excellent Team 解题报告
- oracle中特殊字符的模糊查询