mercurial/changegroup.py
branchstable
changeset 13457 e74fe15dc7fd
parent 13456 ab3f4ee48adc
child 13458 9f2c407caf34
equal deleted inserted replaced
13456:ab3f4ee48adc 13457:e74fe15dc7fd
     7 
     7 
     8 from i18n import _
     8 from i18n import _
     9 import util
     9 import util
    10 import struct, os, bz2, zlib, tempfile
    10 import struct, os, bz2, zlib, tempfile
    11 
    11 
    12 def getchunk(source):
    12 def readexactly(stream, n):
    13     """return the next chunk from changegroup 'source' as a string"""
    13     '''read n bytes from stream.read and abort if less was available'''
    14     d = source.read(4)
    14     s = stream.read(n)
       
    15     if len(s) < n:
       
    16         raise util.Abort(_("stream ended unexpectedly"
       
    17                            " (got %d bytes, expected %d)")
       
    18                           % (len(s), n))
       
    19     return s
       
    20 
       
    21 def getchunk(stream):
       
    22     """return the next chunk from stream as a string"""
       
    23     d = readexactly(stream, 4)
    15     l = struct.unpack(">l", d)[0]
    24     l = struct.unpack(">l", d)[0]
    16     if l <= 4:
    25     if l <= 4:
    17         return ""
    26         return ""
    18     d = source.read(l - 4)
    27     return readexactly(stream, l - 4)
    19     if len(d) < l - 4:
       
    20         raise util.Abort(_("premature EOF reading chunk"
       
    21                            " (got %d bytes, expected %d)")
       
    22                           % (len(d), l - 4))
       
    23     return d
       
    24 
    28 
    25 def chunkheader(length):
    29 def chunkheader(length):
    26     """return a changegroup chunk header (string)"""
    30     """return a changegroup chunk header (string)"""
    27     return struct.pack(">l", length + 4)
    31     return struct.pack(">l", length + 4)
    28 
    32 
   143         return self._stream.tell()
   147         return self._stream.tell()
   144     def close(self):
   148     def close(self):
   145         return self._stream.close()
   149         return self._stream.close()
   146 
   150 
   147     def chunklength(self):
   151     def chunklength(self):
   148         d = self.read(4)
   152         d = readexactly(self._stream, 4)
   149         l = max(0, struct.unpack(">l", d)[0] - 4)
   153         l = max(0, struct.unpack(">l", d)[0] - 4)
   150         if l and self.callback:
   154         if l and self.callback:
   151             self.callback()
   155             self.callback()
   152         return l
   156         return l
   153 
   157 
   154     def chunk(self):
   158     def chunk(self):
   155         """return the next chunk from changegroup 'source' as a string"""
   159         """return the next chunk from changegroup 'source' as a string"""
   156         l = self.chunklength()
   160         l = self.chunklength()
   157         d = self.read(l)
   161         return readexactly(self._stream, l)
   158         if len(d) < l:
       
   159             raise util.Abort(_("premature EOF reading chunk"
       
   160                                " (got %d bytes, expected %d)")
       
   161                              % (len(d), l))
       
   162         return d
       
   163 
   162 
   164     def parsechunk(self):
   163     def parsechunk(self):
   165         l = self.chunklength()
   164         l = self.chunklength()
   166         if not l:
   165         if not l:
   167             return {}
   166             return {}
   168         h = self.read(80)
   167         h = readexactly(self._stream, 80)
   169         node, p1, p2, cs = struct.unpack("20s20s20s20s", h)
   168         node, p1, p2, cs = struct.unpack("20s20s20s20s", h)
   170         data = self.read(l - 80)
   169         data = readexactly(self._stream, l - 80)
   171         return dict(node=node, p1=p1, p2=p2, cs=cs, data=data)
   170         return dict(node=node, p1=p1, p2=p2, cs=cs, data=data)
   172 
   171 
   173 class headerlessfixup(object):
   172 class headerlessfixup(object):
   174     def __init__(self, fh, h):
   173     def __init__(self, fh, h):
   175         self._h = h
   174         self._h = h
   176         self._fh = fh
   175         self._fh = fh
   177     def read(self, n):
   176     def read(self, n):
   178         if self._h:
   177         if self._h:
   179             d, self._h = self._h[:n], self._h[n:]
   178             d, self._h = self._h[:n], self._h[n:]
   180             if len(d) < n:
   179             if len(d) < n:
   181                 d += self._fh.read(n - len(d))
   180                 d += readexactly(self._fh, n - len(d))
   182             return d
   181             return d
   183         return self._fh.read(n)
   182         return readexactly(self._fh, n)
   184 
   183 
   185 def readbundle(fh, fname):
   184 def readbundle(fh, fname):
   186     header = fh.read(6)
   185     header = readexactly(fh, 6)
   187 
   186 
   188     if not fname:
   187     if not fname:
   189         fname = "stream"
   188         fname = "stream"
   190         if not header.startswith('HG') and header.startswith('\0'):
   189         if not header.startswith('HG') and header.startswith('\0'):
   191             fh = headerlessfixup(fh, header)
   190             fh = headerlessfixup(fh, header)