0

连续运行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 构建?

4

2 回答 2

4

我有一个lein-voom的本地补丁(我使用Chouser维护的一个项目),它将解决这个问题,pom.properties如果工作副本完全干净,则将标头时间修复为 VCS(当前只有 git)提交时间。我预计此提交将在下周某个时间完成,尽管我仍在考虑此功能的可配置性。

仅此一项并不能制作稳定的罐子,但它是第一个微不足道的部分。同样有趣的是 jar 中文件的时间戳,它将更改 zip 标头。规范化时间戳也应该很简单,但这是一个单独的步骤。

lein-voom 对确定性构建很感兴趣,这个项目通常会引起您的兴趣,因为它允许通过提交 sha 将依赖项直接指向特定的源版本,从而完全避免了工件。

lein-voom 很年轻,文档和 CLI 很粗糙,但核心功能很可靠。随意在GitHub 项目上发布问题或问题。

于 2014-01-18T04:37:01.550 回答
1

不久前,我写了一篇文章,介绍了使用 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。通过这种方式,多个开发人员可以独立地从源代码构建,然后签署二进制文件以声明他们同意。当达到某个阈值时,代码被认为是确定性的并且可以被释放。

于 2014-03-13T17:23:48.567 回答