How can I create a dynamic list of files in Ant, then save this list for later use in the build process? What I am thinking of is something like an immutable Fileset. Filelist won't work since it doesn't accept wildcards.
In other words, I want to create a list of files based on include/excludes wildcards that does not change once it's created. That is, even if more files are added later that pass the inclusion/exclusion rules -- I want to preserve the initial Fileset result (specifically for deletion later in the build process). Is this possible?
Well, here's what I came up with. Store fileset to property using pathconvert. Then iterate over files later in the build, doing whatever you need to with them. In my case, deleting them.
<macrodef name="storeBuildState">
<sequential>
<fileset dir="${build.dir}" id="current.fileset">
<include name="**/*.jar" />
</fileset>
<pathconvert pathsep="," property="current.fileset.prop" refid="current.fileset"/>
</sequential>
</macrodef>
<macrodef name="deleteStoredBuildState">
<sequential>
<for list="${current.fileset.prop}" param="file">
<sequential>
<delete file="#{file}" verbose="true" />
</sequential>
</for>
</sequential>
</macrodef>
Related
I am signing my jars using following ant commands.
<signjar alias="${alias}" keypass="${keypass}"
storepass="${storepass}"
keystore="${keystorefile}"
signedjar="${dist.dir}/${jar.signed.fileName}"
lazy="true">
<fileset dir="${dist.dir}">
<include name="*.jar" />
<include name="lib/*.jar" />
</fileset>
</signjar>
For single file it is fine that I can change the name of the jars file after signing it,
but when I have multiple jars the above line is not useful, what i am trying to accomplish is ,
for example
If the unsigned jar file name is ab.jar after signing it I want to prependSigned_to it's name likeSigned_ab.jar` and so on for all the jars i have in my fileset.
Can anyone tell me how to do that ?
You can use the ant jar command/task like below in your build script :
<jar basedir="bin" destfile="Signed_${jar-name}.jar">
btw, you missed to type the command you're using, in your question.
The signjar task can take a mapper defining how to translate the input file name into an output file name:
<signjar alias="${alias}" keypass="${keypass}"
storepass="${storepass}"
keystore="${keystorefile}"
destdir="${dist.dir}"
lazy="true">
<fileset dir="${dist.dir}">
<include name="*.jar" />
<include name="lib/*.jar" />
<!-- since we're dumping signed JARs in the same dir as the source
ones, we need to prevent already-signed JARs from being signed
again. A better approach might be to put the Signed_* JARs in
a different directory -->
<exclude name="**/Signed_*" />
</fileset>
<regexpmapper handledirsep="yes"
from="^(.*?)/([^/]*)$$" to="\1/Signed_\2" />
</signjar>
May be you can write couple of macros & call 'signJarsParallel' macro once for every directory for which you want to sign jars.
This is not tested code. You can give it a try. It makes use running tasks parallely & hence increasing speed & signs to temporary-prefixed name you want :
<macrodef name="signMyJars">
<element name="myJar" implicit="true"/>
<sequential>
<signjar alias="${alias}" keypass="${keypass}"
storepass="${storepass}"
keystore="${keystorefile}"
lazy="true">
<myJar/>
</signjar>
</sequential>
</macrodef>
Call only below macro inside your ant target.
<macrodef name="signJarsParallel">
<attribute name="dirName"/>
<sequential>
<for param="file" parallel="true" threadCount="5">
<path>
<fileset dir="#{dirName}">
<include name="*.jar"/>
<include name="lib/*.jar"/>
</fileset>
</path>
<signMyJars>
<fileset file="Signed_#{file}.jar"/>
</signMyJars>
</for>
</sequential>
</macrodef>
I'd like to define a list of variables in ant build file in order to use for loop with this list in my tasks. How can I do that?
p.s.: It should be something like the following:
<varlist name="mylist"> <!-- Actually, there is no such tag in Ant -->
<item>someThing</item>
<item>anotherThing</item>
</varlist>
...
<for param="item" list="${mylist}">
<sequential>
<echo>#{item}</echo>
</sequential>
</for>
<!-- "For" task is supported by Ant-Contrib Tasks
http://ant-contrib.sourceforge.net/tasks/tasks/index.html -->
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<pathelement location="ant-contrib-1.0b3.jar"/>
</classpath>
</taskdef>
<property name="someThing" value="Hello"/>
<property name="anotherThing" value="World!"/>
<target name="loop">
<for param="item" list="${someThing},${anotherThing}">
<sequential>
<echo>#{item}</echo>
</sequential>
</for>
</target>
Not sure if this is what you meant:
<echo message="The first five letters of the alphabet are:"/>
<for list="a,b,c,d,e" param="letter">
<sequential>
<echo>Letter #{letter}</echo>
</sequential>
</for>
Ant Addon Flaka has a very flexible for task. You may use your own property foobar=item1,item2,.. or any existing csv like property, f.e. some property provided by ant path/fileset/dirset like ${ant.refid:whatever} or ${toString:whatever} or the result of an EL function provided by Flaka like split() or list() .. or another list of objects/items to iterate over, see Flaka manual, Flaka examples for more details and examples.
I have a target which has several copy tasks; It basically copies the common jars to our set of applications from a centralized location to the lib folder of the application.
Seeing as this is a regular copy task a jar will be copied only if it is newer than the one currently in the lib folder.
This is the relevant part in the build.xml:
<target name="libs"/>
<copy file=... />
<copy file=... />
<copy file=... />
<antcall target="clean_compiled_classes"/>
</target>
<target name="clean_compiled_classes" if="anyOfTheLibsWereCopied">
<delete .../>
</target>
I'm looking for a way to set the anyOfTheLibsWereCopied property before the ant call in the libs target based on whether or not any of the files has been actually changed.
Thanks,
Ittai
I would advise having a look at the Uptodate task. I have never used it before but I guess what you are trying to do will be implemented along the following lines:
<target name="libs"/>
<uptodate property="isUpToDate">
<srcfiles dir="${source.dir}" includes="**/*.jar"/>
<globmapper from="${source.dir}/*.jar" to="${destination.dir}/*.jar"/>
</uptodate>
<!-- tasks below will only be executed if
there were libs that needed an update -->
<antcall target="copy_libs"/>
<antcall target="clean_compiled_classes"/>
</target>
<target name="copy_libs" unless="isUpToDate">
<copy file=... />
<copy file=... />
<copy file=... />
</target>
<target name="clean_compiled_classes" unless="isUpToDate">
<delete .../>
</target>
Your other option would be to implement your own ant task that does what you want. This would require a bit more work though.
I want to delete the directory if the property "delete-compiled-dir" is set to true. If the property is false then do not execute it. Right now I have
<target name="deleted-after-compilation" depends="compile,jar">
<condition property="${delete-compiled-dir}" value="true">
<delete dir="${compilation-dir}" />
</condition>
<echo> Deleting Compiled Directory Classes </echo>
</target>
I get the error message :
condition doesn't support the nested "delete" element.
You can add the condition to your target using if (see manual).
The target will only be executed when the property compilation-dir is set (to any value, e.g. false).
<target name="deleted-after-compilation" depends="compile,jar"
if="${compilation-dir}">
<delete dir="${compilation-dir}" />
<echo> Deleting Compiled Directory Classes </echo>
</target>
To only execute it when a property is set to true, you need to set another property first and check this one in the if. You could add both as dependency the another target:
<target name="set-delete-property">
<condition property="delete-compilation-dir">
<istrue value="${compilation-dir}"/>
</condition>
</target>
<target name="deleted-after-compilation"
depends="compile,jar" if="${compilation-dir}">
....
<target name="some-target"
depends="set-delete-property,deleted-after-compilation">
</target>
There are a few ways to do this:
Use conditions on the target entity
Targets can contain if and unless conditions. The target will execute depending whether or not the property is set. (Not set to true, just set). This is a common way to see if you need to do something or not:
<target name="deleted.after.compilation"
if="delete.compiled.dir"
depends="jar">
<delete dir="${compilation-dir}" />
<echo> Deleting Compiled Directory Classes </echo>
</target>
You can set the property on the command line:
$ ant -Ddelete.compiled.dir all
Note: I use periods as separators for the names of properties and targets. Also note that I only depend upon the target jar since jar is also dependent upon compile, there's no need to have them both.
Use Ant's 1.9.1 conditional clauses
As of Ant 1.9.1, Ant has conditional attributes that can be added to tasks. You need to add a Namepsace declaration in your <project> entity:
<project ...
xmlns:if="ant:if"
xmlns:unless="ant:unless">
<target name="deleted.after.compilation"
depends="jar">
<delete dir="${compilation-dir}" if:true="${delete.compiled.dir}"/>
<echo if:true="${delete.compiled.dir}"> Deleting Compiled Directory Classes </echo>
</target>
Use Ant-Contrib's If Statement
Ha ha, that wacky Ant-Contrib library. No one knows who maintains it, and it hasn't been touched in years, but many people depend so heavily on it.
<project ...>
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<fileset dir="${ivy.dir}/antcontrib">
<include name="ant-contrib*.jar"/>
</fileset>
</classpath>
</taskdef>
<target name="deleted.after.compilation"
depends="jar">
<if>
<istrue value="${delete.compiled.dir}"/>
<then>
<delete dir="${compilation-dir}"/>
<echo>Deleting Compiled Directory Classes </echo>
</then?
</if>
</target>
You can see why Ant-Contrib is popular. It contains a lot of power, and we all know it. Plus, if someone is still using Ant 1.8 or 1.7, this will still work.
if you have get the property ,you can just use it in a target.
<target name="delete" if="${delete-compiled-dir}">
<delete dir="${compilation-dir}" />
</target>
As of Ant 1.9.1, you can use conditionals on any task. Described here.
Add this namespace to your project element:
<project name="yourproject" xmlns:if="ant:if">
Then add this to your delete:
<delete dir="${compilation-dir}" if:true="${delete-compiled-dir}"/>
I need to write an Ant target that appends together (comma-delimited) a list of '.jar' file names from a folder into a variable, which is later used as input to an outside utility.
I am running into barriers of scope and immutability. I have access to ant-contrib, but unfortunately the version I am stuck with does not have access to the 'for' task. Here's what I have so far:
<target name="getPrependJars">
<var name="prependJars" value="" />
<foreach param="file" target="appendJarPath">
<path>
<fileset dir="${project.name}/hotfixes">
<include name="*.jar"/>
</fileset>
</path>
</foreach>
<echo message="result ${prependJars}" />
</target>
<target name="appendJarPath">
<if>
<equals arg1="${prependJars}" arg2="" />
<then>
<var name="prependJars" value="-prependJars ${file}" />
</then>
<else>
<var name="prependJars" value="${prependJars},${file}" />
</else>
</if>
</target>
It seems that 'appendJarPath' only modifies 'prependJars' within its own scope. As a test, I tried using 'antcallback' which works for a single target call, but does not help me very much with my list of files.
I realize that I am working somewhat against the grain, and lexical scope is desirable in the vast majority of instances, but i really would like to get this working one way or another. Does anybody have any creative ideas to solve this problem?
You might be able to use the pathconvert task, which allows you to specify the separator character as comma.
<target name="getPrependJars">
<fileset id="appendJars" dir="${project.name}/hotfixes">
<include name="*.jar" />
</fileset>
<pathconvert property="prependJars" refid="appendJars" pathsep="," />
<echo message="prependJars: ${prependJars}" />
</target>
I'd simply write a custom task in Java that (1) takes the folder name, (2) assembles the result string and (3) stores it to the ${prependJars} property.
In ant you just define the task (taskdef) and use like all other tasks afterwards.
I did it once when I was faced with a simliar problem and found that it was very, very easy.
Here's the tutorial.
If a system path format is useful to you, you can use the following:
<target name="getPrependJars">
<path id="prepend.jars.path">
<fileset dir="${project.name}/hotfixes">
<include name="*.jar"/>
</fileset>
</path>
<property name="prependJars" value="${toString:prepend.jars.path}" />
<echo message="result ${prependJars}" />
</target>