Now that we've got some custom tasks, they might not behave as
expected. The next problem is debugging these tasks. The biggest
issue with this is if it's a problem that only is exposed on the build
machine. In our case at Atalasoft, builds are complicated to start.
I've made the build scripts generic enough that they can follow branches, and
the changes are reflected through command line flags to NAnt that change the
build script behavior. As a result, starting these builds in
as-close-as-possible way to the build server environment means running in the
build environment, and the build environment get's kicked by cruise
control. Without some really amazing timing, attaching to that NAnt
process in the debugger is hard, right? Wrong. Enter: System.Diagnostics.
Ok, this is nothing new to most developers, but you can make NAnt and
System.Diagnostics play off each other in a way that makes your scripts and
custom tasks easy to debug.
On my first iteration, I simply put a Debugger.Launch();
call in where I wanted the debugger to be attached. This is all well and
good, except that I have to rebuild the assembly and distribute it to the build
server. Having 3 build servers and our NAnt tasks in source control, this
isn't such a simple process. Instead, I wanted to make sure I could
easily change the build script on specific tasks where I needed debugging, and
only there. For this, I refactored the Tasks types, and stuck in a new AtalaTask class, which is to be inherited by all my custom
tasks. AtalaTask inherits NAnt.Core.Task,
and places one more boolean task attribute in (like
the "verbose" attribute in Task) called "debug,” and has its own
AtalaExecuteTask() to take place of the ExecuteTask(). But having this AtalaTask
type means I can make global changes to all my custom tasks easily in the
future:
using NAnt.Core;
using
NAnt.Core.Attributes;
using
System.Diagnostics;
namespace
Atalasoft.NAnt.Tasks
{
public abstract class AtalaTask : Task
{
protected
bool _debugTask = false;
[TaskAttribute("debug", Required = false)]
[BooleanValidator()]
public bool DebugTask {
get
{ return _debugTask; }
set
{ _debugTask = value; }
}
protected
override void
ExecuteTask()
{
if
(DebugTask && !Debugger.IsAttached)
Debugger.Launch();
AtalaExecuteTask();
}
protected
abstract void
AtalaExecuteTask();
}
}
Now, when you enter the debugger you can set a breakpoint in your AtalaExecuteTask()
function and do a little jig. To take
advantage of this, just set the debug attribute on your task to true and the
debugger will prompt you when it hits that point:
<AtalaFileRegex
debug="true">

Now you can get smashing on that F10 key!