Ant Successful even when Ant Task fails - ant

There must be a simple setting I am missing so forgive me, but I've noticed on two occasions that my bad ant tasks do not cause the build to fail. For example:
Ant copy when source file does not exist ... BUILD SUCCESSFUL
Ant unzip, when task reports "can't write file" or similar message ... BUILD SUCCESSFUL
Ant exec error, invalid syntax ... BUILD SUCCESSFUL
How do I guarantee all ant task errors will result in a build failure?

<EXEC> tasks do no fail by default. You need to enable this with failonerror="true"
Failure of the Ant <COPY> task depends on what resource collection type is used. If you use a fileset or patternset, then all missing files are silently ignored. You can force a failure only by using the filelist type or the parameterized 'file` attribute is used.
Therefore what you want to use is either:
<copy todir="my_dir" file="foo" />
<copy todir="my_dir" flatten="true">
<filelist dir="" files="foo" />
</copy>
<copy todir="my_dir" flatten="true">
<filelist dir="">
<file name="foo" />
<file name="bar" />
<file name="zed" />
</filelist>
</copy>

Have you tried following:
<copy todir="your/path/details" failonerror="true">
</copy>
<zip destfile="your/path/details" whenempty="fail">
</zip>
<exec executable="your/path/details" failonerror="true">
</exec>

Related

macrodef'd <jar> task not behaving like an implicit fileset?

Using standard Ant 1.9.7 to assemble a bunch of jar files. We've made a macro to help cut down on the verbosity of the XML:
<!-- All 'description' bits snipped for SO posting. -->
<macrodef name="buildjar">
... bunch of <attribute> ...
<element name="also"/>
<sequential>
<jar ....>
<manifest> ... </manifest>
<fileset what="stuff in every jar file" />
<fileset what="and this stuff too" />
<mappedresources if:true="beauty">
<fileset for when truth is beauty/>
<globmapper from="ugly" to="beauty"/>
</mappedresoruces>
<!-- Anything else for this specific jar. -->
<also/>
</jar>
</sequential>
</macrodef>
This works:
<buildjar .........>
<also>
<fileset file="/some/path/somewhere/a_single_file"/>
</also>
</buildjar>
But this does not:
<buildjar .........>
<also>
<include name="/some/path/somewhere/a_single_file"/>
</also>
</buildjar>
There are no errors. Looking at ant -d output, there's no mention of the additional entry at all, where in the first example there is a line for fileset: Setup scanner in dir /some/path/somewhere with patternSet{ includes: [a_single_file] excludes: [] }
Ditto for multiple files. This works:
<buildjar .........>
<also>
<fileset dir="/some/path/somewhere">
<include name="one_file" />
<include name="foo**" />
</fileset>
</also>
</buildjar>
but this does not:
<buildjar .........>
<also>
<include name="/some/path/somewhere/one_file"/>
<include name="/some/path/somewhere/foo**"/>
</also>
</buildjar>
According to the Ant manual's page for <jar>,
This task forms an implicit FileSet and supports most attributes of <fileset> (dir becomes basedir) as well as the nested <include>, <exclude> and <patternset> elements.
So in theory, shouldn't an <include> simply be enough, and become a nested element of the macro'd <jar>?
Obviously, in practice this isn't a problem (we slap a bigass comment in the build files telling people to not leave out the explicit <fileset>). And we can't put the <fileset> into the macro definition like this:
<macrodef name="buildjar">
<element name="also"/>
<sequential>
<jar ....>
.....
<!-- Anything else for this specific jar. -->
>> <fileset dir="some_generic_base_path">
<also/>
>> </fileset>
</jar>
</sequential>
</macrodef>
because then when the calling code does a buildjar without any also blocks, the unrestricted fileset will include the entire some_generic_base_path tree.
Is this simply some interaction between macrodefs and filesets that has taken us by surprise?
Short answer is no - it's not a macrodef problem. To use the implicit fileset you must specify the basedir attribute for the <jar> task. Here's an example that illustrates this:
<jar destfile="my.jar">
<include name="a/b" />
</jar>
<zip destfile="my.zip" >
<include name="a/b" />
</zip>
In the example the <jar> task will succeed and create a manifest-only jar file. But the <zip> task will fail saying:
BUILD FAILED
build.xml:8: basedir attribute must be set, or at least one resource collection must be given!
The jar task is based on the zip task and inherits its check for resources. Because the jar task has some - the manifest - the error is not thrown.
If you want to use the implicit fileset, specify a basedir.

Intentionally fail Ant build when using <delete> with a <fileset> including missing files

<delete includeEmptyDirs="false" failonerror="true">
<fileset dir="${dest.dir}" includes="a.txt,b.txt,c.abc"/>
</delete>
For example, if file a.txt is changed to a1.txt2 or something then Ant is not failing to find file. What to do?
That is not the purpose of failonerror attribute in this case.
From ant manual delete task :
Controls whether an error (such as a failure to delete a file)
stops the build or is merely reported to the screen. Only relevant if
quiet is "false".
It's not an error, if fileset doesn't match.
Also you don't need to set failonerror=true as it is default.
To make it fail, use fail with condition and resourcecount, f.e.:
<delete includeEmptyDirs="false" failonerror="true">
<fileset dir="${dest.dir}" includes="a.txt,b.txt,c.abc" id="foobar"/>
</delete>
<fail message="Fileset doesn't match !">
<condition>
<resourcecount when="eq" count="0">
<fileset refid="foobar"/>
</resourcecount>
</condition>
</fail>

