You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by Matt Denner <ma...@evtechnology.com> on 2001/09/06 13:20:06 UTC

conditional logic and making it nicely extensible

Dear all,

my first mail to this so if i'm out of order or in the wrong place then bash
me know :)

i have been given the task of maintaining and upgrading our Ant build system.
after spending a few days separating out generic tasks into nice files and
writing a few new Ant tasks i have come to a point where i really want to
get down into the Ant code and make (what i think are) some valuable changes.

i have written a couple of neat
org.apache.tools.ant.taskdefs.condition.Condition derived classes:

* IsPropertySet (that will return true from eval() if the property is set)
* IsTargetDefined (that returns true from eval() if the target is defined
   in the project).

around these i've written a class called ConditionWrapper that allows me to
extend the condition logic in Ant without having to change the code.  so, in
my project i might write:

<conditionwrapper class="com.evtechnology.ant.IsPropertySet">
   <param name="property" value="build.this.now"/>
</conditionwrapper>

to get a condition that, if the 'build.this.now' property is set, will do
something.  i even updated the ConditionBase class to access an instance of
ConditionWrapper so you can do things like <not><conditionwrapper...></not>.

i then had a look at CallTarget (which is the <antcall> element) and made
that have a conditional bit so that i could do:

<antcall target="build.something">
   <conditionwrapper class="com.evtechnology.ant.IsTargetDefined">
     <param name="target" value="build.something"/>
   </conditionwrapper>
</antcall>

so that the call to the 'build.something' target will only occur if the
target exists.

suddenly it dawned on me that what i really wanted was something that would
allow me to execute different tasks based on a generic condition.  something
like:

<conditionaltask>
   <conditionwrapper class="com.evtechnology.ant.IsTargetDefined">
     <param name="target" value="build.something"/>
   </conditionwrapper>
   <success>
     <antcall target="build.something"/>
   </success>
   <failure>
     <echo message="Build target 'build.something' doesn't exist"/>
   </failure>
</conditionaltask>

which would, if the condition passed (which could be any of the Condition
classes) execute the <success> actions, and if it failed would execute the
<failure> actions.  something like:

<conditionaltask>
   <available file="xyz.txt"/>
   <success><property name="file.there" value="true"/></success>
   <failure/>
</conditionaltask>

is exactly the same as doing the simple <available> but would offer the
ability to set the value of 'file.there' to something if the file is
available and something different if it isn't.

[ jees, will this guy ever get to the point? ed :) ]

finally, here's why this whole message was started: rather than have to
create a ConditionalTask class that will have addOr(), addNot(), addXYZ()
methods, i'd rather try to make ant handle an addCondition() generically.
so my ConditionalTask might look like:

public final class ConditionalTask {
   public void addCondition(final Condition condition) ...
}

ant addCondition() would be called even if i wrote:

<conditionaltask>
   <not>...</not>
</conditionaltask>

or:

<conditionaltask>
   <and>...</and>
</conditionaltask>

or any of the org.apache.tools.ant.taskdefs.condition.Condition derived
classes.

AFAIK, right now this isn't possible.  i have managed to hack a bit at the
Ant code to handle this special case but i end up in all sorts of mess and
generally get NullPointerExceptions all over the shop.  is anyone looking
at doing / done similar stuff?  does anyone have any guidance for what bits
of the Ant code i should be looking at if i want to handle generic methods
like addCondition() or addTask()?

i'd appreciate all help.

Cheers,
Matt

p.s. i've got several "bug" fixes and stuff that i'd like to contribute back
      to the source.  who do i talk to about the changes i've made (like
      making <mapper> elements work across different directories)?

-----------------------------------------------------------------------------
Sessami is a trademark of Escape Velocity Technology Mobile Services Limited.
All information contained in this e-mail is confidential and for the use of
the addressee only.  If you receive this message in error please notify.


Re: conditional logic and making it nicely extensible

Posted by Jack Woehr <ja...@purematrix.com>.
Matt Denner wrote:

> but thanks, that has given me an insight into the mentality of an Ant
> project writer ;)  i guess nobody is maintaining a FAQ with these useful
> tips in it?

This will give you a lot about the Theology of ant.:

     http://jakarta.apache.org/ant/ant2/requested-features.txt

As for a FAQ, the manual is pretty good. Though I think the manual should
include something like the example I gave you of a conditional call.

