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) |