Why cannot Ant taskdef cannot load a resource outside ./net - ant

When declaring external ant tasks using taskdef, for instance ant-contrib, the proposed setup is to use the followin taskdef:
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="lib/ant-contrib/ant-contrib-1.0b3.jar"/>
</classpath>
</taskdef>
This works when antcontrib.properties is located in net/sf/antcontrib relative to the build.xml file.
But when I put it in lib/net/sf/antcontrib and changes the taskdef into
<taskdef resource="lib/net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="lib/ant-contrib/ant-contrib-1.0b3.jar"/>
</classpath>
</taskdef>
Ant is not able to find the properties file, it gives the error
[taskdef] Could not load definitions from resource
lib/net/sf/antcontrib/antcontrib.properties. It could not be found.
It seems like ant treats the lib directory separately and fails to load a taskdef resource from there.

As Alex said, you shouldn't need to unzip the jar. The <taskdef> can load antcontrib.properties directly out of the jar.
The error you got is because you changed the resource path, but the path to the file inside the compressed jar/zip is still the same. The taskdef isn't paying attention to the properties file you moved because the <classpath> you provided to <taskdef> tells it to only look in the jar.

Use antlib.xml resource:
Here is the taskdef definition that I use:
<property name="ant-contrib.jar" location="..."/>
<taskdef
resource="net/sf/antcontrib/antlib.xml"
uri="http://ant-contrib.sourceforge.net"
>
<classpath>
<pathelement location="${ant-contrib.jar}"/>
</classpath>
</taskdef>
You do not need to extract anything from the jar file. Also, uri attribute is optional if you do not want to use namespaces with antcontrib tasks.

To handle classpath for tasks definitions, I use a classpath ref in Ant, it's way easier. You can link either a directory containing classes, either a directory containing many .jar, either (of course) a single .jar.
For example :
<!-- Properties -->
<property name="lib" value="lib/" />
<property name="classes" value="bin/" />
<!-- Classpath definition -->
<path id="runtime-classpath" >
<pathelement location="${bin}" />
<fileset dir="${lib}">
<include name="*.jar"/>
</fileset>
</path>
<!-- Taskdefs definitions -->
<taskdef name="myTask" classname="org.stackoverflow.tasks.MyTask" classpathref="runtime-classpath" />
<!-- Tasks -->
<target name="test" description="Test Action">
<myTask parameter1="value" />
</target>

Related

Ant for script how to continue if any iteration fails

I writing an ant build file to check all translate files in a directory.
I want the ant for script to continue checking the rest files if an checking error in any file appear.
My ant task:
<taskdef name="validate" classname="ValidateTranslateFile">
<classpath>
<pathelement location="${ant-libs-dir}/TranslateFileUtilities.jar" />
<pathelement location="../web/WEB-INF/lib/commons-io-2.5.jar" />
<pathelement location="../web/WEB-INF/lib/commons-lang3-3.5.jar" />
</classpath>
</taskdef>
<for param="program">
<path>
<fileset dir="../web/WEB-INF" includes="*.txt" />
</path>
<sequential>
<validate targetFile="#{program}" checkLanguages="true" checkKeysOrder="true" />
</sequential>
</for>
</target>
the Result:
it checks the files till the first error appear, and then the BUILD FAILED.
Could any one help me with that?
The for task is not part of standard ANT. It is a 3rd party extension documented here:
http://ant-contrib.sourceforge.net/tasks/tasks/for.html
The documentation suggests using a "keepgoing" attribute to ignore errors, this might be the answer you're looking for.
If this is a custom ANT task you are writing, perhaps you should consider refactoring the code to operate on a fileset? This would enable you to call task as follows:
<validate checkLanguages="true" checkKeysOrder="true">
<fileset dir="../web/WEB-INF" includes="*.txt" />
</validate>
Simpler and more robust.

read properties file inside ant taskdef

I'm defining a build.xml file and I need to read some paths from a properties file. Reading from it is ok on my defined targets. The problem comes when I try to read the values inside my taskdef. How can I achieve this?
I have something like this:
<taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask">
<classpath>
<fileset dir="${paths.jaxb.lib}" includes="*.jar" />
</classpath>
</taskdef>
My "paths.jaxb.lib" is the path to the jaxb lib folder. How can I get this value from my paths.properties file?
Read the properties file before the <taskdef> task.
If paths.properties is...
paths.jaxb.lib=path/to/my/jaxb/lib
...then in build.xml...
<!-- Loading the Java properties file sets the paths.jaxb.lib Ant property. -->
<property file="paths.properties"/>
<taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask">
<classpath>
<fileset dir="${paths.jaxb.lib}" includes="*.jar" />
</classpath>
</taskdef>

