Macrodef and "local properties" - ant

I am trying to move a file (specified by a pattern) to a given location in an Ant macrodef:
<macrodef name="extract">
<attribute name="package"/>
<sequential>
<!-- the path will contain the unique file in extracted regardless of the name -->
<path id="source_refid">
<dirset dir="${dep}/lib/#{package}/extracted/">
<include name="#{package}-*"/>
</dirset>
</path>
<!-- this is not working: properties are immutable -->
<property name="source_name" refid="source_refid"/>
<move
file="${source_name}"
tofile="${dep}/#{package}/"
overwrite="true"
/>
</sequential>
</macrodef>
This will work just once as ${source_name} is immutable.
An option would be to use the variable task but I didn't find a way to assign a refid to a var.
Is there a way to have something similar to local variable in a macrodef? Or (XY problem) is there a better way to solve my problem?

Since Ant 1.8 you can use the local task for this. For example:
<local name="source_name"/>
<property name="source_name" refid="source_refid"/>
Your example is just the sort of thing local is for!

Related

Macrodef in Ant : passing a value outside the definition

I have the following macro definition in Ant and I would like to pass the "cmdStatus" value outside this macro def:
<macrodef name="execEtlBinScript">
<attribute name="script" />
<sequential>
<exec executable="#{script}" resultproperty="cmdStatus"/>
</sequential>
</macrodef>
Do you have any idea if it is possible or not ?
Thank you for any help.
Kind regards,
foxrafi
In your exemple, the property cmdStatus is set and is then available outside the macrodef. But I guess that your issue is that if your call several times your macro, you don't get the next status values as properties in Ant are immutable.
The way to handle it properly is to make the result property an attribute of the macro:
<macrodef name="execEtlBinScript">
<attribute name="script" />
<attribute name="resultproperty" />
<sequential>
<exec executable="#{script}" resultproperty="#{resultproperty}"/>
</sequential>
</macrodef>
Then each call to the macrodef will get its value via a different property:
<execEtlBinScript script="somescript" resultproperty="status1" />
<echo message="Result of the first call: ${status1}" />
<execEtlBinScript script="somescript" resultproperty="status2" />
<echo message="Result of the second call: ${status2}" />

How to identify if a file is copied from a particular archive?

I am new to ANT.
I have a very specific scenario to handle in this:
STEP-1: I need to look for the pattern of filenames in certain ear files. If the pattern matches then I need to extract those files.
STEP-2: And if any file is extracted from a certain ear (similar to zip-file) file, then I need to search for another set of files, and copy those set of files too.
The case to handle is "How to identify if a file is copied from a particular archive" if found then proceed to step 2, else move to next archive.
I have achieved STEP-1 but no idea how to achieve step-2.
STEP-1
<!-- Set via arguments passed -->
<patternset id="pattern.needtocopy" includes="${needtocopyfile.pattern}" excludes="${ignore.pattern}">
</patternset>
<target name="get-binaries-from-baseline">
<for param="binary">
<path>
<fileset dir="${baseline.dir}/target/aaa/bbb/ccc" includes="*.ear" />
</path>
<sequential>
<basename file="#{binary}" property="#{binary}.basename" />
<unzip src="#{binary}" dest="${baseline.dir}">
<patternset refid="pattern.needtocopy" />
<mapper type="flatten" />
</unzip>
</sequential>
</for>
</target>
STEP-2:
????
Need help in this.
Thanks.
Well I resolved the same, using a groovy script based on the resources I could find.
<target name="findJars">
<zipfileset id="found" src="${ear-name}">
<patternset refid="${patternsetref}" />
</zipfileset>
<groovy>
project.references.found.each {
println it.name
println project.properties.'ear-name'
println project.properties.'dest.dir'
}
</groovy>
</target>
And then I added another task which takes this filename and ear-file-name as input and extracts the related jars based on file to search pattern.

How to pass paramters by refrence in ant

