diff --git a/hgext/win32mbcs.py b/hgext/win32mbcs.py --- a/hgext/win32mbcs.py +++ b/hgext/win32mbcs.py @@ -49,6 +49,9 @@ def decode(arg): return tuple(map(decode, arg)) elif isinstance(arg, list): return map(decode, arg) + elif isinstance(arg, dict): + for k, v in arg.items(): + arg[k] = decode(v) return arg def encode(arg): @@ -58,29 +61,50 @@ def encode(arg): return tuple(map(encode, arg)) elif isinstance(arg, list): return map(encode, arg) + elif isinstance(arg, dict): + for k, v in arg.items(): + arg[k] = encode(v) return arg -def wrapper(func, args): +def appendsep(s): + # ensure the path ends with os.sep, appending it if necessary. + try: + us = decode(s) + except UnicodeError: + us = s + if us and us[-1] not in ':/\\': + s += os.sep + return s + +def wrapper(func, args, kwds): # check argument is unicode, then call original for arg in args: if isinstance(arg, unicode): - return func(*args) + return func(*args, **kwds) try: # convert arguments to unicode, call func, then convert back - return encode(func(*decode(args))) + return encode(func(*decode(args), **decode(kwds))) except UnicodeError: - # If not encoded with encoding.encoding, report it then - # continue with calling original function. - raise util.Abort(_("[win32mbcs] filename conversion fail with" + raise util.Abort(_("[win32mbcs] filename conversion failed with" " %s encoding\n") % (encoding.encoding)) -def wrapname(name): +def wrapperforlistdir(func, args, kwds): + # Ensure 'path' argument ends with os.sep to avoids + # misinterpreting last 0x5c of MBCS 2nd byte as path separator. + if args: + args = list(args) + args[0] = appendsep(args[0]) + if kwds.has_key('path'): + kwds['path'] = appendsep(kwds['path']) + return func(*args, **kwds) + +def wrapname(name, wrapper): module, name = name.rsplit('.', 1) module = sys.modules[module] func = getattr(module, name) - def f(*args): - return wrapper(func, args) + def f(*args, **kwds): + return wrapper(func, args, kwds) try: f.__name__ = func.__name__ # fail with python23 except Exception: @@ -110,7 +134,8 @@ def reposetup(ui, repo): # fake is only for relevant environment. if encoding.encoding.lower() in problematic_encodings.split(): for f in funcs.split(): - wrapname(f) + wrapname(f, wrapper) + wrapname("mercurial.osutil.listdir", wrapperforlistdir) ui.debug(_("[win32mbcs] activated with encoding: %s\n") % encoding.encoding) diff --git a/mercurial/store.py b/mercurial/store.py --- a/mercurial/store.py +++ b/mercurial/store.py @@ -284,16 +284,17 @@ class fncachestore(basicstore): self.pathjoiner = pathjoiner self.path = self.pathjoiner(path, 'store') self.createmode = _calcmode(self.path) - self._op = opener(self.path) - self._op.createmode = self.createmode - self.fncache = fncache(self._op) + op = opener(self.path) + op.createmode = self.createmode + fnc = fncache(op) + self.fncache = fnc def fncacheopener(path, mode='r', *args, **kw): if (mode not in ('r', 'rb') and path.startswith('data/') - and path not in self.fncache): - self.fncache.add(path) - return self._op(hybridencode(path), mode, *args, **kw) + and path not in fnc): + fnc.add(path) + return op(hybridencode(path), mode, *args, **kw) self.opener = fncacheopener def join(self, f):