ANT - Converting a String to Path with location attribute

I have the following ANT script that gives me a list of websphere libraries at runtime based on the websphere root directory. I need to convert the resulting string into separate path location elements
My current script is
<?xml version="1.0" encoding="UTF-8"?>
<project name="TestPath" basedir="." default="print-dirset">
<target name="init" description="Define websphere libraries">
<property name="compile.lib.dir" value="C:\Software\WAS85" />
</target>
<target name="print-dirset" depends="init" description="">
<path id="websphere.libs">
<dirset dir="${compile.lib.dir}">
<include name="*" />
</dirset>
</path>
<property name="websphere.libs.list" refid="websphere.libs" />
<echo message="websphere.libs.list: ${websphere.libs.list}" />
<pathconvert property="websphere.libs.convert" pathsep="${file.separator}*${path.separator}">
<path path="${websphere.libs.list}" />
</pathconvert>
<echo message="websphere.libs.convert: ${websphere.libs.convert}" />
</target>
</project>
which outputs a string like below
[echo] websphere.libs.list: C:\Software\WAS85\Scheduler;C:\Software\WAS85\UDDIReg;C:\Software\WAS85\bin;C:\Software\WAS85\configuration;....C:\Software\WAS85\web;C:\Software\WAS85\wlp
[echo] websphere.libs.convert: C:\Software\WAS85\Scheduler\*;C:\Software\WAS85\UDDIReg\*;C:\Software\WAS85\bin\*;C:\Software\WAS85\configuration\*;...C:\Software\WAS85\web\*;C:\Software\WAS85\wlp
I would like to translate the second string above into a structure like below
<path id="websphere.classpath">
<pathelement location="C:\Software\WAS85\Scheduler\*" />
<pathelement location="C:\Software\WAS85\UDDIReg\*" />
<pathelement location="C:\Software\WAS85\bin\*" />
<pathelement location="C:\Software\WAS85\configuration\*" />
......
<pathelement location="C:\Software\WAS85\web\*" />
<pathelement location="C:\Software\WAS85\wlp\*" />
</path>
The last element in the conversion also needs to add the '\*' part which is not in the original string.
which can then be used with a structure like
<path id="compile.classpath">
<path refid="ext.classpath"/>
<path refid="websphere.classpath"/>
<path refid="module.compile.classpath"/>
</path>
The purpose of the above attempt is to reduce the length of classpath by using wildcard classpath provided by JDK 1.6 and which is available in ANT starting ANT 1.8.2. I am using ANT 1.8.4.
I am not an expert in ANT, I can just get by, by looking at examples.
Is there a way to achieve what I am trying to do? How can I do it? Any example would be very helpful.
If all of your dependencies reside in C:\Software\WAS85, you can use fileset to catch all of your dependencies:
<fileset dir="${compile.lib.dir}" id="compile.files">
<include name="**/*.java"/>
<!-- include name="**/*.jar" /-->
</fileset>
You can then use to refer to this fileset as compile.files elsewhere in your build.xml.
I was able to get the wildcard part to work by using the fork="yes" and executable="path-to-my-executable" attributes in the javac task.
I do not want to mark the question answered, because my basic question was about converting the string. But since the answer received didn't talk about that and also didn't mention how to get wildcard classpath working, and the purpose of my question was to get the wildcard classpath working, i have noted it here for whoever is trying to get that to work
I still need some help in converting the semi-colon separated string to construct like below
<path id="websphere.classpath">
<pathelement location="C:\Software\WAS85\Scheduler\*" />
<pathelement location="C:\Software\WAS85\UDDIReg\*" />
<pathelement location="C:\Software\WAS85\bin\*" />
<pathelement location="C:\Software\WAS85\configuration\*" />
......
<pathelement location="C:\Software\WAS85\web\*" />
<pathelement location="C:\Software\WAS85\wlp\*" />
</path>
Update:
I wrote a custom ANT task to get the wildcard classpath working

Ant and yuicompressor

