Force Ant to substitue a substitution variable - ant

I use a software (Drops) based on ant script.
I try to dynamically generate the destination path of a file that I want to copy. To do this I execute a linux command line.
In my application, I have this properties :
environment.props.environment_name=recette
application.props.target.gmao=/opt/${environment.props.environment_name}/gmao-ws
I expected Ant to replace ${environment.props.environment_name} by its value at runtime. But it doesn't.
Here is the Ant script that I wrote :
<project xmlns:drops="antlib:com.arcadsoftware.mmk.anttasks" name="deployJar" basedir="." default="main">
<taskdef resource="net/sf/antcontrib/antlib.xml"/>
<taskdef resource="com/dropssoftware/drops/ant/antlib.xml"/>
<loadDropsContext/>
<target name="main">
<!-- get the value of the property "application.props.target.gmao" -->
<propertycopy name="target.dir" from="application.props.target.gmao"/>
<!-- I expect this to print target.dir=/opt/recette/gmao-ws but it print target.dir=/opt/${environment.props.environment_name}/gmao-ws -->
<echoproperties />
<!-- Supposed to copy from /opt/drops/storage/afile.jar to /opt/recette/gmao-ws but the property "target.dir" is wrong -->
<exec executable="sudo">
<arg value="/bin/cp"/>
<arg value="${param.artifacts.root}/${param.jar.root}"/>
<arg value="${target.dir}"/>
</exec>
</target>
</project>
With this input :
param.env=gmao
param.artifacts.root=/opt/drops/storage/
It is supposed to copy a file from the artifacts directory to the /opt/recette/gmao-ws directory. But Ant tried to copy it to /opt/${environment.props.environment_name}/gmao-ws.
I don't understand why Ant doesn't replace ${environment.props.environment_name} by its value.
Is it possible to force Ant to replace the substitution variable by its value ?

Not entirely clear what you're trying to do. The propertycopy task is not part of normal Ant, coming from a 3rd party extension called ant-contrib
I suspect what you're trying to do can be done with normal property substitution. I have provided an example.
Example
A simple example of how to pass in parameters to a build file by setting properties:
$ ant -Dparam.from=AAA -Dparam.to=BBB
build:
[echo]
[echo] sudo
[echo] /bin/cp
[echo] /opt/drops/storage/AAA
[echo] /opt/drops/storage/BBB
[echo]
build.xml
Note the 3 properties declared at the top? These are effectively the default values available for override.
<project name="demo" default="build">
<property name="param.artifacts.root" value="/opt/drops/storage"/>
<property name="param.from" value="fromDir"/>
<property name="param.to" value="toDir"/>
<target name="build">
<echo>
sudo
/bin/cp
${param.artifacts.root}/${param.from}
${param.artifacts.root}/${param.to}
</echo>
</target>
</project>

I think that I find the answer to my question in ant document :
https://ant.apache.org/manual/properties.html
Normally property values can not be changed, once a property is set, most tasks will not allow its value to be modified.
In the case of the software that I use : Drops, it loaded the application properties BEFORE the environment properties.
So application.props.target.gmao is set BEFORE environment.props.environment_name and the ${environment.props.environment_name} cannot be replace.
The answer to my question is seems to be NO, it's not possible to force Ant to replace the substitution variable by its value.
It's done automatically if the variables are loaded in the good order.

Related

Checksum task in Ant not working as expected

I am struggling with a small ant file/target that is as follows:
<project name="test" default="test" basedir=".">
<property name="out.dir" value="${basedir}/out/"/>
<property name="apidoc.path" value="${out.dir}test.zip"/>
<property name="apidoc.input" value="${basedir}/../source//apidocs"/>
<property name="apidoc.sha" value="TODO"/>
<target name="test">
<echo message="Starting target APIDOC"/>
<zip destfile="${apidoc.path}" basedir="${apidoc.input}" update="no"/>
<echo message="${apidoc.path}"/>
<checksum file="${apidoc.path}" algorithm="SHA-256" property="apidoc.sha"/>
<echo message="Hash wert ist ${apidoc.sha}"/>
</target>
</project>
The target should create a zip file from a doc folder (it does) and then store the hash value of the zip file into a property for further use. However, the hash value is not stored in the property. I get the output as follow:
test:
[echo] Starting target APIDOC
[echo] /Users/user1/git/project/out/test.zip
[echo] Hash wert ist TODO
BUILD SUCCESSFUL
Does anybody have and idea, what is going wrong here?
Properties in Ant are immutable. This line
<property name="apidoc.sha" value="TODO"/>
sets the value, and after that it can't be changed.
If you run ant with the -v command-line option you should see a message like
Override ignored for property "apidoc.sha"
indicating that the attempt to alter the property value in the <checksum> task is being ignored.

