2006-07-14 22:17:22 +04:00
|
|
|
# streamclone.py - streaming clone server support for mercurial
|
|
|
|
#
|
|
|
|
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
|
|
|
|
#
|
2009-04-26 03:08:54 +04:00
|
|
|
# This software may be used and distributed according to the terms of the
|
2010-01-20 07:20:08 +03:00
|
|
|
# GNU General Public License version 2 or any later version.
|
2006-07-14 22:17:22 +04:00
|
|
|
|
2009-01-12 20:09:14 +03:00
|
|
|
import util, error
|
2009-05-20 20:35:47 +04:00
|
|
|
from mercurial import store
|
|
|
|
|
2006-07-14 22:17:22 +04:00
|
|
|
# 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:
|
|
|
|
#
|
2009-06-09 17:25:17 +04:00
|
|
|
# server writes out line that says filename, how many bytes in
|
2006-07-14 22:17:22 +04:00
|
|
|
# file. separator is ascii nul, byte count is string.
|
|
|
|
#
|
|
|
|
# server writes out raw file data.
|
|
|
|
|
2010-02-07 17:31:53 +03:00
|
|
|
def allowed(ui):
|
2010-02-09 23:12:34 +03:00
|
|
|
return ui.configbool('server', 'uncompressed', True, untrusted=True)
|
2010-02-07 17:31:53 +03:00
|
|
|
|
|
|
|
def stream_out(repo):
|
2006-07-14 22:17:22 +04:00
|
|
|
'''stream out all metadata files in repository.
|
|
|
|
writes to file-like object, must support write() and optional flush().'''
|
2006-07-16 03:06:35 +04:00
|
|
|
|
2010-02-07 17:31:53 +03:00
|
|
|
if not allowed(repo.ui):
|
2010-07-17 00:20:19 +04:00
|
|
|
yield '1\n' # error: 1
|
|
|
|
return
|
2006-07-16 03:06:35 +04:00
|
|
|
|
2008-08-14 05:18:44 +04:00
|
|
|
entries = []
|
|
|
|
total_bytes = 0
|
2006-11-20 21:41:49 +03:00
|
|
|
try:
|
2009-04-22 04:01:22 +04:00
|
|
|
# get consistent snapshot of repo, lock during scan
|
|
|
|
lock = repo.lock()
|
2008-08-14 05:18:44 +04:00
|
|
|
try:
|
2009-09-19 03:15:38 +04:00
|
|
|
repo.ui.debug('scanning\n')
|
2008-08-14 05:18:44 +04:00
|
|
|
for name, ename, size in repo.store.walk():
|
2009-10-01 00:08:11 +04:00
|
|
|
entries.append((name, size))
|
2008-08-14 05:18:44 +04:00
|
|
|
total_bytes += size
|
|
|
|
finally:
|
2009-04-22 04:01:22 +04:00
|
|
|
lock.release()
|
2009-01-12 20:09:14 +03:00
|
|
|
except error.LockError:
|
2010-07-17 00:20:19 +04:00
|
|
|
yield '2\n' # error: 2
|
|
|
|
return
|
2006-07-14 22:17:22 +04:00
|
|
|
|
2010-07-17 00:20:19 +04:00
|
|
|
yield '0\n' # success
|
2009-09-19 03:15:38 +04:00
|
|
|
repo.ui.debug('%d files, %d bytes to transfer\n' %
|
2006-07-14 22:17:22 +04:00
|
|
|
(len(entries), total_bytes))
|
2008-08-15 15:25:57 +04:00
|
|
|
yield '%d %d\n' % (len(entries), total_bytes)
|
2006-07-14 22:17:22 +04:00
|
|
|
for name, size in entries:
|
2009-09-19 03:15:38 +04:00
|
|
|
repo.ui.debug('sending %s (%d bytes)\n' % (name, size))
|
2009-10-01 00:08:11 +04:00
|
|
|
# partially encode name over the wire for backwards compat
|
|
|
|
yield '%s\0%d\n' % (store.encodedir(name), size)
|
2006-12-05 13:28:23 +03:00
|
|
|
for chunk in util.filechunkiter(repo.sopener(name), limit=size):
|
2008-08-15 15:25:57 +04:00
|
|
|
yield chunk
|