You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@ant.apache.org by Cyril Sagan <cy...@gmail.com> on 2013/09/27 00:15:49 UTC

"scoping" for macro definitions?

Is there a way to override a macro defined from a library I cannot
control, my goal is to provide a local implementation, but not have to
change all the callers.

I'm stuck on Ant 1.7.0, and cannot update.

How could I "fake out" a scoping mechanism to accomplish something like:
<super.macroImplementation/> or <project[@name].macroImplemenation/>

I tried using <presetdef/> to "override" the macro, but I can't figure
out how to invoke the original macro of the same name.  I could
redefine the macro from the library in my local ant script, but I
don't want to open a possibility that my local implementation could
get out of sync with the one from the provided library.

Another way to express what I need is the macro equivalent of target
overriding, which is accomplished with the code snip below, but I need
it for <macrodef/>!

common.xml:
    <project name="common_library">
        <target name="stuff">
            <!-- run stuff from common library -->
        </target>
    </project>

build.xml:
    <project name="myBuild">
        <import file="common.xml" />
        <target name="stuff" depends="mystuff_first, common_library.stuff"
/>

        <!-- henceforth target="stuff" is *my* implementation -->
    </project>


But what if its a macro (or scriptdef)?  In principle here's what I was
hoping could
work, but it doesn't, so that's why I'm asking:

common.xml:
    <project name="common_library">
        <macrodef name="routine">
            <attribute name="arg1" />
            <attribute name="arg2" />
            <sequential>
                <!-- macro definition from common library -->
            </sequential>
        </target>
    </project>

build.xml:
    <project name="myBuild">
        <import file="common.xml" />
        <presetdef name="routine">
            <local_routine/>
        </presetdef>

        <macrodef name="local_routine">
            <attribute name="arg1" />
            <attribute name="arg2" />
            <sequential>
                <!-- add some logic here... -->
                <common_library.routine arg1="@{arg1} arg2="@{arg2}" />
            </sequential>
        </macrodef>

        <!-- henceforth <routine/> is *my* implementation -->
    </project>

Any ideas would be much appreciated.  Thanks.

--Cyril

RE: "scoping" for macro definitions?

Posted by Martin Gainty <mg...@hotmail.com>.
that was my initial answer .. but then I considered the collision of the global ant namespace (that macrodef plays in) with a customised non-ant namespace
<Macrodef> is implicitly declared within Ants global namespace 

The default namespace used by Ant is "antlib:org.apache.tools.ant". 

thus 

embedding any other elements with non-ant namespaces inside Ant global namespace is verboten 
(that is up until the end tag </Macrodef> is encountered)

 

Parser> I am parsing macrodef with antlib:org.apache.tools.ant namespace 
Operator>Here is new Element with New Namespace embedded inside Macrodef
Parser:No you cannot I am still parsing the elements and attributes of antlib:org.apache.tools.ant.namespace

 

Since Ant namespace is globally available we can reference Ant namespace types inside customised namespaces 
consider:


>From Ant 1.6.2, elements nested inside a namespaced element may also be in Ant's default namespace. This means that the following is now allowed: 
 <typedef resource="org/example/tasks.properties"
   uri="http://example.org/tasks"/>
 <my:task xmlns:my="http://example.org/tasks">
   <config a="foo" b="bar"/>  <!-- embedded element inside ANTs default namespace so this is ok-->
   ...
 </my:task>


NOT allowed

 <typedef resource="org/example/tasks.properties"
   uri="http://example.org/tasks"/>
<task xmlns:my="http://example.org/tasks">
   <my:config a="foo" b="bar"/> <!-- custom namespace is not aware of types declared from ant namespace -->
   ...
</task>


IMHO DefineAttribute static class (embedded in Macrodef) is the solution why
1)DefineAttribute stays within the Macrodef and stays within global ant namespace (antlib:org.apache.tools.ant) boundaries
2)DefineAttribute accomodates assignment of unique values for each instantation of the MacroDef

 

Here is the code

