# HG changeset patch # User Dirkjan Ochtman # Date 1279651943 -7200 # Node ID 04f76a95484257cfa02a5044d6f78e818cd03aac # Parent 2f8adc60e01328523052b1829ca9846ec1285f60 protocol: move the streamclone implementation into wireproto diff -r 2f8adc60e013 -r 04f76a954842 mercurial/streamclone.py --- a/mercurial/streamclone.py Tue Jul 20 09:56:37 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -# streamclone.py - streaming clone server support for mercurial -# -# Copyright 2006 Vadim Gelfer -# -# This software may be used and distributed according to the terms of the -# GNU General Public License version 2 or any later version. - -import util, error -from mercurial import store - -# 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: -# -# server writes out line that says filename, how many bytes in -# file. separator is ascii nul, byte count is string. -# -# server writes out raw file data. - -def allowed(ui): - return ui.configbool('server', 'uncompressed', True, untrusted=True) - -def stream_out(repo): - '''stream out all metadata files in repository. - writes to file-like object, must support write() and optional flush().''' - - if not allowed(repo.ui): - yield '1\n' # error: 1 - return - - entries = [] - total_bytes = 0 - try: - # get consistent snapshot of repo, lock during scan - lock = repo.lock() - try: - repo.ui.debug('scanning\n') - for name, ename, size in repo.store.walk(): - entries.append((name, size)) - total_bytes += size - finally: - lock.release() - except error.LockError: - yield '2\n' # error: 2 - return - - yield '0\n' # success - repo.ui.debug('%d files, %d bytes to transfer\n' % - (len(entries), total_bytes)) - yield '%d %d\n' % (len(entries), total_bytes) - for name, size in entries: - repo.ui.debug('sending %s (%d bytes)\n' % (name, size)) - # partially encode name over the wire for backwards compat - yield '%s\0%d\n' % (store.encodedir(name), size) - for chunk in util.filechunkiter(repo.sopener(name), limit=size): - yield chunk diff -r 2f8adc60e013 -r 04f76a954842 mercurial/wireproto.py --- a/mercurial/wireproto.py Tue Jul 20 09:56:37 2010 +0200 +++ b/mercurial/wireproto.py Tue Jul 20 20:52:23 2010 +0200 @@ -9,7 +9,7 @@ from i18n import _ from node import bin, hex import changegroup as changegroupmod -import streamclone, repo, error, encoding, util +import repo, error, encoding, util, store import pushkey as pushkey_ # list of nodes encoding / decoding @@ -171,7 +171,7 @@ def capabilities(repo, proto): caps = 'lookup changegroupsubset branchmap pushkey'.split() - if streamclone.allowed(repo.ui): + if _allowstream(repo.ui): caps.append('stream=%d' % repo.changelog.version) caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority)) return ' '.join(caps) @@ -220,8 +220,52 @@ r = pushkey_.push(repo, namespace, key, old, new) return '%s\n' % int(r) +def _allowstream(ui): + return ui.configbool('server', 'uncompressed', True, untrusted=True) + def stream(repo, proto): - return streamres(streamclone.stream_out(repo)) + '''If the server supports streaming clone, it advertises the "stream" + capability with a value representing the version and flags of the repo + it is serving. Client checks to see if it understands the format. + + The format is simple: the server writes out a line with the amount + of files, then the total amount of bytes to be transfered (separated + by a space). Then, for each file, the server first writes the filename + and filesize (separated by the null character), then the file contents. + ''' + + if not _allowstream(repo.ui): + return '1\n' + + entries = [] + total_bytes = 0 + try: + # get consistent snapshot of repo, lock during scan + lock = repo.lock() + try: + repo.ui.debug('scanning\n') + for name, ename, size in repo.store.walk(): + entries.append((name, size)) + total_bytes += size + finally: + lock.release() + except error.LockError: + return '2\n' # error: 2 + + def streamer(repo, entries, total): + '''stream out all metadata files in repository.''' + yield '0\n' # success + repo.ui.debug('%d files, %d bytes to transfer\n' % + (len(entries), total_bytes)) + yield '%d %d\n' % (len(entries), total_bytes) + for name, size in entries: + repo.ui.debug('sending %s (%d bytes)\n' % (name, size)) + # partially encode name over the wire for backwards compat + yield '%s\0%d\n' % (store.encodedir(name), size) + for chunk in util.filechunkiter(repo.sopener(name), limit=size): + yield chunk + + return streamres(streamer(repo, entries, total_bytes)) def unbundle(repo, proto, heads): their_heads = decodelist(heads)