[sideband] Ensure last bit of progress channel is written

If the last sideband progress message didn't end in \r or \n, there
may still be a buffered message at the end of a fetch or push. Ensure
that message gets written, too, even if it may be only partial.

Bug: 575629
Change-Id: I38edccb5cffb89e00e468480b43c7d951fb63e8e
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
This commit is contained in:
Thomas Wolf 2022-02-26 12:46:50 +01:00
parent 45287f1097
commit ac78c17523
4 changed files with 56 additions and 7 deletions

View File

@ -79,6 +79,8 @@ public void progressPartial() throws IOException {
init(packet("message"));
assertTrue(sideband.read() < 0);
assertEquals("", messages.toString());
sideband.drainMessages();
assertEquals("message\n", messages.toString());
}
@Test
@ -128,6 +130,8 @@ public void progressPartialCR() throws IOException {
init(packet("message 0%\rmessage 100%"));
assertTrue(sideband.read() < 0);
assertEquals("message 0%\r", messages.toString());
sideband.drainMessages();
assertEquals("message 0%\rmessage 100%\n", messages.toString());
}
@Test
@ -135,6 +139,8 @@ public void progressPartialLF() throws IOException {
init(packet("message 0%\nmessage 100%"));
assertTrue(sideband.read() < 0);
assertEquals("message 0%\n", messages.toString());
sideband.drainMessages();
assertEquals("message 0%\nmessage 100%\n", messages.toString());
}
@Test
@ -142,6 +148,8 @@ public void progressPartialCRLF() throws IOException {
init(packet("message 0%\r\nmessage 100%"));
assertTrue(sideband.read() < 0);
assertEquals("message 0%\r\n", messages.toString());
sideband.drainMessages();
assertEquals("message 0%\r\nmessage 100%\n", messages.toString());
}
@Test
@ -152,6 +160,8 @@ public void progressPartialSplitCR() throws IOException {
assertEquals("", messages.toString());
assertTrue(sideband.read() < 0);
assertEquals("message 0%\r", messages.toString());
sideband.drainMessages();
assertEquals("message 0%\rmessage 100%\n", messages.toString());
}
@Test
@ -162,6 +172,8 @@ public void progressPartialSplitLF() throws IOException {
assertEquals("", messages.toString());
assertTrue(sideband.read() < 0);
assertEquals("message 0%\n", messages.toString());
sideband.drainMessages();
assertEquals("message 0%\nmessage 100%\n", messages.toString());
}
@Test
@ -172,6 +184,8 @@ public void progressPartialSplitCRLF() throws IOException {
assertEquals("", messages.toString());
assertTrue(sideband.read() < 0);
assertEquals("message 0%\r\n", messages.toString());
sideband.drainMessages();
assertEquals("message 0%\r\nmessage 100%\n", messages.toString());
}
@Test
@ -197,6 +211,9 @@ public void progressInterleavedPartial() throws IOException {
assertEquals("message 0%\r", messages.toString());
assertTrue(sideband.read() < 0);
assertEquals("message 0%\rmessage 10%\r", messages.toString());
sideband.drainMessages();
assertEquals("message 0%\rmessage 10%\rmessage 100%\n",
messages.toString());
}
private String packet(String data) {

View File

@ -1,7 +1,7 @@
/*
* Copyright (C) 2008, 2010 Google Inc.
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008, 2020 Shawn O. Pearce <spearce@spearce.org> and others
* Copyright (C) 2008, 2022 Shawn O. Pearce <spearce@spearce.org> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@ -1004,9 +1004,12 @@ private void receivePack(final ProgressMonitor monitor,
OutputStream outputStream) throws IOException {
onReceivePack();
InputStream input = in;
if (sideband)
input = new SideBandInputStream(input, monitor, getMessageWriter(),
outputStream);
SideBandInputStream sidebandIn = null;
if (sideband) {
sidebandIn = new SideBandInputStream(input, monitor,
getMessageWriter(), outputStream);
input = sidebandIn;
}
try (ObjectInserter ins = local.newObjectInserter()) {
PackParser parser = ins.newPackParser(input);
@ -1015,6 +1018,10 @@ private void receivePack(final ProgressMonitor monitor,
parser.setLockMessage(lockMessage);
packLock = parser.parse(monitor);
ins.flush();
} finally {
if (sidebandIn != null) {
sidebandIn.drainMessages();
}
}
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
* Copyright (C) 2008, 2022 Shawn O. Pearce <spearce@spearce.org> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@ -194,10 +194,11 @@ protected void doPush(final ProgressMonitor monitor,
// the other data channels.
//
int b = in.read();
if (0 <= b)
if (0 <= b) {
throw new TransportException(uri, MessageFormat.format(
JGitText.get().expectedEOFReceived,
Character.valueOf((char) b)));
}
}
}
} catch (TransportException e) {
@ -205,6 +206,9 @@ protected void doPush(final ProgressMonitor monitor,
} catch (Exception e) {
throw new TransportException(uri, e.getMessage(), e);
} finally {
if (in instanceof SideBandInputStream) {
((SideBandInputStream) in).drainMessages();
}
close();
}
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
* Copyright (C) 2008, 2022 Shawn O. Pearce <spearce@spearce.org> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@ -28,6 +28,8 @@
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Unmultiplexes the data portion of a side-band channel.
@ -46,6 +48,10 @@
* @since 4.11
*/
public class SideBandInputStream extends InputStream {
private static final Logger LOG = LoggerFactory
.getLogger(SideBandInputStream.class);
static final int CH_DATA = 1;
static final int CH_PROGRESS = 2;
static final int CH_ERROR = 3;
@ -210,6 +216,21 @@ private void beginTask(int totalWorkUnits) {
monitor.beginTask(remote(currentTask), totalWorkUnits);
}
/**
* Forces any buffered progress messages to be written.
*/
void drainMessages() {
if (!progressBuffer.isEmpty()) {
try {
progress("\n"); //$NON-NLS-1$
} catch (IOException e) {
// Just log; otherwise this IOException might hide a real
// TransportException
LOG.error(e.getMessage(), e);
}
}
}
private static String remote(String msg) {
String prefix = JGitText.get().prefixRemote;
StringBuilder r = new StringBuilder(prefix.length() + msg.length() + 1);