aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Strapetz2010-08-31 07:26:29 (EDT)
committerShawn O. Pearce2010-08-31 15:08:09 (EDT)
commit253b36d27a3d249ec8290b99bf38275d003766e1 (patch)
tree7f40eb1532df06f7ec33c99b2841675a89317083
parentb3aa5802b9acc0b3a3861bc0483d13cd537b2d77 (diff)
downloadjgit-253b36d27a3d249ec8290b99bf38275d003766e1.zip
jgit-253b36d27a3d249ec8290b99bf38275d003766e1.tar.gz
jgit-253b36d27a3d249ec8290b99bf38275d003766e1.tar.bz2
Partial support for index file format "3".refs/changes/46/1446/4
Extended flags are processed and available via DirCacheEntry's new isSkipWorkTree() and isIntentToAdd() methods. "resolve-undo" information is completely ignored since its an optional extension. Change-Id: Ie6e9c6784c9f265ca3c013c6dc0e6bd29d3b7233
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.index.v3.skipWorkTreebin0 -> 741 bytes
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java32
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java24
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java72
6 files changed, 115 insertions, 15 deletions
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.index.v3.skipWorkTree b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.index.v3.skipWorkTree
new file mode 100644
index 0000000..4cbd703
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.index.v3.skipWorkTree
Binary files differ
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java
index f37d040..f5cdfae 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java
@@ -44,10 +44,12 @@
package org.eclipse.jgit.dircache;
import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -59,6 +61,7 @@ import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.JGitTestUtil;
public class DirCacheCGitCompatabilityTest extends LocalDiskRepositoryTestCase {
@@ -179,6 +182,35 @@ public class DirCacheCGitCompatabilityTest extends LocalDiskRepositoryTestCase {
}
}
+ public void testReadWriteV3() throws Exception {
+ final File file = pathOf("gitgit.index.v3.skipWorkTree");
+ final DirCache dc = new DirCache(file, FS.DETECTED);
+ dc.read();
+
+ assertEquals(7, dc.getEntryCount());
+ assertV3TreeEntry(0, "dir1/file1.txt", false, false, dc);
+ assertV3TreeEntry(1, "dir2/file2.txt", true, false, dc);
+ assertV3TreeEntry(2, "dir3/file3.txt", false, false, dc);
+ assertV3TreeEntry(3, "dir3/file3a.txt", true, false, dc);
+ assertV3TreeEntry(4, "dir4/file4.txt", true, false, dc);
+ assertV3TreeEntry(5, "dir4/file4a.txt", false, false, dc);
+ assertV3TreeEntry(6, "file.txt", true, false, dc);
+
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ dc.writeTo(bos);
+ final byte[] indexBytes = bos.toByteArray();
+ final byte[] expectedBytes = IO.readFully(file);
+ assertTrue(Arrays.equals(expectedBytes, indexBytes));
+ }
+
+ private static void assertV3TreeEntry(int indexPosition, String path,
+ boolean skipWorkTree, boolean intentToAdd, DirCache dc) {
+ final DirCacheEntry entry = dc.getEntry(indexPosition);
+ assertEquals(path, entry.getPathString());
+ assertEquals(skipWorkTree, entry.isSkipWorkTree());
+ assertEquals(intentToAdd, entry.isIntentToAdd());
+ }
+
private File pathOf(final String name) {
return JGitTestUtil.getTestResourceFile(name);
}
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
index 14c0ba0..5bebd18 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
@@ -2,6 +2,7 @@ DIRCChecksumMismatch=DIRC checksum mismatch
DIRCExtensionIsTooLargeAt=DIRC extension {0} is too large at {1} bytes.
DIRCExtensionNotSupportedByThisVersion=DIRC extension {0} not supported by this version.
DIRCHasTooManyEntries=DIRC has too many entries.
+DIRCUnrecognizedExtendedFlags=Unrecognized extended flags: {0}
JRELacksMD5Implementation=JRE lacks MD5 implementation
URINotSupported=URI not supported: {0}
URLNotFound={0} not found
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
index ea40fe8..927fa7c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
@@ -62,6 +62,7 @@ public class JGitText extends TranslationBundle {
/***/ public String DIRCExtensionIsTooLargeAt;
/***/ public String DIRCExtensionNotSupportedByThisVersion;
/***/ public String DIRCHasTooManyEntries;
+ /***/ public String DIRCUnrecognizedExtendedFlags;
/***/ public String JRELacksMD5Implementation;
/***/ public String URINotSupported;
/***/ public String URLNotFound;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
index a117c8d..143447c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
@@ -91,8 +91,6 @@ public class DirCache {
private static final int EXT_TREE = 0x54524545 /* 'TREE' */;
- private static final int INFO_LEN = DirCacheEntry.INFO_LEN;
-
private static final DirCacheEntry[] NO_ENTRIES = {};
static final Comparator<DirCacheEntry> ENT_CMP = new Comparator<DirCacheEntry>() {
@@ -322,7 +320,7 @@ public class DirCache {
tree = null;
}
- private void readFrom(final FileInputStream inStream) throws IOException,
+ private void readFrom(final InputStream inStream) throws IOException,
CorruptObjectException {
final BufferedInputStream in = new BufferedInputStream(inStream);
final MessageDigest md = Constants.newMessageDigest();
@@ -335,7 +333,10 @@ public class DirCache {
if (!is_DIRC(hdr))
throw new CorruptObjectException(JGitText.get().notADIRCFile);
final int ver = NB.decodeInt32(hdr, 4);
- if (ver != 2)
+ boolean extended = false;
+ if (ver == 3)
+ extended = true;
+ else if (ver != 2)
throw new CorruptObjectException(MessageFormat.format(JGitText.get().unknownDIRCVersion, ver));
entryCnt = NB.decodeInt32(hdr, 8);
if (entryCnt < 0)
@@ -343,10 +344,13 @@ public class DirCache {
// Load the individual file entries.
//
- final byte[] infos = new byte[INFO_LEN * entryCnt];
+ final int infoLength = DirCacheEntry.getMaximumInfoLength(extended);
+ final byte[] infos = new byte[infoLength * entryCnt];
sortedEntries = new DirCacheEntry[entryCnt];
+
+ final MutableInteger infoAt = new MutableInteger();
for (int i = 0; i < entryCnt; i++)
- sortedEntries[i] = new DirCacheEntry(infos, i * INFO_LEN, in, md);
+ sortedEntries[i] = new DirCacheEntry(infos, infoAt, in, md);
lastModified = liveFile.lastModified();
// After the file entries are index extensions, and then a footer.
@@ -484,15 +488,19 @@ public class DirCache {
}
}
- private void writeTo(final OutputStream os) throws IOException {
+ void writeTo(final OutputStream os) throws IOException {
final MessageDigest foot = Constants.newMessageDigest();
final DigestOutputStream dos = new DigestOutputStream(os, foot);
+ boolean extended = false;
+ for (int i = 0; i < entryCnt; i++)
+ extended |= sortedEntries[i].isExtended();
+
// Write the header.
//
final byte[] tmp = new byte[128];
System.arraycopy(SIG_DIRC, 0, tmp, 0, SIG_DIRC.length);
- NB.encodeInt32(tmp, 4, /* version */2);
+ NB.encodeInt32(tmp, 4, extended ? 3 : 2);
NB.encodeInt32(tmp, 8, entryCnt);
dos.write(tmp, 0, 12);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
index 308d4d1..defab97 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
@@ -62,6 +62,7 @@ import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.util.IO;
+import org.eclipse.jgit.util.MutableInteger;
import org.eclipse.jgit.util.NB;
/**
@@ -108,12 +109,19 @@ public class DirCacheEntry {
private static final int P_OBJECTID = 40;
private static final int P_FLAGS = 60;
+ private static final int P_FLAGS2 = 62;
/** Mask applied to data in {@link #P_FLAGS} to get the name length. */
private static final int NAME_MASK = 0xfff;
- static final int INFO_LEN = 62;
+ private static final int INTENT_TO_ADD = 0x20000000;
+ private static final int SKIP_WORKTREE = 0x40000000;
+ private static final int EXTENDED_FLAGS = (INTENT_TO_ADD | SKIP_WORKTREE);
+ private static final int INFO_LEN = 62;
+ private static final int INFO_LEN_EXTENDED = 64;
+
+ private static final int EXTENDED = 0x40;
private static final int ASSUME_VALID = 0x80;
/** In-core flag signaling that the entry should be considered as modified. */
@@ -131,13 +139,26 @@ public class DirCacheEntry {
/** Flags which are never stored to disk. */
private byte inCoreFlags;
- DirCacheEntry(final byte[] sharedInfo, final int infoAt,
+ DirCacheEntry(final byte[] sharedInfo, final MutableInteger infoAt,
final InputStream in, final MessageDigest md) throws IOException {
info = sharedInfo;
- infoOffset = infoAt;
+ infoOffset = infoAt.value;
IO.readFully(in, info, infoOffset, INFO_LEN);
- md.update(info, infoOffset, INFO_LEN);
+
+ final int len;
+ if (isExtended()) {
+ len = INFO_LEN_EXTENDED;
+ IO.readFully(in, info, infoOffset + INFO_LEN, INFO_LEN_EXTENDED - INFO_LEN);
+
+ if ((getExtendedFlags() & ~EXTENDED_FLAGS) != 0)
+ throw new IOException(MessageFormat.format(JGitText.get()
+ .DIRCUnrecognizedExtendedFlags, String.valueOf(getExtendedFlags())));
+ } else
+ len = INFO_LEN;
+
+ infoAt.value += len;
+ md.update(info, infoOffset, len);
int pathLen = NB.decodeUInt16(info, infoOffset + P_FLAGS) & NAME_MASK;
int skipped = 0;
@@ -170,7 +191,7 @@ public class DirCacheEntry {
// Index records are padded out to the next 8 byte alignment
// for historical reasons related to how C Git read the files.
//
- final int actLen = INFO_LEN + pathLen;
+ final int actLen = len + pathLen;
final int expLen = (actLen + 8) & ~7;
final int padLen = expLen - actLen - skipped;
if (padLen > 0) {
@@ -258,14 +279,15 @@ public class DirCacheEntry {
}
void write(final OutputStream os) throws IOException {
+ final int len = isExtended() ? INFO_LEN_EXTENDED : INFO_LEN;
final int pathLen = path.length;
- os.write(info, infoOffset, INFO_LEN);
+ os.write(info, infoOffset, len);
os.write(path, 0, pathLen);
// Index records are padded out to the next 8 byte alignment
// for historical reasons related to how C Git read the files.
//
- final int actLen = INFO_LEN + pathLen;
+ final int actLen = len + pathLen;
final int expLen = (actLen + 8) & ~7;
if (actLen != expLen)
os.write(nullpad, 0, expLen - actLen);
@@ -401,6 +423,24 @@ public class DirCacheEntry {
}
/**
+ * Returns whether this entry should be skipped from the working tree.
+ *
+ * @return true if this entry should be skipepd.
+ */
+ public boolean isSkipWorkTree() {
+ return (getExtendedFlags() & SKIP_WORKTREE) != 0;
+ }
+
+ /**
+ * Returns whether this entry is intent to be added to the Index.
+ *
+ * @return true if this entry is intent to add.
+ */
+ public boolean isIntentToAdd() {
+ return (getExtendedFlags() & INTENT_TO_ADD) != 0;
+ }
+
+ /**
* Obtain the raw {@link FileMode} bits for this entry.
*
* @return mode bits for the entry.
@@ -575,6 +615,13 @@ public class DirCacheEntry {
| NB.decodeUInt16(info, infoOffset + P_FLAGS) & ~NAME_MASK);
}
+ /**
+ * @return true if the entry contains extended flags.
+ */
+ boolean isExtended() {
+ return (info[infoOffset + P_FLAGS] & EXTENDED) != 0;
+ }
+
private long decodeTS(final int pIdx) {
final int base = infoOffset + pIdx;
final int sec = NB.decodeInt32(info, base);
@@ -588,6 +635,13 @@ public class DirCacheEntry {
NB.encodeInt32(info, base + 4, ((int) (when % 1000)) * 1000000);
}
+ private int getExtendedFlags() {
+ if (isExtended())
+ return NB.decodeUInt16(info, infoOffset + P_FLAGS2) << 16;
+ else
+ return 0;
+ }
+
private static String toString(final byte[] path) {
return Constants.CHARSET.decode(ByteBuffer.wrap(path)).toString();
}
@@ -615,4 +669,8 @@ public class DirCacheEntry {
}
return componentHasChars;
}
+
+ static int getMaximumInfoLength(boolean extended) {
+ return extended ? INFO_LEN_EXTENDED : INFO_LEN;
+ }
}