Implement ls-refs in UploadPack
Implement support for Git protocol v2's "ls-refs" command and its "symrefs" and "peel" parameters. This adds support for this command to UploadPack but the git://, ssh://, and git:// transports do not make use of it yet. That will have to wait for later patches. Change-Id: I8abc6bcc6ed4a88c165677ff1245625aca01267b Signed-off-by: Jonathan Tan <jonathantanmy@google.com> Signed-off-by: Jonathan Nieder <jrn@google.com>
This commit is contained in:
parent
2661bc0813
commit
332bc61124
|
@ -19,6 +19,7 @@
|
|||
import org.eclipse.jgit.revwalk.RevBlob;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.eclipse.jgit.revwalk.RevTree;
|
||||
import org.eclipse.jgit.revwalk.RevTag;
|
||||
import org.eclipse.jgit.transport.UploadPack.RequestPolicy;
|
||||
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
|
||||
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
|
||||
|
@ -368,6 +369,7 @@ private ByteArrayInputStream uploadPackV2(String... inputLines) throws Exception
|
|||
|
||||
// capability advertisement (always sent)
|
||||
assertThat(pckIn.readString(), is("version 2"));
|
||||
assertThat(pckIn.readString(), is("ls-refs"));
|
||||
assertTrue(pckIn.readString() == PacketLineIn.END);
|
||||
return recvStream;
|
||||
}
|
||||
|
@ -380,4 +382,83 @@ public void testV2EmptyRequest() throws Exception {
|
|||
assertThat(recvStream.available(), is(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testV2LsRefs() throws Exception {
|
||||
RevCommit tip = remote.commit().message("message").create();
|
||||
remote.update("master", tip);
|
||||
server.updateRef("HEAD").link("refs/heads/master");
|
||||
RevTag tag = remote.tag("tag", tip);
|
||||
remote.update("refs/tags/tag", tag);
|
||||
|
||||
ByteArrayInputStream recvStream = uploadPackV2("command=ls-refs\n", PacketLineIn.END);
|
||||
PacketLineIn pckIn = new PacketLineIn(recvStream);
|
||||
|
||||
assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD"));
|
||||
assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
|
||||
assertThat(pckIn.readString(), is(tag.toObjectId().getName() + " refs/tags/tag"));
|
||||
assertTrue(pckIn.readString() == PacketLineIn.END);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testV2LsRefsSymrefs() throws Exception {
|
||||
RevCommit tip = remote.commit().message("message").create();
|
||||
remote.update("master", tip);
|
||||
server.updateRef("HEAD").link("refs/heads/master");
|
||||
RevTag tag = remote.tag("tag", tip);
|
||||
remote.update("refs/tags/tag", tag);
|
||||
|
||||
ByteArrayInputStream recvStream = uploadPackV2("command=ls-refs\n", PacketLineIn.DELIM, "symrefs", PacketLineIn.END);
|
||||
PacketLineIn pckIn = new PacketLineIn(recvStream);
|
||||
|
||||
assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD symref-target:refs/heads/master"));
|
||||
assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
|
||||
assertThat(pckIn.readString(), is(tag.toObjectId().getName() + " refs/tags/tag"));
|
||||
assertTrue(pckIn.readString() == PacketLineIn.END);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testV2LsRefsPeel() throws Exception {
|
||||
RevCommit tip = remote.commit().message("message").create();
|
||||
remote.update("master", tip);
|
||||
server.updateRef("HEAD").link("refs/heads/master");
|
||||
RevTag tag = remote.tag("tag", tip);
|
||||
remote.update("refs/tags/tag", tag);
|
||||
|
||||
ByteArrayInputStream recvStream = uploadPackV2("command=ls-refs\n", PacketLineIn.DELIM, "peel", PacketLineIn.END);
|
||||
PacketLineIn pckIn = new PacketLineIn(recvStream);
|
||||
|
||||
assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD"));
|
||||
assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
|
||||
assertThat(
|
||||
pckIn.readString(),
|
||||
is(tag.toObjectId().getName() + " refs/tags/tag peeled:"
|
||||
+ tip.toObjectId().getName()));
|
||||
assertTrue(pckIn.readString() == PacketLineIn.END);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testV2LsRefsMultipleCommands() throws Exception {
|
||||
RevCommit tip = remote.commit().message("message").create();
|
||||
remote.update("master", tip);
|
||||
server.updateRef("HEAD").link("refs/heads/master");
|
||||
RevTag tag = remote.tag("tag", tip);
|
||||
remote.update("refs/tags/tag", tag);
|
||||
|
||||
ByteArrayInputStream recvStream = uploadPackV2(
|
||||
"command=ls-refs\n", PacketLineIn.DELIM, "symrefs", "peel", PacketLineIn.END,
|
||||
"command=ls-refs\n", PacketLineIn.DELIM, PacketLineIn.END);
|
||||
PacketLineIn pckIn = new PacketLineIn(recvStream);
|
||||
|
||||
assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD symref-target:refs/heads/master"));
|
||||
assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
|
||||
assertThat(
|
||||
pckIn.readString(),
|
||||
is(tag.toObjectId().getName() + " refs/tags/tag peeled:"
|
||||
+ tip.toObjectId().getName()));
|
||||
assertTrue(pckIn.readString() == PacketLineIn.END);
|
||||
assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " HEAD"));
|
||||
assertThat(pckIn.readString(), is(tip.toObjectId().getName() + " refs/heads/master"));
|
||||
assertThat(pckIn.readString(), is(tag.toObjectId().getName() + " refs/tags/tag"));
|
||||
assertTrue(pckIn.readString() == PacketLineIn.END);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -222,6 +222,13 @@ public class GitProtocolConstants {
|
|||
*/
|
||||
public static final String CAPABILITY_PUSH_OPTIONS = "push-options"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* The server supports listing refs using protocol v2.
|
||||
*
|
||||
* @since 5.0
|
||||
*/
|
||||
public static final String COMMAND_LS_REFS = "ls-refs"; //$NON-NLS-1$
|
||||
|
||||
static enum MultiAck {
|
||||
OFF, CONTINUE, DETAILED;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
|
@ -176,6 +177,11 @@ protected void end() throws IOException {
|
|||
|
||||
boolean first = true;
|
||||
|
||||
private boolean useProtocolV2;
|
||||
|
||||
/* only used in protocol v2 */
|
||||
private final Map<String, String> symrefs = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Initialize this advertiser with a repository for peeling tags.
|
||||
*
|
||||
|
@ -186,6 +192,15 @@ public void init(Repository src) {
|
|||
repository = src;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param b
|
||||
* true if this advertiser should advertise using the
|
||||
* protocol v2 format, false otherwise
|
||||
*/
|
||||
public void setUseProtocolV2(boolean b) {
|
||||
useProtocolV2 = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle tag peeling.
|
||||
* <p>
|
||||
|
@ -253,7 +268,11 @@ public void advertiseCapability(String name, String value) {
|
|||
* @since 3.6
|
||||
*/
|
||||
public void addSymref(String from, String to) {
|
||||
advertiseCapability(OPTION_SYMREF, from + ':' + to);
|
||||
if (useProtocolV2) {
|
||||
symrefs.put(from, to);
|
||||
} else {
|
||||
advertiseCapability(OPTION_SYMREF, from + ':' + to);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -273,6 +292,23 @@ public Set<ObjectId> send(Map<String, Ref> refs) throws IOException {
|
|||
if (ref.getObjectId() == null)
|
||||
continue;
|
||||
|
||||
if (useProtocolV2) {
|
||||
String symrefPart = symrefs.containsKey(ref.getName())
|
||||
? (" symref-target:" + symrefs.get(ref.getName()))
|
||||
: "";
|
||||
String peelPart = "";
|
||||
if (derefTags) {
|
||||
if (!ref.isPeeled() && repository != null) {
|
||||
ref = repository.peel(ref);
|
||||
}
|
||||
if (ref.getPeeledObjectId() != null) {
|
||||
peelPart = " peeled:" + ref.getPeeledObjectId().getName();
|
||||
}
|
||||
}
|
||||
writeOne(ref.getObjectId().getName() + " " + ref.getName() + symrefPart + peelPart + "\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
advertiseAny(ref.getObjectId(), ref.getName());
|
||||
|
||||
if (!derefTags)
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
package org.eclipse.jgit.transport;
|
||||
|
||||
import static org.eclipse.jgit.lib.RefDatabase.ALL;
|
||||
import static org.eclipse.jgit.transport.GitProtocolConstants.COMMAND_LS_REFS;
|
||||
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT;
|
||||
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_ALLOW_REACHABLE_SHA1_IN_WANT;
|
||||
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_ALLOW_TIP_SHA1_IN_WANT;
|
||||
|
@ -117,6 +118,7 @@ public class UploadPack {
|
|||
// supports protocol version 2.
|
||||
private static final String[] v2CapabilityAdvertisement = {
|
||||
"version 2",
|
||||
COMMAND_LS_REFS
|
||||
};
|
||||
|
||||
/** Policy the server uses to validate client requests */
|
||||
|
@ -864,6 +866,35 @@ else if (requestValidator instanceof AnyRequestValidator)
|
|||
sendPack(accumulator);
|
||||
}
|
||||
|
||||
private void lsRefsV2() throws IOException {
|
||||
PacketLineOutRefAdvertiser adv = new PacketLineOutRefAdvertiser(pckOut);
|
||||
Map<String, Ref> refs = getAdvertisedOrDefaultRefs();
|
||||
String line;
|
||||
|
||||
adv.setUseProtocolV2(true);
|
||||
|
||||
line = pckIn.readString();
|
||||
|
||||
// Currently, we do not support any capabilities, so the next
|
||||
// line is DELIM if there are arguments or END if not.
|
||||
if (line == PacketLineIn.DELIM) {
|
||||
while ((line = pckIn.readString()) != PacketLineIn.END) {
|
||||
if (line.equals("peel")) {
|
||||
adv.setDerefTags(true);
|
||||
} else if (line.equals("symrefs")) {
|
||||
findSymrefs(adv, refs);
|
||||
} else {
|
||||
throw new PackProtocolException("unexpected " + line);
|
||||
}
|
||||
}
|
||||
} else if (line != PacketLineIn.END) {
|
||||
throw new PackProtocolException("unexpected " + line);
|
||||
}
|
||||
|
||||
adv.send(refs);
|
||||
adv.end();
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if this is the last command and we should tear down the
|
||||
* connection.
|
||||
|
@ -882,6 +913,10 @@ private boolean serveOneCommandV2() throws IOException {
|
|||
// case.
|
||||
return true;
|
||||
}
|
||||
if (command.equals("command=" + COMMAND_LS_REFS)) {
|
||||
lsRefsV2();
|
||||
return false;
|
||||
}
|
||||
throw new PackProtocolException("unknown command " + command);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue