Include a File If a Condition Is Met Inside Apache Ant fileset - java

Is there a way to include or exclude certain files based on a condition in Apache Ant (1.8.3)? For instance, I have a macrodef that takes an attribute. I would like to include certain files if the attribute's value matches xyz:
<macrodef name="pkgmacro">
<attribute name="myattr" />
<sequential>
<zip destfile="${dist}/#{myattr}.war">
<fileset dir="${dist}/webapp" >
<include name="**/#{myattr}/**" />
<exclude name="WEB-INF/config/**" />
<!-- if #{myattr} = "xyz", then
<include name="PATH/TO/file.xml" />
-->
</fileset>
<zipfileset dir="${ear}/#{myattr}/WEB-INF/" includes="*.xml" prefix="WEB-INF/" />
</zip>
</sequential>
</macrodef>
For instance, if myattr value is xyz, I would like to include the commented file in portion above.

Fileset can use nested include/exlucde patternsets with if/unless
Attribute. The pattern is included/excluded when a named property is set or not, so no ant addons needed.Some snippet :
<project>
<!-- property that triggers your include/exclude
maybe set via condition in some other target .. -->
<property name="foo" value="bar"/>
<macrodef name="pkgmacro">
<attribute name="myattr" />
<sequential>
<fileset dir="C:/whatever" id="foobar">
<!-- alternatively
<include name="*.bat" unless="#{myattr}"/>
-->
<include name="*.bat" if="#{myattr}"/>
</fileset>
<!-- print fileset contents -->
<echo>${toString:foobar}</echo>
</sequential>
</macrodef>
<pkgmacro myattr="foo"/>
</project>
--EDIT after comment --
The if/unless attribute after include name/exclude name checks whether the given value is a property which is set (when using if="..") or not set (when using unless="..") in the ant project scope - it doesn't check for a specific value.
<include name="*.xml" unless="foo"/>
means include is only active if no property named foo is set in your project
<include name="*.xml" if="foo"/>
means include is only active if property named foo is set in your project
Works fine for me , used Ant 1.7.1, had no Ant 1.8.x around right now :
<project>
<echo>$${ant.version} => ${ant.version}</echo>
<macrodef name="pkgmacro">
<attribute name="myattr"/>
<sequential>
<condition property="pass">
<equals arg1="#{myattr}" arg2="xyz" />
</condition>
<fileset dir="C:/whatever" id="foobar">
<include name="*.bat" if="pass" />
</fileset>
<echo>${toString:foobar}</echo>
</sequential>
</macrodef>
<pkgmacro myattr="xyz"/>
</project>
output :
[echo] ${ant.version} => Apache Ant version 1.7.1 compiled on June 27 2008
[echo] switchant.bat;foobar.bat;foo.bat
-- EDIT after comment --
Using serveral include patterns works fine :
...
<fileset dir="C:/whatever" id="foobar">
<include name="*.xml" if="pass" />
<include name="*.bat" if="pass"/>
<include name="**/*.txt" if="pass"/>
</fileset>
...
maybe you're using the wrong patterns ?
-- EDIT after comment --
Here is the reference to <local> task which is needed to work with the properties in the current scope, in this case, <sequential>:
<macrodef name="pkgmacro">
<attribute name="myattr"/>
<sequential>
<!-- make property pass mutable -->
<local name="pass"/>
<condition property="pass">
<equals arg1="#{myattr}" arg2="xyz" />
</condition>
<fileset dir="C:/whatever" id="foobar">
<include name="*.xml" if="pass" />
<include name="*.bat" if="pass" />
<include name="**/*.txt" if="pass" />
</fileset>
<!-- print value of property pass and fileset contents -->
<echo>$${pass} = ${pass}${line.separator}${toString:foobar}</echo>
</sequential>
</macrodef>

if you can use ant-contrib, then try this:
<contrib:if>
<equals arg1="${myattr}" arg2="xyz" />
<then>
<include name="PATH/TO/file.xml" />
</then>
</contrib:if>
if you can't use ant-contrib, try this:
http://jaysonlorenzen.wordpress.com/2010/03/10/apache-ant-if-else-condition-without-ant-contrib/

Related

Java ant help, differing fileset to be used for different targets

