Перестроить муравей, когда файлы были удалены

Я строю проекты с Ant и хочу вызвать перекомпиляцию, когда источники изменились. Это в основном работает автоматически со стандартной задачей javac, за исключением одного случая:

Когда исходный файл удален, но никаких других изменений не сделано, ничего не перекомпилируется.

Даже если это приведет к невозможности чистой компиляции проекта без ошибок, сборка все равно будет успешной из-за оставшихся файлов классов.

Делать чистую сборку каждый раз не вариант, так как у нас есть 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-файл имеет соответствующий файл класса, в разнице будет две записи для файла класса.

Это была еще одна попытка:

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

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>
Другие вопросы по тегам