From 9f3bc78f364bcb3b81344c201ff26945bc6be011 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 18 Mar 2020 09:51:57 +0000 Subject: [PATCH] Update extract to write files to their original, unlayered location --- .../jarmode/layertools/ExtractCommand.java | 2 +- .../jarmode/layertools/IndexedLayers.java | 14 ++++++++++++- .../boot/jarmode/layertools/Layers.java | 7 +++++++ .../layertools/ExtractCommandTests.java | 21 ++++++++++++------- .../layertools/IndexedLayersTests.java | 18 ++++++++++++++++ 5 files changed, 52 insertions(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/ExtractCommand.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/ExtractCommand.java index eeee906400..7142784997 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/ExtractCommand.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/ExtractCommand.java @@ -83,7 +83,7 @@ class ExtractCommand extends Command { } private void write(ZipInputStream zip, ZipEntry entry, File destination) throws IOException { - String path = StringUtils.cleanPath(entry.getName()); + String path = StringUtils.cleanPath(this.layers.getOriginalLocation(entry)); File file = new File(destination, path); if (file.getAbsolutePath().startsWith(destination.getAbsolutePath())) { mkParentDirs(file); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/IndexedLayers.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/IndexedLayers.java index f09e0d3f22..32871cd270 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/IndexedLayers.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/IndexedLayers.java @@ -44,7 +44,7 @@ class IndexedLayers implements Layers { private static final String SPRING_BOOT_APPLICATION_LAYER = "springbootapplication"; - private static final Pattern LAYER_PATTERN = Pattern.compile("^BOOT-INF\\/layers\\/([a-zA-Z0-9-]+)\\/.*$"); + private static final Pattern LAYER_PATTERN = Pattern.compile("^BOOT-INF\\/layers\\/([a-zA-Z0-9-]+)\\/(.*$)"); private List layers; @@ -74,6 +74,18 @@ class IndexedLayers implements Layers { } return this.layers.contains(APPLICATION_LAYER) ? APPLICATION_LAYER : SPRING_BOOT_APPLICATION_LAYER; } + + @Override + public String getOriginalLocation(ZipEntry entry) { + String name = entry.getName(); + Matcher matcher = LAYER_PATTERN.matcher(name); + if (matcher.matches()) { + String layer = matcher.group(1); + Assert.state(this.layers.contains(layer), () -> "Unexpected layer '" + layer + "'"); + return "BOOT-INF/" + matcher.group(2); + } + return name; + } /** * Get an {@link IndexedLayers} instance of possible. 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 181efb3cd8..44ecb45908 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 @@ -41,6 +41,13 @@ interface Layers extends Iterable { * @return the layer that the entry is in */ String getLayer(ZipEntry entry); + + /** + * Returns the original, unlayered location of the given entry. + * @param entry the entry for which the original location is required + * @return the original location + */ + String getOriginalLocation(ZipEntry entry); /** * Return a {@link Layers} instance for the currently running application. diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ExtractCommandTests.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ExtractCommandTests.java index cc0a9e2372..feb240acf8 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ExtractCommandTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ExtractCommandTests.java @@ -70,9 +70,9 @@ class ExtractCommandTests { void runExtractsLayers() throws Exception { this.command.run(Collections.emptyMap(), Collections.emptyList()); assertThat(this.extract.list()).containsOnly("a", "b", "c"); - assertThat(new File(this.extract, "a/a/a.jar")).exists(); - assertThat(new File(this.extract, "b/b/b.jar")).exists(); - assertThat(new File(this.extract, "c/c/c.jar")).exists(); + assertThat(new File(this.extract, "a/a.jar")).exists(); + assertThat(new File(this.extract, "b/b.jar")).exists(); + assertThat(new File(this.extract, "c/c.jar")).exists(); } @Test @@ -81,17 +81,17 @@ class ExtractCommandTests { this.command.run(Collections.singletonMap(ExtractCommand.DESTINATION_OPTION, out.getAbsolutePath()), Collections.emptyList()); assertThat(this.extract.list()).containsOnly("out"); - assertThat(new File(this.extract, "out/a/a/a.jar")).exists(); - assertThat(new File(this.extract, "out/b/b/b.jar")).exists(); - assertThat(new File(this.extract, "out/c/c/c.jar")).exists(); + assertThat(new File(this.extract, "out/a/a.jar")).exists(); + assertThat(new File(this.extract, "out/b/b.jar")).exists(); + assertThat(new File(this.extract, "out/c/c.jar")).exists(); } @Test void runWhenHasLayerParamsExtractsLimitedLayers() { this.command.run(Collections.emptyMap(), Arrays.asList("a", "c")); assertThat(this.extract.list()).containsOnly("a", "c"); - assertThat(new File(this.extract, "a/a/a.jar")).exists(); - assertThat(new File(this.extract, "c/c/c.jar")).exists(); + assertThat(new File(this.extract, "a/a.jar")).exists(); + assertThat(new File(this.extract, "c/c.jar")).exists(); } private File createJarFile(String name) throws IOException { @@ -133,6 +133,11 @@ class ExtractCommandTests { return "c"; } + @Override + public String getOriginalLocation(ZipEntry entry) { + return entry.getName().substring(2); + } + } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/IndexedLayersTests.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/IndexedLayersTests.java index ac4d668ec7..694b0f7b53 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/IndexedLayersTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/IndexedLayersTests.java @@ -75,6 +75,24 @@ class IndexedLayersTests { IndexedLayers layers = new IndexedLayers("test"); assertThat(layers.getLayer(mockEntry("META-INF/MANIFEST.MF"))).isEqualTo("springbootapplication"); } + + @Test + void getOriginalLocationWithLibJarReturnsBootInfLibLocation() { + IndexedLayers layers = new IndexedLayers("test"); + assertThat(layers.getOriginalLocation(mockEntry("BOOT-INF/layers/test/lib/file.jar"))).isEqualTo("BOOT-INF/lib/file.jar"); + } + + @Test + void getOriginalLocationWithClassesEntryReturnsBootInfClassesLocation() { + IndexedLayers layers = new IndexedLayers("test"); + assertThat(layers.getOriginalLocation(mockEntry("BOOT-INF/layers/test/classes/com/example/Test.class"))).isEqualTo("BOOT-INF/classes/com/example/Test.class"); + } + + @Test + void getOriginalLocationWhenDoesNotMatchLayerPatternsReturnsEntryLocationAsIs() { + IndexedLayers layers = new IndexedLayers("test"); + assertThat(layers.getOriginalLocation(mockEntry("META-INF/MANIFEST.MF"))).isEqualTo("META-INF/MANIFEST.MF"); + } private ZipEntry mockEntry(String name) { ZipEntry entry = mock(ZipEntry.class);