-->

execute Ant task if TWO conditions are met

2019-01-27 16:34发布

问题:

The above ant script implements if dir_is_empty then git-clone else git-fetch using Ant-1.7.1 core statements:

<target name="update" depends="git.clone, git.fetch" />

<target name="check.dir">
  <fileset dir="${dir}" id="fileset"/>
  <pathconvert refid="fileset" property="dir.contains-files" setonempty="false"/>
</target>

<target name="git.clone" depends="check.dir" unless="dir.contains-files">
  <exec executable="git">
    <arg value="clone"/>
    <arg value="${repo}"/>
    <arg value="${dir}"/>
  </exec>
</target>

<target name="git.fetch" depends="check.dir" if="dir.contains-files" >
  <exec executable="git" dir="${dir}">
    <arg value="fetch"/>
  </exec>
</target>

(see my other post)


But how to implement a target enabled by two conditions?

if dir_does_not_exist or dir_is_empty then git-clone else git-fetch

my current attempt:

<target name="git.clone" 
        depends="chk.exist, chk.empty" 
        unless="!dir.exist || dir.noempty" >
  [...]
</target>

<target name="chk.exist">
  <condition property="dir.exist">
    <available file="${dir}/.git" type="dir"/>
  </condition>
</target>

[...]

I would prefer Ant-1.7.1 core statements. But I am open about other possibilities as Ant contrib, or embedded script... Feel free to post your ideas...

(See also question Execute ANT task just if a condition is met)

回答1:

Even when bound to Ant 1.7.1 you may combine your 3 chk targets into one, see the condition part in the snippet. Since Ant 1.9.1 (better use Ant 1.9.3 because of bugs in Ant 1.9.1 see this answer for details) it is possible to add if and unless attributes on all tasks and nested elements, so no extra target needed, f.e. :

<project xmlns:if="ant:if" xmlns:unless="ant:unless">

  <condition property="cloned" else="false">
    <and>
      <available file="${dir}/.git" type="dir" />
      <resourcecount when="gt" count="0">
        <fileset dir="${dir}/.git" />
      </resourcecount>
    </and>
  </condition>

  <exec executable="git" unless:true="${cloned}">
    <arg value="clone" />
    <arg value="${repo}" />
    <arg value="${dir}" />
  </exec>

  <exec executable="git" dir="${dir}" if:true="${cloned}">
    <arg value="fetch" />
  </exec>

</project>


回答2:

From the ant documentation on targets:

Only one propertyname can be specified in the if/unless clause. If you want to check multiple conditions, you can use a dependend target for computing the result for the check:

<target name="myTarget" depends="myTarget.check" if="myTarget.run">
     <echo>Files foo.txt and bar.txt are present.</echo>
</target>

<target name="myTarget.check">
     <condition property="myTarget.run">
         <and>
             <available file="foo.txt"/>
             <available file="bar.txt"/>
         </and>
     </condition>
</target>

Moreover, there were some discussions on dev@ant.apache.org and user@ant.apache.org mailing-lists:

  • Using multiple properties in the 'if' and 'unless' conditions (June 2006)
  • Support mutliple if and unless (August 2008)
  • Multiple conditions satisfying in an ant target (October 2008)

For example, the following target combines two properties (dir.exist and dir.noempty) to create another one (cloned) using operators <and> and <istrue> (many other operators are documented as <or>, <xor>, <not>, <isfalse>, <equals>, <length>).

<target name="chk" depends="chk.exist, chk.empty" >
  <condition property="cloned">
    <and>
      <istrue value="dir.exist"   />
      <istrue value="dir.noempty" />
    </and>
  </condition>
</target>

The above property "cloned" is used by targets git.clone and git.fetch as follows:

<target name="update" depends="git.clone, git.fetch" />

<target name="git.clone" depends="chk" unless="cloned" >
  <exec  executable="git" >
    <arg value="clone"   />
    <arg value="${repo}" />
    <arg value="${dir}"  />
  </exec>
</target>

<target name="git.fetch" depends="chk" if="cloned" >
  <exec executable="git" dir="${dir}">
    <arg value="fetch"/>
  </exec>
</target>

<target name="chk.exist" >
  <condition property="dir.exist" >
    <available file="${dir}" type="dir" />
  </condition>
</target>

<target name="chk.empty" >
  <fileset dir="${dir}" id="fileset" />
  <pathconvert refid="fileset" property="dir.noempty" setonempty="false" />
</target>