Ant & how to parse a properties file to echo back the values - ant

I have a properties file that I want to echo out the values
<HSMKeys>
<Key domain="default" value="TestA" />
<Key domain="fixed" value="TestB" />
</HSMKeys>
as
[echo] domain=default value=TestA
[echo] domain=fixed value=TestB
How can I do this, ie loop over the properties file and have the two variables that would be in the echo.
I have tried the following
<for list="${HSMKeys.Key.domain}" param="domain">
<sequential>
<echo>domain=#{domain}</echo>
</sequential>
</for>
ie I can only get at one attribute value at a time, not both at once.
Thanks.

As #thekbb has stated this is not a properties file, however, ANT supports the parsing of XML files as properties.
<project name="demo" default="print">
<xmlproperty file="properties.xml"/>
<target name="print">
<echoproperties prefix="HSMKeys."/>
</target>
</project>
Produces the following output:
print:
[echoproperties] #Ant properties
[echoproperties] #Tue Dec 03 23:44:14 GMT 2013
[echoproperties] HSMKeys.Key=,
[echoproperties] HSMKeys.Key(domain)=default,fixed
[echoproperties] HSMKeys.Key(value)=TestA,TestB
May not be exactly what you need but has the advantage of not requiring additional jars like Ant-contrib.

That's not a properties file. Properties files are key/value pairs. How are you populating list?
a property file ant will understand will look like:
domain.default=TestA
domain.fixed=testB
I recommend avoiding ant-contrib at all costs... what are you really trying to do?
you could simply use echoproperties
<project name="test" default="echo" basedir=".">
<property file="build.properties" />
<target name="echo" >
<echoproperties prefix="domain."/>
</target>
</project>

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.

How to locate specific property in ANT if the xml property file provided to ant has repeating xml elements

I am trying to read a property file (xml) in ANT.
Following is the sample data.
<WebLogicDomain>
<Domain>MyDomain</Domain>
<Environment>DEV</Environment>
<Servers>
<Server id = '1'>
<Host>Host1</Host>
<Port>14100</Port>
<AliasName>adminserver</AliasName>
<IsAdmin>true</IsAdmin>
<AdminServerHost>adminHost</AdminServerHost>
<ClusterName>#NA</ClusterName>
<MinHeap>512MB</MinHeap>
<MaxHeap>2048MB</MaxHeap>
</Server>
<Server id = '2'>
<Host>Host2</Host>
<Port>14110</Port>
<AliasName>managedserver01</AliasName>
<IsAdmin>false</IsAdmin>
<AdminServerHost>adminHost</AdminServerHost>
<ClusterName>Cluster1</ClusterName>
<MinHeap>512MB</MinHeap>
<MaxHeap>2048MB</MaxHeap>
</Server>
</Servers>
</WebLogicDomain>
With this property file I can easily access Domain & Environment properties but How do I get specific Server Properties?
If I need to get ${WebLogicDomain.Servers.Server[1].Host} i.e Host present at index 1, how do I get that?
Follwoing doesn't work as expected.
<project name="SampleProject">
<xmlproperty file="buildproperties.xml" />
<target name="init">
<echo> ******** XML property file has been loaded. ******** </echo>
<echo> Domain name is : ${WebLogicDomain.Domain}</echo>
<echo> Environment is : ${WebLogicDomain.Environment}</echo>
<echo> First Server Details are : ${WebLogicDomain.Servers.Server[1].Host} </echo>
</target>
</project>
When I run the init target, I get following error.
init:
[echo] ******** XML property file has been loaded. ********
[echo] Domain name is : MyDomain
[echo] Environment is : DEV
[echo] First Server Details are : ${WebLogicDomain.Servers.Server[1].Host}
When Ant's xmlproperty task finds multiple elements with the same name in the same location, it saves them to a single property as a comma-delimited list. Try using the xmlproperty task to view all the properties that your build has loaded, along with corresponding nested elements. DOM information, unfortunately, is mostly lost. You can try to rely on the order in which the properties are listed, using regex to extract the relevant information, but this will almost certainly be awkward and unreliable.
<xmlproperty file="weblogic.xml" />
<echoproperties prefix="WebLogicDomain" />
Output:
[echoproperties] #Ant properties
[echoproperties] #Thu Feb 15 16:42:17 PST 2018
[echoproperties] WebLogicDomain.Domain=MyDomain
[echoproperties] WebLogicDomain.Environment=DEV
[echoproperties] WebLogicDomain.Servers.Server(id)=1,2
[echoproperties] WebLogicDomain.Servers.Server.AdminServerHost=adminHost,adminHost
[echoproperties] WebLogicDomain.Servers.Server.AliasName=adminserver,managedserver01
[echoproperties] WebLogicDomain.Servers.Server.ClusterName=\#NA,Cluster1
[echoproperties] WebLogicDomain.Servers.Server.Host=Host1,Host2
[echoproperties] WebLogicDomain.Servers.Server.IsAdmin=true,false
[echoproperties] WebLogicDomain.Servers.Server.MaxHeap=2048MB,2048MB
[echoproperties] WebLogicDomain.Servers.Server.MinHeap=512MB,512MB
[echoproperties] WebLogicDomain.Servers.Server.Port=14100,14110
If you really need to do XML parsing that is more complicated than basic string retrieval, there's a 3rd party plugin called XmlTask that can accomplish this. http://www.oopsconsultancy.com/software/xmltask/
<taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask">
<classpath location="lib/xmltask.jar"/>
</taskdef>
<target name="default">
<xmltask source="weblogic.xml">
<copy path="WebLogicDomain/Servers/Server[#id='1']/Host/text()" property="server.1.host"/>
</xmltask>
<echo message="${server.1.host}" />
</target>
Output:
[echo] Host1

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.

