ant-contrib - if/then/else task - ant

I am using ant, and I have a problem with if/then/else task, (ant-contrib-1.0b3.jar).
I am running something that can be simplified with build.xml below.
I am expecting to obtain from 'ant -Dgiv=Luke' the message
input name: Luke
should be overwritten with John except for Mark: John
but it seems property "giv" is not overwritten inside if/then/else..
input name: Luke
should be overwritten with John except for Mark: Luke
Is it depending from the fact I am using equals task with ${giv} ?
Otherwise what is wrong in my code?
build.xml CODE:
<project name="Friend" default="ifthen" basedir=".">
<property name="runningLocation" location="" />
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="${runningLocation}/antlib/ant-contrib-1.0b3.jar" />
</classpath>
</taskdef>
<target name="ifthen">
<echo message="input name: ${giv}" />
<if>
<equals arg1="${giv}" arg2="Mark" />
<then>
</then>
<else>
<property name="giv" value="John" />
</else>
</if>
<echo message="should be overwritten with John except for Mark: ${giv}" />
</target>
</project>

In Ant a property is always set once, after that variable is not alterable anymore.
Here follows a solution using standard Ant (without ant-contrib) which could be useful for the people who does not want an extra dependency.
<target name="test" >
<echo message="input name: ${param}" />
<condition property="cond" >
<equals arg1="${param}" arg2="Mark" />
</condition>
</target>
<target name="init" depends="test" if="cond">
<property name="param2" value="Mark" />
</target>
<target name="finalize" depends="init">
<property name="param2" value="John" />
<echo message="should be overwritten with John except for Mark: ${param2}" />
</target>

Ant Properties are very hard to overwrite (if not impossible). What you need is a Variable. These are also defined in the Ant Contrib JAR.
Editing your example:
<target name="ifthen">
<var name="Evangelist" value="${giv}" />
<echo message="input name: ${Evangelist}" />
<if>
<equals arg1="${Evangelist}" arg2="Mark" />
<then>
</then>
<else>
<var name="Evangelist" value="John" />
</else>
</if>
<echo message="should be overwritten with John except for Mark: ${Evangelist}" />
</target>

<project name="Friend" default="ifthen" basedir=".">
<property name="runningLocation" location="" />
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="${runningLocation}/antlib/ant-contrib-1.0b3.jar" />
</classpath>
</taskdef>
<target name="ifthen">
<echo message="input name: ${giv}" />
<if>
<equals arg1="${giv}" arg2="Mark" />
<then>
</then>
<else>
<var name="giv" unset="true"/>
<property name="giv" value="John" />
</else>
</if>
<echo message="should be overwritten with John except for Mark: ${giv}" />
</target>
</project>
We can use var task to unset the property also.

I know this is old, but should prove handy to others searching for a solution.
to re-assign a property without using ant-contrib, use macrodef with a script.
<macrodef name="property-change">
<attribute name="name"/>
<attribute name="value"/>
<sequential>
<script language="javascript"><![CDATA[
project.setProperty("#{name}", "#{value}");
]]></script>
</sequential>
</macrodef>
then in anywhere in ant, just call this like the property tag
<property-change name="giv" value="John"/>
to Implement this in your original version of xml, it would look like this:
<project name="Friend" default="ifthen" basedir=".">
<property name="runningLocation" location="" />
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="${runningLocation}/antlib/ant-contrib-1.0b3.jar" />
</classpath>
</taskdef>
<target name="ifthen">
<echo message="input name: ${giv}" />
<if>
<equals arg1="${giv}" arg2="Mark" />
<then>
</then>
<else>
<property-change name="giv" value="John" />
</else>
</if>
<echo message="should be overwritten with John except for Mark: ${giv}" />
</target>
</project>
This sample is given purely as an example on writing a macro to replace the <var> command in ant-contrib. In a situation like this one, where the <if> command is being used, it makes more sense to use <var> sinnce ant-contrib is already loaded, and <var> might be faster in processing.
Hope this helps.

It is possible to re-assign the value of a property using the ant-contrib 'propertycopy'. This is an alternative to using ant-contrib Variables.
This way the property "giv" can be overwritten.
<target name="ifthen">
<echo message="input name: ${giv}" />
<if>
<equals arg1="${giv}" arg2="Mark" />
<then>
</then>
<else>
<property name="tempName" value="John" />
<propertycopy name="giv" from="tempName" override="true" />
</else>
</if>
<echo message="should be overwritten with John except for Mark: ${giv}" />
</target>
Be aware this assumes the property tempName is not already set to a value other than 'John'.

Related

using if with resourcecontains in and is not returning true value

