This is an automated email from the ASF dual-hosted git repository. matrei pushed a commit to branch 15186-zip-date in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit fa79873fda5bf24a87c56f63f8c952049c212b15 Author: Mattias Reichel <[email protected]> AuthorDate: Mon Nov 3 10:47:48 2025 +0100 fix(forge): explicit zip directories and entry metadata Fixes gh-15186 --- .../java/org/grails/forge/io/ZipOutputHandler.java | 45 ++++++++++++++++++++-- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/ZipOutputHandler.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/ZipOutputHandler.java index 17775db48c..0173cf6ea1 100644 --- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/ZipOutputHandler.java +++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/ZipOutputHandler.java @@ -31,12 +31,17 @@ import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.attribute.FileTime; +import java.time.Instant; +import java.util.HashSet; +import java.util.Set; public class ZipOutputHandler implements OutputHandler { private final ZipArchiveOutputStream zipOutputStream; private final File zip; private final String directory; + private final Set<String> createdDirs = new HashSet<>(); public ZipOutputHandler(Project project) throws IOException { File baseDirectory = new File(".").getCanonicalFile(); @@ -78,10 +83,19 @@ public class ZipOutputHandler implements OutputHandler { @Override public void write(String path, Template contents) throws IOException { - ZipArchiveEntry zipEntry = new ZipArchiveEntry(directory != null ? StringUtils.prependUri(directory, path) : path); - if (contents.isExecutable()) { - zipEntry.setUnixMode(UnixStat.FILE_FLAG | 0755); - } + String entryName = (directory != null ? StringUtils.prependUri(directory, path) : path); + FileTime lastModified = FileTime.from(Instant.now()); + + // ensure parent directories exist as explicit dir entries + // https://github.com/apache/grails-core/issues/15186 + createParentDirs(entryName, lastModified); + + ZipArchiveEntry zipEntry = new ZipArchiveEntry(entryName); + setZipEntryMetadata( + zipEntry, + lastModified, + UnixStat.FILE_FLAG | (contents.isExecutable() ? 0755 : 0644) + ); zipOutputStream.putArchiveEntry(zipEntry); contents.write(zipOutputStream); zipOutputStream.closeArchiveEntry(); @@ -92,4 +106,27 @@ public class ZipOutputHandler implements OutputHandler { zipOutputStream.finish(); zipOutputStream.close(); } + + private void createParentDirs(String entryName, FileTime lastModified) throws IOException { + int slash = entryName.lastIndexOf('/'); + if (slash < 0) return; + + int i = 0; + while ((i = entryName.indexOf('/', i)) >= 0) { + String dir = entryName.substring(0, i + 1); + if (createdDirs.add(dir)) { + ZipArchiveEntry directoryEntry = new ZipArchiveEntry(dir); + setZipEntryMetadata(directoryEntry, lastModified, UnixStat.DIR_FLAG | 0755); + zipOutputStream.putArchiveEntry(directoryEntry); + zipOutputStream.closeArchiveEntry(); + } + i++; + } + } + + private void setZipEntryMetadata(ZipArchiveEntry zipEntry, FileTime lastModified, int unixMode) { + zipEntry.setLastModifiedTime(lastModified); + zipEntry.setTime(lastModified.toMillis()); + zipEntry.setUnixMode(unixMode); + } }
