ant filterset property scope - ant

I'd like to use a filterset to write out a file replacing a variable which is set as an ant property. I can pass the property if I have a nested filterset, but not a refid; I'm reusing the filterset, so I'd like to use the refid.
foo.old just contains foo=#foo#
This works:
<target name="filterset-test1">
<property name="bar" value="here is foo" />
<copy file="foo.old" tofile="foo.new1">
<filterset begintoken="#" endtoken="#">
<filter token="foo" value="${bar}" />
</filterset>
</copy>
</target>
And this fails to replace the token:
<filterset id="test-filters" begintoken="#" endtoken="#">
<filter token="foo" value="${bar}" />
</filterset>
<target name="filterset-test3">
<property name="bar" value="property doesn't pass thru" />
<copy file="foo.old" tofile="foo.new3">
<filterset refid="test-filters" />
</copy>
</target>
Is there a way to do the latter? I've also tried writing a properties file and using it as the filtersfile property.

The issue appears to be that inside the top-level filterset:
<filterset id="test-filters" begintoken="#" endtoken="#">
<filter token="foo" value="${bar}" />
</filterset>
The property bar is undefined. Moving the property definition for bar outside target filterset-test3 should work:
<?xml version="1.0" encoding="UTF-8" ?>
<project name="filter-test">
<property name="bar" value="property doesn't pass thru" />
<filterset id="test-filters" begintoken="#" endtoken="#">
<filter token="foo" value="${bar}" />
</filterset>
<target name="filterset-test3">
<copy file="foo.old" tofile="foo.new3">
<filterset refid="test-filters" />
</copy>
</target>
</project>

Related

Find the number of occurrences of a particular character like comma in a string using ant script?

<project>
<target name="test">
<property name="src.dir" value="src" />
<property name="search4" value=","/>
<fileset id="existing" dir="${src.dir}/src">
<patternset id="files">
<include name="*.txt"/>
</patternset>
</fileset>
<resourcecount property="count">
<fileset id="matches" dir="../src">
<patternset refid="files" />
<contains text="${search4}" />
</fileset>
</resourcecount>
<echo message="Found '${search4}' in files : '${count}'"/>
</target>
</project>
I used this, but this only prints the first occurrence. I would like to print the total count.
For eg - abc,xyz,pg--> The number of occurrences of commas(,) is 2.
Here's one way. Copies the file to another file, with a filter to remove all non-commas, then gets the size of the output, which is the number of commas in the input file.
<delete file="out.txt" />
<copy file="in.txt" tofile="out.txt">
<filterchain>
<striplinebreaks />
<replaceregex pattern="[^,]" replace="" flags="gm" />
</filterchain>
</copy>
<length file="out.txt" property="out.size" />
<echo message="Commas found: ${out.size}" />
On your follow up question: how to restrict this to just the first line of the file: add this before the "striplinebreaks" line:
<headfilter lines="1" />
That will count commas in just the first line of the file.

Ant - Using Resource Unions with Macrodef

I have an Ant Macrodef that has an <element> placeholder. I am attempting to use the <element> to pass a resourceCollection for processing. The contents of the <element> is populated correctly prior to invoking the macrodef. Unfortunately, during invocation, it comes in as empty.
Macrodef:
<macrodef name="doStuff" description="Amazing macrodef that fails me.">
<element name="fs" optional="true" description="resource/element/fileset to be manipulated />
<sequential>
<echo message="fs: ${toString:fs}" />
<pathconvert property="outputProp" pathsep=" ">
<fs />
</pathconvert>
</sequential>
</macrodef>
and it is invoked via the following pieces of a build.xml file I have:
<fileset id="files1" dir=".">
<include name="inc/*" />
<include name="lib/*" />
</fileset>
<fileset id="files2" dir=".">
<include name="bin/*" />
</fileset>
<union id="allFiles">
<resources refid="files1" />
<resources refid="files2" />
</union>
<target name="doStuffToFiles">
<doStuff>
<fs>
<resources refid="allFiles" />
</fs>
</doStuff>
</target>
I'm unsure why, but going through the union and resources, instead of using a direct fileset with a refid, seemed to be confusing my Ant setup. The following has worked for me on Ant 1.9.2
<macrodef name="doStuff" description="Amazing macrodef that fails me.">
<element name="fs"
optional="false"
description="resource/element/fileset to be manipulated />
<sequential>
<pathconvert property="outputProp" pathsep=" ">
<fs />
<map from="${basedir}/" to=""/>
</pathconvert>
</sequential>
</macrodef>
<target name="doStuffToFiles">
<fileset id="files1" dir=".">
<include name="inc/**"/>
<include name="lib/**"/>
</fileset>
<fileset id="files2" dir=".">
<include name="bin/**"/>
</fileset>
<doStuff>
<fs>
<fileset refid="files1" />
<fileset refid="files2" />
</fs>
</doStuff>
</target>

Merge two Java source files using Ant

I want to merge two different files using Ant. How do I do it?
Ex a.java and B.java
<target name="merge">
<property prefix="app.properties" file="input1.txt" />
<property prefix="app.properties" file="input2.txt" />
<echoproperties destfile="output.txt">
<propertyset>
<propertyref prefix="app.properties"/>
<mapper type="glob" from="app.properties.*" to=""/>
</propertyset>
</echoproperties>
</target>
this is not working correctly
Use the concat task
<concat destfile="output.txt">
<fileset file="input1.txt" />
<fileset file="input2.txt" />
</concat>

Replace property in a xml file using ANT

