I am using Ant to do a database build by basically using the exec task to run some SQL scripts.
However, there might be errors generated during the script execution (e.g. could not properly drop a connected user, etc) so I check for this by looking through two output log files.
Here's a snippet of the relevant target:
<target name="build">
<echo message="Add foo bar baz"/>
<exec executable="${db.sqlplus}">
</exec>
<echo message="Load x y z"/>
<exec executable="${db.sqlplus}" dir="foobar">
</exec>
<!--Check the log files here-->
<antcall target="check-log-file">
<param name="file.to.check" value="${output.log.1}"/>
</antcall>
<antcall target="check-log-file">
<param name="file.to.check" value="${output.log.2}"/>
</antcall>
<antcall target="fail-if-error"/>
</target>
<!--=============================================================================
Check the file named in the property file.to.check to see if there are errors.
The way this works is to find all lines containing the text "ERROR" and put
them into a separate file. Then it checks to see if this file has non-zero
length. If so, then there are errors, and it sets the property errors.found.
Then it calls the send-email target, which doesn't execute if the
errors.found property isn't set.
-->
<target name="check-log-file"
description="Checks the file (specified in ${file.to.check}) for errors">
<property name="file.errorcount" value="${file.to.check}.errorcount"
description="The file to hold the error lines"/>
<copy file="${file.to.check}" tofile="${file.errorcount}">
<filterchain>
<linecontains>
<contains value="ERROR"/>
</linecontains>
</filterchain>
</copy>
<condition property="errors.found" value="true">
<length file="${file.errorcount}" when="gt" length="0"/>
</condition>
<antcall target="check-log-file-send-email"/>
</target>
<!--=========================================================================
If there are any errors, send an email to let someone know
-->
<target name="check-log-file-send-email" if="errors.found"
description="Sends an email out if error detected">
<resourcecount property="error.count">
<tokens><!-- default tokenizer is a line tokenizer -->
<file file="${file.to.check}.errorcount"/>
</tokens>
</resourcecount>
<echo
message="Database build (${e1.codeline} - ${error.count} errors found..."/>
<antcall target="mail">
<param name="from-address" value="build"/>
<param name="to-list" value="myemail"/>
<param name="subject"
value="Automated database build error report for ${db.host}"/>
<param name="message"
value="See attached log file, ${error.count} error(s)found..."/>
<param name="attach" value="${file.to.check}"/>
</antcall>
</target>
<!--==========================================================================
Fails the database build if errors were detected.
-->
<target name="fail-if-error" if="errors.found">
<echo message="Errors found - setting database fail flag..."/>
<fail message="Errors detected during ${codeline} database build. Check logs."/>
</target>
When there are errors the build does not fail.
I think it's because the antcall task to check the logs does not return the property error.
Found back to the build target, so when fail-if-error is called, that property is unset.
Is that right?
Is there a way to set it up to fail properly?
Properties are passed to the new target using nested <param> elements. An investigation of the Ant source code reveals that antcall instantiates and calls the ant task using the current buildfile. This means that a new project instance is created and properties work the same as they do for ant .
We can use the <fail> Ant task to exit the Ant script but this will fail the build. Sometimes we may have some checking during the build such that it could exit peacefully without build failure in certain cases.
An Ant target is a sequence of tasks to be executed to perform a part (or whole) of the build process. Ant targets are defined by the user of Ant. Thus, what tasks an Ant target contains depends on what the user of Ant is trying to do in the build script.
Which version of Java is required to run Apache Ant? You will need Java installed on your system, version 1.8 or later required.
The antcall will set the property in the scope of its execution, so when you get to your check it is not set. Instead try using a macrodef
, this will run in the current scope and set the errors-found property in that scope so the later check can read it. You'd define the macrodef something like this:
<macrodef name="check-log-file">
<attribute name="fileToCheck"/>
<!--note attributes are referenced with an "@" rather than a "$" -->
<property name="file.errorcount" value="@{fileToCheck}.errorcount"/>
<copy file="@{fileToCheck}" tofile="${file.errorcount}">
...
</macrodef>
and call it like this:
<check-log-file fileToCheck="${output.log.1}"/>
<check-log-file fileToCheck="${output.log.1}"/>
Thanks to Rich Seller, who provided the idea of using a macrodef. The macrodef needed a little cleanup (property not allowed inside a macrodef, tasks need to be wrapped in a sequential tag) so I'm providing it here in full:
<macrodef name="check-log-file">
<attribute name="file.to.check"/>
<attribute name="file.errorcount" default="@{file.to.check}.errorcount" description="The file to hold the error lines"/>
<sequential>
<copy file="@{file.to.check}" tofile="@{file.errorcount}">
<filterchain>
<linecontains>
<contains value="ERROR"/>
</linecontains>
</filterchain>
</copy>
<condition property="errors.found" value="true">
<length file="@{file.errorcount}" when="gt" length="0"/>
</condition>
<antcall target="check-log-file-send-email">
<param name="file.to.check" value="@{file.to.check}"/>
</antcall>
</sequential>
</macrodef>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With