How would you write a build.xml file, using neither custom code nor external dependencies (such as a shell script), that:
Generates a build number of the form major.minor.revision (e.g., 01.02.34).
Auto-increments the revision on each compile of the source code.
Auto-increments the minor version on each execution of a dist(ribution) task.
Additionally:
Provides an option to increment the major number.
Provides an option to increment the minor number.
Whenever the major number is incremented, the minor and revision numbers are set to 0.
Whenever the minor number is incremented, the revision number is set to 0.
Bonus:
Creates a variable based on the git revision number (like a subversion revision number).
Clarification:
Automatic checkout (or commit) is not required.
Integration with Subversion is not desired.
Thank you for any examples. Here are some related sites that describe how to perform similar tasks:
Create a Build Number with Ant.
Using the BuildNumber Ant task.
Ant and Build Version Numbers.
The build_info.properties file:
build.major.number=00
build.revision.number=00
build.minor.number=00
The build.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<project name="project" default="current-number">
<property file="build_info.properties"/>
<property name="build.number" value="${build.major.number}.${build.minor.number}.${build.revision.number}"/>
<target name="current-number">
<echo>Current build number:${build.number}</echo>
</target>
<target name="compile">
<antcall target="revision"></antcall>
</target>
<target name="dist">
<antcall target="minor"></antcall>
</target>
<target name="revision">
<propertyfile file="build_info.properties">
<entry key="build.revision.number" type="int" operation="+" value="1" pattern="00"/>
</propertyfile>
</target>
<target name="minor">
<propertyfile file="build_info.properties">
<entry key="build.minor.number" type="int" operation="+" value="1" pattern="00"/>
<entry key="build.revision.number" type="int" value="0" pattern="00"/>
</propertyfile>
</target>
<target name="major">
<propertyfile file="build_info.properties">
<entry key="build.major.number" type="int" operation="+" value="1" pattern="00"/>
<entry key="build.minor.number" type="int" value="0" pattern="00"/>
<entry key="build.revision.number" type="int" value="0" pattern="00"/>
</propertyfile>
</target>
<target name="all">
<propertyfile file="build_info.properties">
<entry key="build.major.number" type="int" operation="+" value="1" pattern="00"/>
<entry key="build.minor.number" type="int" operation="+" value="1" pattern="00"/>
<entry key="build.revision.number" type="int" operation="+" value="1" pattern="00"/>
</propertyfile>
</target>
</project>
This solution does increment minor or revision number automatically if a compile or a dist target has been selected. The incrementation can be switched off if one of the following properties has been set:
-Dno.increment.minor=true
-Dno.increment.revision=true
If the property inc.major has been set, then the major number will be incremented and the other both values will be set to zero. The SHA-1 checksum is being calculated by the textual representation of the version file.
By the way: If would have been allowed, you could create your own ant task in java script, which is included in JDK 6.
Now here's the ant file
<?xml version="1.0" encoding="UTF-8"?>
<project name="Numbers" default="dist" basedir=".">
<property name="version.file" location="${basedir}/version.properties"/>
<target name="inc.revision.properties" unless="no.increment.revision">
<propertyfile file="${version.file}">
<entry key="minor.number" default="00" operation="=" pattern="00" type="int"/>
<entry key="major.number" default="00" operation="=" pattern="00" type="int"/>
<entry key="build.number" default="00" operation="+" pattern="00" type="int"/>
</propertyfile>
</target>
<target name="inc.minor.properties" unless="no.increment.minor">
<propertyfile file="${version.file}">
<entry key="minor.number" default="00" operation="+" pattern="00" type="int"/>
<entry key="major.number" default="00" operation="=" pattern="00" type="int"/>
<entry key="build.number" value="00" operation="=" type="int"/>
</propertyfile>
</target>
<target name="inc.major" if="inc.major">
<property name="no.increment.minor" value="true" />
<property name="no.increment.revision" value="true" />
<propertyfile file="${version.file}">
<entry key="minor.number" value="00" operation="=" pattern="00" type="int"/>
<entry key="major.number" default="00" operation="+" pattern="00" type="int"/>
<entry key="build.number" value="00" operation="=" pattern="00" type="int"/>
</propertyfile>
<load.version.info/>
</target>
<target name="inc.minor" depends="inc.major,inc.minor.properties">
<property name="no.increment.revision" value="true"/>
<load.version.info/>
</target>
<target name="inc.revision" depends="inc.major,inc.revision.properties">
<load.version.info/>
</target>
<macrodef name="load.version.info">
<sequential>
<property file="${version.file}"/>
<checksum file="${version.file}" property="sha1.number" algorithm="SHA" format="CHECKSUM"/>
<echo>Version: ${major.number}.${minor.number}.${build.number}</echo>
<echo>SHA1: ${sha1.number}</echo>
</sequential>
</macrodef>
<target name="compile" depends="inc.revision" description="Compile Task"/>
<target name="dist" depends="inc.minor, compile" description="Dest Task"/>
</project>
Build Process
build_info.properties will be created during build in your project
folder You could write all information about your build in this file.
Like build number, major and minor numbers of release, timestamp, and revision number.
Your build script can
modify these values how ever your
want
After the build was successfull commit the file 'build_info.properties' back to the
repository
During Development
After first build the file build_info.properties will be placed in the repository.
You can change and commit any number (major, minor, build numbers) by your self when ever you want, or increase it automatically during build like build.number in the example below.
svnant Example
Using svnant 1.3.0:
<target name="checkout">
<echo>Checking out revision ${param_SubProjectSvnREV} of project: ${param_SubProjectSvnName}</echo>
<svn username="${svnant.repository.user}" password="${svnant.repository.passwd}">
<checkout url="${svnant.latest.url}/${param_SubProjectSvnName}/" revision="${param_SubProjectSvnREV}" destPath="${all.projects.dir}/${param_SubProjectDirName}" />
<info target="${all.projects.dir}/${param_SubProjectDirName}" ></info>
</svn>
<propertyfile file="${all.projects.dir}/${param_SubProjectDirName}/build_info.properties" comment="Modify build numbers in a properties file.">
<entry key="build.number" type="int" operation="+" value="1" pattern="00"/><!--increment it here -->
<entry key="build.revision" type="string" value="${svn.info.rev}"/>
<entry key="build.major.number" default="01"/><!-- can do some logic here to increase the values, or write value from somewhere else-->
<entry key="build.minor.number" default="01"/><!-- can do some logic here to increase the values, or write value from somewhere else-->
</propertyfile>
</target>
<target name="compile" depends="checkout">
<property file="${all.projects.dir}/${param_SubProjectDirName}/build_info.properties" />
<mkdir dir="${release.name}/${param_SubProjectDirName}/${build.major.number}.${build.minor.number}.${build.number}" />
<!-- compile it to the new folder, an so on... -->
<!-- after all, if the build wass successfull, commit the file 'build_info.properties' back to repository -->
</target>
The easiest way of doing this is to change the problem. Instead of making the Any build do this for you, have whatever process that you're calling Ant calculate what the version number should be, and then pass that in as a property e.g.
ant -Dbuild.version=1.2.3
This has the flexibility of whatever build you're working with being able to take its cue from whatever, such as the SVN revision, the current date and time, or whatever.
ant -Dbuild.version=svnversion .
ant -Dbuild.version=date +"%Y%m%d%H%D"
ant -Dbuild.version=${major}.svnversion ..date +"%Y%m%d%H%D"
etc. You can get pretty comprehensive if you want.
If you want to have an ever incrementing number, then you can store it in a file and then pass that in at compile time. For example, you can do:
VER=cat build.version
VER=$((VER+1))
echo $VER > build.version
Lastly, if you really want this to be in the build.xml file, the best thing to do is have a separate task to execute the increment-and-build option and fork off a nested ant build with your 'main' target. You'd thus end up with
ant -> ant -Dbuild.version=1.2.3.4 -> ...
In other words, given your build.xml with a (current) default of 'build', then change it to 'version' and have the ant 'version task do the calculation followed by a nested call to and build.
Implementation is left as an exercise to the reader, as is translating the approach to a non-UNIX platform.
This was a while ago, so this is from memory:
I build a custom CruiseControl.Net labeller block that ticked up the build number on each build. It maintained an XML file with all 4 components of the version number and identified each project by name (so it could support multiple projects).
The four values it generated get passed to the build process (nAnt, in our case), which had the responsibility of tweaking all the AssemblyInfo.cs files to reflect the proper build number.
Edited to note: The only value that get automatically ticked up was the build number. Major/Minor version numbers were specified in the CC.Net project configuration. The build number restarted at 0001 for each change in major or minor revision number (e.g., if you went from version 7.1 to version 7.3, for instance, the 7.1 build might be at build number 783, but the first 7.3 build started with build number 1; the next 7.1 build would be build 784.
Change version numbers merely required tweaking 1 setting the CC.Net config file.
In my project i don’t increase the minor and major number automatically. We set it from our global build properties. Like that:
<entry key="build.major.number" value="${global.release.major}"></entry>
<entry key="build.minor.number" value="${global.release.minor}"></entry>
That’s because they will be changed for releases (not for test or other builds) and committed together with other sources (we have be able to build some old or branch version).
But if you want to increase the minor number, you can do it like the build number in my example.
<entry key="build.major.number" type="int" operation="+" default="1" pattern="00"/>
We can use conditions to check if we should increase the micro,minor and major version.
Increase minor if micro is 9, and so on.
<target name="increaseBuildNumber" depends="increase.micro, increase.minor, increase.major" description="Increase Build Number"/>
<target name="increase.micro" if ="microNotEquals9">
<propertyfile file="build.properties">
<entry key="micro.number" default="0" operation="+" pattern="0" type="int"/>
</propertyfile>
</target>
<target name="increase.minor" if = "microEquals9andMinorNotEquals9">
<propertyfile file="build.properties">
<entry key="minor.number" default="0" operation="+" pattern="0" type="int"/>
<entry key="micro.number" value="0" operation="=" pattern="0" type="int"/>
</propertyfile>
</target>
<target name="increase.major" if = "microAndMinorEquals9" >
<propertyfile file="build.properties">
<entry key="major.number" default="0" operation="+" pattern="0" type="int"/>
<entry key="minor.number" value="0" operation="=" pattern="0" type="int"/>
<entry key="micro.number" value="0" operation="=" pattern="0" type="int"/>
</propertyfile>
</target>
<condition property="minorEquals9">
<equals arg1="${minor.number}" arg2="9"/>
</condition>
<condition property="microEquals9andMinorNotEquals9">
<and>
<equals arg1="${micro.number}" arg2="9"/>
<not><equals arg1="${minor.number}" arg2="9"/></not>
</and>
</condition>
<condition property="microAndMinorEquals9">
<and>
<equals arg1="${micro.number}" arg2="9"/>
<equals arg1="${minor.number}" arg2="9"/>
</and>
</condition>
<condition property="microNotEquals9">
<not><equals arg1="${micro.number}" arg2="9"/></not>
</condition>
Related
I have a ant build script which creates a war file. The file content are as follows.
<?xml version="1.0" encoding="UTF-8"?>
<project name="TestProj" default="war" basedir=".">
<property name="project-name" value="${ant.project.name}" />
<property name="builder" value="IaasTeam" />
<property name="war-file-name" value="${project-name}.war" />
<property name="source-directory" value="src" />
<property name="classes-directory" value="build/classes" />
<property name="web-directory" value="WebContent" />
<property name="web-xml-file" value="WebContent/WEB-INF/web.xml" />
<property name="lib.dir" value="WebContent/WEB-INF/lib" />
<property name="catalina.home" value="../../outside/project/lib"/>
<tstamp prefix="build-info">
<format property="current-date" pattern="d-MMMM-yyyy" locale="en" />
<format property="current-time" pattern="hh:mm:ss a z" locale="en" />
</tstamp>
<property name="build-directory" value="build" />
<path id="classpath">
<fileset dir="${lib.dir}" includes="**/*.jar"/>
<fileset dir="${catalina.home}" includes="**/*.jar"/>
</path>
<target name="clean">
<delete dir="build"/>
</target>
<target name="compile">
<mkdir dir="build/classes"/>
<javac includeantruntime="false" srcdir="src" destdir="build/classes" classpathref="classpath" />
</target>
<target name="war" depends="clean,compile">
<mkdir dir="${build-directory}" />
<delete file="${build-directory}/${war-file-name}" />
<war warfile="${build-directory}/${war-file-name}" webxml="${web-xml-file}">
<classes dir="${classes-directory}" />
<fileset dir="${web-directory}">
<!-- Need to exclude it since webxml is an attribute of the war tag above -->
<exclude name="WEB-INF/web.xml" />
</fileset>
<manifest>
<attribute name="Built-By" value="${builder}" />
<attribute name="Built-On" value="${build-info.current-date}" />
<attribute name="Built-At" value="${build-info.current-time}" />
</manifest>
</war>
</target>
I am using Jenkins as a build server (this is hosted on different machine kind of DEV environment).
I also use Gitlab as a repository and after pushing the latest code I have a hook for Jenkins job which gets triggered automatically and calls this build.xml.
Now the issues here is that when I run this script on my local machine everything works well but when Jenkins execute this it fails during the compilation phase giving me below error.
compile:
[mkdir] Created dir: /app/infra/jenkins/workspace/TestProj/build/classes
[javac] Compiling 49 source files to /app/infra/jenkins/workspace/TestProj/build/classes
BUILD FAILED
/app/infra/jenkins/workspace/TestProj/build.xml:27: /app/infra/jenkins/outside/project/lib does not exist.
The reason for this issue is the build server does not have any directoy called outside/project/lib.
The only reason of adding this directory in my build.xml is to have the container specific jar files ready for compiling.
How can I fix this issue?
Do I need to copy container specific jars on my build server? Or is there any way to tell Jenkins that not to copy this external jars but just use them for compilation.
Where would Jenkins find the jars? They need to be accessible otherwise your build will fail. If you don't want to have the files checked in (which is very sensible), you could use Apache Ivy to download them for you.
This is the most common way of handling the situation you're having. Using a dependency management framework like Ivy (or Maven, or similar) will save you a lot of headaches down the line. I recommend you have a look at their tutorial. After you set it up, your ant build will take care of downloading the files you need.
I have a very little knowledge about writing build files using ant targets.
the problem i am facilng is i want to have a build file which should import other ant build file if the given condition is satisfied.
For suppose here in the below code if ${myresult} is set to true then the postgreswebtest.xml should be used else mysqlwebtest.xml should be used.
So i tried to achieve this with the following code.
<?xml version="1.0" encoding="utf-8" ?>
<project name="webtest" default="build" basedir=".">
<target name="build">
<property name="DBTYPE" value="${arg0}" />
<echo message="${DBTYPE}" />
<condition property="myresult">
<equals arg1="${DBTYPE}" arg2="postgres" />
</condition>
<echo message="${myresult}" />
<if>
<isset property="myresult"/>
<then>
<import file="postgreswebtest.xml" />
</then>
<else>
<import file="mysqlwebtest.xml" />
</else>
</if>
</target>
</project>
but when i execute this code getting the following error.
BUILD FAILED:
webtest.xml:21: import only allowed as a top-level task
Could someone please help me out with the solution
You can use ant ant task instead which acts as if it is imporing supplied build file. Refer to : https://ant.apache.org/manual/Tasks/ant.html for more details.
With ant you can provide default target to run as well.
With this approach it will conditional evaluate and import file inside your 'build' target.
<if>
<isset property="myresult"/>
<then>
<ant antfile="postgreswebtest.xml" />
</then>
<else>
<ant antfile="mysqlwebtest.xml" />
</else>
</if>
There are a couple of questions to this topic already, but none of them seem to work properly.
Here is a list of them:
Bulding an multi-platform SWT application using Ant
Build multi-platform executable for a SWT application (Eclipse)
Build multi-platform executable for a SWT application using maven
SWT jar for different platform
Create cross platform Java SWT Application
My requirement is to build an ant script that creates one jar per platform, i.e. one for Windows x86, one for Windows x64, Linux x86/x64 and so on.
Does anyone have any further insight?
Using the aforementioned methods, I was not able to produce a workable solution. It either ended with the SWT jar file not automatically being loaded or it not being included in the classpath.
If someone can come up with a working example (ideally including the complete source code), that would be grand!
Right, so I finally came up with a solution that I successfully tested on three platforms.
The two magic components are the jar-in-jar-loader and a proper build script.
The build script with comments can be found here:
<project name="RandomApp" basedir="." default="clean-build">
<property name="src.dir" value="src" />
<!-- Define the necessary paths -->
<property name="build.dir" value="bin_temp" />
<property name="lib.dir" value="lib" />
<property name="lib.deploy.dir" value="lib_swt" />
<property name="classes.dir" value="${build.dir}/classes" />
<property name="jar.dir" value="${build.dir}/jar" />
<property name="img.dir" value="img" />
<property name="res.dir" value="res" />
<!-- Define the main class -->
<property name="main-class" value="org.baz.desktop.randomapp.gui.RandomApp" />
<path id="base-classpath">
<fileset dir="${lib.dir}" includes="**/*.jar" />
</path>
<!-- Define the class path -->
<path id="classpath">
<fileset dir="${lib.dir}" includes="**/*.jar" />
<fileset dir="${lib.deploy.dir}" includes="**/swt_win32_x64.jar" />
</path>
<!-- Clean previously built files -->
<target name="clean">
<delete dir="${build.dir}" />
</target>
<!-- Compile the project -->
<target name="compile">
<mkdir dir="${classes.dir}" />
<javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath" includeantruntime="false" />
</target>
<macrodef name="createclasspath">
<attribute name="name" />
<attribute name="swtlib" />
<sequential>
<pathconvert property="#{name}.classpath" pathsep=" ">
<path refid="base-classpath" />
<fileset dir="${lib.deploy.dir}" includes="**/swt_#{swtlib}.jar" />
<mapper>
<chainedmapper>
<flattenmapper />
<globmapper from="*.jar" to="*.jar" />
</chainedmapper>
</mapper>
</pathconvert>
</sequential>
</macrodef>
<!-- Define classpath and create the jar folder -->
<target name="pre_jar" depends="compile">
<!-- Linux 32bit -->
<createclasspath name="win86" swtlib="win32_x86" />
<!-- Linux 64bit -->
<createclasspath name="win64" swtlib="win32_x64" />
<!-- Windows 32bit -->
<createclasspath name="linux86" swtlib="linux_gtk_x86" />
<!-- Windows 64bit -->
<createclasspath name="linux64" swtlib="linux_gtk_x64" />
<!-- MacOS 32bit -->
<createclasspath name="macos86" swtlib="macos_x86" />
<!-- MacOS 64bit -->
<createclasspath name="macos64" swtlib="macos_x64" />
<mkdir dir="${jar.dir}" />
</target>
<macrodef name="createjar">
<attribute name="swtlib" />
<attribute name="swtclasspath" />
<sequential>
<jar destfile="${jar.dir}/${ant.project.name}_#{swtlib}.jar" basedir="${classes.dir}">
<manifest>
<attribute name="Main-Class" value="org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader" />
<attribute name="Rsrc-Main-Class" value="${main-class}" />
<attribute name="Class-Path" value="." />
<attribute name="Rsrc-Class-Path" value="./ #{swtclasspath}" />
</manifest>
<zipgroupfileset dir="${lib.dir}" includes="**/jar-in-jar-loader.jar" />
<zipfileset dir="${lib.deploy.dir}" includes="**/swt_#{swtlib}.jar" />
<zipfileset dir="${lib.dir}" includes="**/*.jar" excludes="**/jar-in-jar-loader.jar" />
</jar>
</sequential>
</macrodef>
<!-- Create the jar files -->
<target name="jar" depends="pre_jar">
<!-- Linux 32bit -->
<createjar swtlib="linux_gtk_x86" swtclasspath="${linux86.classpath}" />
<!-- Linux 64bit -->
<createjar swtlib="linux_gtk_x64" swtclasspath="${linux64.classpath}" />
<!-- Windows 32bit -->
<createjar swtlib="win32_x86" swtclasspath="${win86.classpath}" />
<!-- Windows 64bit -->
<createjar swtlib="win32_x64" swtclasspath="${win64.classpath}" />
<!-- MacOS 32bit -->
<createjar swtlib="macos_x86" swtclasspath="${macos86.classpath}" />
<!-- MacOS 64bit -->
<createjar swtlib="macos_x64" swtclasspath="${macos64.classpath}" />
</target>
<target name="clean-build" depends="clean,jar" />
</project>
What it basically does is define a base classpath without any SWT library.
Then it creates platform specific classpaths using the base one and adding the appropriate platform SWT library.
The jar task then creates a separate jar for each platform using these classpaths and the jar-in-jar-loader.
And that's it, a fully automated way of generating jars for each (supported) platform.
I've created an example project that people can download and test out. It's an easy starting point for a multi-platform application.
https://www.dropbox.com/s/ianrbl4bn0fmsdi/SWTApplication.7z
Update:
I've managed to significantly shorten the ant script by making proper use of macrodef :)
Can i set an variable in available tag like this?
<available file="${inf.root}/schema_params/#{componame}-schema.sql"
type="file"
variable="schema.file" />
because when i use property instead of variable in available tag, Its value is immutable. But i want to change it at run time.Below is my code.i want to copy 1 file checking through my component list. if the file exists, i have to copy and move it. else i have to skip the logic. But whats happening is, if i dont use this code,
<var name="schema.params.file" unset="true"/>
<property name="schema.params.file" value="false"/>
<var name="scripts.dir" unset="true"/>
<property name="scripts.dir" value="false"/>
in the first iteration if schema.params.file,scripts.dir is set to true if files exist, it is not overided in the next iteration even though if file doenot exist. so i have added above code.but now always the values are set to false again by above code. how can i overcome the issue of overiding these 2 schema.params.file,scripts.dir in every iteration?
<for list="${t1.#{componentname}}" param="installableid" delimiter="${line.separator}">
<sequential>
<available file="${infinys.root}/schema_params/#{componentname}-schema_params.sql"
type="file"
property="schema.params.file" />
<available file="${stage.dir}/#{componentname}/#{installableid}/schema/install/scripts"
type="dir" property="scripts.dir"/>
<if>
<and>
<equals arg1="true" arg2="${schema.params.file}" />
<equals arg1="true" arg2="${scripts.dir}" />
</and>
<then>
<copy file="${infinys.root}/schema_params/#{componentname}-schema_params.sql"
todir="${stage.dir}/#{componentname}/#{installableid}/schema/install/scripts"
failonerror="false" />
<move file="${stage.dir}/#{componentname}/#{installableid}/schema/install/scripts/#{componentname}-schema_params.sql"
tofile="${stage.dir}/#{componentname}/#{installableid}/schema/install/scripts/schema_params.sql"
failonerror="false"/>
<chmod file="${stage.dir}/#{componentname}/#{installableid}/schema/install/scripts/schema_params.sql" perm="775"/>
<var name="schema.params.file" unset="true"/>
<property name="schema.params.file" value="false"/>
<var name="scripts.dir" unset="true"/>
<property name="scripts.dir" value="false"/>
</then>
</if>
</sequential>
</for>
Can i set an variable in available tag like this?
Yes, you can.
Macro names are changed with each iteration. The <var/> task is simply a way to unset and reset a property in Ant. It's part of the Ant-Contrib project. You don't need to unset and reset the property:
<var name="schema.params.file" unset="true"/>
<property name="schema.params.file" value="false"/>
You could do this in a single statement:
<var name="schema.params.file" value="false"/>
Their use is highly discouraged since it breaks Ant's immutable property idea. However, I've find that I too use <var/> a lot when going through <for/> loops and sometimes <macrodef>. Newer versions of Ant allow you to localize properties, so I suspect the <var/> task will soon no longer be needed.
Another thing which may make things a bit easier is that you can use <if/> tests with <available/>
<if>
<then>
<and>
<available file="${infinys.root}/schema_params/#{componentname}-schema_params.sql"
type="file"/>
<available file="${stage.dir}/#{componentname}/#{installableid}/schema/install/scripts"
type="dir"/>
</and>
<sequencial>
....
</sequential/>
</then>
</if>
Doing this may make your code a bit cleaner and easier to understand. It will also eliminate the need to unset properties in the first place.
Ant doesn't allow overwriting properties. You still can use macrodef but that's another story (see How to over-write the property in Ant?).
What you can do is move the internals of your cycle to the separate target like (can't see why you copy a file to another location and immediately move it to another another location, so I just replaced this copy-move with one copy)
<target name="cycle-body">
<available file="${schema.params.file.name}" type="file" property="schema.params.file" />
<available file="${scripts.dir.name}" type="dir" property="scripts.dir"/>
<if>
<and>
<equals arg1="true" arg2="${schema.params.file}" />
<equals arg1="true" arg2="${scripts.dir}" />
</and>
<then>
<copy file="${schema.params.file.name}"
tofile="${scripts.dir.name}/schema_params.sql" failonerror="false"/>
<chmod file="${scripts.dir.name}/schema_params.sql" perm="775"/>
</then>
</if>
</target>
and call it like
<for list="${t1.#{componentname}}" param="installableid" delimiter="${line.separator}">
<antcall target="cycle-body">
<param name="schema.params.file.name" value="${infinys.root}/schema_params/#{componentname}-schema_params.sql" />
<param name="scripts.dir.name" value="${stage.dir}/#{componentname}/#{installableid}/schema/install/scripts" />
</acntcall>
</for>
I have a webapp to be ran on Tomcat6/JbossAS 5 and, for versioning purposes, I have several AND targets that will perform a set of operations to define a constant with version number and build datetime.
The targets perform the following:
Delete the Release.java
Copy the Release.template to Release.java with the versioning info properly set as a constant (public static final String)
The thing is that, the constant references are replaced on the code before compilation. For instance, where I have
log.debug("Release: " + Release.info);
I can see, using java decompiler, the following (let's assume that "TO_BE_DEFINED" is the initial value for Relase.info):
log.debug("Release: TO_BE_DEFINED");
The targets are the following:
<target name="build-config" >
<!-- config -->
<property name="project.name" value="MY PROJECT" />
<property name="release.prefix" value="MPROJECT" />
<property name="release.num" value="1.0" />
<property name="release.info.file.path" value="org/my/project/Release" />
<tstamp>
<format property="release.date" pattern="yyyy-MM-dd HH:mm:ss z" />
</tstamp>
<!-- end config -->
<property name="release.version" value="${release.prefix}-${release.num}" />
<property name="release.info" value="${release.version} ${release.date}" />
</target>
<target name="build-replace">
<filter token="release.info" value="${release.version} ${release.date}" />
<delete file="${src.dir}/${release.info.file.path}.java" />
<copy file="${src.dir}/${release.info.file.path}.template" tofile="${src.dir}/${release.info.file.path}.java" filtering="true" />
</target>
<target name="build-myproj-1.0.jar" depends="init,buil-config,build-replace,compile">
<mkdir dir="${dist.dir}"/>
<jar compress="true" jarfile="${dist.dir}/MPROJECT-1.0.jar">
<fileset dir="${build.classes.dir}"
excludes="META-INF/*.*, WEB-INF/classes/*.xml"
includes="**/*.class"
/>
<manifest>
<section name="${project.name}">
<attribute name="Release-Version" value="${release.version}" />
<attribute name="Release-Date" value="${release.date}" />
</section>
</manifest>
</jar>
</target>
and my class is defined as
public abstract class Release {
/** Release info */
public static final String INFO = "TO_BE_DEFINED";
}
I understand that this may be a little bit confusing and if I'm missing some information please feel free to ask
Compile-time constants are replaced in client code when the client code is compiled.
To get the client code to pick up the new value of the constant, either recompile everything, replace the field with a getter, or use one of the strategies from this question