##// END OF EJS Templates
filelog encoding: move the encoding/decoding into store...
Benoit Boissinot -
r8531:810387f5 default
parent child Browse files
Show More
@@ -10,21 +10,7 b' import revlog'
10 class filelog(revlog.revlog):
10 class filelog(revlog.revlog):
11 def __init__(self, opener, path):
11 def __init__(self, opener, path):
12 revlog.revlog.__init__(self, opener,
12 revlog.revlog.__init__(self, opener,
13 "/".join(("data", self.encodedir(path + ".i"))))
13 "/".join(("data", path + ".i")))
14
15 # This avoids a collision between a file named foo and a dir named
16 # foo.i or foo.d
17 def encodedir(self, path):
18 return (path
19 .replace(".hg/", ".hg.hg/")
20 .replace(".i/", ".i.hg/")
21 .replace(".d/", ".d.hg/"))
22
23 def decodedir(self, path):
24 return (path
25 .replace(".d.hg/", ".d/")
26 .replace(".i.hg/", ".i/")
27 .replace(".hg.hg/", ".hg/"))
28
14
29 def read(self, node):
15 def read(self, node):
30 t = self.revision(node)
16 t = self.revision(node)
@@ -2026,7 +2026,8 b' class localrepository(repo.repository):'
2026 raise error.ResponseError(
2026 raise error.ResponseError(
2027 _('Unexpected response from remote server:'), l)
2027 _('Unexpected response from remote server:'), l)
2028 self.ui.debug(_('adding %s (%s)\n') % (name, util.bytecount(size)))
2028 self.ui.debug(_('adding %s (%s)\n') % (name, util.bytecount(size)))
2029 ofp = self.sopener(name, 'w')
2029 # for backwards compat, name was partially encoded
2030 ofp = self.sopener(store.decodedir(name), 'w')
2030 for chunk in util.filechunkiter(fp, limit=size):
2031 for chunk in util.filechunkiter(fp, limit=size):
2031 ofp.write(chunk)
2032 ofp.write(chunk)
2032 ofp.close()
2033 ofp.close()
@@ -11,6 +11,24 b' import os, stat'
11
11
12 _sha = util.sha1
12 _sha = util.sha1
13
13
14 # This avoids a collision between a file named foo and a dir named
15 # foo.i or foo.d
16 def encodedir(path):
17 if not path.startswith('data/'):
18 return path
19 return (path
20 .replace(".hg/", ".hg.hg/")
21 .replace(".i/", ".i.hg/")
22 .replace(".d/", ".d.hg/"))
23
24 def decodedir(path):
25 if not path.startswith('data/'):
26 return path
27 return (path
28 .replace(".d.hg/", ".d/")
29 .replace(".i.hg/", ".i/")
30 .replace(".hg.hg/", ".hg/"))
31
14 def _buildencodefun():
32 def _buildencodefun():
15 e = '_'
33 e = '_'
16 win_reserved = [ord(x) for x in '\\:*?"<>|']
34 win_reserved = [ord(x) for x in '\\:*?"<>|']
@@ -34,8 +52,8 b' def _buildencodefun():'
34 pass
52 pass
35 else:
53 else:
36 raise KeyError
54 raise KeyError
37 return (lambda s: "".join([cmap[c] for c in s]),
55 return (lambda s: "".join([cmap[c] for c in encodedir(s)]),
38 lambda s: "".join(list(decode(s))))
56 lambda s: decodedir("".join(list(decode(s)))))
39
57
40 encodefilename, decodefilename = _buildencodefun()
58 encodefilename, decodefilename = _buildencodefun()
41
59
@@ -104,6 +122,8 b' def hybridencode(path):'
104 '''
122 '''
105 if not path.startswith('data/'):
123 if not path.startswith('data/'):
106 return path
124 return path
125 # escape directories ending with .i and .d
126 path = encodedir(path)
107 ndpath = path[len('data/'):]
127 ndpath = path[len('data/'):]
108 res = 'data/' + auxencode(encodefilename(ndpath))
128 res = 'data/' + auxencode(encodefilename(ndpath))
109 if len(res) > MAX_PATH_LEN_IN_HGSTORE:
129 if len(res) > MAX_PATH_LEN_IN_HGSTORE:
@@ -155,7 +175,7 b' class basicstore:'
155 self.opener.createmode = self.createmode
175 self.opener.createmode = self.createmode
156
176
157 def join(self, f):
177 def join(self, f):
158 return self.pathjoiner(self.path, f)
178 return self.pathjoiner(self.path, encodedir(f))
159
179
160 def _walk(self, relpath, recurse):
180 def _walk(self, relpath, recurse):
161 '''yields (unencoded, encoded, size)'''
181 '''yields (unencoded, encoded, size)'''
@@ -170,7 +190,7 b' class basicstore:'
170 fp = self.pathjoiner(p, f)
190 fp = self.pathjoiner(p, f)
171 if kind == stat.S_IFREG and f[-2:] in ('.d', '.i'):
191 if kind == stat.S_IFREG and f[-2:] in ('.d', '.i'):
172 n = util.pconvert(fp[striplen:])
192 n = util.pconvert(fp[striplen:])
173 l.append((n, n, st.st_size))
193 l.append((decodedir(n), n, st.st_size))
174 elif kind == stat.S_IFDIR and recurse:
194 elif kind == stat.S_IFDIR and recurse:
175 visit.append(fp)
195 visit.append(fp)
176 return sorted(l)
196 return sorted(l)
@@ -215,6 +235,8 b' class encodedstore(basicstore):'
215 [self.pathjoiner('store', f) for f in _data.split()])
235 [self.pathjoiner('store', f) for f in _data.split()])
216
236
217 class fncache(object):
237 class fncache(object):
238 # the filename used to be partially encoded
239 # hence the encodedir/decodedir dance
218 def __init__(self, opener):
240 def __init__(self, opener):
219 self.opener = opener
241 self.opener = opener
220 self.entries = None
242 self.entries = None
@@ -231,20 +253,20 b' class fncache(object):'
231 if (len(line) < 2) or (line[-1] != '\n'):
253 if (len(line) < 2) or (line[-1] != '\n'):
232 t = _('invalid entry in fncache, line %s') % (n + 1)
254 t = _('invalid entry in fncache, line %s') % (n + 1)
233 raise util.Abort(t)
255 raise util.Abort(t)
234 self.entries.add(line[:-1])
256 self.entries.add(decodedir(line[:-1]))
235 fp.close()
257 fp.close()
236
258
237 def rewrite(self, files):
259 def rewrite(self, files):
238 fp = self.opener('fncache', mode='wb')
260 fp = self.opener('fncache', mode='wb')
239 for p in files:
261 for p in files:
240 fp.write(p + '\n')
262 fp.write(encodedir(p) + '\n')
241 fp.close()
263 fp.close()
242 self.entries = set(files)
264 self.entries = set(files)
243
265
244 def add(self, fn):
266 def add(self, fn):
245 if self.entries is None:
267 if self.entries is None:
246 self._load()
268 self._load()
247 self.opener('fncache', 'ab').write(fn + '\n')
269 self.opener('fncache', 'ab').write(encodedir(fn) + '\n')
248
270
249 def __contains__(self, fn):
271 def __contains__(self, fn):
250 if self.entries is None:
272 if self.entries is None:
@@ -8,6 +8,8 b''
8 import util, error
8 import util, error
9 from i18n import _
9 from i18n import _
10
10
11 from mercurial import store
12
11 class StreamException(Exception):
13 class StreamException(Exception):
12 def __init__(self, code):
14 def __init__(self, code):
13 Exception.__init__(self)
15 Exception.__init__(self)
@@ -46,7 +48,8 b' def stream_out(repo, untrusted=False):'
46 try:
48 try:
47 repo.ui.debug(_('scanning\n'))
49 repo.ui.debug(_('scanning\n'))
48 for name, ename, size in repo.store.walk():
50 for name, ename, size in repo.store.walk():
49 entries.append((name, size))
51 # for backwards compat, name was partially encoded
52 entries.append((store.encodedir(name), size))
50 total_bytes += size
53 total_bytes += size
51 finally:
54 finally:
52 lock.release()
55 lock.release()
@@ -36,8 +36,8 b' checking manifests'
36 crosschecking files in changesets and manifests
36 crosschecking files in changesets and manifests
37 checking files
37 checking files
38 data/a.i@0: missing revlog!
38 data/a.i@0: missing revlog!
39 data/a.i.hg.hg/c.i@2: missing revlog!
39 data/a.i.hg/c.i@2: missing revlog!
40 data/a.i.hg/b.i@1: missing revlog!
40 data/a.i/b.i@1: missing revlog!
41 3 files, 3 changesets, 3 total revisions
41 3 files, 3 changesets, 3 total revisions
42 3 integrity errors encountered!
42 3 integrity errors encountered!
43 (first damaged changeset appears to be 0)
43 (first damaged changeset appears to be 0)
General Comments 0
You need to be logged in to leave comments. Login now