import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevFlag;
-import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.RefAdvertiser;
import org.eclipse.jgit.util.HttpSupport;
rsp.setCharacterEncoding(Constants.CHARACTER_ENCODING);
final Repository db = getRepository(req);
- final RevWalk walk = new RevWalk(db);
- try {
- final RevFlag ADVERTISED = walk.newFlag("ADVERTISED");
+ final OutputStreamWriter out = new OutputStreamWriter(
+ new SmartOutputStream(req, rsp), Constants.CHARSET);
+ final RefAdvertiser adv = new RefAdvertiser() {
+ @Override
+ protected void writeOne(final CharSequence line) throws IOException {
+ // Whoever decided that info/refs should use a different
+ // delimiter than the native git:// protocol shouldn't
+ // be allowed to design this sort of stuff. :-(
+ out.append(line.toString().replace(' ', '\t'));
+ }
- final OutputStreamWriter out = new OutputStreamWriter(
- new SmartOutputStream(req, rsp), Constants.CHARSET);
- final RefAdvertiser adv = new RefAdvertiser() {
- @Override
- protected void writeOne(final CharSequence line)
- throws IOException {
- // Whoever decided that info/refs should use a different
- // delimiter than the native git:// protocol shouldn't
- // be allowed to design this sort of stuff. :-(
- out.append(line.toString().replace(' ', '\t'));
- }
+ @Override
+ protected void end() {
+ // No end marker required for info/refs format.
+ }
+ };
+ adv.init(db);
+ adv.setDerefTags(true);
- @Override
- protected void end() {
- // No end marker required for info/refs format.
- }
- };
- adv.init(walk, ADVERTISED);
- adv.setDerefTags(true);
-
- Map<String, Ref> refs = db.getAllRefs();
- refs.remove(Constants.HEAD);
- adv.send(refs);
- out.close();
- } finally {
- walk.release();
- }
+ Map<String, Ref> refs = db.getAllRefs();
+ refs.remove(Constants.HEAD);
+ adv.send(refs);
+ out.close();
}
}
package org.eclipse.jgit.transport;
import java.io.IOException;
+import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefComparator;
import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevFlag;
-import org.eclipse.jgit.revwalk.RevObject;
-import org.eclipse.jgit.revwalk.RevTag;
-import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.util.RefMap;
/** Support for the start of {@link UploadPack} and {@link ReceivePack}. */
}
}
- private RevWalk walk;
-
- private RevFlag ADVERTISED;
-
private final StringBuilder tmpLine = new StringBuilder(100);
private final char[] tmpId = new char[Constants.OBJECT_ID_STRING_LENGTH];
private final Set<String> capablities = new LinkedHashSet<String>();
+ private final Set<ObjectId> sent = new HashSet<ObjectId>();
+
+ private Repository repository;
+
private boolean derefTags;
private boolean first = true;
/**
- * Initialize a new advertisement formatter.
+ * Initialize this advertiser with a repository for peeling tags.
*
- * @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).
+ * @param src
+ * the repository to read from.
*/
- public void init(final RevWalk protoWalk, final RevFlag advertisedFlag) {
- walk = protoWalk;
- ADVERTISED = advertisedFlag;
+ public void init(Repository src) {
+ repository = src;
}
/**
* This method must be invoked prior to any of the following:
* <ul>
* <li>{@link #send(Map)}
- * <li>{@link #advertiseHave(AnyObjectId)}
- * <li>{@link #includeAdditionalHaves(Repository)}
* </ul>
*
* @param deref
* zero or more refs to format for the client. The collection is
* sorted before display if necessary, and therefore may appear
* in any order.
+ * @return set of ObjectIds that were advertised to the client.
* @throws IOException
* the underlying output stream failed to write out an
* advertisement record.
*/
- public void send(final Map<String, Ref> refs) throws IOException {
- for (final Ref r : getSortedRefs(refs)) {
- final RevObject obj = parseAnyOrNull(r.getObjectId());
- if (obj != null) {
- advertiseAny(obj, r.getName());
- if (derefTags && obj instanceof RevTag)
- advertiseTag((RevTag) obj, r.getName() + "^{}");
+ public Set<ObjectId> send(Map<String, Ref> refs) throws IOException {
+ for (Ref ref : getSortedRefs(refs)) {
+ if (ref.getObjectId() == null)
+ continue;
+
+ advertiseAny(ref.getObjectId(), ref.getName());
+
+ if (!derefTags)
+ continue;
+
+ if (!ref.isPeeled()) {
+ if (repository == null)
+ continue;
+ ref = repository.peel(ref);
}
+
+ if (ref.getPeeledObjectId() != null)
+ advertiseAny(ref.getPeeledObjectId(), ref.getName() + "^{}");
}
+ return sent;
}
private Iterable<Ref> getSortedRefs(Map<String, Ref> all) {
* advertisement record.
*/
public void advertiseHave(AnyObjectId id) throws IOException {
- RevObject obj = parseAnyOrNull(id);
- if (obj != null) {
- advertiseAnyOnce(obj, ".have");
- if (obj instanceof RevTag)
- advertiseAnyOnce(((RevTag) obj).getObject(), ".have");
- }
+ advertiseAnyOnce(id, ".have");
}
/**
return first;
}
- private RevObject parseAnyOrNull(final AnyObjectId id) {
- if (id == null)
- return null;
- try {
- return walk.parseAny(id);
- } catch (IOException e) {
- return null;
- }
- }
-
- private void advertiseAnyOnce(final RevObject obj, final String refName)
+ private void advertiseAnyOnce(AnyObjectId obj, final String refName)
throws IOException {
- if (!obj.has(ADVERTISED))
+ if (!sent.contains(obj))
advertiseAny(obj, refName);
}
- private void advertiseAny(final RevObject obj, final String refName)
+ private void advertiseAny(AnyObjectId obj, final String refName)
throws IOException {
- obj.add(ADVERTISED);
+ sent.add(obj.toObjectId());
advertiseId(obj, refName);
}
- private void advertiseTag(final RevTag tag, final String refName)
- throws IOException {
- RevObject o = tag;
- do {
- // Fully unwrap here so later on we have these already parsed.
- final RevObject target = ((RevTag) o).getObject();
- try {
- walk.parseHeaders(target);
- } catch (IOException err) {
- return;
- }
- target.add(ADVERTISED);
- o = target;
- } while (o instanceof RevTag);
- advertiseAny(tag.getObject(), refName);
- }
-
/**
* Advertise one object under a specific name.
* <p>
/** null if {@link #commonBase} should be examined again. */
private Boolean okToGiveUp;
- /** Marked on objects we sent in our advertisement list. */
- private final RevFlag ADVERTISED;
+ /** Objects we sent in our advertisement list, clients can ask for these. */
+ private Set<ObjectId> advertised;
/** Marked on objects the client has asked us to give them. */
private final RevFlag WANT;
walk = new RevWalk(db);
walk.setRetainBody(false);
- ADVERTISED = walk.newFlag("ADVERTISED");
WANT = walk.newFlag("WANT");
PEER_HAS = walk.newFlag("PEER_HAS");
COMMON = walk.newFlag("COMMON");
walk.carry(PEER_HAS);
SAVE = new RevFlagSet();
- SAVE.add(ADVERTISED);
SAVE.add(WANT);
SAVE.add(PEER_HAS);
refFilter = RefFilter.DEFAULT;
if (biDirectionalPipe)
sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut));
else {
+ advertised = new HashSet<ObjectId>();
refs = refFilter.filter(db.getAllRefs());
- for (Ref r : refs.values()) {
- try {
- walk.parseAny(r.getObjectId()).add(ADVERTISED);
- } catch (IOException e) {
- // Skip missing/corrupt objects
- }
+ for (Ref ref : refs.values()) {
+ if (ref.getObjectId() != null)
+ advertised.add(ref.getObjectId());
}
}
* the formatter failed to write an advertisement.
*/
public void sendAdvertisedRefs(final RefAdvertiser adv) throws IOException {
- adv.init(walk, ADVERTISED);
+ adv.init(db);
adv.advertiseCapability(OPTION_INCLUDE_TAG);
adv.advertiseCapability(OPTION_MULTI_ACK_DETAILED);
adv.advertiseCapability(OPTION_MULTI_ACK);
adv.advertiseCapability(OPTION_NO_PROGRESS);
adv.setDerefTags(true);
refs = refFilter.filter(db.getAllRefs());
- adv.send(refs);
+ advertised = adv.send(refs);
adv.end();
}
if (o.has(WANT)) {
// Already processed, the client repeated itself.
- } else if (o.has(ADVERTISED)) {
+ } else if (advertised.contains(o)) {
o.add(WANT);
wantAll.add(o);