D2404: util: enable observing of util.bufferedinputpipe

indygreg (Gregory Szorc) phabricator at mercurial-scm.org
Mon Feb 26 16:17:34 EST 2018


indygreg updated this revision to Diff 6136.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2404?vs=6025&id=6136

REVISION DETAIL
  https://phab.mercurial-scm.org/D2404

AFFECTED FILES
  mercurial/util.py

CHANGE DETAILS

diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -373,6 +373,13 @@
     This class lives in the 'util' module because it makes use of the 'os'
     module from the python stdlib.
     """
+    def __new__(cls, fh):
+        # If we receive a fileobjectproxy, we need to use a variation of this
+        # class that notifies observers about activity.
+        if isinstance(fh, fileobjectproxy):
+            cls = observedbufferedinputpipe
+
+        return super(bufferedinputpipe, cls).__new__(cls)
 
     def __init__(self, input):
         self._input = input
@@ -453,6 +460,8 @@
             self._lenbuf += len(data)
             self._buffer.append(data)
 
+        return data
+
 def mmapread(fp):
     try:
         fd = getattr(fp, 'fileno', lambda: fp)()
@@ -505,6 +514,8 @@
 
     def __getattribute__(self, name):
         ours = {
+            r'_observer',
+
             # IOBase
             r'close',
             # closed if a property
@@ -639,6 +650,46 @@
         return object.__getattribute__(self, r'_observedcall')(
             r'read1', *args, **kwargs)
 
+class observedbufferedinputpipe(bufferedinputpipe):
+    """A variation of bufferedinputpipe that is aware of fileobjectproxy.
+
+    ``bufferedinputpipe`` makes low-level calls to ``os.read()`` that
+    bypass ``fileobjectproxy``. Because of this, we need to make
+    ``bufferedinputpipe`` aware of these operations.
+
+    This variation of ``bufferedinputpipe`` can notify observers about
+    ``os.read()`` events. It also re-publishes other events, such as
+    ``read()`` and ``readline()``.
+    """
+    def _fillbuffer(self):
+        res = super(observedbufferedinputpipe, self)._fillbuffer()
+
+        fn = getattr(self._input._observer, r'osread', None)
+        if fn:
+            fn(res, _chunksize)
+
+        return res
+
+    # We use different observer methods because the operation isn't
+    # performed on the actual file object but on us.
+    def read(self, size):
+        res = super(observedbufferedinputpipe, self).read(size)
+
+        fn = getattr(self._input._observer, r'bufferedread', None)
+        if fn:
+            fn(res, size)
+
+        return res
+
+    def readline(self, *args, **kwargs):
+        res = super(observedbufferedinputpipe, self).readline(*args, **kwargs)
+
+        fn = getattr(self._input._observer, r'bufferedreadline', None)
+        if fn:
+            fn(res)
+
+        return res
+
 DATA_ESCAPE_MAP = {pycompat.bytechr(i): br'\x%02x' % i for i in range(256)}
 DATA_ESCAPE_MAP.update({
     b'\\': b'\\\\',
@@ -702,6 +753,16 @@
 
         self.fh.write('%s> flush() -> %r\n' % (self.name, res))
 
+    # For observedbufferedinputpipe.
+    def bufferedread(self, res, size):
+        self.fh.write('%s> bufferedread(%d) -> %d' % (
+            self.name, size, len(res)))
+        self._writedata(res)
+
+    def bufferedreadline(self, res):
+        self.fh.write('%s> bufferedreadline() -> %d' % (self.name, len(res)))
+        self._writedata(res)
+
 def makeloggingfileobject(logh, fh, name, reads=True, writes=True,
                           logdata=False):
     """Turn a file object into a logging file object."""



To: indygreg, #hg-reviewers
Cc: mercurial-devel


More information about the Mercurial-devel mailing list