--
Jack J. Woehr     # "I never worry that all hell will break loose.
Senior Consultant #  I worry that half hell will break loose, which
Purematrix, Inc.  #  is much harder to detect." - George Carlin



Re: conditional logic and making it nicely extensible

Posted by Matt Denner <ma...@evtechnology.com>.
Jack Woehr wrote:
 >

> I have since realized that the way to accomplish what you and I both want
> in the TRUE ANT THEOLOGY :-) is to
> 
>    1. Set a variable using Condition
>          1. That variable should be the name of a target
>    2. Use Antcall on the variable to hit the right target
> 
> Here's an example ... run it without setting any props, then run it with


i can certainly see how that works and, must admit, i hadn't thought of it.
i'll look at it to see if it helps with our build system but we do
something pretty similar: we call a XYZ.check target as a dependency of
the XYZ target, and have that set a XYZ.doit property which XYZ has as an
if; or more simply:

<target name="XYZ" depends="XYZ.check" if="XYZ.doit">
   ...
</target>

<target name="XYZ.check">
   <condition property="XYZ.doit">
     ...
   </condition>
</target>

when we have a choice then we simply create do targets XYZ.success and
XYZ.failure with 'if' and 'unless' attributes.  it works ok but doesn't
half look nasty!

that really wasn't the intention of the email, although it was part of the
thinking.  what i really need is opinions on how to improve the
introspection that Ant does on elements to allow for a much nicer method of
extension (specifically the conditional stuff).

but thanks, that has given me an insight into the mentality of an Ant
project writer ;)  i guess nobody is maintaining a FAQ with these useful
tips in it?

Cheers,
Matt

-----------------------------------------------------------------------------
Sessami is a trademark of Escape Velocity Technology Mobile Services Limited.
All information contained in this e-mail is confidential and for the use of
the addressee only.  If you receive this message in error please notify.


Re: conditional logic and making it nicely extensible

Posted by Jack Woehr <ja...@purematrix.com>.
Matt Denner wrote:

> Dear all,
>
> my first mail to this so if i'm out of order or in the wrong place then bash
> me know :)
>

Hi Matt ...

I posted to the list in a similar vein and was met with resounding silence :-)

My suggestion for AntCallIfElse along the lines of (the equally declarative) m4's
ifelse() macro is appended at the end of this message.

I have since realized that the way to accomplish what you and I both want
in the TRUE ANT THEOLOGY :-) is to

  1. Set a variable using Condition
       1. That variable should be the name of a target
  2. Use Antcall on the variable to hit the right target

Here's an example ... run it without setting any props, then run it with

     -Ddeterminant=yes

to get the conditional target hitting we want.

     <?xml version="1.0" encoding="UTF-8"?>
     <project default="myIfElse">
     <target name="myIfElse">
       <property name="callWhich" value="noItWarnt"/>
       <condition property="callWhich" value="yesItWas">
         <and>
           <equals arg1="${determinant}" arg2="yes"/>
         </and>
       </condition>
       <antcall target="${callWhich}"/>
     </target>

     <target name="yesItWas">
       <echo message="Yes!"/>
     </target>

     <target name="noItWarnt">
       <echo message="No :("/>
     </target>
     </project>

Here's the idea I had posted to the list earlier that was "met with silence".
-------------------------------------------------------

I'm looking at http://jakarta.apache.org/ant/ant2/requested-features.txt

      [DISC] procedural versus purely declarative
      -------------------------------------------

      * Simple flow control (if-then-else, for)

        [REJECTED - vetoes by Conor MacNeill, Glenn McAllister, Peter Donald
                    and Stefan Bodewig]

The reasons to keep Ant essentially declarative are obvious. With approval I note
that you also rejected a motion to make Ant 'purely declarative', a shibboleth
refuted already in logic programming.

There is precedent, however, for a "declarative kind of proceduralism" in other
declarative languages, for example, the m4 ifelse() macro.

It looks as if one could employ the style of coding worked out by Stefan Bodewig in
org/apache/tools/ant/taskdefs/condition to create a class CallTargetsIfElse based
on CallTarget. This would allow syntax like:

    <antcallifelse>
        <equal>
            <arg1="${some.prop}"/>
            <arg2="${some.prop}"/>
        </equal>
        <if target="true_target">
            <param="${a}"/>
            <param="${b}"/>
        </if>
        <else target="false_target">
                <param="${c}"/>
                <param="${b}"/>
        </else>
    </antcallifelse>

