diff --git a/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/DhtRepository.java b/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/DhtRepository.java index 9f60ef575..faff469e9 100644 --- a/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/DhtRepository.java +++ b/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/DhtRepository.java @@ -153,6 +153,11 @@ public void scanForRepoChanges() { refdb.clearCache(); } + @Override + public void notifyIndexChanged() { + // we do not support non-bare repositories yet + } + @Override public String toString() { return "DhtRepostitory[" + key + " / " + name + "]"; diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java index 1c1cb0fcb..c64ca88f0 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2008-2009, Google Inc. + * Copyright (C) 2011, Matthias Sohn * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -49,9 +50,13 @@ import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.File; +import org.eclipse.jgit.events.IndexChangedEvent; +import org.eclipse.jgit.events.IndexChangedListener; +import org.eclipse.jgit.events.ListenerList; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.RepositoryTestCase; @@ -187,6 +192,73 @@ public void testBuildOneFile_Commit() throws Exception { } } + @Test + public void testBuildOneFile_Commit_IndexChangedEvent() + throws Exception { + final class ReceivedEventMarkerException extends RuntimeException { + private static final long serialVersionUID = 1L; + // empty + } + + final String path = "a-file-path"; + final FileMode mode = FileMode.REGULAR_FILE; + // "old" date in 2008 + final long lastModified = 1218123387057L; + final int length = 1342; + DirCacheEntry entOrig; + boolean receivedEvent = false; + + DirCache dc = db.lockDirCache(); + IndexChangedListener listener = new IndexChangedListener() { + + public void onIndexChanged(IndexChangedEvent event) { + throw new ReceivedEventMarkerException(); + } + }; + + ListenerList l = db.getListenerList(); + l.addIndexChangedListener(listener); + DirCacheBuilder b = dc.builder(); + + entOrig = new DirCacheEntry(path); + entOrig.setFileMode(mode); + entOrig.setLastModified(lastModified); + entOrig.setLength(length); + b.add(entOrig); + try { + b.commit(); + } catch (ReceivedEventMarkerException e) { + receivedEvent = true; + } + if (!receivedEvent) + fail("did not receive IndexChangedEvent"); + + // do the same again, as this doesn't change index compared to first + // round we should get no event this time + dc = db.lockDirCache(); + listener = new IndexChangedListener() { + + public void onIndexChanged(IndexChangedEvent event) { + throw new ReceivedEventMarkerException(); + } + }; + + l = db.getListenerList(); + l.addIndexChangedListener(listener); + b = dc.builder(); + + entOrig = new DirCacheEntry(path); + entOrig.setFileMode(mode); + entOrig.setLastModified(lastModified); + entOrig.setLength(length); + b.add(entOrig); + try { + b.commit(); + } catch (ReceivedEventMarkerException e) { + fail("unexpected IndexChangedEvent"); + } + } + @Test public void testFindSingleFile() throws Exception { final String path = "a-file-path"; 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 af98c3315..55256d638 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java @@ -1,6 +1,7 @@ /* * Copyright (C) 2008-2010, Google Inc. * Copyright (C) 2008, Shawn O. Pearce + * Copyright (C) 2011, Matthias Sohn * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -63,6 +64,8 @@ import org.eclipse.jgit.JGitText; import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.UnmergedPathException; +import org.eclipse.jgit.events.IndexChangedEvent; +import org.eclipse.jgit.events.IndexChangedListener; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectInserter; @@ -94,6 +97,8 @@ public class DirCache { private static final DirCacheEntry[] NO_ENTRIES = {}; + private static final byte[] NO_CHECKSUM = {}; + static final Comparator ENT_CMP = new Comparator() { public int compare(final DirCacheEntry o1, final DirCacheEntry o2) { final int cr = cmp(o1, o2); @@ -203,6 +208,39 @@ public static DirCache lock(final File indexLocation, final FS fs) return c; } + /** + * Create a new in-core index representation, lock it, and read from disk. + *

+ * The new index will be locked and then read before it is returned to the + * caller. Read failures are reported as exceptions and therefore prevent + * the method from returning a partially populated index. On read failure, + * the lock is released. + * + * @param indexLocation + * location of the index file on disk. + * @param fs + * the file system abstraction which will be necessary to perform + * certain file system operations. + * @param indexChangedListener + * listener to be informed when DirCache is committed + * @return a cache representing the contents of the specified index file (if + * it exists) or an empty cache if the file does not exist. + * @throws IOException + * the index file is present but could not be read, or the lock + * could not be obtained. + * @throws CorruptObjectException + * the index file is using a format or extension that this + * library does not support. + */ + public static DirCache lock(final File indexLocation, final FS fs, + IndexChangedListener indexChangedListener) + throws CorruptObjectException, + IOException { + DirCache c = lock(indexLocation, fs); + c.registerIndexChangedListener(indexChangedListener); + return c; + } + /** Location of the current version of the index file. */ private final File liveFile; @@ -224,6 +262,15 @@ public static DirCache lock(final File indexLocation, final FS fs) /** Keep track of whether the index has changed or not */ private FileSnapshot snapshot; + /** index checksum when index was read from disk */ + private byte[] readIndexChecksum; + + /** index checksum when index was written to disk */ + private byte[] writeIndexChecksum; + + /** listener to be informed on commit */ + private IndexChangedListener indexChangedListener; + /** * Create a new in-core index representation. *

@@ -330,6 +377,7 @@ public void clear() { sortedEntries = NO_ENTRIES; entryCnt = 0; tree = null; + readIndexChecksum = NO_CHECKSUM; } private void readFrom(final InputStream inStream) throws IOException, @@ -412,8 +460,8 @@ else if (ver != 2) } } - final byte[] exp = md.digest(); - if (!Arrays.equals(exp, hdr)) { + readIndexChecksum = md.digest(); + if (!Arrays.equals(readIndexChecksum, hdr)) { throw new CorruptObjectException(JGitText.get().DIRCChecksumMismatch); } } @@ -544,8 +592,8 @@ void writeTo(final OutputStream os) throws IOException { dos.write(tmp, 0, 8); bb.writeTo(dos, null); } - - os.write(foot.digest()); + writeIndexChecksum = foot.digest(); + os.write(writeIndexChecksum); os.close(); } @@ -567,6 +615,9 @@ public boolean commit() { if (!tmp.commit()) return false; snapshot = tmp.getCommitSnapshot(); + if (indexChangedListener != null + && !Arrays.equals(readIndexChecksum, writeIndexChecksum)) + indexChangedListener.onIndexChanged(new IndexChangedEvent()); return true; } @@ -794,4 +845,8 @@ public boolean hasUnmergedPaths() { } return false; } + + private void registerIndexChangedListener(IndexChangedListener listener) { + this.indexChangedListener = listener; + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java index 3a3e1c558..f31217a96 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java @@ -69,6 +69,8 @@ import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.errors.RevisionSyntaxException; +import org.eclipse.jgit.events.IndexChangedEvent; +import org.eclipse.jgit.events.IndexChangedListener; import org.eclipse.jgit.events.ListenerList; import org.eclipse.jgit.events.RepositoryEvent; import org.eclipse.jgit.revwalk.RevBlob; @@ -883,7 +885,15 @@ public DirCache readDirCache() throws NoWorkTreeException, */ public DirCache lockDirCache() throws NoWorkTreeException, CorruptObjectException, IOException { - return DirCache.lock(getIndexFile(), getFS()); + // we want DirCache to inform us so that we can inform registered + // listeners about index changes + IndexChangedListener l = new IndexChangedListener() { + + public void onIndexChanged(IndexChangedEvent event) { + notifyIndexChanged(); + } + }; + return DirCache.lock(getIndexFile(), getFS(), l); } static byte[] gitInternalSlash(byte[] bytes) { @@ -1065,6 +1075,11 @@ public File getWorkTree() throws NoWorkTreeException { */ public abstract void scanForRepoChanges() throws IOException; + /** + * Notify that the index changed + */ + public abstract void notifyIndexChanged(); + /** * @param refName * diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileRepository.java index cd661e2d2..13776140d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileRepository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileRepository.java @@ -393,10 +393,14 @@ private void detectIndexChanges() { File indexFile = getIndexFile(); if (snapshot == null) snapshot = FileSnapshot.save(indexFile); - else if (snapshot.isModified(indexFile)) { - snapshot = FileSnapshot.save(indexFile); - fireEvent(new IndexChangedEvent()); - } + else if (snapshot.isModified(indexFile)) + notifyIndexChanged(); + } + + @Override + public void notifyIndexChanged() { + snapshot = FileSnapshot.save(getIndexFile()); + fireEvent(new IndexChangedEvent()); } /**