3

我创建了几个自定义条件用于我的项目的构建过程。细节可能不是很相关,但它们的逻辑很少,用于有条件地抑制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条件会从第一个条件中吐出 true 并忽略缺失的类型。但是,这不起作用,而是以“或不支持嵌套的“olderormissing”元素失败。” 也许这种方法将是徒劳的?

理想情况下,我希望 Ant 处理此问题,而无需将条件实现拆分为需要显式手动预编译的单独或子项目(如果我可以让 Ant 自动编译子项目,那就太好了,但我可以'没有办法让这种情况发生得足够早,以便满足需求typedef)。对于在类中实现的两行逻辑来说,一个单独的项目肯定感觉有点矫枉过正。

这个关于 taskdefs 的相关问题似乎是相关的,但并不完全适用于这个用例 AFAICT。

4

2 回答 2

0

好的,我从Ant taskdef 教程中得到了一些线索。typedefs 和s 可以在condition设置适当属性的目标中更好地使用,但仅在设置前体类时调用。我们可以设置一个特殊的引导目标,javac只在相关的 Ant 扩展类上运行。我们还需要让实际的检索/解析发生在一个单独的任务中,这样我们就可以强制它独立于条件的值发生。

<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因为后者不允许我指定类路径,所以用处不大)

于 2012-12-04T01:31:19.440 回答
0

为什么不直接使用 ivy 来填充 lib 目录,然后只运行 ivy 来填充它。

<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>

拥有一个清除所有缓存并启用干净构建的“clean-all”目标非常重要。

我看到您正在使用 symlink 选项,该选项解决了有关此本地构建缓存方法消耗的空间的可能问题。

于 2012-12-04T19:30:57.140 回答