Avoid Printing Build Successful after ant exits a target

I have an ant script which calls a target from another script. When this target is fully executed, the second script exits with a "Build Successful" message, which is a bit confusing to the users. I dont want the second ant script to echo "Build Successful" on its exit.
My code is
<target name="startRemoteJboss" description="Starts Remote Instance of Jboss">
<echo message="starting Remote Jboss" />
<sshexec output="remoteJboss.txt" trust="true" host="${jboss.remote.host}" username="${jboss.remote.username}" password="${jboss.remote.password}" command="ant -f build.xml startJboss" port="${jboss.remote.port}" failonerror="no"/>
</target>
The second build file target looks like
<target name="startJboss" description="Starts Jboss">
<echo message="starting Jboss" />
<exec executable="${jboss.home}/bin/run.sh" spawn="true">
<arg line="-b 0.0.0.0 -c default" />
</exec>
<sleep seconds="150" />
<echo message="Jboss is UP" />
</target>
When the startJboss completes it execution, i would like it to not print "Build Successful"
[sshexec] BUILD SUCCESSFUL
[sshexec] Total time: 10 seconds
Since you're capturing the output to a file (<sshexec output="remoteJboss.txt" ...), then you should be able to strip these lines from it, e.g.:
<concat>
<fileset dir="." includes="remoteJboss.txt" />
<filterchain>
<linecontains negate="true">
<contains value="[sshexec] BUILD SUCCESSFUL"/>
</linecontains>
<linecontains negate="true">
<contains value="[sshexec] Total time:"/>
</linecontains>
</filterchain>
</concat>
To printout to the user (assuming you're using concat already), or use the destFile attribute to specify a copy of the output file where these lines are stripped out:
<concat destfile="remoteJboss_short.txt" >
Best practice is to use macrodef for sharing functionality, means make a macrodef of your startJboss target instead of starting another ant instance with new project scope.
This will also avoid the BUILD SUCCESSFUL output.
EDIT
The "BUILD SUCCESSFUL" string comes from ant's DefaultLogger#getBuildSuccessfulMessage(). You may write your own logger that returns an empty string or any other string instead, see ant manual listeners and loggers for details.

modify ant classpath on the fly

I want to use resolvers (ssh) which are dependant on ant classpath.
Something like
<resolvers>
...
<ssh ...
...
</resolvers>
To use it I need jsch in ant classpath. Ant script should depends only on common lib (which also includes resolved jsch dependencies) - to use it on any client PC. Scenario is:
task to download lib.
Extract libs (jsch and etc.)
ivy:configure
But ivy:configure does not have any classpathref param, so it is unclear for me how to load jars I extracted.
Is it possible?
Or, probably, somehow run ant again internally with extended classpath?
Ok,
so my comment to question looked good for me but at the end it did not work.
The only way I found (working way I mean) is to to run ant script with
Download common-lib (with ) which includes all jar-libs required for optional ivy processing
Construct new classpath and run exec on same build file with required target:
<target name="call.task" if="wrapped.task.name">
<path id="ant.class.path">
<fileset dir="${tools.lib.dir}" >
<include name="*.jar" />
</fileset>
<pathelement location="${java.class.path}" />
</path>
<condition property="append.dest.dir" value="-Ddest.dir=${dest.dir}" else="">
<isset property="dest.dir"/>
</condition>
<exec executable="ant" failonerror="true">
<arg line="-f ivy-build.xml" />
<arg line='-lib "${toString:ant.class.path}"' />
<arg value="${wrapped.task.name}" />
<arg value="${append.dest.dir}" />
</exec>
</target>

Inconsistent NoClassDefFoundError in subant java task

My ant build script starts with a java task that uses fork=true
<java fork="true"
classname="org.apache.tools.ant.launch.Launcher"
jvm="${java.home}/bin/java"
classpathref="class.path">
<arg value="-f" />
<arg value="${ant.file}" />
<arg value="generate" />
</java>
The <arg value="generate" /> points to another task in the same ant build file.
This task starts another target with a subant task that points to another file.
<subant verbose="true" target="replace">
<fileset dir="${basedir}" includes="refactor.xml" />
</subant>
This file refactor.xml starts a java task again with fork=true.
<java classpathref="class.path"
classname="namespace.Tool"
fork="true"/>
The strange behaviour is: everything works fine, except once in a while I get the NoClassDefFoundError error for the namespace.Tool java source file.
After e.g. closing, reopening the file the error may disappear, however there is no reproducible behaviour.
I tried avoiding the subant construction (used to unclutter) but this doesn't help.
Finally the class.path that is referenced is like this:
<path id="class.path">
<pathelement location="../common/bin" />
<pathelement location="./bin" />
<fileset dir="${build.dir}">
<include name="...jar" />
</fileset>
</path>
Any ideas?
Cause was <pathelement location="./bin" />.
This bin folder was recompiled by Eclipse as soon as in other steps in the sequence of Ant tasks e.g. a folder was deleted. The default setting in Eclipse is to recompile all code at such a moment.
As a result the Ant process may or may not find a specific class in this bin folder resulting in the inconsistent NoClassDefFoundError.

Resources