Ant自定义条件typedef:确保编译类在构建期间可用(鸡和鸡蛋)

时间:2012-12-03 07:35:29

标签: java ant ivy

我已经创建了几个Custom Conditions,用于我项目的构建过程。细节可能不是很相关,但它们的逻辑很少,并且用于有条件地抑制ivy:resolve任务的运行(这是一个好主意是否是一个单独的问题,但对于我的项目,这需要为构建过程增加12秒甚至只是读取缓存。)

我遇到的问题是,第一次构建项目时,这些条件的实现(现在只使用它们存在于项目的主源代码树中)是不可用的。在这种情况下,我想要运行<ivy:resolve>,以便我可以完全构建项目(包括condition实现),然后condition实现可供以后使用

我试图通过希望or条件懒惰并且在那里使用available元素来实现这一点:

<typedef onerror="report" name="olderormissing" classname="myproject.buildutils.FileOlderOrMissingCondition" classpath="${main.jar}" />
<condition property="ivy.needs.refresh">
    <or>
        <!-- fetch new if we don't have the helper classes -->
        <not><available classname="myproject.buildutils.FileOlderOrMissingCondition" /></not>
        <!-- only fetch ivy deps hourly -->
        <olderormissing file="${ivy.build.record}" threshold="3600" />
    </or>
</condition>

<!-- Ivy task using the above property -->
<target name="resolve" description="--> retrieve dependencies with ivy" if="${ivy.needs.refresh}">
    <ivy:retrieve symlink="true" sync="false" pattern="${jars.dir}/[conf]/[artifact].[ext]" keep="true" log="download-only" />
</target>

我曾希望如果实现类不可用,or条件将从第一个条件吐出,并忽略缺少的类型。但是,这不起作用,而是以“或不支持嵌套的”oldormissing“元素”失败。也许这种做法是徒劳的?

理想情况下,我希望Ant能够处理这个问题,而无需将条件实现拆分为需要显式手动预编译的单独或子项目(如果我可以让Ant自动编译子项目,那会很棒,但是我无法找到一种方法来尽早发生这种情况,以满足需求typedef)。对于在类中实现的两行逻辑,一个单独的项目肯定会有点过分。

This related question on taskdefs似乎相关,但并不完全适用于此用例AFAICT。

2 个答案:

答案 0 :(得分:0)

好的,我从Ant taskdef tutorial得到了一些线索。 typedefcondition可以在设置适当属性的目标中更好地使用,但仅在设置前体类时调用。我们可以设置一个特殊的bootstrapping目标,仅在相关的Ant扩展类上运行javac。我们还需要在单独的任务中进行实际的检索/解决,因此我们可以强制它独立于条件的值发生。

<condition property="ant.extensions.missing">
    <not>
        <available classname="readproject.ant.FileOlderOrMissingCondition" classpath="${main.jar}" />
    </not>
</condition>

<target name="ant-bootstrapping" depends="init" if="ant.extensions.missing" description="(internal) build the project-internal Ant extensions if needed">
    <antcall target="force-resolve" />
    <javac srcdir="${src}" destdir="${build}" classpathref="build.classpath" includeantruntime="false" includes="**/ant/**/*.java" debug="on"/>
</target>


<!-- need to set up the conditions internally, since the custom types are defined in the project itself -->
<target name="pre-resolve" depends="ant-bootstrapping" description="(internal) set up internal variables to determine if Ivy needs refreshing">
    <typedef onerror="report" name="olderormissing" classname="myproject.ant.FileOlderOrMissingCondition" classpath="${build}" />
    <condition property="ivy.needs.refresh">
        <!-- only fetch ivy deps hourly -->
        <olderormissing file="${ivy.build.record}" threshold="3600" />
    </condition>
</target>

<target name="resolve" description="retrieve dependencies with ivy" if="ivy.needs.refresh" depends="pre-resolve">
    <antcall target="force-resolve" />
</target>

<target name="force-resolve" description="Force retrieval of Ivy dependencies">
    <ivy:retrieve symlink="true" sync="false" pattern="${jars.dir}/[conf]/[artifact].[ext]" keep="true" log="download-only" />
    <ivy:report todir="${ivy.reports}" />
    <touch file="${ivy.build.record}" />
</target>

我的主编译目标依赖于resolve目标,就像以前一样,无论是在干净安装还是刷新,所有内容都能令人满意地构建,但Ivy不会让我的构建时间不必要地慢24倍。

(我还应该注意,我在这里使用的是available而不是typefound,因为后者不允许我指定类路径,因此没有多大用处)

答案 1 :(得分:0)

为什么不用常春藤来填充lib目录,然后只运行常春藤来填充它。

<available file="lib" type="dir" property="local.lib.present"/>

<target name="resolve" unless="local.lib.present">
    <ivy:retrieve symlink="true" pattern="lib/[conf]/[artifact].[ext]"/>
</target>

..

<target name="clean">
    <delete dir="build"/>
</target>

<target name="clean-all" depends="clean">
    <delete dir="lib"/>
    <ivy:clean-cache/>
</target>

拥有一个“清理所有”目标,清除所有缓存并实现干净的构建非常重要。

我看到你正在使用符号链接选项,该选项解决了有关本地构建缓存方法所占用空间的可能问题。