我们使用Jenkins,它使用md5指纹来识别工件以及工件自上次构建以来是否发生了更改。不幸的是,Maven构建总是生成不同的二进制工件。
因此,我正在研究让Maven为同一组输入文件生成相同的jar工件,无论它们是在哪里和何时构建的,这意味着jar文件中的条目必须进行排序——不仅是在索引中,而且是在写入jar文件的顺序中。
在检查了使用maven汇编插件的maven jar插件后,我的结论是,他们不会在一次写入所有文件之前收集所有要写入内存的文件,而是一次写入一个文件。这意味着最好对生成的jar进行后处理,而不是更改当前行为,这样我就可以在那时对条目进行排序,将时间戳清零,等等。
我不熟悉编写Maven插件,所以我的问题是,我应该如何编写一个插件,让Maven知道如何判断正在进行的工件jar的位置,以及如何将其连接到我的pom.xml中?
(一开始我需要这个来处理jar文件,但war文件也不错(。
如前所述,这可以基于类似于maven-shade-plugin
的东西来完成。我继续写了一个简单的插件来添加这个功能——请参阅https://github.com/manouti/jar-timestamp-normalize-maven-plugin(可在中央回购中获得(。
该行为基于shade
插件。它由一个名为normalize
的单一目标组成,该目标可以绑定到package
生命周期阶段,并在项目的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>
关于插件的一些注意事项:
构建中的工件通过
project#getArtifact()
访问,其中project
是org.apache.maven.project.MavenProject
。规范化主要包括三个步骤:
将所有Jar条目的上次修改时间设置为特定的时间戳(默认值为
1970-01-01 00:00:00AM
,但可以通过-Dtimestamp
系统属性进行更改(。重新排序清单中的属性(按字母顺序(,但始终排在第一位的
Manifest-Version
除外。从
pom.properties
文件中删除包含时间戳的注释,该时间戳会导致Jar在不同的构建中有所不同。
一旦调用,目标将在原始工件(名为artifactId-version-normalized.jar
(旁边生成输出文件,即在project.build.directory
目录中。
创建maven插件项目
mvn archetype:generate
-DgroupId=sample.plugin
-DartifactId=hello-maven-plugin
-DarchetypeGroupId=org.apache.maven.archetypes
-DarchetypeArtifactId=maven-archetype-plugin
调用该命令,它将生成一个名为MyMojo.java
的类的框架项目
在execute()
方法中编写你的东西,并通过mvn clean install
将该插件安装到你的存储库中
然后将它的执行与您的项目联系起来,在您的项目pom.xml
中
<build>
<plugins>
<plugin>
<groupId>sample.plugin</groupId>
<artifactId>hello-maven-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>sayhi</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
访问Mojo 内的项目属性
/**
* The Maven project.
*
* @parameter expression="${project}"
* @required
* @readonly
*/
private MavenProject project;
然后
project.getProperties("build.directory")
并读取其他属性以确定您的jar文件打包
请参阅
- maven:指导java插件开发
我同意创建一个自定义的maven插件似乎是一个更好的选择。我不知道有没有一个现有的插件为您提供了解决方案。
md5校验和(或者我的存储库中的sha-1(是用安装插件生成的,所以你似乎需要扩展它,或者写一个新的插件,在安装阶段后工作。
我有两个关于这个插件的建议:
1(当考虑简单时,这个插件应该:
- 读取生成的jar:
- 提取所有条目
- 排除某些条目(例如MANIFEST.MF(
- 对剩余条目进行排序
- 为内存中的每个提取md5
- 从所有提取的数据中生成一个md5
然而,当考虑在哪里&当独立性:根据.class文件结构Java_class_file,编译后的类文件中包含次要、主要版本条目。所以,如果编译器发生变化,.class文件也会发生变化。在这种情况下,我们需要从这一点检查源代码级别:(因此,如果不能保证复印机版本,这个解决方案将变得毫无用处。
2(作为一个非常肮脏但简单的解决方案,此插件可能只提取模块的pom.xml
文件的md5代码。但是您必须保证jar中的每个更改都手动反映到一个次要版本(或内部版本号(。
您可以编写由Groovy-maven插件执行的Groovy脚本,而不是编写自己的插件:
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>groovy-maven-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
import java.util.jar.*
String fileName = '${project.build.directory}/${project.build.finalName}.jar'
println "Editing file ${fileName}"
JarFile file = new JarFile(fileName);
// do your edit
</source>
</configuration>
</execution>
</executions>
</plugin>