I'm new to Ant, so I'm looking for ideas here.
I'm looking for a way to use a different fileset per ANT target, and I'm not finding any luck reading the ANT documentation. To be concrete, here is what I have:
<fileset id="MY-FILESET-ONE" dir="..." />
<include name="**/*.java />
</fileset>
<fileset id="MY-FILESET-TWO" dir="..." />
<include name="**/*.other />
</fileset>
<target name="BASETARGET" depends="...">
<fileset refid="MY-FILESET-ONE" />
</target>
<target name="ANT-TARGET-ONE" depends="BASETARGET">
<fileset refid="MY-FILESET-ONE" />
</target>
<target name="ANT-TARGET-TWO" depends="BASETARGET" />
<fileset refid="MY-FILESET-TWO" />
</target>
What I want to do is have the fileset that the target BASETARGET uses be different depending on which target is invoked. If ANT-TARGET-ONE is invoked, use a different fileset, than if ANT-TARGET-TWO is invoked.
Here's something like I envision:
<target name="BASETARGET" depend="...">
<fileset refid="${myvar} />
</target>
<target name="ANT-TARGET-ONE" depends="BASETARGET">
<var name="myvar" value="MY-FILESET-ONE" />
</target>
<target name="ANT-TARGET-TWO">
<var name="myvar" value="MY-FILESET-ONE" />
</target>
How can I achieve this using ant? Basically I want to control which sets of my unit-tests get run depending on the target being invoked? I know properties can only be set once, so I don't think that could possibly work. I looked at the var here: http://ant-contrib.sourceforge.net/tasks/tasks/variable_task.html
however, trying to get the value out of 'myvar' like this:
<fileset refid="${myvar} />
results in a error, I'm unsure how to achieve this!
"What I want to do is have the fileset that the target BASETARGET uses be different depending on which target is invoked."
Here's a small example for that: you simply create the filesets with a given ID and refer them in your base target.
<project name="test" basedir=".">
<target name="base">
<copy todir="out">
<fileset refid="files-to-copy"/>
</copy>
</target>
<target name="def-fs-1" >
<fileset id="files-to-copy" dir="in">
<include name="a.txt" />
</fileset>
</target>
<target name="def-fs-2" >
<fileset id="files-to-copy" dir="in">
<include name="b.txt" />
</fileset>
</target>
<target name="t1" depends="def-fs-1,base" />
<target name="t2" depends="def-fs-2,base" />
</project>

Ant does not support for loop inside batchtest element

I want to define in command line what unit tests are to be run. Tests are defined in a logical structure based on Java packages. From the command line I want to define what Java packages are to be included in the test run (i.e. what tests to include).
In this way I want to loop through a tokenized list of path values, and include Java tests from these paths. However the batchtest element does not support nested for loops. How can I modify this to do what I want? So the amount of includes are as many as there are defined path values.
Updated:
I have defined target like this:
<target name="test">
<property name="path" value="**"/>
<junit fork="yes" failureproperty="true" forkmode="once">
<formatter type="xml" />
<classpath>
<pathelement path="bin.path"/>
</classpath>
<batchtest haltonerror="false" todir="${test.dir}">
<fileset dir="/src/test/">
<for list="${path}" param="path">
<sequential>
<var name="path" value="#{path}"/>
<include name="**/${path}/**/*.java" />
</sequential>
</for>
</fileset>
</batchtest>
</junit>
You could use reguler expression.
For example;
<batchtest haltonfailure="yes" todir="/test">
<fileset dir="/build/classes/"
includes="**/TestBlaBla.class" excludes="**/BlaBla.class" />
</batchtest>
I hope it helps to you.

How do I sign a dozen JAR files with jarsigner?

