Using an updated ant property in the same target - ant

I have a build.xml file in my ant project and I'm trying to set a build number with properties. I have the following fields in a file called version.properties:
build.major.number
build.minor.number
build.revision.number
build.number
and my build.number format is:
${build.major.number}.${build.minor.number}.${build.revision.number}
and I am currently updating the number
of the revision with propertyfile operation="+" when running my "dist" target. Now everything is working quite fine, except that the build number is always taken from the previous build eg revision.number = 5, build number = 1.1.4.
I have gotten it to work with making 2 targets and dependency for updating the version.properties file with firstly updating the revision number and then in the next target updating the build.number file.
It seems that the operation="+" is executed after every value assignment in a target so I can get the updated value with creating a new target, but it seems sloppy and I would like to be able to do it in only 1 target.
If the 2-target option is as clean as you can get without any JS scripts or any extra packages then okay, I just need to know if it is like that.

Original version.properties
build.major.number=1
build.minor.number=1
build.revision.number=4
build.number=1.1.4
build.xml
<project name="ant-propertyfile-task" default="run" basedir=".">
<target name="run">
<propertyfile file="version.properties">
<entry key="build.revision.number" type="int" operation="+" value="1"/>
</propertyfile>
<loadproperties srcFile="version.properties"/>
<property
name="new.build.number"
value="${build.major.number}.${build.minor.number}.${build.revision.number}"
/>
<propertyfile file="version.properties">
<entry key="build.number" value="${new.build.number}"/>
</propertyfile>
</target>
</project>
Updated version.properties
build.major.number=1
build.minor.number=1
build.revision.number=5
build.number=1.1.5

Related

In Ant, how can I dynamically build a property that references a property file?

I am using Input tasks to collect specific property values and I want to concatenate those into one property value that references my properties file.
I can generate the format of the property but at runtime it is treated as a string and not a property reference.
Example properties file:
# build.properties
# Some Server Credentials
west.1.server = TaPwxOsa
west.2.server = DQmCIizF
east.1.server = ZCTgqq9A
Example build file:
<property file="build.properties"/>
<target name="login">
<input message="Enter Location:" addproperty="loc" />
<input message="Enter Sandbox:" addproperty="box" />
<property name="token" value="\$\{${loc}.${box}.server}" />
<echo message="${token}"/>
</target>
When I call login and provide "west" and "1" for the input values, echo will print ${west.1.server} but it will not retrieve the property value from the properties file.
If I hardcode the property value in the message:
<echo message="${west.1.server}"/>
then Ant will dutifully retrieve the string from the properties file.
How can I get Ant to accept the dynamically generated property value and treat it as a property to be retrieved from the properties file?
The props antlib provides support for this but as far as I know there's no binary release available yet so you have to build it from source.
An alternative approach would be to use a macrodef:
<macrodef name="setToken">
<attribute name="loc"/>
<attribute name="box"/>
<sequential>
<property name="token" value="${#{loc}.#{box}.server}" />
</sequential>
</macrodef>
<setToken loc="${loc}" box="${box}"/>
Additional example using the Props antlib.
Needs Ant >= 1.8.0 (works fine with latest Ant version 1.9.4)
and Props antlib binaries.
The current build.xml in official Props antlib GIT Repository (or here) doesn't work out of the box :
BUILD FAILED
Target "compile" does not exist in the project "props".
Get the sources of props antlib and unpack in filesystem.
Get the sources of antlibs-common and unpack contents to ../ant-antlibs-props-master/common
Run ant antlib for building the jar :
[jar] Building jar: c:\area51\ant-antlibs-props-master\build\lib\ant-props-1.0Alpha.jar
Otherwise get the binaries from MVNRepository or here
The examples in ../antunit are quite helpful.
For nested properties look in nested-test.xml
Put the ant-props.jar on ant classpath.
<project xmlns:props="antlib:org.apache.ant.props">
<!-- Activate Props antlib -->
<propertyhelper>
<props:nested/>
</propertyhelper>
<property file="build.properties"/>
<input message="Enter Location:" addproperty="loc" />
<input message="Enter Sandbox:" addproperty="box" />
<property name="token" value="${${loc}.${box}.server}"/>
<echo message="${token}"/>
</project>
output :
Buildfile: c:\area51\ant\tryme.xml
[input] Enter Location:
west
[input] Enter Sandbox:
1
[echo] TaPwxOsa
BUILD SUCCESSFUL
Total time: 4 seconds
Solution is :
Consider problem is this, where you want to achieve this :
<property name="prop" value="${${anotherprop}}"/> (double expanding the property)?
You can use javascript:
<script language="javascript">
propname = project.getProperty("anotherprop");
project.setNewProperty("prop", propname);
</script>
I gave it a try and this is working for me.

