Ant Utility Tasks

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

This page collects the small tasks that do not belong to a larger topic but appear in almost every real build file: echo, input (with input handlers), record, tstamp, checksum, buildnumber, hostinfo, diagnostics, antversion, whichresource, antstructure and sleep. It is written against Apache Ant 1.10.18 and was checked on 2026-10-16 with JDK 26 on macOS. Every example was run on that day on a scratch copy of the tidepool project’s data/stations.csv; output is shown as Ant printed it, with absolute paths shortened to . or ... and nothing else edited. All tasks are in Ant’s core ant.jar (no extra JARs); antversion and whichresource also exist as conditions, described on Conditions & Control Flow. Properties used below follow the rules on Properties, in particular that a property, once set, cannot be changed.

echo

echo writes a message to the build’s loggers, or to a file. The message comes from message or from the element’s text, and a task with neither prints a blank line. Whitespace in element text is kept, including the newline right after the opening tag, which is why multi-line echo bodies usually start on the same line as the tag.

Attribute Effect

message, nested text

What to print.

level

error, warning, info, verbose or debug. The default is warning, so a plain echo is shown even with -quiet.

file, output, append

Write to a file, or (output, Ant 1.8) any resource that supports output, instead of the log. append defaults to false; level is ignored when writing to a file.

encoding, force

Character encoding of the file (Ant 1.7), and overwrite a read-only destination file (Ant 1.8.2).

Log levels

A build is filtered by the command-line level: -quiet (-q), none, -verbose (-v), -debug (-d). The target below echoes one message at every level:

build.xml (echo-levels target)
<target name="echo-levels">
  <echo message="This is error message." level="error"/>
  <echo message="This is warning message."/>
  <echo message="This is info message." level="info"/>
  <echo message="This is verbose message." level="verbose"/>
  <echo message="This is debug message." level="debug"/>
</target>

Run with each switch (only the [echo] lines are kept):

$ ant -q echo-levels
     [echo] This is error message.
     [echo] This is warning message.

$ ant echo-levels
     [echo] This is error message.
     [echo] This is warning message.
     [echo] This is info message.

$ ant -v echo-levels
     [echo] This is error message.
     [echo] This is warning message.
     [echo] This is info message.
     [echo] This is verbose message.

$ ant -d echo-levels
     [echo] This is error message.
     [echo] This is warning message.
     [echo] This is info message.
     [echo] This is verbose message.
     [echo] This is debug message.

This matches the table in the manual. The practical rule: use info for normal progress, verbose for detail that helps when something goes wrong, debug for dumps, and error only for messages that must show even in -quiet runs. The same levels govern the -verbose and -debug output of every other task, as explained on Running Ant.

Echoing to a file and the double dollar

Generating a script is a common use. In the element text, a single $ starts a property reference, so to write a literal $ (here the shell’s $*) you write $$:

build.xml (echo-file target)
<target name="echo-file">
  <mkdir dir="${build.dir}"/>
  <echo file="${build.dir}/runner.sh" append="false">#!/bin/sh
java -Xmx512m -jar tidepool-cli.jar $$*
</echo>
  <echo file="${build.dir}/runner.sh" append="true">echo "built by ${ant.project.name}"
</echo>
  <loadfile srcfile="${build.dir}/runner.sh" property="runner"/>
  <echo>${runner}</echo>
</target>
     [echo] #!/bin/sh
     [echo] java -Xmx512m -jar tidepool-cli.jar $*
     [echo] echo "built by tidepool-utils"

echo does not set the executable bit; follow it with chmod (on Unix) or setpermissions (File Operations). The echoxml task, for XML content, is on Documentation & XML.

input and input handlers

input asks the user for a value through the project’s input handler. It takes a message (or element text), optional validargs (a comma-separated, case-sensitive list; input outside it is rejected), addproperty (the property to create) and defaultvalue (used when the user just presses Return). input behaves like property: an existing property is not overridden, and since Ant 1.6 the task does not even prompt if the property is already set.

Prompting and validating

The target asks a yes/no question, and re-asks until the answer is valid:

build.xml (input targets)
<target name="input-yesno">
  <input message="Publish to the local repository (y/n)?" validargs="y,n" addproperty="do.publish"/>
  <echo>do.publish=${do.publish}</echo>
</target>

<target name="input-default">
  <input message="Station id:" addproperty="station.id" defaultvalue="SF"/>
  <echo>station.id=${station.id}</echo>
