##// END OF EJS Templates
streamclone: partially encode filename over the wire, not for local read (issue1847)...
Greg Ward -
r9506:49b62395 default
parent child Browse files
Show More
@@ -1,67 +1,67 b''
1 # streamclone.py - streaming clone server support for mercurial
1 # streamclone.py - streaming clone server support for mercurial
2 #
2 #
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7
7
8 import util, error
8 import util, error
9 from i18n import _
9 from i18n import _
10
10
11 from mercurial import store
11 from mercurial import store
12
12
13 class StreamException(Exception):
13 class StreamException(Exception):
14 def __init__(self, code):
14 def __init__(self, code):
15 Exception.__init__(self)
15 Exception.__init__(self)
16 self.code = code
16 self.code = code
17 def __str__(self):
17 def __str__(self):
18 return '%i\n' % self.code
18 return '%i\n' % self.code
19
19
20 # if server supports streaming clone, it advertises "stream"
20 # if server supports streaming clone, it advertises "stream"
21 # capability with value that is version+flags of repo it is serving.
21 # capability with value that is version+flags of repo it is serving.
22 # client only streams if it can read that repo format.
22 # client only streams if it can read that repo format.
23
23
24 # stream file format is simple.
24 # stream file format is simple.
25 #
25 #
26 # server writes out line that says how many files, how many total
26 # server writes out line that says how many files, how many total
27 # bytes. separator is ascii space, byte counts are strings.
27 # bytes. separator is ascii space, byte counts are strings.
28 #
28 #
29 # then for each file:
29 # then for each file:
30 #
30 #
31 # server writes out line that says filename, how many bytes in
31 # server writes out line that says filename, how many bytes in
32 # file. separator is ascii nul, byte count is string.
32 # file. separator is ascii nul, byte count is string.
33 #
33 #
34 # server writes out raw file data.
34 # server writes out raw file data.
35
35
36 def stream_out(repo, untrusted=False):
36 def stream_out(repo, untrusted=False):
37 '''stream out all metadata files in repository.
37 '''stream out all metadata files in repository.
38 writes to file-like object, must support write() and optional flush().'''
38 writes to file-like object, must support write() and optional flush().'''
39
39
40 if not repo.ui.configbool('server', 'uncompressed', untrusted=untrusted):
40 if not repo.ui.configbool('server', 'uncompressed', untrusted=untrusted):
41 raise StreamException(1)
41 raise StreamException(1)
42
42
43 entries = []
43 entries = []
44 total_bytes = 0
44 total_bytes = 0
45 try:
45 try:
46 # get consistent snapshot of repo, lock during scan
46 # get consistent snapshot of repo, lock during scan
47 lock = repo.lock()
47 lock = repo.lock()
48 try:
48 try:
49 repo.ui.debug(_('scanning\n'))
49 repo.ui.debug(_('scanning\n'))
50 for name, ename, size in repo.store.walk():
50 for name, ename, size in repo.store.walk():
51 # for backwards compat, name was partially encoded
51 entries.append((name, size))
52 entries.append((store.encodedir(name), size))
53 total_bytes += size
52 total_bytes += size
54 finally:
53 finally:
55 lock.release()
54 lock.release()
56 except error.LockError:
55 except error.LockError:
57 raise StreamException(2)
56 raise StreamException(2)
58
57
59 yield '0\n'
58 yield '0\n'
60 repo.ui.debug(_('%d files, %d bytes to transfer\n') %
59 repo.ui.debug(_('%d files, %d bytes to transfer\n') %
61 (len(entries), total_bytes))
60 (len(entries), total_bytes))
62 yield '%d %d\n' % (len(entries), total_bytes)
61 yield '%d %d\n' % (len(entries), total_bytes)
63 for name, size in entries:
62 for name, size in entries:
64 repo.ui.debug(_('sending %s (%d bytes)\n') % (name, size))
63 repo.ui.debug(_('sending %s (%d bytes)\n') % (name, size))
65 yield '%s\0%d\n' % (name, size)
64 # partially encode name over the wire for backwards compat
65 yield '%s\0%d\n' % (store.encodedir(name), size)
66 for chunk in util.filechunkiter(repo.sopener(name), limit=size):
66 for chunk in util.filechunkiter(repo.sopener(name), limit=size):
67 yield chunk
67 yield chunk
@@ -1,38 +1,43 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 cp "$TESTDIR"/printenv.py .
3 cp "$TESTDIR"/printenv.py .
4
4
5 hg init test
5 hg init test
6 cd test
6 cd test
7 echo foo>foo
7 echo foo>foo
8 mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
9 echo foo>foo.d/foo
10 echo bar>foo.d/bAr.hg.d/BaR
11 echo bar>foo.d/baR.d.hg/bAR
12
8 hg commit -A -m 1
13 hg commit -A -m 1
9 hg --config server.uncompressed=True serve -p $HGPORT -d --pid-file=../hg1.pid
14 hg --config server.uncompressed=True serve -p $HGPORT -d --pid-file=../hg1.pid
10 hg serve -p $HGPORT1 -d --pid-file=../hg2.pid
15 hg serve -p $HGPORT1 -d --pid-file=../hg2.pid
11 # Test server address cannot be reused
16 # Test server address cannot be reused
12 hg serve -p $HGPORT1 2>&1 | sed -e "s/abort: cannot start server at ':$HGPORT1':.*/abort: cannot start server at ':20060':/"
17 hg serve -p $HGPORT1 2>&1 | sed -e "s/abort: cannot start server at ':$HGPORT1':.*/abort: cannot start server at ':20060':/"
13 cd ..
18 cd ..
14 cat hg1.pid hg2.pid >> $DAEMON_PIDS
19 cat hg1.pid hg2.pid >> $DAEMON_PIDS
15
20
16 echo % clone via stream
21 echo % clone via stream
17 http_proxy= hg clone --uncompressed http://localhost:$HGPORT/ copy 2>&1 | \
22 http_proxy= hg clone --uncompressed http://localhost:$HGPORT/ copy 2>&1 | \
18 sed -e 's/[0-9][0-9.]*/XXX/g' -e 's/[KM]\(B\/sec\)/X\1/'
23 sed -e 's/[0-9][0-9.]*/XXX/g' -e 's/[KM]\(B\/sec\)/X\1/'
19 hg verify -R copy
24 hg verify -R copy
20
25
21 echo % try to clone via stream, should use pull instead
26 echo % try to clone via stream, should use pull instead
22 http_proxy= hg clone --uncompressed http://localhost:$HGPORT1/ copy2
27 http_proxy= hg clone --uncompressed http://localhost:$HGPORT1/ copy2
23
28
24 echo % clone via pull
29 echo % clone via pull
25 http_proxy= hg clone http://localhost:$HGPORT1/ copy-pull
30 http_proxy= hg clone http://localhost:$HGPORT1/ copy-pull
26 hg verify -R copy-pull
31 hg verify -R copy-pull
27
32
28 cd test
33 cd test
29 echo bar > bar
34 echo bar > bar
30 hg commit -A -d '1 0' -m 2
35 hg commit -A -d '1 0' -m 2
31 cd ..
36 cd ..
32
37
33 echo % pull
38 echo % pull
34 cd copy-pull
39 cd copy-pull
35 echo '[hooks]' >> .hg/hgrc
40 echo '[hooks]' >> .hg/hgrc
36 echo 'changegroup = python ../printenv.py changegroup' >> .hg/hgrc
41 echo 'changegroup = python ../printenv.py changegroup' >> .hg/hgrc
37 hg pull | sed -e 's,:[0-9][0-9]*/,/,'
42 hg pull | sed -e 's,:[0-9][0-9]*/,/,'
38 cd ..
43 cd ..
@@ -1,44 +1,47 b''
1 adding foo
1 adding foo
2 adding foo.d/bAr.hg.d/BaR
3 adding foo.d/baR.d.hg/bAR
4 adding foo.d/foo
2 abort: cannot start server at ':20060':
5 abort: cannot start server at ':20060':
3 % clone via stream
6 % clone via stream
4 streaming all changes
7 streaming all changes
5 XXX files to transfer, XXX bytes of data
8 XXX files to transfer, XXX bytes of data
6 transferred XXX bytes in XXX seconds (XXX XB/sec)
9 transferred XXX bytes in XXX seconds (XXX XB/sec)
7 updating working directory
10 updating working directory
8 XXX files updated, XXX files merged, XXX files removed, XXX files unresolved
11 XXX files updated, XXX files merged, XXX files removed, XXX files unresolved
9 checking changesets
12 checking changesets
10 checking manifests
13 checking manifests
11 crosschecking files in changesets and manifests
14 crosschecking files in changesets and manifests
12 checking files
15 checking files
13 1 files, 1 changesets, 1 total revisions
16 4 files, 1 changesets, 4 total revisions
14 % try to clone via stream, should use pull instead
17 % try to clone via stream, should use pull instead
15 requesting all changes
18 requesting all changes
16 adding changesets
19 adding changesets
17 adding manifests
20 adding manifests
18 adding file changes
21 adding file changes
19 added 1 changesets with 1 changes to 1 files
22 added 1 changesets with 4 changes to 4 files
20 updating working directory
23 updating working directory
21 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
24 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
22 % clone via pull
25 % clone via pull
23 requesting all changes
26 requesting all changes
24 adding changesets
27 adding changesets
25 adding manifests
28 adding manifests
26 adding file changes
29 adding file changes
27 added 1 changesets with 1 changes to 1 files
30 added 1 changesets with 4 changes to 4 files
28 updating working directory
31 updating working directory
29 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
32 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
30 checking changesets
33 checking changesets
31 checking manifests
34 checking manifests
32 crosschecking files in changesets and manifests
35 crosschecking files in changesets and manifests
33 checking files
36 checking files
34 1 files, 1 changesets, 1 total revisions
37 4 files, 1 changesets, 4 total revisions
35 adding bar
38 adding bar
36 % pull
39 % pull
37 changegroup hook: HG_NODE=cfbd11a1fa315300a080c3de8fe36b0fc5820acf HG_SOURCE=pull HG_URL=http://localhost/
40 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=http://localhost/
38 pulling from http://localhost/
41 pulling from http://localhost/
39 searching for changes
42 searching for changes
40 adding changesets
43 adding changesets
41 adding manifests
44 adding manifests
42 adding file changes
45 adding file changes
43 added 1 changesets with 1 changes to 1 files
46 added 1 changesets with 1 changes to 1 files
44 (run 'hg update' to get a working copy)
47 (run 'hg update' to get a working copy)
General Comments 0
You need to be logged in to leave comments. Login now