Ant -propertyfile resolve from cmd

I am trying to create property file for a project.
the project can use different DB (Oracle or Mssql , but not both)
Beacuse of that i have made 3 property files:
common.properties
mssql.properties
oracle.properties
i want to use the ant properties hierarchy feature in order to set some of this properties.
for example,i can define at,common.properties :
db.hostname= localhost
db.port= 1433
then on mssql\oracle.proprties file i can build
db.connectionString= jdbc:sqlserver://${db.hostname}:${db.port}
on my build.xml
I have wrote :
<property file="common.properties"/>
In order to set concrete DB i have wrote on CMD :
Ant-1.8.4\bin\ant -propertyfile mssql.properties
The problem is that ant doesn't use the references i have defined at the common.properties
int order to resolve:
db.connectionString
How can i solve this issue using cmd?
The problem is the order in which the properties are created. The file "mssql.properties" gets loaded first before executing the ANT script. This explains why the property "db.connectionString" is assigned the strings "${db.hostname}" and "${db.port}" because these properties have no value. Their value gets set when the script runs and loads the second property file.
Alternative approach is to use a property to indicate the db type.
Example
├── build.xml
├── common.properties
└── mssql.properties
Run as follows
$ ant -Ddb=mssql
Buildfile: /home/mark/tmp/build.xml
echo:
[echo] db.connectionString=jdbc:sqlserver://localhost:1433
build.xml
<project name="demo" default="echo">
<property file="common.properties"/>
<property file="${db}.properties"/>
<target name="echo">
<echo message="db.connectionString=${db.connectionString}"/>
</target>
</project>
For extra credit
This approach also enables error checking, in case the correct db type is not specified:
<project name="demo" default="echo">
<property file="common.properties"/>
<property file="${db}.properties"/>
<available property="db.prop.file" file="${db.properties}"/>
<target name="echo">
<fail message="Missing a property file for a ${db} database" unless="db.prop.file"/>
<echo message="db.connectionString=${db.connectionString}"/>
</target>
</project>

Change baseDir attribute while using import tag

Let me first provide the background of the problem I'm facing.
I have a directory structure as below.
c:\myDirectory
c:\myDirectory\Project1
c:\myDirectory\Scripts
Under the c:\myDirectory\Scripts there is a script that download the source code (from svn) and creates the c:\myDirectory\Project1 directory.
I have another ant scripts ( c:\myDirectory\Scripts**compile-source.xml ) that compiles the Project1
from an ant script build.xml that is downloaded to c:\myDirectory\Project1
Snippet for c:\myDirectory\Scripts\compile-source.xml
<project name="compile" default="buildAll" basedir=".">
<property file=".\build.properties">
</property>
.......
<import file="${project.home.path}/${project.name}/build.xml"/>
<target name="buildAll">
<antcall target="jar-pack"/>
</target>
</project>
Snippet for c:\myDirectory\Project1\build.xml.
<project name="CommonFeatures" default="jar-pack" basedir=".">
<description>
A build file for the Common Features project
</description>
....
</project>
Note that the basedir for the project is set as "." for both the above ant scripts.
When I execute the script c:\myDirectory\Scripts\compile-source.xml from the c:\myDirectory\Scripts directory the target "jar-pack" present in the c:\myDirectory\Project1\build.xml gets executed.
However, the problem is that basedir attribude in build.xml ( basedir="." ) is the current working directory and in this case its c:\myDirectory\Scripts. Hence the script build.xml errors out since the basedir for build.xml is expected to be c:\myDirectory\Project1. The build.xml script would have worked, if basedir="." were set to "c:\myDirectory\Project1", but unfortunately build.xml file comes from the source code that is downloaded and I'm unable to edit.
So here's my question, Is it possible to do any of the following.
Override the value of the attribude basedir="." in build.xml when the is done in c:\myDirectory\Scripts\compile-source.xml ?
Is it possible to change the basedir in build.xml by any other mechanism so that the script c:\myDirectory\Project1\build.xml is executed under directory c:\myDirectory\Project1 ?
Any other way to resolve this issue?
Any help from Ant experts to overcome this issue is highly appreciated.
You can update basedir using subant task. Check this answer
Create the following build.xml file (assuming it is in Z:/any/folder):
<?xml version="1.0" encoding="UTF-8"?>
<project name="project">
<target name="mytarget">
<subant target="debug">
<property name="basedir" value="X:/any/dir/with/project"/>
<fileset dir="Y:/any/folder/with" includes="build.xml"/>
</subant>
</target>
</project>
The you can execute ant mytarget from Z:/any/folder
You can specifically reference the location of your build file, which is described in this stack overflow thread. This would allow you to get and use the directory your build file resides in as a reference point.
For your case the usage of the subant or ant tasks may be better suited, but nevertheless...
You can (but you should know/consider the side-effects!) extend ant with the common ant-contrib task definitions and use the var task which is able to override properties. Make sure to use the latest version (> 1.0b3).
<!-- adjust to your path and include it somewhere at the beginning of your project file -->
<taskdef resource="net/sf/antcontrib/antlib.xml" classpath="lib/ant-contrib-1.0b3.jar" />
<!-- works e.g. for basedir = /foo/bar to update it to /foo/bar/.. ~ /foo -->
<var name="basedir" value="${basedir}/.." />
update: but one has to be careful, because this does not change . (current working directory) (so <property name="x" location="tmp" /> would be relative to . and not to basedir anymore ; update: setting basedir outside of ant or via <project basedir= also sets . to basedir!). Here is some test target proving the effect on both:
<target name="tst.dummy.basedir-override">
<!-- example output:
tst.dummy.basedir-override:
[echo] basedir before: basedir=D:\tst, '.'=D:\tst\.
[echo] updating it via 'var' to '..'
[echo] basedir now: basedir=D:\tst/.., '.'=D:\tst\.
-->
<property name="cur" location="." /> <!-- makes the relative path absolute -->
<echo message="basedir before: basedir=${basedir}, '.'=${cur}" />
<echo message="updating it via 'var' to '..'" />
<var name="basedir" value="${basedir}/.." />
<property name="cur2" location="." /> <!-- makes the relative path absolute -->
<echo message="basedir now: basedir=${basedir}, '.'=${cur2}" />
</target>

