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