--- a/mercurial/sshpeer.py Tue Feb 18 21:23:13 2025 +0100
+++ b/mercurial/sshpeer.py Wed Feb 05 16:49:43 2025 +0000
@@ -10,6 +10,8 @@
import re
import uuid
+from typing import Callable, Optional
+
from .i18n import _
from . import (
error,
@@ -47,6 +49,31 @@
display(_(b"remote: "), l, b'\n')
+def _write_all(
+ write_once: Callable[[bytes], Optional[int]],
+ data: bytes,
+) -> Optional[int]:
+ """write data with a non blocking function
+
+ In case not all data were written, keep writing until everything is
+ written.
+ """
+ to_write = len(data)
+ written = write_once(data)
+ if written is None:
+ written = 0
+ if written < to_write:
+ data = memoryview(data)
+ while written < to_write:
+ wrote = write_once(data[written:])
+ # XXX if number of written bytes is "None", the destination is
+ # full. Some `select` call would be better than the current active
+ # polling.
+ if wrote is not None:
+ written += wrote
+ return written
+
+
class doublepipe:
"""Operate a side-channel pipe in addition of a main one
@@ -91,9 +118,14 @@
act = fds
return (self._main.fileno() in act, self._side.fileno() in act)
- def write(self, data):
+ def _write_once(self, data: bytes) -> Optional[int]:
+ """Write as much data as possible in a non blocking way"""
return self._call(b'write', data)
+ def write(self, data: bytes) -> Optional[int]:
+ """write all data in a blocking way"""
+ return _write_all(self._write_once, data)
+
def read(self, size):
r = self._call(b'read', size)
if size != 0 and not r:
@@ -124,6 +156,8 @@
# data can be '' or 0
if (data is not None and not data) or self._main.closed:
_forwardoutput(self._ui, self._side)
+ if methname == b'write':
+ return 0
return b''
while True:
mainready, sideready = self._wait()