aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit/src/org/eclipse/jgit/util
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit/src/org/eclipse/jgit/util')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/Base64.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/BlockList.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/CachedAuthenticator.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/Equality.java26
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java257
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java90
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java11
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java17
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java112
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/GSSManagerFactory.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateFormatter.java88
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateParser.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/GitTimeParser.java248
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java11
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java86
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/IntList.java7
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/Iterators.java57
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/LfsFactory.java18
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/LongList.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/NB.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/RawCharSequence.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java188
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/RawSubStringPattern.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java21
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/RelativeDateFormatter.java23
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/SignatureUtils.java39
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/Stats.java25
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java84
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java228
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFInputStream.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java5
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFInputStream.java41
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFOutputStream.java5
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/ByteBufferInputStream.java137
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/CountingOutputStream.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/DisabledOutputStream.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/InterruptTimer.java16
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/IsolatedOutputStream.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/LimitedInputStream.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/MessageWriter.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/SilentInputStream.java49
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/StreamCopyThread.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/TeeInputStream.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/TeeOutputStream.java5
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/ThrowingPrintWriter.java30
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/TimeoutInputStream.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/TimeoutOutputStream.java5
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/UnionInputStream.java17
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1Java.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/UbcCheck.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicSystemClock.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/time/ProposedTimestamp.java7
56 files changed, 1372 insertions, 656 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/Base64.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/Base64.java
index 119c96e02e..48d1c50c7d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/Base64.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/Base64.java
@@ -96,6 +96,7 @@ public class Base64 {
* @param destOffset
* the index where output will be put
*/
+ @SuppressWarnings("UnnecessaryParentheses")
private static void encode3to4(byte[] source, int srcOffset,
int numSigBytes, byte[] destination, int destOffset) {
// We have to shift left 24 in order to flush out the 1's that appear
@@ -201,6 +202,7 @@ public class Base64 {
* the index where output will be put
* @return the number of decoded bytes converted
*/
+ @SuppressWarnings("UnnecessaryParentheses")
private static int decode4to3(byte[] source, int srcOffset,
byte[] destination, int destOffset) {
// Example: Dk==
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/BlockList.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/BlockList.java
index 527c5a69df..557e2cde3b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/BlockList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/BlockList.java
@@ -75,13 +75,11 @@ public class BlockList<T> extends AbstractList<T> {
tailBlock = directory[0];
}
- /** {@inheritDoc} */
@Override
public int size() {
return size;
}
- /** {@inheritDoc} */
@Override
public void clear() {
for (T[] block : directory) {
@@ -94,7 +92,6 @@ public class BlockList<T> extends AbstractList<T> {
tailBlock = directory[0];
}
- /** {@inheritDoc} */
@Override
public T get(int index) {
if (index < 0 || size <= index)
@@ -102,7 +99,6 @@ public class BlockList<T> extends AbstractList<T> {
return directory[toDirectoryIndex(index)][toBlockIndex(index)];
}
- /** {@inheritDoc} */
@Override
public T set(int index, T element) {
if (index < 0 || size <= index)
@@ -160,7 +156,6 @@ public class BlockList<T> extends AbstractList<T> {
}
}
- /** {@inheritDoc} */
@Override
public boolean add(T element) {
int i = tailBlkIdx;
@@ -191,7 +186,6 @@ public class BlockList<T> extends AbstractList<T> {
return true;
}
- /** {@inheritDoc} */
@Override
public void add(int index, T element) {
if (index == size) {
@@ -213,7 +207,6 @@ public class BlockList<T> extends AbstractList<T> {
}
}
- /** {@inheritDoc} */
@Override
public T remove(int index) {
if (index == size - 1) {
@@ -253,7 +246,6 @@ public class BlockList<T> extends AbstractList<T> {
tailBlock = directory[tailDirIdx];
}
- /** {@inheritDoc} */
@Override
public Iterator<T> iterator() {
return new MyIterator();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/CachedAuthenticator.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/CachedAuthenticator.java
index 5815c62e89..d8183eb8be 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/CachedAuthenticator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/CachedAuthenticator.java
@@ -32,7 +32,6 @@ public abstract class CachedAuthenticator extends Authenticator {
cached.add(ca);
}
- /** {@inheritDoc} */
@Override
protected final PasswordAuthentication getPasswordAuthentication() {
final String host = getRequestingHost();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
index 12af374b2e..c8421d6012 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
@@ -86,8 +86,8 @@ public class ChangeIdUtil {
}
}
- private static final Pattern issuePattern = Pattern
- .compile("^(Bug|Issue)[a-zA-Z0-9-]*:.*$"); //$NON-NLS-1$
+ private static final Pattern signedOffByPattern = Pattern
+ .compile("^Signed-off-by:.*$"); //$NON-NLS-1$
private static final Pattern footerPattern = Pattern
.compile("(^[a-zA-Z0-9-]+:(?!//).*$)"); //$NON-NLS-1$
@@ -159,7 +159,7 @@ public class ChangeIdUtil {
int footerFirstLine = indexOfFirstFooterLine(lines);
int insertAfter = footerFirstLine;
for (int i = footerFirstLine; i < lines.length; ++i) {
- if (issuePattern.matcher(lines[i]).matches()) {
+ if (!signedOffByPattern.matcher(lines[i]).matches()) {
insertAfter = i + 1;
continue;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/Equality.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/Equality.java
index da1684630b..ff136f7b3b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/Equality.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/Equality.java
@@ -13,22 +13,24 @@ package org.eclipse.jgit.util;
/**
* Equality utilities.
*
- * @since: 6.2
+ * @since 6.2
*/
public class Equality {
/**
- * Compare by reference
- *
- * @param a
- * First object to compare
- * @param b
- * Second object to compare
- * @return {@code true} if the objects are identical, {@code false}
- * otherwise
- *
- * @since 6.2
- */
+ * Compare by reference
+ *
+ * @param <T>
+ * type of the objects to compare
+ * @param a
+ * First object to compare
+ * @param b
+ * Second object to compare
+ * @return {@code true} if the objects are identical, {@code false}
+ * otherwise
+ *
+ * @since 6.2
+ */
@SuppressWarnings("ReferenceEquality")
public static <T> boolean isSameInstance(T a, T b) {
return a == b;
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 aef9e64e02..6a40fad1db 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -30,9 +30,6 @@ import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
-import java.security.AccessControlException;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
import java.text.MessageFormat;
import java.time.Duration;
import java.time.Instant;
@@ -69,6 +66,7 @@ import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.LockFailedException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.file.FileSnapshot;
+import org.eclipse.jgit.internal.util.ShutdownHook;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
@@ -98,6 +96,9 @@ public abstract class FS {
private static final Pattern VERSION = Pattern
.compile("\\s(\\d+)\\.(\\d+)\\.(\\d+)"); //$NON-NLS-1$
+ private static final Pattern EMPTY_PATH = Pattern
+ .compile("^[\\p{javaWhitespace}" + File.pathSeparator + "]*$"); //$NON-NLS-1$ //$NON-NLS-2$
+
private volatile Boolean supportSymlinks;
/**
@@ -118,6 +119,7 @@ public abstract class FS {
* Detect the file system
*
* @param cygwinUsed
+ * whether cygwin is used
* @return FS instance
*/
public FS detect(Boolean cygwinUsed) {
@@ -149,8 +151,11 @@ public abstract class FS {
/**
* @param stdout
+ * stdout stream
* @param stderr
+ * stderr stream
* @param rc
+ * return code
*/
public ExecutionResult(TemporaryBuffer stdout, TemporaryBuffer stderr,
int rc) {
@@ -160,6 +165,8 @@ public abstract class FS {
}
/**
+ * Get buffered standard output stream
+ *
* @return buffered standard output stream
*/
public TemporaryBuffer getStdout() {
@@ -167,6 +174,8 @@ public abstract class FS {
}
/**
+ * Get buffered standard error stream
+ *
* @return buffered standard error stream
*/
public TemporaryBuffer getStderr() {
@@ -174,6 +183,8 @@ public abstract class FS {
}
/**
+ * Get the return code of the process
+ *
* @return the return code of the process
*/
public int getRc() {
@@ -202,7 +213,7 @@ public abstract class FS {
* </p>
*/
public static final Duration FALLBACK_TIMESTAMP_RESOLUTION = Duration
- .ofMillis(2000);
+ .ofSeconds(2);
/**
* Fallback FileStore attributes used when we can't measure the
@@ -250,31 +261,6 @@ public abstract class FS {
private static final AtomicInteger threadNumber = new AtomicInteger(1);
/**
- * Don't use the default thread factory of the ForkJoinPool for the
- * CompletableFuture; it runs without any privileges, which causes
- * trouble if a SecurityManager is present.
- * <p>
- * Instead use normal daemon threads. They'll belong to the
- * SecurityManager's thread group, or use the one of the calling thread,
- * as appropriate.
- * </p>
- *
- * @see java.util.concurrent.Executors#newCachedThreadPool()
- */
- private static final ExecutorService FUTURE_RUNNER = new ThreadPoolExecutor(
- 0, 5, 30L, TimeUnit.SECONDS,
- new LinkedBlockingQueue<Runnable>(),
- runnable -> {
- Thread t = new Thread(runnable,
- "JGit-FileStoreAttributeReader-" //$NON-NLS-1$
- + threadNumber.getAndIncrement());
- // Make sure these threads don't prevent application/JVM
- // shutdown.
- t.setDaemon(true);
- return t;
- });
-
- /**
* Use a separate executor with at most one thread to synchronize
* writing to the config. We write asynchronously since the config
* itself might be on a different file system, which might otherwise
@@ -287,7 +273,7 @@ public abstract class FS {
*/
private static final ExecutorService SAVE_RUNNER = new ThreadPoolExecutor(
0, 1, 1L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue<Runnable>(),
+ new LinkedBlockingQueue<>(),
runnable -> {
Thread t = new Thread(runnable,
"JGit-FileStoreAttributeWriter-" //$NON-NLS-1$
@@ -299,18 +285,16 @@ public abstract class FS {
static {
// Shut down the SAVE_RUNNER on System.exit()
+ ShutdownHook.INSTANCE
+ .register(FileStoreAttributes::shutdownSafeRunner);
+ }
+
+ private static void shutdownSafeRunner() {
try {
- Runtime.getRuntime().addShutdownHook(new Thread(() -> {
- try {
- SAVE_RUNNER.shutdownNow();
- SAVE_RUNNER.awaitTermination(100,
- TimeUnit.MILLISECONDS);
- } catch (Exception e) {
- // Ignore; we're shutting down
- }
- }));
- } catch (IllegalStateException e) {
- // ignore - may fail if shutdown is already in progress
+ SAVE_RUNNER.shutdownNow();
+ SAVE_RUNNER.awaitTermination(100, TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ // Ignore; we're shutting down
}
}
@@ -379,6 +363,7 @@ public abstract class FS {
private static FileStoreAttributes getFileStoreAttributes(Path dir) {
FileStore s;
+ CompletableFuture<Optional<FileStoreAttributes>> f = null;
try {
if (Files.exists(dir)) {
s = Files.getFileStore(dir);
@@ -401,7 +386,7 @@ public abstract class FS {
return FALLBACK_FILESTORE_ATTRIBUTES;
}
- CompletableFuture<Optional<FileStoreAttributes>> f = CompletableFuture
+ f = CompletableFuture
.supplyAsync(() -> {
Lock lock = locks.computeIfAbsent(s,
l -> new ReentrantLock());
@@ -453,7 +438,7 @@ public abstract class FS {
locks.remove(s);
}
return attributes;
- }, FUTURE_RUNNER);
+ });
f = f.exceptionally(e -> {
LOG.error(e.getLocalizedMessage(), e);
return Optional.empty();
@@ -471,10 +456,13 @@ public abstract class FS {
}
// fall through and return fallback
} catch (IOException | ExecutionException | CancellationException e) {
+ cancel(f);
LOG.error(e.getMessage(), e);
} catch (TimeoutException | SecurityException e) {
+ cancel(f);
// use fallback
} catch (InterruptedException e) {
+ cancel(f);
LOG.error(e.getMessage(), e);
Thread.currentThread().interrupt();
}
@@ -483,6 +471,13 @@ public abstract class FS {
return FALLBACK_FILESTORE_ATTRIBUTES;
}
+ private static void cancel(
+ CompletableFuture<Optional<FileStoreAttributes>> f) {
+ if (f != null) {
+ f.cancel(true);
+ }
+ }
+
@SuppressWarnings("boxing")
private static Duration measureMinimalRacyInterval(Path dir) {
LOG.debug("{}: start measure minimal racy interval in {}", //$NON-NLS-1$
@@ -828,6 +823,8 @@ public abstract class FS {
private Duration minimalRacyInterval;
/**
+ * Get the minimal racy interval
+ *
* @return the measured minimal interval after a file has been modified
* in which we cannot rely on lastModified to detect
* modifications
@@ -837,6 +834,8 @@ public abstract class FS {
}
/**
+ * Get the measured filesystem timestamp resolution
+ *
* @return the measured filesystem timestamp resolution
*/
@NonNull
@@ -849,6 +848,7 @@ public abstract class FS {
* timestamp resolution
*
* @param fsTimestampResolution
+ * resolution of filesystem timestamps
*/
public FileStoreAttributes(
@NonNull Duration fsTimestampResolution) {
@@ -883,21 +883,6 @@ public abstract class FS {
}
/**
- * Whether FileStore attributes should be determined asynchronously
- *
- * @param asynch
- * whether FileStore attributes should be determined
- * asynchronously. If false access to cached attributes may block
- * for some seconds for the first call per FileStore
- * @since 5.1.9
- * @deprecated Use {@link FileStoreAttributes#setBackground} instead
- */
- @Deprecated
- public static void setAsyncFileStoreAttributes(boolean asynch) {
- FileStoreAttributes.setBackground(asynch);
- }
-
- /**
* Auto-detect the appropriate file system abstraction, taking into account
* the presence of a Cygwin installation on the system. Using jgit in
* combination with Cygwin requires a more elaborate (and possibly slower)
@@ -1009,7 +994,7 @@ public abstract class FS {
File tempFile = null;
try {
tempFile = File.createTempFile("tempsymlinktarget", ""); //$NON-NLS-1$ //$NON-NLS-2$
- File linkName = new File(tempFile.getParentFile(), "tempsymlink"); //$NON-NLS-1$
+ File linkName = new File(tempFile.getPath() + "-tempsymlink"); //$NON-NLS-1$
createSymLink(linkName, tempFile.getPath());
supportSymlinks = Boolean.TRUE;
linkName.delete();
@@ -1070,23 +1055,6 @@ public abstract class FS {
* symbolic links, the modification time of the link is returned, rather
* than that of the link target.
*
- * @param f
- * a {@link java.io.File} object.
- * @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
@@ -1115,29 +1083,12 @@ public abstract class FS {
* <p>
* For symlinks it sets the modified time of the link target.
*
- * @param f
- * a {@link java.io.File} object.
- * @param time
- * 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.
- * <p>
- * For symlinks it sets the modified time of the link target.
- *
* @param p
* a {@link Path} object.
* @param time
* last modified time
* @throws java.io.IOException
+ * if an IO error occurred
* @since 5.1.9
*/
public void setLastModified(Path p, Instant time) throws IOException {
@@ -1152,6 +1103,7 @@ public abstract class FS {
* a {@link java.io.File} object.
* @return length of a file
* @throws java.io.IOException
+ * if an IO error occurred
* @since 3.0
*/
public long length(File path) throws IOException {
@@ -1164,7 +1116,7 @@ public abstract class FS {
* @param f
* a {@link java.io.File} object.
* @throws java.io.IOException
- * this may be a Java7 subclass with detailed information
+ * if an IO error occurred
* @since 3.3
*/
public void delete(File f) throws IOException {
@@ -1264,8 +1216,10 @@ public abstract class FS {
* Return all the attributes of a file, without following symbolic links.
*
* @param file
+ * the file
* @return {@link BasicFileAttributes} of the file
- * @throws IOException in case of any I/O errors accessing the file
+ * @throws IOException
+ * in case of any I/O errors accessing the file
*
* @since 4.5.6
*/
@@ -1283,11 +1237,10 @@ public abstract class FS {
}
private File defaultUserHomeImpl() {
- String home = AccessController.doPrivileged(
- (PrivilegedAction<String>) () -> System.getProperty("user.home") //$NON-NLS-1$
- );
- if (home == null || home.length() == 0)
+ String home = SystemReader.getInstance().getProperty("user.home"); //$NON-NLS-1$
+ if (StringUtils.isEmptyOrNull(home)) {
return null;
+ }
return new File(home).getAbsoluteFile();
}
@@ -1303,8 +1256,10 @@ public abstract class FS {
* @return the first match found, or null
* @since 3.0
*/
+ @SuppressWarnings("StringSplitter")
protected static File searchPath(String path, String... lookFor) {
- if (path == null) {
+ if (StringUtils.isEmptyOrNull(path)
+ || EMPTY_PATH.matcher(path).find()) {
return null;
}
@@ -1421,13 +1376,6 @@ public abstract class FS {
}
} catch (IOException e) {
LOG.error("Caught exception in FS.readPipe()", e); //$NON-NLS-1$
- } catch (AccessControlException e) {
- LOG.warn(MessageFormat.format(
- JGitText.get().readPipeIsNotAllowedRequiredPermission,
- command, dir, e.getPermission()));
- } catch (SecurityException e) {
- LOG.warn(MessageFormat.format(JGitText.get().readPipeIsNotAllowed,
- command, dir));
}
if (debug) {
LOG.debug("readpipe returns null"); //$NON-NLS-1$
@@ -1671,6 +1619,7 @@ public abstract class FS {
* a {@link java.io.File} object.
* @return target of link or null
* @throws java.io.IOException
+ * if an IO error occurred
* @since 3.0
*/
public String readSymLink(File path) throws IOException {
@@ -1684,6 +1633,7 @@ public abstract class FS {
* a {@link java.io.File} object.
* @return true if the path is a symbolic link (and we support these)
* @throws java.io.IOException
+ * if an IO error occurred
* @since 3.0
*/
public boolean isSymLink(File path) throws IOException {
@@ -1738,6 +1688,7 @@ public abstract class FS {
* @return true if path is hidden, either starts with . on unix or has the
* hidden attribute in windows
* @throws java.io.IOException
+ * if an IO error occurred
* @since 3.0
*/
public boolean isHidden(File path) throws IOException {
@@ -1752,6 +1703,7 @@ public abstract class FS {
* @param hidden
* whether to set the file hidden
* @throws java.io.IOException
+ * if an IO error occurred
* @since 3.0
*/
public void setHidden(File path, boolean hidden) throws IOException {
@@ -1766,6 +1718,7 @@ public abstract class FS {
* @param target
* target path of the symlink
* @throws java.io.IOException
+ * if an IO error occurred
* @since 3.0
*/
public void createSymLink(File path, String target) throws IOException {
@@ -1773,24 +1726,6 @@ public abstract class FS {
}
/**
- * Create a new file. See {@link java.io.File#createNewFile()}. Subclasses
- * of this class may take care to provide a safe implementation for this
- * even if {@link #supportsAtomicCreateNewFile()} is <code>false</code>
- *
- * @param path
- * the file to be created
- * @return <code>true</code> if the file was created, <code>false</code> if
- * the file already existed
- * @throws java.io.IOException
- * @deprecated use {@link #createNewFileAtomic(File)} instead
- * @since 4.5
- */
- @Deprecated
- public boolean createNewFile(File path) throws IOException {
- return path.createNewFile();
- }
-
- /**
* A token representing a file created by
* {@link #createNewFileAtomic(File)}. The token must be retained until the
* file has been deleted in order to guarantee that the unique file was
@@ -1810,6 +1745,8 @@ public abstract class FS {
}
/**
+ * Whether the file was created successfully
+ *
* @return {@code true} if the file was created successfully
*/
public boolean isCreated() {
@@ -1852,6 +1789,7 @@ public abstract class FS {
* @return LockToken this token must be closed after the created file was
* deleted
* @throws IOException
+ * if an IO error occurred
* @since 4.7
*/
public LockToken createNewFileAtomic(File path) throws IOException {
@@ -2011,6 +1949,8 @@ public abstract class FS {
environment.put(Constants.GIT_DIR_KEY,
repository.getDirectory().getAbsolutePath());
if (!repository.isBare()) {
+ environment.put(Constants.GIT_COMMON_DIR_KEY,
+ repository.getCommonDirectory().getAbsolutePath());
environment.put(Constants.GIT_WORK_TREE_KEY,
repository.getWorkTree().getAbsolutePath());
}
@@ -2106,7 +2046,7 @@ public abstract class FS {
case "post-receive": //$NON-NLS-1$
case "post-update": //$NON-NLS-1$
case "push-to-checkout": //$NON-NLS-1$
- return repository.getDirectory();
+ return repository.getCommonDirectory();
default:
return repository.getWorkTree();
}
@@ -2119,7 +2059,7 @@ public abstract class FS {
if (hooksDir != null) {
return new File(hooksDir);
}
- File dir = repository.getDirectory();
+ File dir = repository.getCommonDirectory();
return dir == null ? null : new File(dir, Constants.HOOKS);
}
@@ -2317,7 +2257,9 @@ public abstract class FS {
* The standard input stream passed to the process
* @return The result of the executed command
* @throws java.lang.InterruptedException
+ * if thread was interrupted
* @throws java.io.IOException
+ * if an IO error occurred
* @since 4.2
*/
public ExecutionResult execute(ProcessBuilder pb, InputStream in)
@@ -2346,6 +2288,8 @@ public abstract class FS {
public static class Attributes {
/**
+ * Whether this are attributes of a directory
+ *
* @return true if this are the attributes of a directory
*/
public boolean isDirectory() {
@@ -2353,6 +2297,8 @@ public abstract class FS {
}
/**
+ * Whether this are attributes of an executable file
+ *
* @return true if this are the attributes of an executable file
*/
public boolean isExecutable() {
@@ -2360,6 +2306,8 @@ public abstract class FS {
}
/**
+ * Whether this are the attributes of a symbolic link
+ *
* @return true if this are the attributes of a symbolic link
*/
public boolean isSymbolicLink() {
@@ -2367,6 +2315,8 @@ public abstract class FS {
}
/**
+ * Whether this are the attributes of a regular file
+ *
* @return true if this are the attributes of a regular file
*/
public boolean isRegularFile() {
@@ -2374,6 +2324,8 @@ public abstract class FS {
}
/**
+ * Get the file creation time
+ *
* @return the time when the file was created
*/
public long getCreationTime() {
@@ -2381,16 +2333,8 @@ 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 lastModifiedInstant.toEpochMilli();
- }
-
- /**
+ * Get the time when this object was last modified
+ *
* @return the time when this object was last modified
* @since 5.1.9
*/
@@ -2441,14 +2385,18 @@ public abstract class FS {
* Constructor when there are issues with reading. All attributes except
* given will be set to the default values.
*
- * @param fs
* @param path
+ * file path
+ * @param fs
+ * FS to use
*/
public Attributes(File path, FS fs) {
this(fs, path, false, false, false, false, false, 0L, EPOCH, 0L);
}
/**
+ * Get the length of this file
+ *
* @return length of this file object
*/
public long getLength() {
@@ -2458,6 +2406,8 @@ public abstract class FS {
}
/**
+ * Get the filename
+ *
* @return the filename
*/
public String getName() {
@@ -2465,6 +2415,8 @@ public abstract class FS {
}
/**
+ * Get the file the attributes apply to
+ *
* @return the file the attributes apply to
*/
public File getFile() {
@@ -2522,6 +2474,33 @@ public abstract class FS {
}
/**
+ * Get common dir path.
+ *
+ * @param dir
+ * the .git folder
+ * @return common dir path
+ * @throws IOException
+ * if commondir file can't be read
+ *
+ * @since 7.0
+ */
+ public File getCommonDir(File dir) throws IOException {
+ // first the GIT_COMMON_DIR is same as GIT_DIR
+ File commonDir = dir;
+ // now check if commondir file exists (e.g. worktree repository)
+ File commonDirFile = new File(dir, Constants.COMMONDIR_FILE);
+ if (commonDirFile.isFile()) {
+ String commonDirPath = new String(IO.readFully(commonDirFile))
+ .trim();
+ commonDir = new File(commonDirPath);
+ if (!commonDir.isAbsolute()) {
+ commonDir = new File(dir, commonDirPath).getCanonicalFile();
+ }
+ }
+ return commonDir;
+ }
+
+ /**
* This runnable will consume an input stream's content into an output
* stream as soon as it gets available.
* <p>
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java
index 1c113617f8..db2b5b4f71 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010, Robin Rosenberg and others
+ * Copyright (C) 2010, 2024, Robin Rosenberg and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -203,7 +203,16 @@ public class FS_POSIX extends FS {
/** {@inheritDoc} */
@Override
public boolean canExecute(File f) {
- return FileUtils.canExecute(f);
+ if (!isFile(f)) {
+ return false;
+ }
+ try {
+ Path path = FileUtils.toPath(f);
+ Set<PosixFilePermission> pset = Files.getPosixFilePermissions(path);
+ return pset.contains(PosixFilePermission.OWNER_EXECUTE);
+ } catch (IOException ex) {
+ return false;
+ }
}
/** {@inheritDoc} */
@@ -250,8 +259,12 @@ public class FS_POSIX extends FS {
/** {@inheritDoc} */
@Override
public ProcessBuilder runInShell(String cmd, String[] args) {
- List<String> argv = new ArrayList<>(4 + args.length);
+ List<String> argv = new ArrayList<>(5 + args.length);
argv.add("sh"); //$NON-NLS-1$
+ if (SystemReader.getInstance().isMacOS()) {
+ // Use a login shell to get the full normal $PATH
+ argv.add("-l"); //$NON-NLS-1$
+ }
argv.add("-c"); //$NON-NLS-1$
argv.add(cmd + " \"$@\""); //$NON-NLS-1$
argv.add(cmd);
@@ -328,73 +341,6 @@ public class FS_POSIX extends FS {
return supportsAtomicFileCreation == AtomicFileCreation.SUPPORTED;
}
- @Override
- @SuppressWarnings("boxing")
- /**
- * {@inheritDoc}
- * <p>
- * An implementation of the File#createNewFile() semantics which works also
- * on NFS. If the config option
- * {@code core.supportsAtomicCreateNewFile = true} (which is the default)
- * then simply File#createNewFile() is called.
- *
- * But if {@code core.supportsAtomicCreateNewFile = false} then after
- * successful creation of the lock file a hard link to that lock file is
- * created and the attribute nlink of the lock file is checked to be 2. If
- * multiple clients manage to create the same lock file nlink would be
- * greater than 2 showing the error.
- *
- * @see "https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html"
- *
- * @deprecated use {@link FS_POSIX#createNewFileAtomic(File)} instead
- * @since 4.5
- */
- @Deprecated
- public boolean createNewFile(File lock) throws IOException {
- if (!lock.createNewFile()) {
- return false;
- }
- if (supportsAtomicCreateNewFile()) {
- return true;
- }
- Path lockPath = lock.toPath();
- Path link = null;
- FileStore store = null;
- try {
- store = Files.getFileStore(lockPath);
- } catch (SecurityException e) {
- return true;
- }
- try {
- Boolean canLink = CAN_HARD_LINK.computeIfAbsent(store,
- s -> Boolean.TRUE);
- if (Boolean.FALSE.equals(canLink)) {
- return true;
- }
- link = Files.createLink(
- Paths.get(lock.getAbsolutePath() + ".lnk"), //$NON-NLS-1$
- lockPath);
- Integer nlink = (Integer) (Files.getAttribute(lockPath,
- "unix:nlink")); //$NON-NLS-1$
- if (nlink > 2) {
- LOG.warn(MessageFormat.format(
- JGitText.get().failedAtomicFileCreation, lockPath,
- nlink));
- return false;
- } else if (nlink < 2) {
- CAN_HARD_LINK.put(store, Boolean.FALSE);
- }
- return true;
- } catch (UnsupportedOperationException | IllegalArgumentException e) {
- CAN_HARD_LINK.put(store, Boolean.FALSE);
- return true;
- } finally {
- if (link != null) {
- Files.delete(link);
- }
- }
- }
-
/**
* {@inheritDoc}
* <p>
@@ -418,6 +364,7 @@ public class FS_POSIX extends FS {
* @return LockToken this lock token must be held until the file is no
* longer needed
* @throws IOException
+ * if an IO error occurred
* @since 5.0
*/
@Override
@@ -446,8 +393,7 @@ public class FS_POSIX extends FS {
return token(true, null);
}
link = Files.createLink(Paths.get(uniqueLinkPath(file)), path);
- Integer nlink = (Integer) (Files.getAttribute(path,
- "unix:nlink")); //$NON-NLS-1$
+ Integer nlink = (Integer) Files.getAttribute(path, "unix:nlink"); //$NON-NLS-1$
if (nlink.intValue() > 2) {
LOG.warn(MessageFormat.format(
JGitText.get().failedAtomicFileCreation, path, nlink));
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 ae73d3feb8..5926655b7b 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
@@ -58,43 +58,36 @@ public class FS_Win32 extends FS {
super(src);
}
- /** {@inheritDoc} */
@Override
public FS newInstance() {
return new FS_Win32(this);
}
- /** {@inheritDoc} */
@Override
public boolean supportsExecute() {
return false;
}
- /** {@inheritDoc} */
@Override
public boolean canExecute(File f) {
return false;
}
- /** {@inheritDoc} */
@Override
public boolean setExecute(File f, boolean canExec) {
return false;
}
- /** {@inheritDoc} */
@Override
public boolean isCaseSensitive() {
return false;
}
- /** {@inheritDoc} */
@Override
public boolean retryFailedLockFileCommit() {
return true;
}
- /** {@inheritDoc} */
@Override
public Entry[] list(File directory, FileModeStrategy fileModeStrategy) {
if (!Files.isDirectory(directory.toPath(), LinkOption.NOFOLLOW_LINKS)) {
@@ -140,7 +133,6 @@ public class FS_Win32 extends FS {
return result.toArray(new Entry[0]);
}
- /** {@inheritDoc} */
@Override
protected File discoverGitExe() {
String path = SystemReader.getInstance().getenv("PATH"); //$NON-NLS-1$
@@ -171,7 +163,6 @@ public class FS_Win32 extends FS {
return gitExe;
}
- /** {@inheritDoc} */
@Override
protected File userHomeImpl() {
String home = SystemReader.getInstance().getenv("HOME"); //$NON-NLS-1$
@@ -194,7 +185,6 @@ public class FS_Win32 extends FS {
return super.userHomeImpl();
}
- /** {@inheritDoc} */
@Override
public ProcessBuilder runInShell(String cmd, String[] args) {
List<String> argv = new ArrayList<>(3 + args.length);
@@ -207,7 +197,6 @@ public class FS_Win32 extends FS {
return proc;
}
- /** {@inheritDoc} */
@Override
public Attributes getAttributes(File path) {
return FileUtils.getFileAttributesBasic(this, path);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java
index add5498175..237879110a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java
@@ -14,8 +14,6 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.File;
import java.io.OutputStream;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -43,10 +41,7 @@ public class FS_Win32_Cygwin extends FS_Win32 {
* @return true if cygwin is found
*/
public static boolean isCygwin() {
- final String path = AccessController
- .doPrivileged((PrivilegedAction<String>) () -> System
- .getProperty("java.library.path") //$NON-NLS-1$
- );
+ final String path = System.getProperty("java.library.path"); //$NON-NLS-1$
if (path == null)
return false;
File found = FS.searchPath(path, "cygpath.exe"); //$NON-NLS-1$
@@ -72,13 +67,11 @@ public class FS_Win32_Cygwin extends FS_Win32 {
super(src);
}
- /** {@inheritDoc} */
@Override
public FS newInstance() {
return new FS_Win32_Cygwin(this);
}
- /** {@inheritDoc} */
@Override
public File resolve(File dir, String pn) {
String useCygPath = System.getProperty("jgit.usecygpath"); //$NON-NLS-1$
@@ -99,18 +92,14 @@ public class FS_Win32_Cygwin extends FS_Win32 {
return super.resolve(dir, pn);
}
- /** {@inheritDoc} */
@Override
protected File userHomeImpl() {
- final String home = AccessController.doPrivileged(
- (PrivilegedAction<String>) () -> System.getenv("HOME") //$NON-NLS-1$
- );
+ final String home = System.getenv("HOME"); //$NON-NLS-1$
if (home == null || home.length() == 0)
return super.userHomeImpl();
return resolve(new File("."), home); //$NON-NLS-1$
}
- /** {@inheritDoc} */
@Override
public ProcessBuilder runInShell(String cmd, String[] args) {
List<String> argv = new ArrayList<>(4 + args.length);
@@ -129,14 +118,12 @@ public class FS_Win32_Cygwin extends FS_Win32 {
return QuotedString.BOURNE.quote(cmd.replace(File.separatorChar, '/'));
}
- /** {@inheritDoc} */
@Override
public String relativize(String base, String other) {
final String relativized = super.relativize(base, other);
return relativized.replace(File.separatorChar, '/');
}
- /** {@inheritDoc} */
@Override
public ProcessResult runHookIfPresent(Repository repository, String hookName,
String[] args, OutputStream outRedirect, OutputStream errRedirect,
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 f013e7e095..39c67f1b86 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
@@ -288,12 +288,14 @@ public class FileUtils {
* @throws java.nio.file.AtomicMoveNotSupportedException
* if file cannot be moved as an atomic file system operation
* @throws java.io.IOException
+ * if an IO error occurred
* @since 4.1
*/
public static void rename(final File src, final File dst,
CopyOption... options)
throws AtomicMoveNotSupportedException, IOException {
int attempts = FS.DETECTED.retryFailedLockFileCommit() ? 10 : 1;
+ IOException finalError = null;
while (--attempts >= 0) {
try {
Files.move(toPath(src), toPath(dst), options);
@@ -301,29 +303,35 @@ public class FileUtils {
} catch (AtomicMoveNotSupportedException e) {
throw e;
} catch (IOException e) {
- try {
- if (!dst.delete()) {
- delete(dst, EMPTY_DIRECTORIES_ONLY | RECURSIVE);
+ if (attempts == 0) {
+ // Only delete on the last attempt.
+ try {
+ if (!dst.delete()) {
+ delete(dst, EMPTY_DIRECTORIES_ONLY | RECURSIVE);
+ }
+ // On *nix there is no try, you do or do not
+ Files.move(toPath(src), toPath(dst), options);
+ return;
+ } catch (IOException e2) {
+ e2.addSuppressed(e);
+ finalError = e2;
}
- // On *nix there is no try, you do or do not
- Files.move(toPath(src), toPath(dst), options);
- return;
- } catch (IOException e2) {
- // ignore and continue retry
}
}
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- throw new IOException(
- MessageFormat.format(JGitText.get().renameFileFailed,
- src.getAbsolutePath(), dst.getAbsolutePath()),
- e);
+ if (attempts > 0) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ throw new IOException(MessageFormat.format(
+ JGitText.get().renameFileFailed,
+ src.getAbsolutePath(), dst.getAbsolutePath()), e);
+ }
}
}
throw new IOException(
MessageFormat.format(JGitText.get().renameFileFailed,
- src.getAbsolutePath(), dst.getAbsolutePath()));
+ src.getAbsolutePath(), dst.getAbsolutePath()),
+ finalError);
}
/**
@@ -446,6 +454,7 @@ public class FileUtils {
* the target of the symbolic link
* @return the path to the symbolic link
* @throws java.io.IOException
+ * if an IO error occurred
* @since 4.2
*/
public static Path createSymLink(File path, String target)
@@ -474,6 +483,7 @@ public class FileUtils {
* a {@link java.io.File} object.
* @return target path of the symlink, or null if it is not a symbolic link
* @throws java.io.IOException
+ * if an IO error occurred
* @since 3.0
*/
public static String readSymLink(File path) throws IOException {
@@ -499,6 +509,7 @@ public class FileUtils {
* The parent dir, can be null to use system default temp dir.
* @return the temp dir created.
* @throws java.io.IOException
+ * if an IO error occurred
* @since 3.4
*/
public static File createTempDir(String prefix, String suffix, File dir)
@@ -620,11 +631,11 @@ public class FileUtils {
}
/**
- * Determine if an IOException is a Stale NFS File Handle
+ * Determine if an IOException is a stale NFS file handle
*
* @param ioe
* an {@link java.io.IOException} object.
- * @return a boolean true if the IOException is a Stale NFS FIle Handle
+ * @return a boolean true if the IOException is a stale NFS file handle
* @since 4.1
*/
public static boolean isStaleFileHandle(IOException ioe) {
@@ -635,13 +646,13 @@ public class FileUtils {
}
/**
- * Determine if a throwable or a cause in its causal chain is a Stale NFS
- * File Handle
+ * Determine if a throwable or a cause in its causal chain is a stale NFS
+ * file handle
*
* @param throwable
* a {@link java.lang.Throwable} object.
* @return a boolean true if the throwable or a cause in its causal chain is
- * a Stale NFS File Handle
+ * a stale NFS file handle
* @since 4.7
*/
public static boolean isStaleFileHandleInCausalChain(Throwable throwable) {
@@ -749,7 +760,10 @@ public class FileUtils {
}
/**
+ * Check if file is a symlink
+ *
* @param file
+ * the file to be checked if it is a symbolic link
* @return {@code true} if the passed file is a symbolic link
*/
static boolean isSymlink(File file) {
@@ -757,21 +771,10 @@ public class FileUtils {
}
/**
- * @param file
- * @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();
- }
-
- /**
+ * Get last modified timestamp of a file
+ *
* @param path
+ * file path
* @return lastModified attribute for given file, not following symbolic
* links
*/
@@ -795,8 +798,10 @@ public class FileUtils {
* Return all the attributes of a file, without following symbolic links.
*
* @param file
+ * the file
* @return {@link BasicFileAttributes} of the file
- * @throws IOException in case of any I/O errors accessing the file
+ * @throws IOException
+ * in case of any I/O errors accessing the file
*
* @since 4.5.6
*/
@@ -807,21 +812,12 @@ public class FileUtils {
/**
* Set the last modified time of a file system object.
*
- * @param file
- * @param time
- * @throws IOException
- */
- @Deprecated
- static void setLastModified(File file, long time) throws IOException {
- Files.setLastModifiedTime(toPath(file), FileTime.fromMillis(time));
- }
-
- /**
- * Set the last modified time of a file system object.
- *
* @param path
+ * file path
* @param time
+ * last modified timestamp of the file
* @throws IOException
+ * if an IO error occurred
*/
static void setLastModified(Path path, Instant time)
throws IOException {
@@ -829,7 +825,10 @@ public class FileUtils {
}
/**
+ * Whether the file exists
+ *
* @param file
+ * the file
* @return {@code true} if the given file exists, not following symbolic
* links
*/
@@ -838,9 +837,13 @@ public class FileUtils {
}
/**
+ * Check if file is hidden (on Windows)
+ *
* @param file
+ * the file
* @return {@code true} if the given file is hidden
* @throws IOException
+ * if an IO error occurred
*/
static boolean isHidden(File file) throws IOException {
return Files.isHidden(toPath(file));
@@ -854,6 +857,7 @@ public class FileUtils {
* @param hidden
* a boolean.
* @throws java.io.IOException
+ * if an IO error occurred
* @since 4.1
*/
public static void setHidden(File file, boolean hidden) throws IOException {
@@ -868,6 +872,7 @@ public class FileUtils {
* a {@link java.io.File}.
* @return length of the given file
* @throws java.io.IOException
+ * if an IO error occurred
* @since 4.1
*/
public static long getLength(File file) throws IOException {
@@ -879,7 +884,10 @@ public class FileUtils {
}
/**
+ * Check if file is directory
+ *
* @param file
+ * the file
* @return {@code true} if the given file is a directory, not following
* symbolic links
*/
@@ -888,7 +896,10 @@ public class FileUtils {
}
/**
+ * Check if File is a file
+ *
* @param file
+ * the file
* @return {@code true} if the given file is a file, not following symbolic
* links
*/
@@ -929,8 +940,12 @@ public class FileUtils {
}
/**
+ * Get basic file attributes
+ *
* @param fs
+ * a {@link org.eclipse.jgit.util.FS} object.
* @param file
+ * the file
* @return non null attributes object
*/
static Attributes getFileAttributesBasic(FS fs, File file) {
@@ -1079,6 +1094,7 @@ public class FileUtils {
* @param f
* the file to touch
* @throws IOException
+ * if an IO error occurred
* @since 5.1.8
*/
public static void touch(Path f) throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/GSSManagerFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/GSSManagerFactory.java
index be56e5ecf5..ba0df932ce 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/GSSManagerFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/GSSManagerFactory.java
@@ -28,7 +28,7 @@ public abstract class GSSManagerFactory {
* @return detected GSSManager factory
*/
public static GSSManagerFactory detect() {
- return (SunGSSManagerFactory.isSupported()) ? new SunGSSManagerFactory()
+ return SunGSSManagerFactory.isSupported() ? new SunGSSManagerFactory()
: new DefaultGSSManagerFactory();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateFormatter.java
index e6bf497ac4..332e65985e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateFormatter.java
@@ -10,10 +10,10 @@
package org.eclipse.jgit.util;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.time.format.FormatStyle;
import java.util.Locale;
-import java.util.TimeZone;
import org.eclipse.jgit.lib.PersonIdent;
@@ -26,9 +26,9 @@ import org.eclipse.jgit.lib.PersonIdent;
*/
public class GitDateFormatter {
- private DateFormat dateTimeInstance;
+ private DateTimeFormatter dateTimeFormat;
- private DateFormat dateTimeInstance2;
+ private DateTimeFormatter dateTimeFormat2;
private final Format format;
@@ -96,30 +96,34 @@ public class GitDateFormatter {
default:
break;
case DEFAULT: // Not default:
- dateTimeInstance = new SimpleDateFormat(
+ dateTimeFormat = DateTimeFormatter.ofPattern(
"EEE MMM dd HH:mm:ss yyyy Z", Locale.US); //$NON-NLS-1$
break;
case ISO:
- dateTimeInstance = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", //$NON-NLS-1$
+ dateTimeFormat = DateTimeFormatter.ofPattern(
+ "yyyy-MM-dd HH:mm:ss Z", //$NON-NLS-1$
Locale.US);
break;
case LOCAL:
- dateTimeInstance = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy", //$NON-NLS-1$
+ dateTimeFormat = DateTimeFormatter.ofPattern(
+ "EEE MMM dd HH:mm:ss yyyy", //$NON-NLS-1$
Locale.US);
break;
case RFC:
- dateTimeInstance = new SimpleDateFormat(
+ dateTimeFormat = DateTimeFormatter.ofPattern(
"EEE, dd MMM yyyy HH:mm:ss Z", Locale.US); //$NON-NLS-1$
break;
case SHORT:
- dateTimeInstance = new SimpleDateFormat("yyyy-MM-dd", Locale.US); //$NON-NLS-1$
+ dateTimeFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd", //$NON-NLS-1$
+ Locale.US);
break;
case LOCALE:
case LOCALELOCAL:
- SystemReader systemReader = SystemReader.getInstance();
- dateTimeInstance = systemReader.getDateTimeInstance(
- DateFormat.DEFAULT, DateFormat.DEFAULT);
- dateTimeInstance2 = systemReader.getSimpleDateFormat("Z"); //$NON-NLS-1$
+ dateTimeFormat = DateTimeFormatter
+ .ofLocalizedDateTime(FormatStyle.MEDIUM)
+ .withLocale(Locale.US);
+ dateTimeFormat2 = DateTimeFormatter.ofPattern("Z", //$NON-NLS-1$
+ Locale.US);
break;
}
}
@@ -135,39 +139,45 @@ public class GitDateFormatter {
@SuppressWarnings("boxing")
public String formatDate(PersonIdent ident) {
switch (format) {
- case RAW:
- int offset = ident.getTimeZoneOffset();
+ case RAW: {
+ int offset = ident.getZoneOffset().getTotalSeconds();
String sign = offset < 0 ? "-" : "+"; //$NON-NLS-1$ //$NON-NLS-2$
int offset2;
- if (offset < 0)
+ if (offset < 0) {
offset2 = -offset;
- else
+ } else {
offset2 = offset;
- int hours = offset2 / 60;
- int minutes = offset2 % 60;
+ }
+ int minutes = (offset2 / 60) % 60;
+ int hours = offset2 / 60 / 60;
return String.format("%d %s%02d%02d", //$NON-NLS-1$
- ident.getWhen().getTime() / 1000, sign, hours, minutes);
+ ident.getWhenAsInstant().getEpochSecond(), sign, hours,
+ minutes);
+ }
case RELATIVE:
- return RelativeDateFormatter.format(ident.getWhen());
+ return RelativeDateFormatter.format(ident.getWhenAsInstant());
case LOCALELOCAL:
case LOCAL:
- dateTimeInstance.setTimeZone(SystemReader.getInstance()
- .getTimeZone());
- return dateTimeInstance.format(ident.getWhen());
- case LOCALE:
- TimeZone tz = ident.getTimeZone();
- if (tz == null)
- tz = SystemReader.getInstance().getTimeZone();
- dateTimeInstance.setTimeZone(tz);
- dateTimeInstance2.setTimeZone(tz);
- return dateTimeInstance.format(ident.getWhen()) + " " //$NON-NLS-1$
- + dateTimeInstance2.format(ident.getWhen());
- default:
- tz = ident.getTimeZone();
- if (tz == null)
- tz = SystemReader.getInstance().getTimeZone();
- dateTimeInstance.setTimeZone(ident.getTimeZone());
- return dateTimeInstance.format(ident.getWhen());
+ return dateTimeFormat
+ .withZone(SystemReader.getInstance().getTimeZoneId())
+ .format(ident.getWhenAsInstant());
+ case LOCALE: {
+ ZoneId tz = ident.getZoneId();
+ if (tz == null) {
+ tz = SystemReader.getInstance().getTimeZoneId();
+ }
+ return dateTimeFormat.withZone(tz).format(ident.getWhenAsInstant())
+ + " " //$NON-NLS-1$
+ + dateTimeFormat2.withZone(tz)
+ .format(ident.getWhenAsInstant());
+ }
+ default: {
+ ZoneId tz = ident.getZoneId();
+ if (tz == null) {
+ tz = SystemReader.getInstance().getTimeZoneId();
+ }
+ return dateTimeFormat.withZone(tz).format(ident.getWhenAsInstant());
+ }
}
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateParser.java
index 6a4b39652a..f080056546 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateParser.java
@@ -28,7 +28,10 @@ import org.eclipse.jgit.internal.JGitText;
* used. One example is the parsing of the config parameter gc.pruneexpire. The
* parser can handle only subset of what native gits approxidate parser
* understands.
+ *
+ * @deprecated Use {@link GitTimeParser} instead.
*/
+@Deprecated(since = "7.1")
public class GitDateParser {
/**
* The Date representing never. Though this is a concrete value, most
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/GitTimeParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitTimeParser.java
new file mode 100644
index 0000000000..acaa1ce563
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitTimeParser.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2024 Christian Halstrick and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.util;
+
+import java.text.MessageFormat;
+import java.text.ParseException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.util.EnumMap;
+import java.util.Map;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.internal.JGitText;
+
+/**
+ * Parses strings with time and date specifications into
+ * {@link java.time.Instant}.
+ *
+ * When git needs to parse strings specified by the user this parser can be
+ * used. One example is the parsing of the config parameter gc.pruneexpire. The
+ * parser can handle only subset of what native gits approxidate parser
+ * understands.
+ *
+ * @since 7.1
+ */
+public class GitTimeParser {
+
+ private static final Map<ParseableSimpleDateFormat, DateTimeFormatter> formatCache = new EnumMap<>(
+ ParseableSimpleDateFormat.class);
+
+ // An enum of all those formats which this parser can parse with the help of
+ // a DateTimeFormatter. There are other formats (e.g. the relative formats
+ // like "yesterday" or "1 week ago") which this parser can parse but which
+ // are not listed here because they are parsed without the help of a
+ // DateTimeFormatter.
+ enum ParseableSimpleDateFormat {
+ ISO("yyyy-MM-dd HH:mm:ss Z"), // //$NON-NLS-1$
+ RFC("EEE, dd MMM yyyy HH:mm:ss Z"), // //$NON-NLS-1$
+ SHORT("yyyy-MM-dd"), // //$NON-NLS-1$
+ SHORT_WITH_DOTS_REVERSE("dd.MM.yyyy"), // //$NON-NLS-1$
+ SHORT_WITH_DOTS("yyyy.MM.dd"), // //$NON-NLS-1$
+ SHORT_WITH_SLASH("MM/dd/yyyy"), // //$NON-NLS-1$
+ DEFAULT("EEE MMM dd HH:mm:ss yyyy Z"), // //$NON-NLS-1$
+ LOCAL("EEE MMM dd HH:mm:ss yyyy"); //$NON-NLS-1$
+
+ private final String formatStr;
+
+ ParseableSimpleDateFormat(String formatStr) {
+ this.formatStr = formatStr;
+ }
+ }
+
+ private GitTimeParser() {
+ // This class is not supposed to be instantiated
+ }
+
+ /**
+ * Parses a string into a {@link java.time.LocalDateTime} using the default
+ * locale. Since this parser also supports relative formats (e.g.
+ * "yesterday") the caller can specify the reference date. These types of
+ * strings can be parsed:
+ * <ul>
+ * <li>"never"</li>
+ * <li>"now"</li>
+ * <li>"yesterday"</li>
+ * <li>"(x) years|months|weeks|days|hours|minutes|seconds ago"<br>
+ * Multiple specs can be combined like in "2 weeks 3 days ago". Instead of '
+ * ' one can use '.' to separate the words</li>
+ * <li>"yyyy-MM-dd HH:mm:ss Z" (ISO)</li>
+ * <li>"EEE, dd MMM yyyy HH:mm:ss Z" (RFC)</li>
+ * <li>"yyyy-MM-dd"</li>
+ * <li>"yyyy.MM.dd"</li>
+ * <li>"MM/dd/yyyy",</li>
+ * <li>"dd.MM.yyyy"</li>
+ * <li>"EEE MMM dd HH:mm:ss yyyy Z" (DEFAULT)</li>
+ * <li>"EEE MMM dd HH:mm:ss yyyy" (LOCAL)</li>
+ * </ul>
+ *
+ * @param dateStr
+ * the string to be parsed
+ * @return the parsed {@link java.time.LocalDateTime}
+ * @throws java.text.ParseException
+ * if the given dateStr was not recognized
+ */
+ public static LocalDateTime parse(String dateStr) throws ParseException {
+ return parse(dateStr, SystemReader.getInstance().civilNow());
+ }
+
+ /**
+ * Parses a string into a {@link java.time.Instant} using the default
+ * locale. Since this parser also supports relative formats (e.g.
+ * "yesterday") the caller can specify the reference date. These types of
+ * strings can be parsed:
+ * <ul>
+ * <li>"never"</li>
+ * <li>"now"</li>
+ * <li>"yesterday"</li>
+ * <li>"(x) years|months|weeks|days|hours|minutes|seconds ago"<br>
+ * Multiple specs can be combined like in "2 weeks 3 days ago". Instead of '
+ * ' one can use '.' to separate the words</li>
+ * <li>"yyyy-MM-dd HH:mm:ss Z" (ISO)</li>
+ * <li>"EEE, dd MMM yyyy HH:mm:ss Z" (RFC)</li>
+ * <li>"yyyy-MM-dd"</li>
+ * <li>"yyyy.MM.dd"</li>
+ * <li>"MM/dd/yyyy",</li>
+ * <li>"dd.MM.yyyy"</li>
+ * <li>"EEE MMM dd HH:mm:ss yyyy Z" (DEFAULT)</li>
+ * <li>"EEE MMM dd HH:mm:ss yyyy" (LOCAL)</li>
+ * </ul>
+ *
+ * @param dateStr
+ * the string to be parsed
+ * @return the parsed {@link java.time.Instant}
+ * @throws java.text.ParseException
+ * if the given dateStr was not recognized
+ * @since 7.2
+ */
+ public static Instant parseInstant(String dateStr) throws ParseException {
+ return parse(dateStr).atZone(SystemReader.getInstance().getTimeZoneId())
+ .toInstant();
+ }
+
+ // Only tests seem to use this method
+ static LocalDateTime parse(String dateStr, LocalDateTime now)
+ throws ParseException {
+ dateStr = dateStr.trim();
+
+ if (dateStr.equalsIgnoreCase("never")) { //$NON-NLS-1$
+ return LocalDateTime.MAX;
+ }
+ LocalDateTime ret = parseRelative(dateStr, now);
+ if (ret != null) {
+ return ret;
+ }
+ for (ParseableSimpleDateFormat f : ParseableSimpleDateFormat.values()) {
+ try {
+ return parseSimple(dateStr, f);
+ } catch (DateTimeParseException e) {
+ // simply proceed with the next parser
+ }
+ }
+ ParseableSimpleDateFormat[] values = ParseableSimpleDateFormat.values();
+ StringBuilder allFormats = new StringBuilder("\"") //$NON-NLS-1$
+ .append(values[0].formatStr);
+ for (int i = 1; i < values.length; i++) {
+ allFormats.append("\", \"").append(values[i].formatStr); //$NON-NLS-1$
+ }
+ allFormats.append("\""); //$NON-NLS-1$
+ throw new ParseException(
+ MessageFormat.format(JGitText.get().cannotParseDate, dateStr,
+ allFormats.toString()),
+ 0);
+ }
+
+ // tries to parse a string with the formats supported by DateTimeFormatter
+ private static LocalDateTime parseSimple(String dateStr,
+ ParseableSimpleDateFormat f) throws DateTimeParseException {
+ DateTimeFormatter dateFormat = formatCache.computeIfAbsent(f,
+ format -> DateTimeFormatter
+ .ofPattern(f.formatStr)
+ .withLocale(SystemReader.getInstance().getLocale()));
+ TemporalAccessor parsed = dateFormat.parse(dateStr);
+ return parsed.isSupported(ChronoField.HOUR_OF_DAY)
+ ? LocalDateTime.from(parsed)
+ : LocalDate.from(parsed).atStartOfDay();
+ }
+
+ // tries to parse a string with a relative time specification
+ @SuppressWarnings("nls")
+ @Nullable
+ private static LocalDateTime parseRelative(String dateStr,
+ LocalDateTime now) {
+ // check for the static words "yesterday" or "now"
+ if (dateStr.equals("now")) {
+ return now;
+ }
+
+ if (dateStr.equals("yesterday")) {
+ return now.minusDays(1);
+ }
+
+ // parse constructs like "3 days ago", "5.week.2.day.ago"
+ String[] parts = dateStr.split("\\.| ", -1);
+ int partsLength = parts.length;
+ // check we have an odd number of parts (at least 3) and that the last
+ // part is "ago"
+ if (partsLength < 3 || (partsLength & 1) == 0
+ || !parts[parts.length - 1].equals("ago")) {
+ return null;
+ }
+ int number;
+ for (int i = 0; i < parts.length - 2; i += 2) {
+ try {
+ number = Integer.parseInt(parts[i]);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ if (parts[i + 1] == null) {
+ return null;
+ }
+ switch (parts[i + 1]) {
+ case "year":
+ case "years":
+ now = now.minusYears(number);
+ break;
+ case "month":
+ case "months":
+ now = now.minusMonths(number);
+ break;
+ case "week":
+ case "weeks":
+ now = now.minusWeeks(number);
+ break;
+ case "day":
+ case "days":
+ now = now.minusDays(number);
+ break;
+ case "hour":
+ case "hours":
+ now = now.minusHours(number);
+ break;
+ case "minute":
+ case "minutes":
+ now = now.minusMinutes(number);
+ break;
+ case "second":
+ case "seconds":
+ now = now.minusSeconds(number);
+ break;
+ default:
+ return null;
+ }
+ }
+ return now;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java
index e3ba606346..1942342c45 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java
@@ -321,6 +321,7 @@ public class HttpSupport {
* a {@link org.eclipse.jgit.transport.http.HttpConnection}
* object.
* @throws java.io.IOException
+ * if an IO error occurred
* @since 4.3
*/
public static void disableSslVerify(HttpConnection conn)
@@ -346,7 +347,9 @@ public class HttpSupport {
* that have all available protocols enabled already, up to the one
* specified.
* <p>
+ * <br>
* <table>
+ * <caption>TLS versions</caption>
* <tr>
* <td>SSLContext.getInstance()</td>
* <td>OpenJDK</td>
@@ -354,16 +357,16 @@ public class HttpSupport {
* </tr>
* <tr>
* <td>"TLS"</td>
- * <td>Supported: TLSv1, TLSV1.1, TLSv1.2 (+ TLSv1.3)<br />
+ * <td>Supported: TLSv1, TLSV1.1, TLSv1.2 (+ TLSv1.3)<br>
* Enabled: TLSv1, TLSV1.1, TLSv1.2 (+ TLSv1.3)</td>
- * <td>Supported: TLSv1, TLSV1.1, TLSv1.2<br />
+ * <td>Supported: TLSv1, TLSV1.1, TLSv1.2<br>
* Enabled: TLSv1</td>
* </tr>
* <tr>
* <td>"TLSv1.2"</td>
- * <td>Supported: TLSv1, TLSV1.1, TLSv1.2<br />
+ * <td>Supported: TLSv1, TLSV1.1, TLSv1.2<br>
* Enabled: TLSv1, TLSV1.1, TLSv1.2</td>
- * <td>Supported: TLSv1, TLSV1.1, TLSv1.2<br />
+ * <td>Supported: TLSv1, TLSV1.1, TLSv1.2<br>
* Enabled: TLSv1.2</td>
* </tr>
* </table>
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java
index 80877bbdc6..8cc5316271 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java
@@ -66,19 +66,7 @@ public class IO {
public static final byte[] readSome(File path, int limit)
throws FileNotFoundException, IOException {
try (SilentFileInputStream in = new SilentFileInputStream(path)) {
- byte[] buf = new byte[limit];
- int cnt = 0;
- for (;;) {
- int n = in.read(buf, cnt, buf.length - cnt);
- if (n <= 0)
- break;
- cnt += n;
- }
- if (cnt == buf.length)
- return buf;
- byte[] res = new byte[cnt];
- System.arraycopy(buf, 0, res, 0, cnt);
- return res;
+ return in.readNBytes(limit);
}
}
@@ -99,37 +87,10 @@ public class IO {
public static final byte[] readFully(File path, int max)
throws FileNotFoundException, IOException {
try (SilentFileInputStream in = new SilentFileInputStream(path)) {
- long sz = Math.max(path.length(), 1);
- if (sz > max)
+ byte[] buf = in.readNBytes(max);
+ if (in.read() != -1) {
throw new IOException(MessageFormat.format(
JGitText.get().fileIsTooLarge, path));
-
- byte[] buf = new byte[(int) sz];
- int valid = 0;
- for (;;) {
- if (buf.length == valid) {
- if (buf.length == max) {
- int next = in.read();
- if (next < 0)
- break;
-
- throw new IOException(MessageFormat.format(
- JGitText.get().fileIsTooLarge, path));
- }
-
- byte[] nb = new byte[Math.min(buf.length * 2, max)];
- System.arraycopy(buf, 0, nb, 0, valid);
- buf = nb;
- }
- int n = in.read(buf, valid, buf.length - valid);
- if (n < 0)
- break;
- valid += n;
- }
- if (valid < buf.length) {
- byte[] nb = new byte[valid];
- System.arraycopy(buf, 0, nb, 0, valid);
- buf = nb;
}
return buf;
}
@@ -157,26 +118,7 @@ public class IO {
*/
public static ByteBuffer readWholeStream(InputStream in, int sizeHint)
throws IOException {
- byte[] out = new byte[sizeHint];
- int pos = 0;
- while (pos < out.length) {
- int read = in.read(out, pos, out.length - pos);
- if (read < 0)
- return ByteBuffer.wrap(out, 0, pos);
- pos += read;
- }
-
- int last = in.read();
- if (last < 0)
- return ByteBuffer.wrap(out, 0, pos);
-
- try (TemporaryBuffer.Heap tmp = new TemporaryBuffer.Heap(
- Integer.MAX_VALUE)) {
- tmp.write(out);
- tmp.write(last);
- tmp.copy(in);
- return ByteBuffer.wrap(tmp.toByteArray());
- }
+ return ByteBuffer.wrap(in.readAllBytes());
}
/**
@@ -197,13 +139,9 @@ public class IO {
*/
public static void readFully(final InputStream fd, final byte[] dst,
int off, int len) throws IOException {
- while (len > 0) {
- final int r = fd.read(dst, off, len);
- if (r <= 0)
- throw new EOFException(JGitText.get().shortReadOfBlock);
- off += r;
- len -= r;
- }
+ int read = fd.readNBytes(dst, off, len);
+ if (read != len)
+ throw new EOFException(JGitText.get().shortReadOfBlock);
}
/**
@@ -271,14 +209,7 @@ public class IO {
*/
public static int readFully(InputStream fd, byte[] dst, int off)
throws IOException {
- int r;
- int len = 0;
- while (off < dst.length
- && (r = fd.read(dst, off, dst.length - off)) >= 0) {
- off += r;
- len += r;
- }
- return len;
+ return fd.readNBytes(dst, off, dst.length - off);
}
/**
@@ -300,6 +231,7 @@ public class IO {
*/
public static void skipFully(InputStream fd, long toSkip)
throws IOException {
+ // same as fd.skipNBytes(toSkip) of JDK 12;
while (toSkip > 0) {
final long r = fd.skip(toSkip);
if (r <= 0)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/IntList.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/IntList.java
index cc4f0a46fe..6a5190c6a2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/IntList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/IntList.java
@@ -204,7 +204,6 @@ public class IntList {
entries = n;
}
- /** {@inheritDoc} */
@Override
public String toString() {
final StringBuilder r = new StringBuilder();
@@ -220,6 +219,8 @@ public class IntList {
/**
* A comparator of primitive ints.
+ *
+ * @since 6.6
*/
public interface IntComparator {
@@ -230,8 +231,8 @@ public class IntList {
* the first int to compare
* @param second
* the second int to compare
- * @return a negative number if first < second, 0 if first == second, or
- * a positive number if first > second
+ * @return a negative number if first &lt; second, 0 if first == second, or
+ * a positive number if first &gt; second
*/
int compare(int first, int second);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/Iterators.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/Iterators.java
new file mode 100644
index 0000000000..74b728bdf7
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/Iterators.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2025, NVIDIA Corporation.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.util;
+
+import java.util.Iterator;
+
+/**
+ * Utility class for Iterators
+ *
+ * @since 6.10.2
+ */
+public class Iterators {
+ /**
+ * Create an iterator which traverses an array in reverse.
+ *
+ * @param array T[]
+ * @return Iterator<T>
+ */
+ public static <T> Iterator<T> reverseIterator(T[] array) {
+ return new Iterator<>() {
+ int index = array.length;
+
+ @Override
+ public boolean hasNext() {
+ return index > 0;
+ }
+
+ @Override
+ public T next() {
+ return array[--index];
+ }
+ };
+ }
+
+ /**
+ * Make an iterable for easy use in modern for loops.
+ *
+ * @param iterator Iterator<T>
+ * @return Iterable<T>
+ */
+ public static <T> Iterable<T> iterable(Iterator<T> iterator) {
+ return new Iterable<>() {
+ @Override
+ public Iterator<T> iterator() {
+ return iterator;
+ }
+ };
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/LfsFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/LfsFactory.java
index 7456c71f5f..7b7c1d0886 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/LfsFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/LfsFactory.java
@@ -43,6 +43,8 @@ public class LfsFactory {
}
/**
+ * Get the LFS factory instance
+ *
* @return the current LFS implementation
*/
public static LfsFactory getInstance() {
@@ -50,6 +52,8 @@ public class LfsFactory {
}
/**
+ * Set the LFS factory instance
+ *
* @param instance
* register a {@link LfsFactory} instance as the
* {@link LfsFactory} implementation to use.
@@ -59,6 +63,8 @@ public class LfsFactory {
}
/**
+ * Whether LFS support is available
+ *
* @return whether LFS support is available
*/
public boolean isAvailable() {
@@ -105,6 +111,7 @@ public class LfsFactory {
* @return a loader for the actual data of a blob, or the original loader in
* case LFS is not applicable.
* @throws IOException
+ * if an IO error occurred
*/
public ObjectLoader applySmudgeFilter(Repository db,
ObjectLoader loader, Attribute attribute) throws IOException {
@@ -117,6 +124,7 @@ public class LfsFactory {
* @param repo
* the {@link Repository} the hook is applied to.
* @param outputStream
+ * output stream
* @return a {@link PrePushHook} implementation or <code>null</code>
*/
@Nullable
@@ -131,7 +139,9 @@ public class LfsFactory {
* @param repo
* the {@link Repository} the hook is applied to.
* @param outputStream
+ * output stream
* @param errorStream
+ * error stream
* @return a {@link PrePushHook} implementation or <code>null</code>
* @since 5.6
*/
@@ -153,6 +163,8 @@ public class LfsFactory {
}
/**
+ * Whether LFS is enabled
+ *
* @param db
* the repository to check
* @return whether LFS is enabled for the given repository locally or
@@ -163,6 +175,8 @@ public class LfsFactory {
}
/**
+ * Get git attributes for given path
+ *
* @param db
* the repository
* @param path
@@ -285,6 +299,8 @@ public class LfsFactory {
}
/**
+ * Get stream length
+ *
* @return the length of the stream
*/
public long getLength() {
@@ -298,6 +314,8 @@ public class LfsFactory {
*/
public interface LfsInstallCommand extends Callable<Void> {
/**
+ * Set the repository to enable LFS for
+ *
* @param repo
* the repository to enable support for.
* @return The {@link LfsInstallCommand} for chaining.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/LongList.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/LongList.java
index b2bdfc1fd7..47f38f4627 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/LongList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/LongList.java
@@ -140,7 +140,6 @@ public class LongList {
entries = n;
}
- /** {@inheritDoc} */
@Override
public String toString() {
final StringBuilder r = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/NB.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/NB.java
index 7b4ff7ff16..fea7172d84 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/NB.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/NB.java
@@ -133,7 +133,7 @@ public final class NB {
* @since 3.0
*/
public static long decodeInt64(final byte[] intbuf, final int offset) {
- long r = intbuf[offset] << 8;
+ long r = (long) intbuf[offset] << 8;
r |= intbuf[offset + 1] & 0xff;
r <<= 8;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawCharSequence.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawCharSequence.java
index 3de7a1587c..be4bd9e356 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawCharSequence.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawCharSequence.java
@@ -41,25 +41,21 @@ public final class RawCharSequence implements CharSequence {
endPtr = end;
}
- /** {@inheritDoc} */
@Override
public char charAt(int index) {
return (char) (buffer[startPtr + index] & 0xff);
}
- /** {@inheritDoc} */
@Override
public int length() {
return endPtr - startPtr;
}
- /** {@inheritDoc} */
@Override
public CharSequence subSequence(int start, int end) {
return new RawCharSequence(buffer, startPtr + start, startPtr + end);
}
- /** {@inheritDoc} */
@Override
public String toString() {
final int n = length();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
index 0e8e9b3d84..3ed72516c7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
@@ -13,10 +13,17 @@ package org.eclipse.jgit.util;
import static java.nio.charset.StandardCharsets.ISO_8859_1;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.time.Instant.EPOCH;
+import static java.time.ZoneOffset.UTC;
import static org.eclipse.jgit.lib.ObjectChecker.author;
import static org.eclipse.jgit.lib.ObjectChecker.committer;
import static org.eclipse.jgit.lib.ObjectChecker.encoding;
+import static org.eclipse.jgit.lib.ObjectChecker.object;
+import static org.eclipse.jgit.lib.ObjectChecker.parent;
+import static org.eclipse.jgit.lib.ObjectChecker.tag;
import static org.eclipse.jgit.lib.ObjectChecker.tagger;
+import static org.eclipse.jgit.lib.ObjectChecker.tree;
+import static org.eclipse.jgit.lib.ObjectChecker.type;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
@@ -25,6 +32,10 @@ import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -39,14 +50,6 @@ import org.eclipse.jgit.lib.PersonIdent;
* Handy utility functions to parse raw object contents.
*/
public final class RawParseUtils {
- /**
- * UTF-8 charset constant.
- *
- * @since 2.2
- * @deprecated use {@link java.nio.charset.StandardCharsets#UTF_8} instead
- */
- @Deprecated
- public static final Charset UTF8_CHARSET = UTF_8;
private static final byte[] digits10;
@@ -354,6 +357,7 @@ public final class RawParseUtils {
* if the string is not hex formatted.
* @since 4.3
*/
+ @SuppressWarnings("IntLongMath")
public static final long parseHexInt64(final byte[] bs, final int p) {
long r = digits16[bs[p]] << 4;
@@ -461,6 +465,29 @@ public final class RawParseUtils {
}
/**
+ * Parse a Git style timezone string in [+-]hhmm format
+ *
+ * @param b
+ * buffer to scan.
+ * @param ptr
+ * position within buffer to start parsing digits at.
+ * @param ptrResult
+ * optional location to return the new ptr value through. If null
+ * the ptr value will be discarded.
+ * @return the ZoneOffset represention of the timezone offset string.
+ * Invalid offsets default to UTC.
+ */
+ private static ZoneId parseZoneOffset(final byte[] b, int ptr,
+ MutableInteger ptrResult) {
+ int hhmm = parseBase10(b, ptr, ptrResult);
+ try {
+ return ZoneOffset.ofHoursMinutes(hhmm / 100, hhmm % 100);
+ } catch (DateTimeException e) {
+ return UTC;
+ }
+ }
+
+ /**
* Locate the first position after a given character.
*
* @param b
@@ -519,17 +546,24 @@ public final class RawParseUtils {
}
/**
- * Locate the end of the header. Note that headers may be
- * more than one line long.
+ * Locate the first end of line after the given position, while treating
+ * following lines which are starting with spaces as part of the current
+ * line.
+ * <p>
+ * For example, {@code nextLfSkippingSplitLines(
+ * "row \n with space at beginning of a following line\nThe actual next line",
+ * 0)} will return the position of {@code "\nThe actual next line"}.
+ *
* @param b
* buffer to scan.
* @param ptr
- * position within buffer to start looking for the end-of-header.
- * @return new position just after the header. This is either
- * b.length, or the index of the header's terminating newline.
- * @since 5.1
+ * position within buffer to start looking for the next line.
+ * @return new position just after the line end of the last line-split. This
+ * is either b.length, or the index of the current split-line's
+ * terminating newline.
+ * @since 6.9
*/
- public static final int headerEnd(final byte[] b, int ptr) {
+ public static final int nextLfSkippingSplitLines(final byte[] b, int ptr) {
final int sz = b.length;
while (ptr < sz) {
final byte c = b[ptr++];
@@ -537,7 +571,62 @@ public final class RawParseUtils {
return ptr - 1;
}
}
- return ptr - 1;
+ return ptr;
+ }
+
+ /**
+ * Extract a part of a buffer as a header value, removing the single blanks
+ * at the front of continuation lines.
+ *
+ * @param b
+ * buffer to extract the header from
+ * @param start
+ * of the header value, see
+ * {@link #headerStart(byte[], byte[], int)}
+ * @param end
+ * of the header; see
+ * {@link #nextLfSkippingSplitLines(byte[], int)}
+ * @return the header value, with blanks indicating continuation lines
+ * stripped
+ * @since 6.9
+ */
+ public static final byte[] headerValue(final byte[] b, int start, int end) {
+ byte[] data = new byte[end - start];
+ int out = 0;
+ byte last = '\0';
+ for (int in = start; in < end; in++) {
+ byte ch = b[in];
+ if (ch != ' ' || last != '\n') {
+ data[out++] = ch;
+ }
+ last = ch;
+ }
+ if (out == data.length) {
+ return data;
+ }
+ return Arrays.copyOf(data, out);
+ }
+
+ /**
+ * Locate the first end of header after the given position. Note that
+ * headers may be more than one line long.
+ * <p>
+ * Also note that there might be multiple headers. If you wish to find the
+ * last header's end - call this in a loop.
+ *
+ * @param b
+ * buffer to scan.
+ * @param ptr
+ * position within buffer to start looking for the header
+ * (normally a new-line).
+ * @return new position just after the line end. This is either b.length, or
+ * the index of the header's terminating newline.
+ * @since 5.1
+ * @deprecated use {{@link #nextLfSkippingSplitLines}} directly instead
+ */
+ @Deprecated
+ public static final int headerEnd(final byte[] b, int ptr) {
+ return nextLfSkippingSplitLines(b, ptr);
}
/**
@@ -575,6 +664,22 @@ public final class RawParseUtils {
}
/**
+ * Returns whether the message starts with any known headers.
+ *
+ * @param b
+ * buffer to scan.
+ * @return whether the message starts with any known headers
+ * @since 6.9
+ */
+ public static final boolean hasAnyKnownHeaders(byte[] b) {
+ return match(b, 0, tree) != -1 || match(b, 0, parent) != -1
+ || match(b, 0, author) != -1 || match(b, 0, committer) != -1
+ || match(b, 0, encoding) != -1 || match(b, 0, object) != -1
+ || match(b, 0, type) != -1 || match(b, 0, tag) != -1
+ || match(b, 0, tagger) != -1;
+ }
+
+ /**
* Locate the first position before a given character.
*
* @param b
@@ -868,6 +973,26 @@ public final class RawParseUtils {
}
/**
+ * Parse the "encoding " header into a character set reference.
+ * <p>
+ * If unsuccessful, return UTF-8.
+ *
+ * @param buffer
+ * buffer to scan.
+ * @return the Java character set representation. Never null. Default to
+ * UTF-8.
+ * @see #parseEncoding(byte[])
+ * @since 6.7
+ */
+ public static Charset guessEncoding(byte[] buffer) {
+ try {
+ return parseEncoding(buffer);
+ } catch (IllegalCharsetNameException | UnsupportedCharsetException e) {
+ return UTF_8;
+ }
+ }
+
+ /**
* Parse a name string (e.g. author, committer, tagger) into a PersonIdent.
* <p>
* Leading spaces won't be trimmed from the string, i.e. will show up in the
@@ -931,17 +1056,19 @@ public final class RawParseUtils {
// character if there is no trailing LF.
final int tzBegin = lastIndexOfTrim(raw, ' ',
nextLF(raw, emailE - 1) - 2) + 1;
- if (tzBegin <= emailE) // No time/zone, still valid
- return new PersonIdent(name, email, 0, 0);
+ if (tzBegin <= emailE) { // No time/zone, still valid
+ return new PersonIdent(name, email, EPOCH, UTC);
+ }
final int whenBegin = Math.max(emailE,
lastIndexOfTrim(raw, ' ', tzBegin - 1) + 1);
- if (whenBegin >= tzBegin - 1) // No time/zone, still valid
- return new PersonIdent(name, email, 0, 0);
+ if (whenBegin >= tzBegin - 1) { // No time/zone, still valid
+ return new PersonIdent(name, email, EPOCH, UTC);
+ }
- final long when = parseLongBase10(raw, whenBegin, null);
- final int tz = parseTimeZoneOffset(raw, tzBegin);
- return new PersonIdent(name, email, when * 1000L, tz);
+ long when = parseLongBase10(raw, whenBegin, null);
+ return new PersonIdent(name, email, Instant.ofEpochSecond(when),
+ parseZoneOffset(raw, tzBegin, null));
}
/**
@@ -979,16 +1106,16 @@ public final class RawParseUtils {
name = decode(raw, nameB, stop);
final MutableInteger ptrout = new MutableInteger();
- long when;
- int tz;
+ Instant when;
+ ZoneId tz;
if (emailE < stop) {
- when = parseLongBase10(raw, emailE + 1, ptrout);
- tz = parseTimeZoneOffset(raw, ptrout.value);
+ when = Instant.ofEpochSecond(parseLongBase10(raw, emailE + 1, ptrout));
+ tz = parseZoneOffset(raw, ptrout.value, null);
} else {
- when = 0;
- tz = 0;
+ when = EPOCH;
+ tz = UTC;
}
- return new PersonIdent(name, email, when * 1000L, tz);
+ return new PersonIdent(name, email, when, tz);
}
/**
@@ -1237,6 +1364,7 @@ public final class RawParseUtils {
final int sz = b.length;
if (ptr == 0)
ptr += 48; // skip the "object ..." line.
+ // Assume the rest of the current paragraph is all headers.
while (ptr < sz && b[ptr] != '\n')
ptr = nextLF(b, ptr);
if (ptr < sz && b[ptr] == '\n')
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawSubStringPattern.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawSubStringPattern.java
index 57464f3c41..04fdcd0fa4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawSubStringPattern.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawSubStringPattern.java
@@ -98,7 +98,6 @@ public class RawSubStringPattern {
return needleString;
}
- /** {@inheritDoc} */
@Override
public String toString() {
return pattern();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java
index 462bab081a..350ec76cf9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java
@@ -43,6 +43,8 @@ public class RefList<T extends Ref> implements Iterable<Ref> {
/**
* Create an empty unmodifiable reference list.
*
+ * @param <T>
+ * type of reference being stored.
* @return an empty unmodifiable reference list.
*/
@SuppressWarnings("unchecked")
@@ -70,7 +72,6 @@ public class RefList<T extends Ref> implements Iterable<Ref> {
this.cnt = src.cnt;
}
- /** {@inheritDoc} */
@Override
public Iterator<Ref> iterator() {
return new Iterator<>() {
@@ -286,7 +287,6 @@ public class RefList<T extends Ref> implements Iterable<Ref> {
return add(idx, ref);
}
- /** {@inheritDoc} */
@Override
public String toString() {
StringBuilder r = new StringBuilder();
@@ -305,6 +305,8 @@ public class RefList<T extends Ref> implements Iterable<Ref> {
/**
* Create a {@link Collector} for {@link Ref}.
*
+ * @param <T>
+ * type of reference being stored.
* @param mergeFunction
* if specified the result will be sorted and deduped.
* @return {@link Collector} for {@link Ref}
@@ -355,7 +357,11 @@ public class RefList<T extends Ref> implements Iterable<Ref> {
list = new Ref[Math.max(capacity, 16)];
}
- /** @return number of items in this builder's internal collection. */
+ /**
+ * Get size
+ *
+ * @return number of items in this builder's internal collection.
+ */
public int size() {
return size;
}
@@ -390,6 +396,7 @@ public class RefList<T extends Ref> implements Iterable<Ref> {
* after additions are complete using {@link #sort()}.
*
* @param ref
+ * reference to add
*/
public void add(T ref) {
if (list.length == size) {
@@ -404,6 +411,7 @@ public class RefList<T extends Ref> implements Iterable<Ref> {
* Add all items from another builder.
*
* @param other
+ * another builder
* @since 5.4
*/
public void addAll(Builder other) {
@@ -454,6 +462,7 @@ public class RefList<T extends Ref> implements Iterable<Ref> {
* Dedupe the refs in place. Must be called after {@link #sort}.
*
* @param mergeFunction
+ * function used for de-duplication
*/
@SuppressWarnings("unchecked")
void dedupe(BinaryOperator<T> mergeFunction) {
@@ -475,7 +484,11 @@ public class RefList<T extends Ref> implements Iterable<Ref> {
Arrays.fill(list, size, list.length, null);
}
- /** @return an unmodifiable list using this collection's backing array. */
+ /**
+ * Get unmodifiable list based on this list
+ *
+ * @return an unmodifiable list using this collection's backing array.
+ */
public RefList<T> toRefList() {
return new RefList<>(list, size);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java
index c68a76cef4..a4d1fd5b70 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java
@@ -119,13 +119,11 @@ public class RefMap extends AbstractMap<String, Ref> {
this.resolved = (RefList<Ref>) resolved;
}
- /** {@inheritDoc} */
@Override
public boolean containsKey(Object name) {
return get(name) != null;
}
- /** {@inheritDoc} */
@Override
public Ref get(Object key) {
String name = toRefName((String) key);
@@ -137,7 +135,6 @@ public class RefMap extends AbstractMap<String, Ref> {
return ref;
}
- /** {@inheritDoc} */
@Override
public Ref put(String keyName, Ref value) {
String name = toRefName(keyName);
@@ -165,7 +162,6 @@ public class RefMap extends AbstractMap<String, Ref> {
return prior;
}
- /** {@inheritDoc} */
@Override
public Ref remove(Object key) {
String name = toRefName((String) key);
@@ -189,13 +185,11 @@ public class RefMap extends AbstractMap<String, Ref> {
return res;
}
- /** {@inheritDoc} */
@Override
public boolean isEmpty() {
return entrySet().isEmpty();
}
- /** {@inheritDoc} */
@Override
public Set<Entry<String, Ref>> entrySet() {
if (entrySet == null) {
@@ -238,7 +232,6 @@ public class RefMap extends AbstractMap<String, Ref> {
return entrySet;
}
- /** {@inheritDoc} */
@Override
public String toString() {
StringBuilder r = new StringBuilder();
@@ -259,6 +252,7 @@ public class RefMap extends AbstractMap<String, Ref> {
* Create a {@link Collector} for {@link Ref}.
*
* @param mergeFunction
+ * merge function
* @return {@link Collector} for {@link Ref}
* @since 5.4
*/
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RelativeDateFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RelativeDateFormatter.java
index 5611b1e78e..b6b19e0e7b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RelativeDateFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RelativeDateFormatter.java
@@ -10,6 +10,8 @@
package org.eclipse.jgit.util;
import java.text.MessageFormat;
+import java.time.Duration;
+import java.time.Instant;
import java.util.Date;
import org.eclipse.jgit.internal.JGitText;
@@ -42,12 +44,29 @@ public class RelativeDateFormatter {
* @return age of given {@link java.util.Date} compared to now formatted in
* the same relative format as returned by
* {@code git log --relative-date}
+ * @deprecated Use {@link #format(Instant)} instead.
*/
+ @Deprecated(since = "7.2")
@SuppressWarnings("boxing")
public static String format(Date when) {
+ return format(when.toInstant());
+ }
- long ageMillis = SystemReader.getInstance().getCurrentTime()
- - when.getTime();
+ /**
+ * Get age of given {@link java.time.Instant} compared to now formatted in the
+ * same relative format as returned by {@code git log --relative-date}
+ *
+ * @param when
+ * an instant to format
+ * @return age of given instant compared to now formatted in
+ * the same relative format as returned by
+ * {@code git log --relative-date}
+ * @since 7.2
+ */
+ @SuppressWarnings("boxing")
+ public static String format(Instant when) {
+ long ageMillis = Duration
+ .between(when, SystemReader.getInstance().now()).toMillis();
// shouldn't happen in a perfect world
if (ageMillis < 0)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/SignatureUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SignatureUtils.java
index cf06172c17..e3e3e04fd9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SignatureUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SignatureUtils.java
@@ -13,8 +13,8 @@ import java.text.MessageFormat;
import java.util.Locale;
import org.eclipse.jgit.internal.JGitText;
-import org.eclipse.jgit.lib.GpgSignatureVerifier.SignatureVerification;
-import org.eclipse.jgit.lib.GpgSignatureVerifier.TrustLevel;
+import org.eclipse.jgit.lib.SignatureVerifier.SignatureVerification;
+import org.eclipse.jgit.lib.SignatureVerifier.TrustLevel;
import org.eclipse.jgit.lib.PersonIdent;
/**
@@ -39,29 +39,34 @@ public final class SignatureUtils {
* to use for dates
* @return a textual representation of the {@link SignatureVerification},
* using LF as line separator
+ *
+ * @since 7.0
*/
public static String toString(SignatureVerification verification,
PersonIdent creator, GitDateFormatter formatter) {
StringBuilder result = new StringBuilder();
- // Use the creator's timezone for the signature date
- PersonIdent dateId = new PersonIdent(creator,
- verification.getCreationDate());
- result.append(MessageFormat.format(JGitText.get().verifySignatureMade,
- formatter.formatDate(dateId)));
- result.append('\n');
+ if (verification.creationDate() != null) {
+ // Use the creator's timezone for the signature date
+ PersonIdent dateId = new PersonIdent(creator,
+ verification.creationDate().toInstant());
+ result.append(
+ MessageFormat.format(JGitText.get().verifySignatureMade,
+ formatter.formatDate(dateId)));
+ result.append('\n');
+ }
result.append(MessageFormat.format(
JGitText.get().verifySignatureKey,
- verification.getKeyFingerprint().toUpperCase(Locale.ROOT)));
+ verification.keyFingerprint().toUpperCase(Locale.ROOT)));
result.append('\n');
- if (!StringUtils.isEmptyOrNull(verification.getSigner())) {
+ if (!StringUtils.isEmptyOrNull(verification.signer())) {
result.append(
MessageFormat.format(JGitText.get().verifySignatureIssuer,
- verification.getSigner()));
+ verification.signer()));
result.append('\n');
}
String msg;
- if (verification.getVerified()) {
- if (verification.isExpired()) {
+ if (verification.verified()) {
+ if (verification.expired()) {
msg = JGitText.get().verifySignatureExpired;
} else {
msg = JGitText.get().verifySignatureGood;
@@ -69,14 +74,14 @@ public final class SignatureUtils {
} else {
msg = JGitText.get().verifySignatureBad;
}
- result.append(MessageFormat.format(msg, verification.getKeyUser()));
- if (!TrustLevel.UNKNOWN.equals(verification.getTrustLevel())) {
+ result.append(MessageFormat.format(msg, verification.keyUser()));
+ if (!TrustLevel.UNKNOWN.equals(verification.trustLevel())) {
result.append(' ' + MessageFormat
.format(JGitText.get().verifySignatureTrust, verification
- .getTrustLevel().name().toLowerCase(Locale.ROOT)));
+ .trustLevel().name().toLowerCase(Locale.ROOT)));
}
result.append('\n');
- msg = verification.getMessage();
+ msg = verification.message();
if (!StringUtils.isEmptyOrNull(msg)) {
result.append(msg);
result.append('\n');
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java
index e29704158d..42a76b5b16 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java
@@ -48,6 +48,7 @@ public class SshSupport {
* cases.
* @return The entire output read from stdout.
* @throws IOException
+ * if an IO error occurred
* @throws CommandFailedException
* if the ssh command execution failed, error message contains
* the content of stderr.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/Stats.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/Stats.java
index d957deb34c..efa6e7ddc3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/Stats.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/Stats.java
@@ -43,14 +43,18 @@ public class Stats {
}
/**
- * @return number of the added values
+ * Returns the number of added values
+ *
+ * @return the number of added values
*/
public int count() {
return n;
}
/**
- * @return minimum of the added values
+ * Returns the smallest value added
+ *
+ * @return the smallest value added
*/
public double min() {
if (n < 1) {
@@ -60,7 +64,9 @@ public class Stats {
}
/**
- * @return maximum of the added values
+ * Returns the biggest value added
+ *
+ * @return the biggest value added
*/
public double max() {
if (n < 1) {
@@ -70,9 +76,10 @@ public class Stats {
}
/**
- * @return average of the added values
+ * Returns the average of the added values
+ *
+ * @return the average of the added values
*/
-
public double avg() {
if (n < 1) {
return Double.NaN;
@@ -81,7 +88,9 @@ public class Stats {
}
/**
- * @return variance of the added values
+ * Returns the variance of the added values
+ *
+ * @return the variance of the added values
*/
public double var() {
if (n < 2) {
@@ -91,7 +100,9 @@ public class Stats {
}
/**
- * @return standard deviation of the added values
+ * Returns the standard deviation of the added values
+ *
+ * @return the standard deviation of the added values
*/
public double stddev() {
return Math.sqrt(this.var());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java
index 917add3609..e381a3bcc9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java
@@ -14,6 +14,7 @@ import java.text.MessageFormat;
import java.util.Collection;
import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
@@ -22,6 +23,8 @@ import org.eclipse.jgit.lib.Constants;
*/
public final class StringUtils {
+ private static final String EMPTY = ""; //$NON-NLS-1$
+
private static final long KiB = 1024;
private static final long MiB = 1024 * KiB;
@@ -181,9 +184,9 @@ public final class StringUtils {
*
* @param stringValue
* the string to parse.
- * @return the boolean interpretation of {@code value}.
+ * @return the boolean interpretation of {@code stringValue}.
* @throws java.lang.IllegalArgumentException
- * if {@code value} is not recognized as one of the standard
+ * if {@code stringValue} is not recognized as one of the standard
* boolean names.
*/
public static boolean toBoolean(String stringValue) {
@@ -275,6 +278,44 @@ public final class StringUtils {
}
/**
+ * Remove the specified character from beginning and end of a string
+ * <p>
+ * If the character repeats, all copies
+ *
+ * @param str input string
+ * @param c character to remove
+ * @return the input string with c
+ * @since 7.2
+ */
+ public static String trim(String str, char c) {
+ if (str == null || str.length() == 0) {
+ return str;
+ }
+
+ int endPos = str.length()-1;
+ while (endPos >= 0 && str.charAt(endPos) == c) {
+ endPos--;
+ }
+
+ // Whole string is c
+ if (endPos == -1) {
+ return EMPTY;
+ }
+
+ int startPos = 0;
+ while (startPos < endPos && str.charAt(startPos) == c) {
+ startPos++;
+ }
+
+ if (startPos == 0 && endPos == str.length()-1) {
+ // No need to copy
+ return str;
+ }
+
+ return str.substring(startPos, endPos+1);
+ }
+
+ /**
* Appends {@link Constants#DOT_GIT_EXT} unless the given name already ends
* with that suffix.
*
@@ -346,7 +387,7 @@ public final class StringUtils {
* allow negative numbers, too
* @return the value parsed
* @throws NumberFormatException
- * if the {@value} is not parseable, or beyond the range of
+ * if the {@code value} is not parseable, or beyond the range of
* {@link Long}
* @throws StringIndexOutOfBoundsException
* if the string is empty or contains only whitespace, or
@@ -420,7 +461,7 @@ public final class StringUtils {
* allow negative numbers, too
* @return the value parsed
* @throws NumberFormatException
- * if the {@value} is not parseable or beyond the range of
+ * if the {@code value} is not parseable or beyond the range of
* {@link Integer}
* @throws StringIndexOutOfBoundsException
* if the string is empty or contains only whitespace, or
@@ -463,4 +504,39 @@ public final class StringUtils {
}
return String.valueOf(value);
}
+
+ /**
+ * Compares Strings and returns the initial sequence of characters that is
+ * common to all of them.
+ *
+ * @param strings
+ * Strings to consider
+ * @return common prefix of all Strings
+ * @since 6.8
+ */
+ public static @NonNull String commonPrefix(@Nullable String... strings) {
+ if (strings == null || strings.length == 0) {
+ return EMPTY;
+ }
+ String first = strings[0];
+ if (first == null) {
+ return EMPTY;
+ }
+ if (strings.length == 1) {
+ return first;
+ }
+ for (int i = 0; i < first.length(); i++) {
+ char currentChar = first.charAt(i);
+ for (int j = 1; j < strings.length; j++) {
+ String str = strings[j];
+ if (str == null) {
+ return EMPTY;
+ }
+ if (str.length() == i || currentChar != str.charAt(i)) {
+ return str.substring(0, i);
+ }
+ }
+ }
+ return first;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
index a8a77904a2..0b7c6204f2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
@@ -23,10 +23,12 @@ import java.nio.charset.UnsupportedCharsetException;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicReference;
@@ -39,6 +41,7 @@ import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectChecker;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.storage.file.UserConfigFile;
import org.eclipse.jgit.util.time.MonotonicClock;
import org.eclipse.jgit.util.time.MonotonicSystemClock;
import org.slf4j.Logger;
@@ -124,28 +127,20 @@ public abstract class SystemReader {
@Override
public FileBasedConfig openUserConfig(Config parent, FS fs) {
- return new FileBasedConfig(parent, new File(fs.userHome(), ".gitconfig"), //$NON-NLS-1$
- fs);
- }
-
- private Path getXDGConfigHome(FS fs) {
- String configHomePath = getenv(Constants.XDG_CONFIG_HOME);
- if (StringUtils.isEmptyOrNull(configHomePath)) {
- configHomePath = new File(fs.userHome(), ".config") //$NON-NLS-1$
- .getAbsolutePath();
- }
- try {
- return Paths.get(configHomePath);
- } catch (InvalidPathException e) {
- LOG.error(JGitText.get().logXDGConfigHomeInvalid,
- configHomePath, e);
+ File homeFile = new File(fs.userHome(), ".gitconfig"); //$NON-NLS-1$
+ Path xdgPath = getXdgConfigDirectory(fs);
+ if (xdgPath != null) {
+ Path configPath = xdgPath.resolve("git") //$NON-NLS-1$
+ .resolve(Constants.CONFIG);
+ return new UserConfigFile(parent, homeFile, configPath.toFile(),
+ fs);
}
- return null;
+ return new FileBasedConfig(parent, homeFile, fs);
}
@Override
public FileBasedConfig openJGitConfig(Config parent, FS fs) {
- Path xdgPath = getXDGConfigHome(fs);
+ Path xdgPath = getXdgConfigDirectory(fs);
if (xdgPath != null) {
Path configPath = xdgPath.resolve("jgit") //$NON-NLS-1$
.resolve(Constants.CONFIG);
@@ -176,11 +171,87 @@ public abstract class SystemReader {
}
@Override
+ public Instant now() {
+ return Instant.now();
+ }
+
+ @Override
public int getTimezone(long when) {
return getTimeZone().getOffset(when) / (60 * 1000);
}
}
+ /**
+ * Delegating SystemReader. Reduces boiler-plate code applications need to
+ * implement when overriding only a few of the SystemReader's methods.
+ *
+ * @since 6.9
+ */
+ public static class Delegate extends SystemReader {
+
+ private final SystemReader delegate;
+
+ /**
+ * Create a delegating system reader
+ *
+ * @param delegate
+ * the system reader to delegate to
+ */
+ public Delegate(SystemReader delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public String getHostname() {
+ return delegate.getHostname();
+ }
+
+ @Override
+ public String getenv(String variable) {
+ return delegate.getenv(variable);
+ }
+
+ @Override
+ public String getProperty(String key) {
+ return delegate.getProperty(key);
+ }
+
+ @Override
+ public FileBasedConfig openUserConfig(Config parent, FS fs) {
+ return delegate.openUserConfig(parent, fs);
+ }
+
+ @Override
+ public FileBasedConfig openSystemConfig(Config parent, FS fs) {
+ return delegate.openSystemConfig(parent, fs);
+ }
+
+ @Override
+ public FileBasedConfig openJGitConfig(Config parent, FS fs) {
+ return delegate.openJGitConfig(parent, fs);
+ }
+
+ @Override
+ public long getCurrentTime() {
+ return delegate.getCurrentTime();
+ }
+
+ @Override
+ public Instant now() {
+ return delegate.now();
+ }
+
+ @Override
+ public int getTimezone(long when) {
+ return delegate.getTimezone(when);
+ }
+
+ @Override
+ public ZoneOffset getTimeZoneAt(Instant when) {
+ return delegate.getTimeZoneAt(when);
+ }
+ }
+
private static volatile SystemReader INSTANCE = DEFAULT;
/**
@@ -391,6 +462,66 @@ public abstract class SystemReader {
}
/**
+ * Gets the directory denoted by environment variable XDG_CONFIG_HOME. If
+ * the variable is not set or empty, return a path for
+ * {@code $HOME/.config}.
+ *
+ * @param fileSystem
+ * {@link FS} to get the user's home directory
+ * @return a {@link Path} denoting the directory, which may exist or not, or
+ * {@code null} if the environment variable is not set and there is
+ * no home directory, or the path is invalid.
+ * @since 6.7
+ */
+ public Path getXdgConfigDirectory(FS fileSystem) {
+ String configHomePath = getenv(Constants.XDG_CONFIG_HOME);
+ if (StringUtils.isEmptyOrNull(configHomePath)) {
+ File home = fileSystem.userHome();
+ if (home == null) {
+ return null;
+ }
+ configHomePath = new File(home, ".config").getAbsolutePath(); //$NON-NLS-1$
+ }
+ try {
+ return Paths.get(configHomePath);
+ } catch (InvalidPathException e) {
+ LOG.error(JGitText.get().logXDGConfigHomeInvalid, configHomePath,
+ e);
+ }
+ return null;
+ }
+
+ /**
+ * Gets the directory denoted by environment variable XDG_CACHE_HOME. If
+ * the variable is not set or empty, return a path for
+ * {@code $HOME/.cache}.
+ *
+ * @param fileSystem
+ * {@link FS} to get the user's home directory
+ * @return a {@link Path} denoting the directory, which may exist or not, or
+ * {@code null} if the environment variable is not set and there is
+ * no home directory, or the path is invalid.
+ * @since 7.3
+ */
+ public Path getXdgCacheDirectory(FS fileSystem) {
+ String cacheHomePath = getenv(Constants.XDG_CACHE_HOME);
+ if (StringUtils.isEmptyOrNull(cacheHomePath)) {
+ File home = fileSystem.userHome();
+ if (home == null) {
+ return null;
+ }
+ cacheHomePath = new File(home, ".cache").getAbsolutePath(); //$NON-NLS-1$
+ }
+ try {
+ return Paths.get(cacheHomePath);
+ } catch (InvalidPathException e) {
+ LOG.error(JGitText.get().logXDGCacheHomeInvalid, cacheHomePath,
+ e);
+ }
+ return null;
+ }
+
+ /**
* Update config and its parents if they seem modified
*
* @param config
@@ -419,10 +550,37 @@ public abstract class SystemReader {
* Get the current system time
*
* @return the current system time
+ *
+ * @deprecated Use {@link #now()}
*/
+ @Deprecated(since = "7.1")
public abstract long getCurrentTime();
/**
+ * Get the current system time
+ *
+ * @return the current system time
+ *
+ * @since 7.1
+ */
+ public Instant now() {
+ // Subclasses overriding getCurrentTime should keep working
+ // TODO(ifrade): Once we remove getCurrentTime, use Instant.now()
+ return Instant.ofEpochMilli(getCurrentTime());
+ }
+
+ /**
+ * Get "now" as civil time, in the System timezone
+ *
+ * @return the current system time
+ *
+ * @since 7.1
+ */
+ public LocalDateTime civilNow() {
+ return LocalDateTime.ofInstant(now(), getTimeZoneId());
+ }
+
+ /**
* Get clock instance preferred by this system.
*
* @return clock instance preferred by this system.
@@ -438,20 +596,48 @@ public abstract class SystemReader {
* @param when
* a system timestamp
* @return the local time zone
+ *
+ * @deprecated Use {@link #getTimeZoneAt(Instant)} instead.
*/
+ @Deprecated(since = "7.1")
public abstract int getTimezone(long when);
/**
+ * Get the local time zone offset at "when" time
+ *
+ * @param when
+ * a system timestamp
+ * @return the local time zone
+ * @since 7.1
+ */
+ public ZoneOffset getTimeZoneAt(Instant when) {
+ return getTimeZoneId().getRules().getOffset(when);
+ }
+
+ /**
* Get system time zone, possibly mocked for testing
*
* @return system time zone, possibly mocked for testing
* @since 1.2
+ *
+ * @deprecated Use {@link #getTimeZoneId()}
*/
+ @Deprecated(since = "7.1")
public TimeZone getTimeZone() {
return TimeZone.getDefault();
}
/**
+ * Get system time zone, possibly mocked for testing
+ *
+ * @return system time zone, possibly mocked for testing
+ * @since 7.1
+ */
+ public ZoneId getTimeZoneId() {
+ return ZoneId.systemDefault();
+ }
+
+ /**
* Get the locale to use
*
* @return the locale to use
@@ -586,9 +772,7 @@ public abstract class SystemReader {
}
private String getOsName() {
- return AccessController.doPrivileged(
- (PrivilegedAction<String>) () -> getProperty("os.name") //$NON-NLS-1$
- );
+ return getProperty("os.name"); //$NON-NLS-1$
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFInputStream.java
index cedb159827..ccc19691b1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFInputStream.java
@@ -57,14 +57,12 @@ public class AutoCRLFInputStream extends InputStream {
this.detectBinary = detectBinary;
}
- /** {@inheritDoc} */
@Override
public int read() throws IOException {
final int read = read(single, 0, 1);
return read == 1 ? single[0] & 0xff : -1;
}
- /** {@inheritDoc} */
@Override
public int read(byte[] bs, int off, int len) throws IOException {
if (len == 0)
@@ -103,7 +101,6 @@ public class AutoCRLFInputStream extends InputStream {
return n;
}
- /** {@inheritDoc} */
@Override
public void close() throws IOException {
in.close();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java
index 305ccbd7e6..9fb316f28d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoCRLFOutputStream.java
@@ -65,14 +65,12 @@ public class AutoCRLFOutputStream extends OutputStream {
this.detectBinary = detectBinary;
}
- /** {@inheritDoc} */
@Override
public void write(int b) throws IOException {
onebytebuf[0] = (byte) b;
write(onebytebuf, 0, 1);
}
- /** {@inheritDoc} */
@Override
public void write(byte[] b) throws IOException {
int overflow = buffer(b, 0, b.length);
@@ -80,7 +78,6 @@ public class AutoCRLFOutputStream extends OutputStream {
write(b, b.length - overflow, overflow);
}
- /** {@inheritDoc} */
@Override
public void write(byte[] b, int startOff, int startLen)
throws IOException {
@@ -151,7 +148,6 @@ public class AutoCRLFOutputStream extends OutputStream {
write(binbuf, 0, cachedLen);
}
- /** {@inheritDoc} */
@Override
public void flush() throws IOException {
if (binbufcnt <= binbuf.length) {
@@ -161,7 +157,6 @@ public class AutoCRLFOutputStream extends OutputStream {
out.flush();
}
- /** {@inheritDoc} */
@Override
public void close() throws IOException {
flush();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFInputStream.java
index 7db882c074..4b9706a3ce 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFInputStream.java
@@ -147,52 +147,12 @@ public class AutoLFInputStream extends InputStream {
&& flags.contains(StreamFlag.FOR_CHECKOUT);
}
- /**
- * Creates a new InputStream, wrapping the specified stream.
- *
- * @param in
- * raw input stream
- * @param detectBinary
- * whether binaries should be detected
- * @since 2.0
- * @deprecated since 5.9, use {@link #create(InputStream, StreamFlag...)}
- * instead
- */
- @Deprecated
- public AutoLFInputStream(InputStream in, boolean detectBinary) {
- this(in, detectBinary, false);
- }
-
- /**
- * Creates a new InputStream, wrapping the specified stream.
- *
- * @param in
- * raw input stream
- * @param detectBinary
- * whether binaries should be detected
- * @param abortIfBinary
- * throw an IOException if the file is binary
- * @since 3.3
- * @deprecated since 5.9, use {@link #create(InputStream, StreamFlag...)}
- * instead
- */
- @Deprecated
- public AutoLFInputStream(InputStream in, boolean detectBinary,
- boolean abortIfBinary) {
- this.in = in;
- this.detectBinary = detectBinary;
- this.abortIfBinary = abortIfBinary;
- this.forCheckout = false;
- }
-
- /** {@inheritDoc} */
@Override
public int read() throws IOException {
final int read = read(single, 0, 1);
return read == 1 ? single[0] & 0xff : -1;
}
- /** {@inheritDoc} */
@Override
public int read(byte[] bs, int off, int len)
throws IOException {
@@ -242,7 +202,6 @@ public class AutoLFInputStream extends InputStream {
return isBinary;
}
- /** {@inheritDoc} */
@Override
public void close() throws IOException {
in.close();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFOutputStream.java
index a0e9fb68c5..e56991d43a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFOutputStream.java
@@ -69,14 +69,12 @@ public class AutoLFOutputStream extends OutputStream {
this.detectBinary = detectBinary;
}
- /** {@inheritDoc} */
@Override
public void write(int b) throws IOException {
onebytebuf[0] = (byte) b;
write(onebytebuf, 0, 1);
}
- /** {@inheritDoc} */
@Override
public void write(byte[] b) throws IOException {
int overflow = buffer(b, 0, b.length);
@@ -85,7 +83,6 @@ public class AutoLFOutputStream extends OutputStream {
}
}
- /** {@inheritDoc} */
@Override
public void write(byte[] b, int startOff, int startLen)
throws IOException {
@@ -164,7 +161,6 @@ public class AutoLFOutputStream extends OutputStream {
write(binbuf, 0, cachedLen);
}
- /** {@inheritDoc} */
@Override
public void flush() throws IOException {
if (binbufcnt <= binbuf.length) {
@@ -173,7 +169,6 @@ public class AutoLFOutputStream extends OutputStream {
out.flush();
}
- /** {@inheritDoc} */
@Override
public void close() throws IOException {
flush();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ByteBufferInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ByteBufferInputStream.java
new file mode 100644
index 0000000000..804f7f860a
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ByteBufferInputStream.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2023, SAP SE and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.util.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.InvalidMarkException;
+import java.util.Objects;
+
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.internal.JGitText;
+
+/**
+ * An {@link InputStream} backed by a {@link ByteBuffer}.
+ *
+ * @since 6.8
+ */
+public class ByteBufferInputStream extends InputStream {
+
+ private ByteBuffer buf;
+
+ /**
+ * Creates a {@link ByteBufferInputStream}
+ *
+ * @param buf
+ * the ByteBuffer backing the stream
+ */
+ public ByteBufferInputStream(@NonNull ByteBuffer buf) {
+ this.buf = buf;
+ }
+
+ @Override
+ public int read() throws IOException {
+ nullCheck();
+ if (buf.hasRemaining()) {
+ return buf.get() & 0xFF;
+ }
+ return -1;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ nullCheck();
+ return read(b, 0, b.length);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ nullCheck();
+ Objects.checkFromIndexSize(off, len, b.length);
+ if (len == 0) {
+ return 0;
+ }
+ int length = Math.min(buf.remaining(), len);
+ if (length == 0) {
+ return -1;
+ }
+ buf.get(b, off, length);
+ return length;
+ }
+
+ @Override
+ public byte[] readAllBytes() throws IOException {
+ return readNBytes(buf.remaining());
+ }
+
+ @Override
+ public byte[] readNBytes(int len) throws IOException {
+ int l = Math.min(len, buf.remaining());
+ byte[] b = new byte[l];
+ read(b);
+ return b;
+ }
+
+ @Override
+ public int readNBytes(byte[] b, int off, int len) throws IOException {
+ return read(b, off, len);
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ nullCheck();
+ if (n <= 0) {
+ return 0;
+ }
+ // ByteBuffer index has type int
+ int delta = n > Integer.MAX_VALUE ? buf.remaining()
+ : Math.min((int) n, buf.remaining());
+ buf.position(buf.position() + delta);
+ return delta;
+ }
+
+ @Override
+ public int available() throws IOException {
+ nullCheck();
+ return buf.remaining();
+ }
+
+ @Override
+ public void close() {
+ buf = null;
+ }
+
+ @Override
+ public synchronized void mark(int readlimit) {
+ buf.mark();
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ try {
+ buf.reset();
+ } catch (InvalidMarkException e) {
+ throw new IOException(e);
+ }
+ }
+
+ @Override
+ public boolean markSupported() {
+ return true;
+ }
+
+ private void nullCheck() throws IOException {
+ if (buf == null) {
+ throw new IOException(JGitText.get().inputStreamClosed);
+ }
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/CountingOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/CountingOutputStream.java
index 782f3f4ca6..d0049d29de 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/CountingOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/CountingOutputStream.java
@@ -39,27 +39,23 @@ public class CountingOutputStream extends OutputStream {
return cnt;
}
- /** {@inheritDoc} */
@Override
public void write(int val) throws IOException {
out.write(val);
cnt++;
}
- /** {@inheritDoc} */
@Override
public void write(byte[] buf, int off, int len) throws IOException {
out.write(buf, off, len);
cnt += len;
}
- /** {@inheritDoc} */
@Override
public void flush() throws IOException {
out.flush();
}
- /** {@inheritDoc} */
@Override
public void close() throws IOException {
out.close();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/DisabledOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/DisabledOutputStream.java
index f1bfbe29a5..03c25bb702 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/DisabledOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/DisabledOutputStream.java
@@ -27,7 +27,6 @@ public final class DisabledOutputStream extends OutputStream {
// more than one instance from being created.
}
- /** {@inheritDoc} */
@Override
public void write(int b) throws IOException {
// We shouldn't be writing output at this stage, there
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/InterruptTimer.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/InterruptTimer.java
index 7e46afbc4b..888b8fbb09 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/InterruptTimer.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/InterruptTimer.java
@@ -104,10 +104,20 @@ public final class InterruptTimer {
*/
public void terminate() {
state.terminate();
+ boolean interrupted = false;
try {
- thread.join();
- } catch (InterruptedException e) {
- //
+ while (true) {
+ try {
+ thread.join();
+ return;
+ } catch (InterruptedException e) {
+ interrupted = true;
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/IsolatedOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/IsolatedOutputStream.java
index 2bbdbefd38..1faf6ea9aa 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/IsolatedOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/IsolatedOutputStream.java
@@ -58,13 +58,11 @@ public class IsolatedOutputStream extends OutputStream {
new ArrayBlockingQueue<>(1), new NamedThreadFactory());
}
- /** {@inheritDoc} */
@Override
public void write(int ch) throws IOException {
write(new byte[] { (byte) ch }, 0, 1);
}
- /** {@inheritDoc} */
@Override
public void write(byte[] buf, int pos, int cnt)
throws IOException {
@@ -75,7 +73,6 @@ public class IsolatedOutputStream extends OutputStream {
});
}
- /** {@inheritDoc} */
@Override
public void flush() throws IOException {
checkClosed();
@@ -85,7 +82,6 @@ public class IsolatedOutputStream extends OutputStream {
});
}
- /** {@inheritDoc} */
@Override
public void close() throws IOException {
if (!copier.isShutdown()) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/LimitedInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/LimitedInputStream.java
index 88006242d9..681a52988e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/LimitedInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/LimitedInputStream.java
@@ -47,21 +47,18 @@ public abstract class LimitedInputStream extends FilterInputStream {
this.limit = limit;
}
- /** {@inheritDoc} */
@Override
public int available() throws IOException {
return (int) Math.min(in.available(), left);
}
// it's okay to mark even if mark isn't supported, as reset won't work
- /** {@inheritDoc} */
@Override
public synchronized void mark(int readLimit) {
in.mark(readLimit);
mark = left;
}
- /** {@inheritDoc} */
@Override
public int read() throws IOException {
if (left == 0) {
@@ -78,7 +75,6 @@ public abstract class LimitedInputStream extends FilterInputStream {
return result;
}
- /** {@inheritDoc} */
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (left == 0) {
@@ -96,7 +92,6 @@ public abstract class LimitedInputStream extends FilterInputStream {
return result;
}
- /** {@inheritDoc} */
@Override
public synchronized void reset() throws IOException {
if (!in.markSupported())
@@ -109,7 +104,6 @@ public abstract class LimitedInputStream extends FilterInputStream {
left = mark;
}
- /** {@inheritDoc} */
@Override
public long skip(long n) throws IOException {
n = Math.min(n, left);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/MessageWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/MessageWriter.java
index 2637766153..8d5b8fdcba 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/MessageWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/MessageWriter.java
@@ -51,7 +51,6 @@ public class MessageWriter extends Writer {
enc = new OutputStreamWriter(getRawStream(), UTF_8);
}
- /** {@inheritDoc} */
@Override
public void write(char[] cbuf, int off, int len) throws IOException {
synchronized (buf) {
@@ -71,20 +70,17 @@ public class MessageWriter extends Writer {
return buf;
}
- /** {@inheritDoc} */
@Override
public void close() throws IOException {
// Do nothing, we are buffered with no resources.
}
- /** {@inheritDoc} */
@Override
public void flush() throws IOException {
// Do nothing, we are buffered with no resources.
}
/** @return string version of all buffered data. */
- /** {@inheritDoc} */
@Override
public String toString() {
return RawParseUtils.decode(buf.toByteArray());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SilentInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SilentInputStream.java
new file mode 100644
index 0000000000..8c2c61a434
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/SilentInputStream.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2025 Thomas Wolf <twolf@apache.org> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.util.io;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An {@link InputStream} that swallows exceptions on {@link #close()}.
+ *
+ * @since 7.4
+ */
+public class SilentInputStream extends FilterInputStream {
+
+ private static final Logger LOG = LoggerFactory
+ .getLogger(SilentInputStream.class);
+
+ /**
+ * Wraps an existing {@link InputStream}.
+ *
+ * @param in
+ * {@link InputStream} to wrap
+ */
+ public SilentInputStream(InputStream in) {
+ super(in);
+ }
+
+ @Override
+ public void close() throws IOException {
+ try {
+ super.close();
+ } catch (IOException e) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Exception ignored while closing input stream", e); //$NON-NLS-1$
+ }
+ }
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/StreamCopyThread.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/StreamCopyThread.java
index c0724e43f2..ed412fa6f5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/StreamCopyThread.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/StreamCopyThread.java
@@ -67,7 +67,6 @@ public class StreamCopyThread extends Thread {
}
}
- /** {@inheritDoc} */
@Override
public void run() {
try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TeeInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TeeInputStream.java
index 56d0169f7d..96376bfc6a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TeeInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TeeInputStream.java
@@ -46,7 +46,6 @@ public class TeeInputStream extends InputStream {
this.dst = dst;
}
- /** {@inheritDoc} */
@Override
public int read() throws IOException {
byte[] b = skipBuffer();
@@ -54,7 +53,6 @@ public class TeeInputStream extends InputStream {
return n == 1 ? b[0] & 0xff : -1;
}
- /** {@inheritDoc} */
@Override
public long skip(long count) throws IOException {
long skipped = 0;
@@ -71,7 +69,6 @@ public class TeeInputStream extends InputStream {
return skipped;
}
- /** {@inheritDoc} */
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (len == 0)
@@ -83,7 +80,6 @@ public class TeeInputStream extends InputStream {
return n;
}
- /** {@inheritDoc} */
@Override
public void close() throws IOException {
byte[] b = skipBuffer();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TeeOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TeeOutputStream.java
index e6fdd709b2..ab084a66f2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TeeOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TeeOutputStream.java
@@ -34,35 +34,30 @@ public class TeeOutputStream extends OutputStream {
this.stream2 = stream2;
}
- /** {@inheritDoc} */
@Override
public void write(byte[] buf) throws IOException {
this.stream1.write(buf);
this.stream2.write(buf);
}
- /** {@inheritDoc} */
@Override
public void write(byte[] buf, int off, int len) throws IOException {
this.stream1.write(buf, off, len);
this.stream2.write(buf, off, len);
}
- /** {@inheritDoc} */
@Override
public void write(int b) throws IOException {
this.stream1.write(b);
this.stream2.write(b);
}
- /** {@inheritDoc} */
@Override
public void flush() throws IOException {
this.stream1.flush();
this.stream2.flush();
}
- /** {@inheritDoc} */
@Override
public void close() throws IOException {
try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ThrowingPrintWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ThrowingPrintWriter.java
index 3bc92d5bcd..13982b133c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ThrowingPrintWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ThrowingPrintWriter.java
@@ -11,8 +11,6 @@ package org.eclipse.jgit.util.io;
import java.io.IOException;
import java.io.Writer;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
import org.eclipse.jgit.util.SystemReader;
@@ -35,25 +33,19 @@ public class ThrowingPrintWriter extends Writer {
*/
public ThrowingPrintWriter(Writer out) {
this.out = out;
- LF = AccessController
- .doPrivileged((PrivilegedAction<String>) () -> SystemReader
- .getInstance().getProperty("line.separator") //$NON-NLS-1$
- );
+ LF = SystemReader.getInstance().getProperty("line.separator"); //$NON-NLS-1$
}
- /** {@inheritDoc} */
@Override
public void write(char[] cbuf, int off, int len) throws IOException {
out.write(cbuf, off, len);
}
- /** {@inheritDoc} */
@Override
public void flush() throws IOException {
out.flush();
}
- /** {@inheritDoc} */
@Override
public void close() throws IOException {
out.close();
@@ -62,8 +54,10 @@ public class ThrowingPrintWriter extends Writer {
/**
* Print a string and terminate with a line feed.
*
- * @param s a {@link java.lang.String} object.
+ * @param s
+ * a {@link java.lang.String} object.
* @throws java.io.IOException
+ * if an IO error occurred
*/
public void println(String s) throws IOException {
print(s + LF);
@@ -73,6 +67,7 @@ public class ThrowingPrintWriter extends Writer {
* Print a platform dependent new line
*
* @throws java.io.IOException
+ * if an IO error occurred
*/
public void println() throws IOException {
print(LF);
@@ -81,8 +76,10 @@ public class ThrowingPrintWriter extends Writer {
/**
* Print a char
*
- * @param value a char.
+ * @param value
+ * a char.
* @throws java.io.IOException
+ * if an IO error occurred
*/
public void print(char value) throws IOException {
print(String.valueOf(value));
@@ -94,6 +91,7 @@ public class ThrowingPrintWriter extends Writer {
* @param value
* an int.
* @throws java.io.IOException
+ * if an IO error occurred
*/
public void print(int value) throws IOException {
print(String.valueOf(value));
@@ -102,8 +100,10 @@ public class ThrowingPrintWriter extends Writer {
/**
* Print a long as string
*
- * @param value a long.
+ * @param value
+ * a long.
* @throws java.io.IOException
+ * if an IO error occurred
*/
public void print(long value) throws IOException {
print(String.valueOf(value));
@@ -112,8 +112,10 @@ public class ThrowingPrintWriter extends Writer {
/**
* Print a short as string
*
- * @param value a short.
+ * @param value
+ * a short.
* @throws java.io.IOException
+ * if an IO error occurred
*/
public void print(short value) throws IOException {
print(String.valueOf(value));
@@ -128,6 +130,7 @@ public class ThrowingPrintWriter extends Writer {
* @param args
* objects.
* @throws java.io.IOException
+ * if an IO error occurred
*/
public void format(String fmt, Object... args) throws IOException {
print(String.format(fmt, args));
@@ -139,6 +142,7 @@ public class ThrowingPrintWriter extends Writer {
* @param any
* an object.
* @throws java.io.IOException
+ * if an IO error occurred
*/
public void print(Object any) throws IOException {
out.write(String.valueOf(any));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TimeoutInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TimeoutInputStream.java
index 1947b3bf04..4d9f83d233 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TimeoutInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TimeoutInputStream.java
@@ -63,7 +63,6 @@ public class TimeoutInputStream extends FilterInputStream {
timeout = millis;
}
- /** {@inheritDoc} */
@Override
public int read() throws IOException {
try {
@@ -76,13 +75,11 @@ public class TimeoutInputStream extends FilterInputStream {
}
}
- /** {@inheritDoc} */
@Override
public int read(byte[] buf) throws IOException {
return read(buf, 0, buf.length);
}
- /** {@inheritDoc} */
@Override
public int read(byte[] buf, int off, int cnt) throws IOException {
try {
@@ -95,7 +92,6 @@ public class TimeoutInputStream extends FilterInputStream {
}
}
- /** {@inheritDoc} */
@Override
public long skip(long cnt) throws IOException {
try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TimeoutOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TimeoutOutputStream.java
index 3fbf6ffdcb..afd798a1a2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TimeoutOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/TimeoutOutputStream.java
@@ -65,7 +65,6 @@ public class TimeoutOutputStream extends OutputStream {
timeout = millis;
}
- /** {@inheritDoc} */
@Override
public void write(int b) throws IOException {
try {
@@ -78,13 +77,11 @@ public class TimeoutOutputStream extends OutputStream {
}
}
- /** {@inheritDoc} */
@Override
public void write(byte[] buf) throws IOException {
write(buf, 0, buf.length);
}
- /** {@inheritDoc} */
@Override
public void write(byte[] buf, int off, int len) throws IOException {
try {
@@ -97,7 +94,6 @@ public class TimeoutOutputStream extends OutputStream {
}
}
- /** {@inheritDoc} */
@Override
public void flush() throws IOException {
try {
@@ -110,7 +106,6 @@ public class TimeoutOutputStream extends OutputStream {
}
}
- /** {@inheritDoc} */
@Override
public void close() throws IOException {
try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/UnionInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/UnionInputStream.java
index 459888190f..7e950f6529 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/UnionInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/UnionInputStream.java
@@ -12,8 +12,8 @@ package org.eclipse.jgit.util.io;
import java.io.IOException;
import java.io.InputStream;
-import java.util.Iterator;
-import java.util.LinkedList;
+import java.util.ArrayDeque;
+import java.util.Deque;
/**
* An InputStream which reads from one or more InputStreams.
@@ -34,7 +34,7 @@ public class UnionInputStream extends InputStream {
}
};
- private final LinkedList<InputStream> streams = new LinkedList<>();
+ private final Deque<InputStream> streams = new ArrayDeque<>();
/**
* Create an empty InputStream that is currently at EOF state.
@@ -91,7 +91,6 @@ public class UnionInputStream extends InputStream {
return streams.isEmpty();
}
- /** {@inheritDoc} */
@Override
public int read() throws IOException {
for (;;) {
@@ -106,7 +105,6 @@ public class UnionInputStream extends InputStream {
}
}
- /** {@inheritDoc} */
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (len == 0)
@@ -123,13 +121,11 @@ public class UnionInputStream extends InputStream {
}
}
- /** {@inheritDoc} */
@Override
public int available() throws IOException {
return head().available();
}
- /** {@inheritDoc} */
@Override
public long skip(long count) throws IOException {
long skipped = 0;
@@ -163,19 +159,18 @@ public class UnionInputStream extends InputStream {
return skipped;
}
- /** {@inheritDoc} */
@Override
public void close() throws IOException {
IOException err = null;
- for (Iterator<InputStream> i = streams.iterator(); i.hasNext();) {
+ for (InputStream stream : streams) {
try {
- i.next().close();
+ stream.close();
} catch (IOException closeError) {
err = closeError;
}
- i.remove();
}
+ streams.clear();
if (err != null)
throw err;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.java
index 56e90d0636..0a56c83040 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1.java
@@ -193,7 +193,6 @@ public abstract class SHA1 {
* <p>
* Implementations not supporting collision detection always return
* {@code false}.
- * <p>
*
* @return {@code true} if a likely collision was detected.
*/
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1Java.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1Java.java
index 213ee97531..33e6875883 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1Java.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/SHA1Java.java
@@ -407,7 +407,7 @@ class SHA1Java extends SHA1 {
private static int s1(int a, int b, int c, int d, int w_t) {
return rotateLeft(a, 5)
// f: 0 <= t <= 19
- + ((b & c) | ((~b) & d))
+ + ((b & c) | (~b & d))
+ 0x5A827999 + w_t;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/UbcCheck.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/UbcCheck.java
index cebdbee27a..91ee3cc9be 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/UbcCheck.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/sha1/UbcCheck.java
@@ -89,6 +89,7 @@ final class UbcCheck {
private static final int DV_II_55_0_bit = 1 << 30;
private static final int DV_II_56_0_bit = 1 << 31;
+ @SuppressWarnings("UnnecessaryParentheses")
static int check(int[] w) {
int mask = ~0;
mask &= (((((w[44] ^ w[45]) >>> 29) & 1) - 1) | ~(DV_I_48_0_bit
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicSystemClock.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicSystemClock.java
index 66857b5bf8..4e079f08b5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicSystemClock.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/time/MonotonicSystemClock.java
@@ -37,7 +37,6 @@ public class MonotonicSystemClock implements MonotonicClock {
}
}
- /** {@inheritDoc} */
@Override
public ProposedTimestamp propose() {
final long u = nowMicros();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/time/ProposedTimestamp.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/time/ProposedTimestamp.java
index 8c20423bc6..a20eaaf908 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/time/ProposedTimestamp.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/time/ProposedTimestamp.java
@@ -138,7 +138,10 @@ public abstract class ProposedTimestamp implements AutoCloseable {
* Get time since epoch, with up to microsecond resolution.
*
* @return time since epoch, with up to microsecond resolution.
+ *
+ * @deprecated Use instant() instead
*/
+ @Deprecated(since = "7.2")
public Timestamp timestamp() {
return Timestamp.from(instant());
}
@@ -147,7 +150,10 @@ public abstract class ProposedTimestamp implements AutoCloseable {
* Get time since epoch, with up to millisecond resolution.
*
* @return time since epoch, with up to millisecond resolution.
+ *
+ * @deprecated Use instant() instead
*/
+ @Deprecated(since = "7.2")
public Date date() {
return new Date(millis());
}
@@ -162,7 +168,6 @@ public abstract class ProposedTimestamp implements AutoCloseable {
// Do nothing by default.
}
- /** {@inheritDoc} */
@Override
public String toString() {
return instant().toString();