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
This commit is contained in:
parent
195541dd30
commit
0aae64ce74
|
@ -52,6 +52,7 @@
|
||||||
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 void oneSymbolicRef() throws IOException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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";
|
||||||
|
|
|
@ -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.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 boolean hasId(AnyObjectId id) throws IOException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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…
Reference in New Issue