连续运行lein uberjar
两次,我得到两个不同的构建。经过一番unzip / find / sort / diff shell
魔术后,我发现它归结为一些 Maven 文件:更具体地说是pom.properties文件。
这是一个差异:
< #Tue Jan 14 07:07:50 CET 2014
---
> #Tue Jan 14 07:07:01 CET 2014
如何使用 Leiningen(以及 Maven)获得确定性的 Clojure 构建?
连续运行lein uberjar
两次,我得到两个不同的构建。经过一番unzip / find / sort / diff shell
魔术后,我发现它归结为一些 Maven 文件:更具体地说是pom.properties文件。
这是一个差异:
< #Tue Jan 14 07:07:50 CET 2014
---
> #Tue Jan 14 07:07:01 CET 2014
如何使用 Leiningen(以及 Maven)获得确定性的 Clojure 构建?
我有一个lein-voom的本地补丁(我使用Chouser维护的一个项目),它将解决这个问题,pom.properties
如果工作副本完全干净,则将标头时间修复为 VCS(当前只有 git)提交时间。我预计此提交将在下周某个时间完成,尽管我仍在考虑此功能的可配置性。
仅此一项并不能制作稳定的罐子,但它是第一个微不足道的部分。同样有趣的是 jar 中文件的时间戳,它将更改 zip 标头。规范化时间戳也应该很简单,但这是一个单独的步骤。
lein-voom 对确定性构建很感兴趣,这个项目通常会引起您的兴趣,因为它允许通过提交 sha 将依赖项直接指向特定的源版本,从而完全避免了工件。
lein-voom 很年轻,文档和 CLI 很粗糙,但核心功能很可靠。随意在GitHub 项目上发布问题或问题。
不久前,我写了一篇文章,介绍了使用 Maven 进行确定性构建。我在这里提取了要点:
使用程序集插件并像这样配置它:
src/main/assembly/zip.xml
:
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>deterministic</id>
<baseDirectory>/</baseDirectory>
<formats>
<format>zip</format>
</formats>
<fileSets>
<fileSet>
<directory>${project.build.directory}/classes</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
</assembly>
最后添加您自己MANIFEST.MF
记住的额外 CRLF,否则它将无效。
src/main/resources/META-INF/MANIFEST.MF
:
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: yourapp
Build-Jdk: 1.7.0
在 pom.xml 中添加一些插件:
pom.xml:
<plugins>
... other plugins ...
<!-- Step 1: Set all timestamps to same value -->
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>1-touch-classes</id>
<phase>prepare-package</phase>
<configuration>
<target>
<touch datetime="01/01/2000 00:10:00 am">
<fileset dir="target/classes"/>
</touch>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Step 2: Assemble as a ZIP to avoid MANIFEST.MF timestamp -->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.1</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly/zip.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>2-make-assembly</id>
<phase>prepare-package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Step 3: Rename ZIP as JAR -->
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>3-rename-assembly</id>
<phase>package</phase>
<configuration>
<target>
<move file="${project.build.directory}/${project.build.finalName}-deterministic.zip"
tofile="${project.build.directory}/${project.build.finalName}-deterministic.jar"/>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
... more plugins ...
</plugins>
这将创建一个确定性 JAR,但它仍将取决于您构建它的 JVM 和操作系统的确切版本。为了克服这个问题,您应该探索比特币核心项目使用的 gitian 方法,并在 VirtualBox 环境中强制使用特定的 JVM。通过这种方式,多个开发人员可以独立地从源代码构建,然后签署二进制文件以声明他们同意。当达到某个阈值时,代码被认为是确定性的并且可以被释放。