Title: RE: [Nant-users] Transactionality in NAnt

Wow, this seems very interesting.  I'm going to weave this into our process and see what happens.  You may have just saved me weeks of work.

When is the nant.rollback.onfailure.chain property set?  It would seem that they would be included at the point in the XML where they are imported, thus they would be evaluated and set before the all target is performed. If I place the rollback code directly into my projects can I have the nodes at the top or do they need to be at the bottom?

Payton Byrd
Trane eBusiness
QED Team
Phone: 931-905-5386
Fax: 931-648-5901

-----Original Message-----
From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]] On Behalf Of Troy Laurin
Sent: Tuesday, January 25, 2005 11:14 PM
To: [EMAIL PROTECTED] Sourceforge. Net
Subject: Re: [Nant-users] Transactionality in NAnt

Merrill Cornish wrote:
> Bevan,
>
>
>>>>every task needs to have built in "smarts" to support rollback.
>
>
> Perhaps you have suggested an elegant way of providing
 > transaction-like operation while not putting undue stress
 > on Charlie.
>
> What if each <target> definition could include an OPTIONAL
 > error recovery <target>.  As long as you can get by with
 > target-level rollback (rather than task-level), it should
 > give most of the hooks you need while not being a huge,
 > buggy burden to implement.
>
> Merrill

May I suggest a solution that provides full reverse-rollback
functionality with out-of-the-box NAnt 0.85?
Completely flexible, configurable, and not spaghetti code.  Well, IMHO.
  Comments welcome and invited.

Features:
  * Arbitrary level of rollback control.  You can specify rollback
blocks per task, per target, or per set of tasks.
  * 100% control over rollback behaviour.  The person who knows best
what needs to be done to roll a particular action back is you.

Drawbacks:
  * This is all-or-nothing rollback.  There's no way to specify
checkpoints, or to continue processing after rolling back and recovering.
  * Somewhat fragile.  If anyone messes with any of the magic
properties, then rollback will fail.

If someone really wanted a more robust rollback mechanism, then the idea
behind what's going on below can be translated into a set of tasks with
little difficulty... register a build listener to react to onfailure (or
onsuccess, if you want commit support!) events and trigger rollback, you
could also offer explicit rollback (and commit) tasks, as well as nested
or grouped transactions.  There's no need to go messing with the NAnt
core to do something which is 100% process.


The solution itself!  Tested to work in 0.85 rc1.  Play around with the
failure in the test script... move it around, and confirm that it will
only roll back tasks that have been performed.


File 1: General include file "rollback.xml"
<project name="Rollback">
     <property name="nant.rollback.onfailure.chain"
         value="${nant.onfailure}"
             if="${property::exists('nant.onfailure')}" />
     <property name="nant.rollback.onfailure.chain"
         value=""
         unless="${property::exists('nant.onfailure')}" />
     <!-- If nant.onfailure is already set, set up an onfailure
          chain so all onfail targets are called -->

     <property name="nant.onfailure" value="rollback" />
     <property name="rollback.stack" value="" />
     <!-- Initialise the rollback stack -->

     <target name="rollback">
         <echo level="Debug"
             message="Rollback stack = &quot;${rollback.stack}&quot;" />
         <foreach item="String" in="${rollback.stack}" delim=" "
             property="rollback.target">
             <if test="${string::get-length(rollback.target) > 0}">
                 <!-- Skip empty targets, presumably from extra
                      delimiters -->
                 <call target="${rollback.target}"
                     if="${target::exists(rollback.target)}" />
                 <echo level="Warning"
                     message="Rollback target ${rollback.target} unknown"
                     unless="${target::exists(rollback.target)}" />
             </if>
         </foreach>
         <if test="${target::exists(nant.rollback.onfailure.chain)}">
             <!-- Continue the onfailure chain -->
             <call target="${nant.rollback.onfailure.chain" />
         </if>
     </target>
</project>

File 2: Specific build file "rollback-test.xml"
<project name="RollbackTest" default="all">
     <include buildfile="rollback.xml" />

     <target name="foo.perform">
         <echo message="Performing foo..." />
         <property name="rollback.stack"
             value="${rollback.stack} foo.rollback" />
     </target>
     <target name="foo.rollback">
         <echo message="Rolling back foo!" />
     </target>

     <target name="bah.perform">
         <echo message="Performing bah step 1..." />
         <property name="rollback.stack"
             value="${rollback.stack} bah.rollback.1" />
         <fail message="Failed!" />
         <echo message="Performing bah step 2..." />
         <property name="rollback.stack"
             value="${rollback.stack} bah.rollback.2" />
     </target>

     <target name="bah.rollback.1">
         <echo message="Rolling back bah step 1!" />
     </target>
     <target name="bah.rollback.2">
         <echo message="Rolling back bah step 2!" />
     </target>

     <target name="all" depends="foo.perform, bah.perform" />
</project>


-T


-------------------------------------------------------
This SF.Net email is sponsored by: IntelliVIEW -- Interactive Reporting
Tool for open source databases. Create drag-&-drop reports. Save time
by over 75%! Publish reports on the web. Export to DOC, XLS, RTF, etc.
Download a FREE copy at http://www.intelliview.com/go/osdn_nl
_______________________________________________
Nant-users mailing list
Nant-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nant-users

Reply via email to