streamclone.py
70 lines
| 2.2 KiB
| text/x-python
|
PythonLexer
/ mercurial / streamclone.py
Vadim Gelfer
|
r2612 | # streamclone.py - streaming clone server support for mercurial | ||
# | ||||
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> | ||||
# | ||||
Martin Geisler
|
r8225 | # This software may be used and distributed according to the terms of the | ||
Matt Mackall
|
r10263 | # GNU General Public License version 2 or any later version. | ||
Vadim Gelfer
|
r2612 | |||
Matt Mackall
|
r7640 | import util, error | ||
Martin Geisler
|
r6953 | from i18n import _ | ||
Vadim Gelfer
|
r2612 | |||
Benoit Boissinot
|
r8531 | from mercurial import store | ||
Dirkjan Ochtman
|
r6925 | class StreamException(Exception): | ||
def __init__(self, code): | ||||
Exception.__init__(self) | ||||
self.code = code | ||||
def __str__(self): | ||||
return '%i\n' % self.code | ||||
Vadim Gelfer
|
r2612 | # if server supports streaming clone, it advertises "stream" | ||
# capability with value that is version+flags of repo it is serving. | ||||
# client only streams if it can read that repo format. | ||||
# stream file format is simple. | ||||
# | ||||
# server writes out line that says how many files, how many total | ||||
# bytes. separator is ascii space, byte counts are strings. | ||||
# | ||||
# then for each file: | ||||
# | ||||
timeless
|
r8761 | # server writes out line that says filename, how many bytes in | ||
Vadim Gelfer
|
r2612 | # file. separator is ascii nul, byte count is string. | ||
# | ||||
# server writes out raw file data. | ||||
Matt Mackall
|
r10377 | def allowed(ui): | ||
Matt Mackall
|
r10414 | return ui.configbool('server', 'uncompressed', True, untrusted=True) | ||
Matt Mackall
|
r10377 | |||
def stream_out(repo): | ||||
Vadim Gelfer
|
r2612 | '''stream out all metadata files in repository. | ||
writes to file-like object, must support write() and optional flush().''' | ||||
Vadim Gelfer
|
r2621 | |||
Matt Mackall
|
r10377 | if not allowed(repo.ui): | ||
Dirkjan Ochtman
|
r6925 | raise StreamException(1) | ||
Vadim Gelfer
|
r2621 | |||
Matt Mackall
|
r6901 | entries = [] | ||
total_bytes = 0 | ||||
Thomas Arendsen Hein
|
r3687 | try: | ||
Ronny Pfannschmidt
|
r8109 | # get consistent snapshot of repo, lock during scan | ||
lock = repo.lock() | ||||
Matt Mackall
|
r6901 | try: | ||
Martin Geisler
|
r9467 | repo.ui.debug('scanning\n') | ||
Matt Mackall
|
r6901 | for name, ename, size in repo.store.walk(): | ||
Greg Ward
|
r9506 | entries.append((name, size)) | ||
Matt Mackall
|
r6901 | total_bytes += size | ||
finally: | ||||
Ronny Pfannschmidt
|
r8109 | lock.release() | ||
Matt Mackall
|
r7640 | except error.LockError: | ||
Dirkjan Ochtman
|
r6925 | raise StreamException(2) | ||
Thomas Arendsen Hein
|
r3687 | |||
Dirkjan Ochtman
|
r6925 | yield '0\n' | ||
Martin Geisler
|
r9467 | repo.ui.debug('%d files, %d bytes to transfer\n' % | ||
Vadim Gelfer
|
r2612 | (len(entries), total_bytes)) | ||
Dirkjan Ochtman
|
r6925 | yield '%d %d\n' % (len(entries), total_bytes) | ||
Vadim Gelfer
|
r2612 | for name, size in entries: | ||
Martin Geisler
|
r9467 | repo.ui.debug('sending %s (%d bytes)\n' % (name, size)) | ||
Greg Ward
|
r9506 | # partially encode name over the wire for backwards compat | ||
yield '%s\0%d\n' % (store.encodedir(name), size) | ||||
Benoit Boissinot
|
r3791 | for chunk in util.filechunkiter(repo.sopener(name), limit=size): | ||
Dirkjan Ochtman
|
r6925 | yield chunk | ||