/**
 481:     * A nested define element for the MacroDef task.
 482:     *
 483:     * It provides an attribute with a guaranteed unique value
 484:     * on every instantiation of the macro. This allows to use
 485:     * this uniquely named attribute in property names used
 486:     * internally by the macro, thus creating unique property
 487:     * names and side-stepping Ant's property immutability rules.
 488:     * <p>
 489:     * Of course, this work around as the side effect of littering


 490:     * the global Ant property namespace, so is far for ideal, but
 491:     * will have to make do awaiting a better fix...
 492:     *
 493:     * @since ant 1.7
 494:     */
 495:...	      public static class DefineAttribute extends Attribute {
 496:
 497:        private static long count = 0;
 498:        private String prefix = "";
 499:
 500:        /**
 501:         * Sets a prefix for the generated name.
 502:         *
 503:         * @param prefixValue the prefix to use.
 504:         */
 505:...	          public void setPrefix(String prefixValue) {
 506:            prefix = prefixValue;
 507:        }
 508:
 509:        /**
 510:         * Sets the default value.
 511:         *
 512:         * This is not allowed for the define nested element.
 513:         *
 514:         * @param defaultValue not used
 515:         * @throws BuildException, always
 516:         */
 517:...	          public void setDefault(String defaultValue) {
 518:            throw new BuildException(
 519:                "Illegal attribute \"default\" for define element");
 520:        }
 521:
 522:        /**
 523:         * Gets the default value for this attibute.
 524:         * 
 525:         * @return the generated <em>unique</em> name, of the form
 526:         *         "prefix#this classname#&lt;aCounter&gt;".
 527:         */
 528:...	          public String getDefault() {
 529:...	              synchronized (DefineAttribute.class) {
 530:                // Make sure counter is managed globally
 531:                return prefix + "#" + getClass().getName() + "#" + (++count);
 532:            }
 533:        }
 534:
 535:    } // END static class DefineAttribute


http://www.javadocexamples.com/java_source/org/apache/tools/ant/taskdefs/MacroDef.java.html

 

-Martin

 



> Date: Thu, 26 Sep 2013 15:43:24 -0700
> From: vimilsaju@yahoo.com
> Subject: Re: "scoping" for macro definitions?
> To: user@ant.apache.org
> 
> I am not sure if this feature is available in ant 1.7 but can't you use namespaces to scope the macrodefs like follows
> 
> <project name="testBuild" default="all" basedir="." xmlns:c="common" >
> <typedef file="../build-common/buildCommon.xml"uri="common"/>
> 
> Now all the macrodefs in buildCommon.xml has to be accessed as follows
> 
>  <c:theirmacro ...
> 
> Any macrodef you define in your build.xml can be accessed without using the namespace syntax.
> 
> 
> ________________________________
> From: Cyril Sagan <cy...@gmail.com>
> To: Ant Users List <us...@ant.apache.org> 
> Sent: Thursday, September 26, 2013 3:15 PM
> Subject: "scoping" for macro definitions?
> 
> 
> Is there a way to override a macro defined from a library I cannot
> control, my goal is to provide a local implementation, but not have to
> change all the callers.
> 
> I'm stuck on Ant 1.7.0, and cannot update.
> 
> How could I "fake out" a scoping mechanism to accomplish something like:
> <super.macroImplementation/> or <project[@name].macroImplemenation/>
> 
> I tried using <presetdef/> to "override" the macro, but I can't figure
> out how to invoke the original macro of the same name.  I could
> redefine the macro from the library in my local ant script, but I
> don't want to open a possibility that my local implementation could
> get out of sync with the one from the provided library.
> 
> Another way to express what I need is the macro equivalent of target
> overriding, which is accomplished with the code snip below, but I need
> it for <macrodef/>!
> 
> common.xml:
>     <project name="common_library">
>         <target name="stuff">
>             <!-- run stuff from common library -->
>         </target>
>     </project>
> 
> build.xml:
>     <project name="myBuild">
>         <import file="common.xml" />
>         <target name="stuff" depends="mystuff_first, common_library.stuff"
> />
> 
>         <!-- henceforth target="stuff" is *my* implementation -->
>     </project>
> 
> 
> But what if its a macro (or scriptdef)?  In principle here's what I was
> hoping could
> work, but it doesn't, so that's why I'm asking:
> 
> common.xml:
>     <project name="common_library">
>         <macrodef name="routine">
>             <attribute name="arg1" />
>             <attribute name="arg2" />
>             <sequential>
>                 <!-- macro definition from common library -->
>             </sequential>
>         </target>
>     </project>
> 
> build.xml:
>     <project name="myBuild">
>         <import file="common.xml" />
>         <presetdef name="routine">
>             <local_routine/>
>         </presetdef>
> 
>         <macrodef name="local_routine">
>             <attribute name="arg1" />
>             <attribute name="arg2" />
>             <sequential>
>                 <!-- add some logic here... -->
>                 <common_library.routine arg1="@{arg1} arg2="@{arg2}" />
>             </sequential>
>         </macrodef>
> 
>         <!-- henceforth <routine/> is *my* implementation -->
>     </project>
> 
> Any ideas would be much appreciated.  Thanks.
> 
> --Cyril
 		 	   		  

