NANT Script Check if Directory is Empty and then delete - nant

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>

Related

phing dbdeploy with postgres

Hiho,
I want to use Phing an dbdeploy with a postgres DB.
the problem is that I can not connect to the database with the connection string because I can not define a password.
Does any one has an solution for this?
The following is the deply xml:
`
<!-- load the dbdeploy task -->
<taskdef name="dbdeploy" classname="phing.tasks.ext.dbdeploy.DbDeployTask" />
<!-- these two filenames will contain the generated SQL to do the deploy and roll it back -->
<property name="build.dbdeploy.deployfile" value="scripts/deploy-${DSTAMP}${TSTAMP}.sql" />
<property name="build.dbdeploy.undofile" value="scripts/undo-${DSTAMP}${TSTAMP}.sql" />
<!-- generate the deployment scripts -->
<dbdeploy
url="pgsql:host=${db.host};dbname=${db.name}"
userid="${db.username}"
password=""
dir="${phing.dir}/sql"
outputfile="${build.dbdeploy.deployfile}"
undooutputfile="${build.dbdeploy.undofile}" />
<!-- execute the SQL - Use psql command line to avoid trouble with large
files or many statements and PDO -->
<trycatch>
<try>
<exec
command="pqsql -h${db.host} -U${db.username} -p${db.port} -d${db.name} < ${build.dbdeploy.deployfile} -W"
dir="${phing.dir}"
checkreturn="true"
output="${phing.dir}/cache/deploy-${DSTAMP}${TSTAMP}.log"
error="${phing.dir}/cache/deploy-error-${DSTAMP}${TSTAMP}.log"
/>
<echo msg="Datenbank erfolgreich ausgerollt"/>
</try>
<catch>
<echo msg="Fehler beim ausrollen der Datenbank, führe Rollback durch"/>
<exec
command="pgsql -h${db.host} -U${db.username} -p${db.port} -d${db.name} < ${build.dbdeploy.undofile}"
dir="${phing.dir}"
checkreturn="true"
/>
<echo msg="Rollback erfolgreich"/>
</catch>
</trycatch>
</target>
<!-- ============================================ -->
<!-- Target: writeFiles -->
<!-- ============================================ -->
<target name="writeFiles" description="Write all properties in files">
<copy
file="${dir}config/autoload/local.php.dist"
tofile="${dir}config/autoload/local.php"
overwrite="true"
>
<filterchain>
<replacetokens begintoken="#" endtoken="#">
<token key="db.host" value="${db.host}"/>
<token key="db.username" value="${db.username}"/>
<token key="db.password" value="${db.password}"/>
<token key="db.name" value="${db.name}"/>
<token key="db.port" value="${db.port}"/>
</replacetokens>
</filterchain>
</copy>
<echo>local.php geschrieben.</echo>
</target>`
You can create a password file for the system user (the user which will execute the phing script).

How do I check if a file contains a string (using 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>

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!

How to replace string in a file using NANT?

I am trying to replace the occurance of a string in a wxs file using Nant.
I have only found the following example, which uses <replaceString>, but it seems like it can only be used within the copied files. Are there any other way of replacing a string, without actually copying the files over?
<property name="NOW" value="${datetime::now()}" />
<copy todir="out">
<fileset basedir="in">
<include name="**/*" />
</fileset>
<filterchain>
<replacetokens>
<token key="NOW" value="${TODAY}" />
</replacetokens>
<tabstospaces />
</filterchain>
</copy>
Here's the code:
<loadfile file="token.txt" property="token-file">
<filterchain>
<replacetokens>
<token key="NOW" value="${datetime::now()}" />
</replacetokens>
</filterchain>
</loadfile>
The official NAnt docs for <loadfile> element contain the exact sample you need. See the bottom of the page.
Here's how I did it.
<loadfile file="${file}" property="file.content">
<filterchain>
<replacestring from="StringToMatch" to="StringToReplace" ignorecase="true" />
</filterchain>
</loadfile>
<echo file="${file}">${file.content}</echo>
So you are trying to modify a .wxs file which is XML, right?
In this particular case you might use <xmlpoke> if you are able to determine the position of the strings to replace via XPath.
I found a solution for you here: http://frank.overseakids.com/?p=182
<loadfile file=”${dir.template}\template.db_name.sql” property=”restore.db.sql.db_name”>
<filterchain>
<replacetokens>
<!– this looks for tokens like #blah.blah# in the file being loaded and replaces them–>
<token key=”restore.db.prefix” value=”${restore.db.prefix}” />
<token key=”backup.file.path” value=”${backup.file.path}” />
</replacetokens>
</filterchain>
</loadfile>
<property name=”current.db” value=”db_name” />
<property name=”current.log” value=”${dir.log}\${restore.db.logfile.prefix}_db_name.log” />
<property name=”current.file” value=”${dir.template}\restore.db_name.tmp.sql” />
<delete if=”${file::exists(current.file)}” file=”${current.file}” />
<echo file=”${current.file}”>${restore.db.sql.db_name}</echo>
You can wrap this in a <foreach /> element.
I never managed to get the filterchain and replacetokens to work properly. I ended up using this and it works great.
<replacetext filename="${filename}" src="stringToBeReplaced" replacement="replacementString" />
All these answers did not work for me, maybe because I needed to replace a string with spaces in it. Loading a file content with filterchain/replacetokens did nothing to the contents of the associated property. Maybe I'm using it wrong.
The tasks "replacestring" and "replacetext" suggested by #Ally and #John Sterne do not exist.
It's included in a Jenkins build process, thus the ENVIRONMENT variable must be set to the working dir.
<loadfile file="./my/batch.bat" property="file.content" />
<property name="file.content"
value="${string::replace(file.content, 'D:\path to\the working\space', environment::get-variable('WORKSPACE'))}" />
<property name="file.content"
value="${string::replace(file.content, 'Cd C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin', 'CD /D C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin')}" />
<echo file="./my/batch.bat">${file.content}</echo>
I had that problem today. To solve it I used the move command instead of loadfile or copy. This worked for me because since my file was pretty small. The other caution about this is that replacetokens needs a start identifier and end identifier of the token; begintoken and endtoke respectively. If those are not set the default values are the # symbol. So if you want to replace a value such as MY_SERVER_PLACE_HOLDER that means the value in your file must be #MY_SERVER_PLACE_HOLDER#. If you want your token to start with something different than you should specify the begintoken and endtoken values. That should give you an idea of the problems the begin token and endtoken will bring you.
So here is what I did in a nutshell
Moved the file to a temporary location. In that move I used
filterchain with removetokens to change the values in the file.
In step 2, I moved the file back to it's original location.
I then used the delete command to delete the temp folder I created.
Here is a what I did. (May not be syntactically correct since I am not in front of the code at the moment)
<move todir="temp">
<fileset basedir="in">
<include name="myfile.dat" />
</fileset>
<filterchain>
<replacetokens>
<token key="MY_SERVER_PLACE_HOLDER" value="http://www.someserver.com" />
</replacetokens>
<tabstospaces />
</filterchain>
</move>
<move todir="in">
<fileset basedir="temp">
<include name="myfile.dat" />
</fileset>
</move>
<delete dir="temp" />

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