How to pass multiple parameters to a target in Ant?

I have this dummy target:
<mkdir dir="${project.stage}/release
<war destfile="${project.stage}/release/sigma.war">
...
...
</war>
What I want to do is provide two parameters say "abc" & "xyz" which will replace the word release with the values of abc and xyz parameters respectively.
For the first parameter say abc="test", the code above will create a test directory and put the war inside it.Similarly for xyz="production" it will create a folder production and put the war file inside it.
I tried this by using
<antcall target="create.war">
<param name="test" value="${test.param.name}"/>
<param name="production" value="${prod.param.name}"/>
</antcall>
in the target which depends on the dummy target provided above.
Is this the right way to do this.I guess there must be some way to pass multiple parameters and then loop through the parameters one at a time.
unfortunately ant doesn't support iteration like for or foreach loops unless you are refering to files. There is however the ant contrib tasks which solve most if not all of your iteration problems.
You will have to install the .jar first by following the instructions here : http://ant-contrib.sourceforge.net/#install
This should take about 10 seconds. After you can simply use the foreach task to iterate through you custom list. As an example you can follow the below build.xml file :
<project name="test" default="build">
<!--Needed for antcontrib-->
<taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
<target name="build">
<property name="test" value="value_1"/>
<property name="production" value="value_2"/>
<!--Iterate through every token and call target with parameter dir-->
<foreach list="${test},${production}" param="dir" target="create.war"/>
</target>
<target name="create.war">
<echo message="My path is : ${dir}"/>
</target>
</project>
Output :
build:
create.war:
[echo] My path is : value_1
create.war:
[echo] My path is : value_2
BUILD SUCCESSFUL
Total time: 0 seconds
I hope it helps :)
Second solution without using ant contrib. You could encapsulate all your logic into a macrodef and simply call it twice. In any case you would need to write the two parameters at some point in your build file. I don't think there is any way to iterate through properties without using external .jars or BSF languages.
<project name="test" default="build">
<!--Needed for antcontrib-->
<macrodef name="build.war">
<attribute name="dir"/>
<attribute name="target"/>
<sequential>
<antcall target="#{target}">
<param name="path" value="#{dir}"/>
</antcall>
</sequential>
</macrodef>
<target name="build">
<property name="test" value="value_1"/>
<property name="production" value="value_2"/>
<build.war dir="${test}" target="create.war"/>
<build.war dir="${production}" target="create.war"/>
</target>
<target name="create.war">
<echo message="My path is : ${path}"/>
</target>
</project>
I admit that I don't understand the question in detail. Is ${project.stage} the same as the xyz and abc parameters? And why are there two parameters xyz and abc mentioned, when only the word "release" should be replaced?
What I know is, that macrodef (docu) is something very versatile and that it might be of good use here:
<project name="Foo" default="create.wars">
<macrodef name="createwar">
<attribute name="stage" />
<sequential>
<echo message="mkdir dir=#{stage}/release " />
<echo message="war destfile=#{stage}/release/sigma.war" />
</sequential>
</macrodef>
<target name="create.wars">
<createwar stage="test" />
<createwar stage="production" />
</target>
</project>
The output will be:
create.wars:
[echo] mkdir dir=test/release
[echo] war destfile=test/release/sigma.war
[echo] mkdir dir=production/release
[echo] war destfile=production/release/sigma.war
Perhaps we can start from here and adapt this example as required.

