代码的重复是件麻烦事,配置文件的重复也让人不爽。当配置文件出现bad smell时,也要着手进行重构了。
当在CruiseControl(以下简称cc)监控多个项目时,config.xml很容易出现大堆的重复配置。比如我的:
<cruisecontrol>
<property file="common.properties" />
<property name="anthome" value="apache-ant-1.7.0" />
<project name="cc">
<listeners>
<currentbuildstatuslistener file="logs/${project.name}/status.txt"/>
</listeners>
<modificationset quietperiod="30">
<svn RepositoryLocation="${svnloc}/${project.name}" username="${user}" password="${password}"/>
</modificationset>
<schedule interval="20">
<ant anthome="${anthome}" buildfile="buildfiles/${project.name}.xml" target="update"/>
</schedule>
<publishers>
<onsuccess>
<antpublisher anthome="${anthome}" buildfile="buildfiles/${project.name}.xml" target="deploy"/>
</onsuccess>
</publishers>
</project>
<project name="dd">
<listeners>
<currentbuildstatuslistener file="logs/${project.name}/status.txt"/>
</listeners>
<modificationset quietperiod="30">
<svn RepositoryLocation="${svnloc}/${project.name}" username="${user}" password="${password}"/>
</modificationset>
<schedule interval="20">
<ant anthome="${anthome}" buildfile="buildfiles/${project.name}.xml" target="update"/>
</schedule>
<publishers>
<onsuccess>
<antpublisher anthome="${anthome}" buildfile="buildfiles/${project.name}.xml" target="deploy"/>
</onsuccess>
</publishers>
</project>
</cruisecontrol>
当存在多个project时,由于每个project的处理过程是一模一样的,因此配置写了重复的n次。使用plugin定义模板来改变:
<cruisecontrol>
<property file="common.properties" />
<property name="anthome" value="apache-ant-1.7.0" />
<!-- template -->
<plugin name="project">
<listeners>
<currentbuildstatuslistener file="logs/${project.name}/status.txt"/>
</listeners>
<!-- monitoring the svn change -->
<modificationset quietperiod="30">
<svn RepositoryLocation="${svnloc}/${project.name}" username="${user}" password="${password}"/>
</modificationset>
<!-- task -->
<schedule interval="20">
<ant anthome="${anthome}" buildfile="buildfiles/${project.name}.xml" target="update"/>
</schedule>
<!-- publish -->
<publishers>
<onsuccess>
<antpublisher anthome="${anthome}" buildfile="buildfiles/${project.name}.xml" target="deploy"/>
</onsuccess>
</publishers>
</plugin>
<!-- 1..n project -->
<project name="cc"/>
<project name="dd"/>
</cruisecontrol>
有更多的project都只需添加一句话而已。plugin的使用可参考官方
http://cruisecontrol.sourceforge.net/main/plugins.html。其中name属性如果是cc默认定义的,可以不加classname属性,比如这里的name="project"。
由于cc经常和ant配合使用,ant也容易出现大堆的重复配置。比如我的:
cc.xml
<project name="cc" basedir=".">
<property file="../common.properties" />
<property name="project" value="../projects/${ant.project.name}" />
<property name="tomcat" value="../apache-tomcat-5.5.26/webapps" />
<typedef resource="org/tigris/subversion/svnant/svnantlib.xml" />
<target name="checkout">
<svn username="${user}" password="${password}">
<checkout url="${svnloc}/${ant.project.name}"
destPath="${project}"/>
</svn>
</target>
<target name="update">
<svn username="${user}" password="${password}">
<update dir="${project}"/>
</svn>
<!-- war -->
<ant dir="${project}"/>
</target>
<target name="deploy">
<copy todir="${tomcat}">
<fileset dir="${project}/war"/>
</copy>
</target>
</project>
dd.xml
<project name="dd" basedir=".">
<property file="../common.properties" />
<property name="project" value="../projects/${ant.project.name}" />
<property name="tomcat" value="../apache-tomcat-5.5.26/webapps" />
<typedef resource="org/tigris/subversion/svnant/svnantlib.xml" />
<target name="checkout">
<svn username="${user}" password="${password}">
<checkout url="${svnloc}/${ant.project.name}"
destPath="${project}"/>
</svn>
</target>
<target name="update">
<svn username="${user}" password="${password}">
<update dir="${project}"/>
</svn>
<!-- war -->
<ant dir="${project}"/>
</target>
<target name="deploy">
<copy todir="${tomcat}">
<fileset dir="${project}/war"/>
</copy>
</target>
</project>
cc.xml和dd.xml几乎一模一样,只是project name不同而已。使用import task来改变:
先定义公共的xml,这里为import.xml:
<!-- this project name is unuseful -->
<project name="import">
<property file="../common.properties" />
<property name="project" value="../projects/${ant.project.name}" />
<property name="tomcat" value="../apache-tomcat-5.5.26/webapps" />
<typedef resource="org/tigris/subversion/svnant/svnantlib.xml" />
<target name="checkout">
<svn username="${user}" password="${password}">
<checkout url="${svnloc}/${ant.project.name}"
destPath="${project}"/>
</svn>
</target>
<target name="update">
<svn username="${user}" password="${password}">
<update dir="${project}"/>
</svn>
<!-- war -->
<ant dir="${project}"/>
</target>
<target name="deploy">
<copy todir="${tomcat}">
<fileset dir="${project}/war"/>
</copy>
</target>
</project>
在cc.xml和dd.xml中import进来即可:
cc.xml
<project name="cc" basedir=".">
<import file="import.xml" />
</project>
dd.xml
<project name="dd" basedir=".">
<import file="import.xml" />
</project>
需要注意的是,import.xml中的project name是没用的,${ant.project.name}不是指该值,而是指最上层引用的xml的project name。比如cc.xml引用了import.xml,那么${ant.project.name}是指cc.xml的project name。import task有点复制代码的味道。
参考:
http://www.blogjava.net/chelsea/archive/2008/03/06/184374.html
http://cruisecontrol.sourceforge.net/main/plugins.html
http://ant.apache.org/manual/index.html