How to create a Java file dynamically into certain package using Ant concat task?

I have an Ant script file in which I use concat task to create a Java cource file in the specified package which is defined in a properties file.
For example, I define the package name:
ma.package=com.my.package
In Ant script, I call:
<concat destfile="./${prject.root}/${ma.package}/MyClass.java">
However, MyClass.java was created in a subfolder com.my.package, instead of folder structure com\my\package. How to fix it?
I use Eclipse Helios under Windows XP.
You can use a PathConvert with a nested UnpackageMapper to convert the package name to a path. For example:
<project default="test">
<property name="ma.package" value="com.my.package"/>
<target name="test">
<pathconvert property="ma.package.dir">
<path path="${ma.package}"/>
<unpackagemapper from="*" to="*"/>
</pathconvert>
<echo message="ma.package : ${ma.package}"/>
<echo message="ma.package.dir : ${ma.package.dir}"/>
</target>
</project>
The output is:
Buildfile: C:\tmp\ant\build.xml
test:
[echo] ma.package : com.my.package
[echo] ma.package.dir : C:\tmp\ant\com\my\package
So you could use the converted property value in your concat:
<concat destfile="${ma.package.dir}/MyClass.java">

Can Ant expand environment variables from a properties file?

I have a question regarding Ant and its treatment of environment variables.
To illustrate I have a small sample.
Given the Ant build file test.xml:
<project name="myproj" default="testProps">
<property environment="env"/>
<target name="testProps">
<echo message="${env.MyEnvVar}"/>
<echo message="${MY_PROPERTY}"/>
</target>
</project>
And the properties file test.props:
MY_PROPERTY=${env.MyEnvVar}
Now set the environment variable MyEnvVar to some value (foo in my case) and run Ant using this command line:
ant -f test.xml -propertyfile test.props testProps
The output I get is:
[echo] foo
[echo] ${env.MyEnvVar}
What I would like to know is whether there is any way to structure the input properties file such that I get
[echo] foo
[echo] foo
That is, I would like to name an environment variable in the properties file which is replaced within the Ant script. Note - I know how to access environment variables directly (as is done here). What I need to do is make use of a set of Ant scripts that expect one collection of properties in an environment that defines the same properties using different names. Thus the thought of "bridging" them in a properties file.
I am using Ant version 1.6.5.
You need to read the test.props property file after the environment - you could do so using another property task, i.e. add
<property file="test.props" />
after your existing property environment task.
In full:
<property environment="env" />
<property file="test.props" />
<target name="testProps">
<echo message="${env.MyEnvVar}"/>
<echo message="${MY_PROPERTY}"/>
</target>
When you supply the properties file on the command line this gets processed before the content of the build, but at that time ${env.MyEnvVar} is not yet set.

Resources