Does the for/foreach loops in ant-contrib support the equivalent of a "break" or "continue" statement? As far as I can tell, they do not.
Are there any viable work-arounds?
Thanks
-T
There is no easy way to implement this behavior, but maybe the following suggestion will help.
use the the for task (i.e. not the foreach)
set the keepgoing attribute to true
use the fail task with a condition so that the items that need to be skipped will fail.
you can obtain something like a break by defining a property myBreakProperty whenever you detect that you need to break
<for list="a,b,c,d,e" param="letter" keepgoing="true">
<sequential>
<if>
<equals arg1="#{letter}" arg2="c" />
<then>
<property name="myBreakProperty" value="nevermind the value"/>
</then>
</if>
<fail if="myBreakProperty"/>
<echo>Letter #{letter}</echo>
</sequential>
</for>
The output will be: Letter a Letter b
To obtain something like a continue :
<for list="a,b,c,d,e" param="letter" keepgoing="true">
<sequential>
<if>
<equals arg1="#{letter}" arg2="c" />
<then>
<fail/>
</then>
</if>
<echo>Letter #{letter}</echo>
</sequential>
</for>
The output will be: Letter a Letter b Letter d Letter e
You can make a break process flow without running something as harsh as a fail. Using a property to detect when you want to break you can implement something like this:
<var name="break.flag" unset="true"/>
<for list="a,b,c,d,e" param="letter">
<sequential>
<if>
<not>
<isset property="break.flag"/>
</not>
<then>
<if>
<equals arg1="#{letter}" arg2="c" />
<then>
<property name="break.flag" value="true"/>
</then>
</if>
<if>
<not>
<isset property="break.flag"/>
</not>
<then>
<echo>Letter #{letter}</echo>
<echo>Do the rest of the loop here</echo>
</then>
</if>
</then>
</if>
</sequential>
</for>
To really break the loop you could use fail together with trycatch
<trycatch>
<try>
<for param="i" begin="1" end="99">
<sequential>
...
<fail message="break" />
</sequential>
</for>
</try>
<catch />
</trycatch>
Related
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>
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
I have a situation in a build file where I want two OS dependent versions of a macrodef and want to select which one gets "compiled" based on a flag that is true or false.
<condition property="use.windows.macros" value=true else=false
<os family="windows" />
</condition>
Pseudocode
if(use.windows.macrodef)
<macrodef aMacro
... windows version
</macrodef>
else
<macrodef aMacro
... non windows version
</macrodef>
endif
how does one do this sort of thing with the basic out of the box ant xml nodes?
Why do you want two versions of macro? You can use only one (assuming you have ant version >= 1.9.3)
<project xmlns:if="ant:if" xmlns:unless="ant:unless">
<condition property="os.windows">
<os family="windows"/>
</condition>
<condition property="os.linux">
<os family="unix" name="linux" />
</condition>
<macrodef name="sayHello">
<sequential>
<sequential if:set="os.windows">
<echo message="hello from windows" />
</sequential>
<sequential if:set="os.linux">
<echo message="hello from linux" />
</sequential>
</sequential>
</macrodef>
<sayHello />
</project>
Ok - yes a synthesis of the prior partial answer and my work on it but this is what I ended up with as a structure.
I have to create two macros - the first creates the others based on the flags.
I'm not sure how this jibes with canonical ant but it does the job I need done and is easy for someone to see what is meant.
<condition property="os.windows">
<os family="windows"/>
</condition>
<condition property="os.linux">
<os family="unix" name="linux" />
</condition>
<macrodef name="createOsMacros">
<sequential if:set="os.windows">
<macrodef name="doOsMacro">
<attribute name="printstring" default="windows string"/>
<sequential>
<echo message="#{printstring}" />
</sequential>
</macrodef>
</sequential>
<sequential if:set="os.linux">
<macrodef name="doOsMacro">
<attribute name="printstring" default="unix string"/>
<sequential>
<echo message="#{printstring}" />
</sequential>
</macrodef>
</sequential>
</macrodef>
<createOsMacros />
<doOsMacro />
<target name="build">
<for list="${platform}" param="platform" trim="true">
<sequential>
<if>
<equals arg1="${platform}" arg2="${project.SuppoortedPlatforms}" />
<then>
<antcall target="package.${platform}" />
</then>
</if>
</sequential>
</for>
</target>
where i'm getting platfrom values at runtime (eg:windows,ios) and project.SuppoortedPlatforms is declared under build.properties (eg:android,ios). how can i compare the list of strings?
could anyone help me to solve this problem?
Thanks,
sandhiya
You are looping over a comma-separated list of platforms, and for each one you're checking if it is contained in the list of supported platforms in project.SuppoortedPlatforms. This should go like this:
<for list="${platform}" param="platformParam" trim="true">
<sequential>
<if>
<contains string="${project.SuppoortedPlatforms}" substring="#{platformParam}" />
<then>
<antcall target="package.#{platformParam}" />
</then>
</if>
</sequential>
</for>
The parameter in the loop should be accessed with # instead of $. Also it would be better to rename the parameter for readability (platformParam instead of platform).
Instead of using contains task, i myself tried with the nested for loop, its cool working fine.
<for list="${platforms}" param="platformparam" trim="true">
<sequential>
<for list="${project.SupportedPlatforms}" param="supplatformparam" trim="true">
<sequential>
<if>
<equals arg1="#{platformparam}" arg2="#{supplatformparam}" />
<then>
<antcall target="package.#{platformParam}" />
</then>
</if>
</sequential>
</for>
</sequential>
</for>
I need to copy all dml.sql files to inside DB2_List.txt file if DML.sql file is present. But after executing this file i'm getting error like this:
copy doesn't support the nested "if" element.
Please let me know if you have any better idea about the nested loop in Ant.
<available file="DB/DML.sql" property="db.check.present"/>
<copy file="DB/DDL.sql" tofile="DB2/DB2_List.txt" >
<if>
<equals arg1="${db.check.present}" arg2="true"/>
<then>
<filterchain>
<concatfilter append="DB/DML.sql" />
<tokenfilter delimoutput="${line.separator}" />
</filterchain>
</then>
</if>
</copy>
It is possible to accomplish what you are after, you just have to approach it quite differently in Ant. Just note that you will need to utilize separate targets.
<target name="db.check">
<available file="DB/DML.sql" property="db.check.present"/>
</target>
<target name="db.copy" depends="db.check" if="db.check.present">
<copy file="DB/DDL.sql" tofile="DB2/DB2_List.txt" >
<filterchain>
<concatfilter append="DB/DML.sql" />
<tokenfilter delimoutput="${line.separator}" />
</filterchain>
</copy>
</target>
Take a look at Ant 1.9.1 which supports special if/unless attributes on tags. This might be possible:
<project name="mysterious.moe" basedir="." default="package"
xmlns:if="ant:if"
xmlns:unless="ant:unless"/>
<target name="db.copy">
<available file="DB/DML.sql" property="db.check.present"/>
<copy file="DB/DDL.sql"
tofile="DB2/DB2_List.txt">
<filterchain if:true="db.ceck.present">
<concatfilter append="DB/DML.sql" />
<tokenfilter delimoutput="${line.separator}" />
</filterchain>
</copy>
<target>
...
</project>
Otherwise, you'll have to use two separate copies. You can't put <if> antcontrib inside tasks. Only around tasks:
<available file="DB/DML.sql" property="db.check.present"/>
<if>
<equals arg1="${db.check.present}" arg2="true"/>
<then>
<copy file="DB/DDL.sql" tofile="DB2/DB2_List.txt" >
<filterchain>
<concatfilter append="DB/DML.sql" />
<tokenfilter delimoutput="${line.separator}" />
</filterchain>
</copy>
</then>
<else>
<copy file="DB/DDL.sql" tofile="DB2/DB2_List.txt" >
</else>
</if>
</copy>