Re: "scoping" for macro definitions?

Posted by Vimil Saju <vi...@yahoo.com>.
I am not sure if this feature is available in ant 1.7 but can't you use namespaces to scope the macrodefs like follows

<project name="testBuild" default="all" basedir="." xmlns:c="common" >
<typedef file="../build-common/buildCommon.xml"uri="common"/>

Now all the macrodefs in buildCommon.xml has to be accessed as follows

 <c:theirmacro ...

Any macrodef you define in your build.xml can be accessed without using the namespace syntax.


________________________________
 From: Cyril Sagan <cy...@gmail.com>
To: Ant Users List <us...@ant.apache.org> 
Sent: Thursday, September 26, 2013 3:15 PM
Subject: "scoping" for macro definitions?
 

Is there a way to override a macro defined from a library I cannot
control, my goal is to provide a local implementation, but not have to
change all the callers.

I'm stuck on Ant 1.7.0, and cannot update.

How could I "fake out" a scoping mechanism to accomplish something like:
<super.macroImplementation/> or <project[@name].macroImplemenation/>

I tried using <presetdef/> to "override" the macro, but I can't figure
out how to invoke the original macro of the same name.  I could
redefine the macro from the library in my local ant script, but I
don't want to open a possibility that my local implementation could
get out of sync with the one from the provided library.

Another way to express what I need is the macro equivalent of target
overriding, which is accomplished with the code snip below, but I need
it for <macrodef/>!

common.xml:
    <project name="common_library">
        <target name="stuff">
            <!-- run stuff from common library -->
        </target>
    </project>

build.xml:
    <project name="myBuild">
        <import file="common.xml" />
        <target name="stuff" depends="mystuff_first, common_library.stuff"
/>

        <!-- henceforth target="stuff" is *my* implementation -->
    </project>


But what if its a macro (or scriptdef)?  In principle here's what I was
hoping could
work, but it doesn't, so that's why I'm asking:

common.xml:
    <project name="common_library">
        <macrodef name="routine">
            <attribute name="arg1" />
            <attribute name="arg2" />
            <sequential>
                <!-- macro definition from common library -->
            </sequential>
        </target>
    </project>

build.xml:
    <project name="myBuild">
        <import file="common.xml" />
        <presetdef name="routine">
            <local_routine/>
        </presetdef>

        <macrodef name="local_routine">
            <attribute name="arg1" />
            <attribute name="arg2" />
            <sequential>
                <!-- add some logic here... -->
                <common_library.routine arg1="@{arg1} arg2="@{arg2}" />
            </sequential>
        </macrodef>

        <!-- henceforth <routine/> is *my* implementation -->
    </project>

Any ideas would be much appreciated.  Thanks.

--Cyril