Mercurial > hg
changeset 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 | fe31f834a9ff |
children | 8c034a825cfe |
files | mercurial/localrepo.py mercurial/store.py tests/test-hybridencode.py tests/test-hybridencode.py.out tests/test-init.t |
diffstat | 5 files changed, 28 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/localrepo.py Tue Sep 14 23:00:39 2010 +0200 +++ b/mercurial/localrepo.py Sat Oct 09 21:54:50 2010 +0200 @@ -22,7 +22,8 @@ class localrepository(repo.repository): capabilities = set(('lookup', 'changegroupsubset', 'branchmap', 'pushkey')) supportedformats = set(('revlogv1', 'parentdelta')) - supported = supportedformats | set(('store', 'fncache', 'shared')) + supported = supportedformats | set(('store', 'fncache', 'shared', + 'dotencode')) def __init__(self, baseui, path=None, create=0): repo.repository.__init__(self) @@ -52,6 +53,8 @@ requirements.append("store") if self.ui.configbool('format', 'usefncache', True): requirements.append("fncache") + if self.ui.configbool('format', 'dotencode', True): + requirements.append('dotencode') # create an invalid changelog self.opener("00changelog.i", "a").write( '\0\0\0\2' # represents revlogv2
--- 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)
--- a/tests/test-hybridencode.py Tue Sep 14 23:00:39 2010 +0200 +++ b/tests/test-hybridencode.py Sat Oct 09 21:54:50 2010 +0200 @@ -2,7 +2,10 @@ from mercurial import store -enc = store.hybridencode # used for fncache repo format +auxencode = lambda f: store._auxencode(f, True) +hybridencode = lambda f: store._hybridencode(f, auxencode) + +enc = hybridencode # used for 'dotencode' repo format def show(s): print "A = '%s'" % s @@ -22,4 +25,5 @@ 'Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt') show('data/Project.Planning/Resources/AnotherLongDirectoryName/' 'Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt') -show('data/foo.../foo / /a./_. /__/.x../ bla/something.i') +show('data/foo.../foo / /a./_. /__/.x../ bla/.FOO/something.i') +
--- a/tests/test-hybridencode.py.out Tue Sep 14 23:00:39 2010 +0200 +++ b/tests/test-hybridencode.py.out Sat Oct 09 21:54:50 2010 +0200 @@ -16,6 +16,6 @@ A = 'data/Project.Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt' B = 'dh/project_/resource/anotherl/followed/andanoth/andthenanextremelylongfilena0fd7c506f5c9d58204444fc67e9499006bd2d445.txt' -A = 'data/foo.../foo / /a./_. /__/.x../ bla/something.i' -B = 'data/foo..~2e/foo ~20/~20/a~2e/__.~20/____/.x.~2e/ bla/something.i' +A = 'data/foo.../foo / /a./_. /__/.x../ bla/.FOO/something.i' +B = 'data/foo..~2e/foo ~20/~20/a~2e/__.~20/____/~2ex.~2e/~20 bla/~2e_f_o_o/something.i'
--- a/tests/test-init.t Tue Sep 14 23:00:39 2010 +0200 +++ b/tests/test-init.t Sat Oct 09 21:54:50 2010 +0200 @@ -42,6 +42,7 @@ revlogv1 store fncache + dotencode $ echo this > local/foo $ hg ci --cwd local -A -m "init" adding foo @@ -157,6 +158,7 @@ revlogv1 store fncache + dotencode prepare test of init of url configured from paths @@ -173,6 +175,7 @@ revlogv1 store fncache + dotencode verify that clone also expand urls @@ -185,3 +188,4 @@ revlogv1 store fncache + dotencode