win32mbcs.py
121 lines
| 4.1 KiB
| text/x-python
|
PythonLexer
/ hgext / win32mbcs.py
|
r6887 | # win32mbcs.py -- MBCS filename support for Mercurial | ||
|
r5846 | # | ||
# Copyright (c) 2008 Shun-ichi Goto <shunichi.goto@gmail.com> | ||||
# | ||||
|
r6887 | # Version: 0.2 | ||
|
r5846 | # Author: Shun-ichi Goto <shunichi.goto@gmail.com> | ||
# | ||||
|
r8225 | # This software may be used and distributed according to the terms of the | ||
# GNU General Public License version 2, incorporated herein by reference. | ||||
|
r5846 | # | ||
|
r8228 | |||
|
r7598 | """allow to use MBCS path with problematic encoding. | ||
|
r5846 | |||
|
r8001 | Some MBCS encodings are not good for some path operations (i.e. | ||
splitting path, case conversion, etc.) with its encoded bytes. We call | ||||
such a encoding (i.e. shift_jis and big5) as "problematic encoding". | ||||
This extension can be used to fix the issue with those encodings by | ||||
|
r8665 | wrapping some functions to convert to Unicode string before path | ||
|
r8001 | operation. | ||
|
r5846 | |||
|
r8668 | This extension is useful for: | ||
|
r6887 | * Japanese Windows users using shift_jis encoding. | ||
* Chinese Windows users using big5 encoding. | ||||
|
r8001 | * All users who use a repository with one of problematic encodings on | ||
case-insensitive file system. | ||||
|
r6887 | |||
This extension is not needed for: | ||||
|
r8667 | * Any user who use only ASCII chars in path. | ||
|
r6887 | * Any user who do not use any of problematic encodings. | ||
|
r5846 | |||
|
r6887 | Note that there are some limitations on using this extension: | ||
* You should use single encoding in one repository. | ||||
|
r8001 | * You should set same encoding for the repository by locale or | ||
HGENCODING. | ||||
|
r6887 | |||
|
r8665 | Path encoding conversion are done between Unicode and | ||
|
r8760 | encoding.encoding which is decided by Mercurial from current locale | ||
|
r8001 | setting or HGENCODING. | ||
|
r5846 | |||
""" | ||||
import os | ||||
from mercurial.i18n import _ | ||||
|
r7948 | from mercurial import util, encoding | ||
|
r5846 | |||
|
r6887 | def decode(arg): | ||
|
r7877 | if isinstance(arg, str): | ||
|
r7948 | uarg = arg.decode(encoding.encoding) | ||
if arg == uarg.encode(encoding.encoding): | ||||
|
r7877 | return uarg | ||
raise UnicodeError("Not local encoding") | ||||
elif isinstance(arg, tuple): | ||||
return tuple(map(decode, arg)) | ||||
elif isinstance(arg, list): | ||||
return map(decode, arg) | ||||
return arg | ||||
|
r6887 | |||
def encode(arg): | ||||
|
r7877 | if isinstance(arg, unicode): | ||
|
r7948 | return arg.encode(encoding.encoding) | ||
|
r7877 | elif isinstance(arg, tuple): | ||
return tuple(map(encode, arg)) | ||||
elif isinstance(arg, list): | ||||
return map(encode, arg) | ||||
return arg | ||||
|
r6887 | |||
def wrapper(func, args): | ||||
|
r7877 | # check argument is unicode, then call original | ||
for arg in args: | ||||
if isinstance(arg, unicode): | ||||
return func(*args) | ||||
|
r5846 | |||
|
r7877 | try: | ||
# convert arguments to unicode, call func, then convert back | ||||
return encode(func(*decode(args))) | ||||
except UnicodeError: | ||||
|
r7948 | # If not encoded with encoding.encoding, report it then | ||
|
r7877 | # continue with calling original function. | ||
raise util.Abort(_("[win32mbcs] filename conversion fail with" | ||||
|
r7948 | " %s encoding\n") % (encoding.encoding)) | ||
|
r6887 | |||
def wrapname(name): | ||||
|
r7877 | idx = name.rfind('.') | ||
module = name[:idx] | ||||
name = name[idx+1:] | ||||
|
r8491 | module = globals()[module] | ||
|
r7877 | func = getattr(module, name) | ||
def f(*args): | ||||
return wrapper(func, args) | ||||
try: | ||||
f.__name__ = func.__name__ # fail with python23 | ||||
except Exception: | ||||
pass | ||||
setattr(module, name, f) | ||||
|
r6887 | |||
# List of functions to be wrapped. | ||||
# NOTE: os.path.dirname() and os.path.basename() are safe because | ||||
# they use result of os.path.split() | ||||
funcs = '''os.path.join os.path.split os.path.splitext | ||||
os.path.splitunc os.path.normpath os.path.normcase os.makedirs | ||||
util.endswithsep util.splitpath util.checkcase util.fspath''' | ||||
|
r5846 | |||
# codec and alias names of sjis and big5 to be faked. | ||||
|
r6887 | problematic_encodings = '''big5 big5-tw csbig5 big5hkscs big5-hkscs | ||
hkscs cp932 932 ms932 mskanji ms-kanji shift_jis csshiftjis shiftjis | ||||
sjis s_jis shift_jis_2004 shiftjis2004 sjis_2004 sjis2004 | ||||
|
r8714 | shift_jisx0213 shiftjisx0213 sjisx0213 s_jisx0213 950 cp950 ms950 ''' | ||
|
r5846 | |||
def reposetup(ui, repo): | ||||
|
r7877 | # TODO: decide use of config section for this extension | ||
if not os.path.supports_unicode_filenames: | ||||
ui.warn(_("[win32mbcs] cannot activate on this platform.\n")) | ||||
return | ||||
|
r5846 | |||
|
r7877 | # fake is only for relevant environment. | ||
|
r7948 | if encoding.encoding.lower() in problematic_encodings.split(): | ||
|
r7877 | for f in funcs.split(): | ||
wrapname(f) | ||||
|
r7948 | ui.debug(_("[win32mbcs] activated with encoding: %s\n") | ||
% encoding.encoding) | ||||
|
r6887 | |||