I'm reading a file that contains a list of files path.
For each file, I would like to know if it contains a substring.
the answer is always false, although part of it should be true.
Here is my target:
<target name="chek-file">
<loadfile property="file" srcfile="c:\tmp\testing.txt"/>
<for param="line" list="${file}" delimiter="${line.separator}">
<sequential>
<echo>#{line}</echo>
<loadfile property="inner_file" srcfile="#{line}"/>
<if>
<resourcecontains resource="${inner_file}" substring="parent" />
<then>
<echo message="this is a jpa jar"/>
</then>
<else>
<echo message="this is NOT a jpa jar"/>
</else>
</if>
</sequential>
</for>
</target>
the echo is typing "this is NOT a jpa jar" for all jars.
Is 'if' not working with 'resourcecontains'?
OK, found two problems:
1) The second load file is actually not needed here because resourcecontains needs to get the file name and not its value.
2) resourcecontains is inherited from <condition>
so the solution should be:
<target name="chek-file">
<loadfile property="file" srcfile="c:\tmp\testing.txt"/>
<for param="line" list="${file}" delimiter="${line.separator}">
<sequential>
<echo>#{line}</echo>
<condition property="substring_found">
<resourcecontains resource="#{line}" substring="JPA>true" />
</condition>
<echo message="substring_found value: ${substring_found}"/>
<if>
<equals arg1="${substring_found}" arg2="true" />
<then>
<echo message="this is a jpa jar"/>
<get_jar_name_no_version property.to.process="#{line}" output.property="linetobeadd" />
</then>
<else>
<echo message="this is NOT a jpa jar"/>
</else>
</if>
<var name="substring_found" unset="true"/>
</sequential>
</for>
</target>

ant: condition command does not find pattern when pattern is a file path

I am using the following code with the idea of finding a file in a directory that is also part of a list in a file:
<loadfile property="ReportFileContent" srcFile="${ReportFile}"/>
<for param="file">
<path>
<fileset dir="${MainDir}" includes="**/**"/>
</path>
<sequential>
<basename file="#{file}" property="#{file}" />
<condition property="found-file${index2}">
<matches pattern="#{file}" string="${ReportFileContent}"/>
</condition>
<if>
<isset property="found-file${index2}"/>
<then>
<echo message=" Found file #{file}" level="warning" />
</then>
<else>
<echo message="Not Found file #{file}" level="warning" />
</else>
</if>
<math result="index2" operand1="${index2}" operation="+" operand2="1" datatype="int" />
</sequential>
</for>
The command is not working though as it is not finding the file that is available in ${ReportFileContent}.
The content of the ReportFileContent property is the following:
c:\___tools\test\file1.txt;2
c:\___tools\test\file2.txt;2
c:\___tools\test\file3.txt;2
Any idea why the condition is not working correctly?
Thanks
Tony

ant, copy file with it's directory structure

