mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-08-29 03:06:45 +08:00
Apply Gradle fileMode and dirMode consistently in jar and war archives
Fixes gh-37496
This commit is contained in:
parent
fce64878b4
commit
aeeb5cf1f8
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2022 the original author or authors.
|
* Copyright 2012-2023 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -47,6 +47,7 @@ import org.gradle.api.tasks.util.PatternSet;
|
|||||||
*
|
*
|
||||||
* @author Andy Wilkinson
|
* @author Andy Wilkinson
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Scott Frederick
|
||||||
* @see BootJar
|
* @see BootJar
|
||||||
* @see BootWar
|
* @see BootWar
|
||||||
*/
|
*/
|
||||||
@ -113,6 +114,8 @@ class BootArchiveSupport {
|
|||||||
File output = jar.getArchiveFile().get().getAsFile();
|
File output = jar.getArchiveFile().get().getAsFile();
|
||||||
Manifest manifest = jar.getManifest();
|
Manifest manifest = jar.getManifest();
|
||||||
boolean preserveFileTimestamps = jar.isPreserveFileTimestamps();
|
boolean preserveFileTimestamps = jar.isPreserveFileTimestamps();
|
||||||
|
Integer dirMode = jar.getDirMode();
|
||||||
|
Integer fileMode = jar.getFileMode();
|
||||||
boolean includeDefaultLoader = isUsingDefaultLoader(jar);
|
boolean includeDefaultLoader = isUsingDefaultLoader(jar);
|
||||||
Spec<FileTreeElement> requiresUnpack = this.requiresUnpack.getAsSpec();
|
Spec<FileTreeElement> requiresUnpack = this.requiresUnpack.getAsSpec();
|
||||||
Spec<FileTreeElement> exclusions = this.exclusions.getAsExcludeSpec();
|
Spec<FileTreeElement> exclusions = this.exclusions.getAsExcludeSpec();
|
||||||
@ -120,9 +123,9 @@ class BootArchiveSupport {
|
|||||||
Spec<FileCopyDetails> librarySpec = this.librarySpec;
|
Spec<FileCopyDetails> librarySpec = this.librarySpec;
|
||||||
Function<FileCopyDetails, ZipCompression> compressionResolver = this.compressionResolver;
|
Function<FileCopyDetails, ZipCompression> compressionResolver = this.compressionResolver;
|
||||||
String encoding = jar.getMetadataCharset();
|
String encoding = jar.getMetadataCharset();
|
||||||
CopyAction action = new BootZipCopyAction(output, manifest, preserveFileTimestamps, includeDefaultLoader,
|
CopyAction action = new BootZipCopyAction(output, manifest, preserveFileTimestamps, dirMode, fileMode,
|
||||||
layerToolsLocation, requiresUnpack, exclusions, launchScript, librarySpec, compressionResolver,
|
includeDefaultLoader, layerToolsLocation, requiresUnpack, exclusions, launchScript, librarySpec,
|
||||||
encoding, layerResolver);
|
compressionResolver, encoding, layerResolver);
|
||||||
return jar.isReproducibleFileOrder() ? new ReproducibleOrderingCopyAction(action) : action;
|
return jar.isReproducibleFileOrder() ? new ReproducibleOrderingCopyAction(action) : action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +77,10 @@ class BootZipCopyAction implements CopyAction {
|
|||||||
|
|
||||||
private final boolean preserveFileTimestamps;
|
private final boolean preserveFileTimestamps;
|
||||||
|
|
||||||
|
private final Integer dirMode;
|
||||||
|
|
||||||
|
private final Integer fileMode;
|
||||||
|
|
||||||
private final boolean includeDefaultLoader;
|
private final boolean includeDefaultLoader;
|
||||||
|
|
||||||
private final String layerToolsLocation;
|
private final String layerToolsLocation;
|
||||||
@ -95,14 +99,16 @@ class BootZipCopyAction implements CopyAction {
|
|||||||
|
|
||||||
private final LayerResolver layerResolver;
|
private final LayerResolver layerResolver;
|
||||||
|
|
||||||
BootZipCopyAction(File output, Manifest manifest, boolean preserveFileTimestamps, boolean includeDefaultLoader,
|
BootZipCopyAction(File output, Manifest manifest, boolean preserveFileTimestamps, Integer dirMode, Integer fileMode,
|
||||||
String layerToolsLocation, Spec<FileTreeElement> requiresUnpack, Spec<FileTreeElement> exclusions,
|
boolean includeDefaultLoader, String layerToolsLocation, Spec<FileTreeElement> requiresUnpack,
|
||||||
LaunchScriptConfiguration launchScript, Spec<FileCopyDetails> librarySpec,
|
Spec<FileTreeElement> exclusions, LaunchScriptConfiguration launchScript, Spec<FileCopyDetails> librarySpec,
|
||||||
Function<FileCopyDetails, ZipCompression> compressionResolver, String encoding,
|
Function<FileCopyDetails, ZipCompression> compressionResolver, String encoding,
|
||||||
LayerResolver layerResolver) {
|
LayerResolver layerResolver) {
|
||||||
this.output = output;
|
this.output = output;
|
||||||
this.manifest = manifest;
|
this.manifest = manifest;
|
||||||
this.preserveFileTimestamps = preserveFileTimestamps;
|
this.preserveFileTimestamps = preserveFileTimestamps;
|
||||||
|
this.dirMode = dirMode;
|
||||||
|
this.fileMode = fileMode;
|
||||||
this.includeDefaultLoader = includeDefaultLoader;
|
this.includeDefaultLoader = includeDefaultLoader;
|
||||||
this.layerToolsLocation = layerToolsLocation;
|
this.layerToolsLocation = layerToolsLocation;
|
||||||
this.requiresUnpack = requiresUnpack;
|
this.requiresUnpack = requiresUnpack;
|
||||||
@ -225,7 +231,7 @@ class BootZipCopyAction implements CopyAction {
|
|||||||
private void processDirectory(FileCopyDetails details) throws IOException {
|
private void processDirectory(FileCopyDetails details) throws IOException {
|
||||||
String name = details.getRelativePath().getPathString();
|
String name = details.getRelativePath().getPathString();
|
||||||
ZipArchiveEntry entry = new ZipArchiveEntry(name + '/');
|
ZipArchiveEntry entry = new ZipArchiveEntry(name + '/');
|
||||||
prepareEntry(entry, name, getTime(details), UnixStat.FILE_FLAG | details.getMode());
|
prepareEntry(entry, name, getTime(details), getFileMode(details));
|
||||||
this.out.putArchiveEntry(entry);
|
this.out.putArchiveEntry(entry);
|
||||||
this.out.closeArchiveEntry();
|
this.out.closeArchiveEntry();
|
||||||
this.writtenDirectories.add(name);
|
this.writtenDirectories.add(name);
|
||||||
@ -234,7 +240,7 @@ class BootZipCopyAction implements CopyAction {
|
|||||||
private void processFile(FileCopyDetails details) throws IOException {
|
private void processFile(FileCopyDetails details) throws IOException {
|
||||||
String name = details.getRelativePath().getPathString();
|
String name = details.getRelativePath().getPathString();
|
||||||
ZipArchiveEntry entry = new ZipArchiveEntry(name);
|
ZipArchiveEntry entry = new ZipArchiveEntry(name);
|
||||||
prepareEntry(entry, name, getTime(details), UnixStat.FILE_FLAG | details.getMode());
|
prepareEntry(entry, name, getTime(details), getFileMode(details));
|
||||||
ZipCompression compression = BootZipCopyAction.this.compressionResolver.apply(details);
|
ZipCompression compression = BootZipCopyAction.this.compressionResolver.apply(details);
|
||||||
if (compression == ZipCompression.STORED) {
|
if (compression == ZipCompression.STORED) {
|
||||||
prepareStoredEntry(details, entry);
|
prepareStoredEntry(details, entry);
|
||||||
@ -255,7 +261,7 @@ class BootZipCopyAction implements CopyAction {
|
|||||||
String parentDirectory = getParentDirectory(name);
|
String parentDirectory = getParentDirectory(name);
|
||||||
if (parentDirectory != null && this.writtenDirectories.add(parentDirectory)) {
|
if (parentDirectory != null && this.writtenDirectories.add(parentDirectory)) {
|
||||||
ZipArchiveEntry entry = new ZipArchiveEntry(parentDirectory + '/');
|
ZipArchiveEntry entry = new ZipArchiveEntry(parentDirectory + '/');
|
||||||
prepareEntry(entry, parentDirectory, time, UnixStat.DIR_FLAG | UnixStat.DEFAULT_DIR_PERM);
|
prepareEntry(entry, parentDirectory, time, getDirMode());
|
||||||
this.out.putArchiveEntry(entry);
|
this.out.putArchiveEntry(entry);
|
||||||
this.out.closeArchiveEntry();
|
this.out.closeArchiveEntry();
|
||||||
}
|
}
|
||||||
@ -285,7 +291,7 @@ class BootZipCopyAction implements CopyAction {
|
|||||||
// Always write loader entries after META-INF directory (see gh-16698)
|
// Always write loader entries after META-INF directory (see gh-16698)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LoaderZipEntries loaderEntries = new LoaderZipEntries(getTime());
|
LoaderZipEntries loaderEntries = new LoaderZipEntries(getTime(), getDirMode(), getFileMode());
|
||||||
this.writtenLoaderEntries = loaderEntries.writeTo(this.out);
|
this.writtenLoaderEntries = loaderEntries.writeTo(this.out);
|
||||||
if (BootZipCopyAction.this.layerResolver != null) {
|
if (BootZipCopyAction.this.layerResolver != null) {
|
||||||
for (String name : this.writtenLoaderEntries.getFiles()) {
|
for (String name : this.writtenLoaderEntries.getFiles()) {
|
||||||
@ -350,7 +356,7 @@ class BootZipCopyAction implements CopyAction {
|
|||||||
private void writeEntry(String name, ZipEntryContentWriter entryWriter, boolean addToLayerIndex,
|
private void writeEntry(String name, ZipEntryContentWriter entryWriter, boolean addToLayerIndex,
|
||||||
ZipEntryCustomizer entryCustomizer) throws IOException {
|
ZipEntryCustomizer entryCustomizer) throws IOException {
|
||||||
ZipArchiveEntry entry = new ZipArchiveEntry(name);
|
ZipArchiveEntry entry = new ZipArchiveEntry(name);
|
||||||
prepareEntry(entry, name, getTime(), UnixStat.FILE_FLAG | UnixStat.DEFAULT_FILE_PERM);
|
prepareEntry(entry, name, getTime(), getFileMode());
|
||||||
entryCustomizer.customize(entry);
|
entryCustomizer.customize(entry);
|
||||||
this.out.putArchiveEntry(entry);
|
this.out.putArchiveEntry(entry);
|
||||||
entryWriter.writeTo(this.out);
|
entryWriter.writeTo(this.out);
|
||||||
@ -394,6 +400,21 @@ class BootZipCopyAction implements CopyAction {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getDirMode() {
|
||||||
|
return (BootZipCopyAction.this.dirMode != null) ? BootZipCopyAction.this.dirMode
|
||||||
|
: UnixStat.DIR_FLAG | UnixStat.DEFAULT_DIR_PERM;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getFileMode() {
|
||||||
|
return (BootZipCopyAction.this.fileMode != null) ? BootZipCopyAction.this.fileMode
|
||||||
|
: UnixStat.FILE_FLAG | UnixStat.DEFAULT_FILE_PERM;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getFileMode(FileCopyDetails details) {
|
||||||
|
return (BootZipCopyAction.this.fileMode != null) ? BootZipCopyAction.this.fileMode
|
||||||
|
: UnixStat.FILE_FLAG | details.getMode();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,7 +24,6 @@ import java.util.Set;
|
|||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
import org.apache.commons.compress.archivers.zip.UnixStat;
|
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
|
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
|
||||||
import org.gradle.api.file.FileTreeElement;
|
import org.gradle.api.file.FileTreeElement;
|
||||||
@ -42,8 +41,14 @@ class LoaderZipEntries {
|
|||||||
|
|
||||||
private final Long entryTime;
|
private final Long entryTime;
|
||||||
|
|
||||||
LoaderZipEntries(Long entryTime) {
|
private final int dirMode;
|
||||||
|
|
||||||
|
private final int fileMode;
|
||||||
|
|
||||||
|
LoaderZipEntries(Long entryTime, int dirMode, int fileMode) {
|
||||||
this.entryTime = entryTime;
|
this.entryTime = entryTime;
|
||||||
|
this.dirMode = dirMode;
|
||||||
|
this.fileMode = fileMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
WrittenEntries writeTo(ZipArchiveOutputStream out) throws IOException {
|
WrittenEntries writeTo(ZipArchiveOutputStream out) throws IOException {
|
||||||
@ -67,13 +72,13 @@ class LoaderZipEntries {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void writeDirectory(ZipArchiveEntry entry, ZipArchiveOutputStream out) throws IOException {
|
private void writeDirectory(ZipArchiveEntry entry, ZipArchiveOutputStream out) throws IOException {
|
||||||
prepareEntry(entry, UnixStat.DIR_FLAG | UnixStat.DEFAULT_DIR_PERM);
|
prepareEntry(entry, this.dirMode);
|
||||||
out.putArchiveEntry(entry);
|
out.putArchiveEntry(entry);
|
||||||
out.closeArchiveEntry();
|
out.closeArchiveEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeClass(ZipArchiveEntry entry, ZipInputStream in, ZipArchiveOutputStream out) throws IOException {
|
private void writeClass(ZipArchiveEntry entry, ZipInputStream in, ZipArchiveOutputStream out) throws IOException {
|
||||||
prepareEntry(entry, UnixStat.FILE_FLAG | UnixStat.DEFAULT_FILE_PERM);
|
prepareEntry(entry, this.fileMode);
|
||||||
out.putArchiveEntry(entry);
|
out.putArchiveEntry(entry);
|
||||||
copy(in, out);
|
copy(in, out);
|
||||||
out.closeArchiveEntry();
|
out.closeArchiveEntry();
|
||||||
|
@ -29,6 +29,7 @@ import java.nio.file.Path;
|
|||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Enumeration;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -45,6 +46,9 @@ import java.util.stream.Collectors;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
|
|
||||||
|
import org.apache.commons.compress.archivers.zip.UnixStat;
|
||||||
|
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||||
|
import org.apache.commons.compress.archivers.zip.ZipFile;
|
||||||
import org.gradle.testkit.runner.BuildResult;
|
import org.gradle.testkit.runner.BuildResult;
|
||||||
import org.gradle.testkit.runner.TaskOutcome;
|
import org.gradle.testkit.runner.TaskOutcome;
|
||||||
import org.junit.jupiter.api.TestTemplate;
|
import org.junit.jupiter.api.TestTemplate;
|
||||||
@ -62,6 +66,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
*
|
*
|
||||||
* @author Andy Wilkinson
|
* @author Andy Wilkinson
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
|
* @author Scott Frederick
|
||||||
*/
|
*/
|
||||||
abstract class AbstractBootArchiveIntegrationTests {
|
abstract class AbstractBootArchiveIntegrationTests {
|
||||||
|
|
||||||
@ -515,6 +520,48 @@ abstract class AbstractBootArchiveIntegrationTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestTemplate
|
||||||
|
void defaultDirAndFileModesAreUsed() throws IOException {
|
||||||
|
BuildResult result = this.gradleBuild.build(this.taskName);
|
||||||
|
assertThat(result.task(":" + this.taskName).getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
|
||||||
|
try (ZipFile jarFile = new ZipFile(new File(this.gradleBuild.getProjectDir(), "build/libs").listFiles()[0])) {
|
||||||
|
Enumeration<ZipArchiveEntry> entries = jarFile.getEntries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
ZipArchiveEntry entry = entries.nextElement();
|
||||||
|
if (entry.getName().startsWith("META-INF/")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
assertEntryMode(entry, UnixStat.DIR_FLAG | UnixStat.DEFAULT_DIR_PERM);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertEntryMode(entry, UnixStat.FILE_FLAG | UnixStat.DEFAULT_FILE_PERM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestTemplate
|
||||||
|
void dirModeAndFileModeAreApplied() throws IOException {
|
||||||
|
BuildResult result = this.gradleBuild.build(this.taskName);
|
||||||
|
assertThat(result.task(":" + this.taskName).getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
|
||||||
|
try (ZipFile jarFile = new ZipFile(new File(this.gradleBuild.getProjectDir(), "build/libs").listFiles()[0])) {
|
||||||
|
Enumeration<ZipArchiveEntry> entries = jarFile.getEntries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
ZipArchiveEntry entry = entries.nextElement();
|
||||||
|
if (entry.getName().startsWith("META-INF/")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
assertEntryMode(entry, 0500);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertEntryMode(entry, 0400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void copyMainClassApplication() throws IOException {
|
private void copyMainClassApplication() throws IOException {
|
||||||
copyApplication("main");
|
copyApplication("main");
|
||||||
}
|
}
|
||||||
@ -650,4 +697,11 @@ abstract class AbstractBootArchiveIntegrationTests {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void assertEntryMode(ZipArchiveEntry entry, int expectedMode) {
|
||||||
|
assertThat(entry.getUnixMode())
|
||||||
|
.withFailMessage(() -> "Expected mode " + Integer.toOctalString(expectedMode) + " for entry "
|
||||||
|
+ entry.getName() + " but actual is " + Integer.toOctalString(entry.getUnixMode()))
|
||||||
|
.isEqualTo(expectedMode);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
plugins {
|
||||||
|
id 'java'
|
||||||
|
id 'org.springframework.boot' version '{version}'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named("bootJar") {
|
||||||
|
fileMode = 0400
|
||||||
|
dirMode = 0500
|
||||||
|
mainClass = 'com.example.Application'
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
plugins {
|
||||||
|
id 'war'
|
||||||
|
id 'org.springframework.boot' version '{version}'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named("bootWar") {
|
||||||
|
fileMode = 0400
|
||||||
|
dirMode = 0500
|
||||||
|
mainClass = 'com.example.Application'
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user