diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/ImplicitLayers.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/ImplicitLayers.java deleted file mode 100644 index 2bd9abb693..0000000000 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/ImplicitLayers.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2012-2020 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.springframework.boot.jarmode.layertools; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.zip.ZipEntry; - -/** - * {@link Layers} implementation that uses implicit rules to slice the application. - * - * @author Phillip Webb - */ -class ImplicitLayers implements Layers { - - private static final String DEPENDENCIES_LAYER = "dependencies"; - - private static final String SNAPSHOT_DEPENDENCIES_LAYER = "snapshot-dependencies"; - - private static final String RESOURCES_LAYER = "resources"; - - private static final String APPLICATION_LAYER = "application"; - - private static final List LAYERS; - static { - List layers = new ArrayList<>(); - layers.add(DEPENDENCIES_LAYER); - layers.add(SNAPSHOT_DEPENDENCIES_LAYER); - layers.add(RESOURCES_LAYER); - layers.add(APPLICATION_LAYER); - LAYERS = Collections.unmodifiableList(layers); - } - - private static final String[] CLASS_LOCATIONS = { "", "BOOT-INF/classes/" }; - - private static final String[] RESOURCE_LOCATIONS = { "META-INF/resources/", "resources/", "static/", "public/" }; - - @Override - public Iterator iterator() { - return LAYERS.iterator(); - } - - @Override - public String getLayer(ZipEntry entry) { - return getLayer(entry.getName()); - } - - String getLayer(String name) { - if (name.endsWith("SNAPSHOT.jar")) { - return SNAPSHOT_DEPENDENCIES_LAYER; - } - if (name.endsWith(".jar")) { - return DEPENDENCIES_LAYER; - } - if (!name.endsWith(".class")) { - for (String classLocation : CLASS_LOCATIONS) { - for (String resourceLocation : RESOURCE_LOCATIONS) { - if (name.startsWith(classLocation + resourceLocation)) { - return RESOURCES_LAYER; - } - } - } - } - return APPLICATION_LAYER; - } - -} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/Layers.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/Layers.java index 9b2a7523d1..181efb3cd8 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/Layers.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/Layers.java @@ -49,7 +49,10 @@ interface Layers extends Iterable { */ static Layers get(Context context) { IndexedLayers indexedLayers = IndexedLayers.get(context); - return (indexedLayers != null) ? indexedLayers : new ImplicitLayers(); + if (indexedLayers == null) { + throw new IllegalStateException("Failed to load layers.idx which is required by layertools"); + } + return indexedLayers; } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/HelpCommandTests.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/HelpCommandTests.java index 8dd508416c..33ed674572 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/HelpCommandTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/HelpCommandTests.java @@ -17,11 +17,19 @@ package org.springframework.boot.jarmode.layertools; import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collections; +import java.util.jar.JarEntry; +import java.util.zip.ZipOutputStream; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; @@ -38,10 +46,13 @@ class HelpCommandTests { private TestPrintStream out; + @TempDir + File temp; + @BeforeEach - void setup() { + void setup() throws Exception { Context context = mock(Context.class); - given(context.getJarFile()).willReturn(new File("test.jar")); + given(context.getJarFile()).willReturn(createJarFile("test.jar")); this.command = new HelpCommand(context, LayerToolsJarMode.Runner.getCommands(context)); this.out = new TestPrintStream(this); } @@ -60,4 +71,19 @@ class HelpCommandTests { } + private File createJarFile(String name) throws IOException { + File file = new File(this.temp, name); + try (ZipOutputStream jarOutputStream = new ZipOutputStream(new FileOutputStream(file))) { + JarEntry indexEntry = new JarEntry("BOOT-INF/layers.idx"); + jarOutputStream.putNextEntry(indexEntry); + Writer writer = new OutputStreamWriter(jarOutputStream, StandardCharsets.UTF_8); + writer.write("a\n"); + writer.write("b\n"); + writer.write("c\n"); + writer.write("d\n"); + writer.flush(); + } + return file; + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ImplicitLayersTests.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ImplicitLayersTests.java deleted file mode 100644 index ebc5771d73..0000000000 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ImplicitLayersTests.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2012-2020 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.springframework.boot.jarmode.layertools; - -import java.util.zip.ZipEntry; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link ImplicitLayers}. - * - * @author Phillip Webb - */ -class ImplicitLayersTests { - - private Layers layers = new ImplicitLayers(); - - @Test - void iteratorReturnsLayers() { - assertThat(this.layers).containsExactly("dependencies", "snapshot-dependencies", "resources", "application"); - } - - @Test - void getLayerWhenSnapshotJarReturnsSnapshotDependencies() { - assertThat(this.layers.getLayer(zipEntry("BOOT-INF/lib/mylib-SNAPSHOT.jar"))) - .isEqualTo("snapshot-dependencies"); - } - - @Test - void getLayerWhenNonSnapshotJarReturnsDependencies() { - assertThat(this.layers.getLayer(zipEntry("BOOT-INF/lib/mylib.jar"))).isEqualTo("dependencies"); - } - - @Test - void getLayerWhenLoaderClassReturnsApplication() { - assertThat(this.layers.getLayer(zipEntry("org/springframework/boot/loader/Example.class"))) - .isEqualTo("application"); - } - - @Test - void getLayerWhenStaticResourceReturnsResources() { - assertThat(this.layers.getLayer(zipEntry("BOOT-INF/classes/META-INF/resources/image.gif"))) - .isEqualTo("resources"); - assertThat(this.layers.getLayer(zipEntry("BOOT-INF/classes/resources/image.gif"))).isEqualTo("resources"); - assertThat(this.layers.getLayer(zipEntry("BOOT-INF/classes/static/image.gif"))).isEqualTo("resources"); - assertThat(this.layers.getLayer(zipEntry("BOOT-INF/classes/public/image.gif"))).isEqualTo("resources"); - assertThat(this.layers.getLayer(zipEntry("META-INF/resources/image.gif"))).isEqualTo("resources"); - assertThat(this.layers.getLayer(zipEntry("resources/image.gif"))).isEqualTo("resources"); - assertThat(this.layers.getLayer(zipEntry("static/image.gif"))).isEqualTo("resources"); - assertThat(this.layers.getLayer(zipEntry("public/image.gif"))).isEqualTo("resources"); - } - - @Test - void getLayerWhenRegularClassReturnsApplication() { - assertThat(this.layers.getLayer(zipEntry("BOOT-INF/classes/com.example/App.class"))).isEqualTo("application"); - } - - @Test - void getLayerWhenClassResourceReturnsApplication() { - assertThat(this.layers.getLayer(zipEntry("BOOT-INF/classes/application.properties"))).isEqualTo("application"); - } - - private ZipEntry zipEntry(String name) { - return new ZipEntry(name); - } - -} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/LayerToolsJarModeTests.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/LayerToolsJarModeTests.java index ba0cc1828a..a556bc5e94 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/LayerToolsJarModeTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/LayerToolsJarModeTests.java @@ -17,11 +17,19 @@ package org.springframework.boot.jarmode.layertools; import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; import java.io.PrintStream; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.util.jar.JarEntry; +import java.util.zip.ZipOutputStream; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; @@ -40,10 +48,13 @@ class LayerToolsJarModeTests { private PrintStream systemOut; + @TempDir + File temp; + @BeforeEach - void setup() { + void setup() throws Exception { Context context = mock(Context.class); - given(context.getJarFile()).willReturn(new File("test.jar")); + given(context.getJarFile()).willReturn(createJarFile("test.jar")); this.out = new TestPrintStream(this); this.systemOut = System.out; System.setOut(this.out); @@ -68,4 +79,19 @@ class LayerToolsJarModeTests { assertThat(this.out).hasSameContentAsResource("list-output.txt"); } + private File createJarFile(String name) throws IOException { + File file = new File(this.temp, name); + try (ZipOutputStream jarOutputStream = new ZipOutputStream(new FileOutputStream(file))) { + JarEntry indexEntry = new JarEntry("BOOT-INF/layers.idx"); + jarOutputStream.putNextEntry(indexEntry); + Writer writer = new OutputStreamWriter(jarOutputStream, StandardCharsets.UTF_8); + writer.write("a\n"); + writer.write("b\n"); + writer.write("c\n"); + writer.write("d\n"); + writer.flush(); + } + return file; + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ListCommandTests.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ListCommandTests.java index 1f31f7f250..2d9e793922 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ListCommandTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ListCommandTests.java @@ -16,11 +16,24 @@ package org.springframework.boot.jarmode.layertools; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.util.jar.JarEntry; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; +import static org.mockito.BDDMockito.given; /** * Tests for {@link ListCommand}. @@ -29,20 +42,66 @@ import static org.mockito.Mockito.mock; */ class ListCommandTests { + @TempDir + File temp; + + @Mock + private Context context; + + private File jarFile; + + @BeforeEach + void setup() throws Exception { + MockitoAnnotations.initMocks(this); + this.jarFile = createJarFile("test.jar"); + given(this.context.getJarFile()).willReturn(this.jarFile); + this.command = new ListCommand(this.context); + this.out = new TestPrintStream(this); + } + private ListCommand command; private TestPrintStream out; - @BeforeEach - void setup() { - this.command = new ListCommand(mock(Context.class)); - this.out = new TestPrintStream(this); - } - @Test void listLayersShouldListLayers() { - this.command.printLayers(new ImplicitLayers(), this.out); + Layers layers = IndexedLayers.get(this.context); + this.command.printLayers(layers, this.out); assertThat(this.out).hasSameContentAsResource("list-output.txt"); } + private File createJarFile(String name) throws IOException { + File file = new File(this.temp, name); + try (ZipOutputStream jarOutputStream = new ZipOutputStream(new FileOutputStream(file))) { + writeLayersIndex(jarOutputStream); + String entryPrefix = "BOOT-INF/layers/"; + jarOutputStream.putNextEntry(new ZipEntry(entryPrefix + "a/")); + jarOutputStream.closeEntry(); + jarOutputStream.putNextEntry(new ZipEntry(entryPrefix + "a/a.jar")); + jarOutputStream.closeEntry(); + jarOutputStream.putNextEntry(new ZipEntry(entryPrefix + "b/")); + jarOutputStream.closeEntry(); + jarOutputStream.putNextEntry(new ZipEntry(entryPrefix + "b/b.jar")); + jarOutputStream.closeEntry(); + jarOutputStream.putNextEntry(new ZipEntry(entryPrefix + "c/")); + jarOutputStream.closeEntry(); + jarOutputStream.putNextEntry(new ZipEntry(entryPrefix + "c/c.jar")); + jarOutputStream.closeEntry(); + jarOutputStream.putNextEntry(new ZipEntry(entryPrefix + "d/")); + jarOutputStream.closeEntry(); + } + return file; + } + + private void writeLayersIndex(ZipOutputStream out) throws IOException { + JarEntry indexEntry = new JarEntry("BOOT-INF/layers.idx"); + out.putNextEntry(indexEntry); + Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8); + writer.write("a\n"); + writer.write("b\n"); + writer.write("c\n"); + writer.write("d\n"); + writer.flush(); + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/resources/org/springframework/boot/jarmode/layertools/list-output.txt b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/resources/org/springframework/boot/jarmode/layertools/list-output.txt index 8f96e24d1d..f843c42935 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/resources/org/springframework/boot/jarmode/layertools/list-output.txt +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/resources/org/springframework/boot/jarmode/layertools/list-output.txt @@ -1,4 +1,5 @@ -dependencies -snapshot-dependencies -resources -application +springbootapplication +a +b +c +d