echo message does not show me the correct value from properties file

I have a local.properties file, which contains only one value:
student.id=100
I created the following Ant script to increase the value of student.id by 1 :
<target name="increase-id">
<!-- student.id is increased by 1, no problem -->
<propertyfile file="local.properties">
<entry key="student.id" type="int" operation="+" value="1" />
</propertyfile>
<!--The following echo always show me "Student ID: 1, why?"-->
<echo message="Student ID: ${student.id}"/>
</target>
Every time after I run command ant increase-id , the value of student.id in local.properties file is increased by 1. No problem here. But, the <echo> message always show me Student ID: 1
Why?
This one works for me:
<project name="increase.test" default="increase-id">
<target name="increase-id">
<!-- documentation says that this task is for editing property files -->
<propertyfile file="local.properties">
<entry key="student.id" type="int" operation="+" value="1" />
</propertyfile>
<!-- so you should load this property after edit -->
<property file="local.properties" />
<echo message="Student ID: ${student.id}"/>
</target>
</project>
By the way don't use relative paths. Instead of this always use absolute paths. If you want to load property file which is in the same directory as build.xml you can use <dirname/> task.
<dirname property="build.dir" file="${ant.file.<projectName>}"/>,
where:
${ant.file} is builtin property which indicates to currently runned build.xml
<projectName> is just project name
Try to always create dirname's using this pattern ${ant.file.<projectName> because if you will use only ${ant.file} it will indicates to main build. for example if you have build which runs other build and in the other build you will use ${ant.file} it will indicates to the main build. If it is not clear just read Apache ant documentation and try to create simple build.

Ant: "Duplicated project name in import" with imported build file

I have several build files which all import the same base build file, like this:
base.xml:
<project name="base">
<!-- does not define a 'build' target -->
</project>
buildA.xml:
<project name="buildA">
<import file="base.xml" />
<target name="build">
<ant antfile="buildB.xml" target="build"
inheritall="false" inheritrefs="false" />
</target>
</project>
buildB.xml:
<project name="buildB">
<import file="base.xml" />
<target name="build">
...snip...
</target>
</project>
(Module A depends on module B.)
Now, the above calling of B's build target from buildA.xml gives the following error:
Duplicated project name in import. Project base defined first in buildA.xml and again in buildB.xml
Since both buildA.xml and buildB.xml inherit the same base.xml, this seems unavoidable.
How could I get rid of this error?
Based on sudocode's answer, I solved the problem. Because the absolute path to base.xml is different in both cases, Ant does not recognize it as the same file. Even though inheritAll is set to false, the context of the calling task is preserved and this causes the name clash.
To solve this, one can omit the name attribute from base.xml. Since Ant 1.8, the import task has an attribute as, which can be used to reference base targets when the base project is nameless. If you don't override any targets, you can use include instead of import. I'm on 1.7, so that does not help me.
For previous versions of Ant, you can go through an exec call to prevent proliferation of the Ant context entirely (then you get two running Ant instances). Better yet, find a way to import the exact same base.xml (with the same absolute path) in both files.
Are you using Ant 1.6? This resolved Ant bug looks like the same issue.
EDIT
I tried to reproduce the dir structure you refer to in your recent comment.
./base.xml
./buildA
./buildA/buildA.xml
./buildB
./buildB/buildB.xml
And amended the build files accordingly, e.g.
<project name="buildA">
<import file="../base.xml"/>
<target name="build">
<ant antfile="../buildB/buildB.xml" target="build" inheritall="false" inheritrefs="false"/>
</target>
</project>
I still get no build error for the following with ant 1.8.2 or 1.7.1:
ant -f buildA/buildA.xml build

