How do I check if a file contains a string (using Nant)? - nant

At the moment I'm calling findstr and storing the output in a property to check afterwards - I'm sure there must be a better solution.
<exec program="findstr.exe"
workingdir="${workspaceDir}"
commandline='/i /c:"someText" ${fileName}'
failonerror="false"
output="${coverageExcludeLog}"
resultproperty="foundFile"
/>
Is this really the best way of doing this?

<loadfile file="${fileName}" property="MyFileContents" />
<property name="Mystring" value="someText" />
<property name="search.file" value="${string::contains(MyFileContents, Mystring)}" />
<if test="${bool::parse(search.file)}" > <!-- true or false-->
<echo message="Found the string ${Mystring} in the file ${fileName}" />
</if>

Related

NAnt property::exists() with newly defined property?

In NAnt 0.92, I define a property and immediately after checks it's existence. It doesn't exists... but it exists in a called target. Is this a bug or a feature?!? I search in the documentation but could not find a mention of it.
<target name="test">
<property name="testprop" value="test value" />
<echo message="property value = ${testprop}" />
<if test="${property::exists(testprop)}">
<echo message="property exists, as it should!" />
</if>
<if test="${not property::exists(testprop)}">
<echo message="property doesn't exists... WTF?" />
</if>
<call target="test2" />
</target>
<target name="test2">
<echo message="property value in sub-target = ${testprop}" />
</target>
Output:
test:
[echo] property value = test value
[echo] property doesn't exists... WTF?
test2:
[echo] property value in sub-target = test value
The name of the property needs to be quoted in your call to property::exists. So this is it:
<if test="${not property::exists('testprop')}">
<echo message="property doesn't exists... WTF?" />
<!-- don't swear -->
</if>
Update: What does happen in your example? The unquoted property testprop is replaced by it's value in your call to function property::exists. So you're in fact probing property test value (which BTW isn't a valid property name). Check this out:
<target name="test">
<property name="test.value" value="foo" />
<property name="testprop" value="test.value" />
<echo message="property value = ${testprop}" />
<if test="${property::exists(testprop)}">
<echo message="property exists, as it should!" />
</if>
<if test="${not property::exists(testprop)}">
<echo message="property doesn't exists... WTF?" />
</if>
</target>
Output:
[echo] property value = test.value
[echo] property exists, as it should!

NANT Script Check if Directory is Empty and then delete

I am trying to do following.
I have a root folder and under that 4 subfolders.
Check if a Directory under root is empty or not.
if yes, delete the directory.
Can you please help.
NAnt's delete task in addition with NAntContrib's fileset::has-files function will do the trick.
UPDATE: Here is an example assuming you have a root folder named foo and subfolders named bar1 to bar4:
<target name="go">
<loadtasks assembly="C:\YourPathToNAntContrib\bin\NAnt.Contrib.Tasks.dll" />
<property
name="root"
value="C:\foo" />
<property
name="subfolders"
value="bar1,bar2,bar3,bar4" />
<foreach
item="String"
in="${subfolders}"
delim=","
property="subfolder">
<property
name="basedir"
value="${path::combine(root, subfolder)}" />
<fileset
id="files"
basedir="${basedir}">
<include name="**/*" />
</fileset>
<if test="${not fileset::has-files('files')}">
<delete dir="${basedir}" />
</if>
</foreach>
</target>

Nant: Find file by pattern

What I am trying to do, is to find a file with NAnt. This file could by anywhere in a directory structure of a given folder.
I tried to this with the NAnt-foreach task (this works) but I am not quite convinced of that:
<target name="find-file">
<fail message="Property param.dir must be set" unless="${property::exists('param.dir')}" />
<fail message="Property param.pattern must be set" unless="${property::exists('param.pattern')}" />
<property name="return.file" value="" />
<foreach item="File" property="iterator.file">
<in>
<items>
<include name="${param.dir}\**\${param.pattern}" />
</items>
</in>
<do>
<property name="return.file" value="${iterator.file}" if="${string::get-length(return.file) == 0}" />
</do>
</foreach>
</target>
Is there anybody aware of a better approach? If not how can I accomplish to exit the foreach-loop after the first element is found?
This nantcontrib function will put the matching filenames into a delimited string..
If you know that only one matching file will exist then it may get you what you want. If there are several then you could use the nant substring function to just get the first match by taking the substring up to the first delimiter.
The following nant script:
<?xml version="1.0" encoding="utf-8"?>
<project default="find-file2">
<property name="NantContrib.dir" value="C:\Program Files\nantcontrib-0.85\" readonly="true" />
<target name="LoadNantContrib">
<loadtasks assembly="${NantContrib.dir}bin\NAnt.Contrib.Tasks.dll" />
</target>
<target name="find-file2" depends="LoadNantContrib">
<fileset id="find.set">
<include name="${param.dir}\**\${param.pattern}" />
</fileset>
<property name="return.file" value="${fileset::to-string('find.set', ' | ')}" />
<echo message="return.file=${return.file}"/>
<echo message="Found ${fileset::get-file-count('find.set')} files"/>
</target>
</project>
...and the following folder structure:
\---folderroot
+---folder1
| dontfindme.txt
| findme.txt
|
+---folder2
| dontfindme.txt
|
\---folderempty
...works as expected. Searching for findme.txt finds one file. Searching for dontfindme.txt finds two files. Searching for *.txt finds three files.
Example call:
nant -D:param.dir=folderroot -D:param.pattern=findme.txt
Example output:
find-file2:
[echo] return.file=C:\Documents and Settings\rbaker\My Documents\nantfindfile\folderroot\folder1\findme.txt
[echo] Found 1 files
BUILD SUCCEEDED

Perform a simple calculation in NANT program

I need to do a simple addition in NANT program like 1 + 1 =2. I am finding it difficult as every variable is taken as string by default in NANT. I have also tried using int::parse but it did not work.
Regards
Sarathy
Perhaps you can use convert::to-int. There's also an operator overview here.
I also found two examples that perhaps help to understand overall usage (example 1, example 2):
From example 1:
<if test=“${int::parse(UnitTestsResult) != 0}“>
<fail message=“Atleast one unit test failed!“/>
</if>
From example 2:
<target name="repeat">
<property name="var1" value="0" overwrite="false" />
<echo message="${var1}" />
<property name="var1" value="${convert::to-int(var1) + 1)" />
<call target="repeat" if="${convert::to-int(var1) < 10}" />
</target>
<property name="a" value="1"/>
<echo message="${int::parse(a) + 2}" />
Gives:
[echo] 3

nant: expanding properties in a string

Summary:
How do I expand a property with value "download\${bulidmode}\project\setup.msi" to "download\Debug\project\setup.msi" if the property buildmode contained debug so I can use it as the file="" part of < copy >
Detail:
I have a bit of a requirement to be able to expand properties within a string in nant.
For example I have a target that is copying file A to B. A and B both come from a simple two field CSV file which I'm iterating through using
<foreach item="Line" in="filelist.csv" delim="," property="source.file,target.file">
<property name="sourcefile" value="${path::combine(source.dir,source)}" />
<property name="targetfile" value="${path::combine(download.dir,destination)}" />
<echo message="Copy ${sourcefile} to ${targetfile}" />
<copy file="${sourcefile" tofile="${destination}" />
</foreach>
and the filelist.csv will be
build\manifest.xml
solutiondirectory\setup-proj-directory\Release\setupproj.msi,ProductA\ProductA.msi
solutiondirectory\another-proj-dir\Release\setupproj.msi,ProductB\ProductB.msi
(The reason we split these out is that we write multi-tiered applications and deploy by MSI to each tier - so one product has multiple msi's all built with the same version numbers)
Anyway - I want to change this to that I no longer have "Release" in the filelist.csv file but something like ${build.mode}. I would wrap the above code with a
<foreach item="String" in="Release,Debug" delim="," property="build.mode">
....as above
</foreach>
and the property embedded within the string in the file gets expanded.
I've been beating my head against a brick wall for a few hours, but just can't figure it out.
Thanks
It is possible with a custom function :
<?xml version="1.0"?>
<project>
<script language="C#" prefix="vbfox" >
<code>
<![CDATA[
[Function("expand")]
public string ExpandString(string str)
{
return Project.Properties.ExpandProperties(str, Location.UnknownLocation);
}
]]>
</code>
</script>
<property name="hello" value="{path::combine('_hello_', '_world_')}" />
<property name="hello" value="${'$' + hello}" />
<echo message="${hello}" />
<echo message="${vbfox::expand(hello)}" />
</project>