41

仅当满足条件时,我才需要在特定目标中执行 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}所以我在这个目标中的下一个任务是一个 exec 任务,只有当它是 false时才应该执行。正如我所说,我不想在目标中添加单个任务来使用除非属性。

4

4 回答 4

58

Ant 目标可以有一个可选的iforunless子句。if这意味着仅当属性已设置、使用子句或未使用unless子句1设置时才执行任务。有趣的是,在第一次执行任何相关任务if检查orunless子句。

这意味着,您可以在标准 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 执行 Target 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可能会引起很多混乱。我见过开发人员将属性设置为falseor no,然后想知道为什么目标实际上正在执行,因为if子句设置为 false。

于 2013-01-28T17:07:15.660 回答
13

版本 1.9.1 (*)开始,如果您在项目元素中声明必要的命名空间,则ant 支持在任何任务上以更细粒度的方式使用if- 和 unless- 条件。

(*)请使用最新版本的 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:\test\ant\taskcondition\build.xml
foo:
     [echo] D:\test\ant\taskcondition
     [echo] GOOD
BUILD SUCCESSFUL
Total time: 191 milliseconds
于 2015-08-28T09:57:17.110 回答
6

如果您想要“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>
于 2014-02-21T17:54:18.710 回答
1

在某些情况下,您无法使 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 [ &quot;${myprop}&quot; != &quot;$${myprop}&quot;] || [&quot;${tag_exists}&quot; != &quot;true&quot; ]; then my-bash-command _arguments_; fi" />
</exec>

在上面的my-bash-command说明了您要执行的命令/程序,并且参数说明了该命令的参数。

请注意,如果未设置myprop,则 ${myprop} 将简单地计算为字符串“$”+“{”+“myprop”+“}”(即“${myprop}”),因此我们有将myprop的值与该字符串进行比较。

另一方面,当设置myprop时,它的值可能是字符串true/false,因此为了检查是否满足我们的条件,我们应该将myprop字符串true(或您可能拥有的任何值)进行比较。

Conclusion: using the Ant's exec combined with the OS command IF we can execute arbitrary OS commands/programs without the need of another Ant target. Using the same logic as above the IF-like statement may be tweaked to work even on Windows.

于 2015-09-12T11:37:57.647 回答