Browse Source

Expose RefAdvertiser for reuse outside of the transport package

By making this class and its methods public, and the actual writing
abstract, we can reuse this code for other formats like writing an
info/refs file for HTTP transports.

Change-Id: Id0e349c30a0f5a8c1527e0e7383b80243819d9c5
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
stable-0.7
Shawn O. Pearce 15 years ago
parent
commit
7ed6805425
  1. 17
      org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
  2. 152
      org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java
  3. 17
      org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java

17
org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java

@ -76,6 +76,7 @@ import org.eclipse.jgit.revwalk.RevFlag;
import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.ReceiveCommand.Result; import org.eclipse.jgit.transport.ReceiveCommand.Result;
import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
import org.eclipse.jgit.util.io.InterruptTimer; import org.eclipse.jgit.util.io.InterruptTimer;
import org.eclipse.jgit.util.io.TimeoutInputStream; import org.eclipse.jgit.util.io.TimeoutInputStream;
import org.eclipse.jgit.util.io.TimeoutOutputStream; import org.eclipse.jgit.util.io.TimeoutOutputStream;
@ -519,7 +520,7 @@ public class ReceivePack {
private void service() throws IOException { private void service() throws IOException {
if (biDirectionalPipe) if (biDirectionalPipe)
sendAdvertisedRefs(); sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut));
else else
refs = db.getAllRefs(); refs = db.getAllRefs();
recvCommands(); recvCommands();
@ -574,9 +575,17 @@ public class ReceivePack {
} }
} }
private void sendAdvertisedRefs() throws IOException { /**
* Generate an advertisement of available refs and capabilities.
*
* @param adv
* the advertisement formatter.
* @throws IOException
* the formatter failed to write an advertisement.
*/
public void sendAdvertisedRefs(final RefAdvertiser adv) throws IOException {
final RevFlag advertised = walk.newFlag("ADVERTISED"); final RevFlag advertised = walk.newFlag("ADVERTISED");
final RefAdvertiser adv = new RefAdvertiser(pckOut, walk, advertised); adv.init(walk, advertised);
adv.advertiseCapability(CAPABILITY_DELETE_REFS); adv.advertiseCapability(CAPABILITY_DELETE_REFS);
adv.advertiseCapability(CAPABILITY_REPORT_STATUS); adv.advertiseCapability(CAPABILITY_REPORT_STATUS);
if (allowOfsDelta) if (allowOfsDelta)
@ -589,7 +598,7 @@ public class ReceivePack {
adv.includeAdditionalHaves(); adv.includeAdditionalHaves();
if (adv.isEmpty()) if (adv.isEmpty())
adv.advertiseId(ObjectId.zeroId(), "capabilities^{}"); adv.advertiseId(ObjectId.zeroId(), "capabilities^{}");
pckOut.end(); adv.end();
} }
private void recvCommands() throws IOException { private void recvCommands() throws IOException {

152
org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java

@ -61,12 +61,28 @@ import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.RevWalk;
/** Support for the start of {@link UploadPack} and {@link ReceivePack}. */ /** Support for the start of {@link UploadPack} and {@link ReceivePack}. */
class RefAdvertiser { public abstract class RefAdvertiser {
static class PacketLineOutRefAdvertiser extends RefAdvertiser {
private final PacketLineOut pckOut; private final PacketLineOut pckOut;
private final RevWalk walk; PacketLineOutRefAdvertiser(PacketLineOut out) {
pckOut = out;
}
@Override
protected void writeOne(final CharSequence line) throws IOException {
pckOut.writeString(line.toString());
}
@Override
protected void end() throws IOException {
pckOut.end();
}
}
private RevWalk walk;
private final RevFlag ADVERTISED; private RevFlag ADVERTISED;
private final StringBuilder tmpLine = new StringBuilder(100); private final StringBuilder tmpLine = new StringBuilder(100);
@ -78,22 +94,72 @@ class RefAdvertiser {
private boolean first = true; private boolean first = true;
RefAdvertiser(final PacketLineOut out, final RevWalk protoWalk, /**
final RevFlag advertisedFlag) { * Initialize a new advertisement formatter.
pckOut = out; *
* @param protoWalk
* the RevWalk used to parse objects that are advertised.
* @param advertisedFlag
* flag marked on any advertised objects parsed out of the
* {@code protoWalk}'s object pool, permitting the caller to
* later quickly determine if an object was advertised (or not).
*/
public void init(final RevWalk protoWalk, final RevFlag advertisedFlag) {
walk = protoWalk; walk = protoWalk;
ADVERTISED = advertisedFlag; ADVERTISED = advertisedFlag;
} }
void setDerefTags(final boolean deref) { /**
* Toggle tag peeling.
* <p>
* <p>
* This method must be invoked prior to any of the following:
* <ul>
* <li>{@link #send(Collection)}
* <li>{@link #advertiseHave(AnyObjectId)}
* <li>{@link #includeAdditionalHaves()}
* </ul>
*
* @param deref
* true to show the dereferenced value of a tag as the special
* ref <code>$tag^{}</code> ; false to omit it from the output.
*/
public void setDerefTags(final boolean deref) {
derefTags = deref; derefTags = deref;
} }
void advertiseCapability(String name) { /**
* Add one protocol capability to the initial advertisement.
* <p>
* This method must be invoked prior to any of the following:
* <ul>
* <li>{@link #send(Collection)}
* <li>{@link #advertiseHave(AnyObjectId)}
* <li>{@link #includeAdditionalHaves()}
* </ul>
*
* @param name
* the name of a single protocol capability supported by the
* caller. The set of capabilities are sent to the client in the
* advertisement, allowing the client to later selectively enable
* features it recognizes.
*/
public void advertiseCapability(String name) {
capablities.add(name); capablities.add(name);
} }
void send(final Collection<Ref> refs) throws IOException { /**
* Format an advertisement for the supplied refs.
*
* @param refs
* zero or more refs to format for the client. The collection is
* copied and sorted before display and therefore may appear in
* any order.
* @throws IOException
* the underlying output stream failed to write out an
* advertisement record.
*/
public void send(final Collection<Ref> refs) throws IOException {
for (final Ref r : RefComparator.sort(refs)) { for (final Ref r : RefComparator.sort(refs)) {
final RevObject obj = parseAnyOrNull(r.getObjectId()); final RevObject obj = parseAnyOrNull(r.getObjectId());
if (obj != null) { if (obj != null) {
@ -104,7 +170,21 @@ class RefAdvertiser {
} }
} }
void advertiseHave(AnyObjectId id) throws IOException { /**
* Advertise one object is available using the magic {@code .have}.
* <p>
* The magic {@code .have} advertisement is not available for fetching by a
* client, but can be used by a client when considering a delta base
* candidate before transferring data in a push. Within the record created
* by this method the ref name is simply the invalid string {@code .have}.
*
* @param id
* identity of the object that is assumed to exist.
* @throws IOException
* the underlying output stream failed to write out an
* advertisement record.
*/
public void advertiseHave(AnyObjectId id) throws IOException {
RevObject obj = parseAnyOrNull(id); RevObject obj = parseAnyOrNull(id);
if (obj != null) { if (obj != null) {
advertiseAnyOnce(obj, ".have"); advertiseAnyOnce(obj, ".have");
@ -113,7 +193,14 @@ class RefAdvertiser {
} }
} }
void includeAdditionalHaves() throws IOException { /**
* Include references of alternate repositories as {@code .have} lines.
*
* @throws IOException
* the underlying output stream failed to write out an
* advertisement record.
*/
public void includeAdditionalHaves() throws IOException {
additionalHaves(walk.getRepository().getObjectDatabase()); additionalHaves(walk.getRepository().getObjectDatabase());
} }
@ -129,7 +216,8 @@ class RefAdvertiser {
advertiseHave(r.getObjectId()); advertiseHave(r.getObjectId());
} }
boolean isEmpty() { /** @return true if no advertisements have been sent yet. */
public boolean isEmpty() {
return first; return first;
} }
@ -172,7 +260,22 @@ class RefAdvertiser {
advertiseAny(tag.getObject(), refName); advertiseAny(tag.getObject(), refName);
} }
void advertiseId(final AnyObjectId id, final String refName) /**
* Advertise one object under a specific name.
* <p>
* If the advertised object is a tag, this method does not advertise the
* peeled version of it.
*
* @param id
* the object to advertise.
* @param refName
* name of the reference to advertise the object as, can be any
* string not including the NUL byte.
* @throws IOException
* the underlying output stream failed to write out an
* advertisement record.
*/
public void advertiseId(final AnyObjectId id, final String refName)
throws IOException { throws IOException {
tmpLine.setLength(0); tmpLine.setLength(0);
id.copyTo(tmpId, tmpLine); id.copyTo(tmpId, tmpLine);
@ -190,6 +293,27 @@ class RefAdvertiser {
} }
} }
tmpLine.append('\n'); tmpLine.append('\n');
pckOut.writeString(tmpLine.toString()); writeOne(tmpLine);
} }
/**
* Write a single advertisement line.
*
* @param line
* the advertisement line to be written. The line always ends
* with LF. Never null or the empty string.
* @throws IOException
* the underlying output stream failed to write out an
* advertisement record.
*/
protected abstract void writeOne(CharSequence line) throws IOException;
/**
* Mark the end of the advertisements.
*
* @throws IOException
* the underlying output stream failed to write out an
* advertisement record.
*/
protected abstract void end() throws IOException;
} }

17
org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java

@ -70,6 +70,7 @@ import org.eclipse.jgit.revwalk.RevFlagSet;
import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevTag; import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
import org.eclipse.jgit.util.io.InterruptTimer; import org.eclipse.jgit.util.io.InterruptTimer;
import org.eclipse.jgit.util.io.TimeoutInputStream; import org.eclipse.jgit.util.io.TimeoutInputStream;
import org.eclipse.jgit.util.io.TimeoutOutputStream; import org.eclipse.jgit.util.io.TimeoutOutputStream;
@ -282,7 +283,7 @@ public class UploadPack {
private void service() throws IOException { private void service() throws IOException {
if (biDirectionalPipe) if (biDirectionalPipe)
sendAdvertisedRefs(); sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut));
else { else {
refs = db.getAllRefs(); refs = db.getAllRefs();
for (Ref r : refs.values()) { for (Ref r : refs.values()) {
@ -309,8 +310,16 @@ public class UploadPack {
sendPack(); sendPack();
} }
private void sendAdvertisedRefs() throws IOException { /**
final RefAdvertiser adv = new RefAdvertiser(pckOut, walk, ADVERTISED); * Generate an advertisement of available refs and capabilities.
*
* @param adv
* the advertisement formatter.
* @throws IOException
* the formatter failed to write an advertisement.
*/
public void sendAdvertisedRefs(final RefAdvertiser adv) throws IOException {
adv.init(walk, ADVERTISED);
adv.advertiseCapability(OPTION_INCLUDE_TAG); adv.advertiseCapability(OPTION_INCLUDE_TAG);
adv.advertiseCapability(OPTION_MULTI_ACK_DETAILED); adv.advertiseCapability(OPTION_MULTI_ACK_DETAILED);
adv.advertiseCapability(OPTION_MULTI_ACK); adv.advertiseCapability(OPTION_MULTI_ACK);
@ -322,7 +331,7 @@ public class UploadPack {
adv.setDerefTags(true); adv.setDerefTags(true);
refs = db.getAllRefs(); refs = db.getAllRefs();
adv.send(refs.values()); adv.send(refs.values());
pckOut.end(); adv.end();
} }
private void recvWants() throws IOException { private void recvWants() throws IOException {

Loading…
Cancel
Save