Mercurial > public > mercurial-scm > hg-stable
diff mercurial/store.py @ 12687:34d8247a4595
store: encode first period or space in filenames (issue1713)
- Mac OS X has problems with filenames starting with '._'
(e.g. '.FOO' -> '._f_o_o' is now encoded as '~2e_f_o_o')
- Explorer of Windows Vista and Windows 7 strip leading spaces of
path elements of filenames when copying trees
Above problems are avoided by encoding the first space (as '~20') or
period (as '~2e') of all path elements.
This introduces a new entry 'dotencode' in .hg/requires, that is,
a new repository filename layout (inside .hg/store).
Newly created repositories require 'dotencode' by default. Specifying
[format]
dotencode = False
in a config file will use the old format instead.
Prior Mercurial versions will abort with the message
abort: requirement 'dotencode' not supported!
when trying to access a local repository that requires 'dotencode'.
New 'dotencode' repositories can be converted to the previous
repository format with
hg --config format.dotencode=0 clone --pull repoA repoB
author | Adrian Buehlmann <adrian@cadifra.com> |
---|---|
date | Sat, 09 Oct 2010 21:54:50 +0200 |
parents | cc39d07d2212 |
children | 4c1fbed00224 |
line wrap: on
line diff
--- a/mercurial/store.py Tue Sep 14 23:00:39 2010 +0200 +++ b/mercurial/store.py Sat Oct 09 21:54:50 2010 +0200 @@ -71,7 +71,7 @@ _windows_reserved_filenames = '''con prn aux nul com1 com2 com3 com4 com5 com6 com7 com8 com9 lpt1 lpt2 lpt3 lpt4 lpt5 lpt6 lpt7 lpt8 lpt9'''.split() -def auxencode(path): +def _auxencode(path, dotencode): res = [] for n in path.split('/'): if n: @@ -83,13 +83,15 @@ if n[-1] in '. ': # encode last period or space ('foo...' -> 'foo..~2e') n = n[:-1] + "~%02x" % ord(n[-1]) + if dotencode and n[0] in '. ': + n = "~%02x" % ord(n[0]) + n[1:] res.append(n) return '/'.join(res) MAX_PATH_LEN_IN_HGSTORE = 120 DIR_PREFIX_LEN = 8 _MAX_SHORTENED_DIRS_LEN = 8 * (DIR_PREFIX_LEN + 1) - 4 -def hybridencode(path): +def _hybridencode(path, auxencode): '''encodes path with a length limit Encodes all paths that begin with 'data/', according to the following. @@ -282,7 +284,8 @@ return iter(self.entries) class fncachestore(basicstore): - def __init__(self, path, opener, pathjoiner): + def __init__(self, path, opener, pathjoiner, encode): + self.encode = encode self.pathjoiner = pathjoiner self.path = self.pathjoiner(path, 'store') self.createmode = _calcmode(self.path) @@ -294,11 +297,11 @@ def fncacheopener(path, mode='r', *args, **kw): if mode not in ('r', 'rb') and path.startswith('data/'): fnc.add(path) - return op(hybridencode(path), mode, *args, **kw) + return op(self.encode(path), mode, *args, **kw) self.opener = fncacheopener def join(self, f): - return self.pathjoiner(self.path, hybridencode(f)) + return self.pathjoiner(self.path, self.encode(f)) def datafiles(self): rewrite = False @@ -306,7 +309,7 @@ pjoin = self.pathjoiner spath = self.path for f in self.fncache: - ef = hybridencode(f) + ef = self.encode(f) try: st = os.stat(pjoin(spath, ef)) yield f, ef, st.st_size @@ -328,6 +331,8 @@ pathjoiner = pathjoiner or os.path.join if 'store' in requirements: if 'fncache' in requirements: - return fncachestore(path, opener, pathjoiner) + auxencode = lambda f: _auxencode(f, 'dotencode' in requirements) + encode = lambda f: _hybridencode(f, auxencode) + return fncachestore(path, opener, pathjoiner, encode) return encodedstore(path, opener, pathjoiner) return basicstore(path, opener, pathjoiner)