ant-contrib for loop and regex in ant scripting - regex

I have a requirement using ant, that the target should extract the two parameters passed as comma separated in a long list of similar pair of parameters passed which are semicolon separated. Currently I am doing something like this:
<?xml version="1.0"?>
<project name="" basedir="." default="test" xmlns:ac="antlib:net.sf.antcontrib">
<target name="test" >
<echo message="Hey There I am using What's App" />
<ac:for list="asdfg,dasfdf;vxxexqxx,hyyypyly;dksfgsgdgf,abaifuacu" delimiter=";" param="val">
<ac:sequential>
<ac:propertyregex property="param1"
input="#{val}"
regexp="([^\.]*)\,.*"
select="\1"
casesensitive="true" />
<ac:propertyregex property="param2"
input="#{val}"
regexp=".*,([^\.]*)"
select="\1"
casesensitive="true" />
<echo message = "val = ${param1}"/>
<echo message = "value = ${param2}"/>
</ac:sequential>
</ac:for>
</target>
</project>
But I am getting the output as:
Buildfile: /tmp/Manish/build.xml
test:
[echo] Hey There I am using What's App
[echo] val = asdfg
[echo] value = dasfdf
[echo] val = asdfg
[echo] value = dasfdf
[echo] val = asdfg
[echo] value = dasfdf
So this is getting looped 3 times(correct) but by only the first value passed in the for loop parameter. Is there some obvious mistake I am making?
Thanks,
Manish Joshi

Try using foreach instead of for and put the propertyregex into a separate target. Here is an example from my ant script, it basically does the same thing.
<target name="loadTestStatic" depends="setTargetEnv,setPassword">
<loadfile property="controlFile" srcFile="${projectDir}/test/config/static/controlFile.txt"/>
<foreach list="${controlFile}" delimiter="${line.separator}" param="descriptor" target="loadConfig"/>
</target>
<target name="loadConfig">
<if>
<matches string="${descriptor}" pattern="^camTool:"/>
<then>
<propertyregex property="camToolFile"
input="${descriptor}"
regexp="camTool:(.*)"
select="\1"
casesensitive="false" />
<echo message="Got cam tool file ${camToolFile}"/>
<camTool file="${camToolFile}"/>
</then>
<else>
<!-- todo: add CM Tool, SQL as required -->
<echo message="Unexpected config ${descriptor} ignored"/>
</else>
</if>
</target>

An alternative approach is to use a scripting language like groovy.
<groovy>
<arg value="asdfg,dasfdf;vxxexqxx,hyyypyly;dksfgsgdgf,abaifuacu"/>
args[0].tokenize(";").each {
def m = it.tokenize(",")
println "val = ${m[0]}"
println "value = ${m[1]}"
}
</groovy>

Alternatively use Ant addon Flaka, f.e. :
<project xmlns:fl="antlib:it.haefelinger.flaka">
<!-- with cvs property -->
<property name="foobar" value="asdfg,dasfdf;vxxexqxx,hyyypyly;dksfgsgdgf,abaifuacu"/>
<fl:for var="item" in="split('${foobar}', ';')">
<fl:let>
param1 ::= split(item, ',')[0]
param2 ::= split(item, ',')[1]
</fl:let>
<echo>
$${param1} => ${param1}
$${param2} => ${param2}
</echo>
</fl:for>
<!-- with list inline -->
<fl:for var="item" in="split('asdfg,dasfdf;vxxexqxx,hyyypyly;dksfgsgdgf,abaifuacu', ';')">
<fl:let>
param1 ::= split(item, ',')[0]
param2 ::= split(item, ',')[1]
</fl:let>
<echo>
$${param1} => ${param1}
$${param2} => ${param2}
</echo>
</fl:for>
</project>
Notice the double '::' in param1 ::= split(item, ',')[0]
means overriding any (also userproperties, defined via -Dkey=value as commandline arguments) existing property
whereas ':=' creates a property but won't overwrite if property already exists.

<target name="myTarget">
<ac:propertyregex property="param1"
input="${myValue}"
regexp="([^\.]*)\,.*"
select="\1"
casesensitive="true" />
<ac:propertyregex property="param2"
input="${myValue}"
regexp=".*,([^\.]*)"
select="\1"
casesensitive="true" />
<echo message = "val = ${param1}"/>
<echo message = "value = ${param2}"/>
</target>
<ac:for list="asdfg,dasfdf;vxxexqxx,hyyypyly;dksfgsgdgf,abaifuacu" delimiter=";" param="val">
<ac:sequential>
<antcall target="myTarget">
<param name="myValue" value="#{val}" />
</antcall>
</ac:sequential>
</ac:for>

