我正在使用Ant构建项目,并希望在源代码发生更改时进行重新编译。这主要与标准javac任务一起自动工作,除了一种情况:
当删除源文件但没有进行其他更改时,不会重新编译任何内容
即使这会使项目无法干净无错误地编译,但由于遗留的类文件,构建仍然会成功。
每次都进行干净的构建不是一种选择,因为我们有137个依赖模块需要很长时间才能构建。此外,我们不希望在完全清理后重试每一个失败的CI构建,看看它是否能正常工作。
这似乎是javac任务应该支持的一个非常基本的东西,但我没有看到任何看起来有用的属性。在尝试了我能想到的任何其他东西后,我都做不好:
找出是否有任何遗留类:
<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文件有一个相应的类文件,那么该类文件将有两个条目存在差异。
这是另一次尝试:
<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>
问题是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>