Browse Source

reftable: resolve symbolic references

resolve(Ref) helps callers recursively chase symbolic references and
is a useful function when wrapping a Reftable inside a RefDatabase, as
RefCursor does not resolve symbolic references during iteration.

Change-Id: I1ba143f403773497972e225dc92c35ecb989e154
stable-4.9
Shawn Pearce 7 years ago
parent
commit
0aae64ce74
  1. 37
      org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java
  2. 39
      org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/Reftable.java

37
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java

@ -52,6 +52,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
@ -239,6 +240,42 @@ public class ReftableTest {
} }
} }
@Test
public void resolveSymbolicRef() throws IOException {
Reftable t = read(write(
sym(HEAD, "refs/heads/tmp"),
sym("refs/heads/tmp", MASTER),
ref(MASTER, 1)));
Ref head = t.exactRef(HEAD);
assertNull(head.getObjectId());
assertEquals("refs/heads/tmp", head.getTarget().getName());
head = t.resolve(head);
assertNotNull(head);
assertEquals(id(1), head.getObjectId());
Ref master = t.exactRef(MASTER);
assertNotNull(master);
assertSame(master, t.resolve(master));
}
@Test
public void failDeepChainOfSymbolicRef() throws IOException {
Reftable t = read(write(
sym(HEAD, "refs/heads/1"),
sym("refs/heads/1", "refs/heads/2"),
sym("refs/heads/2", "refs/heads/3"),
sym("refs/heads/3", "refs/heads/4"),
sym("refs/heads/4", "refs/heads/5"),
sym("refs/heads/5", MASTER),
ref(MASTER, 1)));
Ref head = t.exactRef(HEAD);
assertNull(head.getObjectId());
assertNull(t.resolve(head));
}
@Test @Test
public void oneDeletedRef() throws IOException { public void oneDeletedRef() throws IOException {
String name = "refs/heads/gone"; String name = "refs/heads/gone";

39
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/Reftable.java

@ -43,6 +43,8 @@
package org.eclipse.jgit.internal.storage.reftable; package org.eclipse.jgit.internal.storage.reftable;
import static org.eclipse.jgit.lib.RefDatabase.MAX_SYMBOLIC_REF_DEPTH;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
@ -51,6 +53,7 @@ import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.internal.storage.io.BlockSource; import org.eclipse.jgit.internal.storage.io.BlockSource;
import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.SymbolicRef;
/** Abstract table of references. */ /** Abstract table of references. */
public abstract class Reftable implements AutoCloseable { public abstract class Reftable implements AutoCloseable {
@ -218,6 +221,42 @@ public abstract class Reftable implements AutoCloseable {
} }
} }
/**
* Resolve a symbolic reference to populate its value.
*
* @param symref
* reference to resolve.
* @return resolved {@code symref}, or {@code null}.
* @throws IOException
* if references cannot be read.
*/
@Nullable
public Ref resolve(Ref symref) throws IOException {
return resolve(symref, 0);
}
private Ref resolve(Ref ref, int depth) throws IOException {
if (!ref.isSymbolic()) {
return ref;
}
Ref dst = ref.getTarget();
if (MAX_SYMBOLIC_REF_DEPTH <= depth) {
return null; // claim it doesn't exist
}
dst = exactRef(dst.getName());
if (dst == null) {
return ref;
}
dst = resolve(dst, depth + 1);
if (dst == null) {
return null; // claim it doesn't exist
}
return new SymbolicRef(ref.getName(), dst);
}
@Override @Override
public abstract void close() throws IOException; public abstract void close() throws IOException;
} }

Loading…
Cancel
Save