diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/ImagePackager.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/ImagePackager.java index eabafac45e..213cb7800b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/ImagePackager.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/ImagePackager.java @@ -36,12 +36,16 @@ public class ImagePackager extends Packager { /** * Create a new {@link ImagePackager} instance. * @param source the source file to package + * @param backupFile the backup of the source file to package */ - public ImagePackager(File source) { - super(source, null); + public ImagePackager(File source, File backupFile) { + super(source); + setBackupFile(backupFile); if (isAlreadyPackaged()) { Assert.isTrue(getBackupFile().exists() && getBackupFile().isFile(), "Original source '" + getBackupFile() + "' is required for building an image"); + Assert.state(!isAlreadyPackaged(getBackupFile()), + () -> "Repackaged archive file " + source + " cannot be used to build an image"); } } @@ -57,8 +61,6 @@ public class ImagePackager extends Packager { private void packageImage(Libraries libraries, AbstractJarWriter writer) throws IOException { File source = isAlreadyPackaged() ? getBackupFile() : getSource(); - Assert.state(!isAlreadyPackaged(source), - () -> "Repackaged archive file " + source + " cannot be used to build an image"); try (JarFile sourceJar = new JarFile(source)) { write(sourceJar, libraries, writer); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Packager.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Packager.java index 4b714ef812..8ad560ea4c 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Packager.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Packager.java @@ -76,6 +76,8 @@ public abstract class Packager { private final File source; + private File backupFile; + private Layout layout; private LayoutFactory layoutFactory; @@ -88,9 +90,20 @@ public abstract class Packager { /** * Create a new {@link Packager} instance. - * @param source the source JAR file to package + * @param source the source archive file to package + */ + protected Packager(File source) { + this(source, null); + } + + /** + * Create a new {@link Packager} instance. + * @param source the source archive file to package * @param layoutFactory the layout factory to use or {@code null} + * @deprecated since 2.5.0 in favor of {@link #Packager(File)} and + * {@link #setLayoutFactory(LayoutFactory)} */ + @Deprecated protected Packager(File source, LayoutFactory layoutFactory) { Assert.notNull(source, "Source file must not be null"); Assert.isTrue(source.exists() && source.isFile(), @@ -146,6 +159,14 @@ public abstract class Packager { this.layersIndex = new LayersIndex(layers); } + /** + * Sets the {@link File} to use to backup the original source. + * @param backupFile the file to use to backup the original source + */ + protected void setBackupFile(File backupFile) { + this.backupFile = backupFile; + } + /** * Sets if jarmode jars relevant for the packaging should be automatically included. * @param includeRelevantJarModeJars if relevant jars are included @@ -289,6 +310,9 @@ public abstract class Packager { * @return the file to use to backup the original source */ public final File getBackupFile() { + if (this.backupFile != null) { + return this.backupFile; + } return new File(this.source.getParentFile(), this.source.getName() + ".original"); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java index b01ffffb21..2e139a3f53 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java @@ -32,16 +32,29 @@ import org.springframework.util.Assert; * @author Andy Wilkinson * @author Stephane Nicoll * @author Madhura Bhave + * @author Scott Frederick * @since 1.0.0 */ public class Repackager extends Packager { private boolean backupSource = true; + /** + * Create a new {@link Repackager} instance. + * @param source the source archive file to package + */ public Repackager(File source) { - this(source, null); + super(source); } + /** + * Create a new {@link Repackager} instance. + * @param source the source archive file to package + * @param layoutFactory the layout factory to use or {@code null} + * @deprecated since 2.5.0 in favor of {@link #Repackager(File)} and + * {@link #setLayoutFactory(LayoutFactory)} + */ + @Deprecated public Repackager(File source, LayoutFactory layoutFactory) { super(source, layoutFactory); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/ImagePackagerTests.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/ImagePackagerTests.java index e97e6f37d4..f9760d04ef 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/ImagePackagerTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/ImagePackagerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,7 +40,7 @@ class ImagePackagerTests extends AbstractPackagerTests { @Override protected ImagePackager createPackager(File source) { - return new ImagePackager(source); + return new ImagePackager(source, null); } @Override diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/BuildImageTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/BuildImageTests.java index cc2224f5a9..5f6abcd0aa 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/BuildImageTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/BuildImageTests.java @@ -65,6 +65,52 @@ public class BuildImageTests extends AbstractArchiveIntegrationTests { }); } + @TestTemplate + void whenBuildImageIsInvokedWithClassifierWithoutRepackageTheArchiveIsRepackagedOnTheFly(MavenBuild mavenBuild) { + mavenBuild.project("build-image-classifier").goals("package").prepare(this::writeLongNameResource) + .execute((project) -> { + File jar = new File(project, "target/build-image-classifier-0.0.1.BUILD-SNAPSHOT.jar"); + assertThat(jar).isFile(); + File classifier = new File(project, "target/build-image-classifier-0.0.1.BUILD-SNAPSHOT-test.jar"); + assertThat(classifier).doesNotExist(); + assertThat(buildLog(project)).contains("Building image") + .contains("docker.io/library/build-image-classifier:0.0.1.BUILD-SNAPSHOT") + .contains("Successfully built image"); + ImageReference imageReference = ImageReference.of(ImageName.of("build-image-classifier"), + "0.0.1.BUILD-SNAPSHOT"); + try (GenericContainer container = new GenericContainer<>(imageReference.toString())) { + container.waitingFor(Wait.forLogMessage("Launched\\n", 1)).start(); + } + finally { + removeImage(imageReference); + } + }); + } + + @TestTemplate + void whenBuildImageIsInvokedWithClassifierSourceWithoutRepackageTheArchiveIsRepackagedOnTheFly( + MavenBuild mavenBuild) { + mavenBuild.project("build-image-classifier-source").goals("package").prepare(this::writeLongNameResource) + .execute((project) -> { + File jar = new File(project, "target/build-image-classifier-source-0.0.1.BUILD-SNAPSHOT-test.jar"); + assertThat(jar).isFile(); + File original = new File(project, + "target/build-image-classifier-source-0.0.1.BUILD-SNAPSHOT-test.jar.original"); + assertThat(original).doesNotExist(); + assertThat(buildLog(project)).contains("Building image") + .contains("docker.io/library/build-image-classifier-source:0.0.1.BUILD-SNAPSHOT") + .contains("Successfully built image"); + ImageReference imageReference = ImageReference.of(ImageName.of("build-image-classifier-source"), + "0.0.1.BUILD-SNAPSHOT"); + try (GenericContainer container = new GenericContainer<>(imageReference.toString())) { + container.waitingFor(Wait.forLogMessage("Launched\\n", 1)).start(); + } + finally { + removeImage(imageReference); + } + }); + } + @TestTemplate void whenBuildImageIsInvokedWithRepackageTheExistingArchiveIsUsed(MavenBuild mavenBuild) { mavenBuild.project("build-image-with-repackage").goals("package").prepare(this::writeLongNameResource) @@ -88,6 +134,54 @@ public class BuildImageTests extends AbstractArchiveIntegrationTests { }); } + @TestTemplate + void whenBuildImageIsInvokedWithClassifierAndRepackageTheExistingArchiveIsUsed(MavenBuild mavenBuild) { + mavenBuild.project("build-image-classifier-with-repackage").goals("package") + .prepare(this::writeLongNameResource).execute((project) -> { + File jar = new File(project, + "target/build-image-classifier-with-repackage-0.0.1.BUILD-SNAPSHOT.jar"); + assertThat(jar).isFile(); + File original = new File(project, + "target/build-image-classifier-with-repackage-0.0.1.BUILD-SNAPSHOT-test.jar"); + assertThat(original).isFile(); + assertThat(buildLog(project)).contains("Building image") + .contains("docker.io/library/build-image-classifier-with-repackage:0.0.1.BUILD-SNAPSHOT") + .contains("Successfully built image"); + ImageReference imageReference = ImageReference + .of(ImageName.of("build-image-classifier-with-repackage"), "0.0.1.BUILD-SNAPSHOT"); + try (GenericContainer container = new GenericContainer<>(imageReference.toString())) { + container.waitingFor(Wait.forLogMessage("Launched\\n", 1)).start(); + } + finally { + removeImage(imageReference); + } + }); + } + + @TestTemplate + void whenBuildImageIsInvokedWithClassifierSourceAndRepackageTheExistingArchiveIsUsed(MavenBuild mavenBuild) { + mavenBuild.project("build-image-classifier-source-with-repackage").goals("package") + .prepare(this::writeLongNameResource).execute((project) -> { + File jar = new File(project, + "target/build-image-classifier-source-with-repackage-0.0.1.BUILD-SNAPSHOT-test.jar"); + assertThat(jar).isFile(); + File original = new File(project, + "target/build-image-classifier-source-with-repackage-0.0.1.BUILD-SNAPSHOT-test.jar.original"); + assertThat(original).isFile(); + assertThat(buildLog(project)).contains("Building image").contains( + "docker.io/library/build-image-classifier-source-with-repackage:0.0.1.BUILD-SNAPSHOT") + .contains("Successfully built image"); + ImageReference imageReference = ImageReference + .of(ImageName.of("build-image-classifier-source-with-repackage"), "0.0.1.BUILD-SNAPSHOT"); + try (GenericContainer container = new GenericContainer<>(imageReference.toString())) { + container.waitingFor(Wait.forLogMessage("Launched\\n", 1)).start(); + } + finally { + removeImage(imageReference); + } + }); + } + @TestTemplate void whenBuildImageIsInvokedWithCustomImageName(MavenBuild mavenBuild) { mavenBuild.project("build-image-custom-name").goals("package") diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier-source-with-repackage/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier-source-with-repackage/pom.xml new file mode 100644 index 0000000000..7734c543d6 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier-source-with-repackage/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + org.springframework.boot.maven.it + build-image-classifier-source-with-repackage + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + @java.version@ + @java.version@ + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.0 + + + package + + jar + + + test + + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + repackage + + repackage + + + + + build-image + + + + + test + + + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier-source-with-repackage/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier-source-with-repackage/src/main/java/org/test/SampleApplication.java new file mode 100644 index 0000000000..5053809ef1 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier-source-with-repackage/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.test; + +public class SampleApplication { + + public static void main(String[] args) throws Exception { + System.out.println("Launched"); + synchronized(args) { + args.wait(); // Prevent exit" + } + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier-source/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier-source/pom.xml new file mode 100644 index 0000000000..30b605a5bc --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier-source/pom.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + org.springframework.boot.maven.it + build-image-classifier-source + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + @java.version@ + @java.version@ + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.0 + + + package + + jar + + + test + + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + build-image + + + + + test + + + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier-source/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier-source/src/main/java/org/test/SampleApplication.java new file mode 100644 index 0000000000..5053809ef1 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier-source/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.test; + +public class SampleApplication { + + public static void main(String[] args) throws Exception { + System.out.println("Launched"); + synchronized(args) { + args.wait(); // Prevent exit" + } + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier-with-repackage/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier-with-repackage/pom.xml new file mode 100644 index 0000000000..d2f34ba4c6 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier-with-repackage/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + org.springframework.boot.maven.it + build-image-classifier-with-repackage + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + @java.version@ + @java.version@ + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + repackage + + repackage + + + + + build-image + + + + + test + + + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier-with-repackage/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier-with-repackage/src/main/java/org/test/SampleApplication.java new file mode 100644 index 0000000000..5053809ef1 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier-with-repackage/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.test; + +public class SampleApplication { + + public static void main(String[] args) throws Exception { + System.out.println("Launched"); + synchronized(args) { + args.wait(); // Prevent exit" + } + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier/pom.xml new file mode 100644 index 0000000000..ba64b1df5f --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + org.springframework.boot.maven.it + build-image-classifier + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + @java.version@ + @java.version@ + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + build-image + + + + + test + + + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier/src/main/java/org/test/SampleApplication.java new file mode 100644 index 0000000000..5053809ef1 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-classifier/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.test; + +public class SampleApplication { + + public static void main(String[] args) throws Exception { + System.out.println("Launched"); + synchronized(args) { + args.wait(); // Prevent exit" + } + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractPackagerMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractPackagerMojo.java index 33638a39e8..b195437764 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractPackagerMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractPackagerMojo.java @@ -190,6 +190,42 @@ public abstract class AbstractPackagerMojo extends AbstractDependencyFilterMojo return filters.toArray(new ArtifactsFilter[0]); } + /** + * Return the source {@link Artifact} to repackage. If a classifier is specified and + * an artifact with that classifier exists, it is used. Otherwise, the main artifact + * is used. + * @param classifier the artifact classifier + * @return the source artifact to repackage + */ + protected Artifact getSourceArtifact(String classifier) { + Artifact sourceArtifact = getArtifact(classifier); + return (sourceArtifact != null) ? sourceArtifact : this.project.getArtifact(); + } + + private Artifact getArtifact(String classifier) { + if (classifier != null) { + for (Artifact attachedArtifact : this.project.getAttachedArtifacts()) { + if (classifier.equals(attachedArtifact.getClassifier()) && attachedArtifact.getFile() != null + && attachedArtifact.getFile().isFile()) { + return attachedArtifact; + } + } + } + return null; + } + + protected File getTargetFile(String finalName, String classifier, File targetDirectory) { + String classifierSuffix = (classifier != null) ? classifier.trim() : ""; + if (!classifierSuffix.isEmpty() && !classifierSuffix.startsWith("-")) { + classifierSuffix = "-" + classifierSuffix; + } + if (!targetDirectory.exists()) { + targetDirectory.mkdirs(); + } + return new File(targetDirectory, + finalName + classifierSuffix + "." + this.project.getArtifact().getArtifactHandler().getExtension()); + } + /** * Archive layout types. */ diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java index b69fe05823..78626d4511 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java @@ -29,6 +29,7 @@ import java.util.zip.ZipEntry; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.archivers.tar.TarConstants; +import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.logging.Log; import org.apache.maven.plugins.annotations.Execute; @@ -70,14 +71,14 @@ public class BuildImageMojo extends AbstractPackagerMojo { } /** - * Directory containing the JAR. + * Directory containing the source archive. * @since 2.3.0 */ @Parameter(defaultValue = "${project.build.directory}", required = true) private File sourceDirectory; /** - * Name of the JAR. + * Name of the source archive. * @since 2.3.0 */ @Parameter(defaultValue = "${project.build.finalName}", readonly = true) @@ -91,7 +92,7 @@ public class BuildImageMojo extends AbstractPackagerMojo { private boolean skip; /** - * Classifier used when finding the source jar. + * Classifier used when finding the source archive. * @since 2.3.0 */ @Parameter @@ -153,7 +154,7 @@ public class BuildImageMojo extends AbstractPackagerMojo { } private BuildRequest getBuildRequest(Libraries libraries) { - ImagePackager imagePackager = new ImagePackager(getJarFile()); + ImagePackager imagePackager = new ImagePackager(getArchiveFile(), getBackupFile()); Function content = (owner) -> getApplicationContent(owner, libraries, imagePackager); Image image = (this.image != null) ? this.image : new Image(); if (image.name == null && this.imageName != null) { @@ -173,19 +174,32 @@ public class BuildImageMojo extends AbstractPackagerMojo { return new PackagedTarArchive(owner, libraries, packager); } - private File getJarFile() { + private File getArchiveFile() { // We can use 'project.getArtifact().getFile()' because that was done in a // forked lifecycle and is now null - StringBuilder name = new StringBuilder(this.finalName); - if (StringUtils.hasText(this.classifier)) { - name.append("-").append(this.classifier); + File archiveFile = getTargetFile(this.finalName, this.classifier, this.sourceDirectory); + if (!archiveFile.exists()) { + archiveFile = getSourceArtifact(this.classifier).getFile(); } - name.append(".jar"); - File jarFile = new File(this.sourceDirectory, name.toString()); - if (!jarFile.exists()) { + if (!archiveFile.exists()) { throw new IllegalStateException("Executable jar file required for building image"); } - return jarFile; + if (archiveFile.getName().endsWith(".war")) { + throw new IllegalStateException("Executable jar file required for building image"); + } + return archiveFile; + } + + /** + * Return the {@link File} to use to backup the original source. + * @return the file to use to backup the original source + */ + private File getBackupFile() { + Artifact source = getSourceArtifact(null); + if (this.classifier != null && !this.classifier.equals(source.getClassifier())) { + return source.getFile(); + } + return null; } private BuildRequest customize(BuildRequest request) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java index 8d78b0f5f8..d2639b93e8 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java @@ -207,8 +207,8 @@ public class RepackageMojo extends AbstractPackagerMojo { } private void repackage() throws MojoExecutionException { - Artifact source = getSourceArtifact(); - File target = getTargetFile(); + Artifact source = getSourceArtifact(this.classifier); + File target = getTargetFile(this.finalName, this.classifier, this.outputDirectory); Repackager repackager = getRepackager(source.getFile()); Libraries libraries = getLibraries(this.requiresUnpack); try { @@ -239,41 +239,6 @@ public class RepackageMojo extends AbstractPackagerMojo { } } - /** - * Return the source {@link Artifact} to repackage. If a classifier is specified and - * an artifact with that classifier exists, it is used. Otherwise, the main artifact - * is used. - * @return the source artifact to repackage - */ - private Artifact getSourceArtifact() { - Artifact sourceArtifact = getArtifact(this.classifier); - return (sourceArtifact != null) ? sourceArtifact : this.project.getArtifact(); - } - - private Artifact getArtifact(String classifier) { - if (classifier != null) { - for (Artifact attachedArtifact : this.project.getAttachedArtifacts()) { - if (classifier.equals(attachedArtifact.getClassifier()) && attachedArtifact.getFile() != null - && attachedArtifact.getFile().isFile()) { - return attachedArtifact; - } - } - } - return null; - } - - private File getTargetFile() { - String classifier = (this.classifier != null) ? this.classifier.trim() : ""; - if (!classifier.isEmpty() && !classifier.startsWith("-")) { - classifier = "-" + classifier; - } - if (!this.outputDirectory.exists()) { - this.outputDirectory.mkdirs(); - } - return new File(this.outputDirectory, - this.finalName + classifier + "." + this.project.getArtifact().getArtifactHandler().getExtension()); - } - private Repackager getRepackager(File source) { return getConfiguredPackager(() -> new Repackager(source)); }