Creating an ear-File with ant

I am new to ant i referred many sites , i need to build.xml for my project which consists
of two modules i have application.xml file which represents corresponding war file
so my question is it sufficient to add the application.xml file
<ear destfile="${dist.dir}/${ant.project.name}.ear" appxml="${conf.dir}/application.xml">
<metainf dir="${build.dir}/META-INF"/>
<fileset dir="${dist.dir}" includes="*.jar,*.war"/>
</ear>
whether this will refer the corresponding war files or i need to compile the whole scenario please let me know. how solve this.
I'm not 100% sure what you're asking.
In order to use the <ear> task, you already need to have compiled the required jars and wars.
If those jars and wars have already been built, you simply refer to them in your <ear> task as you did in your example. The application.xml must already exist before you build your ear. The application.xml doesn't build the jars and wars, you have to do that.
If you haven't already built the wars and jars, you need to do that first. A general outline of a build.xml looks something like this:
<project name="foo" basedir="." default="package">
<!-- Some standard properties you've defined -->
<property name="target.dir" value="${basedir}/target"/>
<property name="xxx" value="yyy"/>
<property name="xxx" value="yyy"/>
<property name="xxx" value="yyy"/>
<!-- Compile properties that allow overrides -->
<property name="javac.nowarn" value="false"/>
<property name="javac.listfiles" value="false"/>
<property name="javac.srcdir" value="source"/>
<property name="javac.distdir" value="${target.dir}/classes"/>
<target name="clean"
description="cleans everything nice and shiny">
<delete dir="${target.dir}"/>
</target>
<target name="compile"
description="Compiles everything">
<mkdir dir="${javac.distdir}"/>
<javac srcdir="${javac.srcdir}"
destdir="${javac.destdir}"
[...]
[...]/>
</target>
<target name="package.jar"
depends="compile"
description="Package jarfile">
<jar destfile="${target.dir}/jarname.jar"
[...]
[...]/>
</target>
<target name="package.jar2"
depends="compile"
description="Package jarfile">
<jar destfile="${target.dir}/jarname2.jar"
[...]
[...]/>
</target>
<target name="package.war"
depends="compile"
description="Package jarfile">
<war destfile="${target.dir}/jarname.jar"
[...]
[...]/>
</target>
<target name="package"
depends="package.jar"
description="Make the ear">
<ear destfile="${target.dir}/earfile.ear"
[...]/>
</target>
</project>
Basically, it consists of a bunch of targets and each target does one task. You can have targets depend upon other targets. For example, this particular build.xml will automatically run the package task. The package task depends upon the package.jar task which depends upon the compile task. Thus, the build.xml file will first call compile, then package.jar, then package.
The important thing to remember is that you don't specify the order of the events. You let Ant figure that out, and you let Ant figure out what you need to do. Let's say you've modified a java source file. Ant knows that it has to recompile only that one file. It also knows that it might have to rebuild the jarfile that contains that classfile. And, it then knows it has to rebuild the ear. Most tasks can figure it out on their own, and you don't do a clean for each build. (You notice that the clean target isn't called by package or compile. You have to call it manually).
The only other thing I recommend is that you try to keep your work area clean. Any files you create should be put into the ${target.dir} directory. That way, when you do a clean, you only have to delete that one directory.
I hope this answer your question.

Set a property inside one ant target and use it in another target

My build file is
<target name="default">
<antcall target="child_target"/>
<echo> ${prop1} </echo>
</target>
<target name="child_target">
<property name="prop1" value="val1"/>
</target>
I get an error that ${prop1} has not been set. How do I set a property in the target?
antcall creates a new project. From the Ant documentation:
The called target(s) are run in a new
project; be aware that this means
properties, references, etc. set by
called targets will not persist back
to the calling project.
Use depends instead:
<project default="default">
<target name="default" depends="child_target">
<echo>${prop1}</echo>
</target>
<target name="child_target">
<property name="prop1" value="val1"/>
</target>
</project>
Old and probably dead issue I know, but a property file loaded outside targets but inside the project would also work. Android does this with local.properties like so:
<?xml version="1.0" encoding="UTF-8"?>
<project name="avia" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />

Resources