overwriting ANT properties file

How can i overwrite some existing property with a newly created properties file?
Here is the required structure:
initially load Master.properties
generate new.properties
load new.properties and master.properties
run master.xml (ANT script)
The idea is that Master.properties generates some product version which should be replaced by new.properties. However, other properties in Master.properties should be kept the same.
Reading this does not help as i do not know how can i load the new.properties file
EDIT Here is ANT Script:
<project name="nightly_build" default="main" basedir="C:\Work\NightlyBuild">
<target name="init1">
<sequential>
<property file="C:/Work/NightlyBuild/master.properties"/>
<exec executable="C:/Work/Searchlatestversion.exe">
<arg line='"/SASE Lab Tools" "${Product_Tip}/RELEASE_"'/>
</exec>
<sleep seconds="10"/>
<property file="C:/Work/new.properties"/>
</sequential>
</target>
<target name="init" depends="init1">
<sequential>
<echo message="The product version is ${Product_Version}"/>
<exec executable="C:/Work/checksnapshot.exe">
<arg line='-NightlyBuild ${Product_Version}-AppsMerge' />
</exec>
<sleep seconds="10"/>
<property file="C:/Work/checksnapshot.properties"/>
<tstamp>
<format property="suffix" pattern="yyyy-MM-dd.HHmm"/>
</tstamp>
</sequential>
</target>
<target name="main" depends="init">
<echo message="loading properties files.." />
<echo message="Backing up folder" />
<move file="C:\NightlyBuild\NightlyBuild" tofile="C:\NightlyBuild\NightlyBuild.${suffix}" failonerror="false" />
<exec executable="C:/Work/sortfolder.exe">
<arg line="6" />
</exec>
<exec executable="C:/Work/NightlyBuild/antc.bat">
</exec>
</target>
</project>
in the above script, <exec executable="C:/Work/NightlyBuild/antc.bat"> will run Master.xml ANT script. This Master.xml will load up Master.properties:
<project name="Master ANT Build" default="main" >
<taskdef name="CFileEdit" classname="com.ANT_Tasks.CFileEdit"/>
<!-- ========================================================== -->
<!-- init: sets global properties -->
<!-- ========================================================== -->
<target name="init">
<property environment="env"/>
<!-- ========================================================== -->
<!-- Set the timestamp format -->
<!-- ========================================================== -->
<property file="Master.properties"/>
...
</project>
You should be able to resolve this by looking at the order in which you load (or otherwise specify) your property values. You probably don't need to override property values at all, which something not supported by core Ant.
Maybe you can split your Master.properties into two files - one loaded before you generate new.properties and one loaded after?
Maybe you don't need to generate new.properties at all.
Could you give some more detail on what you need to do?
Since you eventually fork a new Ant process (exec antc.bat), does that not start a fresh environment anyway? If it just loads Master.properties, those are the only properties it will have.
Not sure what your antc.bat does, but it's pretty unusual to exec Ant from Ant in this way. There are two standard tasks which might be useful - Ant and AntCall.
OK running on from your later comments...
Let's say that instead of doing this:
<exec executable="antc.bat">
you instead did something like this:
<ant file="Master.xml" inheritall="false">
<property name="Product_Version" value="${Product_Version}"/>
</ant>
I think that is getting towards what you want. You selectively pass specific values that you have obtained by loading new.properties. See the documentation for the Ant task.
If you still have the problem that you already defined Product_Version before loading new.properties, then I would say get the script you have that produces new.properties to output the version with a different name, e.g. New_Product_Version. Then invoke your master build something like this:
<ant file="Master.xml" inheritall="false">
<property name="Product_Version" value="${New_Product_Version}"/>
</ant>
May be this is a old question. Hopefully OP is reading this.
You can just use the ant task "propertyfile". reference
it can read properties from the file and write back updated values to them.

Resources