只有在满足条件的情况下,我才需要在特定目标中执行 Ant 任务。
我找到了一种方法在目标级别定义条件,但不是在任务级别定义条件。我还发现了一个实现 IF 任务的贡献。
我的问题是,您是否知道通过标准 Ant 任务实现这一目标的方法?
更长的解释:我正在尝试启动Tomcat服务器,以防它停止。为了检测它是否已停止,我使用以下代码:
<echo message="Checking whether Tomcat is running"/>
<condition property="tomcat.running">
<socket server="${tomcat.host}" port="${tomcat.port}"/>
</condition>
因此,我在此目标中的下一个任务是一个执行任务,仅当${tomcat.running}
为假时才应执行。正如我所说,我不想在目标中添加单个任务来使用 except 属性。
Ant 目标可以具有可选的 if
或 unless
子句。这意味着仅当使用 if
子句设置属性或使用unless
子句1 取消设置属性时,才执行任务。有趣的是,if
或unless
子句是在首次执行任何依赖任务后检查的。
这意味着,只有在满足特定条件时,您才能在标准 Ant 中执行此操作,作为执行 Ant 任务的一种方式:
<target name="test.if.tomcat.is.running">
<condition property="tomcat.running">
<socket server="${tomcat.host}" port="${tomcat.port}"/>
</condition>
</target>
<target name="my.target"
if="tomcat.running"
depends="test.if.tomcat.is.running">
<yaddah/>
<yaddah/>
<yaddah/>
</target>
指定希望 Ant 执行目标my.target
。Ant 注意到my.target
取决于test.if.tomcat.is.running
目标,并将首先执行该目标。如果 Tomcat 实际正在运行,test.if.tomcat.is.running
任务将设置 tomcat.running
属性。否则,不会设置该属性。
最后,Ant 将返回到my.target
目标并查看是否设置了属性 tomcat.running
,并且只有在设置了目标my.target
时才执行目标。
或者,您可以使用 Ant-contrib 任务,它可以使您的整个构建过程更容易理解。
如果你想走Ant-Contrib路线,有一种简单的方法来设置Ant-Contrib,所以Ant-contrib jar实际上是你项目的一部分。如果有人从版本控制系统中签出你的项目,他们也会得到 Ant-contrib jar,因此不必自己安装 Ant-Contrib。
下载 Ant-Contrib jar,并将其放入项目根目录中名为 antlib/ac
的目录中。该antlib
可用于各种可选任务jar,例如Findbugs或PMD。只需将每个可选的 Ant jar 放在它们自己的目录中antlib
(就像我把 Ant-Contrib 放在 ac
目录下一样)。
然后,在 build.xml
中,您可以通过以下方式指定 Ant-Contrib 任务:
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<fileset dir="${basedir}/antlib/ac"/>
</classpath>
</taskdef>
现在,您可以使用 Ant-Contrib 任务,而不必担心它们是否安装在特定计算机上。您签出您的项目,您可以自动访问这些任务。
1.没错,if/unless
子句检查属性是否已设置,而不是true
/false
,这可能会导致很多混乱。我见过开发人员将属性设置为 false
或 no
,然后想知道为什么目标实际上正在执行,因为 if
子句设置为 false。
从版本 1.9.1(*) 开始,如果您在项目元素中声明必要的命名空间,则 ant 支持在任何任务上以更细粒度的方式具有 if 和 un-除非条件。
(*) 请使用最新版本的 ant(撰写本文时为 1.9.6),因为 1.9.1 版包含 WRT 这个新功能的缺陷,正如用户@Rebse善意指出的那样。
在下面的示例中,您可以尝试注释/取消注释属性...
<project name="test"
xmlns:if="ant:if"
xmlns:unless="ant:unless">
<property name="is.good" value="hohoho"/>
<!--property name="hide.base" value="boo"/-->
<target name="foo">
<echo unless:set="hide.base">${basedir}</echo>
<echo if:set="is.good">GOOD</echo>
</target>
</project>
。并观察如下输出:
Buildfile: D:testanttaskconditionbuild.xml
foo:
[echo] D:testanttaskcondition
[echo] GOOD
BUILD SUCCESSFUL
Total time: 191 milliseconds
如果你想要一个"if else"类型的实现:
<target name="test.if.tomcat.is.running">
<condition property="tomcat.running" value="true" else="false">
<socket server="${tomcat.host}" port="${tomcat.port}"/>
</condition>
</target>
<target name="my.target.running"
if="${tomcat.running}"
depends="test.if.tomcat.is.running">
...
</target>
<target name="my.target.ifnotrunning"
unless="${tomcat.running}"
depends="test.if.tomcat.is.running">
.....
</target>
在某些情况下,您无法使 Ant 目标依赖于另一个 Ant 目标,因为 if 应根据在 exec 之前初始化的值进行评估(我可以提供一个清晰的例子,但为了简单起见,我不会)。
在类Unix系统上,替代方案(在某些情况下更可取)如下:
<!-- the property that contains the value to be checked agains IF -->
<property name="myprop" value="true"/>
<!-- the Ant's exec combined with OS-IF command -->
<exec executable="bash">
<arg value="-c" />
<arg value="if [ "${myprop}" != "$${myprop}"] || ["${tag_exists}" != "true" ]; then my-bash-command _arguments_; fi" />
</exec>
在上面的 my-bash-command 中,说明了您要执行的命令/程序,参数说明了该命令的参数。
请注意,如果未设置 myprop,则 ${myprop} 将被简单地计算为字符串 "$" + "{" + "myprop" + "}" (即。${myprop}"),因此我们必须将 myprop 的值与该字符串进行比较。
另一方面,当设置myprop时,它的值可能是字符串true/false,因此为了检查是否满足我们的条件,我们应该将myprop与字符串true(或您可能拥有的任何值)进行比较。
结论:将 Ant 的可执行文件与操作系统命令 IF 结合使用,我们可以执行任意操作系统命令/程序,而无需另一个 Ant 目标。使用与上述相同的逻辑,可以调整类似IF的语句,使其即使在Windows上也能工作。