##// END OF EJS Templates
win32mbcs: allow win32mbcs extension to be enabled on cygwin platform...
FUJIWARA Katsunori -
r15724:9e6a13c2 default
parent child Browse files
Show More
@@ -1,160 +1,167 b''
1 1 # win32mbcs.py -- MBCS filename support for Mercurial
2 2 #
3 3 # Copyright (c) 2008 Shun-ichi Goto <shunichi.goto@gmail.com>
4 4 #
5 5 # Version: 0.3
6 6 # Author: Shun-ichi Goto <shunichi.goto@gmail.com>
7 7 #
8 8 # This software may be used and distributed according to the terms of the
9 9 # GNU General Public License version 2 or any later version.
10 10 #
11 11
12 12 '''allow the use of MBCS paths with problematic encodings
13 13
14 14 Some MBCS encodings are not good for some path operations (i.e.
15 15 splitting path, case conversion, etc.) with its encoded bytes. We call
16 16 such a encoding (i.e. shift_jis and big5) as "problematic encoding".
17 17 This extension can be used to fix the issue with those encodings by
18 18 wrapping some functions to convert to Unicode string before path
19 19 operation.
20 20
21 21 This extension is useful for:
22 22
23 23 - Japanese Windows users using shift_jis encoding.
24 24 - Chinese Windows users using big5 encoding.
25 25 - All users who use a repository with one of problematic encodings on
26 26 case-insensitive file system.
27 27
28 28 This extension is not needed for:
29 29
30 30 - Any user who use only ASCII chars in path.
31 31 - Any user who do not use any of problematic encodings.
32 32
33 33 Note that there are some limitations on using this extension:
34 34
35 35 - You should use single encoding in one repository.
36 36 - If the repository path ends with 0x5c, .hg/hgrc cannot be read.
37 37 - win32mbcs is not compatible with fixutf8 extension.
38 38
39 39 By default, win32mbcs uses encoding.encoding decided by Mercurial.
40 40 You can specify the encoding by config option::
41 41
42 42 [win32mbcs]
43 43 encoding = sjis
44 44
45 45 It is useful for the users who want to commit with UTF-8 log message.
46 46 '''
47 47
48 48 import os, sys
49 49 from mercurial.i18n import _
50 50 from mercurial import util, encoding
51 51
52 52 _encoding = None # see extsetup
53 53
54 54 def decode(arg):
55 55 if isinstance(arg, str):
56 56 uarg = arg.decode(_encoding)
57 57 if arg == uarg.encode(_encoding):
58 58 return uarg
59 59 raise UnicodeError("Not local encoding")
60 60 elif isinstance(arg, tuple):
61 61 return tuple(map(decode, arg))
62 62 elif isinstance(arg, list):
63 63 return map(decode, arg)
64 64 elif isinstance(arg, dict):
65 65 for k, v in arg.items():
66 66 arg[k] = decode(v)
67 67 return arg
68 68
69 69 def encode(arg):
70 70 if isinstance(arg, unicode):
71 71 return arg.encode(_encoding)
72 72 elif isinstance(arg, tuple):
73 73 return tuple(map(encode, arg))
74 74 elif isinstance(arg, list):
75 75 return map(encode, arg)
76 76 elif isinstance(arg, dict):
77 77 for k, v in arg.items():
78 78 arg[k] = encode(v)
79 79 return arg
80 80
81 81 def appendsep(s):
82 82 # ensure the path ends with os.sep, appending it if necessary.
83 83 try:
84 84 us = decode(s)
85 85 except UnicodeError:
86 86 us = s
87 87 if us and us[-1] not in ':/\\':
88 88 s += os.sep
89 89 return s
90 90
91 91 def wrapper(func, args, kwds):
92 92 # check argument is unicode, then call original
93 93 for arg in args:
94 94 if isinstance(arg, unicode):
95 95 return func(*args, **kwds)
96 96
97 97 try:
98 98 # convert arguments to unicode, call func, then convert back
99 99 return encode(func(*decode(args), **decode(kwds)))
100 100 except UnicodeError:
101 101 raise util.Abort(_("[win32mbcs] filename conversion failed with"
102 102 " %s encoding\n") % (_encoding))
103 103
104 104 def wrapperforlistdir(func, args, kwds):
105 105 # Ensure 'path' argument ends with os.sep to avoids
106 106 # misinterpreting last 0x5c of MBCS 2nd byte as path separator.
107 107 if args:
108 108 args = list(args)
109 109 args[0] = appendsep(args[0])
110 110 if 'path' in kwds:
111 111 kwds['path'] = appendsep(kwds['path'])
112 112 return func(*args, **kwds)
113 113
114 114 def wrapname(name, wrapper):
115 115 module, name = name.rsplit('.', 1)
116 116 module = sys.modules[module]
117 117 func = getattr(module, name)
118 118 def f(*args, **kwds):
119 119 return wrapper(func, args, kwds)
120 120 try:
121 121 f.__name__ = func.__name__ # fail with python23
122 122 except Exception:
123 123 pass
124 124 setattr(module, name, f)
125 125
126 126 # List of functions to be wrapped.
127 127 # NOTE: os.path.dirname() and os.path.basename() are safe because
128 128 # they use result of os.path.split()
129 129 funcs = '''os.path.join os.path.split os.path.splitext
130 os.path.splitunc os.path.normpath os.makedirs
130 os.path.normpath os.makedirs
131 131 mercurial.util.endswithsep mercurial.util.splitpath mercurial.util.checkcase
132 132 mercurial.util.fspath mercurial.util.pconvert mercurial.util.normpath
133 133 mercurial.util.checkwinfilename mercurial.util.checkosfilename'''
134 134
135 # List of Windows specific functions to be wrapped.
136 winfuncs = '''os.path.splitunc'''
137
135 138 # codec and alias names of sjis and big5 to be faked.
136 139 problematic_encodings = '''big5 big5-tw csbig5 big5hkscs big5-hkscs
137 140 hkscs cp932 932 ms932 mskanji ms-kanji shift_jis csshiftjis shiftjis
138 141 sjis s_jis shift_jis_2004 shiftjis2004 sjis_2004 sjis2004
139 142 shift_jisx0213 shiftjisx0213 sjisx0213 s_jisx0213 950 cp950 ms950 '''
140 143
141 144 def extsetup(ui):
142 145 # TODO: decide use of config section for this extension
143 if not os.path.supports_unicode_filenames:
146 if ((not os.path.supports_unicode_filenames) and
147 (sys.platform != 'cygwin')):
144 148 ui.warn(_("[win32mbcs] cannot activate on this platform.\n"))
145 149 return
146 150 # determine encoding for filename
147 151 global _encoding
148 152 _encoding = ui.config('win32mbcs', 'encoding', encoding.encoding)
149 153 # fake is only for relevant environment.
150 154 if _encoding.lower() in problematic_encodings.split():
151 155 for f in funcs.split():
152 156 wrapname(f, wrapper)
157 if os.name == 'nt':
158 for f in winfuncs.split():
159 wrapname(f, wrapper)
153 160 wrapname("mercurial.osutil.listdir", wrapperforlistdir)
154 161 # Check sys.args manually instead of using ui.debug() because
155 162 # command line options is not yet applied when
156 163 # extensions.loadall() is called.
157 164 if '--debug' in sys.argv:
158 165 ui.write("[win32mbcs] activated with encoding: %s\n"
159 166 % _encoding)
160 167
General Comments 0
You need to be logged in to leave comments. Login now