Properties in Ant are immutable. You will need to use the variable task from ant-contrib (although it is discouraged) to unset the properties:
<ac:for list="asdfg,dasfdf;vxxexqxx,hyyypyly;dksfgsgdgf,abaifuacu" delimiter=";" param="val">
<ac:sequential>
<ac:propertyregex property="param1"
input="#{val}"
regexp="([^\.]*)\,.*"
select="\1"
casesensitive="true" />
<ac:propertyregex property="param2"
input="#{val}"
regexp=".*,([^\.]*)"
select="\1"
casesensitive="true" />
<echo message = "val = ${param1}"/>
<echo message = "value = ${param2}"/>
<ac:var name="param1" unset="true"/>
<ac:var name="param2" unset="true"/>
</ac:sequential>
</ac:for>

Related

Ant nested condition

I have an ant build.xml file which contains the following snippet:
<condition property="apiUrl" value="apiUrl1">
<and>
<equals arg1="${area}" arg2="area1"/>
<equals arg1="${env}" arg2="stage"/>
</and>
</condition>
<condition property="apiUrl" value="apiUrl2">
<and>
<equals arg1="${area}" arg2="area1"/>
<equals arg1="${env}" arg2="develop"/>
</and>
</condition>
As you can see from above, <equals arg1="${area}" arg2="area1"/> is checked twice, and the logic of the snippet is equivalent to the pseudo code:
if (${area} == 'area1' and ${env} == 'stage') {
apiUrl = 'apiUrl1'
}
if (${area} == 'area1' and ${env} == 'develop') {
apiUrl = 'apiUrl2'
}
How can I change build.xml so that its logic becomes the following nested condition?
if (${area} == 'area1') {
if (${env} == 'stage') {
apiUrl = 'apiUrl1'
}
if (${env} == 'develop') {
apiUrl = 'apiUrl2'
}
}
My ant version is 1.10.3.
The reason this seemingly minor change can seem so awkward in Ant is because while the conditional setting of properties is simply controlled with the condition task, the conditional flow of logic is controlled at the target level. Thus, if you want certain steps to run or be skipped depending on a condition, you'll have to create a separate target that first checks the condition and then tells your main target whether or not it should run.
<target name="setApiUrl" depends="checkArea" if="isArea1">
<condition property="apiUrl" value="apiUrl1">
<equals arg1="${env}" arg2="stage"/>
</condition>
<condition property="apiUrl" value="apiUrl2">
<equals arg1="${env}" arg2="develop"/>
</condition>
</target>
<target name="checkArea">
<condition property="isArea1">
<equals arg1="${area}" arg2="area1"/>
</condition>
</target>
you can achieve that using script instead of condition task like this:
<project default="init" name="My Project">
<property name="area" value="area1" />
<property name="env" value="develop" />
<target name="init">
<script language="javascript">
if (project.getProperty('area') == 'area1') {
if (project.getProperty('env') == 'stage') {
project.setProperty('apiUrl', 'apiUrl1');
}
if (project.getProperty('env') == 'develop') {
project.setProperty('apiUrl', 'apiUrl2');
}
}
</script>
<echo>${apiUrl}</echo>
</target>
</project>

Rename a file before Copy Task in ant build

I am new to ant build files.
Currently I get a list of files for build as:
a.cls
b.cls
c.cls
but in my local I have to run build on files, in the same directory:
a-meta.cls
b-meta.cls
c-meta.cls
Here meta keyword stays consistent. And I am using the following build.xml file. I am not sure how can I rename filename before actually copying them. I tried replace, mapper and other antlib tasks. But not helpful.
<project name="test" default="compile">
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<pathelement location="lib/ant-contrib-1.0b3.jar"/>
</classpath>
</taskdef>
<loadfile property="file" srcfile="filesToMove.txt"/> <!-- these are the list of files, i mentioned earlier -->
<target name="compile">
<echo>${file}</echo> <!-- here i have to rename file name to include -meta -->
<copy file="./classes/${file}" tofile="./src/classes/${file}" overwrite="true"/>
</target>
</project>
How to rename the files before moving them.
The solution to it was replacing the .cls to find only the name and then append the -meta.html. As follows (some portion is changed compared to previous version in the question)
<project name="test" default="compile">
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<pathelement location="lib/ant-contrib-1.0b3.jar"/>
</classpath>
</taskdef>
<loadfile property="file" srcfile="filesToMove.txt"/> <!-- these are the list of files, i mentioned earlier -->
<target name="compile">
<echo>${file}</echo> <!-- here i have to rename file name to include -meta -->
<copy file="./classes/${file}" tofile="./src/classes/${file}" overwrite="true"/>
<for param="file">
<path>
<fileset dir="./" includes="*.cls"/>
</path>
<sequential>
<basename file="#{file}" property="#{file}" suffix=".md"/>
<echo message=" ${#{file}}"/>
<copy file="${#{file}}-meta.cls" toDir="test"/>
</sequential>
</for>
</target>
</project>

