Skip to content

Commit

Permalink
Add group discriminant in case of conflict
Browse files Browse the repository at this point in the history
Prior to this commit, the repackage goal silently ignored the case of
two libraries having the same name and version but a different group.
As a result, the second library was overwriting the first one in the
repackaged jar.

This commit adds support for custom Library names and updates the
Maven and Gradle plugins so that the name includes the group ID
when there would otherwise be a duplicate.

Fixes spring-projectsgh-1475
  • Loading branch information
snicoll authored and philwebb committed Sep 3, 2014
1 parent 449752c commit f46fe32
Show file tree
Hide file tree
Showing 69 changed files with 299 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
name: Phil
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,18 @@ public void setCustomConfigurationName(String customConfigurationName) {

@Override
public void doWithLibraries(LibraryCallback callback) throws IOException {
Set<Library> custom = getLibraries(this.customConfigurationName,
Set<GradleLibrary> custom = getLibraries(this.customConfigurationName,
LibraryScope.CUSTOM);
if (custom != null) {
libraries(custom, callback);
}
else {
Set<Library> compile = getLibraries("compile", LibraryScope.COMPILE);
Set<GradleLibrary> compile = getLibraries("compile", LibraryScope.COMPILE);

Set<Library> runtime = getLibraries("runtime", LibraryScope.RUNTIME);
Set<GradleLibrary> runtime = getLibraries("runtime", LibraryScope.RUNTIME);
runtime = minus(runtime, compile);

Set<Library> provided = getLibraries(this.providedConfigurationName,
Set<GradleLibrary> provided = getLibraries(this.providedConfigurationName,
LibraryScope.PROVIDED);
if (provided != null) {
compile = minus(compile, provided);
Expand All @@ -99,13 +99,13 @@ public void doWithLibraries(LibraryCallback callback) throws IOException {
}
}

private Set<Library> getLibraries(String configurationName, LibraryScope scope) {
private Set<GradleLibrary> getLibraries(String configurationName, LibraryScope scope) {
Configuration configuration = (configurationName == null ? null : this.project
.getConfigurations().findByName(configurationName));
if (configuration == null) {
return null;
}
Set<Library> libraries = new LinkedHashSet<Library>();
Set<GradleLibrary> libraries = new LinkedHashSet<GradleLibrary>();
for (ResolvedArtifact artifact : configuration.getResolvedConfiguration()
.getResolvedArtifacts()) {
libraries.add(new ResolvedArtifactLibrary(artifact, scope));
Expand All @@ -115,14 +115,14 @@ private Set<Library> getLibraries(String configurationName, LibraryScope scope)
return libraries;
}

private Set<Library> getLibrariesForFileDependencies(Configuration configuration,
private Set<GradleLibrary> getLibrariesForFileDependencies(Configuration configuration,
LibraryScope scope) {
Set<Library> libraries = new LinkedHashSet<Library>();
Set<GradleLibrary> libraries = new LinkedHashSet<GradleLibrary>();
for (Dependency dependency : configuration.getIncoming().getDependencies()) {
if (dependency instanceof FileCollectionDependency) {
FileCollectionDependency fileDependency = (FileCollectionDependency) dependency;
for (File file : fileDependency.resolve()) {
libraries.add(new Library(file, scope));
libraries.add(new GradleLibrary(fileDependency.getGroup(), file, scope));
}
}
else if (dependency instanceof ProjectDependency) {
Expand All @@ -134,41 +134,80 @@ else if (dependency instanceof ProjectDependency) {
return libraries;
}

private Set<Library> minus(Set<Library> source, Set<Library> toRemove) {
private Set<GradleLibrary> minus(Set<GradleLibrary> source, Set<GradleLibrary> toRemove) {
if (source == null || toRemove == null) {
return source;
}
Set<File> filesToRemove = new HashSet<File>();
for (Library library : toRemove) {
for (GradleLibrary library : toRemove) {
filesToRemove.add(library.getFile());
}
Set<Library> result = new LinkedHashSet<Library>();
for (Library library : source) {
Set<GradleLibrary> result = new LinkedHashSet<GradleLibrary>();
for (GradleLibrary library : source) {
if (!filesToRemove.contains(library.getFile())) {
result.add(library);
}
}
return result;
}

private void libraries(Set<Library> libraries, LibraryCallback callback)
private void libraries(Set<GradleLibrary> libraries, LibraryCallback callback)
throws IOException {
if (libraries != null) {
for (Library library : libraries) {
Set<String> duplicates = getDuplicates(libraries);
for (GradleLibrary library : libraries) {
library.setIncludeGroupName(duplicates.contains(library.getName()));
callback.library(library);
}
}
}

private Set<String> getDuplicates(Set<GradleLibrary> libraries) {
Set<String> duplicates = new HashSet<String>();
Set<String> seen = new HashSet<String>();
for (GradleLibrary library : libraries) {
if (library.getFile() != null && !seen.add(library.getFile().getName())) {
duplicates.add(library.getFile().getName());
}
}
return duplicates;
}

private class GradleLibrary extends Library {

private final String group;

private boolean includeGroupName;

public GradleLibrary(String group, File file, LibraryScope scope) {
super(file, scope);
this.group = group;
}

public void setIncludeGroupName(boolean includeGroupName) {
this.includeGroupName = includeGroupName;
}

@Override
public String getName() {
String name = super.getName();
if(this.includeGroupName && this.group != null) {
name = this.group + "-" + name;
}
return name;
}

}

/**
* Adapts a {@link ResolvedArtifact} to a {@link Library}.
*/
private class ResolvedArtifactLibrary extends Library {
private class ResolvedArtifactLibrary extends GradleLibrary {

private final ResolvedArtifact artifact;

public ResolvedArtifactLibrary(ResolvedArtifact artifact, LibraryScope scope) {
super(artifact.getFile(), scope);
super(null, artifact.getFile(), scope);
this.artifact = artifact;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public void writeEntry(String entryName, InputStream inputStream) throws IOExcep
public void writeNestedLibrary(String destination, Library library)
throws IOException {
File file = library.getFile();
JarEntry entry = new JarEntry(destination + file.getName());
JarEntry entry = new JarEntry(destination + library.getName());
if (library.isUnpackRequired()) {
entry.setComment("UNPACK:" + FileUtils.sha1Hash(file));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
*/
public class Library {

private final String name;

private final File file;

private final LibraryScope scope;
Expand All @@ -49,11 +51,31 @@ public Library(File file, LibraryScope scope) {
* @param unpackRequired if the library needs to be unpacked before it can be used
*/
public Library(File file, LibraryScope scope, boolean unpackRequired) {
this(null, file, scope, unpackRequired);
}

/**
* Create a new {@link Library}.
* @param name the name of the library as it should be written or {@code null} to use
* the file name
* @param file the source file
* @param scope the scope of the library
* @param unpackRequired if the library needs to be unpacked before it can be used
*/
public Library(String name, File file, LibraryScope scope, boolean unpackRequired) {
this.name = (name == null ? file.getName() : name);
this.file = file;
this.scope = scope;
this.unpackRequired = unpackRequired;
}

/**
* @return the name of file as it should be written
*/
public String getName() {
return this.name;
}

/**
* @return the library file
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

Expand Down Expand Up @@ -153,17 +155,22 @@ private void repackage(JarFile sourceJar, File destination, Libraries libraries)
throws IOException {
final JarWriter writer = new JarWriter(destination);
try {
final Set<String> seen = new HashSet<String>();
writer.writeManifest(buildManifest(sourceJar));
writer.writeEntries(sourceJar);

libraries.doWithLibraries(new LibraryCallback() {
@Override
public void library(Library library) throws IOException {
File file = library.getFile();
if (isZip(file)) {
String destination = Repackager.this.layout
.getLibraryDestination(file.getName(), library.getScope());
.getLibraryDestination(library.getName(),
library.getScope());
if (destination != null) {
if (!seen.add(destination + library.getName())) {
throw new IllegalStateException("Duplicate library "
+ library.getName());
}
writer.writeNestedLibrary(destination, library);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,25 @@ public void doWithLibraries(LibraryCallback callback) throws IOException {
assertThat(entry.getComment().length(), equalTo(47));
}

@Test
public void duplicateLibraries() throws Exception {
TestJarFile libJar = new TestJarFile(this.temporaryFolder);
libJar.addClass("a/b/C.class", ClassWithoutMainMethod.class);
final File libJarFile = libJar.getFile();
this.testJarFile.addClass("a/b/C.class", ClassWithMainMethod.class);
File file = this.testJarFile.getFile();
Repackager repackager = new Repackager(file);
this.thrown.expect(IllegalStateException.class);
this.thrown.expectMessage("Duplicate library");
repackager.repackage(new Libraries() {
@Override
public void doWithLibraries(LibraryCallback callback) throws IOException {
callback.library(new Library(libJarFile, LibraryScope.COMPILE, false));
callback.library(new Library(libJarFile, LibraryScope.COMPILE, false));
}
});
}

@Test
public void customLayout() throws Exception {
TestJarFile libJar = new TestJarFile(this.temporaryFolder);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>acme-lib</artifactId>

<parent>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>jar-lib-name-conflict</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
</parent>

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.0.5.RELEASE</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.boot.maven.it.another</groupId>
<artifactId>acme-lib</artifactId>

<parent>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>jar-lib-name-conflict</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
</parent>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>jar-lib-name-conflict</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<modules>
<module>acme-lib</module>
<module>another-acme-lib</module>
<module>test-project</module>
</modules>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>test-project</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>@project.groupId@</groupId>
<artifactId>@project.artifactId@</artifactId>
<version>@project.version@</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifestEntries>
<Not-Used>Foo</Not-Used>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Two dependencies with the same artifactId -->
<dependency>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>acme-lib</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot.maven.it.another</groupId>
<artifactId>acme-lib</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.test;

public class SampleApplication {

public static void main(String[] args) {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import java.io.*;
import org.springframework.boot.maven.*;

File f = new File(basedir, "test-project/target/test-project-0.0.1.BUILD-SNAPSHOT.jar")
new Verify.JarArchiveVerification(f, Verify.SAMPLE_APP) {
@Override
protected void verifyZipEntries(Verify.ArchiveVerifier verifier) throws Exception {
super.verifyZipEntries(verifier)
verifier.assertHasEntryNameStartingWith("lib/org.springframework.boot.maven.it-acme-lib-0.0.1.BUILD-SNAPSHOT.jar")
verifier.assertHasEntryNameStartingWith("lib/org.springframework.boot.maven.it.another-acme-lib-0.0.1.BUILD-SNAPSHOT.jar")
}
}.verify();


Loading

0 comments on commit f46fe32

Please sign in to comment.