Friday, April 13, 2012

ANT example on how to control whether to perform building or not depending on the version in your local perforce repository

Assume you have the ANT build procedure intended to be run on demand. Assume also you would like to automatically check if you have the latest version of your source files in your local version control repository (that is certainly not a problem if you use building as a part of continuous integration flow). This example shows how to design such the procedure using perforce version control. The same approach can be used for any command-line VC-system.

Say that will be enough to use the following properties to make your solution customizable:
changelist.to.sync.number - the number of changelist. Being not set means you'd like to sync the head revision
p4.hostp4.portp4.userp4.passwordp4.client - set of properties to establish the connection to perforce server
p4.project.path - path to project to sync on perforce server
email.serveremail.portemail.passwordemail.useremail.sender.aliasemail.sender.from, email.to - set of properties to establish connection with email server.

Here is the ANT script doing what we want to

<project name="deploy.on.demand" default="default">
 
 <!-- Load properties to customize particular run -->
 <property file="${basedir}/builder.properties"/>
 
 <target name="default">

  <!-- Build the suffix for p4 cmd line -->
  <condition property="changelist.to.sync" else="#head" value="@${changelist.to.sync.number}">
   <isset property="changelist.to.sync.number"/>
  </condition>
  
  <!-- Call perforce sync command -->
  <exec executable="p4" failonerror="true" outputproperty="exec.output">
   <arg value="-p${p4.host}:${p4.port}"/>
   <arg value="-u${p4.user}"/>
   <arg value="-P${p4.password}"/>
   <arg value="-c${p4.client}"/>
   <arg value="sync"/>
   <arg value="${p4.project.path}/...${changelist.to.sync}"/>
  </exec>
  
  <!-- Parce perforce output to figure out if you have the latest virsion -->
  <condition property="dont.do.further.actions">
   <contains string="${exec.output}" substring="file(s) up-to-date"/>
  </condition>

  <!-- Call actual build procedure if you don't have one-->
  <antcall target="futher.actions"/>
  
  <!-- Notify the user you are not going to build if you have one-->
  <antcall target="notify.reject.building"/>
  
 </target> 
 
 <target name="notify.reject.building" if="dont.do.further.actions">
  <mail mailhost="${email.server}" mailport="${email.port}" ssl="flase" password="${email.password}" user="${email.user}" subject="Building rejected!">
   <from name="${email.sender.alias}" address="${email.sender.from}"/>
   <to address="${email.to}"/>
   <message>Building is not going to be performed as you already have requested CL (${changelist.to.sync}) in your local repository</message> 
  </mail>
 </target>

 <target name="futher.actions" unless="dont.do.further.actions">

  <!-- Make actual build here -->
  
 </target>

</project>

First we should execute the command to sync the branch we'd like to build from. To do this we have to convert the desired version number to the syntax perforce understands. Exec target is configured to output the result to the specific property.
Then we parse that property to know if it contains the sub-string perforce returns when it is nothing new to sync. Once it has the corresponding build target is triggered. Otherwise the mail notification is sent so that anyone interested knows the build procedure is not going to be performed.