Wrestling with NAnt, MySQL and Input Scripts
I'm writing an automated database build for a project I'm working on and wanted to avoid having to write batch scripts with paths that are tightly coupled to the build environment. I managed to write out the NAnt targets exactly the way that I wanted:
<?xml version="1.0"?> <project name="Project"> <property name="sql.dir" value="${base.dir}/sql" /> <property name="initialize.ddl" value="${sql.dir}/initial.ddl.sql" /> <target name="db.init"> <call target="db.create" /> </target> <target name="db.create" description="Creates the Database and tables"> <exec basedir="${mysql.dir}" program="mysql.exe" workingdir="${build.artifacts.dir}"> <arg value="--user=${mysql.user}" /> <arg value="--password=${mysql.password}" /> <arg line="< ${initialize.ddl}" /> </exec> </target> </project>
Unfortunately when I run the db.create task it fails. I don't get any clear errors messages, only output from mysql.exe that explains how it should be called. I tried the syntax manually from the command line and it worked no problem. The line where I have the XML encoded less than sign seems to be the culprit but I can't figure out how the syntax should be.
I ended up working on it much longer than I wanted to and still never figured it out. I ended up re-doing it using a template batch script. The batch script contains some placeholders that NAnt will replace using a filter chain. This means that with some tweaks to the local properties and the NAnt task and batch script will work on any box. I think it's ugly, but it works.
Here's the NAnt Xml:
<?xml version="1.0"?> <project name="Project"> <property name="sql.dir" value="${base.dir}/sql" /> <property name="sql.exec" value="${sql.dir}/sql-exec.bat" /> <target name="db.init"> <call target="db.create" /> </target> <target name="expand.sql-exec.template"> <copy file="${sql.exec}.template" tofile="${sql.exec}" overwrite="true"> <filterchain> <replacetokens> <token key="mysql.dir" value="${mysql.dir}" /> <token key="mysql.user" value="${mysql.user}" /> <token key="mysql.password" value="${mysql.password}" /> <token key="sql.script" value="${sql.script}" /> </replacetokens> </filterchain> </copy> </target> <target name="execute.sql.script"> <exec basedir="${sql.dir}" program="${sql.exec}" workingdir="${sql.dir}"> </exec> </target> <target name="db.create" description="Creates the Database and tables"> <property name="sql.script" value="initial.ddl.sql" /> <call target="expand.sql-exec.template" /> <call target="execute.sql.script" /> </target> </project>
And the sql-exec.bat.template looks like:
"@mysql.dir@\mysql.exe" --user=@mysql.user@ --password=@mysql.password@ < @sql.script@
The variables that I'm using in both NAnt scripts are inside a file called local.properties.xml which are always machine specific and not in the version controlled files. If anyone can drop me a hint on how to get the first syntax style working please let me know.
Similar Posts
- Unit Testing Domain Persistence With NDbUnit, NHibernate and SQLite
- My Developer Resolutions For 2009
- My Developer Resolutions For 2010

Comments
Bigrockfan on on 12.29.2008 at 6:50 PM
I am on the seat of my pants wondering if you are going to figure this problem out. I got this twitter message halfway thought the new Bond film and had to leave the theatre because I started fretting about your NAnt script issue. I even asked the guy sitting next to me but he just told me to shut up and stole some of my popcorn.
Can you hurry up and post again before New Year's eve? I would hate to cancel my plans because of distraction.