Show More
@@ -1,69 +1,63 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 or any later version. |
|
6 | # GNU General Public License version 2 or any later version. | |
7 |
|
7 | |||
8 | import util, error |
|
8 | import util, error | |
9 |
|
||||
10 | from mercurial import store |
|
9 | from mercurial import store | |
11 |
|
10 | |||
12 | class StreamException(Exception): |
|
|||
13 | def __init__(self, code): |
|
|||
14 | Exception.__init__(self) |
|
|||
15 | self.code = code |
|
|||
16 | def __str__(self): |
|
|||
17 | return '%i\n' % self.code |
|
|||
18 |
|
||||
19 | # if server supports streaming clone, it advertises "stream" |
|
11 | # if server supports streaming clone, it advertises "stream" | |
20 | # capability with value that is version+flags of repo it is serving. |
|
12 | # capability with value that is version+flags of repo it is serving. | |
21 | # client only streams if it can read that repo format. |
|
13 | # client only streams if it can read that repo format. | |
22 |
|
14 | |||
23 | # stream file format is simple. |
|
15 | # stream file format is simple. | |
24 | # |
|
16 | # | |
25 | # server writes out line that says how many files, how many total |
|
17 | # server writes out line that says how many files, how many total | |
26 | # bytes. separator is ascii space, byte counts are strings. |
|
18 | # bytes. separator is ascii space, byte counts are strings. | |
27 | # |
|
19 | # | |
28 | # then for each file: |
|
20 | # then for each file: | |
29 | # |
|
21 | # | |
30 | # server writes out line that says filename, how many bytes in |
|
22 | # server writes out line that says filename, how many bytes in | |
31 | # file. separator is ascii nul, byte count is string. |
|
23 | # file. separator is ascii nul, byte count is string. | |
32 | # |
|
24 | # | |
33 | # server writes out raw file data. |
|
25 | # server writes out raw file data. | |
34 |
|
26 | |||
35 | def allowed(ui): |
|
27 | def allowed(ui): | |
36 | return ui.configbool('server', 'uncompressed', True, untrusted=True) |
|
28 | return ui.configbool('server', 'uncompressed', True, untrusted=True) | |
37 |
|
29 | |||
38 | def stream_out(repo): |
|
30 | def stream_out(repo): | |
39 | '''stream out all metadata files in repository. |
|
31 | '''stream out all metadata files in repository. | |
40 | writes to file-like object, must support write() and optional flush().''' |
|
32 | writes to file-like object, must support write() and optional flush().''' | |
41 |
|
33 | |||
42 | if not allowed(repo.ui): |
|
34 | if not allowed(repo.ui): | |
43 | raise StreamException(1) |
|
35 | yield '1\n' # error: 1 | |
|
36 | return | |||
44 |
|
37 | |||
45 | entries = [] |
|
38 | entries = [] | |
46 | total_bytes = 0 |
|
39 | total_bytes = 0 | |
47 | try: |
|
40 | try: | |
48 | # get consistent snapshot of repo, lock during scan |
|
41 | # get consistent snapshot of repo, lock during scan | |
49 | lock = repo.lock() |
|
42 | lock = repo.lock() | |
50 | try: |
|
43 | try: | |
51 | repo.ui.debug('scanning\n') |
|
44 | repo.ui.debug('scanning\n') | |
52 | for name, ename, size in repo.store.walk(): |
|
45 | for name, ename, size in repo.store.walk(): | |
53 | entries.append((name, size)) |
|
46 | entries.append((name, size)) | |
54 | total_bytes += size |
|
47 | total_bytes += size | |
55 | finally: |
|
48 | finally: | |
56 | lock.release() |
|
49 | lock.release() | |
57 | except error.LockError: |
|
50 | except error.LockError: | |
58 | raise StreamException(2) |
|
51 | yield '2\n' # error: 2 | |
|
52 | return | |||
59 |
|
53 | |||
60 | yield '0\n' |
|
54 | yield '0\n' # success | |
61 | repo.ui.debug('%d files, %d bytes to transfer\n' % |
|
55 | repo.ui.debug('%d files, %d bytes to transfer\n' % | |
62 | (len(entries), total_bytes)) |
|
56 | (len(entries), total_bytes)) | |
63 | yield '%d %d\n' % (len(entries), total_bytes) |
|
57 | yield '%d %d\n' % (len(entries), total_bytes) | |
64 | for name, size in entries: |
|
58 | for name, size in entries: | |
65 | repo.ui.debug('sending %s (%d bytes)\n' % (name, size)) |
|
59 | repo.ui.debug('sending %s (%d bytes)\n' % (name, size)) | |
66 | # partially encode name over the wire for backwards compat |
|
60 | # partially encode name over the wire for backwards compat | |
67 | yield '%s\0%d\n' % (store.encodedir(name), size) |
|
61 | yield '%s\0%d\n' % (store.encodedir(name), size) | |
68 | for chunk in util.filechunkiter(repo.sopener(name), limit=size): |
|
62 | for chunk in util.filechunkiter(repo.sopener(name), limit=size): | |
69 | yield chunk |
|
63 | yield chunk |
General Comments 0
You need to be logged in to leave comments.
Login now