Как могут ant компилировать-и-jar байт-идентичные файлы jar, т.е. Так MD5 соответствует, если изменяется значение .java(и, следовательно, класс .class)?
Резюме
Как вы можете сделать ant несколько раз генерировать байт-идентичные файлы jar из тех же .class файлов?
Фон
Наш процесс сборки делает следующее:
- получает файлы определения веб-сервисов (wsdl) из другого репозитория источника приложения.
- запускает wsdl2java для создания файла .java для использования клиентами веб-сервиса (например, наше приложение)
- компилирует java файлы
- создает файл .jar из выходного файла компилятора
- проверяет файл артефакта в исходном элементе управления
Примечание. Мы делаем этот последний шаг, чтобы разработчики имели доступ к этому файлу jar без его создания. Мы используем специальный "производный" каталог, чтобы отличать источник от артефактов.
Проблема
Мы не можем получить ant для генерации байт-идентичных .jar файлов, даже если исходные файлы не изменились, т.е. каждая сборка генерирует несколько другую банку (с другим MD5)
Я проверил Интернет и нашел этот вопрос примерно через 5 лет назад:
Если я скомпилирую некоторый код и создаю jar и связанный файл md5 с помощью ANTконтрольная сумма в файле md5 отличается каждый раз, даже если код не изменился. Любая идея, почему это так, как можно обойти? Я подозреваю, что какая-то информация о временной отметке куда-то прибывает.
http://www.velocityreviews.com/forums/t150783-creating-new-jar-same-code-different-md5.html
В ответах я попытался сделать следующее:
- установите метку времени на "0" во всех файлах .class перед jarring
- указание файла манифеста, а также установление метки времени 0 для этого манифеста
[Примечание: этот второй шаг кажется неэффективным. См. Ниже]
После каждой сборки файл .jar по-прежнему имеет другую сумму MD5.
Файл CSI: 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/**"
/>
Другие параметры
Мы могли бы использовать fancier ant для программирования только в файле .jar, если изменились .java файлы.
Ответы
Ответ 1
Так как jar - это просто zip файл incognito, вы можете попробовать использовать задачу zip
, чтобы добавить файл манифеста под META-INF/
вручную. Надеюсь, что обходит любую внутреннюю магию, связанную с обработкой манифестной задачей в баночке.
Просто боковое примечание, так как похоже, что наличие равных MD5 является критическим, я бы рекомендовал вам добавить тест на здравомыслие как часть сборки, например, скомпилировать специальный "dummy" код, который никогда не меняется в банку и не проверяет jar MD5 соответствует ожидаемому. Это защитит сборку от непредвиденных изменений (например, после обновления до ant, JRE, ОС, изменения часового пояса и т.д.)
Ответ 2
Я столкнулся с аналогичной проблемой, но немного другой. Я решил поделиться им здесь, поскольку это касается темы вопроса. Чтобы создать два байт-идентичных файла с цифровой подписью JAR в другое время, нужно учитывать следующие моменты:
- Временные метки:
**/*.class
файлы должны иметь одну и ту же метку времени (java.util.zip.ZipEntry.setTime(long)
). Кроме того, файл META-INF/MANIFEST.MF
и файлы сертификатов (*.RSA
, *.DSA
и *.SF
) добавляются в файл JAR с меткой "now". Поэтому, даже если вы решили не компилировать классы и использовать уже скомпилированные (т.е. Те, у которых есть исходная временная метка 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 -Элементы-в-HashMap-отличаются-когда-The-же-программа-это-обкатку-jvm5-против-jvm6).
Итак, в основном есть два уровня проблемы. Во-первых, инструмент JAR/ZIP, который упаковывает файлы со своими временными метками файловой системы и, таким образом, создает двоичные файлы JAR для одного и того же набора классов Java, которые являются двоичными равными, но были скомпилированы в другое время. Во-вторых, инструмент подписывания JAR, который изменяет файл META-INF/MANIFEST-MF
и добавляет больше файлов в архив JAR (сертификаты и контрольные суммы файла файла).
Решением может быть пользовательский подписчик JAR, который устанавливает временные метки всех элементов файла JAR в постоянное время и заказывает записи файла MANIFEST.MF
(например, по алфавиту). До сих пор это, по моим сведениям, единственный способ создания двухбайтовых идентичных файлов JAR с цифровой подписью в разные моменты времени.
Ответ 3
Если бы эта же проблема, приземлился на этой странице. Ответ выше, написанный Jiri Patera, был очень полезен в понимании того, почему я не смог получить md5sums того, что, как я ожидал, будет иметь два одинаковых файла, после того, как вы поставили под себя и отменили файлы 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.