Show More
@@ -60,30 +60,13 b' class localrepository(repo.repository):' | |||
|
60 | 60 | if r not in self.supported: |
|
61 | 61 | raise repo.RepoError(_("requirement '%s' not supported") % r) |
|
62 | 62 | |
|
63 | # setup store | |
|
64 | if "store" in requirements: | |
|
65 | self.encodefn = store.encodefilename | |
|
66 | self.decodefn = store.decodefilename | |
|
67 | self.spath = os.path.join(self.path, "store") | |
|
68 | else: | |
|
69 | self.encodefn = lambda x: x | |
|
70 | self.decodefn = lambda x: x | |
|
71 | self.spath = self.path | |
|
63 | self.store = store.store(requirements, self.path) | |
|
72 | 64 | |
|
73 | try: | |
|
74 | # files in .hg/ will be created using this mode | |
|
75 | mode = os.stat(self.spath).st_mode | |
|
76 | # avoid some useless chmods | |
|
77 | if (0777 & ~util._umask) == (0777 & mode): | |
|
78 | mode = None | |
|
79 | except OSError: | |
|
80 | mode = None | |
|
81 | ||
|
82 | self._createmode = mode | |
|
83 | self.opener.createmode = mode | |
|
84 | sopener = util.opener(self.spath) | |
|
85 | sopener.createmode = mode | |
|
86 | self.sopener = store.encodedopener(sopener, self.encodefn) | |
|
65 | self.spath = self.store.path | |
|
66 | self.sopener = self.store.opener | |
|
67 | self.sjoin = self.store.join | |
|
68 | self._createmode = self.store.createmode | |
|
69 | self.opener.createmode = self.store.createmode | |
|
87 | 70 | |
|
88 | 71 | self.ui = ui.ui(parentui=parentui) |
|
89 | 72 | try: |
@@ -481,10 +464,6 b' class localrepository(repo.repository):' | |||
|
481 | 464 | def join(self, f): |
|
482 | 465 | return os.path.join(self.path, f) |
|
483 | 466 | |
|
484 | def sjoin(self, f): | |
|
485 | f = self.encodefn(f) | |
|
486 | return os.path.join(self.spath, f) | |
|
487 | ||
|
488 | 467 | def wjoin(self, f): |
|
489 | 468 | return os.path.join(self.root, f) |
|
490 | 469 | |
@@ -2061,6 +2040,25 b' class localrepository(repo.repository):' | |||
|
2061 | 2040 | return self.stream_in(remote) |
|
2062 | 2041 | return self.pull(remote, heads) |
|
2063 | 2042 | |
|
2043 | def storefiles(self): | |
|
2044 | '''get all *.i and *.d files in the store | |
|
2045 | ||
|
2046 | Returns (list of (filename, size), total_bytes)''' | |
|
2047 | ||
|
2048 | lock = None | |
|
2049 | try: | |
|
2050 | self.ui.debug('scanning\n') | |
|
2051 | entries = [] | |
|
2052 | total_bytes = 0 | |
|
2053 | # get consistent snapshot of repo, lock during scan | |
|
2054 | lock = self.lock() | |
|
2055 | for name, size in self.store.walk(): | |
|
2056 | entries.append((name, size)) | |
|
2057 | total_bytes += size | |
|
2058 | return entries, total_bytes | |
|
2059 | finally: | |
|
2060 | del lock | |
|
2061 | ||
|
2064 | 2062 | # used to avoid circular references so destructors work |
|
2065 | 2063 | def aftertrans(files): |
|
2066 | 2064 | renamefiles = [tuple(t) for t in files] |
@@ -55,14 +55,13 b' class statichttprepository(localrepo.loc' | |||
|
55 | 55 | |
|
56 | 56 | # setup store |
|
57 | 57 | if "store" in requirements: |
|
58 | self.encodefn = store.encodefilename | |
|
59 | self.decodefn = store.decodefilename | |
|
60 | 58 | self.spath = self.path + "/store" |
|
61 | 59 | else: |
|
62 | self.encodefn = lambda x: x | |
|
63 | self.decodefn = lambda x: x | |
|
64 | 60 | self.spath = self.path |
|
65 | self.sopener = store.encodedopener(opener(self.spath), self.encodefn) | |
|
61 | self.encodefn = store.encodefn(requirements) | |
|
62 | so = opener(self.spath) | |
|
63 | self.sopener = lambda path, *args, **kw: so( | |
|
64 | self.encodefn(path), *args, **kw) | |
|
66 | 65 | |
|
67 | 66 | self.manifest = manifest.manifest(self.sopener) |
|
68 | 67 | self.changelog = changelog.changelog(self.sopener) |
@@ -5,6 +5,8 b'' | |||
|
5 | 5 | # This software may be used and distributed according to the terms |
|
6 | 6 | # of the GNU General Public License, incorporated herein by reference. |
|
7 | 7 | |
|
8 | import os, stat, osutil, util | |
|
9 | ||
|
8 | 10 | def _buildencodefun(): |
|
9 | 11 | e = '_' |
|
10 | 12 | win_reserved = [ord(x) for x in '\\:*?"<>|'] |
@@ -33,7 +35,91 b' def _buildencodefun():' | |||
|
33 | 35 | |
|
34 | 36 | encodefilename, decodefilename = _buildencodefun() |
|
35 | 37 | |
|
36 | def encodedopener(openerfn, fn): | |
|
37 | def o(path, *args, **kw): | |
|
38 | return openerfn(fn(path), *args, **kw) | |
|
39 | return o | |
|
38 | def _dirwalk(path, recurse): | |
|
39 | '''yields (filename, size)''' | |
|
40 | for e, kind, st in osutil.listdir(path, stat=True): | |
|
41 | pe = os.path.join(path, e) | |
|
42 | if kind == stat.S_IFDIR: | |
|
43 | if recurse: | |
|
44 | for x in _dirwalk(pe, True): | |
|
45 | yield x | |
|
46 | elif kind == stat.S_IFREG: | |
|
47 | yield pe, st.st_size | |
|
48 | ||
|
49 | class _store: | |
|
50 | '''base class for local repository stores''' | |
|
51 | def __init__(self, path): | |
|
52 | self.path = path | |
|
53 | try: | |
|
54 | # files in .hg/ will be created using this mode | |
|
55 | mode = os.stat(self.path).st_mode | |
|
56 | # avoid some useless chmods | |
|
57 | if (0777 & ~util._umask) == (0777 & mode): | |
|
58 | mode = None | |
|
59 | except OSError: | |
|
60 | mode = None | |
|
61 | self.createmode = mode | |
|
62 | ||
|
63 | def join(self, f): | |
|
64 | return os.path.join(self.path, f) | |
|
65 | ||
|
66 | def _revlogfiles(self, relpath='', recurse=False): | |
|
67 | '''yields (filename, size)''' | |
|
68 | if relpath: | |
|
69 | path = os.path.join(self.path, relpath) | |
|
70 | else: | |
|
71 | path = self.path | |
|
72 | striplen = len(self.path) + len(os.sep) | |
|
73 | filetypes = ('.d', '.i') | |
|
74 | for f, size in _dirwalk(path, recurse): | |
|
75 | if (len(f) > 2) and f[-2:] in filetypes: | |
|
76 | yield util.pconvert(f[striplen:]), size | |
|
77 | ||
|
78 | def _datafiles(self): | |
|
79 | for x in self._revlogfiles('data', True): | |
|
80 | yield x | |
|
81 | ||
|
82 | def walk(self): | |
|
83 | '''yields (direncoded filename, size)''' | |
|
84 | # yield data files first | |
|
85 | for x in self._datafiles(): | |
|
86 | yield x | |
|
87 | # yield manifest before changelog | |
|
88 | meta = util.sort(self._revlogfiles()) | |
|
89 | meta.reverse() | |
|
90 | for x in meta: | |
|
91 | yield x | |
|
92 | ||
|
93 | class directstore(_store): | |
|
94 | def __init__(self, path): | |
|
95 | _store.__init__(self, path) | |
|
96 | self.encodefn = lambda x: x | |
|
97 | self.opener = util.opener(self.path) | |
|
98 | self.opener.createmode = self.createmode | |
|
99 | ||
|
100 | class encodedstore(_store): | |
|
101 | def __init__(self, path): | |
|
102 | _store.__init__(self, os.path.join(path, 'store')) | |
|
103 | self.encodefn = encodefilename | |
|
104 | op = util.opener(self.path) | |
|
105 | op.createmode = self.createmode | |
|
106 | self.opener = lambda f, *args, **kw: op(self.encodefn(f), *args, **kw) | |
|
107 | ||
|
108 | def _datafiles(self): | |
|
109 | for f, size in self._revlogfiles('data', True): | |
|
110 | yield decodefilename(f), size | |
|
111 | ||
|
112 | def join(self, f): | |
|
113 | return os.path.join(self.path, self.encodefn(f)) | |
|
114 | ||
|
115 | def encodefn(requirements): | |
|
116 | if 'store' not in requirements: | |
|
117 | return lambda x: x | |
|
118 | else: | |
|
119 | return encodefilename | |
|
120 | ||
|
121 | def store(requirements, path): | |
|
122 | if 'store' not in requirements: | |
|
123 | return directstore(path) | |
|
124 | else: | |
|
125 | return encodedstore(path) |
@@ -5,40 +5,12 b'' | |||
|
5 | 5 | # This software may be used and distributed according to the terms |
|
6 | 6 | # of the GNU General Public License, incorporated herein by reference. |
|
7 | 7 | |
|
8 |
import |
|
|
8 | import util, lock | |
|
9 | 9 | |
|
10 | 10 | # if server supports streaming clone, it advertises "stream" |
|
11 | 11 | # capability with value that is version+flags of repo it is serving. |
|
12 | 12 | # client only streams if it can read that repo format. |
|
13 | 13 | |
|
14 | def walkrepo(root): | |
|
15 | '''iterate over metadata files in repository. | |
|
16 | walk in natural (sorted) order. | |
|
17 | yields 2-tuples: name of .d or .i file, size of file.''' | |
|
18 | ||
|
19 | strip_count = len(root) + len(os.sep) | |
|
20 | def walk(path, recurse): | |
|
21 | for e, kind, st in osutil.listdir(path, stat=True): | |
|
22 | pe = os.path.join(path, e) | |
|
23 | if kind == stat.S_IFDIR: | |
|
24 | if recurse: | |
|
25 | for x in walk(pe, True): | |
|
26 | yield x | |
|
27 | else: | |
|
28 | if kind != stat.S_IFREG or len(e) < 2: | |
|
29 | continue | |
|
30 | sfx = e[-2:] | |
|
31 | if sfx in ('.d', '.i'): | |
|
32 | yield pe[strip_count:], st.st_size | |
|
33 | # write file data first | |
|
34 | for x in walk(os.path.join(root, 'data'), True): | |
|
35 | yield x | |
|
36 | # write manifest before changelog | |
|
37 | meta = util.sort(walk(root, False)) | |
|
38 | meta.reverse() | |
|
39 | for x in meta: | |
|
40 | yield x | |
|
41 | ||
|
42 | 14 | # stream file format is simple. |
|
43 | 15 | # |
|
44 | 16 | # server writes out line that says how many files, how many total |
@@ -59,28 +31,14 b' def stream_out(repo, fileobj, untrusted=' | |||
|
59 | 31 | fileobj.write('1\n') |
|
60 | 32 | return |
|
61 | 33 | |
|
62 | # get consistent snapshot of repo. lock during scan so lock not | |
|
63 | # needed while we stream, and commits can happen. | |
|
64 | repolock = None | |
|
65 | 34 | try: |
|
66 | try: | |
|
67 | repolock = repo.lock() | |
|
35 | entries, total_bytes = repo.storefiles() | |
|
68 | 36 |
|
|
69 | 37 |
|
|
70 | 38 |
|
|
71 | 39 |
|
|
72 | 40 | |
|
73 | 41 |
|
|
74 | repo.ui.debug('scanning\n') | |
|
75 | entries = [] | |
|
76 | total_bytes = 0 | |
|
77 | for name, size in walkrepo(repo.spath): | |
|
78 | name = repo.decodefn(util.pconvert(name)) | |
|
79 | entries.append((name, size)) | |
|
80 | total_bytes += size | |
|
81 | finally: | |
|
82 | del repolock | |
|
83 | ||
|
84 | 42 | repo.ui.debug('%d files, %d bytes to transfer\n' % |
|
85 | 43 | (len(entries), total_bytes)) |
|
86 | 44 | fileobj.write('%d %d\n' % (len(entries), total_bytes)) |
General Comments 0
You need to be logged in to leave comments.
Login now