summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java8
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ObjectFileServlet.java9
-rw-r--r--org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java11
-rw-r--r--org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java19
-rw-r--r--org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/time/TimeUtil.java99
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowDirCache.java22
-rw-r--r--org.eclipse.jgit.test/META-INF/MANIFEST.MF5
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java2
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java22
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java24
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java4
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java28
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java15
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java7
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java14
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileSnapshotTest.java23
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java7
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java20
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileSnapshotTest.java24
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java8
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java12
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexModificationTimesTest.java31
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java14
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java47
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java7
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java22
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java8
-rw-r--r--org.eclipse.jgit/.settings/.api_filters62
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java5
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java11
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java13
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java47
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java128
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java9
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java21
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java7
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java45
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java9
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/OpenSshConfig.java7
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java9
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java67
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java71
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java37
50 files changed, 783 insertions, 290 deletions
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java
index 05510a05b0..946fb15a3d 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java
@@ -58,12 +58,14 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.text.MessageFormat;
+import java.time.Instant;
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.util.FS;
/**
* Dumps a file over HTTP GET (or its information via HEAD).
@@ -76,7 +78,7 @@ final class FileSender {
private final RandomAccessFile source;
- private final long lastModified;
+ private final Instant lastModified;
private final long fileLen;
@@ -89,7 +91,7 @@ final class FileSender {
this.source = new RandomAccessFile(path, "r");
try {
- this.lastModified = path.lastModified();
+ this.lastModified = FS.DETECTED.lastModifiedInstant(path);
this.fileLen = source.getChannel().size();
this.end = fileLen;
} catch (IOException e) {
@@ -114,7 +116,7 @@ final class FileSender {
}
}
- long getLastModified() {
+ Instant getLastModified() {
return lastModified;
}
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ObjectFileServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ObjectFileServlet.java
index 62f075c73c..5a27be6430 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ObjectFileServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ObjectFileServlet.java
@@ -54,6 +54,7 @@ import static org.eclipse.jgit.util.HttpSupport.HDR_LAST_MODIFIED;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.time.Instant;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
@@ -76,7 +77,9 @@ abstract class ObjectFileServlet extends HttpServlet {
@Override
String etag(FileSender sender) throws IOException {
- return Long.toHexString(sender.getLastModified());
+ Instant lastModified = sender.getLastModified();
+ return Long.toHexString(lastModified.getEpochSecond())
+ + Long.toHexString(lastModified.getNano());
}
}
@@ -145,7 +148,9 @@ abstract class ObjectFileServlet extends HttpServlet {
try {
final String etag = etag(sender);
- final long lastModified = (sender.getLastModified() / 1000) * 1000;
+ // HTTP header Last-Modified header has a resolution of 1 sec, see
+ // https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.29
+ final long lastModified = sender.getLastModified().getEpochSecond();
String ifNoneMatch = req.getHeader(HDR_IF_NONE_MATCH);
if (etag != null && etag.equals(ifNoneMatch)) {
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
index 12b2169500..50e6f2da5a 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
@@ -51,6 +51,7 @@ import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -322,12 +323,13 @@ public abstract class LocalDiskRepositoryTestCase {
throws IllegalStateException, IOException {
DirCache dc = repo.readDirCache();
StringBuilder sb = new StringBuilder();
- TreeSet<Long> timeStamps = new TreeSet<>();
+ TreeSet<Instant> timeStamps = new TreeSet<>();
// iterate once over the dircache just to collect all time stamps
if (0 != (includedOptions & MOD_TIME)) {
- for (int i=0; i<dc.getEntryCount(); ++i)
- timeStamps.add(Long.valueOf(dc.getEntry(i).getLastModified()));
+ for (int i = 0; i < dc.getEntryCount(); ++i) {
+ timeStamps.add(dc.getEntry(i).getLastModifiedInstant());
+ }
}
// iterate again, now produce the result string
@@ -339,7 +341,8 @@ public abstract class LocalDiskRepositoryTestCase {
sb.append(", stage:" + stage);
if (0 != (includedOptions & MOD_TIME)) {
sb.append(", time:t"+
- timeStamps.headSet(Long.valueOf(entry.getLastModified())).size());
+ timeStamps.headSet(entry.getLastModifiedInstant())
+ .size());
}
if (0 != (includedOptions & SMUDGE))
if (entry.isSmudged())
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
index 987f923b0e..49f5c5febb 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
@@ -57,7 +57,9 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.file.Path;
+import java.time.Instant;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
@@ -284,7 +286,7 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase {
dce = new DirCacheEntry(treeItr.getEntryPathString());
dce.setFileMode(treeItr.getEntryFileMode());
- dce.setLastModified(treeItr.getEntryLastModified());
+ dce.setLastModified(treeItr.getEntryLastModifiedInstant());
dce.setLength((int) len);
try (FileInputStream in = new FileInputStream(
treeItr.getEntryFile())) {
@@ -361,7 +363,8 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase {
* @throws InterruptedException
* @throws IOException
*/
- public static long fsTick(File lastFile) throws InterruptedException,
+ public static Instant fsTick(File lastFile)
+ throws InterruptedException,
IOException {
File tmp;
FS fs = FS.DETECTED;
@@ -375,15 +378,15 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase {
tmp = File.createTempFile("fsTickTmpFile", null,
lastFile.getParentFile());
}
- long res = FS.getFsTimerResolution(tmp.toPath()).toMillis();
+ long res = FS.getFsTimerResolution(tmp.toPath()).toNanos();
long sleepTime = res / 10;
try {
- long startTime = fs.lastModified(lastFile);
- long actTime = fs.lastModified(tmp);
- while (actTime <= startTime) {
- Thread.sleep(sleepTime);
+ Instant startTime = fs.lastModifiedInstant(lastFile);
+ Instant actTime = fs.lastModifiedInstant(tmp);
+ while (actTime.compareTo(startTime) <= 0) {
+ TimeUnit.NANOSECONDS.sleep(sleepTime);
FileUtils.touch(tmp.toPath());
- actTime = fs.lastModified(tmp);
+ actTime = fs.lastModifiedInstant(tmp);
}
return actTime;
} finally {
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/time/TimeUtil.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/time/TimeUtil.java
new file mode 100644
index 0000000000..1f8070d919
--- /dev/null
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/time/TimeUtil.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2019, Matthias Sohn <matthias.sohn@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.junit.time;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.FileTime;
+import java.time.Instant;
+
+import org.eclipse.jgit.util.FS;
+
+/**
+ * Utility methods for handling timestamps
+ */
+public class TimeUtil {
+ /**
+ * Set the lastModified time of a given file by adding a given offset to the
+ * current lastModified time
+ *
+ * @param path
+ * path of a file to set last modified
+ * @param offsetMillis
+ * offset in milliseconds, if negative the new lastModified time
+ * is offset before the original lastModified time, otherwise
+ * after the original time
+ * @return the new lastModified time
+ */
+ public static Instant setLastModifiedWithOffset(Path path,
+ long offsetMillis) {
+ Instant mTime = FS.DETECTED.lastModifiedInstant(path)
+ .plusMillis(offsetMillis);
+ try {
+ Files.setLastModifiedTime(path, FileTime.from(mTime));
+ return mTime;
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ /**
+ * Set the lastModified time of file a to the one from file b
+ *
+ * @param a
+ * file to set lastModified time
+ * @param b
+ * file to read lastModified time from
+ */
+ public static void setLastModifiedOf(Path a, Path b) {
+ Instant mTime = FS.DETECTED.lastModifiedInstant(b);
+ try {
+ Files.setLastModifiedTime(a, FileTime.from(mTime));
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowDirCache.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowDirCache.java
index 7f99d76bda..14a60a3b46 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowDirCache.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowDirCache.java
@@ -48,8 +48,10 @@ package org.eclipse.jgit.pgm.debug;
import static java.lang.Integer.valueOf;
-import java.text.SimpleDateFormat;
-import java.util.Date;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Locale;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEntry;
@@ -67,25 +69,27 @@ class ShowDirCache extends TextBuiltin {
/** {@inheritDoc} */
@Override
protected void run() throws Exception {
- final SimpleDateFormat fmt;
- fmt = new SimpleDateFormat("yyyy-MM-dd,HH:mm:ss.SSS"); //$NON-NLS-1$
+ final DateTimeFormatter fmt = DateTimeFormatter
+ .ofPattern("yyyy-MM-dd,HH:mm:ss.nnnnnnnnn") //$NON-NLS-1$
+ .withLocale(Locale.getDefault())
+ .withZone(ZoneId.systemDefault());
final DirCache cache = db.readDirCache();
for (int i = 0; i < cache.getEntryCount(); i++) {
final DirCacheEntry ent = cache.getEntry(i);
final FileMode mode = FileMode.fromBits(ent.getRawMode());
final int len = ent.getLength();
- long lastModified = ent.getLastModified();
- final Date mtime = new Date(lastModified);
+ Instant mtime = ent.getLastModifiedInstant();
final int stage = ent.getStage();
outw.print(mode);
outw.format(" %6d", valueOf(len)); //$NON-NLS-1$
outw.print(' ');
- if (millis)
- outw.print(lastModified);
- else
+ if (millis) {
+ outw.print(mtime.toEpochMilli());
+ } else {
outw.print(fmt.format(mtime));
+ }
outw.print(' ');
outw.print(ent.getObjectId().name());
outw.print(' ');
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index f469173aac..89ce34dbf4 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -40,6 +40,7 @@ Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
org.eclipse.jgit.internal.storage.reftable;version="[5.1.9,5.2.0)",
org.eclipse.jgit.internal.storage.reftree;version="[5.1.9,5.2.0)",
org.eclipse.jgit.junit;version="[5.1.9,5.2.0)",
+ org.eclipse.jgit.junit.time;version="[5.1.9,5.2.0)",
org.eclipse.jgit.lfs;version="[5.1.9,5.2.0)",
org.eclipse.jgit.lib;version="[5.1.9,5.2.0)",
org.eclipse.jgit.merge;version="[5.1.9,5.2.0)",
@@ -62,12 +63,12 @@ Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
org.eclipse.jgit.util;version="[5.1.9,5.2.0)",
org.eclipse.jgit.util.io;version="[5.1.9,5.2.0)",
org.eclipse.jgit.util.sha1;version="[5.1.9,5.2.0)",
- org.tukaani.xz;version="[1.6.0,2.0)",
org.junit;version="[4.12,5.0.0)",
org.junit.experimental.theories;version="[4.12,5.0.0)",
org.junit.rules;version="[4.12,5.0.0)",
org.junit.runner;version="[4.12,5.0.0)",
org.junit.runners;version="[4.12,5.0.0)",
- org.slf4j;version="[1.7.0,2.0.0)"
+ org.slf4j;version="[1.7.0,2.0.0)",
+ org.tukaani.xz;version="[1.6.0,2.0)"
Require-Bundle: org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
org.hamcrest.library;bundle-version="[1.1.0,2.0.0)"
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
index 911f659149..c67c86a937 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
@@ -1266,7 +1266,7 @@ public class AddCommandTest extends RepositoryTestCase {
DirCacheEntry entry = new DirCacheEntry(path, stage);
entry.setObjectId(id);
entry.setFileMode(FileMode.REGULAR_FILE);
- entry.setLastModified(file.lastModified());
+ entry.setLastModified(FS.DETECTED.lastModifiedInstant(file));
entry.setLength((int) file.length());
builder.add(entry);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
index 71df59e1ff..08ad7b8bcc 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
@@ -43,6 +43,7 @@
*/
package org.eclipse.jgit.api;
+import static java.time.Instant.EPOCH;
import static org.eclipse.jgit.lib.Constants.MASTER;
import static org.eclipse.jgit.lib.Constants.R_HEADS;
import static org.hamcrest.CoreMatchers.is;
@@ -60,6 +61,9 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.attribute.FileTime;
+import java.time.Instant;
import org.eclipse.jgit.api.CheckoutResult.Status;
import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
@@ -74,6 +78,7 @@ import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.junit.time.TimeUtil;
import org.eclipse.jgit.lfs.BuiltinLFS;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
@@ -86,6 +91,7 @@ import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
import org.eclipse.jgit.util.SystemReader;
import org.junit.Before;
@@ -360,14 +366,14 @@ public class CheckoutCommandTest extends RepositoryTestCase {
File file = new File(db.getWorkTree(), "Test.txt");
long size = file.length();
- long mTime = file.lastModified() - 5000L;
- assertTrue(file.setLastModified(mTime));
+ Instant mTime = TimeUtil.setLastModifiedWithOffset(file.toPath(),
+ -5000L);
DirCache cache = DirCache.lock(db.getIndexFile(), db.getFS());
DirCacheEntry entry = cache.getEntry("Test.txt");
assertNotNull(entry);
entry.setLength(0);
- entry.setLastModified(0);
+ entry.setLastModified(EPOCH);
cache.write();
assertTrue(cache.commit());
@@ -375,10 +381,12 @@ public class CheckoutCommandTest extends RepositoryTestCase {
entry = cache.getEntry("Test.txt");
assertNotNull(entry);
assertEquals(0, entry.getLength());
- assertEquals(0, entry.getLastModified());
+ assertEquals(EPOCH, entry.getLastModifiedInstant());
- db.getIndexFile().setLastModified(
- db.getIndexFile().lastModified() - 5000);
+ Files.setLastModifiedTime(db.getIndexFile().toPath(),
+ FileTime.from(FS.DETECTED
+ .lastModifiedInstant(db.getIndexFile())
+ .minusMillis(5000L)));
assertNotNull(git.checkout().setName("test").call());
@@ -386,7 +394,7 @@ public class CheckoutCommandTest extends RepositoryTestCase {
entry = cache.getEntry("Test.txt");
assertNotNull(entry);
assertEquals(size, entry.getLength());
- assertEquals(mTime, entry.getLastModified());
+ assertEquals(mTime, entry.getLastModifiedInstant());
}
@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
index 3a13aa5a41..a6072a0f5f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
@@ -61,6 +61,7 @@ import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.junit.time.TimeUtil;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
@@ -311,11 +312,11 @@ public class CommitCommandTest extends RepositoryTestCase {
public void commitUpdatesSmudgedEntries() throws Exception {
try (Git git = new Git(db)) {
File file1 = writeTrashFile("file1.txt", "content1");
- assertTrue(file1.setLastModified(file1.lastModified() - 5000));
+ TimeUtil.setLastModifiedWithOffset(file1.toPath(), -5000L);
File file2 = writeTrashFile("file2.txt", "content2");
- assertTrue(file2.setLastModified(file2.lastModified() - 5000));
+ TimeUtil.setLastModifiedWithOffset(file2.toPath(), -5000L);
File file3 = writeTrashFile("file3.txt", "content3");
- assertTrue(file3.setLastModified(file3.lastModified() - 5000));
+ TimeUtil.setLastModifiedWithOffset(file3.toPath(), -5000L);
assertNotNull(git.add().addFilepattern("file1.txt")
.addFilepattern("file2.txt").addFilepattern("file3.txt").call());
@@ -346,11 +347,12 @@ public class CommitCommandTest extends RepositoryTestCase {
assertEquals(0, cache.getEntry("file2.txt").getLength());
assertEquals(0, cache.getEntry("file3.txt").getLength());
- long indexTime = db.getIndexFile().lastModified();
- db.getIndexFile().setLastModified(indexTime - 5000);
+ TimeUtil.setLastModifiedWithOffset(db.getIndexFile().toPath(),
+ -5000L);
write(file1, "content4");
- assertTrue(file1.setLastModified(file1.lastModified() + 2500));
+
+ TimeUtil.setLastModifiedWithOffset(file1.toPath(), 2500L);
assertNotNull(git.commit().setMessage("edit file").setOnly("file1.txt")
.call());
@@ -368,9 +370,9 @@ public class CommitCommandTest extends RepositoryTestCase {
public void commitIgnoresSmudgedEntryWithDifferentId() throws Exception {
try (Git git = new Git(db)) {
File file1 = writeTrashFile("file1.txt", "content1");
- assertTrue(file1.setLastModified(file1.lastModified() - 5000));
+ TimeUtil.setLastModifiedWithOffset(file1.toPath(), -5000L);
File file2 = writeTrashFile("file2.txt", "content2");
- assertTrue(file2.setLastModified(file2.lastModified() - 5000));
+ TimeUtil.setLastModifiedWithOffset(file2.toPath(), -5000L);
assertNotNull(git.add().addFilepattern("file1.txt")
.addFilepattern("file2.txt").call());
@@ -399,11 +401,11 @@ public class CommitCommandTest extends RepositoryTestCase {
assertEquals(0, cache.getEntry("file1.txt").getLength());
assertEquals(0, cache.getEntry("file2.txt").getLength());
- long indexTime = db.getIndexFile().lastModified();
- db.getIndexFile().setLastModified(indexTime - 5000);
+ TimeUtil.setLastModifiedWithOffset(db.getIndexFile().toPath(),
+ -5000L);
write(file1, "content5");
- assertTrue(file1.setLastModified(file1.lastModified() + 1000));
+ TimeUtil.setLastModifiedWithOffset(file1.toPath(), 1000L);
assertNotNull(git.commit().setMessage("edit file").setOnly("file1.txt")
.call());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java
index 43c3a8cf92..3a93839e8c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java
@@ -44,7 +44,6 @@ package org.eclipse.jgit.api;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -55,6 +54,7 @@ import java.util.List;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffEntry.ChangeType;
import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.junit.time.TimeUtil;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.revwalk.RevWalk;
@@ -230,7 +230,7 @@ public class DiffCommandTest extends RepositoryTestCase {
@Test
public void testNoOutputStreamSet() throws Exception {
File file = writeTrashFile("test.txt", "a");
- assertTrue(file.setLastModified(file.lastModified() - 5000));
+ TimeUtil.setLastModifiedWithOffset(file.toPath(), -5000L);
try (Git git = new Git(db)) {
git.add().addFilepattern(".").call();
write(file, "b");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
index 2b97b307bf..588387d3e6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
@@ -42,6 +42,7 @@
*/
package org.eclipse.jgit.api;
+import static java.time.Instant.EPOCH;
import static org.eclipse.jgit.api.ResetCommand.ResetType.HARD;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -52,6 +53,9 @@ import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.attribute.FileTime;
+import java.time.Instant;
import org.eclipse.jgit.api.ResetCommand.ResetType;
import org.eclipse.jgit.api.errors.GitAPIException;
@@ -246,13 +250,13 @@ public class ResetCommandTest extends RepositoryTestCase {
public void testMixedResetRetainsSizeAndModifiedTime() throws Exception {
git = new Git(db);
- writeTrashFile("a.txt", "a").setLastModified(
- System.currentTimeMillis() - 60 * 1000);
+ Files.setLastModifiedTime(writeTrashFile("a.txt", "a").toPath(),
+ FileTime.from(Instant.now().minusSeconds(60)));
assertNotNull(git.add().addFilepattern("a.txt").call());
assertNotNull(git.commit().setMessage("a commit").call());
- writeTrashFile("b.txt", "b").setLastModified(
- System.currentTimeMillis() - 60 * 1000);
+ Files.setLastModifiedTime(writeTrashFile("b.txt", "b").toPath(),
+ FileTime.from(Instant.now().minusSeconds(60)));
assertNotNull(git.add().addFilepattern("b.txt").call());
RevCommit commit2 = git.commit().setMessage("b commit").call();
assertNotNull(commit2);
@@ -262,12 +266,12 @@ public class ResetCommandTest extends RepositoryTestCase {
DirCacheEntry aEntry = cache.getEntry("a.txt");
assertNotNull(aEntry);
assertTrue(aEntry.getLength() > 0);
- assertTrue(aEntry.getLastModified() > 0);
+ assertTrue(aEntry.getLastModifiedInstant().compareTo(EPOCH) > 0);
DirCacheEntry bEntry = cache.getEntry("b.txt");
assertNotNull(bEntry);
assertTrue(bEntry.getLength() > 0);
- assertTrue(bEntry.getLastModified() > 0);
+ assertTrue(bEntry.getLastModifiedInstant().compareTo(EPOCH) > 0);
assertSameAsHead(git.reset().setMode(ResetType.MIXED)
.setRef(commit2.getName()).call());
@@ -276,13 +280,17 @@ public class ResetCommandTest extends RepositoryTestCase {
DirCacheEntry mixedAEntry = cache.getEntry("a.txt");
assertNotNull(mixedAEntry);
- assertEquals(aEntry.getLastModified(), mixedAEntry.getLastModified());
- assertEquals(aEntry.getLastModified(), mixedAEntry.getLastModified());
+ assertEquals(aEntry.getLastModifiedInstant(),
+ mixedAEntry.getLastModifiedInstant());
+ assertEquals(aEntry.getLastModifiedInstant(),
+ mixedAEntry.getLastModifiedInstant());
DirCacheEntry mixedBEntry = cache.getEntry("b.txt");
assertNotNull(mixedBEntry);
- assertEquals(bEntry.getLastModified(), mixedBEntry.getLastModified());
- assertEquals(bEntry.getLastModified(), mixedBEntry.getLastModified());
+ assertEquals(bEntry.getLastModifiedInstant(),
+ mixedBEntry.getLastModifiedInstant());
+ assertEquals(bEntry.getLastModifiedInstant(),
+ mixedBEntry.getLastModifiedInstant());
}
@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java
index d12f302dae..d9a4203779 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java
@@ -53,6 +53,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
+import java.time.Instant;
import org.eclipse.jgit.events.IndexChangedEvent;
import org.eclipse.jgit.events.IndexChangedListener;
@@ -98,7 +99,7 @@ public class DirCacheBuilderTest extends RepositoryTestCase {
public void testBuildOneFile_FinishWriteCommit() throws Exception {
final String path = "a-file-path";
final FileMode mode = FileMode.REGULAR_FILE;
- final long lastModified = 1218123387057L;
+ final Instant lastModified = Instant.ofEpochMilli(1218123387057L);
final int length = 1342;
final DirCacheEntry entOrig;
{
@@ -116,7 +117,7 @@ public class DirCacheBuilderTest extends RepositoryTestCase {
assertEquals(ObjectId.zeroId(), entOrig.getObjectId());
assertEquals(mode.getBits(), entOrig.getRawMode());
assertEquals(0, entOrig.getStage());
- assertEquals(lastModified, entOrig.getLastModified());
+ assertEquals(lastModified, entOrig.getLastModifiedInstant());
assertEquals(length, entOrig.getLength());
assertFalse(entOrig.isAssumeValid());
b.add(entOrig);
@@ -138,7 +139,7 @@ public class DirCacheBuilderTest extends RepositoryTestCase {
assertEquals(ObjectId.zeroId(), entOrig.getObjectId());
assertEquals(mode.getBits(), entOrig.getRawMode());
assertEquals(0, entOrig.getStage());
- assertEquals(lastModified, entOrig.getLastModified());
+ assertEquals(lastModified, entOrig.getLastModifiedInstant());
assertEquals(length, entOrig.getLength());
assertFalse(entOrig.isAssumeValid());
}
@@ -148,7 +149,7 @@ public class DirCacheBuilderTest extends RepositoryTestCase {
public void testBuildOneFile_Commit() throws Exception {
final String path = "a-file-path";
final FileMode mode = FileMode.REGULAR_FILE;
- final long lastModified = 1218123387057L;
+ final Instant lastModified = Instant.ofEpochMilli(1218123387057L);
final int length = 1342;
final DirCacheEntry entOrig;
{
@@ -166,7 +167,7 @@ public class DirCacheBuilderTest extends RepositoryTestCase {
assertEquals(ObjectId.zeroId(), entOrig.getObjectId());
assertEquals(mode.getBits(), entOrig.getRawMode());
assertEquals(0, entOrig.getStage());
- assertEquals(lastModified, entOrig.getLastModified());
+ assertEquals(lastModified, entOrig.getLastModifiedInstant());
assertEquals(length, entOrig.getLength());
assertFalse(entOrig.isAssumeValid());
b.add(entOrig);
@@ -186,7 +187,7 @@ public class DirCacheBuilderTest extends RepositoryTestCase {
assertEquals(ObjectId.zeroId(), entOrig.getObjectId());
assertEquals(mode.getBits(), entOrig.getRawMode());
assertEquals(0, entOrig.getStage());
- assertEquals(lastModified, entOrig.getLastModified());
+ assertEquals(lastModified, entOrig.getLastModifiedInstant());
assertEquals(length, entOrig.getLength());
assertFalse(entOrig.isAssumeValid());
}
@@ -203,7 +204,7 @@ public class DirCacheBuilderTest extends RepositoryTestCase {
final String path = "a-file-path";
final FileMode mode = FileMode.REGULAR_FILE;
// "old" date in 2008
- final long lastModified = 1218123387057L;
+ final Instant lastModified = Instant.ofEpochMilli(1218123387057L);
final int length = 1342;
DirCacheEntry entOrig;
boolean receivedEvent = false;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
index 86e2852872..475819dbb7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
@@ -43,6 +43,7 @@
package org.eclipse.jgit.dircache;
+import static java.time.Instant.EPOCH;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
@@ -188,7 +189,7 @@ public class DirCacheEntryTest {
e.setAssumeValid(false);
e.setCreationTime(2L);
e.setFileMode(FileMode.EXECUTABLE_FILE);
- e.setLastModified(3L);
+ e.setLastModified(EPOCH.plusMillis(3L));
e.setLength(100L);
e.setObjectId(ObjectId
.fromString("0123456789012345678901234567890123456789"));
@@ -199,7 +200,7 @@ public class DirCacheEntryTest {
f.setAssumeValid(true);
f.setCreationTime(10L);
f.setFileMode(FileMode.SYMLINK);
- f.setLastModified(20L);
+ f.setLastModified(EPOCH.plusMillis(20L));
f.setLength(100000000L);
f.setObjectId(ObjectId
.fromString("1234567890123456789012345678901234567890"));
@@ -212,7 +213,7 @@ public class DirCacheEntryTest {
ObjectId.fromString("1234567890123456789012345678901234567890"),
e.getObjectId());
assertEquals(FileMode.SYMLINK, e.getFileMode());
- assertEquals(20L, e.getLastModified());
+ assertEquals(EPOCH.plusMillis(20L), e.getLastModifiedInstant());
assertEquals(100000000L, e.getLength());
if (keepStage)
assertEquals(DirCacheEntry.STAGE_2, e.getStage());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java
index 643daa5c95..6bec056737 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java
@@ -56,6 +56,7 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.time.Instant;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
@@ -71,6 +72,7 @@ import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.file.WindowCacheConfig;
+import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
import org.junit.After;
import org.junit.Before;
@@ -235,7 +237,8 @@ public class ConcurrentRepackTest extends RepositoryTestCase {
private static void write(File[] files, PackWriter pw)
throws IOException {
- final long begin = files[0].getParentFile().lastModified();
+ final Instant begin = FS.DETECTED
+ .lastModifiedInstant(files[0].getParentFile());
NullProgressMonitor m = NullProgressMonitor.INSTANCE;
try (OutputStream out = new BufferedOutputStream(
@@ -252,7 +255,8 @@ public class ConcurrentRepackTest extends RepositoryTestCase {
}
private static void delete(File[] list) throws IOException {
- final long begin = list[0].getParentFile().lastModified();
+ final Instant begin = FS.DETECTED
+ .lastModifiedInstant(list[0].getParentFile());
for (File f : list) {
FileUtils.delete(f);
assertFalse(f + " was removed", f.exists());
@@ -260,14 +264,14 @@ public class ConcurrentRepackTest extends RepositoryTestCase {
touch(begin, list[0].getParentFile());
}
- private static void touch(long begin, File dir) {
- while (begin >= dir.lastModified()) {
+ private static void touch(Instant begin, File dir) throws IOException {
+ while (begin.compareTo(FS.DETECTED.lastModifiedInstant(dir)) >= 0) {
try {
Thread.sleep(25);
} catch (InterruptedException ie) {
//
}
- dir.setLastModified(System.currentTimeMillis());
+ FS.DETECTED.setLastModified(dir.toPath(), Instant.now());
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileSnapshotTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileSnapshotTest.java
index 6e458fbbf0..467f6956ba 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileSnapshotTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileSnapshotTest.java
@@ -51,9 +51,11 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.FileTime;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
+import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
import org.eclipse.jgit.util.SystemReader;
import org.junit.After;
@@ -80,11 +82,12 @@ public class FileSnapshotTest {
FileUtils.delete(trash, FileUtils.RECURSIVE | FileUtils.SKIP_MISSING);
}
- private static void waitNextSec(File f) {
- long initialLastModified = f.lastModified();
+ private static void waitNextTick(File f) throws IOException {
+ Instant initialLastModified = FS.DETECTED.lastModifiedInstant(f);
do {
- f.setLastModified(System.currentTimeMillis());
- } while (f.lastModified() == initialLastModified);
+ FS.DETECTED.setLastModified(f.toPath(), Instant.now());
+ } while (FS.DETECTED.lastModifiedInstant(f)
+ .equals(initialLastModified));
}
/**
@@ -95,10 +98,10 @@ public class FileSnapshotTest {
@Test
public void testActuallyIsModifiedTrivial() throws Exception {
File f1 = createFile("simple");
- waitNextSec(f1);
+ waitNextTick(f1);
FileSnapshot save = FileSnapshot.save(f1);
append(f1, (byte) 'x');
- waitNextSec(f1);
+ waitNextTick(f1);
assertTrue(save.isModified(f1));
}
@@ -113,7 +116,7 @@ public class FileSnapshotTest {
@Test
public void testNewFileWithWait() throws Exception {
File f1 = createFile("newfile");
- waitNextSec(f1);
+ waitNextTick(f1);
FileSnapshot save = FileSnapshot.save(f1);
Thread.sleep(1500);
assertTrue(save.isModified(f1));
@@ -146,8 +149,8 @@ public class FileSnapshotTest {
File f2 = createFile("fool"); // Guarantees new inode x
// wait on f2 since this method resets lastModified of the file
// and leaves lastModified of f1 untouched
- waitNextSec(f2);
- waitNextSec(f2);
+ waitNextTick(f2);
+ waitNextTick(f2);
FileTime timestamp = Files.getLastModifiedTime(f1.toPath());
FileSnapshot save = FileSnapshot.save(f1);
Files.move(f2.toPath(), f1.toPath(), // Now "file" is inode x
@@ -185,7 +188,7 @@ public class FileSnapshotTest {
// 0 sized FileSnapshot.
FileSnapshot fs1 = FileSnapshot.MISSING_FILE;
// UNKNOWN_SIZE FileSnapshot.
- FileSnapshot fs2 = FileSnapshot.save(fs1.lastModified());
+ FileSnapshot fs2 = FileSnapshot.save(fs1.lastModifiedInstant());
assertTrue(fs1.equals(fs2));
assertTrue(fs2.equals(fs1));
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java
index d16998db55..eaa245b4eb 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java
@@ -147,9 +147,10 @@ public abstract class GcTestCase extends LocalDiskRepositoryTestCase {
return tip;
}
- protected long lastModified(AnyObjectId objectId) throws IOException {
- return repo.getFS().lastModified(
- repo.getObjectDatabase().fileFor(objectId));
+ protected long lastModified(AnyObjectId objectId) {
+ return repo.getFS()
+ .lastModifiedInstant(repo.getObjectDatabase().fileFor(objectId))
+ .toEpochMilli();
}
protected static void fsTick() throws InterruptedException, IOException {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java
index cbb73bb08e..8cc06d93f2 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java
@@ -65,6 +65,7 @@ import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
import org.junit.Assume;
import org.junit.Rule;
import org.junit.Test;
@@ -157,13 +158,14 @@ public class ObjectDirectoryTest extends RepositoryTestCase {
// To deal with racy-git situations JGit's Filesnapshot class will
// report a file/folder potentially dirty if
- // cachedLastReadTime-cachedLastModificationTime < 2500ms. This
- // causes JGit to always rescan a file after modification. But:
- // this was true only if the difference between current system time
- // and cachedLastModification time was less than 2500ms. If the
- // modification is more than 2500ms ago we may have reported a
- // file/folder to be clean although it has not been rescanned. A
- // Bug. To show the bug we sleep for more than 2500ms
+ // cachedLastReadTime-cachedLastModificationTime < filesystem
+ // timestamp resolution. This causes JGit to always rescan a file
+ // after modification. But: this was true only if the difference
+ // between current system time and cachedLastModification time was
+ // less than 2500ms. If the modification is more than 2500ms ago we
+ // may have reported a file/folder to be clean although it has not
+ // been rescanned. A bug. To show the bug we sleep for more than
+ // 2500ms
Thread.sleep(2600);
File[] ret = packsFolder.listFiles(new FilenameFilter() {
@@ -173,7 +175,9 @@ public class ObjectDirectoryTest extends RepositoryTestCase {
}
});
assertTrue(ret != null && ret.length == 1);
- Assume.assumeTrue(tmpFile.lastModified() == ret[0].lastModified());
+ FS fs = db.getFS();
+ Assume.assumeTrue(fs.lastModifiedInstant(tmpFile)
+ .equals(fs.lastModifiedInstant(ret[0])));
// all objects are in a new packfile but we will not detect it
assertFalse(receivingDB.hasObject(unknownID));
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileSnapshotTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileSnapshotTest.java
index a1433e9fe5..d5bc61a692 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileSnapshotTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileSnapshotTest.java
@@ -59,6 +59,7 @@ import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
//import java.nio.file.attribute.BasicFileAttributes;
import java.text.ParseException;
+import java.time.Instant;
import java.util.Collection;
import java.util.Iterator;
import java.util.Random;
@@ -80,6 +81,7 @@ import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.storage.pack.PackConfig;
+import org.eclipse.jgit.util.FS;
import org.junit.Test;
public class PackFileSnapshotTest extends RepositoryTestCase {
@@ -188,7 +190,8 @@ public class PackFileSnapshotTest extends RepositoryTestCase {
AnyObjectId chk1 = pf.getPackChecksum();
String name = pf.getPackName();
Long length = Long.valueOf(pf.getPackFile().length());
- long m1 = packFilePath.toFile().lastModified();
+ FS fs = db.getFS();
+ Instant m1 = fs.lastModifiedInstant(packFilePath);
// Wait for a filesystem timer tick to enhance probability the rest of
// this test is done before the filesystem timer ticks again.
@@ -198,15 +201,15 @@ public class PackFileSnapshotTest extends RepositoryTestCase {
// content and checksum are different since compression level differs
AnyObjectId chk2 = repackAndCheck(6, name, length, chk1)
.getPackChecksum();
- long m2 = packFilePath.toFile().lastModified();
- assumeFalse(m2 == m1);
+ Instant m2 = fs.lastModifiedInstant(packFilePath);
+ assumeFalse(m2.equals(m1));
// Repack to create packfile with same name, length. Lastmodified is
// equal to the previous one because we are in the same filesystem timer
// slot. Content and its checksum are different
AnyObjectId chk3 = repackAndCheck(7, name, length, chk2)
.getPackChecksum();
- long m3 = packFilePath.toFile().lastModified();
+ Instant m3 = fs.lastModifiedInstant(packFilePath);
// ask for an unknown git object to force jgit to rescan the list of
// available packs. If we would ask for a known objectid then JGit would
@@ -214,7 +217,7 @@ public class PackFileSnapshotTest extends RepositoryTestCase {
db.getObjectDatabase().has(unknownID);
assertEquals(chk3, getSinglePack(db.getObjectDatabase().getPacks())
.getPackChecksum());
- assumeTrue(m3 == m2);
+ assumeTrue(m3.equals(m2));
}
// Try repacking so fast that we get two new packs which differ only in
@@ -253,7 +256,8 @@ public class PackFileSnapshotTest extends RepositoryTestCase {
// Repack to create third packfile
AnyObjectId chk3 = repackAndCheck(7, name, length, chk2)
.getPackChecksum();
- long m3 = packFilePath.toFile().lastModified();
+ FS fs = db.getFS();
+ Instant m3 = fs.lastModifiedInstant(packFilePath);
db.getObjectDatabase().has(unknownID);
assertEquals(chk3, getSinglePack(db.getObjectDatabase().getPacks())
.getPackChecksum());
@@ -265,8 +269,8 @@ public class PackFileSnapshotTest extends RepositoryTestCase {
// Copy copy2 to packfile data to force modification of packfile without
// changing the packfile's filekey.
copyPack(packFileBasePath, ".copy2", "");
- long m2 = packFilePath.toFile().lastModified();
- assumeFalse(m3 == m2);
+ Instant m2 = fs.lastModifiedInstant(packFilePath);
+ assumeFalse(m3.equals(m2));
db.getObjectDatabase().has(unknownID);
assertEquals(chk2, getSinglePack(db.getObjectDatabase().getPacks())
@@ -275,8 +279,8 @@ public class PackFileSnapshotTest extends RepositoryTestCase {
// Copy copy2 to packfile data to force modification of packfile without
// changing the packfile's filekey.
copyPack(packFileBasePath, ".copy1", "");
- long m1 = packFilePath.toFile().lastModified();
- assumeTrue(m2 == m1);
+ Instant m1 = fs.lastModifiedInstant(packFilePath);
+ assumeTrue(m2.equals(m1));
db.getObjectDatabase().has(unknownID);
assertEquals(chk1, getSinglePack(db.getObjectDatabase().getPacks())
.getPackChecksum());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
index 5a2bd9c333..ac0a34dedf 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
@@ -59,6 +59,7 @@ import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
@@ -78,6 +79,7 @@ import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTag;
+import org.eclipse.jgit.util.FS;
import org.junit.Before;
import org.junit.Test;
@@ -1319,10 +1321,8 @@ public class RefDirectoryTest extends LocalDiskRepositoryTestCase {
private void writePackedRefs(String content) throws IOException {
File pr = new File(diskRepo.getDirectory(), "packed-refs");
write(pr, content);
-
- final long now = System.currentTimeMillis();
- final int oneHourAgo = 3600 * 1000;
- pr.setLastModified(now - oneHourAgo);
+ FS fs = diskRepo.getFS();
+ fs.setLastModified(pr.toPath(), Instant.now().minusSeconds(3600));
}
private void deleteLooseRef(String name) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
index 02073226d0..a4509695d9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
@@ -59,6 +59,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
+import java.time.Instant;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -82,6 +83,7 @@ import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
+import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
import org.eclipse.jgit.util.IO;
import org.junit.Rule;
@@ -790,12 +792,14 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
*
* @param name
* the file in the repository to force a time change on.
+ * @throws IOException
*/
- private void BUG_WorkAroundRacyGitIssues(String name) {
+ private void BUG_WorkAroundRacyGitIssues(String name) throws IOException {
File path = new File(db.getDirectory(), name);
- long old = path.lastModified();
+ FS fs = db.getFS();
+ Instant old = fs.lastModifiedInstant(path);
long set = 1250379778668L; // Sat Aug 15 20:12:58 GMT-03:30 2009
- path.setLastModified(set);
- assertTrue("time changed", old != path.lastModified());
+ fs.setLastModified(path.toPath(), Instant.ofEpochMilli(set));
+ assertFalse("time changed", old.equals(fs.lastModifiedInstant(path)));
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexModificationTimesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexModificationTimesTest.java
index b9bbbeb9e5..a3634141c3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexModificationTimesTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexModificationTimesTest.java
@@ -37,8 +37,12 @@
*/
package org.eclipse.jgit.lib;
+import static java.time.Instant.EPOCH;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import java.time.Instant;
+
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEntry;
@@ -63,11 +67,11 @@ public class IndexModificationTimesTest extends RepositoryTestCase {
DirCacheEntry entry = dc.getEntry(path);
DirCacheEntry entry2 = dc.getEntry(path);
- assertTrue("last modified shall not be zero!",
- entry.getLastModified() != 0);
+ assertFalse("last modified shall not be the epoch!",
+ entry.getLastModifiedInstant().equals(EPOCH));
- assertTrue("last modified shall not be zero!",
- entry2.getLastModified() != 0);
+ assertFalse("last modified shall not be the epoch!",
+ entry2.getLastModifiedInstant().equals(EPOCH));
writeTrashFile(path, "new content");
git.add().addFilepattern(path).call();
@@ -77,11 +81,11 @@ public class IndexModificationTimesTest extends RepositoryTestCase {
entry = dc.getEntry(path);
entry2 = dc.getEntry(path);
- assertTrue("last modified shall not be zero!",
- entry.getLastModified() != 0);
+ assertFalse("last modified shall not be the epoch!",
+ entry.getLastModifiedInstant().equals(EPOCH));
- assertTrue("last modified shall not be zero!",
- entry2.getLastModified() != 0);
+ assertFalse("last modified shall not be the epoch!",
+ entry2.getLastModifiedInstant().equals(EPOCH));
}
}
@@ -97,7 +101,7 @@ public class IndexModificationTimesTest extends RepositoryTestCase {
DirCache dc = db.readDirCache();
DirCacheEntry entry = dc.getEntry(path);
- long masterLastMod = entry.getLastModified();
+ Instant masterLastMod = entry.getLastModifiedInstant();
git.checkout().setCreateBranch(true).setName("side").call();
@@ -110,7 +114,7 @@ public class IndexModificationTimesTest extends RepositoryTestCase {
dc = db.readDirCache();
entry = dc.getEntry(path);
- long sideLastMode = entry.getLastModified();
+ Instant sideLastMod = entry.getLastModifiedInstant();
Thread.sleep(2000);
@@ -120,9 +124,10 @@ public class IndexModificationTimesTest extends RepositoryTestCase {
dc = db.readDirCache();
entry = dc.getEntry(path);
- assertTrue("shall have equal mod time!", masterLastMod == sideLastMode);
- assertTrue("shall not equal master timestamp!",
- entry.getLastModified() == masterLastMod);
+ assertTrue("shall have equal mod time!",
+ masterLastMod.equals(sideLastMod));
+ assertTrue("shall have equal master timestamp!",
+ entry.getLastModifiedInstant().equals(masterLastMod));
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java
index d044e65cf4..d3e4efef53 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java
@@ -50,12 +50,15 @@ import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.time.Instant;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.junit.time.TimeUtil;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.WorkingTreeOptions;
+import org.eclipse.jgit.util.FS;
import org.junit.Test;
public class RacyGitTests extends RepositoryTestCase {
@@ -74,8 +77,8 @@ public class RacyGitTests extends RepositoryTestCase {
// create two files
File a = writeToWorkDir("a", "a");
File b = writeToWorkDir("b", "b");
- assertTrue(a.setLastModified(b.lastModified()));
- assertTrue(b.setLastModified(b.lastModified()));
+ TimeUtil.setLastModifiedOf(a.toPath(), b.toPath());
+ TimeUtil.setLastModifiedOf(b.toPath(), b.toPath());
// wait to ensure that file-modTimes and therefore index entry modTime
// doesn't match the modtime of index-file after next persistance
@@ -97,10 +100,11 @@ public class RacyGitTests extends RepositoryTestCase {
// filesystem timestamp resolution. By changing the index file
// artificially, we create a fake racy situation.
File updatedA = writeToWorkDir("a", "a2");
- long newLastModified = updatedA.lastModified() + 100;
- assertTrue(updatedA.setLastModified(newLastModified));
+ Instant newLastModified = TimeUtil
+ .setLastModifiedWithOffset(updatedA.toPath(), 100L);
resetIndex(new FileTreeIterator(db));
- assertTrue(db.getIndexFile().setLastModified(newLastModified));
+ FS.DETECTED.setLastModified(db.getIndexFile().toPath(),
+ newLastModified);
DirCache dc = db.readDirCache();
// check index state: although racily clean a should not be reported as
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java
index 7f5dba6975..f22b7d6adb 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java
@@ -43,6 +43,7 @@
package org.eclipse.jgit.merge;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.time.Instant.EPOCH;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -54,6 +55,7 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
+import java.time.Instant;
import java.util.Arrays;
import java.util.Map;
@@ -1090,13 +1092,13 @@ public class MergerTest extends RepositoryTestCase {
@Theory
public void checkForCorrectIndex(MergeStrategy strategy) throws Exception {
File f;
- long lastTs4, lastTsIndex;
+ Instant lastTs4, lastTsIndex;
Git git = Git.wrap(db);
File indexFile = db.getIndexFile();
// Create initial content and remember when the last file was written.
f = writeTrashFiles(false, "orig", "orig", "1\n2\n3", "orig", "orig");
- lastTs4 = FS.DETECTED.lastModified(f);
+ lastTs4 = FS.DETECTED.lastModifiedInstant(f);
// add all files, commit and check this doesn't update any working tree
// files and that the index is in a new file system timer tick. Make
@@ -1109,8 +1111,9 @@ public class MergerTest extends RepositoryTestCase {
checkConsistentLastModified("0", "1", "2", "3", "4");
checkModificationTimeStampOrder("1", "2", "3", "4", "<.git/index");
assertEquals("Commit should not touch working tree file 4", lastTs4,
- FS.DETECTED.lastModified(new File(db.getWorkTree(), "4")));
- lastTsIndex = FS.DETECTED.lastModified(indexFile);
+ FS.DETECTED
+ .lastModifiedInstant(new File(db.getWorkTree(), "4")));
+ lastTsIndex = FS.DETECTED.lastModifiedInstant(indexFile);
// Do modifications on the master branch. Then add and commit. This
// should touch only "0", "2 and "3"
@@ -1124,7 +1127,7 @@ public class MergerTest extends RepositoryTestCase {
checkConsistentLastModified("0", "1", "2", "3", "4");
checkModificationTimeStampOrder("1", "4", "*" + lastTs4, "<*"
+ lastTsIndex, "<0", "2", "3", "<.git/index");
- lastTsIndex = FS.DETECTED.lastModified(indexFile);
+ lastTsIndex = FS.DETECTED.lastModifiedInstant(indexFile);
// Checkout a side branch. This should touch only "0", "2 and "3"
fsTick(indexFile);
@@ -1133,7 +1136,7 @@ public class MergerTest extends RepositoryTestCase {
checkConsistentLastModified("0", "1", "2", "3", "4");
checkModificationTimeStampOrder("1", "4", "*" + lastTs4, "<*"
+ lastTsIndex, "<0", "2", "3", ".git/index");
- lastTsIndex = FS.DETECTED.lastModified(indexFile);
+ lastTsIndex = FS.DETECTED.lastModifiedInstant(indexFile);
// This checkout may have populated worktree and index so fast that we
// may have smudged entries now. Check that we have the right content
@@ -1146,13 +1149,13 @@ public class MergerTest extends RepositoryTestCase {
indexState(CONTENT));
fsTick(indexFile);
f = writeTrashFiles(false, "orig", "orig", "1\n2\n3", "orig", "orig");
- lastTs4 = FS.DETECTED.lastModified(f);
+ lastTs4 = FS.DETECTED.lastModifiedInstant(f);
fsTick(f);
git.add().addFilepattern(".").call();
checkConsistentLastModified("0", "1", "2", "3", "4");
checkModificationTimeStampOrder("*" + lastTsIndex, "<0", "1", "2", "3",
"4", "<.git/index");
- lastTsIndex = FS.DETECTED.lastModified(indexFile);
+ lastTsIndex = FS.DETECTED.lastModifiedInstant(indexFile);
// Do modifications on the side branch. Touch only "1", "2 and "3"
fsTick(indexFile);
@@ -1163,7 +1166,7 @@ public class MergerTest extends RepositoryTestCase {
checkConsistentLastModified("0", "1", "2", "3", "4");
checkModificationTimeStampOrder("0", "4", "*" + lastTs4, "<*"
+ lastTsIndex, "<1", "2", "3", "<.git/index");
- lastTsIndex = FS.DETECTED.lastModified(indexFile);
+ lastTsIndex = FS.DETECTED.lastModifiedInstant(indexFile);
// merge master and side. Should only touch "0," "2" and "3"
fsTick(indexFile);
@@ -1330,9 +1333,10 @@ public class MergerTest extends RepositoryTestCase {
assertEquals(
"IndexEntry with path "
+ path
- + " has lastmodified with is different from the worktree file",
- FS.DETECTED.lastModified(new File(workTree, path)), dc.getEntry(path)
- .getLastModified());
+ + " has lastmodified which is different from the worktree file",
+ FS.DETECTED.lastModifiedInstant(new File(workTree, path)),
+ dc.getEntry(path)
+ .getLastModifiedInstant());
}
// Assert that modification timestamps of working tree files are as
@@ -1341,21 +1345,22 @@ public class MergerTest extends RepositoryTestCase {
// then this file must be younger then file i. A path "*<modtime>"
// represents a file with a modification time of <modtime>
// E.g. ("a", "b", "<c", "f/a.txt") means: a<=b<c<=f/a.txt
- private void checkModificationTimeStampOrder(String... pathes)
- throws IOException {
- long lastMod = Long.MIN_VALUE;
+ private void checkModificationTimeStampOrder(String... pathes) {
+ Instant lastMod = EPOCH;
for (String p : pathes) {
boolean strong = p.startsWith("<");
boolean fixed = p.charAt(strong ? 1 : 0) == '*';
p = p.substring((strong ? 1 : 0) + (fixed ? 1 : 0));
- long curMod = fixed ? Long.valueOf(p).longValue()
- : FS.DETECTED.lastModified(new File(db.getWorkTree(), p));
- if (strong)
+ Instant curMod = fixed ? Instant.parse(p)
+ : FS.DETECTED
+ .lastModifiedInstant(new File(db.getWorkTree(), p));
+ if (strong) {
assertTrue("path " + p + " is not younger than predecesssor",
- curMod > lastMod);
- else
+ curMod.compareTo(lastMod) > 0);
+ } else {
assertTrue("path " + p + " is older than predecesssor",
- curMod >= lastMod);
+ curMod.compareTo(lastMod) >= 0);
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java
index 19fcbfd7a2..7777a3c993 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java
@@ -57,10 +57,12 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
+import java.time.Instant;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.transport.OpenSshConfig.Host;
+import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
import org.eclipse.jgit.util.SystemReader;
import org.junit.Before;
@@ -91,13 +93,14 @@ public class OpenSshConfigTest extends RepositoryTestCase {
}
private void config(String data) throws IOException {
- long lastMtime = configFile.lastModified();
+ FS fs = db.getFS();
+ Instant lastMtime = fs.lastModifiedInstant(configFile);
do {
try (final OutputStreamWriter fw = new OutputStreamWriter(
new FileOutputStream(configFile), UTF_8)) {
fw.write(data);
}
- } while (lastMtime == configFile.lastModified());
+ } while (lastMtime.equals(fs.lastModifiedInstant(configFile)));
}
@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
index 33e32cd813..9a0e7d2eac 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
@@ -52,6 +52,7 @@ import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.security.MessageDigest;
+import java.time.Instant;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.ResetCommand.ResetType;
@@ -86,7 +87,7 @@ import org.junit.Test;
public class FileTreeIteratorTest extends RepositoryTestCase {
private final String[] paths = { "a,", "a,b", "a/b", "a0b" };
- private long[] mtime;
+ private Instant[] mtime;
@Override
@Before
@@ -99,11 +100,11 @@ public class FileTreeIteratorTest extends RepositoryTestCase {
// This should stress the sorting code better than doing it in
// the correct order.
//
- mtime = new long[paths.length];
+ mtime = new Instant[paths.length];
for (int i = paths.length - 1; i >= 0; i--) {
final String s = paths[i];
writeTrashFile(s, s);
- mtime[i] = FS.DETECTED.lastModified(new File(trash, s));
+ mtime[i] = db.getFS().lastModifiedInstant(new File(trash, s));
}
}
@@ -199,7 +200,7 @@ public class FileTreeIteratorTest extends RepositoryTestCase {
assertEquals(FileMode.REGULAR_FILE.getBits(), top.mode);
assertEquals(paths[0], nameOf(top));
assertEquals(paths[0].length(), top.getEntryLength());
- assertEquals(mtime[0], top.getEntryLastModified());
+ assertEquals(mtime[0], top.getEntryLastModifiedInstant());
top.next(1);
assertFalse(top.first());
@@ -207,7 +208,7 @@ public class FileTreeIteratorTest extends RepositoryTestCase {
assertEquals(FileMode.REGULAR_FILE.getBits(), top.mode);
assertEquals(paths[1], nameOf(top));
assertEquals(paths[1].length(), top.getEntryLength());
- assertEquals(mtime[1], top.getEntryLastModified());
+ assertEquals(mtime[1], top.getEntryLastModifiedInstant());
top.next(1);
assertFalse(top.first());
@@ -222,7 +223,7 @@ public class FileTreeIteratorTest extends RepositoryTestCase {
assertFalse(sub.eof());
assertEquals(paths[2], nameOf(sub));
assertEquals(paths[2].length(), subfti.getEntryLength());
- assertEquals(mtime[2], subfti.getEntryLastModified());
+ assertEquals(mtime[2], subfti.getEntryLastModifiedInstant());
sub.next(1);
assertTrue(sub.eof());
@@ -233,7 +234,7 @@ public class FileTreeIteratorTest extends RepositoryTestCase {
assertEquals(FileMode.REGULAR_FILE.getBits(), top.mode);
assertEquals(paths[3], nameOf(top));
assertEquals(paths[3].length(), top.getEntryLength());
- assertEquals(mtime[3], top.getEntryLastModified());
+ assertEquals(mtime[3], top.getEntryLastModifiedInstant());
top.next(1);
assertTrue(top.eof());
@@ -345,20 +346,21 @@ public class FileTreeIteratorTest extends RepositoryTestCase {
@Test
public void testIsModifiedFileSmudged() throws Exception {
File f = writeTrashFile("file", "content");
+ FS fs = db.getFS();
try (Git git = new Git(db)) {
// The idea of this test is to check the smudged handling
// Hopefully fsTick will make sure our entry gets smudged
fsTick(f);
writeTrashFile("file", "content");
- long lastModified = f.lastModified();
+ Instant lastModified = fs.lastModifiedInstant(f);
git.add().addFilepattern("file").call();
writeTrashFile("file", "conten2");
- f.setLastModified(lastModified);
+ fs.setLastModified(f.toPath(), lastModified);
// We cannot trust this to go fast enough on
// a system with less than one-second lastModified
// resolution, so we force the index to have the
// same timestamp as the file we look at.
- db.getIndexFile().setLastModified(lastModified);
+ fs.setLastModified(db.getIndexFile().toPath(), lastModified);
}
DirCacheEntry dce = db.readDirCache().getEntry("file");
FileTreeIterator fti = new FileTreeIterator(trash, db.getFS(), db
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
index 6b3d58bae7..bde8a8a6b3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
@@ -43,6 +43,7 @@
package org.eclipse.jgit.util;
+import static java.time.Instant.EPOCH;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -106,7 +107,7 @@ public class FSTest {
assertTrue(fs.exists(link));
String targetName = fs.readSymLink(link);
assertEquals("Ã¥", targetName);
- assertTrue(fs.lastModified(link) > 0);
+ assertTrue(fs.lastModifiedInstant(link).compareTo(EPOCH) > 0);
assertTrue(fs.exists(link));
assertFalse(fs.canExecute(link));
assertEquals(2, fs.length(link));
@@ -119,8 +120,9 @@ public class FSTest {
// Now create the link target
FileUtils.createNewFile(target);
assertTrue(fs.exists(link));
- assertTrue(fs.lastModified(link) > 0);
- assertTrue(fs.lastModified(target) > fs.lastModified(link));
+ assertTrue(fs.lastModifiedInstant(link).compareTo(EPOCH) > 0);
+ assertTrue(fs.lastModifiedInstant(target)
+ .compareTo(fs.lastModifiedInstant(link)) > 0);
assertFalse(fs.canExecute(link));
fs.setExecute(target, true);
assertFalse(fs.canExecute(link));
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
index 5f58e7e457..951a5e30f8 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -8,6 +8,20 @@
</message_arguments>
</filter>
</resource>
+ <resource path="src/org/eclipse/jgit/dircache/DirCacheEntry.java" type="org.eclipse.jgit.dircache.DirCacheEntry">
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.1.9"/>
+ <message_argument value="getLastModifiedInstant()"/>
+ </message_arguments>
+ </filter>
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.1.9"/>
+ <message_argument value="setLastModified(Instant)"/>
+ </message_arguments>
+ </filter>
+ </resource>
<resource path="src/org/eclipse/jgit/errors/PackInvalidException.java" type="org.eclipse.jgit.errors.PackInvalidException">
<filter id="1142947843">
<message_arguments>
@@ -130,6 +144,28 @@
</message_arguments>
</filter>
</resource>
+ <resource path="src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java" type="org.eclipse.jgit.treewalk.WorkingTreeIterator">
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.1.9"/>
+ <message_argument value="getEntryLastModifiedInstant()"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java" type="org.eclipse.jgit.treewalk.WorkingTreeIterator$Entry">
+ <filter id="336695337">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.treewalk.WorkingTreeIterator.Entry"/>
+ <message_argument value="getLastModifiedInstant()"/>
+ </message_arguments>
+ </filter>
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.1.9"/>
+ <message_argument value="getLastModifiedInstant()"/>
+ </message_arguments>
+ </filter>
+ </resource>
<resource path="src/org/eclipse/jgit/util/FS.java" type="org.eclipse.jgit.util.FS">
<filter id="1142947843">
<message_arguments>
@@ -140,16 +176,42 @@
<filter id="1142947843">
<message_arguments>
<message_argument value="5.1.9"/>
+ <message_argument value="lastModifiedInstant(File)"/>
+ </message_arguments>
+ </filter>
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.1.9"/>
+ <message_argument value="lastModifiedInstant(Path)"/>
+ </message_arguments>
+ </filter>
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.1.9"/>
<message_argument value="setAsyncfileStoreAttrCache(boolean)"/>
</message_arguments>
</filter>
<filter id="1142947843">
<message_arguments>
+ <message_argument value="5.1.9"/>
+ <message_argument value="setLastModified(Path, Instant)"/>
+ </message_arguments>
+ </filter>
+ <filter id="1142947843">
+ <message_arguments>
<message_argument value="5.2.3"/>
<message_argument value="getFsTimerResolution(Path)"/>
</message_arguments>
</filter>
</resource>
+ <resource path="src/org/eclipse/jgit/util/FS.java" type="org.eclipse.jgit.util.FS$Attributes">
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.1.9"/>
+ <message_argument value="getLastModifiedInstant()"/>
+ </message_arguments>
+ </filter>
+ </resource>
<resource path="src/org/eclipse/jgit/util/FileUtils.java" type="org.eclipse.jgit.util.FileUtils">
<filter id="1142947843">
<message_arguments>
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index 9af6cce59d..6ac6955f06 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -561,6 +561,7 @@ rawLogMessageDoesNotParseAsLogEntry=Raw log message does not parse as log entry
readConfigFailed=Reading config file ''{0}'' failed
readerIsRequired=Reader is required
readingObjectsFromLocalRepositoryFailed=reading objects from local repository failed: {0}
+readLastModifiedFailed=Reading lastModified of {0} failed
readTimedOut=Read timed out after {0} ms
receivePackObjectTooLarge1=Object too large, rejecting the pack. Max object size limit is {0} bytes.
receivePackObjectTooLarge2=Object too large ({0} bytes), rejecting the pack. Max object size limit is {1} bytes.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
index f0408ab3d4..a2cd4aeb2a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
@@ -50,6 +50,7 @@ import static org.eclipse.jgit.lib.FileMode.TYPE_TREE;
import java.io.IOException;
import java.io.InputStream;
+import java.time.Instant;
import java.util.Collection;
import java.util.LinkedList;
@@ -228,7 +229,7 @@ public class AddCommand extends GitCommand<DirCache> {
if (GITLINK != mode) {
entry.setLength(f.getEntryLength());
- entry.setLastModified(f.getEntryLastModified());
+ entry.setLastModified(f.getEntryLastModifiedInstant());
long len = f.getEntryContentLength();
// We read and filter the content multiple times.
// f.getEntryContentLength() reads and filters the input and
@@ -241,7 +242,7 @@ public class AddCommand extends GitCommand<DirCache> {
}
} else {
entry.setLength(0);
- entry.setLastModified(0);
+ entry.setLastModified(Instant.ofEpochSecond(0));
entry.setObjectId(f.getEntryObjectId());
}
builder.add(entry);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
index d07532c092..cea28fac18 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
@@ -392,7 +392,7 @@ public class CommitCommand extends GitCommand<RevCommit> {
final DirCacheEntry dcEntry = new DirCacheEntry(path);
long entryLength = fTree.getEntryLength();
dcEntry.setLength(entryLength);
- dcEntry.setLastModified(fTree.getEntryLastModified());
+ dcEntry.setLastModified(fTree.getEntryLastModifiedInstant());
dcEntry.setFileMode(fTree.getIndexFileMode(dcTree));
boolean objectExists = (dcTree != null
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
index 13ce4e7690..d7c9ad5e04 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
@@ -422,7 +422,7 @@ public class ResetCommand extends GitCommand<Ref> {
DirCacheIterator.class);
if (dcIter != null && dcIter.idEqual(cIter)) {
DirCacheEntry indexEntry = dcIter.getDirCacheEntry();
- entry.setLastModified(indexEntry.getLastModified());
+ entry.setLastModified(indexEntry.getLastModifiedInstant());
entry.setLength(indexEntry.getLength());
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
index 01d070cbd9..ff7c4c64bc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
@@ -332,7 +332,7 @@ public class StashApplyCommand extends GitCommand<ObjectId> {
DirCacheIterator.class);
if (dcIter != null && dcIter.idEqual(cIter)) {
DirCacheEntry indexEntry = dcIter.getDirCacheEntry();
- entry.setLastModified(indexEntry.getLastModified());
+ entry.setLastModified(indexEntry.getLastModifiedInstant());
entry.setLength(indexEntry.getLength());
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
index c32890d8a4..0d010adb26 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
@@ -300,7 +300,8 @@ public class StashCreateCommand extends GitCommand<RevCommit> {
final DirCacheEntry entry = new DirCacheEntry(
treeWalk.getRawPath());
entry.setLength(wtIter.getEntryLength());
- entry.setLastModified(wtIter.getEntryLastModified());
+ entry.setLastModified(
+ wtIter.getEntryLastModifiedInstant());
entry.setFileMode(wtIter.getEntryFileMode());
long contentLength = wtIter.getEntryContentLength();
try (InputStream in = wtIter.openEntryStream()) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
index 14653fe17f..340214b068 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
@@ -497,8 +497,9 @@ public class DirCache {
throw new CorruptObjectException(JGitText.get().DIRCHasTooManyEntries);
snapshot = FileSnapshot.save(liveFile);
- int smudge_s = (int) (snapshot.lastModified() / 1000);
- int smudge_ns = ((int) (snapshot.lastModified() % 1000)) * 1000000;
+ // TODO (ms) combine smudge_s and smudge_ns into Duration
+ int smudge_s = (int) (snapshot.lastModifiedInstant().getEpochSecond());
+ int smudge_ns = snapshot.lastModifiedInstant().getNano();
// Load the individual file entries.
//
@@ -679,8 +680,8 @@ public class DirCache {
// so we use the current timestamp as a approximation.
myLock.createCommitSnapshot();
snapshot = myLock.getCommitSnapshot();
- smudge_s = (int) (snapshot.lastModified() / 1000);
- smudge_ns = ((int) (snapshot.lastModified() % 1000)) * 1000000;
+ smudge_s = (int) (snapshot.lastModifiedInstant().getEpochSecond());
+ smudge_ns = snapshot.lastModifiedInstant().getNano();
} else {
// Used in unit tests only
smudge_ns = 0;
@@ -1025,7 +1026,7 @@ public class DirCache {
DirCacheEntry entry = iIter.getDirCacheEntry();
if (entry.isSmudged() && iIter.idEqual(fIter)) {
entry.setLength(fIter.getEntryLength());
- entry.setLastModified(fIter.getEntryLastModified());
+ entry.setLastModified(fIter.getEntryLastModifiedInstant());
}
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
index ca1e3ab275..5110d77dc9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -50,6 +50,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.StandardCopyOption;
import java.text.MessageFormat;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@@ -425,8 +426,10 @@ public class DirCacheCheckout {
// update the timestamp of the index with the one from the
// file if not set, as we are sure to be in sync here.
DirCacheEntry entry = i.getDirCacheEntry();
- if (entry.getLastModified() == 0)
- entry.setLastModified(f.getEntryLastModified());
+ Instant mtime = entry.getLastModifiedInstant();
+ if (mtime == null || mtime.equals(Instant.EPOCH)) {
+ entry.setLastModified(f.getEntryLastModifiedInstant());
+ }
keep(entry);
}
} else
@@ -611,7 +614,7 @@ public class DirCacheCheckout {
File gitlinkDir = new File(repo.getWorkTree(), path);
FileUtils.mkdirs(gitlinkDir, true);
FS fs = repo.getFS();
- entry.setLastModified(fs.lastModified(gitlinkDir));
+ entry.setLastModified(fs.lastModifiedInstant(gitlinkDir));
}
private static ArrayList<String> filterOut(ArrayList<String> strings,
@@ -1433,7 +1436,7 @@ public class DirCacheCheckout {
}
fs.createSymLink(f, target);
entry.setLength(bytes.length);
- entry.setLastModified(fs.lastModified(f));
+ entry.setLastModified(fs.lastModifiedInstant(f));
return;
}
@@ -1502,7 +1505,7 @@ public class DirCacheCheckout {
FileUtils.delete(tmpFile);
}
}
- entry.setLastModified(fs.lastModified(f));
+ entry.setLastModified(fs.lastModifiedInstant(f));
}
// Run an external filter command
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
index 6b1d4f4d8a..4b36f6b96b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
@@ -56,6 +56,7 @@ import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.text.MessageFormat;
+import java.time.Instant;
import java.util.Arrays;
import org.eclipse.jgit.errors.CorruptObjectException;
@@ -144,6 +145,7 @@ public class DirCacheEntry {
/** Flags which are never stored to disk. */
private byte inCoreFlags;
+ // TODO (ms): use Instant to combine smudge_s and smudge_ns
DirCacheEntry(final byte[] sharedInfo, final MutableInteger infoAt,
final InputStream in, final MessageDigest md, final int smudge_s,
final int smudge_ns) throws IOException {
@@ -563,22 +565,51 @@ public class DirCacheEntry {
*
* @return last modification time of this file, in milliseconds since the
* Java epoch (midnight Jan 1, 1970 UTC).
+ * @deprecated use {@link #getLastModifiedInstant()} instead
*/
+ @Deprecated
public long getLastModified() {
return decodeTS(P_MTIME);
}
/**
+ * Get the cached last modification date of this file.
+ * <p>
+ * One of the indicators that the file has been modified by an application
+ * changing the working tree is if the last modification time for the file
+ * differs from the time stored in this entry.
+ *
+ * @return last modification time of this file.
+ * @since 5.1.9
+ */
+ public Instant getLastModifiedInstant() {
+ return decodeTSInstant(P_MTIME);
+ }
+
+ /**
* Set the cached last modification date of this file, using milliseconds.
*
* @param when
* new cached modification date of the file, in milliseconds.
+ * @deprecated use {@link #setLastModified(Instant)} instead
*/
+ @Deprecated
public void setLastModified(long when) {
encodeTS(P_MTIME, when);
}
/**
+ * Set the cached last modification date of this file.
+ *
+ * @param when
+ * new cached modification date of the file.
+ * @since 5.1.9
+ */
+ public void setLastModified(Instant when) {
+ encodeTS(P_MTIME, when);
+ }
+
+ /**
* Get the cached size (mod 4 GB) (in bytes) of this file.
* <p>
* One of the indicators that the file has been modified by an application
@@ -692,7 +723,8 @@ public class DirCacheEntry {
@SuppressWarnings("nls")
@Override
public String toString() {
- return getFileMode() + " " + getLength() + " " + getLastModified()
+ return getFileMode() + " " + getLength() + " "
+ + getLastModifiedInstant()
+ " " + getObjectId() + " " + getStage() + " "
+ getPathString() + "\n";
}
@@ -750,12 +782,25 @@ public class DirCacheEntry {
return 1000L * sec + ms;
}
+ private Instant decodeTSInstant(int pIdx) {
+ final int base = infoOffset + pIdx;
+ final int sec = NB.decodeInt32(info, base);
+ final int nano = NB.decodeInt32(info, base + 4);
+ return Instant.ofEpochSecond(sec, nano);
+ }
+
private void encodeTS(int pIdx, long when) {
final int base = infoOffset + pIdx;
NB.encodeInt32(info, base, (int) (when / 1000));
NB.encodeInt32(info, base + 4, ((int) (when % 1000)) * 1000000);
}
+ private void encodeTS(int pIdx, Instant when) {
+ final int base = infoOffset + pIdx;
+ NB.encodeInt32(info, base, (int) when.getEpochSecond());
+ NB.encodeInt32(info, base + 4, when.getNano());
+ }
+
private int getExtendedFlags() {
if (isExtended())
return NB.decodeUInt16(info, infoOffset + P_FLAGS2) << 16;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index 79133d203c..38c063d071 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -622,6 +622,7 @@ public class JGitText extends TranslationBundle {
/***/ public String readConfigFailed;
/***/ public String readerIsRequired;
/***/ public String readingObjectsFromLocalRepositoryFailed;
+ /***/ public String readLastModifiedFailed;
/***/ public String readTimedOut;
/***/ public String receivePackObjectTooLarge1;
/***/ public String receivePackObjectTooLarge2;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java
index 1b13ccf765..fe3703719c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java
@@ -48,10 +48,10 @@ import static org.eclipse.jgit.lib.Constants.FALLBACK_TIMESTAMP_RESOLUTION;
import java.io.File;
import java.io.IOException;
import java.nio.file.attribute.BasicFileAttributes;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
import java.time.Duration;
-import java.util.Date;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@@ -87,8 +87,14 @@ public class FileSnapshot {
*/
public static final long UNKNOWN_SIZE = -1;
+ private static final Instant UNKNOWN_TIME = Instant.ofEpochMilli(-1);
+
private static final Object MISSING_FILEKEY = new Object();
+ private static final DateTimeFormatter dateFmt = DateTimeFormatter
+ .ofPattern("yyyy-MM-dd HH:mm:ss.nnnnnnnnn") //$NON-NLS-1$
+ .withLocale(Locale.getDefault()).withZone(ZoneId.systemDefault());
+
/**
* A FileSnapshot that is considered to always be modified.
* <p>
@@ -96,8 +102,8 @@ public class FileSnapshot {
* file, but only after {@link #isModified(File)} gets invoked. The returned
* snapshot contains only invalid status information.
*/
- public static final FileSnapshot DIRTY = new FileSnapshot(-1, -1,
- UNKNOWN_SIZE, Duration.ZERO, MISSING_FILEKEY);
+ public static final FileSnapshot DIRTY = new FileSnapshot(UNKNOWN_TIME,
+ UNKNOWN_TIME, UNKNOWN_SIZE, Duration.ZERO, MISSING_FILEKEY);
/**
* A FileSnapshot that is clean if the file does not exist.
@@ -106,8 +112,8 @@ public class FileSnapshot {
* file to be clean. {@link #isModified(File)} will return false if the file
* path does not exist.
*/
- public static final FileSnapshot MISSING_FILE = new FileSnapshot(0, 0, 0,
- Duration.ZERO, MISSING_FILEKEY) {
+ public static final FileSnapshot MISSING_FILE = new FileSnapshot(
+ Instant.EPOCH, Instant.EPOCH, 0, Duration.ZERO, MISSING_FILEKEY) {
@Override
public boolean isModified(File path) {
return FS.DETECTED.exists(path);
@@ -163,18 +169,41 @@ public class FileSnapshot {
* @param modified
* the last modification time of the file
* @return the snapshot.
+ * @deprecated use {@link #save(Instant)} instead.
*/
+ @Deprecated
public static FileSnapshot save(long modified) {
- final long read = System.currentTimeMillis();
+ final Instant read = Instant.now();
+ return new FileSnapshot(read, Instant.ofEpochMilli(modified),
+ UNKNOWN_SIZE, Duration.ZERO, MISSING_FILEKEY);
+ }
+
+ /**
+ * Record a snapshot for a file for which the last modification time is
+ * already known.
+ * <p>
+ * This method should be invoked before the file is accessed.
+ * <p>
+ * Note that this method cannot rely on measuring file timestamp resolution
+ * to avoid racy git issues caused by finite file timestamp resolution since
+ * it's unknown in which filesystem the file is located. Hence the worst
+ * case fallback for timestamp resolution is used.
+ *
+ * @param modified
+ * the last modification time of the file
+ * @return the snapshot.
+ */
+ public static FileSnapshot save(Instant modified) {
+ final Instant read = Instant.now();
return new FileSnapshot(read, modified, UNKNOWN_SIZE, Duration.ZERO,
MISSING_FILEKEY);
}
/** Last observed modification time of the path. */
- private final long lastModified;
+ private final Instant lastModified;
/** Last wall-clock time the path was read. */
- private volatile long lastRead;
+ private volatile Instant lastRead;
/** True once {@link #lastRead} is far later than {@link #lastModified}. */
private boolean cannotBeRacilyClean;
@@ -222,7 +251,7 @@ public class FileSnapshot {
*/
protected FileSnapshot(File file, boolean useConfig) {
this.file = file;
- this.lastRead = System.currentTimeMillis();
+ this.lastRead = Instant.now();
this.fsTimestampResolution = useConfig
? FS.getFsTimerResolution(file.toPath().getParent())
: FALLBACK_TIMESTAMP_RESOLUTION;
@@ -230,18 +259,20 @@ public class FileSnapshot {
try {
fileAttributes = FS.DETECTED.fileAttributes(file);
} catch (IOException e) {
- this.lastModified = file.lastModified();
+ this.lastModified = Instant.ofEpochMilli(file.lastModified());
this.size = file.length();
this.fileKey = MISSING_FILEKEY;
return;
}
- this.lastModified = fileAttributes.lastModifiedTime().toMillis();
+ this.lastModified = fileAttributes.lastModifiedTime().toInstant();
this.size = fileAttributes.size();
this.fileKey = getFileKey(fileAttributes);
- LOG.debug("file={}, create new FileSnapshot: lastRead={} ms" //$NON-NLS-1$
- + ", lastModified={} ms, size={}, fileKey={}", //$NON-NLS-1$
- file, Long.valueOf(lastRead), Long.valueOf(lastModified),
- Long.valueOf(size), fileKey);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("file={}, create new FileSnapshot: lastRead={}, lastModified={}, size={}, fileKey={}", //$NON-NLS-1$
+ file, dateFmt.format(lastRead),
+ dateFmt.format(lastModified), Long.valueOf(size),
+ fileKey.toString());
+ }
}
private boolean sizeChanged;
@@ -252,7 +283,7 @@ public class FileSnapshot {
private boolean wasRacyClean;
- private FileSnapshot(long read, long modified, long size,
+ private FileSnapshot(Instant read, Instant modified, long size,
@NonNull Duration fsTimestampResolution, @NonNull Object fileKey) {
this.file = null;
this.lastRead = read;
@@ -266,8 +297,19 @@ public class FileSnapshot {
* Get time of last snapshot update
*
* @return time of last snapshot update
+ * @deprecated use {@link #lastModifiedInstant()} instead
*/
+ @Deprecated
public long lastModified() {
+ return lastModified.toEpochMilli();
+ }
+
+ /**
+ * Get time of last snapshot update
+ *
+ * @return time of last snapshot update
+ */
+ public Instant lastModifiedInstant() {
return lastModified;
}
@@ -286,16 +328,16 @@ public class FileSnapshot {
* @return true if the path needs to be read again.
*/
public boolean isModified(File path) {
- long currLastModified;
+ Instant currLastModified;
long currSize;
Object currFileKey;
try {
BasicFileAttributes fileAttributes = FS.DETECTED.fileAttributes(path);
- currLastModified = fileAttributes.lastModifiedTime().toMillis();
+ currLastModified = fileAttributes.lastModifiedTime().toInstant();
currSize = fileAttributes.size();
currFileKey = getFileKey(fileAttributes);
} catch (IOException e) {
- currLastModified = path.lastModified();
+ currLastModified = Instant.ofEpochMilli(path.lastModified());
currSize = path.length();
currFileKey = MISSING_FILEKEY;
}
@@ -337,7 +379,7 @@ public class FileSnapshot {
* the other snapshot.
*/
public void setClean(FileSnapshot other) {
- final long now = other.lastRead;
+ final Instant now = other.lastRead;
if (!isRacyClean(now)) {
cannotBeRacilyClean = true;
}
@@ -351,7 +393,7 @@ public class FileSnapshot {
* if sleep was interrupted
*/
public void waitUntilNotRacy() throws InterruptedException {
- while (isRacyClean(System.currentTimeMillis())) {
+ while (isRacyClean(Instant.now())) {
TimeUnit.NANOSECONDS
.sleep((fsTimestampResolution.toNanos() + 1) * 11 / 10);
}
@@ -366,7 +408,7 @@ public class FileSnapshot {
*/
public boolean equals(FileSnapshot other) {
boolean sizeEq = size == UNKNOWN_SIZE || other.size == UNKNOWN_SIZE || size == other.size;
- return lastModified == other.lastModified && sizeEq
+ return lastModified.equals(other.lastModified) && sizeEq
&& Objects.equals(fileKey, other.fileKey);
}
@@ -389,8 +431,7 @@ public class FileSnapshot {
/** {@inheritDoc} */
@Override
public int hashCode() {
- return Objects.hash(Long.valueOf(lastModified), Long.valueOf(size),
- fileKey);
+ return Objects.hash(lastModified, Long.valueOf(size), fileKey);
}
/**
@@ -435,34 +476,37 @@ public class FileSnapshot {
if (this == MISSING_FILE) {
return "MISSING_FILE";
}
- DateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS",
- Locale.US);
- return "FileSnapshot[modified: " + f.format(new Date(lastModified))
- + ", read: " + f.format(new Date(lastRead)) + ", size:" + size
+ return "FileSnapshot[modified: " + dateFmt.format(lastModified)
+ + ", read: " + dateFmt.format(lastRead) + ", size:" + size
+ ", fileKey: " + fileKey + "]";
}
- private boolean isRacyClean(long read) {
+ private boolean isRacyClean(Instant read) {
// add a 10% safety margin
long racyNanos = (fsTimestampResolution.toNanos() + 1) * 11 / 10;
- long delta = (read - lastModified) * 1_000_000;
+ long delta = Duration.between(lastModified, read).toNanos();
wasRacyClean = delta <= racyNanos;
- LOG.debug("file={}, isRacyClean={}, read={} ms, lastModified={} ms," //$NON-NLS-1$
- + " delta={} ns, racy<={} ns", //$NON-NLS-1$
- file, Boolean.valueOf(wasRacyClean), Long.valueOf(read),
- Long.valueOf(lastModified), Long.valueOf(delta),
- Long.valueOf(racyNanos));
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(
+ "file={}, isRacyClean={}, read={}, lastModified={}, delta={} ns, racy<={} ns", //$NON-NLS-1$
+ file, Boolean.valueOf(wasRacyClean), dateFmt.format(read),
+ dateFmt.format(lastModified), Long.valueOf(delta),
+ Long.valueOf(racyNanos));
+ }
return wasRacyClean;
}
- private boolean isModified(long currLastModified) {
+ private boolean isModified(Instant currLastModified) {
// Any difference indicates the path was modified.
- lastModifiedChanged = lastModified != currLastModified;
+ lastModifiedChanged = !lastModified.equals(currLastModified);
if (lastModifiedChanged) {
- LOG.debug("file={}, lastModified changed from {} to {}", //$NON-NLS-1$
- file, Long.valueOf(lastModified),
- Long.valueOf(currLastModified));
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(
+ "file={}, lastModified changed from {} to {}", //$NON-NLS-1$
+ file, dateFmt.format(lastModified),
+ dateFmt.format(currLastModified));
+ }
return true;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
index 3c830e88c1..791a108289 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
@@ -372,8 +372,9 @@ public class GC {
continue oldPackLoop;
if (!oldPack.shouldBeKept()
- && repo.getFS().lastModified(
- oldPack.getPackFile()) < packExpireDate) {
+ && repo.getFS()
+ .lastModifiedInstant(oldPack.getPackFile())
+ .toEpochMilli() < packExpireDate) {
oldPack.close();
if (shouldLoosen) {
loosen(inserter, reader, oldPack, ids);
@@ -561,8 +562,10 @@ public class GC {
String fName = f.getName();
if (fName.length() != Constants.OBJECT_ID_STRING_LENGTH - 2)
continue;
- if (repo.getFS().lastModified(f) >= expireDate)
+ if (repo.getFS().lastModifiedInstant(f)
+ .toEpochMilli() >= expireDate) {
continue;
+ }
try {
ObjectId id = ObjectId.fromString(d + fName);
if (objectsToKeep.contains(id))
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java
index b80c58ca9c..ccca0279aa 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java
@@ -56,8 +56,11 @@ import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
+import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.FileTime;
import java.text.MessageFormat;
+import java.time.Instant;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
@@ -424,7 +427,12 @@ public class LockFile {
FileSnapshot n = FileSnapshot.save(lck);
while (o.equals(n)) {
Thread.sleep(25 /* milliseconds */);
- lck.setLastModified(System.currentTimeMillis());
+ try {
+ Files.setLastModifiedTime(lck.toPath(),
+ FileTime.from(Instant.now()));
+ } catch (IOException e) {
+ n.waitUntilNotRacy();
+ }
n = FileSnapshot.save(lck);
}
}
@@ -474,12 +482,23 @@ public class LockFile {
* Get the modification time of the output file when it was committed.
*
* @return modification time of the lock file right before we committed it.
+ * @deprecated use {@link #getCommitLastModifiedInstant()} instead
*/
+ @Deprecated
public long getCommitLastModified() {
return commitSnapshot.lastModified();
}
/**
+ * Get the modification time of the output file when it was committed.
+ *
+ * @return modification time of the lock file right before we committed it.
+ */
+ public Instant getCommitLastModifiedInstant() {
+ return commitSnapshot.lastModifiedInstant();
+ }
+
+ /**
* Get the {@link FileSnapshot} just before commit.
*
* @return get the {@link FileSnapshot} just before commit.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
index 73ad38c95a..88e05af414 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
@@ -60,6 +60,7 @@ import java.nio.channels.FileChannel.MapMode;
import java.nio.file.AccessDeniedException;
import java.nio.file.NoSuchFileException;
import java.text.MessageFormat;
+import java.time.Instant;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
@@ -107,7 +108,7 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> {
public static final Comparator<PackFile> SORT = new Comparator<PackFile>() {
@Override
public int compare(PackFile a, PackFile b) {
- return b.packLastModified - a.packLastModified;
+ return b.packLastModified.compareTo(a.packLastModified);
}
};
@@ -132,7 +133,7 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> {
private int activeCopyRawData;
- int packLastModified;
+ Instant packLastModified;
private PackFileSnapshot fileSnapshot;
@@ -172,7 +173,7 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> {
public PackFile(File packFile, int extensions) {
this.packFile = packFile;
this.fileSnapshot = PackFileSnapshot.save(packFile);
- this.packLastModified = (int) (fileSnapshot.lastModified() >> 10);
+ this.packLastModified = fileSnapshot.lastModifiedInstant();
this.extensions = extensions;
// Multiply by 31 here so we can more directly combine with another
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
index f60c95f647..d4282e0b85 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -46,6 +46,7 @@
*/
package org.eclipse.jgit.merge;
+import static java.time.Instant.EPOCH;
import static org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm.HISTOGRAM;
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFF_SECTION;
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_ALGORITHM;
@@ -59,6 +60,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -464,7 +466,7 @@ public class ResolveMerger extends ThreeWayMerger {
* @return the entry which was added to the index
*/
private DirCacheEntry add(byte[] path, CanonicalTreeParser p, int stage,
- long lastMod, long len) {
+ Instant lastMod, long len) {
if (p != null && !p.getEntryFileMode().equals(FileMode.TREE)) {
DirCacheEntry e = new DirCacheEntry(path, stage);
e.setFileMode(p.getEntryFileMode());
@@ -491,7 +493,7 @@ public class ResolveMerger extends ThreeWayMerger {
e.getStage());
newEntry.setFileMode(e.getFileMode());
newEntry.setObjectId(e.getObjectId());
- newEntry.setLastModified(e.getLastModified());
+ newEntry.setLastModified(e.getLastModifiedInstant());
newEntry.setLength(e.getLength());
builder.add(newEntry);
return newEntry;
@@ -667,16 +669,17 @@ public class ResolveMerger extends ThreeWayMerger {
// we know about length and lastMod only after we have written the new content.
// This will happen later. Set these values to 0 for know.
DirCacheEntry e = add(tw.getRawPath(), theirs,
- DirCacheEntry.STAGE_0, 0, 0);
+ DirCacheEntry.STAGE_0, EPOCH, 0);
addToCheckout(tw.getPathString(), e, attributes);
}
return true;
} else {
// FileModes are not mergeable. We found a conflict on modes.
// For conflicting entries we don't know lastModified and length.
- add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
- add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
- add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
+ add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
+ add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
+ add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH,
+ 0);
unmergedPaths.add(tw.getPathString());
mergeResults.put(
tw.getPathString(),
@@ -708,7 +711,7 @@ public class ResolveMerger extends ThreeWayMerger {
// the new content.
// This will happen later. Set these values to 0 for know.
DirCacheEntry e = add(tw.getRawPath(), theirs,
- DirCacheEntry.STAGE_0, 0, 0);
+ DirCacheEntry.STAGE_0, EPOCH, 0);
if (e != null) {
addToCheckout(tw.getPathString(), e, attributes);
}
@@ -737,16 +740,16 @@ public class ResolveMerger extends ThreeWayMerger {
// detected later
if (nonTree(modeO) && !nonTree(modeT)) {
if (nonTree(modeB))
- add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
- add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
+ add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
+ add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
unmergedPaths.add(tw.getPathString());
enterSubtree = false;
return true;
}
if (nonTree(modeT) && !nonTree(modeO)) {
if (nonTree(modeB))
- add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
- add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
+ add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
+ add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0);
unmergedPaths.add(tw.getPathString());
enterSubtree = false;
return true;
@@ -773,9 +776,9 @@ public class ResolveMerger extends ThreeWayMerger {
boolean gitlinkConflict = isGitLink(modeO) || isGitLink(modeT);
// Don't attempt to resolve submodule link conflicts
if (gitlinkConflict || !attributes.canBeContentMerged()) {
- add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
- add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
- add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
+ add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
+ add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
+ add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0);
if (gitlinkConflict) {
MergeResult<SubmoduleConflict> result = new MergeResult<>(
@@ -822,10 +825,10 @@ public class ResolveMerger extends ThreeWayMerger {
MergeResult<RawText> result = contentMerge(base, ours, theirs,
attributes);
- add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
- add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
+ add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
+ add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
DirCacheEntry e = add(tw.getRawPath(), theirs,
- DirCacheEntry.STAGE_3, 0, 0);
+ DirCacheEntry.STAGE_3, EPOCH, 0);
// OURS was deleted checkout THEIRS
if (modeO == 0) {
@@ -957,9 +960,9 @@ public class ResolveMerger extends ThreeWayMerger {
// A conflict occurred, the file will contain conflict markers
// the index will be populated with the three stages and the
// workdir (if used) contains the halfway merged content.
- add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
- add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
- add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
+ add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
+ add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
+ add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0);
mergeResults.put(tw.getPathString(), result);
return;
}
@@ -976,7 +979,7 @@ public class ResolveMerger extends ThreeWayMerger {
? FileMode.REGULAR_FILE : FileMode.fromBits(newMode));
if (mergedFile != null) {
dce.setLastModified(
- nonNullRepo().getFS().lastModified(mergedFile));
+ nonNullRepo().getFS().lastModifiedInstant(mergedFile));
dce.setLength((int) mergedFile.length());
}
dce.setObjectId(insertMergeResult(rawMerged, attributes));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java
index e688f6340d..4f1eba66d3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java
@@ -46,6 +46,7 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
+import java.time.Instant;
import java.util.Collection;
import java.util.HashMap;
import java.util.Locale;
@@ -123,7 +124,7 @@ public class NetRC {
private File netrc;
- private long lastModified;
+ private Instant lastModified;
private Map<String, NetRCEntry> hosts = new HashMap<>();
@@ -187,8 +188,10 @@ public class NetRC {
if (netrc == null)
return null;
- if (this.lastModified != this.netrc.lastModified())
+ if (!this.lastModified
+ .equals(FS.DETECTED.lastModifiedInstant(this.netrc))) {
parse();
+ }
NetRCEntry entry = this.hosts.get(host);
@@ -209,7 +212,7 @@ public class NetRC {
private void parse() {
this.hosts.clear();
- this.lastModified = this.netrc.lastModified();
+ this.lastModified = FS.DETECTED.lastModifiedInstant(this.netrc);
try (BufferedReader r = new BufferedReader(new FileReader(netrc))) {
String line = null;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/OpenSshConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/OpenSshConfig.java
index 480055c2e4..4dd5df9cd6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/OpenSshConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/OpenSshConfig.java
@@ -51,6 +51,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -166,7 +167,7 @@ public class OpenSshConfig implements ConfigRepository {
private final File configFile;
/** Modification time of {@link #configFile} when it was last loaded. */
- private long lastModified;
+ private Instant lastModified;
/**
* Encapsulates entries read out of the configuration file, and
@@ -224,8 +225,8 @@ public class OpenSshConfig implements ConfigRepository {
}
private synchronized State refresh() {
- final long mtime = configFile.lastModified();
- if (mtime != lastModified) {
+ final Instant mtime = FS.DETECTED.lastModifiedInstant(configFile);
+ if (!mtime.equals(lastModified)) {
State newState = new State();
try (FileInputStream in = new FileInputStream(configFile)) {
newState.entries = parse(in);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java
index 3d25c2314e..d432c94450 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java
@@ -53,6 +53,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.time.Instant;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -406,8 +407,14 @@ public class FileTreeIterator extends WorkingTreeIterator {
}
@Override
+ @Deprecated
public long getLastModified() {
- return attributes.getLastModifiedTime();
+ return attributes.getLastModifiedInstant().toEpochMilli();
+ }
+
+ @Override
+ public Instant getLastModifiedInstant() {
+ return attributes.getLastModifiedInstant();
}
@Override
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
index 7c6bfb9d63..299f07fb09 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -59,6 +59,7 @@ import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.CharsetEncoder;
import java.text.MessageFormat;
+import java.time.Instant;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
@@ -645,12 +646,24 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
*
* @return last modified time of this file, in milliseconds since the epoch
* (Jan 1, 1970 UTC).
+ * @deprecated use {@link #getEntryLastModifiedInstant()} instead
*/
+ @Deprecated
public long getEntryLastModified() {
return current().getLastModified();
}
/**
+ * Get the last modified time of this entry.
+ *
+ * @return last modified time of this file
+ * @since 5.1.9
+ */
+ public Instant getEntryLastModifiedInstant() {
+ return current().getLastModifiedInstant();
+ }
+
+ /**
* Obtain an input stream to read the file content.
* <p>
* Efficient implementations are not required. The caller will usually
@@ -924,30 +937,28 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
// Git under windows only stores seconds so we round the timestamp
// Java gives us if it looks like the timestamp in index is seconds
- // only. Otherwise we compare the timestamp at millisecond precision,
+ // only. Otherwise we compare the timestamp at nanosecond precision,
// unless core.checkstat is set to "minimal", in which case we only
// compare the whole second part.
- long cacheLastModified = entry.getLastModified();
- long fileLastModified = getEntryLastModified();
- long lastModifiedMillis = fileLastModified % 1000;
- long cacheMillis = cacheLastModified % 1000;
- if (getOptions().getCheckStat() == CheckStat.MINIMAL) {
- fileLastModified = fileLastModified - lastModifiedMillis;
- cacheLastModified = cacheLastModified - cacheMillis;
- } else if (cacheMillis == 0)
- fileLastModified = fileLastModified - lastModifiedMillis;
- // Some Java version on Linux return whole seconds only even when
- // the file systems supports more precision.
- else if (lastModifiedMillis == 0)
- cacheLastModified = cacheLastModified - cacheMillis;
-
- if (fileLastModified != cacheLastModified)
+ Instant cacheLastModified = entry.getLastModifiedInstant();
+ Instant fileLastModified = getEntryLastModifiedInstant();
+ if ((getOptions().getCheckStat() == CheckStat.MINIMAL)
+ || (cacheLastModified.getNano() == 0)
+ // Some Java version on Linux return whole seconds only even
+ // when the file systems supports more precision.
+ || (fileLastModified.getNano() == 0)) {
+ if (fileLastModified.getEpochSecond() != cacheLastModified
+ .getEpochSecond()) {
+ return MetadataDiff.DIFFER_BY_TIMESTAMP;
+ }
+ }
+ if (!fileLastModified.equals(cacheLastModified)) {
return MetadataDiff.DIFFER_BY_TIMESTAMP;
- else if (!entry.isSmudged())
- // The file is clean when you look at timestamps.
- return MetadataDiff.EQUAL;
- else
+ } else if (entry.isSmudged()) {
return MetadataDiff.SMUDGED;
+ }
+ // The file is clean when when comparing timestamps
+ return MetadataDiff.EQUAL;
}
/**
@@ -1274,10 +1285,26 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
* instance member instead.
*
* @return time since the epoch (in ms) of the last change.
+ * @deprecated use {@link #getLastModifiedInstant()} instead
*/
+ @Deprecated
public abstract long getLastModified();
/**
+ * Get the last modified time of this entry.
+ * <p>
+ * <b>Note: Efficient implementation required.</b>
+ * <p>
+ * The implementation of this method must be efficient. If a subclass
+ * needs to compute the value they should cache the reference within an
+ * instance member instead.
+ *
+ * @return time of the last change.
+ * @since 5.1.9
+ */
+ public abstract Instant getLastModifiedInstant();
+
+ /**
* Get the name of this entry within its directory.
* <p>
* Efficient implementations are not required. The caller will obtain
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
index 6e3e336e94..e8570d7417 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -44,6 +44,7 @@
package org.eclipse.jgit.util;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.time.Instant.EPOCH;
import static org.eclipse.jgit.lib.Constants.FALLBACK_TIMESTAMP_RESOLUTION;
import java.io.BufferedReader;
@@ -66,6 +67,7 @@ import java.security.AccessController;
import java.security.PrivilegedAction;
import java.text.MessageFormat;
import java.time.Duration;
+import java.time.Instant;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -625,12 +627,42 @@ public abstract class FS {
* @return last modified time of f
* @throws java.io.IOException
* @since 3.0
+ * @deprecated use {@link #lastModifiedInstant(Path)} instead
*/
+ @Deprecated
public long lastModified(File f) throws IOException {
return FileUtils.lastModified(f);
}
/**
+ * Get the last modified time of a file system object. If the OS/JRE support
+ * symbolic links, the modification time of the link is returned, rather
+ * than that of the link target.
+ *
+ * @param p
+ * a {@link Path} object.
+ * @return last modified time of p
+ * @since 5.1.9
+ */
+ public Instant lastModifiedInstant(Path p) {
+ return FileUtils.lastModifiedInstant(p);
+ }
+
+ /**
+ * Get the last modified time of a file system object. If the OS/JRE support
+ * symbolic links, the modification time of the link is returned, rather
+ * than that of the link target.
+ *
+ * @param f
+ * a {@link File} object.
+ * @return last modified time of p
+ * @since 5.1.9
+ */
+ public Instant lastModifiedInstant(File f) {
+ return FileUtils.lastModifiedInstant(f.toPath());
+ }
+
+ /**
* Set the last modified time of a file system object. If the OS/JRE support
* symbolic links, the link is modified, not the target,
*
@@ -640,12 +672,29 @@ public abstract class FS {
* last modified time
* @throws java.io.IOException
* @since 3.0
+ * @deprecated use {@link #setLastModified(Path, Instant)} instead
*/
+ @Deprecated
public void setLastModified(File f, long time) throws IOException {
FileUtils.setLastModified(f, time);
}
/**
+ * Set the last modified time of a file system object. If the OS/JRE support
+ * symbolic links, the link is modified, not the target,
+ *
+ * @param p
+ * a {@link Path} object.
+ * @param time
+ * last modified time
+ * @throws java.io.IOException
+ * @since 5.1.9
+ */
+ public void setLastModified(Path p, Instant time) throws IOException {
+ FileUtils.setLastModified(p, time);
+ }
+
+ /**
* Get the length of a file or link, If the OS/JRE supports symbolic links
* it's the length of the link, else the length of the target.
*
@@ -1712,9 +1761,19 @@ public abstract class FS {
/**
* @return the time (milliseconds since 1970-01-01) when this object was
* last modified
+ * @deprecated use getLastModifiedInstant instead
*/
+ @Deprecated
public long getLastModifiedTime() {
- return lastModifiedTime;
+ return lastModifiedInstant.toEpochMilli();
+ }
+
+ /**
+ * @return the time when this object was last modified
+ * @since 5.1.9
+ */
+ public Instant getLastModifiedInstant() {
+ return lastModifiedInstant;
}
private final boolean isDirectory;
@@ -1725,7 +1784,7 @@ public abstract class FS {
private final long creationTime;
- private final long lastModifiedTime;
+ private final Instant lastModifiedInstant;
private final boolean isExecutable;
@@ -1743,7 +1802,7 @@ public abstract class FS {
Attributes(FS fs, File file, boolean exists, boolean isDirectory,
boolean isExecutable, boolean isSymbolicLink,
boolean isRegularFile, long creationTime,
- long lastModifiedTime, long length) {
+ Instant lastModifiedInstant, long length) {
this.fs = fs;
this.file = file;
this.exists = exists;
@@ -1752,7 +1811,7 @@ public abstract class FS {
this.isSymbolicLink = isSymbolicLink;
this.isRegularFile = isRegularFile;
this.creationTime = creationTime;
- this.lastModifiedTime = lastModifiedTime;
+ this.lastModifiedInstant = lastModifiedInstant;
this.length = length;
}
@@ -1764,7 +1823,7 @@ public abstract class FS {
* @param path
*/
public Attributes(File path, FS fs) {
- this(fs, path, false, false, false, false, false, 0L, 0L, 0L);
+ this(fs, path, false, false, false, false, false, 0L, EPOCH, 0L);
}
/**
@@ -1810,7 +1869,7 @@ public abstract class FS {
boolean exists = isDirectory || isFile;
boolean canExecute = exists && !isDirectory && canExecute(path);
boolean isSymlink = false;
- long lastModified = exists ? path.lastModified() : 0L;
+ Instant lastModified = exists ? lastModifiedInstant(path) : EPOCH;
long createTime = 0L;
return new Attributes(this, path, exists, isDirectory, canExecute,
isSymlink, isFile, createTime, lastModified, -1);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java
index 98797dc64f..7c07270363 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java
@@ -149,7 +149,7 @@ public class FS_Win32 extends FS {
attrs.isSymbolicLink(),
attrs.isRegularFile(),
attrs.creationTime().toMillis(),
- attrs.lastModifiedTime().toMillis(),
+ attrs.lastModifiedTime().toInstant(),
attrs.size());
result.add(new FileEntry(f, fs, attributes,
fileModeStrategy));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
index 9650602fea..80f188cb2c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
@@ -76,11 +76,14 @@ import java.util.regex.Pattern;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.util.FS.Attributes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* File Utilities
*/
public class FileUtils {
+ private static final Logger LOG = LoggerFactory.getLogger(FileUtils.class);
/**
* Option to delete given {@code File}
@@ -656,13 +659,32 @@ public class FileUtils {
* @return lastModified attribute for given file, not following symbolic
* links
* @throws IOException
+ * @deprecated use {@link #lastModifiedInstant(Path)} instead which returns
+ * FileTime
*/
+ @Deprecated
static long lastModified(File file) throws IOException {
return Files.getLastModifiedTime(toPath(file), LinkOption.NOFOLLOW_LINKS)
.toMillis();
}
/**
+ * @param path
+ * @return lastModified attribute for given file, not following symbolic
+ * links
+ */
+ static Instant lastModifiedInstant(Path path) {
+ try {
+ return Files.getLastModifiedTime(path, LinkOption.NOFOLLOW_LINKS)
+ .toInstant();
+ } catch (IOException e) {
+ LOG.error(MessageFormat
+ .format(JGitText.get().readLastModifiedFailed, path));
+ return Instant.ofEpochMilli(path.toFile().lastModified());
+ }
+ }
+
+ /**
* Return all the attributes of a file, without following symbolic links.
*
* @param file
@@ -680,11 +702,22 @@ public class FileUtils {
* @param time
* @throws IOException
*/
+ @Deprecated
static void setLastModified(File file, long time) throws IOException {
Files.setLastModifiedTime(toPath(file), FileTime.fromMillis(time));
}
/**
+ * @param path
+ * @param time
+ * @throws IOException
+ */
+ static void setLastModified(Path path, Instant time)
+ throws IOException {
+ Files.setLastModifiedTime(path, FileTime.from(time));
+ }
+
+ /**
* @param file
* @return {@code true} if the given file exists, not following symbolic
* links
@@ -788,7 +821,7 @@ public class FileUtils {
readAttributes.isSymbolicLink(),
readAttributes.isRegularFile(), //
readAttributes.creationTime().toMillis(), //
- readAttributes.lastModifiedTime().toMillis(),
+ readAttributes.lastModifiedTime().toInstant(),
readAttributes.isSymbolicLink() ? Constants
.encode(readSymLink(file)).length
: readAttributes.size());
@@ -827,7 +860,7 @@ public class FileUtils {
readAttributes.isSymbolicLink(),
readAttributes.isRegularFile(), //
readAttributes.creationTime().toMillis(), //
- readAttributes.lastModifiedTime().toMillis(),
+ readAttributes.lastModifiedTime().toInstant(),
readAttributes.size());
return attributes;
} catch (IOException e) {