Browse Source

Merge branch 'stable-5.2' into stable-5.3

* stable-5.2:
  Prepare 5.2.3-SNAPSHOT builds
  JGit v5.2.2.201904231744-r
  Revert 4678f4b and provide another solution for bug 467631
  Apache MINA sshd: make sendKexInit() work also for re-keying
  Prepare 5.1.8-SNAPSHOT builds
  JGit v5.1.7.201904200442-r
  ObjectUploadListener: Add callback interface
  Prepare 4.11.9-SNAPSHOT builds
  JGit v4.11.8.201904181247-r
  Prepare 4.9.11-SNAPSHOT builds
  JGit v4.9.10.201904181027-r
  Prepare 4.7.10-SNAPSHOT builds
  JGit v4.7.9.201904161809-r
  Prepare 4.5.8-SNAPSHOT builds
  JGit v4.5.7.201904151645-r
  Remember the cause for invalidating a packfile
  Fix API problem filters
  Fix pack files scan when filesnapshot isn't modified

Change-Id: Ie7e572ac7e346f21fe0c387d7448be168a9c127a
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
tags/v5.3.1.201904271842-r
Matthias Sohn 5 years ago
parent
commit
32f0963b84

+ 27
- 0
org.eclipse.jgit.lfs.server/.settings/.api_filters View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<component id="org.eclipse.jgit.lfs.server" version="2">
<resource path="META-INF/MANIFEST.MF">
<filter id="924844039">
<message_arguments>
<message_argument value="5.3.1"/>
<message_argument value="5.3.0"/>
</message_arguments>
</filter>
</resource>
<resource path="src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java" type="org.eclipse.jgit.lfs.server.fs.ObjectUploadListener">
<filter id="1142947843">
<message_arguments>
<message_argument value="5.1.7"/>
<message_argument value="setCallback(ObjectUploadListener.Callback)"/>
</message_arguments>
</filter>
</resource>
<resource path="src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java" type="org.eclipse.jgit.lfs.server.fs.ObjectUploadListener$Callback">
<filter id="1142947843">
<message_arguments>
<message_argument value="5.1.7"/>
<message_argument value="Callback"/>
</message_arguments>
</filter>
</resource>
</component>

+ 45
- 2
org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java View File

@@ -48,6 +48,7 @@ import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.file.Path;
import java.util.logging.Level;
import java.util.logging.Logger;

