Skip to content

Commit 84b672e

Browse files
committed
Fix timestamp preservation when extracting cached files
The build cache extension was not properly preserving file and directory timestamps when restoring attachedOutputs from cache. This caused Maven to warn about files being 'more recent than the packaged artifact' even after a successful build. Root Causes: 1. The zip() method did not store directory entries with timestamps 2. The unzip() method set directory timestamps immediately, but they were later modified by Files.copy() operations for files within Changes: - Modified CacheUtils.zip() to store directory entries with timestamps via preVisitDirectory() callback - Modified CacheUtils.unzip() to defer directory timestamp updates until after all files are extracted, preventing them from being overwritten - Added Map<Path, Long> to track directory timestamps during extraction This ensures that cached build outputs maintain their original timestamps, preventing spurious warnings and improving build cache consistency.
1 parent 652709f commit 84b672e

File tree

1 file changed

+40
-12
lines changed

1 file changed

+40
-12
lines changed

src/main/java/org/apache/maven/buildcache/CacheUtils.java

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@
3232
import java.nio.file.attribute.PosixFilePermission;
3333
import java.util.Arrays;
3434
import java.util.Collection;
35+
import java.util.HashMap;
3536
import java.util.HashSet;
3637
import java.util.List;
38+
import java.util.Map;
3739
import java.util.NoSuchElementException;
3840
import java.util.Set;
3941
import java.util.stream.Stream;
@@ -179,6 +181,18 @@ public static boolean zip(final Path dir, final Path zip, final String glob, boo
179181
"*".equals(glob) ? null : FileSystems.getDefault().getPathMatcher("glob:" + glob);
180182
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
181183

184+
@Override
185+
public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes attrs) throws IOException {
186+
if (!path.equals(dir)) {
187+
String relativePath = dir.relativize(path).toString() + "/";
188+
ZipArchiveEntry zipEntry = new ZipArchiveEntry(relativePath);
189+
zipEntry.setTime(attrs.lastModifiedTime().toMillis());
190+
zipOutputStream.putArchiveEntry(zipEntry);
191+
zipOutputStream.closeArchiveEntry();
192+
}
193+
return FileVisitResult.CONTINUE;
194+
}
195+
182196
@Override
183197
public FileVisitResult visitFile(Path path, BasicFileAttributes basicFileAttributes)
184198
throws IOException {
@@ -187,6 +201,9 @@ public FileVisitResult visitFile(Path path, BasicFileAttributes basicFileAttribu
187201
final ZipArchiveEntry zipEntry =
188202
new ZipArchiveEntry(dir.relativize(path).toString());
189203

204+
// Preserve timestamp
205+
zipEntry.setTime(basicFileAttributes.lastModifiedTime().toMillis());
206+
190207
// Preserve Unix permissions if requested and filesystem supports it
191208
if (supportsPosix) {
192209
Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(path);
@@ -210,6 +227,7 @@ public static void unzip(Path zip, Path out, boolean preservePermissions) throws
210227
final boolean supportsPosix = preservePermissions
211228
&& out.getFileSystem().supportedFileAttributeViews().contains("posix");
212229

230+
Map<Path, Long> directoryTimestamps = new HashMap<>();
213231
try (ZipArchiveInputStream zis = new ZipArchiveInputStream(Files.newInputStream(zip))) {
214232
ZipArchiveEntry entry = zis.getNextEntry();
215233
while (entry != null) {
@@ -218,26 +236,36 @@ public static void unzip(Path zip, Path out, boolean preservePermissions) throws
218236
throw new RuntimeException("Bad zip entry");
219237
}
220238
if (entry.isDirectory()) {
221-
Files.createDirectory(file);
239+
if (!Files.exists(file)) {
240+
Files.createDirectories(file);
241+
}
242+
directoryTimestamps.put(file, entry.getTime());
222243
} else {
223244
Path parent = file.getParent();
224-
Files.createDirectories(parent);
245+
if (!Files.exists(parent)) {
246+
Files.createDirectories(parent);
247+
}
225248
Files.copy(zis, file, StandardCopyOption.REPLACE_EXISTING);
226-
}
227-
Files.setLastModifiedTime(file, FileTime.fromMillis(entry.getTime()));
228-
229-
// Restore Unix permissions if requested and filesystem supports it
230-
if (supportsPosix) {
231-
int unixMode = entry.getUnixMode();
232-
if (unixMode != 0) {
233-
Set<PosixFilePermission> permissions = modeToPermissions(unixMode);
234-
Files.setPosixFilePermissions(file, permissions);
249+
Files.setLastModifiedTime(file, FileTime.fromMillis(entry.getTime()));
250+
251+
// Restore Unix permissions if requested and filesystem supports it
252+
if (supportsPosix) {
253+
int unixMode = entry.getUnixMode();
254+
if (unixMode != 0) {
255+
Set<PosixFilePermission> permissions = modeToPermissions(unixMode);
256+
Files.setPosixFilePermissions(file, permissions);
257+
}
235258
}
236259
}
237-
238260
entry = zis.getNextEntry();
239261
}
240262
}
263+
264+
// Set directory timestamps after all files have been extracted to avoid them being
265+
// updated by file creation operations
266+
for (Map.Entry<Path, Long> dirEntry : directoryTimestamps.entrySet()) {
267+
Files.setLastModifiedTime(dirEntry.getKey(), FileTime.fromMillis(dirEntry.getValue()));
268+
}
241269
}
242270

243271
public static <T> void debugPrintCollection(

0 commit comments

Comments
 (0)