]> source.dussan.org Git - jgit.git/commitdiff
Add RefDatabase#getRefsByPrefix method 73/120873/4
authorJonathan Tan <jonathantanmy@google.com>
Fri, 6 Apr 2018 22:50:01 +0000 (15:50 -0700)
committerJonathan Nieder <jrn@google.com>
Fri, 20 Apr 2018 18:10:48 +0000 (11:10 -0700)
The existing RefDatabase#getRefs abstract method (to be implemented by
ref database backends) has the following issues:

 - It returns a map with a key (the name of the ref with the prefix
   removed) which is potentially superfluous (it can be derived by the
   caller if need be) and confusing (in that the prefix is removed).
 - The prefix is required to end with a '/', but some backends (e.g.
   reftable) have fast search by prefix regardless of what the last
   character of the prefix is.

Add a new method #getRefsByPrefix that does not have these issues. This
is non-abstract with a default implementation that uses #getRefs (for
backwards compatibility), but ref database backends can reimplement it.

This also prepares for supporting "ref-prefix" in the "ls-refs" command
in the fetch-pack/upload-pack protocol v2, which does not require that
the prefix end with a '/'.

Change-Id: I4c92f852e8c1558095dd460b5fd7b602c1d82df1
Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Signed-off-by: Jonathan Nieder <jrn@google.com>
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java

index e93867829ad7db3b03d6aae413c2014e91366e1a..2481e64997205705085411fd8bade9da40abeddc 100644 (file)
@@ -57,6 +57,7 @@ import static org.junit.Assert.fail;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.util.List;
 import java.util.Map;
 import java.util.TreeSet;
 
@@ -305,4 +306,26 @@ public class RefTest extends SampleDataRepositoryTestCase {
                assertSame(dst.getPeeledObjectId(), ref.getPeeledObjectId());
                assertEquals(dst.isPeeled(), ref.isPeeled());
        }
+
+       private static void checkContainsRef(List<Ref> haystack, Ref needle) {
+               for (Ref ref : haystack) {
+                       if (ref.getName().equals(needle.getName()) &&
+                                       ref.getObjectId().equals(needle.getObjectId())) {
+                               return;
+                       }
+               }
+               fail("list " + haystack + " does not contain ref " + needle);
+       }
+
+       @Test
+       public void testGetRefsByPrefix() throws IOException {
+               List<Ref> refs = db.getRefDatabase().getRefsByPrefix("refs/heads/g");
+               assertEquals(2, refs.size());
+               checkContainsRef(refs, db.exactRef("refs/heads/g"));
+               checkContainsRef(refs, db.exactRef("refs/heads/gitlink"));
+
+               refs = db.getRefDatabase().getRefsByPrefix("refs/heads/prefix/");
+               assertEquals(1, refs.size());
+               checkContainsRef(refs, db.exactRef("refs/heads/prefix/a"));
+       }
 }
index 557bdb994f0c83742ebeaab94c2668bee32f9067..a9ba16afee5a04f2165439ff9087399a472fef3c 100644 (file)
@@ -43,6 +43,8 @@
 
 package org.eclipse.jgit.lib;
 
+import static java.util.stream.Collectors.toList;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -343,10 +345,49 @@ public abstract class RefDatabase {
         *         of each key. The map can be an unsorted map.
         * @throws java.io.IOException
         *             the reference space cannot be accessed.
+        * @deprecated use {@link #getRefsByPrefix} instead
         */
        @NonNull
+       @Deprecated
        public abstract Map<String, Ref> getRefs(String prefix) throws IOException;
 
+       /**
+        * Returns refs whose names start with a given prefix.
+        * <p>
+        * The default implementation uses {@link #getRefs}. Implementors of
+        * {@link RefDatabase} should override this method directly if a better
+        * implementation is possible.
+        *
+        * @param prefix string that names of refs should start with; may be
+        *             empty (to return all refs).
+        * @return immutable list of refs whose names start with {@code prefix}.
+        * @throws java.io.IOException
+        *             the reference space cannot be accessed.
+        * @since 5.0
+        */
+       @NonNull
+       public List<Ref> getRefsByPrefix(String prefix) throws IOException {
+               Map<String, Ref> coarseRefs;
+               int lastSlash = prefix.lastIndexOf('/');
+               if (lastSlash == -1) {
+                       coarseRefs = getRefs(ALL);
+               } else {
+                       coarseRefs = getRefs(prefix.substring(0, lastSlash + 1));
+               }
+
+               List<Ref> result;
+               if (lastSlash + 1 == prefix.length()) {
+                       result = coarseRefs.values().stream().collect(toList());
+               } else {
+                       String p = prefix.substring(lastSlash + 1);
+                       result = coarseRefs.entrySet().stream()
+                                       .filter(e -> e.getKey().startsWith(p))
+                                       .map(e -> e.getValue())
+                                       .collect(toList());
+               }
+               return Collections.unmodifiableList(result);
+       }
+
        /**
         * Get the additional reference-like entities from the repository.
         * <p>