Как могут муравьиные jar-файлы ant compile-and-jar, т. Е. Чтобы MD5 совпадал, если только не изменились .java (и, следовательно, .class)? - PullRequest
12 голосов
/ 01 сентября 2011

Сводка

Как заставить муравей многократно генерировать идентичные байту файлы jar из одних и тех же файлов .class?

Фон

Наш процесс сборки выполняет следующее:

  1. получает файлы определения веб-сервисов (wsdl) из исходного хранилища другого приложения
  2. запускает wsdl2java для генерации файла .java для использования.клиентами веб-служб (т.е. нашим приложением)
  3. компилирует java-файлы
  4. генерирует файл .jar из выходных данных компилятора
  5. проверяет файл jar "артефакта" в исходном кодеcontrol

Примечание. Мы делаем этот последний шаг, чтобы разработчики имели доступ к этому файлу JAR без его сборки.Мы используем специальный «производный» каталог, чтобы отличить источник от артефактов.

Проблема

Мы не можем заставить ant генерировать идентичные байту файлы .jar, даже еслиисходные файлы не изменились, т. е. каждая сборка генерирует немного разные jar (с разными MD5)

Я проверил интернет и нашел этот вопрос около 5 лет назад:

Если яскомпилируйте некоторый код и создайте jar-файл и связанный с ним файл md5, используя ANT, контрольная сумма в файле md5 каждый раз отличается, даже если код не изменился.Есть идеи, почему это так, как это можно обойти?Я подозреваю, что где-то есть информация о метках времени.

http://www.velocityreviews.com/forums/t150783-creating-new-jar-same-code-different-md5.html

В ответах я попытался сделать следующее:

  1. settingотметка времени «0» во всех файлах .class перед jarring
  2. с указанием файла манифеста и установкой отметки времени 0 для этого манифеста

[Примечание: этот второй шаг кажется неэффективным,См. Ниже]

После каждой сборки файл .jar still имеет различную сумму MD5.

CSI: файл JAR

Я не испортил и не исследовал, и содержимое и метки jar совпадают между "разными" банками за одним исключением: разные метки времени для META-INF / MANIFEST.MF.

Код

   <-- touch classes and manifest to set consistent timestamp across builds -->
   <touch millis="0">
    <fileset dir="${mycompany.ws.classes.dir}"/>
   </touch>
   <touch millis="0" file="mymanifest.mf"/>

   <jar destfile="${derived.lib.dir}/mycompanyws.jar"
        manifest="mymanifest.mf"
        basedir="${mycompany.ws.classes.dir}"
        includes="**/com/mycompany/**,**/org/apache/xml/**" 
    />

Другие параметры

Мы могли бы использовать более необычное программирование длятолько проверяйте в файле .jar, если файлы .java были изменены.

Ответы [ 3 ]

4 голосов
/ 09 января 2012

Я столкнулся с подобной проблемой, но немного другой. Я решил поделиться этим здесь, поскольку это относится к теме вопроса. Чтобы создать два идентичных байту файла JAR с цифровой подписью в разное время, необходимо учитывать следующие моменты:

  • Метки времени: **/*.class файлы должны иметь одинаковую метку времени (java.util.zip.ZipEntry.setTime(long)). Кроме того, файл META-INF/MANIFEST.MF и файлы сертификатов (*.RSA, *.DSA и *.SF) добавляются в файл JAR с отметкой времени «сейчас». Таким образом, даже если вы решите не скомпилировать классы и использовать уже скомпилированные классы (т. Е. Классы с исходной меткой времени JAR), ваш результирующий JAR будет двоичным другим.
  • MANIFEST.MF Порядок записей: Обратите внимание, что пары ключ-значение в файле MANIFEST.MF представлены как java.util.HashMap, что "does not guarantee that the order will remain constant over time.". Таким образом, вы можете столкнуться с другой двоичной разницей при подписании файлов JAR с использованием инструмента JDK v5 и JDK v6 jarsigner, так как порядок записей MANIFEST.MF может измениться (http://stackoverflow.com/questions/1879897/order-of-items-in-a-hashmap-differ-when-the-same-program-is-run-in-jvm5-vs-jvm6).

Так что в принципе есть два уровня проблемы. Во-первых, инструмент JAR / ZIP, который упаковывает файлы с их временными метками файловой системы и, таким образом, создает двоичные разные JAR-файлы для одного и того же набора классов Java, которые являются двоичными равными, но были скомпилированы в другое время. Во-вторых, средство подписи JAR, которое изменяет файл META-INF/MANIFEST-MF и добавляет дополнительные файлы в архив JAR (сертификаты и контрольные суммы файлов классов).

Решением может быть пользовательская подписавшая JAR, которая устанавливает временные метки всех элементов файла JAR на постоянное время и упорядочивает записи в файле MANIFEST.MF (например, по алфавиту). На данный момент, насколько мне известно, это единственный способ создания двух байт-идентичных файлов JAR с цифровой подписью в разные моменты времени.

1 голос
/ 01 сентября 2011

Поскольку jar - это инкогнито zip-файла, вы можете попробовать использовать задачу zip, чтобы вручную добавить файл манифеста в META-INF/.Надеемся, что это обходит любую внутреннюю магию, связанную с обработкой манифеста с помощью задачи jar.

Просто примечание, поскольку наличие одинаковых MD5 имеет решающее значение, я бы порекомендовал добавить тест на работоспособность как часть сборкиНапример, скомпилировать какой-нибудь специальный «фиктивный» код, который никогда не превратится в банку, и проверить, что MD5 банки равен ожидаемому.Это защитит сборку от неожиданных изменений (например, после обновления до ant, JRE, OS, изменения часового пояса и т. Д.)

0 голосов
/ 20 марта 2013

Была такая же проблема, приземлилась на этой странице. Приведенный выше ответ Джири Патера был очень полезен для понимания того, почему я не смог получить одинаковые md5 суммы, которые, как я ожидал, представляли собой два одинаковых файла, после подписи и повторного размещения файлов jar.

Это решение, которое я использовал вместо:

jar -tvf $ JARFILE | grep -v META-INF | perl -p -e's / ^ \ s + (\ d +). * \ s + ([\ w] +) / $ 1 $ 2 / g '| md5sum

Это не дает 100% уверенности в том, что банки эквивалентны, но дает достаточно надежное указание.

Он принимает список всех файлов в jarfile минус файлы META_INF, анализирует размер файла и имя файла, а затем запускает текст с размерами файлов и именами файлов по алгоритму md5sum.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...