5

I have a set of build files, some of them calling others -- importing them first. End of line builds may have or may not have a specific target (e.g. "copyother"). I want to call it from my main build file if that target is defined within the end-of-line build script. How can I do it?

Part of the calling script:

<!-- Import project-specific libraries and classpath -->
<property name="build.dir" value="${projectDir}/build"/>
<import file="${build.dir}/build_libs.xml"/>

...

<!-- "copyother" is a foreign target, imported in build_libs.xml per project -->
<target name="pre-package" depends="    clean,
                                        init,
                                        compile-src,
                                        copy-src-resources,
                                        copy-app-resources,
                                        copyother,
                                        compile-tests,
                                        run-junit-tests"/>

I do not want every project to define "copyother" target. How can I do a conditional ant call?

Vladimir Dyuzhev
  • 18,130
  • 10
  • 48
  • 62

3 Answers3

3

I'm guessing you aren't importing the "other" build scripts into your main build.xml. (Because that wouldn't work. Ant treats imports as local.)

At the same time, you are using depends and not ant/ant call so maybe you are importing them, but one at a time.

You can't do what you want in native Ant. As you noted testing for a file is easy but a target is not. Especially if that other project isn't loaded yet. You definitely have to write a custom Ant task to accomplish what you want. Two avenues:

1) Call project.getTargets() and see if your target is there. This involves refactoring your script to use ant/antcall instead of pure depends, but doesn't feel like a hack. Writing a custom Java condition isn't hard and there is an example in the Ant manual.

2) Add a target to the current project if not already there. The new target would be a no-op. [not sure if this approach works]

Jeanne Boyarsky
  • 12,156
  • 2
  • 49
  • 59
1

For the same of completeness. Another approach is to have some target for checking the target.

The approach is discussed here: http://ant.1045680.n5.nabble.com/Checking-if-a-Target-Exists-td4960861.html (vimil's post). Check is done using scriptdef. So it is not that different from other answer(Jeanne Boyarsky), but script is easy to add.

<scriptdef name="hastarget" language="javascript">
    <attribute name="targetname"/>
    <attribute name="property"/>
    <![CDATA[
       var targetname = attributes.get("property");
       if(project.getTargets().containsKey(targetname)) {
            project.setProperty(attributes.get("property"), "true");
       }
     ]]>
</scriptdef>

<target name="check-and-call-exports">
    <hastarget targetname="exports" property="is-export-defined"/>
    <if>
        <isset property="is-export-defined"/>
        <then>
            <antcall target="exports"   if="is-export-defined"/>
        </then>
    </if>
</target>

<target name="target-that-may-run-exports-if-available" depends="check-and-call-exports">
Jayan
  • 18,003
  • 15
  • 89
  • 143
0

You should explore use of the typefound condition, added to ANT in 1.7. You can use it, for example, with the if task from antcontrib like this, but you have to check for a macrodef and not a taskdef due to how it works:

<if>
   <typefound name="some-macrodef"/>
<then>
   <some-macrodef/>
   </then>
</if>

With this, ant files that have a macrodef named "some-macro-or-taskdef" will get it invoked and other ant files without it will not get an error.

Eddie
  • 53,828
  • 22
  • 125
  • 145