如何使用lein获得确定性构建?

时间:2014-01-14 04:06:32

标签: build clojure leiningen deterministic

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

2 个答案:

答案 0 :(得分:4)

我有lein-voom(我用Chouser维护的项目)的本地补丁,它将解决此问题,将pom.properties标头时间修复为VCS(目前只有git)提交时间工作副本完全干净。我希望这个提交能在下周的某个时候完成,不过我还在考虑这个功能的可配置性。

仅凭这一点并不适合稳定的罐子,但这是第一件小事。同样感兴趣的是jar中文件的时间戳,它将改变zip标题。规范化时间戳也应该是直截了当的,但这是一个单独的步骤。

确定性构建对lein-voom很感兴趣,这个项目通常可能是你感兴趣的,因为它允许通过commit sha直接将依赖关系指向特定的源版本,完全避免了工件。

lein-voom非常年轻,文档和CLI非常粗略,但核心功能非常可靠。欢迎在GitHub project上发布问题或解答。

答案 1 :(得分:1)

I wrote up an article一会儿用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和操作系统的确切版本。要克服比特币核心项目使用的you should explore the gitian approach并在VirtualBox环境中强制使用特定的JVM。通过这种方式,多个开发人员可以独立地从源构建,然后签署二进制文件以声明它们是一致的。当达到某个阈值时,代码被认为是确定性的并且可以被释放。