comparison mercurial/wireproto.py @ 11627:04f76a954842

protocol: move the streamclone implementation into wireproto
author Dirkjan Ochtman <dirkjan@ochtman.nl>
date Tue, 20 Jul 2010 20:52:23 +0200
parents cdeb861335d5
children 4e804302d30c
comparison
equal deleted inserted replaced
11626:2f8adc60e013 11627:04f76a954842
7 7
8 import urllib, tempfile, os 8 import urllib, tempfile, os
9 from i18n import _ 9 from i18n import _
10 from node import bin, hex 10 from node import bin, hex
11 import changegroup as changegroupmod 11 import changegroup as changegroupmod
12 import streamclone, repo, error, encoding, util 12 import repo, error, encoding, util, store
13 import pushkey as pushkey_ 13 import pushkey as pushkey_
14 14
15 # list of nodes encoding / decoding 15 # list of nodes encoding / decoding
16 16
17 def decodelist(l, sep=' '): 17 def decodelist(l, sep=' '):
169 r.append(encodelist(b) + "\n") 169 r.append(encodelist(b) + "\n")
170 return "".join(r) 170 return "".join(r)
171 171
172 def capabilities(repo, proto): 172 def capabilities(repo, proto):
173 caps = 'lookup changegroupsubset branchmap pushkey'.split() 173 caps = 'lookup changegroupsubset branchmap pushkey'.split()
174 if streamclone.allowed(repo.ui): 174 if _allowstream(repo.ui):
175 caps.append('stream=%d' % repo.changelog.version) 175 caps.append('stream=%d' % repo.changelog.version)
176 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority)) 176 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
177 return ' '.join(caps) 177 return ' '.join(caps)
178 178
179 def changegroup(repo, proto, roots): 179 def changegroup(repo, proto, roots):
218 218
219 def pushkey(repo, proto, namespace, key, old, new): 219 def pushkey(repo, proto, namespace, key, old, new):
220 r = pushkey_.push(repo, namespace, key, old, new) 220 r = pushkey_.push(repo, namespace, key, old, new)
221 return '%s\n' % int(r) 221 return '%s\n' % int(r)
222 222
223 def _allowstream(ui):
224 return ui.configbool('server', 'uncompressed', True, untrusted=True)
225
223 def stream(repo, proto): 226 def stream(repo, proto):
224 return streamres(streamclone.stream_out(repo)) 227 '''If the server supports streaming clone, it advertises the "stream"
228 capability with a value representing the version and flags of the repo
229 it is serving. Client checks to see if it understands the format.
230
231 The format is simple: the server writes out a line with the amount
232 of files, then the total amount of bytes to be transfered (separated
233 by a space). Then, for each file, the server first writes the filename
234 and filesize (separated by the null character), then the file contents.
235 '''
236
237 if not _allowstream(repo.ui):
238 return '1\n'
239
240 entries = []
241 total_bytes = 0
242 try:
243 # get consistent snapshot of repo, lock during scan
244 lock = repo.lock()
245 try:
246 repo.ui.debug('scanning\n')
247 for name, ename, size in repo.store.walk():
248 entries.append((name, size))
249 total_bytes += size
250 finally:
251 lock.release()
252 except error.LockError:
253 return '2\n' # error: 2
254
255 def streamer(repo, entries, total):
256 '''stream out all metadata files in repository.'''
257 yield '0\n' # success
258 repo.ui.debug('%d files, %d bytes to transfer\n' %
259 (len(entries), total_bytes))
260 yield '%d %d\n' % (len(entries), total_bytes)
261 for name, size in entries:
262 repo.ui.debug('sending %s (%d bytes)\n' % (name, size))
263 # partially encode name over the wire for backwards compat
264 yield '%s\0%d\n' % (store.encodedir(name), size)
265 for chunk in util.filechunkiter(repo.sopener(name), limit=size):
266 yield chunk
267
268 return streamres(streamer(repo, entries, total_bytes))
225 269
226 def unbundle(repo, proto, heads): 270 def unbundle(repo, proto, heads):
227 their_heads = decodelist(heads) 271 their_heads = decodelist(heads)
228 272
229 def check_heads(): 273 def check_heads():