PatchApplier: wrap output's TemporaryBuffer with a CountingOutputStream

The documentation for TemporaryBuffer::length says:
"The length is only accurate after {@link #close()} has been invoked".
However, we need to have the stream open while accessing the length.

This prevents patches on large files to be applied correctly, as the
result get trimmed.

Bug: Google b/309500446
Change-Id: Ic1540f6d0044088f3b46f1fad5f6a28ec254b711
This commit is contained in:
Nitzan Gur-Furman 2023-11-15 21:04:00 +01:00
parent 91c9146224
commit 754a1b4922
5 changed files with 14 additions and 2 deletions

View File

@ -496,6 +496,14 @@ public void testRemoveNewlineAtEnd() throws Exception {
Result result = applyPatch();
verifyChange(result, "x_last_rm_nl");
}
@Test
public void testVeryLongFile() throws Exception {
init("very_long_file");
Result result = applyPatch();
verifyChange(result, "very_long_file");
}
}
public static class WithWorktree extends Base {

View File

@ -88,6 +88,7 @@
import org.eclipse.jgit.util.TemporaryBuffer.LocalFile;
import org.eclipse.jgit.util.io.BinaryDeltaInputStream;
import org.eclipse.jgit.util.io.BinaryHunkInputStream;
import org.eclipse.jgit.util.io.CountingOutputStream;
import org.eclipse.jgit.util.io.EolStreamTypeUtil;
import org.eclipse.jgit.util.sha1.SHA1;
@ -1013,7 +1014,10 @@ && canApplyAt(hunkLines, newLines, 0)) {
// We could check if old == new, but the short-circuiting complicates
// logic for inCore patching, so just write the new thing regardless.
TemporaryBuffer buffer = new TemporaryBuffer.LocalFile(null);
try (OutputStream out = buffer) {
// TemporaryBuffer::length reports incorrect length until the buffer
// is closed. To use it as input for ContentStreamLoader below, we
// need a wrapper with a reliable in-progress length.
try (CountingOutputStream out = new CountingOutputStream(buffer)) {
for (Iterator<ByteBuffer> l = newLines.iterator(); l.hasNext();) {
ByteBuffer line = l.next();
if (line == null) {
@ -1026,7 +1030,7 @@ && canApplyAt(hunkLines, newLines, 0)) {
}
}
return new ContentStreamLoader(buffer::openInputStream,
buffer.length());
out.getCount());
}
}