I am trying to write a ant script to automate the update process of our web application.
When some files is going to be updated, I need to backup that file. my question is how to copy that file to backup directory and also create the directory structure relative to the root directory of my web application?
for example:
${WEB_APP_ROOT}/dir1/file1
${WEB_APP_ROOT}/dir2/subdir1/file2
copied to backup folder should be:
${BACK_UP_DIR}/dir1/file1
${BACK_UP_DIR}/dir2/subdir1/file2
currently, I can only copy all files to backup folder, but if two file with same name but located in different folder will cause problem.
my ant code:
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 对公信贷自动更新Ant任务脚本 created by ggfan#bgzchina.com at 2013.11.14 -->
<project default="patch" basedir=".">
<!-- 引入Weblogic安装目录下的antcontrib包,才能使用if,foreach,propertyregex-->
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<pathelement location="/home/weblogic/Oracle/Middleware/modules/net.sf.antcontrib_1.1.0.0_1-0b2/lib/ant-contrib.jar" />
</classpath>
</taskdef>
<!-- 发布目标路径 -->
<property name="target_dir" value="/home/weblogic/amarsoft/ccms/war/CCMS" />
<!-- 数据库连接配置属性 -->
<property name="db_driver" value="oracle.jdbc.OracleDriver" />
<property name="db_url" value="jdbc:oracle:thin:#10.53.1.116:1521:credit" />
<property name="db_user" value="als_sit" />
<property name="db_pswd" value="als_sit" />
<!-- WLST配置 -->
<property name="wl_target_server" value="AdminServer" />
<property name="wl_admin_url" value="t3://10.53.1.117:7001" />
<property name="wl_user" value="weblogic" />
<property name="wl_pswd" value="weblogic123" />
<property name="wl_app_name" value="CCMS" />
<target name="patch">
<!-- 检查是否存在WEB-INF目录,如果有则说明更新了配置文件或者JAVA类需要重新加载应用 -->
<available file="${patch_dir}/WebRoot/WEB-INF" type="dir" property="WEB-INF.present"/>
<!-- 检查是否存在数据库更新脚本 -->
<available file="${patch_dir}/update.sql" type="file" property="sql.present"/>
<!-- 创建备份目录 -->
<mkdir dir="${patch_dir}/backup" />
<!-- 针对单个文件,检查是否更新还是新增,如果是更新则要先备份 -->
<foreach target="move-to-backup" param="theFile">
<path>
<fileset dir="${patch_dir}/WebRoot" />
</path>
</foreach>
<!-- 提醒用户检查更新列表预览 -->
<input message="Is patching preview above correct?" validargs="y,n" addproperty="patch.continue" />
<!-- 用户确认无误则更新 -->
<if>
<equals arg1="${patch.continue}" arg2="y" />
<then>
<!-- 存在WEB-INF目录,则先停止应用 -->
<if>
<equals arg1="${WEB-INF.present}" arg2="true" />
<then>
<echo message="Directory [WEB-INF] found in patching dir, application will be stoped" />
<wldeploy action="stop" graceful="true" name="${wl_app_name}" user="${wl_user}" password="${wl_pswd}"
verbose="true" adminurl="${wl_admin_url}" targets="${wl_target_server}" />
</then>
</if>
<copy todir="${target_dir}" verbose="true">
<fileset dir="${patch_dir}/WebRoot/" />
</copy>
<!-- 存在数据库更新脚本则执行 -->
<if>
<equals arg1="${sql.present}" arg2="true" />
<then>
<sql driver="${db_driver}" url="${db_url}" userid="${db_user}" password="${db_pswd}">
<classpath>
<pathelement location="/home/weblogic/Oracle/Middleware/wlserver_10.3/server/lib/ojdbc6.jar" />
</classpath>
<transaction src="${patch_dir}/update.sql"/>
</sql>
</then>
</if>
<!-- 更新完成后,重启应用 -->
<if>
<equals arg1="${WEB-INF.present}" arg2="true" />
<then>
<echo message="Application will be started again." />
<wldeploy action="start" name="${wl_app_name}" user="${wl_user}" password="${wl_pswd}"
verbose="true" adminurl="${wl_admin_url}" targets="${wl_target_server}" />
</then>
</if>
<echo message="Patching done! " />
</then>
</if>
</target>
<target name="move-to-backup">
<propertyregex property="target.file" input="${theFile}" regexp=".+/${patch_dir}/WebRoot/(.+)" replace="${target_dir}/\1" casesensitive="true" />
<available file="${target.file}" type="file" property="target.file.exist" />
<if>
<equals arg1="${target.file.exist}" arg2="true" />
<then>
<echo message="[UPDATE] ${target.file}" />
<copy todir="${patch_dir}/backup" verbose="false">
<fileset file="${target.file}" />
</copy>
</then>
<else>
<echo message="[ADD ] ${target.file}" />
</else>
</if>
</target>
</project>
In your target move-to-backup you have this copy task:
<copy todir="${patch_dir}/backup" verbose="false">
<fileset file="${target.file}" />
</copy>
When you define a fileset as a single file, it uses the directory containing the file as the base directory for the fileset, and the path to the file is relative to that: simply the name of the file.
You can do something like this instead, so that the path to the file to be copied is relative to the root of your application:
<copy todir="${patch_dir}/backup" verbose="false">
<fileset dir="${WEB_APP_ROOT}">
<include name="${target.file}" />
</fileset>
</copy>
If your file was
${WEB_APP_ROOT}/x/y/z/file.txt
It would then be copied to
${patch_dir}/backup/x/y/z/file.txt

Change values of list in ANT