I want to sign two dozen jar files using jarsigner, giving the password only once.
Giving multiple files to jarsigner is not possible, according to the man page and using a for-loop on the command line still forces me to input the password for every file.
I would prefer a solution for the command line, but would be okay with ant/maven solution.
System is Linux.
How do I sign a dozen jar-files, giving the password only once?
Here is a snippet from the Ant build file for PSCode - it signs a slew of Jars. The trick is in the foreach element.
<target name="createjars"
depends="compile"
description="Jars the compiled classes">
<mkdir dir="${build}/jar/" />
<foreach target="jar.package" param="package" inheritall="true">
<path>
<dirset dir="${src}/java/org/pscode" includes="**/*" />
</path>
</foreach>
</target>
..and..
<target name='jar.package'>
<script language='javascript'>
<![CDATA[
prop = pscode.getProperty('package');
index1 = prop.lastIndexOf('pscode') + 7;
index2 = prop.length();
prop1 = prop;
path = prop1.substring( index1, index2 );
path2 = path.replaceAll('\\\\','/');
pscode.setProperty('path', path2 );
name = path2.replaceAll('/','.');
pscode.setProperty('jar.name', name + '.jar' );
]]>
</script>
<xmlproperty file="${src}/java/org/pscode/${path}/manifest.xml" />
<!-- echo message='jar.name: ${jar.name} *** ${application.title}' / -->
<if>
<not>
<uptodate targetfile='${build}/dist/lib/${jar.name}' >
<srcfiles dir= '${build}/share/org/pscode/${path}' includes='*.class'/>
</uptodate>
</not>
<then>
<jar
destfile='${build}/dist/lib/${jar.name}'
index='true'
update='true'>
<manifest>
<attribute name="Implementation-Title" value="${application.title}" />
<attribute name="Implementation-Vendor" value="${vendor}" />
<attribute name="Implementation-Vendor-Id" value="org.pscode" />
<attribute name='Implementation-Version' value='${now}' />
</manifest>
<fileset dir='${build}/share'>
<include name='org/pscode/${path}/*.class' />
</fileset>
<fileset dir='${src}/java'>
<include name='org/pscode/${path}/*.png' />
<include name='org/pscode/${path}/*.jpg' />
<include name='org/pscode/${path}/*.gif' />
<include name='org/pscode/${path}/*.xml' />
<include name='org/pscode/${path}/*.html' />
<include name='org/pscode/${path}/*.ser' />
</fileset>
</jar>
</then>
</if>
<!-- If the Jar is updated, any previous signatures will be invalid, it
needs to be signed again. We cannot use the issigned condition since
that merely checks if a Jar is signed, not if the digital signatures are
valid. -->
<exec
executable='${jar.signer}'
resultproperty='jar.signer.result.property'
outputproperty='jar.signer.output.property'>
<arg value='-verify' />
<arg value='${build}/dist/lib/${jar.name}' />
</exec>
<if>
<or>
<not>
<equals arg1='${jar.signer.result.property}' arg2='0' />
</not>
<or>
<contains
string='${jar.signer.output.property}'
substring='unsigned'
casesensitive='false' />
<or>
<contains
string='${jar.signer.output.property}'
substring='SecurityException'
casesensitive='false' />
</or>
</or>
</or>
<then>
<signjar
jar='${build}/dist/lib/${jar.name}'
alias='pscode'
storepass='${sign.password}'
force='true'
verbose='${verbose}'
keystore='${user.home}/${sign.pathfilename}' />
</then>
</if>
</target>
Just for the records: jarsigner is able to read the keystore and key passwords from a file or from an environment variable, using the -keypass / -storepass command line option together with the :file or the :env modifier.
So, it's possible to put each of the passwords in a file (in my example: ~/.storepass and ~/.keypass) and use a for loop like this to sign all jars in the current directory using the key key_alias:
for i in ./*.jar; do jarsigner -storepass:file ~/.storepass -keypass:file ~/.keypass "$i" key_alias;done
To make jarsigner read the passwords from an env variable, you'll have to create those variables first:
export storepass="mystorepassword"
export keypass="mykeypassword"
Now, the loop would look like:
for i in ./*.jar; do jarsigner -storepass:env storepass -keypass:env keypass jarfile.jar key_alias;done

Ant: Rename sub-directories of the same name

Let's say I have a directory structure like this:
animals/dog/details
animals/cat/details
animals/frog/details
animals/horse/details
Using ant, I would like to rename all sub-directories under animals called details to now be named new. So the result would be this:
animals/dog/new
animals/cat/new
animals/frog/new
animals/horse/new
I've tried something like this:
<move tofile="new">
<path id="directories.to.rename">
<dirset dir="animals">
<include name="**/details"/>
</dirset>
</path>
</move>
But get this error:
Cannot concatenate multiple files into a single file.
You can carry out the rename you describe by means of a mapper. For example:
<move todir="animals">
<dirset dir="animals" includes="**/details" />
<globmapper from="*/details" to="*/new"/>
</move>
(There's a similar example at the end of the move task docs.)
The error you saw arose because you've mixed the single-file mode of the move task (tofile) with multiple-file mode.
There's no need to nest the dirset in a path as the move task accepts any file-based resource collection, including dirset.
Use Ant-Contrib's for task and propertyregex task.
<target name="test">
<for param="detailsDir">
<dirset dir="animals">
<include name="**/details"/>
</dirset>
<sequential>
<propertyregex property="output.dir" input="#{detailsDir}" regexp="(.*)/details" replace="\1" />
<move file="#{detailsDir}" toFile="${output.dir}/new" />
</sequential>
</for>
</target>

Ant task to perform only JUnit tests doesn't run tests

I'm trying to make an ant target that only runs the JUnit tests on a project without any other prior actions (no depends). I'm using Emma to instrument these in another target, and then I have another target that does a bytecode mutation on these instrumented classes. All that is working and I can get JUnit to run in that target after I've performed the instrumentation/mutation steps but I need to have the ability to just run the JUnit tests separately from this compile-instrument-mutate chain.
I've build a target that looks like this:
<target name="mutant-test-run" description="Run tests with mutation applied">
<path id="run.classpath">
<pathelement location="${out.dir}" />
</path>
<mkdir dir="${reports}" />
<junit printsummary="yes" fork="true">
<classpath>
<pathelement location="${out.instr.dir}" />
<path refid="junit.classpath" />
<path refid="famaLib.classpath" />
<path refid="run.classpath" />
<path refid="emma.lib" />
</classpath>
<jvmarg value="-Demma.coverage.out.file=${coverage.dir}/coverage.emma" />
<jvmarg value="-Demma.coverage.out.merge=true" />
<formatter type="plain" />
<formatter type="xml" />
<batchtest todir="${reports}">
<fileset dir="${src.dir}">
<include name="test1.java" />
<include name="test2.java" />
<include name="test3.java" />
<include name="test4.java" />
<include name="test5.java" />
</fileset>
</batchtest>
</junit>
<emma enabled="${emma.enabled}">
<report sourcepath="${src.dir}" sort="+block,+name,+method,+class" metrics="method:70,block:80,line:80,class:100">
<fileset dir="${coverage.dir}">
<include name="*.emma" />
</fileset>
<!-- for every type of report desired, configure a nested
element; various report parameters can be inherited from the parent <report>
and individually overridden for each report type:-->
<txt outfile="${coverage.dir}/coverage.txt" depth="package" columns="class,method,block,line,name" />
<xml outfile="${coverage.dir}/coverage.xml" depth="package" />
<html outfile="${coverage.dir}/coverage.html" depth="method" columns="name,class,method,block,line" />
</report>
</emma>
</target>
The jUnit task within the target doesn't get executed however, all I get is the output from the mkdir task and the emma task.
m1> ${ANT_HOME}/bin/ant -f nnbuild.xml -verbose mutant-test-run
Apache Ant(TM) version 1.8.2 compiled on July 5 2011
Buildfile: (Elided path here)/nnbuild.xml
Detected Java version: 1.6 in: /usr/lib64/jvm/java-1.6.0-sun-1.6.0/jre
Detected OS: Linux
parsing buildfile (Elided path)/nnbuild.xml with URI = file:(Elided path)/nnbuild.xml
Project base dir set to: (Elided path)
parsing buildfile jar:file:(Elided ANT_HOME path)/ant/lib/ant.jar!(Elided ANT_HOME path)/ant/antlib.xml with URI = jar:file:(Elided ANT_HOME path)/ant/lib/ant.jar!/org/apache/tools/ant/antlib.xml from a zip file
Build sequence for target(s) `mutant-test-run' is [mutant-test-run]
Complete build sequence is [mutant-test-run, emma, clean, init, compile, run, emma-run, merge, all, sofya, ]
mutant-test-run:
[mkdir] Skipping (Elided path)/reports because it already exists.
[emma] [EMMA v2.0, build 5312 (2005/06/12 19:32:43)]
[report] processing input files ...
[report] 1 file(s) read and merged in 48 ms
[report] nothing to do: no runtime coverage data found in any of the data files
BUILD SUCCESSFUL
Total time: 0 seconds
m1>
How do you setup an ant target to only do JUnit tests?
It looks like your fileset is wrong for the batchtest element, I think maybe you need to include a **:
<batchtest todir="${reports}">
<fileset dir="${src.dir}">
<include name="test1.java" />
<include name="test2.java" />
<include name="test3.java" />
<include name="test4.java" />
<include name="test5.java" />
</fileset>
</batchtest>
From the examples on the page JUnit Task, you can use:
<batchtest fork="yes" todir="${reports.tests}">
<fileset dir="${src.tests}">
<include name="**/*Test*.java"/>
<exclude name="**/AllTests.java"/>
</fileset>
</batchtest>
Where the ** means in any sub-directory.
Another example:
<batchtest todir="${collector.dir}" unless="hasFailingTests">
<fileset dir="${collector.dir}" includes="**/*.java" excludes="**/${collector.class}.*"/>
</batchtest>

Categories

Resources