Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Post-process jar after assembly but before installation (to get idempotent builds)

We use Jenkins which use md5 fingerprinting to identify artifacts and whether the artifact has changed since the last build. Unfortunately Maven builds always generate binary different artifacts.

Therefore I am looking into making Maven generate the same jar artifact for the same set of input files regardless of where and when they were built, which amongst other things mean that the entries in the jar file must be sorted - not only in the index, but in the order they are written to the jar file.

After examining maven-jar-plugin which use maven-assembly-plugin, my conclusions are that they do not collect all files to be written in memory before writing them all at once, but write one at a time. This mean that it may be better to postprocess the generated jar instead of changing the current behavior so I at that time can sort the entries, zero the timestamps, etc.

I am unfamiliar with writing Maven plugins, so my question is, how should I write a plugin which Maven knows how to tell where the artifact-jar-in-progress is located and how I hook it up in my pom.xml?

(At first I need this to work for jar files, but war files would be nice too).

like image 997
Thorbjørn Ravn Andersen Avatar asked Jul 25 '14 17:07

Thorbjørn Ravn Andersen


1 Answers

As mentioned, this can be done based on something similar to maven-shade-plugin. I went ahead and wrote a simple plugin to add this capability -- see https://github.com/manouti/jar-timestamp-normalize-maven-plugin (available on the Central repo).

The behavior is based on the shade plugin. It consists of a single goal called normalize which can be bound to the package lifecycle phase and configured in the project's POM:

<plugins>
    <plugin>
        <groupId>com.github.manouti</groupId>
        <artifactId>jar-timestamp-normalize-maven-plugin</artifactId>
        <version>1.0-SNAPSHOT</version>
        <executions>
            <execution>
                <id>jar-normalize</id>
                <goals>
                    <goal>normalize</goal>
                </goals>
                <phase>package</phase>
            </execution>
        </executions>
    </plugin>
</plugins>

A few notes about the plugin:

  1. The artifact under build is accessed via project#getArtifact() where project is a org.apache.maven.project.MavenProject.

  2. Normalization consists of mainly three steps:

    • Setting the last modified time of all Jar entries to a specific timestamp (default value is 1970-01-01 00:00:00AM but can be changed via -Dtimestamp system property).

    • Reordering (alphabetically) of attributes in the manifest except for Manifest-Version which always comes first.

    • Removing comments from the pom.properties file which contain a timestamp that causes the Jar to differ from one build to another.

Once invoked, the goal will generate the output file next to the original artifact (named artifactId-version-normalized.jar), i.e. in the project.build.directory directory.

like image 107
M A Avatar answered Oct 20 '22 00:10

M A