我使用jar命令构建jar文件。在尝试使用md5签名缓存jar文件时,我发现从完全相同的源构建的jar具有不同的md5签名。
仔细检查后,我发现每次创建的罐子内容都完全相同(diff -qr是空的)。结果是,创建的时间戳被编码在jar文件中,从而抛出md5签名。其他人在这里也发现了同样的情况。
甚至有一篇关于如何用maven每次创建相同的jar文件的博客文章。然而,我想要一个简单的解决方案,使用命令行使用现成的命令,如jar和zip(可能必须在没有安装权限的服务器上执行此操作),可能导致与我目前使用jar命令获得相同的"功能"jar。
EDIT:对于我的目的,快速找到md5也足够了,以便它在构建中是相同的,即使jar不相同。到目前为止,我发现的唯一方法是提取jar中的文件并对所有组件文件进行md5验证。但是我担心这对于较大的jar来说太慢了,并且会破坏缓存它们以避免首先构建它们的目的。有没有更好更快的解决方案?
主要问题是jar命令总是用当前时间创建META-INFMANIFEST.MF
。文件时间保存在zip条目头中。这就是为什么即使jar中的所有文件内容保持不变,MD5值也不同的原因:不同的zip条目头产生不同的zip文件。
对于jar命令,唯一的解决方案是选项-M
:不为条目创建一个清单文件。
Jar命令总是创建META-INFMANIFEST。具有当前时间的MF。Zip存储具有时间戳和文件属性的文件,因此sha256或MD5对于两个工件将是不同的。
我们需要确保所有需要创建jar或zip的文件的创建、最后修改、访问时间戳和文件属性总是相同的。
我已经创建了下面的脚本,它可以采用jar或zip文件,并通过使时间戳常数和设置正确的压缩级别和偏移量使其具有确定性。
#!/bin/bash
usage() {
echo "Usage : ./createDeterministicArtifact.sh <zip/jar file name>"
exit 1
}
info() {
echo "$1"
}
strip_artifact() {
if [ -z ${file} ]; then
usage
fi
if [ -f ${file} -a -s ${file} ]; then
mkdir -p ${file}.tmp
unzip -oq -d ${file}.tmp ${file}
find ${file}.tmp -follow -exec touch -a -m -t 201912010000.00 {} +
if [ "$UNAME" == "Linux" ] ; then
find ${file}.tmp -follow -exec chattr -a {} +
elif [[ "$UNAME" == CYGWIN* || "$UNAME" == MINGW* ]] ; then
find ${file}.tmp -follow -exec attrib -A {} +
fi
cd ${file}.tmp
zip -rq -D -X -9 -A --compression-method deflate ../${file}.new .
cd -
rm -rf ${file}.tmp
info "Recreated deterministic artifact: ${file}.new"
else
info "Input file is empty. Please validate the file and try again"
fi
}
file=$1