apache Ant basename issue with empty input strings - ant

I have the below ant code which gives basename (for ex: abc_01142018.txt) of the file from location input.dir. When the file is available, it works as expected.But when there are no files in input.dir it is picking up a value which I am not passing. I am expecting it to be empty value.
I read about basename and its not mentioned anywhere about how basename works when the input parameter is empty.
<path id="ref-id">
<fileset dir="${input.dir}">
<include name="abc*.txt"/>
</fileset>
</path>
<property name="input.files" refid="ref-id"/>
<basename property="input.file" file="${input.files}" />

There's no need to use Ant's path type or basename task if all you want is a list of file names without parent directories. The fileset type already does this, so just reference its ID instead.
Example:
<target name="test">
<touch file="exists1.txt" />
<touch file="exists2.txt" />
<fileset dir="." id="exists">
<include name="exists*.txt" />
</fileset>
<fileset dir="." id="doesnotexist">
<include name="doesnotexist*.txt" />
</fileset>
<property name="exists" refid="exists" />
<property name="doesnotexist" refid="doesnotexist" />
<echo message="${exists}" />
<echo message="${doesnotexist}" />
</target>

Related

how to use<MacroDef> for recourcecount of all file in folder with different extension

While going through the scenario what i got is that folder collection of different extension file i have use resource count for all extension if i have 3 different extension file than try to get resource count of all file differ with extension
Eg:
<resourcecount property="firstfile">
<fileset dir="${basedir}">
<include name="*.xml" />
</fileset>
</resourcecount>
<echo message="There are ${firstfile} xml in This Folder ${basedir}" />
<resourcecount property="SecondFile">
<fileset dir="${basedir}">
<include name="*.jar" />
</fileset>
</resourcecount>
<echo message="There are ${SecondFile} xml in This Folder ${basedir}" />
How can i use the macrodef for this condition which help in count all file with it
You can do this in many ways, including using plugins, such as ant-contrib, or using ant language extensions. But all of them are overkill compared to this simple build script:
<target name="count">
<countresources type="xml" />
<countresources type="java" />
<countresources type="cpp" />
</target>
<macrodef name="countresources">
<attribute name="type" />
<sequential>
<resourcecount property="#{type}.count">
<fileset dir="${basedir}">
<include name="*.#{type}" />
</fileset>
</resourcecount>
<echo message="There are ${#{type}.count} #{type} files in folder ${basedir}" />
</sequential>
</macrodef>
Hope this helps.

Read the each file name and check for the string using ant

I have particular requirement. I have multiple reports file in particlar directly. Currently I build up ant script reading all files and checking for the particular string using the below code.
<target name="GenerateReports" >
<property name="search.string" value="Internal Error" />
<fileset id="existing" dir="${report.dir}">
<patternset id="files">
<include name="*.txt" />
</patternset>
</fileset>
<fileset id="matches" dir="${report.dir}">
<patternset refid="files" />
<contains text="${search.string}" />
</fileset>
<fail message="Found '${search.string}' in one or more test cases results in '${report.dir}' One or more test cases are failed">
<condition>
<resourcecount when="greater" count="0" refid="matches" />
</condition>
</fail>
</target>
But i want to read each file and give the name of the file where the error exists in my report file.
How to read the each file name and read the content also.
<foreach target="-List-File-Names" param="foreach.file" inheritall="true">
<path>
<fileset dir="${report.dir}" includes="*.txt">
<contains text="${search.string}" />
</fileset>
</path>
</foreach>
<target name="-List-File-Names">
<dirname property="file.dir" file="${foreach.file}"/>
<!-- dirname now holds the file -->
</target>

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.

Ant concat fileset separator

When using concat with fileset in Ant, how do I make an action happen for each element in the fileset. Such as, adding a string:
<fileset dir="${project.path.scripts-library}"
excludes="!*.js, **/*.bak, **/dev.*"
>
<type type="file" />
<include name="**/0*.js" />
<include name="**/1*.js" />
<string>test</string>
</fileset>
Or echoing the current file name for each file in the fileset (and, how do I GET the file name for the current file???):
<fileset dir="${project.path.scripts-library}"
excludes="!*.js, **/*.bak, **/dev.*"
>
<echo file="${app.path.file}"
append="true"
message=",${the.file.name}" />
<type type="file" />
<include name="**/0*.js" />
<include name="**/1*.js" />
</fileset>
I think there is no such thing in default ant. The closest one is <apply>, but it's system specific:
<apply executable="echo"> <!-- run this command with each file name -->
<fileset dir="/tmp" includes="**/*.*"/>
</apply>
Also you can install ant-contrib to enable <for> task:
<taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
<for param="file">
<path>
<fileset dir="/tmp" includes="**/*.*"/>
</path>
<sequential> <!-- run any task here -->
<echo>file [#{file}]</echo>
</sequential>
</for>

How can I print a fileset to a file, one file name per line?

I have a populated fileset and I need to print the matching filenames into a text file.
I tried this:
<fileset id="myfileset" dir="../sounds">
<include name="*.wav" />
<include name="*.ogg" />
</fileset>
<property name="sounds" refid="myfileset" />
<echo file="sounds.txt">${sounds}</echo>
which prints all the files on a single line, separated by semicolons. I need to have one file per line. How can I do this without resorting to calling OS commands or writing Java code?
UPDATE:
Ah, should have been more specific - the list must not contain directories. I'm marking ChssPly76's as the accepted answer anyway, since the pathconvert command was exactly what I was missing. To strip the directories and list only the filenames, I used the "flatten" mapper.
Here is the script that I ended up with:
<fileset id="sounds_fileset" dir="../sound">
<include name="*.wav" />
<include name="*.ogg" />
</fileset>
<pathconvert pathsep="
" property="sounds" refid="sounds_fileset">
<mapper type="flatten" />
</pathconvert>
<echo file="sounds.txt">${sounds}</echo>
Use the PathConvert task:
<fileset id="myfileset" dir="../sounds">
<include name="*.wav" />
<include name="*.ogg" />
</fileset>
<pathconvert pathsep="${line.separator}" property="sounds" refid="myfileset">
<!-- Add this if you want the path stripped -->
<mapper>
<flattenmapper />
</mapper>
</pathconvert>
<echo file="sounds.txt">${sounds}</echo>
Since Ant 1.6 you can use toString:
<echo file="sounds.txt">${toString:myfileset}</echo>

Resources