Symphonious

Living in a state of accord.

Importing an ant buildfile multiple times

According to the ant documentation:

It is possible to include the same file more than once by using different prefixes, it is not possible to import the same file more than once.

Unfortunately, it turns out this isn’t quite true. In most cases, ant will indeed ignore a request to import a file for the second time, so:

<import>
<file name="utils.xml"/>
<file name="utils.xml"/>
</import>

 

will only import utils.xml once. This is true even if there’s a chain of files being imported (so A imports B and C, then B imports C as well, C will only be imported once).

The problem arises if you’re importing the file via two different methods, you might wind up having it actually be imported twice. In my case I was loading build files from a zip archive (why is a long story that I should write up some time) and those build files references other files also within the zip file. So my main build file had:

<import>
<javaresource classpath="bootstrap.zip"
name="basic-build.xml"/>
</import>

Then basic-build.xml included another utils file from the same zip. Being the well-coded ant file that it is, basic-build.xml doesn’t depend on knowing where it’s actually located, so it imports the utils file via:

<import>
<url baseurl=${ant.file.basic-build}" relativePath="ivy-utils.xml"/>
</import>

This all works just fine. Then there came a requirement in our main build file to use one of the macros from ivy-utils.xml to set a version number before basic-build.xml was imported. So the main build file wound up with something like:

<import>
 <javaresource classpath="bootstrap.zip"
name="ivy-utils.xml"/> </import>
<!-- Do some stuff --> <import>
<javaresource classpath="bootstrap.zip"
name="basic-build.xml"/>
</import>

Suddenly the build started failing because ivy-utils.xml was being executed twice and attempting to redefine the ivy configuration which was explicitly disallowed.

Looking at the ant -debug output clearly showed the ivy-utils.xml was being imported twice and not skipped, and even that it came from exactly the same URL. It appears that resolving the same file using two different mechanisms (javaresource and url in this case) caused ant to believe they were different files.

The answer was fairly straight-forward, use url resources consistently when importing the files:

<import>
 <url url="jar:file:${ant.file}/bootstrap.zip!/ivy-utils.xml"/>
</import>
<!-- Do some stuff --> <import>
<url url="jar:file:${ant.file}/bootstrap.zip!/basic-build.xml"/>
</import>

Building a jar: URL like this is a little unpleasant but not unreasonable. Strictly we could have kept importing basic-build.xml using the javaresource approach but being consistent will save surprises in the future.

  • Stefan Bodewig says:

    Interesting, I guess EasyAnt could be hit by this pretty soon.

    Could you please open a bug report for this?

    Thanks

    Stefan

    June 12, 2013 at 7:51 am
  • Adrian Sutton says:

    Happy to log a bug. I had assumed it was a known limitation – seemed pretty reasonable that different resource loaders would find it hard to compare their resources. Now logged at https://issues.apache.org/bugzilla/show_bug.cgi?id=55097

    Also just noted that the simplification I wrote up here for building the jar: URL manually is wrong – using ${ant.file} will include the actual filename on the end, not just the directory. It needs to use then ${dirname} in place of ${ant.file} when building the URL to the zip file.

    June 13, 2013 at 2:51 am
  • Stefan Bodewig says:

    The good thing about holidays is you find time to look into old bug reports :-)

    Finally fixed the issue in svn at least for all cases where the imported resources can be identified via a File or URI, will be fixed in Ant 1.9.4.

    December 31, 2013 at 11:05 am
  • Adrian Sutton says:

    Cool, thanks Stefan. Good to know I won’t be surprised about this the next time I try doing something stupid. :)

    January 7, 2014 at 11:29 am

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

*