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 |
|
|
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 |
|
22 | added 1 changesets with 4 changes to 4 files | |
20 | updating working directory |
|
23 | updating working directory | |
21 |
|
|
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 |
|
30 | added 1 changesets with 4 changes to 4 files | |
28 | updating working directory |
|
31 | updating working directory | |
29 |
|
|
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 |
|
|
37 | 4 files, 1 changesets, 4 total revisions | |
35 | adding bar |
|
38 | adding bar | |
36 | % pull |
|
39 | % pull | |
37 |
changegroup hook: HG_NODE= |
|
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