get property from different ant project - ant

Is it possible to read properties from another ant project ?
I could do it with:
<ant antfile="child/build.xml" target="echoproperties">
<property name="echoproperties.file" value="${tmp}/child.properties" />
</ant>
<property prefix="child" file="${tmp}/child.properties" />
<delete file="${tmp}/child.properties" />
While in child/build.xml:
<target name="echoproperties">
<echoproperties destfile="${echoproperties.file}" />
</target>
But I would like to avoid creating temporary files.

I've found that Ant-Contrib has antfetch task although it's functionality is not that great (no prefix, no propertysets).

Related

how to ignore a failure ant task?

I have this ant script that is reading from a parameter a list of components and running other ant tasks (build.xml's):
<for list="${components.locations}" param="component" failonany="false">
<sequential>
<property name="#{component}" value="true"/>
<if>
<and>
<available file="${repository.location}/#{component}"/>
<available file="${repository.location}/${jars.location}"/>
</and>
<then>
<ant inheritAll="false" antfile="${repository.location}/#{component}/build.xml">
<!-- failonerror="false" -->
<property name="copy.libs" value="${copy.libs}"/>
<property name="repository.location" value="${repository.location}"/>
<property name="jars.location" value="${repository.location}/${jars.location}"/>
</ant>
</then>
</if>
</sequential>
</for>
The problem is if one component is failing, the script doesn't continue to next one.
I tried running with -k (-keep-going) argument but it doesn't help.
I found this property failonerror="false" but it's valid for "exec" tasks and couldn't integrate it with "ant" tasks or inside a "target".
Other direction was "failonany" property of the "for" but I didn't manage setting it up explicitly.
Can you please advice...
Thanks.
First of all, I would suggest deleting ant-contrib.jar and never looking back. Believe me, you will be doing yourself a favor.
You can use the subant task to iterate Ant builds on a set of directories or files. Simply define a dirset and pass any extra properties you need.
Instead of using ant-contrib's <if> block, use the standard target's if attribute to switch the entire target on or off. This is much safer and better practice.
<property name="repository.location" location="repository_location" />
<property name="jars.location" location="${repository.location}/jars" />
<property name="components" value="dir1,dir2,dir3" />
<target name="init">
<condition property="jars.available">
<available file="${jars.location}" />
</condition>
</target>
<target name="default" depends="init" if="jars.available">
<subant inheritall="false" failonerror="false">
<dirset id="components.dirs" dir="${repository.location}" includes="${components}" />
<property name="copy.libs" value="${copy.libs}" />
<property name="repository.location" value="${repository.location}" />
<property name="jars.location" value="${jars.location}" />
</subant>
</target>

Multiple property files for different builds

I have a project with 3 targets for different build variants each having their own property file defined like this:
<target name="dev">
<property file="dev.properties" />
<antcall target="build" />
</target>
<target name="test">
<property file="test.properties" />
<antcall target="build" />
</target>
<target name="prod">
<property file="prod.properties" />
<antcall target="build" />
</target>
All property files define the same properties. Now I need to make a target which would build them all, I tried something like:
<target name="all">
<antcall target="dev" />
<antcall target="test" />
<antcall target="prod" />
</target>
But the problem is that ant properties are immutable and I end up with properties from dev.properties for all builds. What's the recommended approach if I want to build all three targets with their own properties?
Wouldn't it be a lot simpler to have a single build script, and then decide it's purpose at run-time?
For example:
ant -propertyfile build-dev.properties
ant -propertyfile build-test.properties
ant -propertyfile build-prod.properties
..
This approach is more flexible when automating your builds using something like Jenkins. It can detect source code changes and run each build type automatically (and in parallel) if that is the desired outcome.

Unusual ant behavior with presetdef and antcall

Consider the following excerpt from an ant build.xml:
<presetdef name="echo1def">
<echo message="prop: ${foo}" />
</presetdef>
<presetdef name="echo2def">
<sequential>
<echo message="prop: ${foo}" />
</sequential>
</presetdef>
<target name="echotarget1">
<property name="foo" value="bar" />
<echo1def/>
</target>
<target name="echotarget2">
<property name="foo" value="bar" />
<echo2def/>
</target>
<target name="echo1">
<antcall target="echotarget1" />
</target>
<target name="echo2">
<antcall target="echotarget2" />
</target>
Calling any of {echotarget1, echotarget2, echo1} produce the expected output of prop: bar. Calling echo2, however, produces prop: ${foo}.
Why can't the echo2def resolve the ${foo} property? It's defined immediately before, in the same project (i.e., not even on the other side of the antcall). The echo1 call, which does the same thing except the presetdef is not wrapped in <sequential>, has no issue.
Finally,
<target name="echo3">
<property name="foo" value="baz" />
<antcall target="echotarget2" />
</target>
reports prop: baz - so the property from the antcalling project can be seen, even though it is defined after the presetdef is.
Just get rid of <sequential> in your echo2def presetdef, means :
<presetdef name="echo2def">
<echo message="prop: ${foo}" />
</presetdef>
and all will work as expected.
It's because property scopes exist at Apache Ant's various "block" levels including sequential, that's how i.e. the local task (new in Ant 1.8.0) works.
antcall opens a new project scope, without antcall - means calling those targets echotarget1 and echotarget2 directly - it works also, resolving the property ${foo}.

ant large project. How to enforce common output directory structure - include,import and inhertAll=false?

I have a toplevel ant project and many subprojects under it.
./build.xml
./datamodel_src/src/build.xml
./datamodel_src/src/module1/build.xml
./datamodel_src/src/module2/build.xml
./infrastructure_src/src/build.xml
./interfaces_src/src/build.xml
Each of the subproject, I want to enforce a common output directory structure. Project will have a work area and each sub project will have its own work area under it. Each subproject should create its artifacts (lib, docs, classes etc) under a work area for the subproject.
So the output would be some thing like
c:/sandbox/mainprojectworkarea/subprojectworkarea/lib
c:/sandbox/mainprojectworkarea/subprojectworkarea/docs
c:/sandbox/mainprojectworkarea/subprojectworkarea/classes
Currently I do this as follows.
The toplevel build.xml is like below
<project name="toplevelproject" default="compile" basedir=".">
<target name="compile">
<ant dir="infrastructure_src/src" />
<ant dir="interfaces_src/src " /> <!--does not work-->
<ant dir="datamodel_src/src inhertAll=false" /> <!--works-->
</target>
</project>
common.xml is like below
<property environment="env" />
<property name="project.sandbox" value="${env.BUILD_HOME}/sandbox" />
<property name="sandbox" value="${project.sandbox}" />
<property name="pwa" value="${sandbox}/pwa" />
<property name="wa" value="${pwa}/${ant.project.name}" />
<property name="build" value="${wa}/build" />
<property name="lib" value="${wa}/lib" />
<property name="docs" value="${wa}/docs" />
<property name="exports" value="${wa}/exports" />
This is "included" into all projects. For example "datamodel_src/src/build.xml" is like below
<!DOCTYPE project [
<!ENTITY common SYSTEM "../../common.xml">
]>
<project name="dmodel" default="compile" basedir=".">
&common;
<target name="compile">
<echo message="will create lib in ${lib}"/>
<echo message="will create docs in ${docs}"/>
<ant dir="module1" inheritAll="false"/> <!--works fine-->
<ant dir="module2" /> <!--does not work -->
</target>
</project>
This works when I set inhertiAll=false for ant calls.
Is there a better and correct way to?
Expanding answer from Kevin to this question.
Using import the common.xml becomes a real project like below
<project name="toplevelproject" default="compile" basedir=".">
<property name="toplevel" value="settotrue"/>
<target name="compile">
<ant dir="infrastructure_src/src" />
<ant dir="interfaces_src/src" />
<ant dir="datamodel_src/src" />
</target>
</project>
The "datamodel_src/src/build.xml" is now some think like below.
<project name="dmodel" default="compile" basedir=".">
<import file="../../common.xml" />
<target name="compile">
<echo message="will create classes in ${build}"/>
<echo message="will create lib in ${lib}"/>
<ant dir="module1" inheritAll="false"/> <!--works fine-->
<ant dir="module2" /> <!--does not work -->
</target>
</project>
The import gives option to have common targets etc, hence I would go with it.
I'm doing something similar using imports rather than includes. All my common targets and properties are defined in a common build file and each subproject just imports the common file. When you import a file, the properties defined in that file become relative to the importing file.
So I would try doing the following:
Move your compile target from your subproject build files into your common.xml.
Import your common.xml into each subproject build.xml.

Testing Macrodef Attribute without IF

I am attempting to remove all lines that begin with log if a macrodef attribute is set to prod (example below). I plan on using replaceregexp to remove all lines beginning with log. However, I am not sure how to test if an attribute is set to a specific value, besides using the if task. I would like to not introduce any non-core Ant tasks to perform this, but I can't come up with any other solutions. Do I have any other options besides using the if-task?
Thanks
<macrodef name="setBuildstamp">
<attribute name="platform" />
<sequential>
<if>
<equals arg1="platform" arg2="prod" />
<then>
<replaceregexp match="^log\(.*" value="" />
</then>
</if>
</sequential>
</macrodef>
You should use a reference to a parameter, like this #{platform}.
Also, your replaceregexp task is missing a few parameters.
I think that in your particular case it is better to use linecontainsregexp filter reader. Here is modified code (note negate argument to linecontainsregexp).
<macrodef name="setBuildstamp">
<attribute name="platform" />
<sequential>
<if>
<equals arg1="#{platform}" arg2="prod" />
<then>
<copy todir="dest-dir">
<fileset dir="src-dir"/>
<filterchain>
<linecontainsregexp
regexp="^log\(.*"
negate="true"
/>
</filterchain>
</copy>
</then>
</if>
</sequential>
</macrodef>
They may be a couple of ways to solve this, but none are as straightforward as using the ant-contrib element. I'm not sure if this will get you what you need for your application, but you could try the following:
Using conditional targets. If you can replace your macrodef with a target to call, this may work for you. Note that this will set the property globally, so it might not work for your application.
<target name="default">
<condition property="platformIsProd">
<equals arg1="${platform}" arg2="prod" />
</condition>
<antcall target="do-buildstamp" />
</target>
<target name="do-buildstamp" if="platformIsProd">
<echo>doing prod stuff...</echo>
</target>
Handle the 'else' case. If you need to handle an alternate case, you'll need to provide a few targets...
<target name="default">
<property name="platform" value="prod" />
<antcall target="do-buildstamp" />
</target>
<target name="do-buildstamp">
<condition property="platformIsProd">
<equals arg1="${platform}" arg2="prod" />
</condition>
<antcall target="do-buildstamp-prod" />
<antcall target="do-buildstamp-other" />
</target>
<target name="do-buildstamp-prod" if="platformIsProd">
<echo>doing internal prod stuff...</echo>
</target>
<target name="do-buildstamp-other" unless="platformIsProd">
<echo>doing internal non-prod stuff...</echo>
</target>
Using an external build file. If you need to make multiple calls with different values for your property, you could isolate this in another build file within the same project. This creates a bit of a performance hit, but you would not need the additional library.
in build.xml:
<target name="default">
<ant antfile="buildstamp.xml" target="do-buildstamp" />
<ant antfile="buildstamp.xml" target="do-buildstamp">
<property name="platform" value="prod" />
</ant>
<ant antfile="buildstamp.xml" target="do-buildstamp">
<property name="platform" value="nonprod" />
</ant>
</target>
in buildstamp.xml:
<condition property="platformIsProd">
<equals arg1="${platform}" arg2="prod" />
</condition>
<target name="do-buildstamp">
<antcall target="do-buildstamp-prod" />
<antcall target="do-buildstamp-other" />
</target>
<target name="do-buildstamp-prod" if="platformIsProd">
<echo>doing external prod stuff...</echo>
</target>
<target name="do-buildstamp-other" unless="platformIsProd">
<echo>doing external non-prod stuff...</echo>
</target>
Add ant-contrib to your project. Of course, if you can add a file to your project, the easiest thing would be to just add the ant-contrib.jar file. You could put it under a "tools" folder and pull it in using a taskdef:
<taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${basedir}/tools/ant-contrib.jar" />
It looks like when you are building your project specifically for your Production environment - you are stripping out code you don't want to run in Production. Thus you are creating a different binary than what will run in your Dev or Testing environment.
How about using an environment variable or property file at run-time instead of build-time which determines whether or not logging happens? This way when you're having trouble in Production and you want to use the same exact binary (instead of determining the revision, checking out the code, rebuilding with a different environment flag) you just re-deploy it to your Dev or Test environment and turn on debugging in a properties file or environment variable?

Resources