I need to change the values of an ANT-script list in real time.
This is the situation;
I have these properties:
x.y.6.1=something1
x.y.6.2=something2
x.y.6.3=something3
list=6.1,6.2
I want the list to become list=something1;something2
This is the gist of the code;
<target name="target1">
<foreach list="${list}" target="target2" param="var" delimiter="," />
</target>
<target name="target2">
<propertycopy name="var" from="x.y.${var}" silent="true"/>
</target>
Now, the propertycopy part works, however, it will not keep the new value.
I tried many variations, none which worked.
I am using ant-contrib.
Help would be much appreciated!
Adam
The target attribute of your foreach should be the name of the target called.
I guess here it should be <foreach list="${list}" target="agent_version_to_path" param="var" delimiter="," />
If I'm wrong, post your target2 and explain what you're trying to do.
Edit:
Ok for your edit, did you already try override="yes"?
And cannot you change your name of property (var) it is quite confusing!
I'm not a fan of the ant-contrib tasks. Have you considered embedding a scripting language instead?
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="build.path"/>
<groovy>
properties["list"].split(",").each {
println properties["x.y.${it}"]
}
</groovy>
Update
Here's a more complete example that loops and calls another target:
$ ant
Buildfile: build.xml
process:
doSomething:
[echo] something1
doSomething:
[echo] something2
BUILD SUCCESSFUL
Total time: 0 seconds
build.xml
<project name="demo" default="process">
<property file="build.properties"/>
<path id="build.path">
<pathelement location="lib/groovy-all-2.1.5.jar"/>
</path>
<target name="process" description="Process values in a list">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="build.path"/>
<groovy>
properties["list"].split(",").each {
properties.var = properties["x.y.${it}"]
ant.ant(target:"doSomething")
}
</groovy>
</target>
<target name="doSomething">
<echo>${var}</echo>
</target>
</project>
I have solved the problem, in an icky way, but it works great!
<project name="Test" default="main">
<property file="agent.properties" />
<property file="temp_updates.txt" />
<taskdef name="propertycopy" classname="net.sf.antcontrib.property.PropertyCopy" />
<taskdef name="foreach" classname="net.sf.antcontrib.logic.ForEach" />
<target name="main">
<property name="Agent Updates" value="6.1,6.2" />
<antcall target="create_temp_files" />
<antcall target="agent_updates_target" />
<propertycopy name="custom.agent.release.group" from="updates" silent="true" override="true" />
</target>
<target name="agent_updates_target">
<foreach list="${Agent Updates}" target="agent_version_to_path" param="var" delimiter="," />
</target>
<target name="agent_version_to_path">
<propertycopy name="var" from="agent.installer.${var}" silent="true" override="true"/>
<echo message="${var};" file="temp_updates.txt" append="true" />
</target>
<target name="create_temp_files">
<echo message="updates=" file="temp_updates.txt" />
</target>
</project>
on another file, "agent.properties" I had that;
agent.installer.6.3=something3
agent.installer.6.2=something2
agent.installer.6.1=something1
agent.installer.6.0=...
agent.installer.5.6=...
agent.installer.5.0.12=...
agent.installer.5.0.11=...
agent.installer.5.0.9.5=...
agent.installer.3.8=...
agent.installer.3.7=...
As a result, a new file "temp_updates.txt" was created, having
updates=something1;something2;
Which I then loaded into the actual program.
May not be pretty, but it works quite well.
Thank you Skoll and Mark O'Connor for all your help, I used those ideas to come up with this one. I would rate you, but I can't :( Sorry!

Delete files specified via a zipfileset?

I have the following Ant target which extracts contents from a specific .ZIP archive:
<!-- UNPACK-MATH -->
<target name="unpack-math" depends="init-contrib">
<!-- NOTE: the 'unzip' task doesn't fail when it cannot extract over read-only files; however, 'copy' with a 'zipfileset' does. -->
<first id="math.archive">
<fileset dir="${builddir}" includes="MATH_MF*.zip" />
</first>
<if>
<length string="${toString:math.archive}" when="greater" length="0" />
<then>
<copy todir="${basedir}">
<zipfileset src="${toString:math.archive}" />
</copy>
</then>
<else>
<echo message="No math to unpack." />
</else>
</if>
</target>
What I'd like to do now is "clean up" the files that were extracted. However, the following does not work:
<!-- CLEAN-MATH -->
<target name="clean-math" depends="init-contrib">
<first id="math.archive">
<fileset dir="${builddir}" includes="MATH_MF*.zip" />
</first>
<if>
<length string="${toString:math.archive}" when="greater" length="0" />
<then>
<delete>
<zipfileset src="${toString:math.archive}" />
</delete>
</then>
<else>
<echo message="No math to clean." />
</else>
</if>
</target>
I get the following stack trace:
BUILD FAILED
D:\Development\MForce\Games\gamebuild.xml:214: java.lang.ClassCastException: class org.apache.tools.ant.types.resources.ZipResource doesn't provide files
at org.apache.tools.ant.types.resources.comparators.FileSystem.resourceCompare(FileSystem.java:43)
...
Any ideas?
This solution appears to work, but requires unpacking the .ZIP archive (which lists the files you'd like to delete as some other root) first, which I'd prefer to avoid:
<!-- CLEAN-MATH -->
<target name="clean-math" depends="init-contrib">
<first id="math.archive">
<fileset dir="${builddir}" includes="MATH_MF*.zip" />
</first>
<if>
<length string="${toString:math.archive}" when="greater" length="0" />
<then>
<unzip dest="${builddir}/tmp" src="${toString:math.archive}"/>
<delete>
<fileset dir="${basedir}" includes="**/*">
<present present="both" targetdir="${builddir}/tmp"/>
</fileset>
</delete>
<delete dir="${builddir}/tmp"/>
</then>
<else>
<echo message="No math to clean." />
</else>
</if>
</target>

Resources