--- a/mercurial/store.py Mon Sep 17 15:13:17 2012 -0500
+++ b/mercurial/store.py Tue Sep 18 15:30:22 2012 +0200
@@ -22,8 +22,6 @@
>>> encodedir('data/foo.i.hg/bla.i')
'data/foo.i.hg.hg/bla.i'
'''
- if not path.startswith('data/'):
- return path
return (path
.replace(".hg/", ".hg.hg/")
.replace(".i/", ".i.hg/")
@@ -38,7 +36,7 @@
>>> decodedir('data/foo.i.hg.hg/bla.i')
'data/foo.i.hg/bla.i'
'''
- if not path.startswith('data/') or ".hg/" not in path:
+ if ".hg/" not in path:
return path
return (path
.replace(".d.hg/", ".d/")
@@ -132,22 +130,23 @@
basename (e.g. "aux", "aux.foo"). A directory or file named "foo.aux"
doesn't need encoding.
- >>> _auxencode('.foo/aux.txt/txt.aux/con/prn/nul/foo.', True)
+ >>> s = '.foo/aux.txt/txt.aux/con/prn/nul/foo.'
+ >>> _auxencode(s.split('/'), True)
['~2efoo', 'au~78.txt', 'txt.aux', 'co~6e', 'pr~6e', 'nu~6c', 'foo~2e']
- >>> _auxencode('.com1com2/lpt9.lpt4.lpt1/conprn/com0/lpt0/foo.', False)
+ >>> s = '.com1com2/lpt9.lpt4.lpt1/conprn/com0/lpt0/foo.'
+ >>> _auxencode(s.split('/'), False)
['.com1com2', 'lp~749.lpt4.lpt1', 'conprn', 'com0', 'lpt0', 'foo~2e']
- >>> _auxencode('foo. ', True)
+ >>> _auxencode(['foo. '], True)
['foo.~20']
- >>> _auxencode(' .foo', True)
+ >>> _auxencode([' .foo'], True)
['~20.foo']
'''
- res = path.split('/')
- for i, n in enumerate(res):
+ for i, n in enumerate(path):
if not n:
continue
if dotencode and n[0] in '. ':
n = "~%02x" % ord(n[0]) + n[1:]
- res[i] = n
+ path[i] = n
else:
l = n.find('.')
if l == -1:
@@ -158,16 +157,16 @@
# encode third letter ('aux' -> 'au~78')
ec = "~%02x" % ord(n[2])
n = n[0:2] + ec + n[3:]
- res[i] = n
+ path[i] = n
if n[-1] in '. ':
# encode last period or space ('foo...' -> 'foo..~2e')
- res[i] = n[:-1] + "~%02x" % ord(n[-1])
- return res
+ path[i] = n[:-1] + "~%02x" % ord(n[-1])
+ return path
_maxstorepathlen = 120
_dirprefixlen = 8
_maxshortdirslen = 8 * (_dirprefixlen + 1) - 4
-def _hybridencode(path, auxencode):
+def _hybridencode(path, dotencode):
'''encodes path with a length limit
Encodes all paths that begin with 'data/', according to the following.
@@ -198,27 +197,30 @@
The string 'data/' at the beginning is replaced with 'dh/', if the hashed
encoding was used.
'''
- if not path.startswith('data/'):
- return path
- # escape directories ending with .i and .d
- path = encodedir(path)
- ndpath = path[len('data/'):]
- res = 'data/' + '/'.join(auxencode(encodefilename(ndpath)))
+ ef = encodefilename(path).split('/')
+ res = '/'.join(_auxencode(ef, dotencode))
if len(res) > _maxstorepathlen:
+ path = encodedir(path)
digest = _sha(path).hexdigest()
- parts = auxencode(lowerencode(ndpath))
- _root, ext = os.path.splitext(parts[-1])
+ le = lowerencode(path).split('/')[1:]
+ parts = _auxencode(le, dotencode)
basename = parts[-1]
+ _root, ext = os.path.splitext(basename)
sdirs = []
+ sdirslen = 0
for p in parts[:-1]:
d = p[:_dirprefixlen]
if d[-1] in '. ':
# Windows can't access dirs ending in period or space
d = d[:-1] + '_'
- t = '/'.join(sdirs) + '/' + d
- if len(t) > _maxshortdirslen:
- break
+ if sdirslen == 0:
+ t = len(d)
+ else:
+ t = sdirslen + 1 + len(d)
+ if t > _maxshortdirslen:
+ break
sdirs.append(d)
+ sdirslen = t
dirs = '/'.join(sdirs)
if len(dirs) > 0:
dirs += '/'
@@ -346,7 +348,7 @@
def _write(self, files, atomictemp):
fp = self.opener('fncache', mode='wb', atomictemp=atomictemp)
if files:
- fp.write('\n'.join(map(encodedir, files)) + '\n')
+ fp.write(encodedir('\n'.join(files) + '\n'))
fp.close()
self._dirty = False
@@ -394,8 +396,18 @@
self.fncache.add(path)
return self.opener(self.encode(path), mode, *args, **kw)
+def _plainhybridencode(f):
+ return _hybridencode(f, False)
+
+def _dothybridencode(f):
+ return _hybridencode(f, True)
+
class fncachestore(basicstore):
- def __init__(self, path, openertype, encode):
+ def __init__(self, path, openertype, dotencode):
+ if dotencode:
+ encode = _dothybridencode
+ else:
+ encode = _plainhybridencode
self.encode = encode
self.path = path + '/store'
self.pathsep = self.path + '/'
@@ -442,8 +454,6 @@
def store(requirements, path, openertype):
if 'store' in requirements:
if 'fncache' in requirements:
- auxencode = lambda f: _auxencode(f, 'dotencode' in requirements)
- encode = lambda f: _hybridencode(f, auxencode)
- return fncachestore(path, openertype, encode)
+ return fncachestore(path, openertype, 'dotencode' in requirements)
return encodedstore(path, openertype)
return basicstore(path, openertype)
--- a/tests/test-hybridencode.py Mon Sep 17 15:13:17 2012 -0500
+++ b/tests/test-hybridencode.py Tue Sep 18 15:30:22 2012 +0200
@@ -1,7 +1,6 @@
from mercurial import store
-auxencode = lambda f: store._auxencode(f, True)
-hybridencode = lambda f: store._hybridencode(f, auxencode)
+hybridencode = lambda f: store._hybridencode(f, True)
enc = hybridencode # used for 'dotencode' repo format
@@ -41,7 +40,7 @@
', pipe |, question-mark ?, asterisk *')
print "encoding directories ending in .hg, .i or .d with '.hg' suffix"
-show('data/x.hg/x.i/x.d/foo')
+show('data/x.h.i/x.hg/x.i/x.d/foo')
show('data/a.hg/a.i/a.d/foo')
show('data/au.hg/au.i/au.d/foo')
show('data/aux.hg/aux.i/aux.d/foo')
--- a/tests/test-hybridencode.py.out Mon Sep 17 15:13:17 2012 -0500
+++ b/tests/test-hybridencode.py.out Tue Sep 18 15:30:22 2012 +0200
@@ -35,8 +35,8 @@
B = 'data/less ~3c, greater ~3e, colon ~3a, double-quote ~22, backslash ~5c, pipe ~7c, question-mark ~3f, asterisk ~2a'
encoding directories ending in .hg, .i or .d with '.hg' suffix
-A = 'data/x.hg/x.i/x.d/foo'
-B = 'data/x.hg.hg/x.i.hg/x.d.hg/foo'
+A = 'data/x.h.i/x.hg/x.i/x.d/foo'
+B = 'data/x.h.i.hg/x.hg.hg/x.i.hg/x.d.hg/foo'
A = 'data/a.hg/a.i/a.d/foo'
B = 'data/a.hg.hg/a.i.hg/a.d.hg/foo'