I want to use manifestclasspath Ant task. I have a very large build.xml file with a couple of imported other build files and when I run it I get this:
build.xml:1289: The following error occurred while executing this line:
build.xml:165: Property 'some.property' already set!
I am sure that this property is defined only in manifestclasspath task. Here is my code:
<manifestclasspath property="some.property" jarfile="some.jar">
<classpath refid="some.classpath"/>
</manifestclasspath>
This code is located inside of <project>.
What am I doing wrong? Is there a way to add something like condition to set property only if it is not already set? I don't want to use custom Ant tasks such as Ant Contrib's if if there is other way around.
Antcall opens a new project scope, but by default, all of the properties of the current project will be available in the new project. Also if you used something like =
<antcall target="whatever">
<param name="some.property" value="somevalue"/>
</antcall>
in the calling project then ${some.property} is also already set and won't be overwritten, as properties once set are immutable in ant by design.
Alternatively, you may set the inheritAll attribute to false and only "user" properties (those passed on the command-line with -Dproperty=value) will be passed to the new project.
So, when ${some.property} ain't no user property, then use inheritAll="false" and you're done.
btw. it's better to use a dependency between targets via depends="..." attribute than to use antcall, because it opens a new project scope and properties set in the new project won't get back to the calling target because it lives in another project scope..
Following a snippet, note the difference, first without inheritAll attribute
<project default="foo">
<target name="foo">
<property name="name" value="value1" />
<antcall target="bar"/>
</target>
<target name="bar">
<property name="name" value="value2" />
<echo>$${name} = ${name}</echo>
</target>
</project>
output :
[echo] ${name} = value1
second with inheritAll=false
<project default="foo">
<target name="foo">
<property name="name" value="value1" />
<antcall target="bar" inheritAll="false" />
</target>
<target name="bar">
<property name="name" value="value2" />
<echo>$${name} = ${name}</echo>
</target>
</project>
output :
[echo] ${name} = value2
some rules of thumb for antcall, it's rarely used for good reasons :
1. it opens a new project scope (starting a new 'ant -buildfile yourfile.xml yourtarget') so it uses more memory, slowing down your build
2. depending targets of the called target will be called also !
3. properties don't get passed back to the calling target
In some cases it might be ok when calling the same 'standalone' target (a target that has no target it depends on) with different params for reuse. Normally macrodef or scriptdef are used for that purpose. So, think twice before using antcall which also puts superfluous complexity to your scripts, because it works against the normal flow.
Answer to your question in the comment, using a dependency graph instead of antcall
you have some target that holds all conditions and sets the appropriate properties which may be evaluated by targets via if and unless attributes to control the further flow
<project default="main">
<target name="some.target">
<echo>starting..</echo>
</target>
<!-- checking requirements.. -->
<target name="this.target">
<condition property="windowsbuild">
<os family="windows"/>
</condition>
<condition property="windowsbuild">
<os family="unix"/>
</condition>
<!-- ... -->
</target>
<!-- alternatively
<target name="yet.another.target" depends="this.target" if="unixbuild">
-->
<target name="another.target" depends="this.target" unless="windowsbuild">
<!-- your unixspecific stuff goes here .. -->
</target>
<!-- alternatively
<target name="yet.another.target" depends="this.target" if="windowsbuild">
-->
<target name="yet.another.target" depends="this.target" unless="unixbuild">
<!-- your windowspecific stuff goes here .. -->
</target>
Related
We have a Java applet project and we generate the wrapper HTML using Ant, it looks a bit like this:
<target name="build-applet" description="Build web applet" depends="set-build-properties, set-properties">
<antcall target="clean" />
<antcall target="clean-applet" />
<antcall target="set-version" />
<antcall target="compile" />
<antcall target="jar" />
<antcall target="applet" />
</target>
<target name="applet">
<replace file="${applet.dir}/${applet.html.file}">
<replacefilter token="#jar.file#" value="${applet.jar.file}"/>
<replacefilter token="#assets.file#" value="${applet.assets.file}"/>
<replacefilter token="#codebase#" value="${applet.codebase}"/>
</target>
Note that ${applet.codebase} has to be the URL where the applet is loaded from e.g mysite.com/game. It's set in a properties file.
Now I want to be able to build this applet to two different locations, part of a live/test setup. e.g one is accessed at mysite.com/game and the other at mysite.com/test. I have it almost working, except for ${applet.codebase} because this needs to be different in each case. I thought I could have ${applet.codebase} and ${applet.codebase_test} but I don't know how to do this. Maybe there's a way to pass a flag into the applet target from build-applet, and add two top-level targets build-applet-live and build-applet-test which just call build-applet with the parameter.
Why not simply ant -Dapplet.codebase=whatever build.xml, means set ${applet_codebase} as userproperty (= those properties set via -Dkey=value) ?
I have a build.xml that should receive dynamically parameters to the depends field.
I define this parameter in some other app.xml such as:
ops=op1, op2, op3,op4,op5,.... opn
then I import this app.xml into build.xml and want to use the parameter ops there.
<project name="Project" basedir="." default="help">
<target name="test" depends="{$ops}" description="executea series of commands in ant">
<echo message="batch operation job done. tasks = {$ops}"/>
</target>
</project>
How can I pass a parameter from one ant file to another?
The depends parameter does not take properties.
Ant uses a dependency matrix to determine what should be built and in what order. This matrix is calculated before any part of the build file itself is executed, so properties aren't even set when this is done.
What are you trying to accomplish? Maybe if we have a better idea what you want, we can help you with it. Ant isn't a scripting language like BASH or Python.
As already mentioned, you can't put properties into the Depends field. However, if you are setting a property, you can use it in the If field. Example
<project name="appProject">
<target name="test" depends="target1,target2,target3" description="execute series of commands"/>
<target name="target1" if="do.target1">
<echo message="Target1 executed." />
</target>
<target name="target2" if="do.target2">
<echo message="Target2 executed." />
</target>
<target name="target3" if="do.target3">
<echo message="Target3 executed." />
</target>
</project>
Then you set in your build.xml the given target flag do.target1, do.target2 or do.target3 and it gets executed. Basically what you wanted to have. In the If field properties are only checked for value. Also, you don't have to use the ${ } construction for the properties.
To explain it briefly, here is an example:
In build.xml, local-db.xml is imported. And in local-db.xml, there is a target named "warmup" which calls one target of the third file -- local-gr.xml using task.
All the common properties and classpath defs are imported and set in build.xml.
in project.properties:
dest-dir=./destination
in build.xml:
<path id="gr-classpath"> ... </path>
<import file="local-db.xml" />
in local-db.xml:
<ant antfile="local-gr.xml" target="deploy" inheritAll="true" inheritRefs="true" />
In local-gr.xml, there are two targets like this:
<target name="deploy">
<tar ....../>
<foreach list="${list1}" delimiter="," parallel="true" trim="true" param="item" target="deploy-single" />
</target>
<target name="deploy-single">
something using property ${dest-dir} and path "gr-classpath"
</target>
Now here is the problem:
The property ${dest-dir} and path "gr-classpath" can be used in "deploy" because I set inheritAll and inheritRefs, but it can't be used directly in "deploy-single". "inherit" doesn't when the target is called by foreach?
I managed to pass ${dest-dir} to "deploy-single" with the help of the , but I didn't find any way to pass the classpathref "gr-classpath" to "deploy-single".
What I did to work around it was to claim the again in "deploy-single", but I don't like it at all.
Why this happens? What can I do to make it more elegant?
The ant-contrib foreach task doesn't by default propagate all properties and references to it's target. But it does have inheritall and inheritrefs attributes that you can use to make that happen.
<foreach list="${list1}" delimiter="," parallel="true" trim="true"
param="item" target="deploy-single"
inheritall="true" inheritrefs="true"
/>
I'm rather new to Ant but I have experienced it's quite good pattern to create generic ant targets which are to be called with antcall task with varying parameters.
My example is compile target, which compiles multiple systems using complex build command which is a bit different for each system. By using pattern described above it's possible not to create copy paste code for that compile command.
My problem here is, that I'm not aware of any way to pass return value (for example the return value of compiler) back to target which called the antcall task. So is my approach pathological and it's simply not possible to return value from antcall task or do you know any workaround?
Thanks,
Use antcallback from the ant-contrib jar instead of antcall
<target name="testCallback">
<antcallback target="capitalize2" return="myKey">
</antcallback>
<echo>a = ${myKey}</echo>
</target>
<target name="capitalize2">
<property name="myKey" value="it works"/>
</target>
Output:
testCallback:
capitalize2:
[echo] a = it works
BUILD SUCCESSFUL
One approach is to write out a property to a temp file using "echo file= ...." or PropertyFile task. Then read the property back in where required. Kludge but works.
Ant tasks are all about stuff goes in, side effect happens. So trying to program in terms of functions (stuff goes in, stuff comes out) is going to be messy.
That said what you can do is generate a property name per invocation and store the result value in that property. You would need to pass in a indentifier so you do not end up trying to create copies of the same property. Something like this:
<target name="default">
<property name="key" value="world"/>
<antcall target="doSomethingElse">
<param name="param1" value="${key}"/>
</antcall>
<echo>${result-${key}}</echo>
</target>
<target name="doSomethingElse">
<property name="hello-${param1}" value="it works?"/>
</target>
But I believe the more typical approach -instead of antcalls- is to use macros. http://ant.apache.org/manual/Tasks/macrodef.html
Antcall can be used from the ant-contrib jar task.
You can get a similar behaviour with the keyword "depends".
<?xml version="1.0" encoding="UTF-8"?>
<project name="test" default="main">
<target name="main">
<antcall target="build-system-with-depends" />
<!-- wait for different results -->
<waitfor checkevery="1000" checkeveryunit="millisecond" maxwaitunit="millisecond" maxwait="2000">
<available file="dummy.not.present.file" classname="" property=""></available>
</waitfor>
<antcall target="build-system-with-depends" />
</target>
<target name="build-system-with-depends" depends="do-compiler-stuff">
<echo>$${compiler.result}=${compiler.result}</echo>
</target>
<target name="do-compiler-stuff">
<!-- simulate different return states -->
<tstamp>
<format pattern="yyyyMMddHHmmss" property="compiler.result" />
</tstamp>
</target>
</project>
I would like to not call a target in build.xml in the case that there is a certain environment variable.
Using Ant 1.7.0, the following code does not work:
<property environment="env"/>
<property name="app.mode" value="${env.APP_MODE}"/>
<target name="someTarget" unless="${app.mode}">
...
</target>
<target name="all" description="Creates app">
<antcall target="someTarget" />
</target>
Target "someTarget" executes whether there is the environment variable APP_MODE or not.
The docs for the unlessattribute say:
the name of the property that must not be set in order for this target to execute, or something evaluating to false
So in your case, you need to put the name of the property, rather than an evaluation of the property:
<target name="someTarget" unless="app.mode">
...
</target>
Notes
In Ant 1.7.1 and earlier, these attributes could only be property names.
As of Ant 1.8.0, you may instead use property expansion; a value of true (or on or yes) will enable the item, while false (or off or no) will disable it.
Other values are still assumed to be property names and so the item is enabled only if the named property is defined.
Reference
if/unless on the ant manual
Unless attribute suggest in simple language that if property is set then the task would not be get executed. for ex.
<target name="clean" unless="clean.not">
<delete dir="${src}" />
<property name="clean.not" value="true" />
<delete dir="${dest}" />
</target>
Here , if you call clean target , it gets executed first then its value is set. And if you want to call it again in script then it would not as property must not be set in order to get the task executed.