This seems a little clearer than what I do now (is this actually
correct?) :

    <target name="true_target" if="${a}">
        ...
    </target>

    <target name="false_target" unless="${a}">
        ...
    </target>

    <target name="switch">
            <antcall target="true_target"/>
            <antcall target="false_target"/>
    </target>

Would the coding of an AntCallIfElse task be, in the light of your
prior vote cited above, a welcome or unwelcome contribution?

--
Jack J. Woehr     # "I never worry that all hell will break loose.
Senior Consultant #  I worry that half hell will break loose, which
Purematrix, Inc.  #  is much harder to detect." - George Carlin



Re: conditional logic and making it nicely extensible

Posted by Ken Wood <kw...@i2.com>.
Vielen Dank!

Stefan Bodewig wrote:
> 
> On Tue, 11 Sep 2001, Ken Wood <kw...@i2.com> wrote:
> 
> > Since some of us are not good at reading source code
> > and deducing what the xml should look like, could
> > you please provide an example or two???
> 
> Sure 8-)
> 

Examples <snipped>

Re: conditional logic and making it nicely extensible

Posted by Stefan Bodewig <bo...@apache.org>.
On Tue, 11 Sep 2001, Ken Wood <kw...@i2.com> wrote:

> Since some of us are not good at reading source code
> and deducing what the xml should look like, could
> you please provide an example or two???

Sure 8-)

<if> supports three types of nested child elements:

(1) Exactly one condition - the same way <condition> has exactly one
condition child, i.e. one of <not>, <and>, <or>, <available>,
<uptodate>, <os>, <equals>.

(2) Zero or one <then> element.

(3) Zero or one <else> element.

<then> and <else> can themselves contain an arbitrary number of tasks.
If the condition is true the tasks in the <then> element (if present)
will be executed, otherwise the tasks in the <else> element (if
present) will be executed.

<project default="if">
  <target name="if">
    <if>
      <or>
        <equals arg1="${foo}" arg2="bar" />
        <equals arg1="${foo}" arg2="baz" />
      </or>
      <then>
        <echo message="foo is boring" />
      </then>
      <else>
        <echo message="foo is not that boring" />
      </else>
    </if>
  </target>
</project>

would be one example, where values of bar and baz for the property foo
would be considered boring.

<condition property="foo" value="bar">
  <some-condition>
</condition>

would be a shortcut for

<if>
  <some-condition>
  <then>
    <property name="foo" value="bar">
  </then>
</if>

(just that <condition> will override existing properties).

Stefan

Re: conditional logic and making it nicely extensible

Posted by Ken Wood <kw...@i2.com>.
Since some of us are not good at reading source code
and deducing what the xml should look like, could
you please provide an example or two???

Stefan Bodewig wrote:
> 
> On Thu, 06 Sep 2001, Matt Denner <ma...@evtechnology.com> wrote:
> 
> > i have written a couple of neat
> > org.apache.tools.ant.taskdefs.condition.Condition derived classes:
> 
> Great, want to share them (especially the conditionwrapper stuff)?
> 
> > suddenly it dawned on me that what i really wanted was something
> > that would allow me to execute different tasks based on a generic
> > condition.
> 
> After hinting how I'd write an <if> task far too often, I've finally
> created one, <http://jakarta.apache.org/~bodewig/IfTask.java>.  I
> think this is what you are looking for.
> 
> Given our voting history, this task won't become part of Ant's core,
> but I'm willing to maintain it until we have a repository of
> contributed tasks.
> 
> I'll respond to the rest in a second post.
> 
> Stefan

Re: conditional logic and making it nicely extensible

Posted by Stefan Bodewig <bo...@apache.org>.
On Thu, 06 Sep 2001, Matt Denner <ma...@evtechnology.com> wrote:

> i have written a couple of neat
> org.apache.tools.ant.taskdefs.condition.Condition derived classes:

Great, want to share them (especially the conditionwrapper stuff)?

> suddenly it dawned on me that what i really wanted was something
> that would allow me to execute different tasks based on a generic
> condition.

After hinting how I'd write an <if> task far too often, I've finally
created one, <http://jakarta.apache.org/~bodewig/IfTask.java>.  I
think this is what you are looking for.

Given our voting history, this task won't become part of Ant's core,
but I'm willing to maintain it until we have a repository of
contributed tasks.

I'll respond to the rest in a second post.

Stefan