Can Ant expand environment variables from a properties file? - ant

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.

Related

Jenkins ant plugin has wrong value for ${user.dir} working directory

I have the following build file in C:\A\B
<project name="demo" default="printCWD">
<target name="printCWD">
<echo message="user.dir=${user.dir}"/>
</target>
</project>
and run this command whilst in C:\A
ant -buildfile B\build.xml
it prints "C:\A"
But from the Ant plug-in installed on a Jenkins CI machine, which has the Buildfile setting set to "B/build.xml", it prints "/workspace/B"
Why is it on my local machine it prints the folder from which I invoked the ant command, yet on the Jenkins CI server it prints the folder that the buildfile is in?
Many thanks for any help.
Paul
It's because the Jenkins Ant plugin is changing the working directory to the directory containing the buildfile just before executing it, therefore causing user.dir to point to that directory (/workspace/B).
A look at the source code of the Ant plugin at https://github.com/jenkinsci/ant-plugin/blob/master/src/main/java/hudson/tasks/Ant.java reveals that the working directory is changed to the parent of the build file, specifically in this line (note the call to pwd(buildFilePath.getParent()):
r = launcher.launch().cmds(args).envs(env).stdout(aca).pwd(buildFilePath.getParent()).join();
Given this difference in behavior between locally and on Jenkins, I wouldn't personally rely on the user.dir property. If you want to access the current workspace of the Jenkins job, you can use the built-in environment variables provided by Jenkins:
<property environment="env"/>
<target name="printCWD">
<echo message="workspace=${env.WORKSPACE}"/>
</target>
If you don't want to explicitly reference the WORKSPACE env variable in the buildfile, you can provide a custom property to pass it from outside (with the default value set to user.dir):
<property name="root.dir" value="${user.dir}" /> <!-- default value -->
<target name="printCWD">
<echo message="root.dir=${root.dir}"/>
</target>
Then pass -Droot.dir=${WORKSPACE} in the Jenkins job.

Force Ant to substitue a substitution variable

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.

Replacing property dynamically based on environments in Ant scripts

I want to develop ant script which replaces application properties with environment specific properties. My requirement is that I will have all environment properties in single env.properties file. During building the application I need to replace with whatever in env.properties file. Ant replace works well when I have property files for each environment.
Sample : env.properties
dev.AddNETWORK_USER=devUser
dev.ADDPASS=devPass
sit.AddNETWORK_USER=situser
sit.ADDPASS=sitPass
This needs be replaced in mule.properties as
for DEV environment:
dev.AddNETWORK_USER=devUser
dev.ADDPASS=devPass
for SIT environment:
AddNETWORK_USER=sitUser
ADDPASS=sitPass
You can use property ant task on your env.properties file. This allows to access key=value pair based on your need. You can redirect your environment specific properties to file you want or write to one specific file.
<property file="${base.dir}/env.properties"/>
<for list="dev,sit" param="value">
<sequential>
<echo message="#{value}.AddNETWORK_USER=${#{value}.AddNETWORK_USER}" append="true" file="${base.dir}/#{value}Any-File.prop"/>
<echo message="${line.separator}" append="true" file="${para.home}/#{value}Any-File.prop"/>
<echo message="#{value}.ADDPASS=${#{value}.ADDPASS}" append="true" file="${para.home}/#{value}Any-File.prop"/>
</sequential>
</for>

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>

Ant, set environmental variable for <ant> task?

I want to run another ant build file from ant, and the <ant> task looks perfect for this.
The other build file uses environmental variables for a couple things. Is there a way to set environmental variables for the child ant process?
I see that the <exec> task seems to support nested <env>s, but nothing similar for <ant>.
From the documentation of ant task,
By default, all of the properties of the current project will be available
in the new project.
You can also set properties in the new project from the old project by using
nested property tags.
<ant antfile="subproject/property_based_subbuild.xml">
<property environment="env"/>
</ant>
by default the inner ant call inherits the parent properties
<ant inheritAll="true" antfile="subproject/subbuild.xml">
<!--inheritAll="true" is default value, this is unecessary -->
<property name="myprop" value="foo"/>
<antcall target="myTarget"></antcall>
<ant antfile="myAntFile"></ant>
</ant>
In this case, "myTarget" and all targets on "myAntFile" can get "foo" as "myprop" value.

Resources