Is there anything in Ant that allows me to halt the execution of an iterative segment like the break operation? Usage of external libraries is not a problem.
As an example of what I am trying to accomplish:
<for list="1,2,3" param="iteration">
<sequential>
<if>
<equals arg1="#{iteration}" arg2="3"/>
<then>
<!-- Break here -->
</then>
</if>
</sequential>
</for>
The Ant addon Flaka provides a break task, i.e. :
<project xmlns:fl="antlib:it.haefelinger.flaka">
<fl:for var="i" in=" list(1,2,3,4,5,6) ">
<fl:echo>i = #{i}</fl:echo>
<!-- also possible to use
<fl:when test=" i eq 3 "> -->
<fl:when test=" i == 3 ">
<fl:break />
</fl:when>
</fl:for>
</project>
see Flaka Manual especially section 8. Repetative Tasks
for details about break task.
Related
I am basically trying to do the following thing in Ant (v1.9.4):
I have a list of fixed string like {a,b,c,d} --> First how should I declare this in Ant?
Then I have an input parameter such as ${mystring} and I want to check if the variable value is in my list. Which means in this example, if the variable value is equals to a or b or c or d.
If so return true else false (or 0 and 1 something like that).
Is there a simple way to do that?
Thanks,
Thiago
Use ant property task to declare your stringlist.
Use ant contains condition to check whether list contains a specific item.
Something like :
<project>
<!-- your stringlist -->
<property name="csvprop" value="foo,bar,foobar"/>
<!-- fail if 'foobaz' is missing -->
<fail message="foobaz not in List => [${csvprop}]">
<condition>
<not>
<contains string="${csvprop}" substring="foobaz"/>
</not>
</condition>
</fail>
</project>
Or wrap it in a macrodef for resuse :
<project>
<!-- your stringlist -->
<property name="csvprop" value="foo,bar,foobar"/>
<!-- create macrodef -->
<macrodef name="listcontains">
<attribute name="list"/>
<attribute name="item"/>
<sequential>
<fail message="#{item} not in List => [#{list}]">
<condition>
<not>
<contains string="${csvprop}" substring="foobaz"/>
</not>
</condition>
</fail>
</sequential>
</macrodef>
<!-- use macrodef -->
<listcontains item="foobaz" list="${csvprop}"/>
</project>
-- EDIT --
From ant manual condition :
If the condition holds true, the property value is set to true by default; otherwise, the property is not set. You can set the value to something other than the default by specifying the value attribute.
So simply use a condition to create a property that is either true or not set, f.e. combined with the new if/unless feature introduced with Ant 1.9.1 :
<project
xmlns:if="ant:if"
xmlns:unless="ant:unless"
>
<!-- your stringlist -->
<property name="csvprop" value="foo,bar,foobar"/>
<!-- create macrodef -->
<macrodef name="listcontains">
<attribute name="list"/>
<attribute name="item"/>
<sequential>
<condition property="itemfound">
<contains string="${csvprop}" substring="foobaz"/>
</condition>
<!-- echo as example only instead of
your real stuff -->
<echo if:true="${itemfound}">Item #{item} found => OK !!</echo>
<echo unless:true="${itemfound}">Warning => Item #{item} not found !!</echo>
</sequential>
</macrodef>
<!-- use macrodef -->
<listcontains item="foobaz" list="${csvprop}"/>
</project>
output :
[echo] Warning => Item foobaz not found !!
Note that you need the namespace declarations to activate the if/unless feature.
I would like to know if is possible to check/capture the result of a "schemavalidate"/"xmlvalidate" operation?
The idea is to parse the files in a folder, try to validate each of them against an XSD and get the status of the operation in a property (eventually, output the status and the result of the operation in a log file).
The status of the validation can be then checked in order to know if some other tasks should be performed or not on that particular XML file.
For example:
<target name="convert-user-folder">
<echo>${user.folder}</echo>
<!-- Iterate all XML files in the folder -->
<foreach target="validate-xml-file" param="user.input.xml">
<path>
<fileset dir="${user.folder}">
<include name="*.xml" />
</fileset>
</path>
</foreach>
</target>
<target name="validate-xml-file">
<echo message="Validating ${user.input.xml}"/>
<!-- Checking if XML is well formed -->
<echo message="Checking if ${user.input.xml} is well formed"/>
<xmlvalidate file="${user.input.xml}" failonerror="false" lenient="true"/>
<!-- HOW WE COULD CHECK THE RESULT OF THE VALIDATION OPERATIONS
WITHOUT EXITING ?-->
<!-- Checking if file validates against XSD -->
<echo message="Checking if ${user.input.xml} validates against schema"/>
<schemavalidate noNamespaceFile="${xsds.dir}/userInput.xsd"
file="${user.input.xml}" failonerror="false"/>
<!-- HOW WE COULD CHECK THE RESULT OF THE VALIDATION OPERATIONS
WITHOUT EXITING? -->
<!-- HERE WE SHOULD GET IN A PROPERTY THE STATUS OF THE OPERATION AND WRITE
IN A FILE SOMETHING LIKE : "OPERATION STATUS: SUCCESS/FAILURE: The reason
was: something from the schemavalidate output" -->
<!-- IF THE OPERATION WAS SUCCESSFUL WE SHOULD CALL SOME TASKS OTHERWISE
CALL OTHER TASKS -->
</target>
Thanks in advance for your suggestions.
What I needed actually was the trycatch from antcontrib. This solved my problem as in the snippet below.
<target name="validate-xml-file">
<echo message="Validating ${user.input.xml}"/>
<!-- Checking if XML is well formed -->
<echo message="Checking if ${user.input.xml} is well formed"/>
<trycatch property="xml.well.formed.result">
<try>
<xmlvalidate file="${user.input.xml}" failonerror="true" lenient="true"/>
</try>
<catch/>
<finally/>
</trycatch>
<!-- Checking if file validates against XSD -->
<echo message="Checking if ${user.input.xml} validates against schema"/>
<trycatch property="schema.validation.result">
<try>
<schemavalidate noNamespaceFile="${xsds.dir}/userInput.xsd"
file="${user.input.xml}" failonerror="true"/>
</try>
<catch/>
<finally/>
</trycatch>
<!-- Create two properties for the results of the validation -->
<condition property="xml.well.formed.result.set" else="false">
<isset property="xml.well.formed.result"/>
</condition>
<condition property="schema.validation.result.set" else="false">
<isset property="schema.validation.result"/>
</condition>
<!-- Here we can write into a HTML format the result of the operation according
to the xml.well.formed.result, schema.validation.result a.s.o.) -->
<!-- Also, perform something according to the validation or not of the XML -->
<if>
<or>
<equals arg1="${xml.well.formed.result.set}" arg2="true"/>
<equals arg1="${schema.validation.result.set}" arg2="true"/>
</or>
<then>
<!-- Here we call some task -->
</then>
<else>
<!-- Here we call some other task or just fail to fw the failure -->
</else>
</if>
Why don't you simplify the solution by using filesets (instead of using the 3rd party ant-contrib "foreach" task).
<xmlvalidate failonerror="false" ..>
<fileset dir="${user.folder}" includes="*.xml"/>
</xmlvalidate>
<schemavalidate failonerror="false" ..>
<fileset dir="${user.folder}" includes="*.xml"/>
</schemavalidate>
I just tested a similar solution and got the following message telling me the file and line throwing the validation issues:
[schemavalidate] /path/to/file/file.xml:119:18: cvc-complex-type.2.4.a: Invalid content was found starting with element 'helloworld'. One of '???' is expected.
In Ant, how can I test if a property ends with a given value?
For example
<property name="destdir"
value="D:\FeiLong Soft\Essential\Development\repository\org\springframework\spring-beans" />
how can I test if ${destdir} ends with "spring-beans"?
additional:
In my ant-contrib-1.0b3.jar, without 'endswith' task~~
You can test if ${destdir} ends with "spring-beans" like this (assuming you have ant-contrib, and are using Ant 1.7 or later).
<property name="destdir" value="something\spring-beans" />
<condition property="destDirHasBeans">
<matches pattern=".*spring-beans$" string="${destdir}" />
</condition>
<if>
<equals arg1="destDirHasBeans" arg2="true" />
<then>
$destdir ends with spring-beans ...
</then>
<else> ...
</else>
</if>
The '$' in the regex pattern ".*spring-beans$" is an anchor to match at the end of the string.
As Matteo, Ant-Contrib contains a lot of nice stuff, and I use it heavily.
However, in this case can simply use the <basename> task:
<basename property="basedir.name" file="${destdir}"/>
<condition property="ends.with.spring-beans">
<equals arg1="spring-beans" arg2="${basedir.name}"/>
<condition>
The property ${ends.with.spring-beans} will contain true if ${destdir} ends with string-beans and false otherwise. You could use it in the if or unless parameter of the <target> task.
You can use the EndWith condition from Ant-Contrib
<endswith string="${destdir}" with="spring-beans"/>
For example
<if>
<endswith string="${destdir}" with="spring-beans"/>
<then>
<!-- do something -->
</then>
</if>
Edit
<endswith> is part of the Ant-Contrib package that has to be installed and enabled with
<taskdef resource="net/sf/antcontrib/antlib.xml"/>
The JavaScript power can be used for string manipulation in the ANT:
<script language="javascript"> <![CDATA[
// getting the value for property sshexec.outputproperty1
str = project.getProperty("sshexec.outputproperty1");
// get the tail , after the separator ":"
str = str.substring(str.indexOf(":")+1,str.length() ).trim();
// store the result in a new property
project.setProperty("res",str);
]]> </script>
<echo message="Responce ${res}" />
I have a macrodef with a an element called "libs"
<macrodef name="deploy-libs">
<element name="libs"/>
<sequential>
<copy todir="${glassfish.home}/glassfish/domains/domain1/lib">
<fileset dir="${lib}">
<libs/>
</fileset>
</copy>
</sequential>
</macrodef>
which is then invoked as
<deploy-libs>
<libs>
<include name="mysql-connector-*.jar"/>
<include name="junit-*.jar" />
<!-- .... -->
</libs>
</deploy-libs>
I then have another macrodef which calls several macrodefs including "deploy-libs". It would be nice if this macrodef had an element "libs" too but:
<macrodef name="init-glassfish">
<element name="libs"/>
<sequential>
<!-- other stuff -->
<deploy-libs>
<libs>
<libs/>
</libs>
</deploy-libs>
<!-- other stuff -->
</sequential>
</macrodef>
is obviously not working (because of <libs><libs/></libs>):
Commons/ant-glassfish-server.xml:116: unsupported element include
A solution could be to name the element in "init-glassfish" in a different way:
<macrodef name="init-glassfish">
<element name="libraries"/>
<sequential>
<!-- other stuff -->
<deploy-libs>
<libs>
<libraries/>
</libs>
</deploy-libs>
<!-- other stuff -->
</sequential>
</macrodef>
Is there a way to have the element to be named in the same way for both macrodefs?
I found a solution to my question which solves the original problem using a path id
<macrodef name="deploy-libs">
<attribute name="libraries-path-refid"/>
<sequential>
<copy todir="${glassfish.home}/glassfish/domains/domain1/lib">
<path refid="#{libraries-path-refid}"/>
</copy>
</sequential>
</macrodef>
Now this does not solve the issue with the nested elements tags but (XY problem) solves the practical issue. It would be still be nice to know if something similar to the original question is possible.
Apparently, the solution is wrapping additional <libs> elements around in the original call depending on how deep the macros nest. Of course this is a horrible solution because it requires that the macro nesting depth is known on invocation, e.g.:
<deploy-libs>
<libs>
<libs>
<include name="mysql-connector-*.jar"/>
<include name="junit-*.jar" />
<!-- .... -->
</libs>
</libs>
</deploy-libs>
Ant bug 29153 addressing this problem was unfortunately resolved as invalid :(.
<if>
<bool>
<isgreaterthan arg1="${abc}" arg2="${xyz}"/>
</bool>
</if>
when i am running the code, it's showing the error if doesn't support the nested "bool" element.
is there any other option is there at the place of bool which supported by if
The example works in antcontrib-1.0b2 but not the latest antcontrib-1.0b3
Found this after hitting a similar problem after an update
Ant Flaka is a new Ant Plugin that provides an innovative Expression Language which makes many scripting part obsolete. Beside that Flaka provides conditional and repetitive control structures like when, unless, while, for, choose, switch ..
Your if statement with Flaka would look like =
<project xmlns:fl="antlib:it.haefelinger.flaka">
<property name="digitA" value="42"/>
<property name="digitB" value="23"/>
<property name="wordA" value="abcd"/>
<property name="wordB" value="efgh"/>
<!-- compare of digits -->
<fl:when test=" '${digitA}' > '${digitB}' ">
<echo>${digitA} gt ${digitB}</echo>
</fl:when>
<!-- example with string compare in switch -->
<fl:switch value="${wordA}">
<cmp gt="${wordB}">
<echo>${wordA} gt ${wordB}</echo>
</cmp>
<cmp lt="${wordB}">
<echo>${wordA} lt ${wordB}</echo>
</cmp>
</fl:switch>
</project>
please see the comprehensive Flaka Manual for further details !
It looks like you're attempting to use the Antelope if task, as it (unlike the ant-contrib if) supports a nested bool element. But, the error message is indicative of the task not being defined correctly.
Check that you have the Antelope jar, and a suitable taskdef in your buildfile. I use this:
<taskdef resource="ise/antelope/tasks/antlib.xml"
classpath="path/to/AntelopeTasks_3.5.1.jar" />
For details of what the task supports, see the documentation linked to above.
You can use 'bool' tag within 'if' provided you use taskdef for "if" using the classname="ise.antelope.tasks.IfTask"
Eg:
<target name="compare"> <taskdef name="if" classname="ise.antelope.tasks.IfTask"/> <var name="abc" value="2" /> <var name="xyz" value="1" /> <if> <bool> <isgreaterthan arg1="${abc}" arg2="${xyz}"/> </bool> <echo message="${abc} is greater than ${xyz}" /> </if> </target>