Merge branch '3.1.x'

Closes gh-37589
pull/37576/merge
Scott Frederick 1 year ago
commit d37e9424a2

@ -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
*/ */
@ -124,6 +125,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();
@ -131,9 +134,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, resolvedDependencies, layerResolver); compressionResolver, encoding, resolvedDependencies, layerResolver);
return jar.isReproducibleFileOrder() ? new ReproducibleOrderingCopyAction(action) : action; return jar.isReproducibleFileOrder() ? new ReproducibleOrderingCopyAction(action) : action;
} }

@ -87,6 +87,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;
@ -107,14 +111,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,
ResolvedDependencies resolvedDependencies, LayerResolver layerResolver) { ResolvedDependencies resolvedDependencies, 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;
@ -240,7 +246,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);
@ -249,7 +255,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);
@ -273,7 +279,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();
} }
@ -304,7 +310,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()) {
@ -393,7 +399,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);
@ -437,6 +443,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;
@ -44,6 +45,9 @@ import java.util.jar.Manifest;
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;
@ -61,6 +65,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 {
@ -523,6 +528,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");
} }
@ -660,4 +707,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…
Cancel
Save