changeset 8531:810387f59696

filelog encoding: move the encoding/decoding into store the escaping of directories ending with .i or .d doesn't really belong to filelog. we put the encoding/decoding in store instead, for backwards compat, streamclone and the fncache file format still uses the partially encoded filenames.
author Benoit Boissinot <benoit.boissinot@ens-lyon.org>
date Wed, 20 May 2009 18:35:47 +0200
parents 03196ac9a8b9
children b97e2417ae53
files mercurial/filelog.py mercurial/localrepo.py mercurial/store.py mercurial/streamclone.py tests/test-fncache.out
diffstat 5 files changed, 38 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/filelog.py	Wed May 20 18:35:41 2009 +0200
+++ b/mercurial/filelog.py	Wed May 20 18:35:47 2009 +0200
@@ -10,21 +10,7 @@
 class filelog(revlog.revlog):
     def __init__(self, opener, path):
         revlog.revlog.__init__(self, opener,
-                        "/".join(("data", self.encodedir(path + ".i"))))
-
-    # This avoids a collision between a file named foo and a dir named
-    # foo.i or foo.d
-    def encodedir(self, path):
-        return (path
-                .replace(".hg/", ".hg.hg/")
-                .replace(".i/", ".i.hg/")
-                .replace(".d/", ".d.hg/"))
-
-    def decodedir(self, path):
-        return (path
-                .replace(".d.hg/", ".d/")
-                .replace(".i.hg/", ".i/")
-                .replace(".hg.hg/", ".hg/"))
+                        "/".join(("data", path + ".i")))
 
     def read(self, node):
         t = self.revision(node)
--- a/mercurial/localrepo.py	Wed May 20 18:35:41 2009 +0200
+++ b/mercurial/localrepo.py	Wed May 20 18:35:47 2009 +0200
@@ -2026,7 +2026,8 @@
                 raise error.ResponseError(
                     _('Unexpected response from remote server:'), l)
             self.ui.debug(_('adding %s (%s)\n') % (name, util.bytecount(size)))
-            ofp = self.sopener(name, 'w')
+            # for backwards compat, name was partially encoded
+            ofp = self.sopener(store.decodedir(name), 'w')
             for chunk in util.filechunkiter(fp, limit=size):
                 ofp.write(chunk)
             ofp.close()
--- a/mercurial/store.py	Wed May 20 18:35:41 2009 +0200
+++ b/mercurial/store.py	Wed May 20 18:35:47 2009 +0200
@@ -11,6 +11,24 @@
 
 _sha = util.sha1
 
+# This avoids a collision between a file named foo and a dir named
+# foo.i or foo.d
+def encodedir(path):
+    if not path.startswith('data/'):
+        return path
+    return (path
+            .replace(".hg/", ".hg.hg/")
+            .replace(".i/", ".i.hg/")
+            .replace(".d/", ".d.hg/"))
+
+def decodedir(path):
+    if not path.startswith('data/'):
+        return path
+    return (path
+            .replace(".d.hg/", ".d/")
+            .replace(".i.hg/", ".i/")
+            .replace(".hg.hg/", ".hg/"))
+
 def _buildencodefun():
     e = '_'
     win_reserved = [ord(x) for x in '\\:*?"<>|']
@@ -34,8 +52,8 @@
                     pass
             else:
                 raise KeyError
-    return (lambda s: "".join([cmap[c] for c in s]),
-            lambda s: "".join(list(decode(s))))
+    return (lambda s: "".join([cmap[c] for c in encodedir(s)]),
+            lambda s: decodedir("".join(list(decode(s)))))
 
 encodefilename, decodefilename = _buildencodefun()
 
@@ -104,6 +122,8 @@
     '''
     if not path.startswith('data/'):
         return path
+    # escape directories ending with .i and .d
+    path = encodedir(path)
     ndpath = path[len('data/'):]
     res = 'data/' + auxencode(encodefilename(ndpath))
     if len(res) > MAX_PATH_LEN_IN_HGSTORE:
@@ -155,7 +175,7 @@
         self.opener.createmode = self.createmode
 
     def join(self, f):
-        return self.pathjoiner(self.path, f)
+        return self.pathjoiner(self.path, encodedir(f))
 
     def _walk(self, relpath, recurse):
         '''yields (unencoded, encoded, size)'''
@@ -170,7 +190,7 @@
                     fp = self.pathjoiner(p, f)
                     if kind == stat.S_IFREG and f[-2:] in ('.d', '.i'):
                         n = util.pconvert(fp[striplen:])
-                        l.append((n, n, st.st_size))
+                        l.append((decodedir(n), n, st.st_size))
                     elif kind == stat.S_IFDIR and recurse:
                         visit.append(fp)
         return sorted(l)
@@ -215,6 +235,8 @@
                 [self.pathjoiner('store', f) for f in _data.split()])
 
 class fncache(object):
+    # the filename used to be partially encoded
+    # hence the encodedir/decodedir dance
     def __init__(self, opener):
         self.opener = opener
         self.entries = None
@@ -231,20 +253,20 @@
             if (len(line) < 2) or (line[-1] != '\n'):
                 t = _('invalid entry in fncache, line %s') % (n + 1)
                 raise util.Abort(t)
-            self.entries.add(line[:-1])
+            self.entries.add(decodedir(line[:-1]))
         fp.close()
 
     def rewrite(self, files):
         fp = self.opener('fncache', mode='wb')
         for p in files:
-            fp.write(p + '\n')
+            fp.write(encodedir(p) + '\n')
         fp.close()
         self.entries = set(files)
 
     def add(self, fn):
         if self.entries is None:
             self._load()
-        self.opener('fncache', 'ab').write(fn + '\n')
+        self.opener('fncache', 'ab').write(encodedir(fn) + '\n')
 
     def __contains__(self, fn):
         if self.entries is None:
--- a/mercurial/streamclone.py	Wed May 20 18:35:41 2009 +0200
+++ b/mercurial/streamclone.py	Wed May 20 18:35:47 2009 +0200
@@ -8,6 +8,8 @@
 import util, error
 from i18n import _
 
+from mercurial import store
+
 class StreamException(Exception):
     def __init__(self, code):
         Exception.__init__(self)
@@ -46,7 +48,8 @@
         try:
             repo.ui.debug(_('scanning\n'))
             for name, ename, size in repo.store.walk():
-                entries.append((name, size))
+                # for backwards compat, name was partially encoded
+                entries.append((store.encodedir(name), size))
                 total_bytes += size
         finally:
             lock.release()
--- a/tests/test-fncache.out	Wed May 20 18:35:41 2009 +0200
+++ b/tests/test-fncache.out	Wed May 20 18:35:47 2009 +0200
@@ -36,8 +36,8 @@
 crosschecking files in changesets and manifests
 checking files
  data/a.i@0: missing revlog!
- data/a.i.hg.hg/c.i@2: missing revlog!
- data/a.i.hg/b.i@1: missing revlog!
+ data/a.i.hg/c.i@2: missing revlog!
+ data/a.i/b.i@1: missing revlog!
 3 files, 3 changesets, 3 total revisions
 3 integrity errors encountered!
 (first damaged changeset appears to be 0)