I'm trying to replace a version number in a build.xml file using an ANT script.
I've tried various approaches, searched and re-searched StackOverflow for answers but could not get the exact query.
so here is my xml file:
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<project name="feature" default="main" basedir=".">
<target name="init">
<property name="Version" value="1.0.0.20120327"/>
</target>
<target name="main" depends="init">
<description>Main target</description>
</target>
</project>
Now as u can see the Version has yesterday's date. I need to replace it with the current date.
Here is what I've tried:
<target name="replace">
<tstamp >
<format property="touch.time" pattern="yyyyMMdd"/>
</tstamp>
<property name="Feature.dir" location="../feature" />
<!--Didnt Work-->
<copy file="${Feature.dir}\build.xml" tofile="${Feature.dir}\build1.xml"
filtering="yes" overwrite="yes">
<filterset>
<filter token="Version" value="1.0.0.${touch.time}"/>
</filterset>
</copy>
<!--Didnt work
<replacetoken><![CDATA[<property name="Version" value=""/>]]>
</replacetoken>
<replacevalue><![CDATA[<property name="Version"value="1.0.0.${touchtime}" />]]>
</replacevalue>
-->
<!-- Didnt work
<copy file="${Feature.dir}/build.xml" tofile="${Feature.dir}/build1.xml" >
<filterchain>
<tokenfilter>
<replaceregex pattern="^[ \t]*Version[ \t]*=.*$"
replace="Version=1.0.0.${touch.time}"/>
</tokenfilter>
</filterchain>
</copy>
-->
</target>
I would use replaceregex inside a filterchain.
For example:
<copy file="${Feature.dir}\build.xml" tofile="${Feature.dir}\build1.xml"
filtering="yes" overwrite="yes">
<filterchain>
<tokenfilter>
<replaceregex pattern="1.0.0.[0-9.]*" replace="1.0.0.${touch.time}"/>
</tokenfilter>
</filterchain>
</copy>
If you want to replace the file, feel free to copy to a temp file and move it back.
<tempfile property="build.temp.file.name"/>
<copy file="${Feature.dir}\build.xml" tofile="${build.temp.file.name}" ... />
<move file="${build.temp.file.name}" tofile="${Feature.dir}\build.xml" />

Combine filesets using Ant

I have 2 different filesets defined in Ant as follows:
<fileset id="fileset1" dir="${classes.dir}">
</fileset>
<zipfileset id="fileset2" src="myArchive.zip" includes="**/*.class">
</zipfileset>
I want to create a third fileset which is the union of both the above filesets
<fileset id="merged">
</fileset>
Can someone tell me how to do this ? Is it even possible to do something like that ?
Thanks in advance!
One way to do this is with Ant resource collections, in particular a union.
<fileset id="fileset1" dir="${classes.dir}" />
<zipfileset id="fileset2" src="myArchive.zip" includes="**/*.class" />
<union id="onion">
<resources refid="fileset1" />
<resources refid="fileset2" />
</union>
Then you can refer to the 'onion' anywhere you might use a fileset, e.g.
<copy todir="dest">
<resources refid="onion" />
</copy>
I recommend using generic resources elements rather than filesets for maximum flexibility.
Try this: I think it should work, since <fileset> is an implicit <patternset>.
<fileset id="fileset1" dir="${classes.dir}">
</fileset>
<zipfileset id="fileset2" src="myArchive.zip" includes="**/*.class">
</zipfileset>
EDIT: odd. This perhaps?
<patternset id="merged">
<patternset refid="fileset1" />
<patternset refid="fileset2" />
</patternset>
problem with fileset is, that it requires a directory as a base upon it applies the patternset. Which means you have to find a common base directory that is shared by all filesets.
A <pathconvert> Task can take filesets via refid. You can put several filesets (e.g. from various build targets to assemble a compound set in a root/main target for a modular build environment):
<project name="root" basedir="." xmlns:if="ant:if" xmlns:unless="ant:unless">
<!--
it's important to take the xmlns:features in your project head
otherwhise this code won't work
-->
<target name="init">
<!-- set some common prerequisites -->
<property name="prerequisite.property.xyz" value="xyz" />
</target>
<target name="targetA" depends="init">
<fileset dir="${common.basedir}${file.separator}${targetA.subdir}" id="targetA.fileset">
<include name="**/*.html" />
</fileset>
<property name="targetA.fileset.exists" value="true" />
</target>
<target name="targetB" depends="init">
<fileset dir="${common.basedir}${file.separator}${targetB.subdir}" id="targetB.fileset">
<include name="**/*.java" />
</fileset>
<property name="targetB.fileset.exists" value="true" />
</target>
<target name="targetC" depends="init">
<fileset dir="${common.basedir}${file.separator}${targetC.subdir}" id="targetC.fileset">
<include name="**/*.class" />
</fileset>
<property name="targetC.fileset.exists" value="true" />
</target>
<target name="root" depends="init">
<pathconvert property="all.files.as.commaseparated.path" pathsep="," dirsep="/">
<fileset refid="targetA.fileset" if:true="${targetA.fileset.exists}" />
<fileset refid="targetB.fileset" if:true="${targetB.fileset.exists}" />
<fileset refid="targetC.fileset" if:true="${targetC.fileset.exists}" />
<map from="${common.basedir}/" to="" />
</pathconvert>
<!-- assemble new fileset from paths as comma separated property string -->
<fileset id="new.refid" dir="${common.basedir}" includes="${all.files.as.commaseparated.path}" />
</target>
</project>
This can be called via command line like:
ant targetA targetB targetC root
or
ant targetA root
Be aware that root is always the last target being called.

Resources