Hi all this is my code for target calling.
<target name="abc">
<var name="x" value="10"/>
<antcall target="def"/>
<!--Again Access The value of x here and also change it here-->
</target>
<target name="def">
<!--Access The value of x here and also change it here-->
</target>
and also i want to access this X in other build file,is there any way
This is not possible with ant. In an properties are immutable and cannot be reset. The var task from ant contrib can be used to override values, but should be used sparingly.
You could use a temporary file to achieve what you want. But probably you are trying something weird, which can be solved in a different way.
This would also work across buildfiles if they have access to the property file.
<target name="abc">
<var name="x" value="10"/>
<antcall target="def"/>
<!--Again Access The value of x here and also change it here-->
<var unset="true" file="myproperty.properties" /> <!-- read variable from property file-->
</target>
<target name="def">
<echo file="myproperty.properties" append="false">x=12</echo> <!-- create a new propertyfile-->
</target>
For the sake of justice, there is a hack that allows to alter ant's immutable properties without any additional libs (since java 6):
<scriptdef name="propertyreset" language="javascript"
description="Allows to assing #{property} new value">
<attribute name="name"/>
<attribute name="value"/>
project.setProperty(attributes.get("name"), attributes.get("value"));
</scriptdef>
Usage:
<target name="abc">
<property name="x" value="10"/>
<antcall target="def"/>
</target>
<target name="def">
<propertyreset name="x" value="11"/>
</target>
As #oers mentioned, this should be used with care after all canonical approaches proved not to fit.
It is difficult to suggest further without knowing the goal behind the question.

How to to pass configurable file mapping lists to ant macros?

I'm trying to refactor an Ant buildfile with many similar targets into a buildfile that uses macros. This roughly is what it looks like:
<macrodef name="build-text">
<argument name="lang" />
<element name="file-list"/>
<sequential>
<property name="lang" value="#{lang}" />
<xslt style="my_stylesheet.xsl" destdir="build" basedir="src">
<!-- lots of params here -->
<file-list />
</xslt>
</sequential>
</macrodef>
<target name="buildTextDE">
<build-text lang="DE">
<file-list>
<mapper>
<mapper type="glob" from="Text1_${lang}.html" to="Text1_${lang}.fo"/>
<mapper type="glob" from="Text2_${lang}.html" to="Text2_${lang}.fo"/>
</mapper>
</file-list>
</build-text>
</target>
There is another task called buildTextEN that is nearly identical except for the lang attribute. In some cases, the file list differs however. Now how would I like to simplify the buildfile further by defining a "global" mapping list that contains the file lists for German and English, each file with the placeholder for the language. I would like to reference this global mapping where no special case is needed. How would I do that?

ant macrodefs and element naming

I have a macrodef with a an element called "libs"
<macrodef name="deploy-libs">
<element name="libs"/>
<sequential>
<copy todir="${glassfish.home}/glassfish/domains/domain1/lib">
<fileset dir="${lib}">
<libs/>
</fileset>
</copy>
</sequential>
</macrodef>
which is then invoked as
<deploy-libs>
<libs>
<include name="mysql-connector-*.jar"/>
<include name="junit-*.jar" />
<!-- .... -->
</libs>
</deploy-libs>
I then have another macrodef which calls several macrodefs including "deploy-libs". It would be nice if this macrodef had an element "libs" too but:
<macrodef name="init-glassfish">
<element name="libs"/>
<sequential>
<!-- other stuff -->
<deploy-libs>
<libs>
<libs/>
</libs>
</deploy-libs>
<!-- other stuff -->
</sequential>
</macrodef>
is obviously not working (because of <libs><libs/></libs>):
Commons/ant-glassfish-server.xml:116: unsupported element include
A solution could be to name the element in "init-glassfish" in a different way:
<macrodef name="init-glassfish">
<element name="libraries"/>
<sequential>
<!-- other stuff -->
<deploy-libs>
<libs>
<libraries/>
</libs>
</deploy-libs>
<!-- other stuff -->
</sequential>
</macrodef>
Is there a way to have the element to be named in the same way for both macrodefs?
I found a solution to my question which solves the original problem using a path id
<macrodef name="deploy-libs">
<attribute name="libraries-path-refid"/>
<sequential>
<copy todir="${glassfish.home}/glassfish/domains/domain1/lib">
<path refid="#{libraries-path-refid}"/>
</copy>
</sequential>
</macrodef>
Now this does not solve the issue with the nested elements tags but (XY problem) solves the practical issue. It would be still be nice to know if something similar to the original question is possible.
Apparently, the solution is wrapping additional <libs> elements around in the original call depending on how deep the macros nest. Of course this is a horrible solution because it requires that the macro nesting depth is known on invocation, e.g.:
<deploy-libs>
<libs>
<libs>
<include name="mysql-connector-*.jar"/>
<include name="junit-*.jar" />
<!-- .... -->
</libs>
</libs>
</deploy-libs>
Ant bug 29153 addressing this problem was unfortunately resolved as invalid :(.

Resources