Dec 15, 2008

Template expansion with nAnt

If you have a nAnt driven build system, or are planning on putting one together, template expansion can be a very useful tool. It helps you account for variability in the build environment, be it on developer machines or the build server. I’ve posted a couple of links before for nAnt, (see JP’s excellent tutorial series) but this one keeps coming up so I figured I’d dedicate a post to it.

You can simply define properties in your build file and .config templates (or other templates) with tokens to be replaced with property values. When you copy the template file over, the tokens can be replaced by their respective property values, using the filterchain feature.

Here’s a very simple file that doesn’t do much besides copy a .config file over to the deploy folder and expand the tokens in it; right below it there is a section of the web.config.template we will use;

   1: <?xml version="1.0"?>
   2: <project name="eploringormpatterns">
   3:   <property name="connection.string" value="Data Source=ARES;Initial Catalog=ormpatterns;Integrated Security=True" />
   4:  
   5:   <target name="expand.template" default="true">
   6:     <copy file="src\web\web.config.template" tofile="deploy\web\web.config">
   7:       <filterchain>
   8:         <replacetokens>
   9:           <token key="connection.string" value="${connection.string}" />
  10:         </replacetokens>
  11:       </filterchain>
  12:     </copy>
  13:   </target>
  14: </project>

   1: <?xml version="1.0"?>
   2: <configuration>
   3:   <connectionStrings>
   4:     <add name="ormpatterns" connectionString="@connection.string@"
   5:         providerName="System.Data.SqlClient" />
   6:   </connectionStrings>
   7: </configuration>

When you run this build file the web.config.template file will be copied over to “deploy\web\web.config” and the @connection.string@ token will be replaced with the value in the property with the same name.

It would be nice if we didn’t need to touch the .build file every time we needed to customize a property. Well, there’s a way to do that. We can extract the properties that vary in a separate file, say local.settings.xml and include that in the build file. That way we only need to change a tiny file to make the build run in our environment. We end up with something like the file below:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <properties>
   3:   <property name="connection.string" value="Data Source=ARES;Initial Catalog=ormpatterns;Integrated Security=True" />  
   4: </properties>

and in the build file we include the local.settings.xml file like so:

   1: <include buildfile="local.settings.xml" />

Now we have one simple file to edit in order to account for changes in the environment and we never have to touch the build file for small changes.

On a final note, when setting up your nAnt build system, try to avoid folders with spaces in the name. This will save you much pain and suffering,