Extend a Groovy Scriptdef with inline task

If you use AntBuilder within a Scriptdef (which does sound weird), how do you then use inline task elements?

Intro
In a prior post, “Groovy AntBuilder in Ant Scriptdef to Replace Props,” I used an AntBuilder to iteratively create an Ant PropertyFile task. The task was then used as shown in listing 1.

Listing 1 – Snippet of prior Ant script

  <!-- use the "propertiesreplace" scriptdef -->
  <target name="merge" depends="init">

       <propertiesreplace 
              targetfile="oldProps.properties" 
              newpropfile="newProps.properties"
       />

  </target>

Using elements
But now I want (don’t ask, I really did have a good use case) to also explicitly define other replacements using the PropertyTask directly. Sure I could use it after the use of the scriptdef, but how would it be used inside the scriptdef itself? So now the use case is:

Listing 2 – New Ant script with PropertyFile task element

  <!-- use the "propertiesreplace" scriptdef -->
  <target name="merge" depends="init">

       <propertiesreplace 
              targetfile="oldProps.properties" 
              newpropfile="newProps.properties"

              <propertyfile file="oldProps.properties">
                <entry key="ten" value="XX"/>			
              </propertyfile>
       />

  </target>

We still want to use the scriptdef defined task since we are merging property files, but we also want to make other replacements (or modify those that the files would create).

Solution
You’d think, at least I did for a while, that you have to delve into the arcane internals of Groovy’s NodeBuilder and all that. You don’t. See listing 3; you just execute it.

Listing 3 – New Scriptdef handling element

<!-- Replace properties in oldfile 
whose key match those in newfile -->

<scriptdef name="propertiesreplace" language="groovy"
    classpathref="libs">

    <attribute name="mergefile"/>
    <attribute name="propfile"/>

    <![CDATA[
     def ant = new AntBuilder(project)

     ant.propertyfile( file:attributes.get("mergefile") ){
          def props= new Properties()
          props.load(
               new File( attributes.get("propfile") )
                     .newReader()
          )

          props.each{ cur ->
               entry( key:cur.key,value:cur.value )
          }
     }

     def pf = elements.get("propertyfile").get(0)
     pf.execute()
    ]]>
</scriptdef>

Update
Feb 18, 2012: Wow, I looked at listing 3 and couldn’t remember how that worked.
“elements” is a map of the xml nodes within the scriptdef invocation shown in listing 2. Since it is a map we get the corresponding element by key, get(key). Why the final get(0)? Hmmmm. Oh yeah, there may be more then one element with the same name, so we just get the first in this present example.

Off topic
1. It would be nice to have a new GDK extension on Properties class, so that we can load a properties file and iterate as we do with Map. For example:

             new Properties(filepath).each{
                     println "${it.key}=${it.value}"
             }

2. AntBuilder makes using Ant effortless. Imagine copying a log4j properties file to target folder, editing an entry, then printing out the file. Sure you can you use the copy task with nested tokenizer, but not always. Here it is with PropertyFile:

def ant = new AntBuilder()

ant.tstamp(){
  format(property:"BUILD.DATE",pattern:"yyyy-MM-dd'T'HHmmss")
}

def now = ant.project.getProperty("BUILD.DATE")
def path = "../../../user/temp/${args[0]}"

ant.copy(
  file:"../lib/log4j.properties",
  todir:path
)

ant.propertyfile(file:"${path}/log4j.properties"){
    entry(
      key:"log4j.appender.LogFile.file",
      value:"builder-${now}.log"
    )
}

print (new File(targetFile).getText())

That is pretty nice. Not my code, the concept.

3. Along these lines some projects provide even better use of Groovy to handle ‘build’ stuff. The Gant project puts a lightweight facade upon the AntBuilder to create a tool for Ant scripting. And, Gradle takes that to a whole new level to create a “build framework”.

Further Reading

  1. Using Ant from Groovy
  2. Gradle
  3. Gant
  4. Writing Domain-Specific Languages
  5. Groovy for Domain-Specific Languages
  6. Groovy AntBuilder in Ant Scriptdef to Replace Props

Similar Posts:

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.

One thought on “Extend a Groovy Scriptdef with inline task”

Leave a Reply

Your email address will not be published. Required fields are marked *