</target>

With the answer piped on standard input (echo y | ant input-yesno):

input-yesno:
    [input] Publish to the local repository (y/n)? (y, n)
     [echo] do.publish=y

Typing maybe first (printf 'maybe\ny\n' | ant input-yesno) makes the default handler ask again:

input-yesno:
    [input] Publish to the local repository (y/n)? (y, n)
    [input] Publish to the local repository (y/n)? (y, n)
     [echo] do.publish=y

With an empty line the default is used, and a property set beforehand skips the prompt altogether:

$ echo "" | ant input-default
input-default:
    [input] Station id: [SF]
     [echo] station.id=SF

$ ant -Dstation.id=BOS input-default
input-default:
    [input] skipping input as property station.id has already been set.
     [echo] station.id=BOS

The second form is how a build that normally asks questions is made to run unattended: define the answer as a property.

What -noinput really does

-noinput ("do not allow interactive input") does not choose answers for you. It makes standard input unreadable, so the default handler fails when it tries to read:

$ ant -noinput input-yesno
input-yesno:
    [input] Publish to the local repository (y/n)? (y, n)

BUILD FAILED
./build.xml:25: Failed to read input from Console.

and, importantly, the same happens when a defaultvalue is set:

$ ant -noinput input-default
input-default:
    [input] Station id: [SF]

BUILD FAILED
./build.xml:30: Failed to read input from Console.

A defaultvalue is applied only when the handler reads an empty line, never when there is no input at all. For CI, either define the property (-Dstation.id=SF, or a <property> before the input) so the task is skipped, or select a handler that does not read the console. The manual’s recommendation for IDEs that cannot give a prompt is the same: put the answers in a property file and load it before input.

Choosing an input handler

The handler is chosen for the whole build with -inputhandler class, or per task with a nested handler (Ant 1.7):

Handler (type) Behaviour

default

Prompts on the console and reads a line.

propertyfile

Looks the prompt up in the properties file named by the Java system property ant.input.properties.

greedy

Reads standard input until end of file, instead of one line (per its Javadoc).

secure (Ant 1.8)

Reads without echoing the characters, through Java’s System.console(); for passwords.

classname or refid

Your own InputHandler subclass.

The propertyfile handler suits CI. The file’s keys are the prompt texts, with the characters that are special in a properties key escaped:

inputs.properties
Publish\ to\ the\ local\ repository\ (y/n)?=y
Station\ id\:=HNL

The handler reads a Java system property, not an Ant property, so -Dant.input.properties=… on the Ant command line (which sets an Ant property) is not enough: the run failed with System property ant.input.properties for PropertyFileInputHandler not set. Pass it through ANT_OPTS instead:

$ ANT_OPTS="-Dant.input.properties=inputs.properties" ant -inputhandler org.apache.tools.ant.input.PropertyFileInputHandler input-yesno input-default
input-yesno:
     [echo] do.publish=y
input-default:
     [echo] station.id=HNL

The greedy handler took the line SF from a pipe and set the property as expected. The secure handler could not be run here: without a terminal, System.console() is null, and the task failed with a NullPointerException from SecureInputHandler. Run it from a real console. input is not usable from IDEs that do not forward standard input; in that case use a property file as above.

A related point for passwords: avoid typing them on a command line (they land in shell history and process listings) and avoid writing them in the build file. The secure handler, an environment variable read with <property environment="env"/>, or a property file with restricted permissions are the usual routes, covered with other credentials on Supply Chain Security.

Custom handlers, listeners and loggers are documented on Listeners, Loggers & Input Handlers.

record

record attaches a recorder, a build listener that writes the log to a file. Each file name identifies one recorder: the first record with a new name creates and starts it; later calls with the same name change its state.

Attribute Effect

name

The file to record to. Required.

action

start or stop. The first call defaults to start; later calls keep the previous state if the attribute is omitted.

append

yes or no (default). Only honoured the first time the file is used.

loglevel

error, warn, info (default), verbose or debug. It can be raised or lowered during the build.

emacsmode

true removes the [task] banners, like -emacs.

relativeToBaseDir (Ant 1.10.18)

yes makes a relative name relative to the project’s base directory; no (default) relative to the process’s working directory.

The recorder writes what the build logs at its level between start and stop; its stream is flushed after targets and tasks and closed at the end of the build. This target records one stretch of the build at the verbose level, then stops and reads the file back:

