will property be overwritten by later property file? - ant

if i have 2 properties file to be loaded and both contains the same property ${Product.Version}, which will be taken into account in my build.xml script and why?
build.xml
...
<property file="sort.properties" />
<property file="master.properties" />
...
<echo message="${Product.Version} />
sort.properties
Product.Version = 7.00
master.properties
Product.Version = 6.00

Product.Version will be equal to 7.0, once a property is set within ant it will not be overwritten by another attempt to set the property later in the script.

Related

Referencing global Ant property after <local> is used

I can create a local property in Ant within a "block" scope.
But how can I now reference the global property within the same block?
<property name="myprop" value="global"/>
...
<sequential>
<local name="myprop"/>
<property name="myprop" value="local"/>
<echo message="my local prop is ${myprop}"/> //<-- this works fine
<echo message="my global prop is ????"/> //<-- HOW?
</sequential/>
No ant-contrib please.
I'd also like to keep this in Ant, not resorting to JS.
The only thing I could think of was "copying" the global property under a different name to be used in this block
<local name="myglobprop"/>
<property name"myglobprop" value="${myprop}"/>
<local name="myprop"/>
<property name="myprop" value="local"/>
<echo message="my global prop is ${myglobprop}"/>
But that is rather unsightly and seems redundant. I am really just looking for an out-of-scope property reference method.
Edit - use case
My attempt to coerce Ant to do delayed expansion:
Let's say I have a property whose value is a combination of several other properties.
<property name="mycmdline" value="${cmd}=${type}"/>
If ${cmd} and ${type} are known before the above property, all is great. However in my case, these values are not defined (no property set). These values only become known at later stage inside a build macrodef.
I have another simple macrodef that will perform delayed expansion:
<property name="mycmdline" value="${cmd}=${type}"/>
...
<macrodef name="property-expand">
<attribute name="name"/>
<attribute name="value"/>
<sequential>
<fail if="#{name}" message="Property #{name} is already set"/>
<property name="#{name}" value="#{value}"/>
</sequential>
</macrodef>
Finally my build macrodef would contain the following snippet:
<local name="cmd"/>
<local name="type"/>
<local name="mycmdline"/>
<property name="cmd" value="#{cmd}"/>
<property name="type" value="#{type}"/>
<property-expand name="mycmdline" value="${mycmdline}"/>
The last line is obviously wrong. I am creating a (now local) property called mycmdline with expanded value of global (now out of scope) ${mycmdline}. The macrodef for delayed expansion works great on it's own, but the problem is that the global ${mycmdline} is out of scope and cannot be referenced.
What I really wanted is:
<property name="mycmdline" value="${cmd}=${type}"/>
...
<!-- In macrodef now -->
<local name="mycmdline"/>
<property-expand name="mycmdline" value="GLOBAL:${mycmdline}"/>
Instead, what I have to do is:
<property name="unexpanded_mycmdline" value="${cmd}=${type}"/>
...
<!-- In macrodef now -->
<local name="mycmdline"/>
<property-expand name="mycmdline" value="${unexpanded_mycmdline}"/>
Why?
It may not look like a lot of difference, but it's about readability. unexpanded_mycmdline and mycmdline are now two different names, when trying to follow the way the value of property gets used through a script, it now makes a disconnected jump from one property name to another (not matter how similar the names may look). The whole unexpanded_ prefix looks out of place and doesn't fit with the rest of the naming conventions, unless I name all my global variables with some prefix, which doesn't make sense either.

reloading properties after updating a property file

