Data TypesIn addition to the syntax of the build files, there are several useful datatypes in NAnt. These datatypes can change the way a task functions and can simplify complex actions. FilesetFrequently, a build operates on a file: it compiles a file, copies a file, deletes a file, and so forth. A fileset is a set or collection of files to apply an operation to. For example, look at the copy task's use of filesets:<copy todir="release"> <fileset basedir="bin"> <includes name="*.*"/> <excludes name="*.pdb"/> <excludes name="*.obj"/> </fileset> </copy> This code will copy all files except .pdb and .obj from the bin directory to the release directory. PatternsetPatternsets allow modification to a fileset based on a pattern (see Table 4.1).
Listing 4.2. Patternsets with the csc Task<csc target="library" debug="${debug}" output="${releasedir}\LogKit.Net.dll" doc="${docdir ![]() <sources basedir="..\src\org\apache\log"> <includes name="**/*.cs" /> </sources> <references> <includes name="System.dll" /> <includes name="System.Collections.dll" /> <includes name="System.Data.dll" /> </references> <arg value="/nowarn:1591" /> </csc> This compiles all C# files under the ..\src\org\apache\log directory. OptionsetsAn optionset is an alternative way for a task to receive input. Typically, tasks use XML attributes to receive input, but this doesn't always make sense. Consider the SlingshotTask's use of an optionset:<slingshot solution="MySolution.sln" format="nant" output="MySolution.build"> <parameters> <option name="build.basedir" value="..\bin"/> </parameters> </slingshot> Environment VariablesBy using the <sysinfo> task, you can access any environment variables in the build. Listing 4.3 is an example of using system environment variables: Listing 4.3. The sysinfo Task<sysinfo verbose="true"/> <copy todir="${sys.env.BASEDIR}"> _ Copy to a directory set in <fileset basedir="bin"> the environment. <includes name="*.dll"/> <includes name="*.exe"/> </fileset> </copy> PropertiesProperties allow for changing the behavior of a build, just as properties on a component alter that component's behavior (see Executing NAnt" in this chapter). Handling Multiple Versions of .NETThrough the use of the nant.settings.currentframework.version property, you can safeguard your builds against a user who has the wrong version of the .NET runtime. ReferencesThe version of .NET used to compile mainly affects what .NET framework assemblies are used as references in the compiler task. Listing 4.4 shows a common use of reference filesets. Listing 4.4. Filesets<csc target="library" output="${output}" debug="${debug}" define="${define}" doc="${doc}"> <sources> <includes name=" *.cs" /> </sources> <references> <includes name="System.dll" /> <includes name="System.Data.dll" /> <includes name="System.Drawing.dll" /> <includes name="System.Windows.Forms.dll" /> <includes name="System.Xml.dll" /> <includes name="Accessibility.dll" frompath="true" /> <includes name="System.Web.dll" /> <includes name="System.Web.Services.dll" /> </references> </csc> For a second, I want to take a brief sidetrack and talk about how NAnt knows to compile C# code. Currently, the NAnt csc task wraps the command-line compiler, but how does it know where to find that compiler, you might ask? That is a great question. The csc task in Listing 4.5 will compile using the default framework version of .NET (or other CLI implementation) that is specified in the nant.exe.config. The first frameworkinfo element is complete, and the following ones are abbreviated just to show you the CLI frameworks supported by NAnt. Listing 4.5. Configuration File Showing NAnt CLI Framework Support<nantsettings defaultframework="net-1.0"> <frameworks> <frameworkinfo name = "net-1.0" description = "Microsoft .NET Framework 1.0" version = "1.0.3705" runtimeengine=" csharpcompilername = "csc" basiccompilername = "vbc" jsharpcompilername = "vjc" jscriptcompilername = "jsc" resgenname = "resgen"> <sdkdirectory useregistry="true" regkey="Software\Microsoft\.NetFramework" ![]() <frameworkdirectory useregistry="true" regkey="Software\Microsoft ![]() <frameworkassemblydirectory useregistry="true" regkey="Software\Microsoft ![]() </frameworkinfo> <frameworkinfo name = "net-1.1" description = "Microsoft .Net Framework 1.1" ... </frameworkinfo> <frameworkinfo name = "netcf-1.0" description = "Microsoft .Net Compact Framework Framework 1.0" ... </frameworkinfo> <frameworkinfo name = "mono-1.0" description = "gnome projects port of the .Net Framework" ... </frameworkinfo> </frameworks> NOTERegarding the nant.exe.config in Listing 4.5, if you get an error from NAnt saying that it cannot find the DefaultFramework, then you know right where to go: the config file.OK, back to the references discussion. The references in Listing 4.4 would be the same as using the asis parameter and setting it to true, as seen here:<includes name="System.dll" asis="true" /> Unfortunately, filesets do not handle relative paths very well, so if you are using a third-party assembly like Log4Net, then you have to do something different. The following relative path will NOT always work, depending upon what the basepath is.<includes name="..\..\log4net.dll" /> In order to include this assembly reference, you can either use the basedir property on the references fileset:<references basedir="${build.dir}/bin"> <includes name=" log4net.dll" />. </references> use the frompath property on the include node:<includes name=" log4net.dll" frompath="true" /> or read the path from the environment variables:<includes name=" ${sys.env.AssemblyDirectory}\log4net.dll" /> Handling Multiple Versions of NAntSimilarly to multiple versions of .NET, you may run into a problem with a user who has an outdated version of NAnt. Depending on the tasks used in your build, this could either produce the wrong result or cause a NAnt build exception for a missing task. If this is a concern, check the nant.version property and ensure it is at least the version you require. Embedded ScriptingAlthough not technically a property, the example of Embedded Scripting fits well under this section of the chapter. For the truly advanced user who wants functionality that NAnt just does not support, there is an answer: Embedded Scripting. NAnt allows for embedded C# and VB.NET scripts to be executed within a target. Most often the base tasks within NAnt are sufficient enough, and embedded scripts are not needed. The danger of embedded scripts is that the code is obviously unique and has the potential for bugs. In contrast, the tasks that are intrinsic to NAnt have a considerable runtime and testing user base. Listing 4.6 is from the NAnt WIKI site (http://nant.sourceforge.net/wiki/) and lists all available properties. Listing 4.6. NAnt Scripting<script language="C#"> <code><![CDATA[ public static void ScriptMain(Project project) { Log.WriteLine("Properties:"); foreach(DictionaryEntry entry in project.Properties) { Log.WriteLine(string.Format("{0}={1}", entry.Key, entry.Value)); } } ]]></code> </script> Error HandlingWhen an error occurs in a NAnt build, the build automatically fails and does not continue. The output to the command window will indicate what line the build failed on. If the failure is a compiler error, the offending code's line number is given. NAnt provides two special properties for handling error conditions in a build project: nant.onsuccess and nant.onfailure. Listing 4.7 shows the use of nant.onfailure to email a failure report. Lisitng 4.7. Emailing Failures<property name='nant.onfailure' value='emailfailure'> <target name="email failure"> from="buildmaster " tolist="devgroup@yourdomain.com" cclist=" subject="Build Failed" message=" Build Failed " mailhost="mail.yourdomain.com" /> </target> The value of the onfailure task is the name of task in the existing project that you want to execute on a failure. LoggingChapter 8, "Application Logging") to log to an output file. This will log the messages that are put to the screen. Some tasks may include more logging information than others, but you can always use the <echo> task to indicate milestones in the build. Used together with error handling, Listing 4.7 can be extended to include emailing the results of the build, as in Listing 4.8. Listing 4.8. Emailing Build Results<property name='nant.onfailure' value='failure'> <property name='nant.onfailure' value='success> <target name="success"> <property name='emailsubjet' value='Build Success'> <property name=' emailmessage' value='Build Succeeded.'> <call target="email"> </ target> <target name="failure"> <property name='emailsubjet' value='Build Failed'> <property name=' emailmessage' value='Build Failure See attached log.'> <call target="email"> </ target> <target name="email "> from="buildmaster " tolist="devgroup@yourdomain.com" cclist=" subject="${emailsubjet}" message=" ${emailmessage}" file="build.log" mailhost="mail.yourdomain.com" /> </target> To set the location of the build file's log, look back to the section "Executing NAnt." |