diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties index 9b1cb0c91..bc4603eeb 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties @@ -329,6 +329,7 @@ packetSizeMustBeAtMost=packet size {0} must be <= {1} packfileCorruptionDetected=Packfile corruption detected: {0} packfileIsTruncated=Packfile is truncated. packingCancelledDuringObjectsWriting=Packing cancelled during objects writing +packWriterStatistics=Total {0,number,#0} (delta {1,number,#0}), reused {2,number,#0} (delta {3,number,#0}) pathIsNotInWorkingDir=Path is not in working dir peeledLineBeforeRef=Peeled line before ref. peerDidNotSupplyACompleteObjectGraph=peer did not supply a complete object graph diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java index bd63a42db..2834bd254 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java @@ -389,6 +389,7 @@ public class JGitText extends TranslationBundle { /***/ public String packfileCorruptionDetected; /***/ public String packfileIsTruncated; /***/ public String packingCancelledDuringObjectsWriting; + /***/ public String packWriterStatistics; /***/ public String pathIsNotInWorkingDir; /***/ public String peeledLineBeforeRef; /***/ public String peerDidNotSupplyACompleteObjectGraph; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackWriter.java index 3f6a091fc..320fa3b00 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackWriter.java @@ -50,6 +50,7 @@ import static org.eclipse.jgit.storage.pack.StoredObjectRepresentation.PACK_WHOL import java.io.IOException; import java.io.OutputStream; import java.security.MessageDigest; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -155,6 +156,8 @@ public class PackWriter { private final PackConfig config; + private final Statistics stats; + private List sortedByName; private byte packcsum[]; @@ -229,6 +232,7 @@ public class PackWriter { deltaBaseAsOffset = config.isDeltaBaseAsOffset(); reuseDeltas = config.isReuseDeltas(); + stats = new Statistics(); } /** @@ -498,6 +502,7 @@ public class PackWriter { packStream, this); int objCnt = getObjectsNumber(); + stats.totalObjects = objCnt; writeMonitor.beginTask(JGitText.get().writingObjects, objCnt); out.writeFileHeader(PACK_VERSION_GENERATED, objCnt); out.flush(); @@ -508,6 +513,15 @@ public class PackWriter { writeMonitor.endTask(); } + /** + * @return description of what this PackWriter did in order to create the + * final pack stream. The object is only available to callers after + * {@link #writePack(ProgressMonitor, ProgressMonitor, OutputStream)} + */ + public Statistics getStatistics() { + return stats; + } + /** Release all resources used by this writer. */ public void release() { reader.release(); @@ -846,6 +860,9 @@ public class PackWriter { reuseSupport.copyObjectAsIs(out, otp); out.endObject(); otp.setCRC(out.getCRC32()); + stats.reusedObjects++; + if (otp.isDeltaRepresentation()) + stats.reusedDeltas++; return; } catch (StoredObjectRepresentationNotAvailableException gone) { if (otp.getOffset() == out.length()) { @@ -940,6 +957,7 @@ public class PackWriter { DeflaterOutputStream dst = new DeflaterOutputStream(out, deflater); delta.writeTo(dst, null); dst.finish(); + stats.totalDeltas++; } private TemporaryBuffer.Heap delta(final ObjectToPack otp) @@ -1167,4 +1185,22 @@ public class PackWriter { otp.select(next); } + + /** Summary of how PackWriter created the pack. */ + public static class Statistics { + long totalObjects; + + long totalDeltas; + + long reusedObjects; + + long reusedDeltas; + + /** @return formatted message string for display to clients. */ + public String getMessage() { + return MessageFormat.format(JGitText.get().packWriterStatistics, // + totalObjects, totalDeltas, // + reusedObjects, reusedDeltas); + } + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java index 1082cc06e..d8edfa0df 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java @@ -57,6 +57,7 @@ import java.util.Set; import org.eclipse.jgit.JGitText; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.PackProtocolException; +import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ProgressMonitor; @@ -614,6 +615,7 @@ public class UploadPack { ProgressMonitor pm = NullProgressMonitor.INSTANCE; OutputStream packOut = rawOut; + SideBandOutputStream msgOut = null; if (sideband) { int bufsz = SideBandOutputStream.SMALL_BUF; @@ -622,9 +624,11 @@ public class UploadPack { packOut = new SideBandOutputStream(SideBandOutputStream.CH_DATA, bufsz, rawOut); - if (!options.contains(OPTION_NO_PROGRESS)) - pm = new SideBandProgressMonitor(new SideBandOutputStream( - SideBandOutputStream.CH_PROGRESS, bufsz, rawOut)); + if (!options.contains(OPTION_NO_PROGRESS)) { + msgOut = new SideBandOutputStream( + SideBandOutputStream.CH_PROGRESS, bufsz, rawOut); + pm = new SideBandProgressMonitor(msgOut); + } } PackConfig cfg = packConfig; @@ -650,11 +654,19 @@ public class UploadPack { pw.addObject(t); } } + pw.writePack(pm, NullProgressMonitor.INSTANCE, packOut); + packOut.flush(); + + if (msgOut != null) { + String msg = pw.getStatistics().getMessage() + '\n'; + msgOut.write(Constants.encode(msg)); + msgOut.flush(); + } + } finally { pw.release(); } - packOut.flush(); if (sideband) pckOut.end();