build.xml (record target)
<target name="record">
  <record name="${build.dir}/steps.log" action="start" loglevel="verbose"/>
  <echo>first step</echo>
  <echo level="verbose">only in the recording</echo>
  <record name="${build.dir}/steps.log" action="stop"/>
  <echo>not recorded</echo>
  <loadfile srcfile="${build.dir}/steps.log" property="steps"/>
  <echo>--- steps.log ---${line.separator}${steps}</echo>
</target>
     [echo] first step
     [echo] not recorded
     [echo] --- steps.log ---
     [echo]      [echo] first step
     [echo]      [echo] only in the recording

The console (run at the default level) shows two messages; the file holds the first one and the verbose one, and not "not recorded". The 1.10.18 attribute relativeToBaseDir matters when Ant is started from another directory. Running ant -f ../ant-utility-tasks/build.xml record-relative from a sibling directory with one recorder per setting:

<target name="record-relative">
  <record name="steps-cwd.log" action="start"/>
  <record name="steps-base.log" action="start" relativeToBaseDir="yes"/>
  <echo>hello recorders</echo>
  <record name="steps-cwd.log" action="stop"/>
  <record name="steps-base.log" action="stop" relativeToBaseDir="yes"/>
</target>

produced one file in each place, each holding the one [echo] line:

steps-cwd.log    in the working directory           (28 bytes)
steps-base.log   in the project's base directory    (28 bytes)

Every record call for that file has to repeat relativeToBaseDir="yes", because the attribute is part of how the name is resolved. A first version of this target left it off the stop call: that call resolved steps-base.log against the working directory, created a second, empty recorder there (a zero-byte steps-base.log), and the real recorder in the base directory was never stopped, so it went on recording to the end of the build (46 bytes, with BUILD SUCCESSFUL).

tstamp

tstamp sets DSTAMP (yyyyMMdd), TSTAMP (HHmm) and TODAY (MMMM d yyyy) in the project, and can set more properties with nested format elements: property, pattern (a SimpleDateFormat pattern), timezone, locale, and offset with a unit (millisecond to year). prefix prefixes all properties. Put it in an initialisation target.

build.xml (tstamp target)
<target name="tstamp">
  <tstamp/>
  <tstamp prefix="start">
    <format property="iso" pattern="yyyy-MM-dd'T'HH:mm:ss'Z'" timezone="UTC"/>
    <format property="yesterday" pattern="yyyy-MM-dd" offset="-1" unit="day" timezone="UTC"/>
  </tstamp>
  <echo>DSTAMP=${DSTAMP} TSTAMP=${TSTAMP} TODAY=${TODAY}</echo>
  <echo>start.iso=${start.iso} start.yesterday=${start.yesterday}</echo>
</target>
     [echo] DSTAMP=20261016 TSTAMP=1144 TODAY=October 16 2026
     [echo] start.iso=2026-10-16T09:44:53Z start.yesterday=2026-10-15

(The local time zone on the test machine was CEST, two hours ahead of UTC, which is why TSTAMP and start.iso differ.)

Reproducible dates

A build that stamps the current time cannot be reproduced. Ant lets you fix the time:

  • the magic property ant.tstamp.now (seconds since the epoch) and ant.tstamp.now.iso (ISO-8601), since Ant 1.10.2;

  • the SOURCE_DATE_EPOCH environment variable, since Ant 1.10.8 (an invalid value logs a debug message and the current date is used);

  • since Ant 1.10.18, when SOURCE_DATE_EPOCH is the source, the time zone of DSTAMP, TSTAMP and TODAY is UTC, and nested format elements default to UTC and the en_US locale unless they say otherwise.

The same target with the fixed values:

$ SOURCE_DATE_EPOCH=0 ant -q tstamp
     [echo] DSTAMP=19700101 TSTAMP=0000 TODAY=January 1 1970
     [echo] start.iso=1970-01-01T00:00:00Z start.yesterday=1969-12-31

$ ant -q -Dant.tstamp.now.iso=1972-04-17T08:07:00Z tstamp
     [echo] DSTAMP=19720417 TSTAMP=0907 TODAY=April 17 1972
     [echo] start.iso=1972-04-17T08:07:00Z start.yesterday=1972-04-16