I am trying to integrate yuicompressor with Ant to automate the minification of our CSS and JS files. However, I keep getting the following error message when I try to run build.xml:
BUILD FAILED
/Applications/MAMP/htdocs/zanadu-dev/build/build.xml:64: taskdef A class needed by class com.yahoo.platform.yui.compressor.YUICompressTask cannot be found: org/mozilla/javascript/EvaluatorException
using the classloader AntClassLoader[/usr/share/ant/lib/YUIAnt.jar:/usr/share/ant/lib/yuicompressor-2.4.6/build/yuicompressor-2.4.6.jar:/usr/share/ant/lib/yuicompressor-2.4.6/lib/rhino-1.6R7.jar]
Here is the code in my build.xml file:
<target name="minify" depends="build" description="Minifiy CSS and JS files">
<available file="${antlib.dir}/YUIAnt.jar" property="YUIANT_AVAILABLE" />
<fail unless="YUIANT_AVAILABLE" message="YUIAnt.jar not found" />
<taskdef name="yuicompress" classname="com.yahoo.platform.yui.compressor.YUICompressTask">
<classpath>
<pathelement path="${antlib.dir}/YUIAnt.jar" />
<pathelement path="${antlib.dir}/yuicompressor-2.4.6/build/yuicompressor-2.4.6.jar" />
<pathelement path="${antlib.dir}/yuicompressor-2.4.6/lib/rhino-1.6R7.jar" />
</classpath>
</taskdef>
<mkdir dir="${jsminify.dir}" />
<yuicompress linebreak="300" warn="false" munge="yes" preserveallsemicolons="true"
outputfolder="${jsmin.dir}">
<fileset dir="${js.dir}" >
<include name="**/*.js" />
</fileset>
</yuicompress>
<mkdir dir="${cssminify.dir}" />
<yuicompress linebreak="300" warn="false" munge="yes" preserveallsemicolons="true"
outputfolder="${cssmin.dir}">
<fileset dir="${css.dir}" >
<include name="**/*.css" />
</fileset>
</yuicompress>
</target>
I have tried following several online examples on this, but all seem to yield the same error message. Not sure exactly where I can find the EvaluatorException class that seems to be missing.
Any idea what I may be doing wrong?
Cheers!
Your taskdef is missing one lib.
<taskdef name="yuicompress" classname="com.yahoo.platform.yui.compressor.YUICompressTask">
<classpath>
<pathelement path="${antlib.dir}/YUIAnt.jar" />
<pathelement path="${antlib.dir}/yuicompressor-2.4.6.jar" />
<pathelement path="${antlib.dir}/rhino-1.6R7.jar" />
</classpath>
</taskdef>
EDIT:,
The problem is somehow related to the jar locations and Ant's class-loader, see this post
One workaround is to copy YUIAnt.jar, yuicompressor-2.4.6.jar and rhino-1.6R7.jar to one directory. Then use it like above. I've tried and it works.
if you use http://code.google.com/p/yui-compressor-ant-task/ for me solution was to use classname="net.noha.tools.ant.yuicompressor.tasks.YuiCompressorTask" instead of classname="com.yahoo.platform.yui.compressor.YUICompressTask"

Ant path convert

Good afternoon
I am running ant to process some code now I have path "com/source/project" in properties but I need to pass "com.source.project" to my java code is there anyway I can convert "/" to "." using ant command
thanks
PropertyRegex task works for you, but you need to install ant-contrib.
<project>
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="./ant-contrib-1.0b3.jar"/>
</classpath>
</taskdef>
<property name="path" value="com/source/project"/>
<echo message="Path=${path}"/>
<propertyregex property="java.package.name"
input="${path}"
regexp="/"
replace="."
global="true"
defaultValue="${path}" />
<echo message="package=${java.package.name}"/>
</project>
Here's some complete project that uses the Ant Plugin Flaka. I also had to replace the ${path.separator} with '.' to start some java classes. See the comments starting with ';'
<project xmlns:fl="antlib:it.haefelinger.flaka">
<fl:install-property-handler/>
<property name="srcroot" value="path/to/srcrootdir"/>
<property name="classroot" value="path/to/classrootdir"/>
<!-- determine all main classes -->
<fileset dir="${srcroot}" includes="**/*.java" id="mainclasses">
<contains text="public static void main"/>
</fileset>
<!-- iterate over those main classes and
call the corresponding classfile -->
<fl:for var="file" in="split('${toString:mainclasses}', ';')">
<fl:let>
; strip the .java Extension
file = replace(file, '', '.java')
; replace fileseparator with '.'
; on Windows you have to use the following line
; replace(file, '\.', '${file.separator}${file.separator}')
file = replace(file, '\.', '${file.separator}')
</fl:let>
<fl:echo>
starting => #{file} in ${classroot}
</fl:echo>
<java classname="#{file}">
<classpath>
<!--
when using a fileset you'll get a
java.util.zip.ZipException because you're
referencing classfiles and no jars
therefore you have to use
pathelement and location
-->
<pathelement location="${classroot}"/>
</classpath>
</java>
</fl:for>
</project>

Resources