]> source.dussan.org Git - jgit.git/commitdiff
RevWalk support for shallow clones 45/8345/11
authorMarc Strapetz <marc.strapetz@syntevo.com>
Mon, 29 Oct 2012 15:34:33 +0000 (16:34 +0100)
committerChris Aniszczyk <zx@twitter.com>
Wed, 21 Nov 2012 16:46:02 +0000 (10:46 -0600)
StartGenerator now processes .git/shallow to have the
RevWalk stop for shallow commits.

See RevWalkShallowTest for tests.

Bug: 394543
CQ: 6908
Change-Id: Ia5af1dab3fe9c7888f44eeecab1e1bcf2e8e48fe
Signed-off-by: Chris Aniszczyk <zx@twitter.com>
14 files changed:
org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FooterLineTest.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkShallowTest.java [new file with mode: 0644]
org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java
org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java
org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsReader.java
org.eclipse.jgit/src/org/eclipse/jgit/storage/file/CachedObjectDirectory.java
org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileObjectDatabase.java
org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileRepository.java
org.eclipse.jgit/src/org/eclipse/jgit/storage/file/ObjectDirectory.java
org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCursor.java

index 7f440df22a8243d5ffbef84bb8fd4e6891e78a6b..1720b26bbca024a5b980dd357e79dd0ab184d470 100644 (file)
@@ -48,7 +48,7 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-
+import java.io.IOException;
 import java.util.List;
 
 import org.eclipse.jgit.lib.Constants;