The second run shows the difference: with ant.tstamp.now.iso the standard TSTAMP is still in the local time zone (0907 for 08:07 UTC on a machine one hour ahead then), whereas with SOURCE_DATE_EPOCH the 1.10.18 rule makes it UTC (0000). For reproducible builds set SOURCE_DATE_EPOCH and give explicit timezone attributes to your own formats. Maven has project.build.outputTimestamp and Gradle reproducible archives for the same goal, compared on Build Automation Fundamentals.

checksum

checksum creates or verifies checksum files and properties. The attributes:

Attribute Effect

file, nested resource collection

What to checksum. Nested collections must be file-system resources.

algorithm

A MessageDigest algorithm name. The default is MD5; the manual warns that MD5 and SHA-1 are broken for security purposes, so use SHA-256 or stronger.

provider

A JCE provider for algorithms the JDK lacks.

fileext

Extension of the checksum file. The default is . plus the algorithm name exactly as you wrote it.

todir

Write checksum files to another directory.

property

Without verifyproperty: the property that receives the checksum. With it: the checksum you expect (the value itself).

verifyproperty

Set to true or false after comparing with the existing checksum file or property.

pattern, format

pattern is a MessageFormat ({0} checksum, {1} file name; since Ant 1.8.2 also {2}, {3}, {4} for relative and absolute paths). format is CHECKSUM (default, the digest only), MD5SUM ({0} *{1}, as GNU md5sum) or SVF.

totalproperty

A property for a checksum of all checksums and relative paths, with / separators for portability.

forceoverwrite, readbuffersize

Overwrite newer checksum files; buffer size for large files.

The target computes a SHA-256 checksum into a property, writes a *.sha256 file in GNU format, verifies it, then modifies the file and verifies again:

build.xml (checksum target)
<target name="checksum">
  <mkdir dir="${build.dir}"/>
  <copy file="data/stations.csv" todir="${build.dir}/ck"/>
  <checksum file="${build.dir}/ck/stations.csv" algorithm="SHA-256" property="stations.sha256"/>
  <echo>sha256=${stations.sha256}</echo>
  <checksum file="${build.dir}/ck/stations.csv" algorithm="SHA-256" fileext=".sha256" format="MD5SUM"/>
  <loadfile srcfile="${build.dir}/ck/stations.csv.sha256" property="sumfile"/>
  <echo>${sumfile}</echo>
  <checksum file="${build.dir}/ck/stations.csv" algorithm="SHA-256" fileext=".sha256" format="MD5SUM" verifyproperty="ck.ok1"/>
  <echo>verify unchanged: ${ck.ok1}</echo>
  <echo file="${build.dir}/ck/stations.csv" append="true">XXX,tampered,0,0,
</echo>
  <checksum file="${build.dir}/ck/stations.csv" algorithm="SHA-256" fileext=".sha256" format="MD5SUM" verifyproperty="ck.ok2"/>
  <echo>verify tampered: ${ck.ok2}</echo>
</target>
     [echo] sha256=37a3148aacc8e1738a9c923806fd0a973c61b955f404c9c5e1af721bebe7baa7
     [echo] 37a3148aacc8e1738a9c923806fd0a973c61b955f404c9c5e1af721bebe7baa7 *stations.csv
     [echo] verify unchanged: true
     [echo] verify tampered: false

The digest equals the one printed by the operating system’s tool, shasum -a 256 data/stations.csv: 37a3148aacc8e1738a9c923806fd0a973c61b955f404c9c5e1af721bebe7baa7. The *stations.csv form in the file is what shasum -a 256 -c (binary mode) reads, so the file can be checked outside Ant.

The extension keeps the case of the algorithm name. With a nested fileset and algorithm="SHA-256" and no fileext:

$ ls build/ck2
stations.csv
stations.csv.SHA-256

The manual warns about exactly this: ask for SHA1 and you get .SHA1, ask for sha1 and you get .sha1. On a case-insensitive file system (the macOS default, used here) two runs with different spellings write the same file, so pick one spelling or set fileext explicitly. Use checksums to verify downloads, as in the get example on Network & Remote Tasks, and to publish them with your release; the wider picture, including signatures and Gradle’s dependency verification, is on Supply Chain Security.

buildnumber

buildnumber reads a number from a file (build.number in the working directory by default), sets the property build.number to it (0 when the file is missing), increments it and writes it back. The file attribute names another file. The propertyfile task gives finer control (other property names, number formats).

Because the property is immutable, a second buildnumber in the same build does not change build.number, although it still increments the file:

build.xml (buildnumber target)
<target name="buildnumber">
  <buildnumber file="${build.dir}/build.number"/>
  <echo>build.number=${build.number}</echo>
</target>

Running the target twice in one build (ant buildnumber buildnumber; Ant executed it twice, as the output shows), starting from no file, is the same as having two buildnumber tasks:

     [echo] build.number=0
     [echo] build.number=0

$ cat build/build.number
#Build Number for ANT. Do not edit!
#Fri Oct 16 11:45:02 CEST 2026
build.number=2

Both messages print 0, yet the file holds 2. The first call set the property to 0 and wrote 1; the second could not change the property and wrote 2. Run the task once per build, early, and read the property afterwards. A build number kept in a file that is committed to version control makes every build a change; many projects prefer a CI-provided number passed as a property.

hostinfo

hostinfo sets NAME, DOMAIN, ADDR4 and ADDR6 for a host (the local machine by default), with an optional prefix. If the host cannot be found, the values fall back to the name given, localhost/localdomain, 0.0.0.0 or 127.0.0.1, and :: or ::1. It is useful for host-stamped file names and for writing the build machine into a manifest. Run for localhost so no real host name appears:

build.xml (hostinfo target)
<target name="hostinfo">
  <hostinfo prefix="local" host="localhost"/>
  <echo>local.NAME=${local.NAME} local.DOMAIN=${local.DOMAIN} local.ADDR4=${local.ADDR4} local.ADDR6=${local.ADDR6}</echo>
</target>
     [echo] local.NAME=localhost local.DOMAIN=localdomain local.ADDR4=127.0.0.1 local.ADDR6=0:0:0:0:0:0:0:1

The manual’s own example resolves www.apache.org and was not run here, because it would query the network.

diagnostics

diagnostics runs Ant’s -diagnostics report inside the build, which helps when Ant is started from an IDE and you need to know what it can see. The same report is printed by ant -diagnostics. The report has these sections (taken from a real run; the content of the long ones, which contain paths and system properties of the machine, is not reproduced): Implementation Version, ANT PROPERTIES, ANT_HOME/lib jar listing, USER_HOME/.ant/lib jar listing, Tasks availability, XML Parser information, XSLT Processor information, Symlinking information, System properties, Temp dir, Locale information and Proxy information.

The most useful section is the task availability list. On the test machine, with no extra libraries installed, it printed:

[diagnostics]  Tasks availability
[diagnostics] -------------------------------------------
[diagnostics] sshsession : Missing dependency com.jcraft.jsch.Logger
[diagnostics] scp : Missing dependency com.jcraft.jsch.Logger
[diagnostics] image : Missing dependency javax.media.jai.PlanarImage
[diagnostics] jdepend : Missing dependency jdepend.textui.JDepend
[diagnostics] xz : Missing dependency org.tukaani.xz.FilterOptions
[diagnostics] sshexec : Missing dependency com.jcraft.jsch.Logger
[diagnostics] ftp : Missing dependency org.apache.commons.net.ftp.FTPConnectionClosedException
[diagnostics] A task being missing/unavailable should only matter if you are trying to use it

This is the quickest way to find out which JAR a task is missing; the network tasks in the list are the ones described on Network & Remote Tasks.

antversion

antversion stores the running Ant’s version in a property (property, required as a task) and can check it: atleast or exactly (format major.minor.point). It is also a condition. The property is set only if the check passes. Use it to fail early when a build needs a task or attribute from a newer Ant:

build.xml (antversion target)
<target name="antversion">
  <antversion property="ant.is.recent" atleast="1.10.14"/>
  <antversion property="ant.version.found"/>
  <echo>antversion=${ant.version.found} atleast1.10.14=${ant.is.recent}</echo>
  <condition property="ant.exactly.1.10.18">
    <antversion exactly="1.10.18"/>
  </condition>
  <echo>exactly 1.10.18: ${ant.exactly.1.10.18}</echo>
  <antversion property="never" atleast="1.11.0"/>
  <echo>atleast 1.11.0: ${never}</echo>
</target>
     [echo] antversion=1.10.18 atleast1.10.14=1.10.18
     [echo] exactly 1.10.18: true
     [echo] atleast 1.11.0: ${never}

The last line shows the unset property left as written. To turn a missing minimum version into an error, combine it with fail and unless:

<antversion property="ant.ok" atleast="1.10.18"/>
<fail unless="ant.ok" message="Ant 1.10.18 or later is required (CVE-2026-78254)"/>

whichresource

whichresource finds a class (class) or resource (resource) on the supplied classpath (classpath, classpathref or a nested classpath) or on the system class path, and sets property to its URL if found. It answers "which JAR does this class come from?", the common cause of NoSuchMethodError and duplicate-library problems.

build.xml (whichresource target)
<target name="whichresource">
  <whichresource property="ant.project.loc" class="org.apache.tools.ant.Project"/>
  <echo>${ant.project.loc}</echo>
  <whichresource property="missing.loc" class="io.tidepool.NoSuchClass"/>
  <echo>missing: ${missing.loc}</echo>
</target>
     [echo] jar:file:/.../apache-ant-1.10.18/lib/ant.jar!/org/apache/tools/ant/Project.class
     [echo] missing: ${missing.loc}

antstructure

antstructure writes a DTD describing every task and type Ant currently knows (output is required). The manual cautions that it is not a real DTD for build files, because the same element can take different attributes in different places, that it does not know which attributes are required, and that it only knows what is defined now (add your own definitions with taskdef or typedef first). A custom structure printer (an implementation of org.apache.tools.ant.taskdefs.AntStructure.StructurePrinter declared with typedef and nested in the task, Ant 1.7) can emit another format.

build.xml (antstructure target)
<target name="antstructure">
  <mkdir dir="${build.dir}"/>
  <antstructure output="${build.dir}/project.dtd"/>
</target>

On 1.10.18 the file was 210,814 bytes. Its entry for echo shows the style (every attribute #IMPLIED; the file as a whole has 4,499 #IMPLIED and only 2 #REQUIRED markers):

<!ELEMENT echo (#PCDATA)>
<!ATTLIST echo
          id ID #IMPLIED
          level (error | warn | warning | info | verbose | debug) #IMPLIED
          force %boolean; #IMPLIED
          encoding CDATA #IMPLIED
          append %boolean; #IMPLIED

(Only the first lines of the ATTLIST are shown.) Treat the file as documentation of what exists, not as a validating schema; the elements of a build file itself are covered on Build File Structure.

sleep

sleep pauses the build. The time is the sum of hours, minutes, seconds and milliseconds; individual values may be negative if the total is positive. failonerror controls whether an error (for example an interruption) breaks the build. The manual notes that sleep times are hints: small values may be rounded up, and clock granularity makes measuring them unreliable.

<target name="sleep">
  <sleep seconds="1" milliseconds="500"/>
</target>
sleep:
BUILD SUCCESSFUL
Total time: 1 second

Ant reports whole seconds, so the 1.5 seconds shows as 1. A fixed sleep is a poor way to wait for a service: use waitfor with a condition and a timeout, described on Conditions & Control Flow.

The same jobs in Maven and Gradle

Job Maven Gradle

Print a message

maven-antrun-plugin with <echo>, or the plugin’s own logging

println or logger.lifecycle in the build script

Ask the user

Nothing in the core; use -D properties and -B

A -P property read in the script (providers.gradleProperty)

Build date

maven.build.timestamp, and project.build.outputTimestamp for reproducible archives

Reproducible archives by default since Gradle 9.0

Checksum files

Generated for installed and deployed artifacts by the install and deploy machinery

Generated for published artifacts by the publishing plugins

Run Ant tasks as they are

maven-antrun-plugin

The ant object in the build script

The Maven and Gradle cells are summaries; the details live on the pages listed in Comparing Ant, Maven & Gradle, and the Gradle way of calling these Ant tasks is on Ant integration.

Where the books and older build files are outdated

  • The tstamp examples in older books use the current time only. Ant 1.10.2, 1.10.8 and 1.10.18 added ant.tstamp.now, SOURCE_DATE_EPOCH support and the UTC rule for it; use them for reproducible builds.

  • checksum examples default to MD5 and show .MD5 files; use SHA-256 or stronger and set fileext explicitly.

  • The input task’s long-standing complaint (passwords echoed on the console) was addressed in Java 6, and Ant 1.7.1 and 1.8 added the secure handler; the advice to "just prompt for the password" in older material should use it.

  • Advice that -noinput lets defaultvalue answer for you is wrong, as shown above: it makes the read fail.

  • diagnostics did not exist before Ant 1.7.0; build files written for earlier versions test for problems by hand.

References