diff --git a/mercurial/streamclone.py b/mercurial/streamclone.py --- a/mercurial/streamclone.py +++ b/mercurial/streamclone.py @@ -206,7 +206,8 @@ def generatev1(repo): # partially encode name over the wire for backwards compat yield '%s\0%d\n' % (store.encodedir(name), size) if size <= 65536: - yield svfs.read(name) + with svfs(name, 'rb') as fp: + yield fp.read(size) else: for chunk in util.filechunkiter(svfs(name), limit=size): yield chunk diff --git a/tests/test-clone-uncompressed.t b/tests/test-clone-uncompressed.t --- a/tests/test-clone-uncompressed.t +++ b/tests/test-clone-uncompressed.t @@ -50,3 +50,43 @@ Clone with background file closing enabl preparing listkeys for "phases" sending listkeys command received listkey for "phases": 58 bytes + + +Stream clone while repo is changing: + + $ mkdir changing + $ cd changing + +extension for delaying the server process so we reliably can modify the repo +while cloning + + $ cat > delayer.py < import time + > from mercurial import extensions, scmutil + > def __call__(orig, self, path, *args, **kwargs): + > if path == 'data/f1.i': + > time.sleep(2) + > return orig(self, path, *args, **kwargs) + > extensions.wrapfunction(scmutil.vfs, '__call__', __call__) + > EOF + +prepare repo with small and big file to cover both code paths in emitrevlogdata + + $ hg init repo + $ touch repo/f1 + $ $TESTDIR/seq.py 50000 > repo/f2 + $ hg -R repo ci -Aqm "0" + $ hg -R repo serve -p $HGPORT1 -d --pid-file=hg.pid --config extensions.delayer=delayer.py + $ cat hg.pid >> $DAEMON_PIDS + +clone while modifying the repo between stating file with write lock and +actually serving file content + + $ hg clone -q --uncompressed -U http://localhost:$HGPORT1 clone & + $ sleep 1 + $ echo >> repo/f1 + $ echo >> repo/f2 + $ hg -R repo ci -m "1" + $ wait + $ hg -R clone id + 000000000000