changeset 13115:bda5f35fbf67

httpsendfile: record progress information during read() This allows us to provide deterministic progress information during transfer of bundle data over HTTP. This is required because we currently buffer the bundle data to local disk prior to transfer since wsgiref lacks chunked transfer-coding support.
author Augie Fackler <durin42@gmail.com>
date Fri, 10 Dec 2010 13:31:06 -0600
parents 8f29a08e7bbc
children c36dad4f6e54
files mercurial/httprepo.py mercurial/url.py
diffstat 2 files changed, 22 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/httprepo.py	Tue Dec 07 15:50:28 2010 +0100
+++ b/mercurial/httprepo.py	Fri Dec 10 13:31:06 2010 -0600
@@ -160,7 +160,7 @@
                     break
 
         tempname = changegroup.writebundle(cg, None, type)
-        fp = url.httpsendfile(tempname, "rb")
+        fp = url.httpsendfile(self.ui, tempname, "rb")
         headers = {'Content-Type': 'application/mercurial-0.1'}
 
         try:
--- a/mercurial/url.py	Tue Dec 07 15:50:28 2010 +0100
+++ b/mercurial/url.py	Fri Dec 10 13:31:06 2010 -0600
@@ -258,18 +258,36 @@
     defines a __len__ attribute to feed the Content-Length header.
     """
 
-    def __init__(self, *args, **kwargs):
+    def __init__(self, ui, *args, **kwargs):
         # We can't just "self._data = open(*args, **kwargs)" here because there
         # is an "open" function defined in this module that shadows the global
         # one
+        self.ui = ui
         self._data = __builtin__.open(*args, **kwargs)
-        self.read = self._data.read
         self.seek = self._data.seek
         self.close = self._data.close
         self.write = self._data.write
+        self._len = os.fstat(self._data.fileno()).st_size
+        self._pos = 0
+        self._total = len(self) / 1024 * 2
+
+    def read(self, *args, **kwargs):
+        try:
+            ret = self._data.read(*args, **kwargs)
+        except EOFError:
+            self.ui.progress(_('sending'), None)
+        self._pos += len(ret)
+        # We pass double the max for total because we currently have
+        # to send the bundle twice in the case of a server that
+        # requires authentication. Since we can't know until we try
+        # once whether authentication will be required, just lie to
+        # the user and maybe the push succeeds suddenly at 50%.
+        self.ui.progress(_('sending'), self._pos / 1024,
+                         unit=_('kb'), total=self._total)
+        return ret
 
     def __len__(self):
-        return os.fstat(self._data.fileno()).st_size
+        return self._len
 
 def _gen_sendfile(connection):
     def _sendfile(self, data):