replaceregexp ant not inserting tabulation

I want to replace a tabulation when I have a match in a file. I have this code:
<property name="line.separator" location="\r" />
<property name="tab.separator" location="\t" />
<target name="replace">
<replaceregexp
match='#WebMethod([\s\S]*?(?=public))public\s+(\w+)\s+(\w*)[\s\S]+?(?=\))[\s\S]+?(?=MSE)(\w+)\s+(\w*)[\s\S+]+?(?=throws)throws\s+(\w*)'
replace='#WebMethod(operationName="\$4")${line.separator}${tab.separator}#RequestWrapper(localName = "\$3")${line.separator}\r#ResponseWrapper(localName = "\$2")${line.separator}\rpublic \$2 \$3\(${line.separator}\r\r\$4 \$5)${line.separator}\r\rthrows MSFWebServiceException' flags="g,m">
<fileset dir="${project.dir}" />
</replaceregexp>
But the part of
#WebMethod(operationName="\$4")${line.separator}${tab.separator}#RequestWrapper
returns this:
#WebMethod(operationName="MSEPDetalleFigPartDTO")
C:t#RequestWrapper
So the \n goes ok, but the \t doesn't work because it replace the \t with C:t instead of a tabulation.
Any help would be appreciate.
kindest regards
This is cause by location instead of value and \t instead of :
<property name="tab.separator" location="\t" />
instead of
<property name="tab.separator" value=" " />
The property line.separator is already set (because it is an Ant built-in property), so your first line is just ignored.
location="\t" means the file location of the file t in the root directory, in your case it is the drive C:

Ant matches giving false positives

I am trying to process/skip tasks with the help of the matches task.
But I am getting "false positives", the matches returns true when I think it should return false.
Following code is being used:
<property name="moduleList" value="AP|MR"/>
<echo message="ModuleList is ${moduleList}" />
...some for loop here...
<echo message="Found ${zipFilename}" />
<if>
<matches pattern="${moduleList}" string="${zipFilename}" />
<then>
<echo message="Creating ${zipFilename}" />
</then>
<else>
<echo message="Skipping ${zipFilename}" />
</else>
</if>
The zipfileName is determined by looping through a folder and taking basename of files, zipfileNames being encountered are AP, MR and VAP
The result of this piece of code are:
[echo] ModuleList is AP|MR
[echo] Found AP
[echo] Creating AP
[echo] Found MR
[echo] Creating MR
[echo] Found VAP
[echo] Creating VAP
[echo] Found eFormsPolicy
[echo] Skipping eFormsPolicy
So according to me VAP is a false positive.
Or is there something wrong with my matches?
AFAIK ant.regexp.regexpimpl is not set, so ant is using Jdk14Regexp implementation
Could it be that you are getting the false positives because VAP ends with AP? What if you changed your matches pattern to ^(${moduleList})$? When the moduleList is actually substituted in, it would become ^(AP|MR)$, which would not match VAP.

regex AFTER grouping construct not being set correctly?

Based on this thread. I've tried to replace the set the current version of my project in my NAnt script.
Here's my Replace snippet
<target name="Replace">
<loadfile file="${SetVersionCpp.File}" property="h.file.content" />
<regex
input="${h.file.content}"
pattern="(?'BEFORE'[.\s]*)${LineBegining}\s*[\s\d,]*\r\n(?'AFTER'[.\s]*)" />
<echo
file="${SetVersionCpp.File}"
message="${BEFORE}${LineBegining} ${ReplaceWith}
${AFTER}"
append="false"
verbose="true" />
</target>
Which I call on this file
#define FILEVER 0, 2, 0, 3
#define PRODUCTVER 0, 2, 0, 3
#define STRFILEVER "00.02.00.03\0"
#define STRPRODUCTVER "00.02.00.03\0"
with the following parameters
<property name="SetVersionCpp.File" value="${baseline.dir}\VersionNo.h" />
<property name="LineBegining" value="#define FILEVER" />
<property name="ReplaceWith" value="${FileVersion}" />
Based on the output, the AFTER variable is not capturing the rest of the file for some reason. This is what I get:
[#define FILEVER 0, 2, 0, 30
]
*I put it in brackets so that the whitespace got correctly formatted
Any ideas what I'm doing wrong?
I've fixed it by setting the options to Singleline so that . would match line breaks and by removing the classes from the groups:
<regex
input="${h.file.content}"
options="Singleline"
pattern="(?'BEFORE'.*)${LineBegining}\s*[\s\d,]*\r\n(?'AFTER'.*)" />