2

我正在使用 Ant 构建项目,并希望在源更改时重新编译。这主要适用于标准 javac-task,除了一种情况:

当源文件被删除但没有进行其他更改时,不会重新编译任何内容。

即使这会使项目无法干净无误地编译,由于遗留的类文件,构建仍然会成功。

每次都进行干净的构建不是一种选择,因为我们有 137 个依赖模块需要很长时间才能构建。此外,我们不想在完全清理后重试每个失败的 CI 构建以查看它是否会工作。

这似乎是 javac-task 应该支持的非常基本的东西,但我没有看到任何看起来有用的属性。在尝试了我能想到的任何其他方法后,我无法做到:

找出是否有任何剩余的课程:

<difference id="targets.todelete">
  <union>
    <mappedresources>
      <fileset dir="${src.java.dir}" includes="**/*.java" />
      <globmapper from="*.java" to="*.class" />
    </mappedresources>
  </union>
  <union>
    <fileset dir="${build.java.dir}" includes="**/*.class" />
  </union>
</difference>

以上不起作用,差异实际上似乎更像是一个工会。如果一个java-file有一个对应的class-file,那么这个class文件的区别就会有两个入口。

这是另一个尝试:

<fileset id="del" dir="${src.java.dir}" includes="**/*.java" casesensitive="false" defaultexcludes="false">
  <different targetdir="${build.java.dir}" ignoreFileTimes="true">
    <globmapper from="*.java" to="*.class" />
  </different>
</fileset>

我试图找到所有不同的文件,但结果或多或少与上面相同。

当我尝试不使用映射器时,在 和 中使用部分重叠的源文件集,它确实按预期工作。这使我怀疑与资源差异有关的任何事情都不能很好地与映射文件一起使用。

这里有人知道如何以任何其他方式实现我的目标吗?

更新: 这是正确处理内部类的有效解决方案。我需要多个源目录,这使事情变得更加复杂。

<!-- find class files with without corresponding source files -->
<fileset id="src1" dir="${src.java.dir}" includes="**/*.java" />
<fileset id="src2" dir="${build.generated.java.dir}" includes="**/*.java" erroronmissingdir="no" />
<fileset id="src3" dir="${generated.java.dir}" includes="**/*.java" erroronmissingdir="no" />

<fileset id="build" dir="${build.java.dir}" includes="**/*.class" erroronmissingdir="no" />
<difference id="targets.todelete">
  <resourcelist>
    <string>${toString:src1};${toString:src2};${toString:src3}</string>
    <filterchain>
      <tokenfilter>
        <replacestring from=";" to="${line.separator}" />
        <replacestring from=".java" to=".class" />
      </tokenfilter>
      <ignoreblank/>
      <prefixlines prefix="${build.java.dir}/" />
    </filterchain>
  </resourcelist>
  <resourcelist>
    <string>${toString:build}</string>
    <filterchain>
      <tokenfilter>
        <replacestring from=";" to="${line.separator}" />
        <!-- map inner classes back to their java files -->
        <replaceregex pattern="\$.*(.class)" replace="\1" flags="gi"/>
      </tokenfilter>
      <prefixlines prefix="${build.java.dir}/" />
    </filterchain>
  </resourcelist>
</difference>

<if>
  <not>
    <length string="${toString:targets.todelete}" trim="true" length="0" />
  </not>
  <then>
    <echo>Source files were deleted, cleaning output to force re-build!</echo>
    <delete dir="${build.java.dir}" />
    <delete dir="${build.test.java.dir}" />
    <delete dir="${cobertura_html_report.dir}" />
  </then>
</if>
4

1 回答 1

1

问题是difference资源集合根据绝对路径而不是相对路径来区分。并且没有办法让 Ant 将映射器应用到完整的绝对路径。它仅适用于资源名称。

解决方案是将文件集序列化为字符串列表,对该字符串列表进行适当的更改,并将它们解释为不同的文件。

这是建议的 build.xml 片段,它应该计算正确的类文件列表:

<fileset id="src" dir="${src.java.dir}" includes="**/*.java"/>

<fileset id="build" dir="${build.java.dir}" includes="**/*.class"/>

<difference id="targets.todelete">
    <resourcelist>
        <string>${toString:src}</string>
        <filterchain>
            <tokenfilter>
                <replacestring from=";" to="${line.separator}" />
                <replacestring from=".java" to=".class" />
            </tokenfilter>
            <prefixlines prefix="${build.java.dir}" />
        </filterchain>
    </resourcelist>
    <resourcelist>
        <string>${toString:build}</string>
        <filterchain>
            <tokenfilter>
                <replacestring from=";" to="${line.separator}" />
            </tokenfilter>
            <prefixlines prefix="${build.java.dir}" />
        </filterchain>
    </resourcelist>
</difference>
于 2013-06-26T23:34:45.717 回答