I'm trying to read a property after updating it using propertyfile task. Something like
<property file="test.properties" />
<echo>before :: ${modules}</echo>
<propertyfile file="test.properties" >
<entry key="modules" type="string" operation="+" value="foo" />
</propertyfile>
<property file="${status.path}/test.properties" />
<echo>after :: ${modules}</echo>.
It doesn't seem to load the second time. But the property file is updated.
You can invoke a new ant runtime with the antcall task that ignores the properties of your main target runtime - just make sure to include inheritAll="false"
<target name="main">
<property file="test.properties"/>
<echo>before :: ${modules}</echo>
<propertyfile file="test.properties">
<entry key="modules" type="string" operation="+" value="foo" />
</propertyfile>
<antcall target="second-runtime" inheritAll="false"/>
</target>
<target name="second-runtime">
<property file="${status.path}/test.properties" />
<echo>after :: ${modules}</echo>
</target>
antcall refrence
As sudocode already mentioned, in Core Ant properties are immutable - for good reasons.
With the unset task from Antelope Ant Tasks you're able to unset all properties set in a file with a one liner :
<unset file="test.properties"/>
afterwards
<propertyfile file="test.properties" >
<entry key="modules" type="string" operation="+" value="foo" />
</propertyfile>
will work.
Hint : the task works only for normal properties, not for xmlproperties.
But there's a simple workararound, simply use <echoproperties prefix="..." destfile="foo.properties"/> and afterwards <unset file="foo.properties"/>
If you don't want to use Antelope for that specific task only, you may write a macrodef or own task with similar features.
For this case, when whole properties file is loaded twice, I suggest using different prefixes for the first and second load. First load with aprefix attribute equal to first. Access the properties with this prefix, that is property foo will be accessible as first.foo. Then save the properties file and load again, but this time without a prefix. You will get modified properties in suitable place.
Without using the prefix the second load will do nothing, as ant prevents properties from overriding. Others pointed that already.
Ant properties are immutable - once set, they are fixed. So reloading the properties file will not refresh the value of a property already set.
this macro allow you to change the property value after fixed one
<macrodef name="set" >
<attribute name="name"/>
<attribute name="value"/>
<sequential>
<script language="javascript">
<![CDATA[
project.setProperty("#{name}", "#{value}");
]]>
</script>
</sequential>
</macrodef>
you can create a new properties file and save the property in the new file.
Provide the reference of the file in the next line.
Done :)

Ant manifestclasspath: property already set

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>

How can I allow an Ant property file to override the value set in another?

I have an ant file that does the following:
<property file="project.properties" description="Project configuration properties"/>
<property file="build-defaults.properties" description="default build configuration."/>
<property file="build.properties" description="local build configuration overrides"/>
I want to have defaults set in build-defaults.properties (which is checked in to SCM) but allow developers to override values in a local build.properties so that they can work with local paths.
The problem is, it doesn't seem to be working; I've set this up, created an override in build.properties, but the value of my path remains the one set in build-defaults.properties. How do I accomplish this?
The initial problem with your set up is that you've got build.properties and build-defaults.properties reversed.
Ant Properties are set once and then can never be overridden. That's why setting any property on the command line via a -Dproperty=value will always override anything you've set in the file; the property is set and then nothing can override it.
So the way you want this set up is:
<property file="build.properties" description="local build configuration overrides"/>
<property file="project.properties" description="Project configuration properties"/>
<property file="build-defaults.properties" description="default build configuration."/>
This way:
Anything set at the command line takes precedence over build.properties
Anything set in build.properties overrides other values
etc. on down the line.
Actually ant properties may be overriden. See the documentation of the property task:
Normally property values can not be changed, once a property is set,
most tasks will not allow its value to be modified.
One of the tasks that are able to override the property value is script. Also any custom task may use this backdoor. Other proposals are in question Ant loadfile override property. This is against the spirit of ant and usually unnecessary. But it's good to know that, because I just had an opposite problem: why the property value changed although it is immutable.
Here is a sample target that uses script task to change the value of a property. It shows the basic methods to work with properties. All methods are described in Ant Api which is not available online. You need to download the Ant Manual. In its api directory there is the api documentation.
<target name="t1">
<property name="a" value="one" />
<script language="javascript">
sProp = project.getProperty("a");
sProp = sProp.replace("e", "ly");
project.setProperty("a", sProp);
project.setNewProperty("a", "new value");
</script>
<property name="a" value="two" />
<echo>a=${a}</echo>
</target>
How to easily setup the script task? Making the script task running with beanshell language is a bit tricky and non-trivial, but it's explained in this answer. However as Rebse noted, using javascript language is supported out of the box in jdk 6.
Ant property can't be overwritten unless using macro and javascript plug-in to do:
Step 1: define a macro function to overwrite property
<!--overwrite property's value-->
<macrodef name="set" >
<attribute name="name"/>
<attribute name="value"/>
<sequential>
<script language="javascript">
<![CDATA[
project.setProperty("#{name}", "#{value}");
]]>
</script>
</sequential>
</macrodef>
Step 2: use the macro in the ant xml
<set
name="your_target_property"
value="your_value" or "${another_property}"
</set>

How to call some Ant target only if some environment variable was not set?

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.

Resources