@@ -87,6 +88,29 @@ public class ObjectUploadListener implements ReadListener {

private final ByteBuffer buffer = ByteBuffer.allocateDirect(8192);

private final Path path;

private long uploaded;

private Callback callback;

/**
* Callback invoked after object upload completed.
*
* @since 5.1.7
*/
public interface Callback {
/**
* Notified after object upload completed.
*
* @param path
* path to the object on the backend
* @param size
* uploaded size in bytes
*/
void uploadCompleted(String path, long size);
}

/**
* Constructor for ObjectUploadListener.
*
@@ -113,9 +137,24 @@ public class ObjectUploadListener implements ReadListener {
this.inChannel = Channels.newChannel(in);
this.out = repository.getOutputStream(id);
this.channel = Channels.newChannel(out);
this.path = repository.getPath(id);
this.uploaded = 0L;
response.setContentType(Constants.CONTENT_TYPE_GIT_LFS_JSON);
}

/**
* Set the callback to invoke after upload completed.
*
* @param callback
* the callback
* @return {@code this}.
* @since 5.1.7
*/
public ObjectUploadListener setCallback(Callback callback) {
this.callback = callback;
return this;
}

/**
* {@inheritDoc}
*
@@ -126,12 +165,13 @@ public class ObjectUploadListener implements ReadListener {
while (in.isReady()) {
if (inChannel.read(buffer) > 0) {
buffer.flip();
channel.write(buffer);
uploaded += Integer.valueOf(channel.write(buffer)).longValue();
buffer.compact();
} else {
buffer.flip();
while (buffer.hasRemaining()) {
channel.write(buffer);
uploaded += Integer.valueOf(channel.write(buffer))
.longValue();
}
close();
return;
@@ -159,6 +199,9 @@ public class ObjectUploadListener implements ReadListener {
if (!response.isCommitted()) {
response.setStatus(HttpServletResponse.SC_OK);
}
if (callback != null) {
callback.uploadCompleted(path.toString(), uploaded);
}
} finally {
context.complete();
}

+ 26
- 21
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java View File

@@ -149,10 +149,27 @@ public class JGitClientSession extends ClientSessionImpl {
@Override
protected IoWriteFuture sendIdentification(String ident)
throws IOException {
// Nothing; we do this below together with the KEX init in
// sendStartSsh(). Called only from the ClientSessionImpl constructor,
// where the return value is ignored.
return null;
StatefulProxyConnector proxy = proxyHandler;
if (proxy != null) {
try {
// We must not block here; the framework starts reading messages
// from the peer only once the initial sendKexInit() following
// this call to sendIdentification() has returned!
proxy.runWhenDone(() -> {
JGitClientSession.super.sendIdentification(ident);
return null;
});
// Called only from the ClientSessionImpl constructor, where the
// return value is ignored.
return null;
} catch (IOException e) {
throw e;
} catch (Exception other) {
throw new IOException(other.getLocalizedMessage(), other);
}
} else {
return super.sendIdentification(ident);
}
}

@Override
@@ -161,12 +178,13 @@ public class JGitClientSession extends ClientSessionImpl {
if (proxy != null) {
try {
// We must not block here; the framework starts reading messages
// from the peer only once sendKexInit() has returned!
// from the peer only once the initial sendKexInit() has
// returned!
proxy.runWhenDone(() -> {
sendStartSsh();
JGitClientSession.super.sendKexInit();
return null;
});
// sendKexInit() is called only from the ClientSessionImpl
// This is called only from the ClientSessionImpl
// constructor, where the return value is ignored.
return null;
} catch (IOException e) {
@@ -175,23 +193,10 @@ public class JGitClientSession extends ClientSessionImpl {
throw new IOException(other.getLocalizedMessage(), other);
}
} else {
return sendStartSsh();
return super.sendKexInit();
}
}

/**
* Sends the initial messages starting the ssh setup: the client
* identification and the KEX init message.
*
* @return the client's KEX seed
* @throws IOException
* if something goes wrong
*/
private byte[] sendStartSsh() throws IOException {
super.sendIdentification(clientVersion);
return super.sendKexInit();
}

/**
* {@inheritDoc}
*

+ 12
- 8
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/AbstractClientProxyConnector.java View File

@@ -43,7 +43,9 @@
package org.eclipse.jgit.internal.transport.sshd.proxy;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
@@ -61,12 +63,12 @@ public abstract class AbstractClientProxyConnector
private static final long DEFAULT_PROXY_TIMEOUT_MILLIS = TimeUnit.SECONDS
.toMillis(30L);

/** Guards {@link #done} and {@link #startSsh}. */
/** Guards {@link #done} and {@link #bufferedCommands}. */
private Object lock = new Object();

private boolean done;

private Callable<Void> startSsh;
private List<Callable<Void>> bufferedCommands = new ArrayList<>();

private AtomicReference<Runnable> unregister = new AtomicReference<>();

@@ -173,18 +175,20 @@ public abstract class AbstractClientProxyConnector
* if starting ssh fails
*/
protected void setDone(boolean success) throws Exception {
Callable<Void> starter;
List<Callable<Void>> buffered;
Runnable unset = unregister.getAndSet(null);
if (unset != null) {
unset.run();
}
synchronized (lock) {
done = true;
starter = startSsh;
startSsh = null;
buffered = bufferedCommands;
bufferedCommands = null;
}
if (success && starter != null) {
starter.call();
if (success && buffered != null) {
for (Callable<Void> starter : buffered) {
starter.call();
}
}
}

@@ -192,7 +196,7 @@ public abstract class AbstractClientProxyConnector
public void runWhenDone(Callable<Void> starter) throws Exception {
synchronized (lock) {
if (!done) {
this.startSsh = starter;
bufferedCommands.add(starter);
return;
}
}

+ 6
- 3
org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/StatefulProxyConnector.java View File

@@ -78,12 +78,15 @@ public interface StatefulProxyConnector extends ClientProxyConnector {
void messageReceived(IoSession session, Readable buffer) throws Exception;

/**
* Runs {@code startSsh} once the proxy connection is established.
* Runs {@code command} once the proxy connection is established. May be
* called multiple times; commands are run sequentially. If the proxy
* connection is already established, {@code command} is executed directly
* synchronously.
*
* @param startSsh
* @param command
* operation to run
* @throws Exception
* if the operation is run synchronously and throws an exception
*/
void runWhenDone(Callable<Void> startSsh) throws Exception;
void runWhenDone(Callable<Void> command) throws Exception;
}

+ 63
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffEntryTest.java View File

@@ -59,9 +59,12 @@ import org.eclipse.jgit.diff.DiffEntry.ChangeType;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEditor;
import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.treewalk.EmptyTreeIterator;
import org.eclipse.jgit.treewalk.FileTreeIterator;
@@ -417,4 +420,64 @@ public class DiffEntryTest extends RepositoryTestCase {
assertEquals(FileMode.REGULAR_FILE, diff.getOldMode());
}
}

@Test
public void shouldReportSubmoduleReplacedByFileMove() throws Exception {
// Create a submodule
FileRepository submoduleStandalone = createWorkRepository();
JGitTestUtil.writeTrashFile(submoduleStandalone, "fileInSubmodule",
"submodule");
Git submoduleStandaloneGit = Git.wrap(submoduleStandalone);
submoduleStandaloneGit.add().addFilepattern("fileInSubmodule").call();
submoduleStandaloneGit.commit().setMessage("add file to submodule")
.call();

Repository submodule_db = Git.wrap(db).submoduleAdd()
.setPath("modules/submodule")
.setURI(submoduleStandalone.getDirectory().toURI().toString())
.call();
File submodule_trash = submodule_db.getWorkTree();
addRepoToClose(submodule_db);
writeTrashFile("fileInRoot", "root");
Git rootGit = Git.wrap(db);
rootGit.add().addFilepattern("fileInRoot").call();
rootGit.commit().setMessage("add submodule and root file").call();
// Dummy change on fileInRoot
writeTrashFile("fileInRoot", "changed");
rootGit.add().addFilepattern("fileInRoot").call();
RevCommit firstCommit = rootGit.commit().setMessage("change root file")
.call();
// Remove the submodule again and move fileInRoot into that subfolder
rootGit.rm().setCached(true).addFilepattern("modules/submodule").call();
recursiveDelete(submodule_trash);
JGitTestUtil.deleteTrashFile(db, "fileInRoot");
// Move the fileInRoot file
writeTrashFile("modules/submodule/fileInRoot", "changed");
rootGit.rm().addFilepattern("fileInRoot").addFilepattern("modules/")
.call();
rootGit.add().addFilepattern("modules/").call();
RevCommit secondCommit = rootGit.commit()
.setMessage("remove submodule and move root file")
.call();
// Diff should report submodule having been deleted and file moved
// (deleted and added)
try (TreeWalk walk = new TreeWalk(db)) {
walk.addTree(firstCommit.getTree());
walk.addTree(secondCommit.getTree());
walk.setRecursive(true);
List<DiffEntry> diffs = DiffEntry.scan(walk);
assertEquals(3, diffs.size());
DiffEntry e = diffs.get(0);
assertEquals(DiffEntry.ChangeType.DELETE, e.getChangeType());
assertEquals("fileInRoot", e.getOldPath());
e = diffs.get(1);
assertEquals(DiffEntry.ChangeType.DELETE, e.getChangeType());
assertEquals("modules/submodule", e.getOldPath());
assertEquals(FileMode.GITLINK, e.getOldMode());
e = diffs.get(2);
assertEquals(DiffEntry.ChangeType.ADD, e.getChangeType());
assertEquals("modules/submodule/fileInRoot", e.getNewPath());
}

}
}

+ 33
- 1
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java View File

@@ -43,12 +43,14 @@

package org.eclipse.jgit.lib;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Set;

import org.eclipse.jgit.api.CloneCommand;
@@ -128,7 +130,8 @@ public class IndexDiffSubmoduleTest extends RepositoryTestCase {
IndexDiff indexDiff = new IndexDiff(db2, Constants.HEAD,
new FileTreeIterator(db2));
indexDiff.setIgnoreSubmoduleMode(mode);
assertFalse(indexDiff.diff());
boolean changed = indexDiff.diff();
assertFalse(changed);
}

@Theory
@@ -263,4 +266,33 @@ public class IndexDiffSubmoduleTest extends RepositoryTestCase {
assertDiff(indexDiff, mode, IgnoreSubmoduleMode.ALL,
IgnoreSubmoduleMode.DIRTY, IgnoreSubmoduleMode.UNTRACKED);
}

@Theory
public void testSubmoduleReplacedByMovedFile(IgnoreSubmoduleMode mode)
throws Exception {
Git git = Git.wrap(db);
git.rm().setCached(true).addFilepattern("modules/submodule").call();
recursiveDelete(submodule_trash);
JGitTestUtil.deleteTrashFile(db, "fileInRoot");
// Move the fileInRoot file
writeTrashFile("modules/submodule/fileInRoot", "root");
git.rm().addFilepattern("fileInRoot").addFilepattern("modules/").call();
git.add().addFilepattern("modules/").call();
IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
new FileTreeIterator(db));
indexDiff.setIgnoreSubmoduleMode(mode);
assertTrue(indexDiff.diff());
String[] removed = indexDiff.getRemoved().toArray(new String[0]);
Arrays.sort(removed);
if (IgnoreSubmoduleMode.ALL.equals(mode)) {
assertArrayEquals(new String[] { "fileInRoot" }, removed);
} else {
assertArrayEquals(
new String[] { "fileInRoot", "modules/submodule" },
removed);
}
assertEquals("[modules/submodule/fileInRoot]",
indexDiff.getAdded().toString());
}

}