@@ -58,7 +58,7 @@ import org.junit.Test;
 
 public class FooterLineTest extends RepositoryTestCase {
        @Test
-       public void testNoFooters_EmptyBody() {
+       public void testNoFooters_EmptyBody() throws IOException {
                final RevCommit commit = parse("");
                final List<FooterLine> footers = commit.getFooterLines();
                assertNotNull(footers);
@@ -66,7 +66,7 @@ public class FooterLineTest extends RepositoryTestCase {
        }
 
        @Test
-       public void testNoFooters_NewlineOnlyBody1() {
+       public void testNoFooters_NewlineOnlyBody1() throws IOException {
                final RevCommit commit = parse("\n");
                final List<FooterLine> footers = commit.getFooterLines();
                assertNotNull(footers);
@@ -74,7 +74,7 @@ public class FooterLineTest extends RepositoryTestCase {
        }
 
        @Test
-       public void testNoFooters_NewlineOnlyBody5() {
+       public void testNoFooters_NewlineOnlyBody5() throws IOException {
                final RevCommit commit = parse("\n\n\n\n\n");
                final List<FooterLine> footers = commit.getFooterLines();
                assertNotNull(footers);
@@ -82,7 +82,7 @@ public class FooterLineTest extends RepositoryTestCase {
        }
 
        @Test
-       public void testNoFooters_OneLineBodyNoLF() {
+       public void testNoFooters_OneLineBodyNoLF() throws IOException {
                final RevCommit commit = parse("this is a commit");
                final List<FooterLine> footers = commit.getFooterLines();
                assertNotNull(footers);
@@ -90,7 +90,7 @@ public class FooterLineTest extends RepositoryTestCase {
        }
 
        @Test
-       public void testNoFooters_OneLineBodyWithLF() {
+       public void testNoFooters_OneLineBodyWithLF() throws IOException {
                final RevCommit commit = parse("this is a commit\n");
                final List<FooterLine> footers = commit.getFooterLines();
                assertNotNull(footers);
@@ -98,7 +98,7 @@ public class FooterLineTest extends RepositoryTestCase {
        }
 
        @Test
-       public void testNoFooters_ShortBodyNoLF() {
+       public void testNoFooters_ShortBodyNoLF() throws IOException {
                final RevCommit commit = parse("subject\n\nbody of commit");
                final List<FooterLine> footers = commit.getFooterLines();
                assertNotNull(footers);
@@ -106,7 +106,7 @@ public class FooterLineTest extends RepositoryTestCase {
        }
 
        @Test
-       public void testNoFooters_ShortBodyWithLF() {
+       public void testNoFooters_ShortBodyWithLF() throws IOException {
                final RevCommit commit = parse("subject\n\nbody of commit\n");
                final List<FooterLine> footers = commit.getFooterLines();
                assertNotNull(footers);
@@ -114,7 +114,7 @@ public class FooterLineTest extends RepositoryTestCase {
        }
 
        @Test
-       public void testSignedOffBy_OneUserNoLF() {
+       public void testSignedOffBy_OneUserNoLF() throws IOException {
                final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n"
                                + "Signed-off-by: A. U. Thor <a@example.com>");
                final List<FooterLine> footers = commit.getFooterLines();
@@ -130,7 +130,7 @@ public class FooterLineTest extends RepositoryTestCase {
        }
 
        @Test
-       public void testSignedOffBy_OneUserWithLF() {
+       public void testSignedOffBy_OneUserWithLF() throws IOException {
                final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n"
                                + "Signed-off-by: A. U. Thor <a@example.com>\n");
                final List<FooterLine> footers = commit.getFooterLines();
@@ -146,7 +146,7 @@ public class FooterLineTest extends RepositoryTestCase {
        }
 
        @Test
-       public void testSignedOffBy_IgnoreWhitespace() {
+       public void testSignedOffBy_IgnoreWhitespace() throws IOException {
                // We only ignore leading whitespace on the value, trailing
                // is assumed part of the value.
                //
@@ -165,7 +165,7 @@ public class FooterLineTest extends RepositoryTestCase {
        }
 
        @Test
-       public void testEmptyValueNoLF() {
+       public void testEmptyValueNoLF() throws IOException {
                final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n"
                                + "Signed-off-by:");
                final List<FooterLine> footers = commit.getFooterLines();
@@ -181,7 +181,7 @@ public class FooterLineTest extends RepositoryTestCase {
        }
 
        @Test
-       public void testEmptyValueWithLF() {
+       public void testEmptyValueWithLF() throws IOException {
                final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n"
                                + "Signed-off-by:\n");
                final List<FooterLine> footers = commit.getFooterLines();
@@ -197,7 +197,7 @@ public class FooterLineTest extends RepositoryTestCase {
        }
 
        @Test
-       public void testShortKey() {
+       public void testShortKey() throws IOException {
                final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n"
                                + "K:V\n");
                final List<FooterLine> footers = commit.getFooterLines();
@@ -213,7 +213,7 @@ public class FooterLineTest extends RepositoryTestCase {
        }
 
        @Test
-       public void testNonDelimtedEmail() {
+       public void testNonDelimtedEmail() throws IOException {
                final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n"
                                + "Acked-by: re@example.com\n");
                final List<FooterLine> footers = commit.getFooterLines();
@@ -229,7 +229,7 @@ public class FooterLineTest extends RepositoryTestCase {
        }
 
        @Test
-       public void testNotEmail() {
+       public void testNotEmail() throws IOException {
                final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n"
                                + "Acked-by: Main Tain Er\n");
                final List<FooterLine> footers = commit.getFooterLines();
@@ -245,7 +245,7 @@ public class FooterLineTest extends RepositoryTestCase {
        }
 
        @Test
-       public void testSignedOffBy_ManyUsers() {
+       public void testSignedOffBy_ManyUsers() throws IOException {
                final RevCommit commit = parse("subject\n\nbody of commit\n"
                                + "Not-A-Footer-Line: this line must not be read as a footer\n"
                                + "\n" // paragraph break, now footers appear in final block
@@ -281,7 +281,7 @@ public class FooterLineTest extends RepositoryTestCase {
        }
 
        @Test
-       public void testSignedOffBy_SkipNonFooter() {
+       public void testSignedOffBy_SkipNonFooter() throws IOException {
                final RevCommit commit = parse("subject\n\nbody of commit\n"
                                + "Not-A-Footer-Line: this line must not be read as a footer\n"
                                + "\n" // paragraph break, now footers appear in final block
@@ -314,7 +314,7 @@ public class FooterLineTest extends RepositoryTestCase {
        }
 
        @Test
-       public void testFilterFootersIgnoreCase() {
+       public void testFilterFootersIgnoreCase() throws IOException {
                final RevCommit commit = parse("subject\n\nbody of commit\n"
                                + "Not-A-Footer-Line: this line must not be read as a footer\n"
                                + "\n" // paragraph break, now footers appear in final block
@@ -332,7 +332,7 @@ public class FooterLineTest extends RepositoryTestCase {
        }
 
        @Test
-       public void testMatchesBugId() {
+       public void testMatchesBugId() throws IOException {
                final RevCommit commit = parse("this is a commit subject for test\n"
                                + "\n" // paragraph break, now footers appear in final block
                                + "Simple-Bug-Id: 42\n");
@@ -352,7 +352,7 @@ public class FooterLineTest extends RepositoryTestCase {
                assertFalse("not CC", line.matches(FooterKey.CC));
        }
 
-       private RevCommit parse(final String msg) {
+       private RevCommit parse(final String msg) throws IOException {
                final StringBuilder buf = new StringBuilder();
                buf.append("tree " + ObjectId.zeroId().name() + "\n");
                buf.append("author A. U. Thor <a@example.com> 1 +0000\n");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkShallowTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkShallowTest.java
new file mode 100644 (file)
index 0000000..479d9d3
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2012, Marc Strapetz <marc.strapetz@syntevo.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.jgit.junit.JGitTestUtil;
+import org.eclipse.jgit.lib.*;
+import org.junit.*;
+
+import static org.junit.Assert.*;
+
+public class RevWalkShallowTest extends RevWalkTestCase {
+
+       // Accessing ==============================================================
+
+       @Test
+       public void testDepth1() throws Exception {
+               final RevCommit a = commit();
+               final RevCommit b = commit(a);
+               final RevCommit c = commit(b);
+               final RevCommit d = commit(c);
+
+               createShallowFile(d);
+
+               rw.reset();
+               markStart(d);
+               assertCommit(d, rw.next());
+               assertNull(rw.next());
+       }
+
+       @Test
+       public void testDepth2() throws Exception {
+               final RevCommit a = commit();
+               final RevCommit b = commit(a);
+               final RevCommit c = commit(b);
+               final RevCommit d = commit(c);
+
+               createShallowFile(c);
+
+               rw.reset();
+               markStart(d);
+               assertCommit(d, rw.next());
+               assertCommit(c, rw.next());
+               assertNull(rw.next());
+       }
+
+       @Test
+       public void testDepth3() throws Exception {
+               final RevCommit a = commit();
+               final RevCommit b = commit(a);
+               final RevCommit c = commit(b);
+               final RevCommit d = commit(c);
+
+               createShallowFile(b);
+
+               rw.reset();
+               markStart(d);
+               assertCommit(d, rw.next());
+               assertCommit(c, rw.next());
+               assertCommit(b, rw.next());
+               assertNull(rw.next());
+       }
+
+       @Test
+       public void testMergeCommitOneParentShallow() throws Exception {
+               final RevCommit a = commit();
+               final RevCommit b = commit(a);
+               final RevCommit c = commit(b);
+               final RevCommit d = commit(b);
+               final RevCommit e = commit(d);
+               final RevCommit merge = commit(c, e);
+
+               createShallowFile(e);
+
+               rw.reset();
+               markStart(merge);
+               assertCommit(merge, rw.next());
+               assertCommit(e, rw.next());
+               assertCommit(c, rw.next());
+               assertCommit(b, rw.next());
+               assertCommit(a, rw.next());
+               assertNull(rw.next());
+       }
+
+       @Test
+       public void testMergeCommitEntirelyShallow() throws Exception {
+               final RevCommit a = commit();
+               final RevCommit b = commit(a);
+               final RevCommit c = commit(b);
+               final RevCommit d = commit(b);
+               final RevCommit e = commit(d);
+               final RevCommit merge = commit(c, e);
+
+               createShallowFile(c, e);
+
+               rw.reset();
+               markStart(merge);
+               assertCommit(merge, rw.next());
+               assertCommit(e, rw.next());
+               assertCommit(c, rw.next());
+               assertNull(rw.next());
+       }
+
+       @Test
+       public void testObjectDirectorySnapshot() throws Exception {
+               RevCommit a = commit();
+               RevCommit b = commit(a);
+               RevCommit c = commit(b);
+               RevCommit d = commit(c);
+
+               createShallowFile(d);
+
+               rw.reset();
+               markStart(d);
+               assertCommit(d, rw.next());
+               assertNull(rw.next());
+
+               rw = createRevWalk();
+               a = rw.lookupCommit(a);
+               b = rw.lookupCommit(b);
+               c = rw.lookupCommit(c);
+               d = rw.lookupCommit(d);
+
+               rw.reset();
+               markStart(d);
+               assertCommit(d, rw.next());
+               assertNull(rw.next());
+
+               createShallowFile(c);
+
+               rw = createRevWalk();
+               a = rw.lookupCommit(a);
+               b = rw.lookupCommit(b);
+               c = rw.lookupCommit(c);
+               d = rw.lookupCommit(d);
+
+               rw.reset();
+               markStart(d);
+               assertCommit(d, rw.next());
+               assertCommit(c, rw.next());
+               assertNull(rw.next());
+       }
+
+       private void createShallowFile(ObjectId... shallowCommits)
+                       throws IOException {
+               final StringBuilder builder = new StringBuilder();
+               for (ObjectId commit : shallowCommits)
+                       builder.append(commit.getName() + "\n");
+               JGitTestUtil.write(new File(rw.repository.getDirectory(), "shallow"),
+                               builder.toString());
+       }
+}
index e7b1fe89568afc8b08d31d8e54bc6f999166e3c0..3270267881c722cfcf12041bb46034037ed79e15 100644 (file)
@@ -423,6 +423,7 @@ sequenceTooLargeForDiffAlgorithm=Sequence too large for difference algorithm.
 serviceNotEnabledNoName=Service not enabled
 serviceNotPermitted={0} not permitted
 serviceNotPermittedNoName=Service not permitted
+shallowCommitsAlreadyInitialized=Shallow commits have already been initialized
 shortCompressedStreamAt=Short compressed stream at {0}
 shortReadOfBlock=Short read of block.
 shortReadOfOptionalDIRCExtensionExpectedAnotherBytes=Short read of optional DIRC extension {0}; expected another {1} bytes within the section.
index 48963253c67819f866c5f8b2ba8a0f930ffd5e4f..7caeba8bebaab3f24d854d51388b9a1bbcbc87a7 100644 (file)
@@ -484,6 +484,7 @@ public class JGitText extends TranslationBundle {
        /***/ public String serviceNotEnabledNoName;
        /***/ public String serviceNotPermitted;
        /***/ public String serviceNotPermittedNoName;
+       /***/ public String shallowCommitsAlreadyInitialized;
        /***/ public String shortCompressedStreamAt;
        /***/ public String shortReadOfBlock;
        /***/ public String shortReadOfOptionalDIRCExtensionExpectedAnotherBytes;
index d5be3157d57c5111a04e8f6dfad3707b9ec29d3a..e66e3a8354672938c5354ff2b5c89ac3d8cac73b 100644 (file)
@@ -340,6 +340,9 @@ public final class Constants {
        /** Name of the submodules file */
        public static final String DOT_GIT_MODULES = ".gitmodules";
 
+       /** Name of the .git/shallow file */
+       public static final String SHALLOW = "shallow";
+
        /**
         * Create a new digest function for objects.
         *
index cd3706bbe3489c8f254ef708facd12c1b3e53d9b..ee4f3d9e08f9597e16d34087123a1d29ad7109f4 100644 (file)
@@ -48,6 +48,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
@@ -250,6 +251,14 @@ public abstract class ObjectReader {
                        throws MissingObjectException, IncorrectObjectTypeException,
                        IOException;
 
+       /**
+        * Returns IDs for those commits which should be considered as shallow.
+        *
+        * @return IDs of shallow commits
+        * @throws IOException
+        */
+       public abstract Set<ObjectId> getShallowCommits() throws IOException;
+
        /**
         * Asynchronous object opening.
         *
index 05c173888aa148b172fd1e2bf88448c8f6b8964f..6363014415721029ea6a8fdf78169bc1765b5357 100644 (file)
@@ -80,7 +80,11 @@ public class RevCommit extends RevObject {
         *         available to the caller.
         */
        public static RevCommit parse(byte[] raw) {
-               return parse(new RevWalk((ObjectReader) null), raw);
+               try {
+                       return parse(new RevWalk((ObjectReader) null), raw);
+               } catch (IOException ex) {
+                       throw new RuntimeException(ex);
+               }
        }
 
        /**
@@ -88,7 +92,7 @@ public class RevCommit extends RevObject {
         *
         * This method inserts the commit directly into the caller supplied revision
         * pool, making it appear as though the commit exists in the repository,
-        * even if it doesn't.  The repository under the pool is not affected.
+        * even if it doesn't. The repository under the pool is not affected.
         *
         * @param rw
         *            the revision pool to allocate the commit within. The commit's
@@ -97,8 +101,10 @@ public class RevCommit extends RevObject {
         *            the canonical formatted commit to be parsed.
         * @return the parsed commit, in an isolated revision pool that is not
         *         available to the caller.
+        * @throws IOException
+        *             in case of RevWalk initialization fails
         */
-       public static RevCommit parse(RevWalk rw, byte[] raw) {
+       public static RevCommit parse(RevWalk rw, byte[] raw) throws IOException {
                ObjectInserter.Formatter fmt = new ObjectInserter.Formatter();
                boolean retain = rw.isRetainBody();
                rw.setRetainBody(true);
@@ -146,7 +152,11 @@ public class RevCommit extends RevObject {
                }
        }
 
-       void parseCanonical(final RevWalk walk, final byte[] raw) {
+       void parseCanonical(final RevWalk walk, final byte[] raw)
+                       throws IOException {
+               if (!walk.shallowCommitsInitialized)
+                       walk.initializeShallowCommits();
+
                final MutableObjectId idBuffer = walk.idBuffer;
                idBuffer.fromString(raw, 5);
                tree = walk.lookupTree(idBuffer);
index 93428f9851763478989830a95033bc081763fc6f..8e07048e21e4bcbb8e302333e00ac427cd8a409d 100644 (file)
@@ -192,6 +192,8 @@ public class RevWalk implements Iterable<RevCommit> {
 
        private boolean retainBody;
 
+       boolean shallowCommitsInitialized;
+
        /**
         * Create a new revision walker for a given repository.
         *
@@ -1209,6 +1211,7 @@ public class RevWalk implements Iterable<RevCommit> {
                roots.clear();
                queue = new DateRevQueue();
                pending = new StartGenerator(this);
+               shallowCommitsInitialized = false;
        }
 
        /**
@@ -1312,4 +1315,18 @@ public class RevWalk implements Iterable<RevCommit> {
                if (carry != 0)
                        RevCommit.carryFlags(c, carry);
        }
+
+       void initializeShallowCommits() throws IOException {
+               if (shallowCommitsInitialized)
+                       throw new IllegalStateException(
+                                       JGitText.get().shallowCommitsAlreadyInitialized);
+
+               shallowCommitsInitialized = true;
+
+               if (reader == null)
+                       return;
+
+               for (ObjectId id : reader.getShallowCommits())
+                       lookupCommit(id).parents = RevCommit.NO_PARENTS;
+       }
 }
index 6a76258ed3cf97568760086d07ce494d03d2a2c9..b5244d0439a1b4f3621ad0ffc73d6c29f8f0e74b 100644 (file)
@@ -61,6 +61,7 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.zip.DataFormatException;
 import java.util.zip.Inflater;
@@ -192,6 +193,11 @@ public final class DfsReader extends ObjectReader implements ObjectReuseAsIs {
                throw new MissingObjectException(objectId.copy(), typeHint);
        }
 
+       @Override
+       public Set<ObjectId> getShallowCommits() {
+               return Collections.emptySet();
+       }
+
        private static final Comparator<FoundObject<?>> FOUND_OBJECT_SORT = new Comparator<FoundObject<?>>() {
                public int compare(FoundObject<?> a, FoundObject<?> b) {
                        int cmp = a.packIndex - b.packIndex;
index 8e87b08ee206220323233224950bcf75643519b2..37ab0e0860f32cd7a50de57b71e39ed3a1226dba 100644 (file)
@@ -141,6 +141,11 @@ class CachedObjectDirectory extends FileObjectDatabase {
                return wrapped.getFS();
        }
 
+       @Override
+       Set<ObjectId> getShallowCommits() throws IOException {
+               return wrapped.getShallowCommits();
+       }
+
        @Override
        Collection<? extends CachedPack> getCachedPacks() throws IOException {
                return wrapped.getCachedPacks();
index f28facbec6f7ef392e0bb7dc09f0b0c3030fb714..ffbd2edfbde1ff8934f42724cf93b0241fdf309e 100644 (file)
@@ -137,6 +137,8 @@ abstract class FileObjectDatabase extends ObjectDatabase {
 
        abstract FS getFS();
 
+       abstract Set<ObjectId> getShallowCommits() throws IOException;
+
        /**
         * Open an object from this database.
         * <p>
index 33a51269de2fc5ed613ba2e3d2907144b0ebcbfd..2393e607e299a12328a247ac98e1d4c866089eff 100644 (file)
@@ -178,7 +178,8 @@ public class FileRepository extends Repository {
                objectDatabase = new ObjectDirectory(repoConfig, //
                                options.getObjectDirectory(), //
                                options.getAlternateObjectDirectories(), //
-                               getFS());
+                               getFS(), //
+                               new File(getDirectory(), Constants.SHALLOW));
 
                if (objectDatabase.exists()) {
                        final long repositoryFormatVersion = getConfig().getLong(
index eab6ed6e70ebe0ac28a60cd1c2d190ca2ba4e667..7b5d3a63c7be89be7afd3a87a793f1190c06e876 100644 (file)
@@ -127,6 +127,12 @@ public class ObjectDirectory extends FileObjectDatabase {
 
        private final UnpackedObjectCache unpackedObjectCache;
 
+       private final File shallowFile;
+
+       private FileSnapshot shallowFileSnapshot = FileSnapshot.DIRTY;
+
+       private Set<ObjectId> shallowCommitsIds;
+
        /**
         * Initialize a reference to an on-disk object directory.
         *
@@ -139,11 +145,14 @@ public class ObjectDirectory extends FileObjectDatabase {
         * @param fs
         *            the file system abstraction which will be necessary to perform
         *            certain file system operations.
+        * @param shallowFile
+        *            file which contains IDs of shallow commits, null if shallow
+        *            commits handling should be turned off
         * @throws IOException
         *             an alternate object cannot be opened.
         */
        public ObjectDirectory(final Config cfg, final File dir,
-                       File[] alternatePaths, FS fs) throws IOException {
+                       File[] alternatePaths, FS fs, File shallowFile) throws IOException {
                config = cfg;
                objects = dir;
                infoDirectory = new File(objects, "info");
@@ -154,6 +163,7 @@ public class ObjectDirectory extends FileObjectDatabase {
                cachedPacks = new AtomicReference<CachedPackList>();
                unpackedObjectCache = new UnpackedObjectCache();
                this.fs = fs;
+               this.shallowFile = shallowFile;
 
                alternates = new AtomicReference<AlternateHandle[]>();
                if (alternatePaths != null) {
@@ -614,6 +624,30 @@ public class ObjectDirectory extends FileObjectDatabase {
                return fs;
        }
 
+       @Override
+       Set<ObjectId> getShallowCommits() throws IOException {
+               if (shallowFile == null || !shallowFile.isFile())
+                       return Collections.emptySet();
+
+               if (shallowFileSnapshot == null
+                               || shallowFileSnapshot.isModified(shallowFile)) {
+                       shallowCommitsIds = new HashSet<ObjectId>();
+
+                       final BufferedReader reader = open(shallowFile);
+                       try {
+                               String line;
+                               while ((line = reader.readLine()) != null)
+                                       shallowCommitsIds.add(ObjectId.fromString(line));
+                       } finally {
+                               reader.close();
+                       }
+
+                       shallowFileSnapshot = FileSnapshot.save(shallowFile);
+               }
+
+               return shallowCommitsIds;
+       }
+
        private void insertPack(final PackFile pf) {
                PackList o, n;
                do {
@@ -829,7 +863,7 @@ public class ObjectDirectory extends FileObjectDatabase {
                        return new AlternateRepository(db);
                }
 
-               ObjectDirectory db = new ObjectDirectory(config, objdir, null, fs);
+               ObjectDirectory db = new ObjectDirectory(config, objdir, null, fs, null);
                return new AlternateHandle(db);
        }
 
index 0e9970fcc86265f9d7cd21d2117b67a5437ee7f1..5555a3c40480283cd171cfb3707e80463f304b30 100644 (file)
@@ -52,6 +52,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.zip.DataFormatException;
 import java.util.zip.Inflater;
 
@@ -130,6 +131,11 @@ final class WindowCursor extends ObjectReader implements ObjectReuseAsIs {
                return ldr;
        }
 
+       @Override
+       public Set<ObjectId> getShallowCommits() throws IOException {
+               return db.getShallowCommits();
+       }
+
        public long getObjectSize(AnyObjectId objectId, int typeHint)
                        throws MissingObjectException, IncorrectObjectTypeException,
                        IOException {