+ 0
- 18
org.eclipse.jgit.test/tst/org/eclipse/jgit/util/PathsTest.java View File

@@ -88,30 +88,15 @@ public class PathsTest {
assertEquals(0, compare(
a, 0, a.length, FileMode.TREE.getBits(),
b, 0, b.length, FileMode.TREE.getBits()));
assertEquals(0, compare(
a, 0, a.length, FileMode.TREE.getBits(),
b, 0, b.length, FileMode.GITLINK.getBits()));
assertEquals(0, compare(
a, 0, a.length, FileMode.GITLINK.getBits(),
b, 0, b.length, FileMode.GITLINK.getBits()));
assertEquals(0, compare(
a, 0, a.length, FileMode.GITLINK.getBits(),
b, 0, b.length, FileMode.TREE.getBits()));
assertEquals(0, compare(
a, 0, a.length, FileMode.REGULAR_FILE.getBits(),
b, 0, b.length, FileMode.REGULAR_FILE.getBits()));
assertEquals(-47, compare(
a, 0, a.length, FileMode.REGULAR_FILE.getBits(),
b, 0, b.length, FileMode.TREE.getBits()));
assertEquals(0, compare(
a, 0, a.length, FileMode.REGULAR_FILE.getBits(),
b, 0, b.length, FileMode.GITLINK.getBits()));
assertEquals(47, compare(
a, 0, a.length, FileMode.TREE.getBits(),
b, 0, b.length, FileMode.REGULAR_FILE.getBits()));
assertEquals(0, compare(
a, 0, a.length, FileMode.GITLINK.getBits(),
b, 0, b.length, FileMode.REGULAR_FILE.getBits()));

assertEquals(0, compareSameName(
a, 0, a.length,
@@ -119,9 +104,6 @@ public class PathsTest {
assertEquals(0, compareSameName(
a, 0, a.length,
b, 0, b.length, FileMode.REGULAR_FILE.getBits()));
assertEquals(0, compareSameName(
a, 0, a.length,
b, 0, b.length, FileMode.GITLINK.getBits()));

a = Constants.encode("a.c");
b = Constants.encode("a");

+ 10
- 4
org.eclipse.jgit/.settings/.api_filters View File

@@ -3,16 +3,22 @@
<resource path="META-INF/MANIFEST.MF">
<filter id="924844039">
<message_arguments>
<message_argument value="5.3.0"/>
<message_argument value="5.3.1"/>
<message_argument value="5.3.0"/>
</message_arguments>
</filter>
</resource>
<resource path="src/org/eclipse/jgit/util/FS.java" type="org.eclipse.jgit.util.FS">
<resource path="src/org/eclipse/jgit/errors/PackInvalidException.java" type="org.eclipse.jgit.errors.PackInvalidException">
<filter id="1142947843">
<message_arguments>
<message_argument value="4.5.7"/>
<message_argument value="PackInvalidException(File, Throwable)"/>
</message_arguments>
</filter>
<filter id="1142947843">
<message_arguments>
<message_argument value="4.5.6"/>
<message_argument value="fileAttributes(File)"/>
<message_argument value="4.5.7"/>
<message_argument value="PackInvalidException(String, Throwable)"/>
</message_arguments>
</filter>
</resource>

+ 32
- 2
org.eclipse.jgit/src/org/eclipse/jgit/errors/PackInvalidException.java View File

@@ -60,9 +60,24 @@ public class PackInvalidException extends IOException {
*
* @param path
* path of the invalid pack file.
* @deprecated Use {@link #PackInvalidException(File, Throwable)}.
*/
@Deprecated
public PackInvalidException(File path) {
this(path.getAbsolutePath());
this(path, null);
}

/**
* Construct a pack invalid error with cause.
*
* @param path
* path of the invalid pack file.
* @param cause
* cause of the pack file becoming invalid.
* @since 4.5.7
*/
public PackInvalidException(File path, Throwable cause) {
this(path.getAbsolutePath(), cause);
}

/**
@@ -70,8 +85,23 @@ public class PackInvalidException extends IOException {
*
* @param path
* path of the invalid pack file.
* @deprecated Use {@link #PackInvalidException(String, Throwable)}.
*/
@Deprecated
public PackInvalidException(String path) {
super(MessageFormat.format(JGitText.get().packFileInvalid, path));
this(path, null);
}

/**
* Construct a pack invalid error with cause.
*
* @param path
* path of the invalid pack file.
* @param cause
* cause of the pack file becoming invalid.
* @since 4.5.7
*/
public PackInvalidException(String path, Throwable cause) {
super(MessageFormat.format(JGitText.get().packFileInvalid, path), cause);
}
}

+ 6
- 2
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BlockBasedFile.java View File

@@ -83,6 +83,9 @@ abstract class BlockBasedFile {
/** True once corruption has been detected that cannot be worked around. */
volatile boolean invalid;

/** Exception that caused the packfile to be flagged as invalid */
protected volatile Exception invalidatingCause;

BlockBasedFile(DfsBlockCache cache, DfsPackDescription desc, PackExt ext) {
this.cache = cache;
this.key = desc.getStreamKey(ext);
@@ -136,8 +139,9 @@ abstract class BlockBasedFile {

DfsBlock readOneBlock(long pos, DfsReader ctx, ReadableChannel rc)
throws IOException {
if (invalid)
throw new PackInvalidException(getFileName());
if (invalid) {
throw new PackInvalidException(getFileName(), invalidatingCause);
}

ctx.stats.readBlock++;
long start = System.nanoTime();

+ 5
- 2
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java View File

@@ -181,7 +181,7 @@ public final class DfsPackFile extends BlockBasedFile {
}

if (invalid) {
throw new PackInvalidException(getFileName());
throw new PackInvalidException(getFileName(), invalidatingCause);
}

Repository.getGlobalListenerList()
@@ -240,6 +240,7 @@ public final class DfsPackFile extends BlockBasedFile {
return index;
} catch (IOException e) {
invalid = true;
invalidatingCause = e;
throw e;
}
}
@@ -703,8 +704,10 @@ public final class DfsPackFile extends BlockBasedFile {

private IOException packfileIsTruncated() {
invalid = true;
return new IOException(MessageFormat.format(
IOException exc = new IOException(MessageFormat.format(
JGitText.get().packfileIsTruncated, getFileName()));
invalidatingCause = exc;
return exc;
}

private void readFully(long position, byte[] dstbuf, int dstoff, int cnt,

+ 8
- 12
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java View File

@@ -132,8 +132,6 @@ public class ObjectDirectory extends FileObjectDatabase {

private final File alternatesFile;

private final AtomicReference<PackList> packList;

private final FS fs;

private final AtomicReference<AlternateHandle[]> alternates;
@@ -146,6 +144,8 @@ public class ObjectDirectory extends FileObjectDatabase {

private Set<ObjectId> shallowCommitsIds;

final AtomicReference<PackList> packList;

/**
* Initialize a reference to an on-disk object directory.
*
@@ -673,13 +673,8 @@ public class ObjectDirectory extends FileObjectDatabase {
transientErrorCount = p.incrementTransientErrorCount();
}
if (warnTmpl != null) {
if (LOG.isDebugEnabled()) {
LOG.debug(MessageFormat.format(warnTmpl,
p.getPackFile().getAbsolutePath()), e);
} else {
LOG.warn(MessageFormat.format(warnTmpl,
p.getPackFile().getAbsolutePath()));
}
LOG.warn(MessageFormat.format(warnTmpl,
p.getPackFile().getAbsolutePath()), e);
} else {
if (doLogExponentialBackoff(transientErrorCount)) {
// Don't remove the pack from the list, as the error may be
@@ -766,7 +761,7 @@ public class ObjectDirectory extends FileObjectDatabase {
return InsertLooseObjectResult.FAILURE;
}

private boolean searchPacksAgain(PackList old) {
boolean searchPacksAgain(PackList old) {
// Whether to trust the pack folder's modification time. If set
// to false we will always scan the .git/objects/pack folder to
// check for new pack files. If set to true (default) we use the
@@ -916,7 +911,8 @@ public class ObjectDirectory extends FileObjectDatabase {
final String packName = base + PACK.getExtension();
final File packFile = new File(packDirectory, packName);
final PackFile oldPack = forReuse.remove(packName);
if (oldPack != null && oldPack.getFileSnapshot().isModified(packFile)) {
if (oldPack != null
&& !oldPack.getFileSnapshot().isModified(packFile)) {
list.add(oldPack);
continue;
}
@@ -1073,7 +1069,7 @@ public class ObjectDirectory extends FileObjectDatabase {
return new File(new File(getDirectory(), d), f);
}

private static final class PackList {
static final class PackList {
/** State just before reading the pack directory. */
final FileSnapshot snapshot;


+ 12
- 8
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java View File

@@ -135,6 +135,8 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> {

private volatile boolean invalid;

private volatile Exception invalidatingCause;

private boolean invalidBitmap;

private AtomicInteger transientErrorCount = new AtomicInteger();
@@ -184,7 +186,7 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> {
idx = loadedIdx;
if (idx == null) {
if (invalid) {
throw new PackInvalidException(packFile);
throw new PackInvalidException(packFile, invalidatingCause);
}
try {
idx = PackIndex.open(extFile(INDEX));
@@ -208,6 +210,7 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> {
throw e;
} catch (IOException e) {
invalid = true;
invalidatingCause = e;
throw e;
}
}
@@ -661,7 +664,7 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> {

private void doOpen() throws IOException {
if (invalid) {
throw new PackInvalidException(packFile);
throw new PackInvalidException(packFile, invalidatingCause);
}
try {
synchronized (readLock) {
@@ -671,13 +674,13 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> {
}
} catch (InterruptedIOException e) {
// don't invalidate the pack, we are interrupted from another thread
openFail(false);
openFail(false, e);
throw e;
} catch (FileNotFoundException fn) {
// don't invalidate the pack if opening an existing file failed
// since it may be related to a temporary lack of resources (e.g.
// max open files)
openFail(!packFile.exists());
openFail(!packFile.exists(), fn);
throw fn;
} catch (EOFException | AccessDeniedException | NoSuchFileException
| CorruptObjectException | NoPackSignatureException
@@ -685,20 +688,21 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> {
| UnsupportedPackIndexVersionException
| UnsupportedPackVersionException pe) {
// exceptions signaling permanent problems with a pack
openFail(true);
openFail(true, pe);
throw pe;
} catch (IOException | RuntimeException ge) {
// generic exceptions could be transient so we should not mark the
// pack invalid to avoid false MissingObjectExceptions
openFail(false);
openFail(false, ge);
throw ge;
}
}

private void openFail(boolean invalidate) {
private void openFail(boolean invalidate, Exception cause) {
activeWindows = 0;
activeCopyRawData = 0;
invalid = invalidate;
invalidatingCause = cause;
doClose();
}

@@ -725,7 +729,7 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> {
// Detect the situation and throw a proper exception so that can be properly
// managed by the main packfile search loop and the Git client won't receive
// any failures.
throw new PackInvalidException(packFile);
throw new PackInvalidException(packFile, invalidatingCause);
}
if (length < pos + size)
size = (int) (length - pos);

+ 40
- 4
org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java View File

@@ -47,7 +47,11 @@

package org.eclipse.jgit.lib;

import java.io.File;
import java.io.IOException;
import java.nio.file.DirectoryIteratorException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
@@ -261,6 +265,8 @@ public class IndexDiff {

private Set<String> missing = new HashSet<>();

private Set<String> missingSubmodules = new HashSet<>();

private Set<String> modified = new HashSet<>();

private Set<String> untracked = new HashSet<>();
@@ -501,9 +507,15 @@ public class IndexDiff {
if (dirCacheIterator != null) {
if (workingTreeIterator == null) {
// in index, not in workdir => missing
if (!isEntryGitLink(dirCacheIterator)
|| ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL)
missing.add(treeWalk.getPathString());
boolean isGitLink = isEntryGitLink(dirCacheIterator);
if (!isGitLink
|| ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL) {
String path = treeWalk.getPathString();
missing.add(path);
if (isGitLink) {
missingSubmodules.add(path);
}
}
} else {
if (workingTreeIterator.isModified(
dirCacheIterator.getDirCacheEntry(), true,
@@ -543,8 +555,8 @@ public class IndexDiff {
smw.getPath()), e);
}
try (Repository subRepo = smw.getRepository()) {
String subRepoPath = smw.getPath();
if (subRepo != null) {
String subRepoPath = smw.getPath();
ObjectId subHead = subRepo.resolve("HEAD"); //$NON-NLS-1$
if (subHead != null
&& !subHead.equals(smw.getObjectId())) {
@@ -573,6 +585,21 @@ public class IndexDiff {
recordFileMode(subRepoPath, FileMode.GITLINK);
}
}
} else if (missingSubmodules.remove(subRepoPath)) {
// If the directory is there and empty but the submodule
// repository in .git/modules doesn't exist yet it isn't
// "missing".
File gitDir = new File(
new File(repository.getDirectory(),
Constants.MODULES),
subRepoPath);
if (!gitDir.isDirectory()) {
File dir = SubmoduleWalk.getSubmoduleDirectory(
repository, subRepoPath);
if (dir.isDirectory() && !hasFiles(dir)) {
missing.remove(subRepoPath);
}
}
}
}
}
@@ -592,6 +619,15 @@ public class IndexDiff {
return true;
}

private boolean hasFiles(File directory) {
try (DirectoryStream<java.nio.file.Path> dir = Files
.newDirectoryStream(directory.toPath())) {
return dir.iterator().hasNext();
} catch (DirectoryIteratorException | IOException e) {
return false;
}
}

private void recordFileMode(String path, FileMode mode) {
Set<String> values = fileModes.get(mode);
if (path != null) {

+ 2
- 12
org.eclipse.jgit/src/org/eclipse/jgit/util/Paths.java View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016, 2018 Google Inc.
* Copyright (C) 2016, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -43,7 +43,6 @@

package org.eclipse.jgit.util;

import static org.eclipse.jgit.lib.FileMode.TYPE_GITLINK;
import static org.eclipse.jgit.lib.FileMode.TYPE_MASK;
import static org.eclipse.jgit.lib.FileMode.TYPE_TREE;

@@ -107,7 +106,7 @@ public class Paths {
aPath, aPos, aEnd, aMode,
bPath, bPos, bEnd, bMode);
if (cmp == 0) {
cmp = modeCompare(aMode, bMode);
cmp = lastPathChar(aMode) - lastPathChar(bMode);
}
return cmp;
}
@@ -184,15 +183,6 @@ public class Paths {
return 0;
}

private static int modeCompare(int aMode, int bMode) {
if ((aMode & TYPE_MASK) == TYPE_GITLINK
|| (bMode & TYPE_MASK) == TYPE_GITLINK) {
// Git links can be equal to files or folders
return 0;
}
return lastPathChar(aMode) - lastPathChar(bMode);
}

private Paths() {
}
}

Loading…
Cancel
Save