##// END OF EJS Templates
Use os.path.split() for MBCS with win32mbcs extension.
Shun-ichi GOTO -
r9099:3d456bf3 default
parent child Browse files
Show More
@@ -1,284 +1,282
1 # windows.py - Windows utility function implementations for Mercurial
1 # windows.py - Windows utility function implementations for Mercurial
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 import osutil, error
9 import osutil, error
10 import errno, msvcrt, os, re, sys
10 import errno, msvcrt, os, re, sys
11
11
12 nulldev = 'NUL:'
12 nulldev = 'NUL:'
13 umask = 002
13 umask = 002
14
14
15 # wrap osutil.posixfile to provide friendlier exceptions
15 # wrap osutil.posixfile to provide friendlier exceptions
16 def posixfile(name, mode='r', buffering=-1):
16 def posixfile(name, mode='r', buffering=-1):
17 try:
17 try:
18 return osutil.posixfile(name, mode, buffering)
18 return osutil.posixfile(name, mode, buffering)
19 except WindowsError, err:
19 except WindowsError, err:
20 raise IOError(err.errno, err.strerror)
20 raise IOError(err.errno, err.strerror)
21 posixfile.__doc__ = osutil.posixfile.__doc__
21 posixfile.__doc__ = osutil.posixfile.__doc__
22
22
23 class winstdout(object):
23 class winstdout(object):
24 '''stdout on windows misbehaves if sent through a pipe'''
24 '''stdout on windows misbehaves if sent through a pipe'''
25
25
26 def __init__(self, fp):
26 def __init__(self, fp):
27 self.fp = fp
27 self.fp = fp
28
28
29 def __getattr__(self, key):
29 def __getattr__(self, key):
30 return getattr(self.fp, key)
30 return getattr(self.fp, key)
31
31
32 def close(self):
32 def close(self):
33 try:
33 try:
34 self.fp.close()
34 self.fp.close()
35 except: pass
35 except: pass
36
36
37 def write(self, s):
37 def write(self, s):
38 try:
38 try:
39 # This is workaround for "Not enough space" error on
39 # This is workaround for "Not enough space" error on
40 # writing large size of data to console.
40 # writing large size of data to console.
41 limit = 16000
41 limit = 16000
42 l = len(s)
42 l = len(s)
43 start = 0
43 start = 0
44 while start < l:
44 while start < l:
45 end = start + limit
45 end = start + limit
46 self.fp.write(s[start:end])
46 self.fp.write(s[start:end])
47 start = end
47 start = end
48 except IOError, inst:
48 except IOError, inst:
49 if inst.errno != 0: raise
49 if inst.errno != 0: raise
50 self.close()
50 self.close()
51 raise IOError(errno.EPIPE, 'Broken pipe')
51 raise IOError(errno.EPIPE, 'Broken pipe')
52
52
53 def flush(self):
53 def flush(self):
54 try:
54 try:
55 return self.fp.flush()
55 return self.fp.flush()
56 except IOError, inst:
56 except IOError, inst:
57 if inst.errno != errno.EINVAL: raise
57 if inst.errno != errno.EINVAL: raise
58 self.close()
58 self.close()
59 raise IOError(errno.EPIPE, 'Broken pipe')
59 raise IOError(errno.EPIPE, 'Broken pipe')
60
60
61 sys.stdout = winstdout(sys.stdout)
61 sys.stdout = winstdout(sys.stdout)
62
62
63 def _is_win_9x():
63 def _is_win_9x():
64 '''return true if run on windows 95, 98 or me.'''
64 '''return true if run on windows 95, 98 or me.'''
65 try:
65 try:
66 return sys.getwindowsversion()[3] == 1
66 return sys.getwindowsversion()[3] == 1
67 except AttributeError:
67 except AttributeError:
68 return 'command' in os.environ.get('comspec', '')
68 return 'command' in os.environ.get('comspec', '')
69
69
70 def openhardlinks():
70 def openhardlinks():
71 return not _is_win_9x() and "win32api" in globals()
71 return not _is_win_9x() and "win32api" in globals()
72
72
73 def system_rcpath():
73 def system_rcpath():
74 try:
74 try:
75 return system_rcpath_win32()
75 return system_rcpath_win32()
76 except:
76 except:
77 return [r'c:\mercurial\mercurial.ini']
77 return [r'c:\mercurial\mercurial.ini']
78
78
79 def user_rcpath():
79 def user_rcpath():
80 '''return os-specific hgrc search path to the user dir'''
80 '''return os-specific hgrc search path to the user dir'''
81 try:
81 try:
82 path = user_rcpath_win32()
82 path = user_rcpath_win32()
83 except:
83 except:
84 home = os.path.expanduser('~')
84 home = os.path.expanduser('~')
85 path = [os.path.join(home, 'mercurial.ini'),
85 path = [os.path.join(home, 'mercurial.ini'),
86 os.path.join(home, '.hgrc')]
86 os.path.join(home, '.hgrc')]
87 userprofile = os.environ.get('USERPROFILE')
87 userprofile = os.environ.get('USERPROFILE')
88 if userprofile:
88 if userprofile:
89 path.append(os.path.join(userprofile, 'mercurial.ini'))
89 path.append(os.path.join(userprofile, 'mercurial.ini'))
90 path.append(os.path.join(userprofile, '.hgrc'))
90 path.append(os.path.join(userprofile, '.hgrc'))
91 return path
91 return path
92
92
93 def parse_patch_output(output_line):
93 def parse_patch_output(output_line):
94 """parses the output produced by patch and returns the filename"""
94 """parses the output produced by patch and returns the filename"""
95 pf = output_line[14:]
95 pf = output_line[14:]
96 if pf[0] == '`':
96 if pf[0] == '`':
97 pf = pf[1:-1] # Remove the quotes
97 pf = pf[1:-1] # Remove the quotes
98 return pf
98 return pf
99
99
100 def sshargs(sshcmd, host, user, port):
100 def sshargs(sshcmd, host, user, port):
101 '''Build argument list for ssh or Plink'''
101 '''Build argument list for ssh or Plink'''
102 pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
102 pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
103 args = user and ("%s@%s" % (user, host)) or host
103 args = user and ("%s@%s" % (user, host)) or host
104 return port and ("%s %s %s" % (args, pflag, port)) or args
104 return port and ("%s %s %s" % (args, pflag, port)) or args
105
105
106 def testpid(pid):
106 def testpid(pid):
107 '''return False if pid dead, True if running or not known'''
107 '''return False if pid dead, True if running or not known'''
108 return True
108 return True
109
109
110 def set_flags(f, l, x):
110 def set_flags(f, l, x):
111 pass
111 pass
112
112
113 def set_binary(fd):
113 def set_binary(fd):
114 # When run without console, pipes may expose invalid
114 # When run without console, pipes may expose invalid
115 # fileno(), usually set to -1.
115 # fileno(), usually set to -1.
116 if hasattr(fd, 'fileno') and fd.fileno() >= 0:
116 if hasattr(fd, 'fileno') and fd.fileno() >= 0:
117 msvcrt.setmode(fd.fileno(), os.O_BINARY)
117 msvcrt.setmode(fd.fileno(), os.O_BINARY)
118
118
119 def pconvert(path):
119 def pconvert(path):
120 return '/'.join(path.split(os.sep))
120 return '/'.join(path.split(os.sep))
121
121
122 def localpath(path):
122 def localpath(path):
123 return path.replace('/', '\\')
123 return path.replace('/', '\\')
124
124
125 def normpath(path):
125 def normpath(path):
126 return pconvert(os.path.normpath(path))
126 return pconvert(os.path.normpath(path))
127
127
128 def samestat(s1, s2):
128 def samestat(s1, s2):
129 return False
129 return False
130
130
131 # A sequence of backslashes is special iff it precedes a double quote:
131 # A sequence of backslashes is special iff it precedes a double quote:
132 # - if there's an even number of backslashes, the double quote is not
132 # - if there's an even number of backslashes, the double quote is not
133 # quoted (i.e. it ends the quoted region)
133 # quoted (i.e. it ends the quoted region)
134 # - if there's an odd number of backslashes, the double quote is quoted
134 # - if there's an odd number of backslashes, the double quote is quoted
135 # - in both cases, every pair of backslashes is unquoted into a single
135 # - in both cases, every pair of backslashes is unquoted into a single
136 # backslash
136 # backslash
137 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
137 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
138 # So, to quote a string, we must surround it in double quotes, double
138 # So, to quote a string, we must surround it in double quotes, double
139 # the number of backslashes that preceed double quotes and add another
139 # the number of backslashes that preceed double quotes and add another
140 # backslash before every double quote (being careful with the double
140 # backslash before every double quote (being careful with the double
141 # quote we've appended to the end)
141 # quote we've appended to the end)
142 _quotere = None
142 _quotere = None
143 def shellquote(s):
143 def shellquote(s):
144 global _quotere
144 global _quotere
145 if _quotere is None:
145 if _quotere is None:
146 _quotere = re.compile(r'(\\*)("|\\$)')
146 _quotere = re.compile(r'(\\*)("|\\$)')
147 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
147 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
148
148
149 def quotecommand(cmd):
149 def quotecommand(cmd):
150 """Build a command string suitable for os.popen* calls."""
150 """Build a command string suitable for os.popen* calls."""
151 # The extra quotes are needed because popen* runs the command
151 # The extra quotes are needed because popen* runs the command
152 # through the current COMSPEC. cmd.exe suppress enclosing quotes.
152 # through the current COMSPEC. cmd.exe suppress enclosing quotes.
153 return '"' + cmd + '"'
153 return '"' + cmd + '"'
154
154
155 def popen(command, mode='r'):
155 def popen(command, mode='r'):
156 # Work around "popen spawned process may not write to stdout
156 # Work around "popen spawned process may not write to stdout
157 # under windows"
157 # under windows"
158 # http://bugs.python.org/issue1366
158 # http://bugs.python.org/issue1366
159 command += " 2> %s" % nulldev
159 command += " 2> %s" % nulldev
160 return os.popen(quotecommand(command), mode)
160 return os.popen(quotecommand(command), mode)
161
161
162 def explain_exit(code):
162 def explain_exit(code):
163 return _("exited with status %d") % code, code
163 return _("exited with status %d") % code, code
164
164
165 # if you change this stub into a real check, please try to implement the
165 # if you change this stub into a real check, please try to implement the
166 # username and groupname functions above, too.
166 # username and groupname functions above, too.
167 def isowner(st):
167 def isowner(st):
168 return True
168 return True
169
169
170 def find_exe(command):
170 def find_exe(command):
171 '''Find executable for command searching like cmd.exe does.
171 '''Find executable for command searching like cmd.exe does.
172 If command is a basename then PATH is searched for command.
172 If command is a basename then PATH is searched for command.
173 PATH isn't searched if command is an absolute or relative path.
173 PATH isn't searched if command is an absolute or relative path.
174 An extension from PATHEXT is found and added if not present.
174 An extension from PATHEXT is found and added if not present.
175 If command isn't found None is returned.'''
175 If command isn't found None is returned.'''
176 pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
176 pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
177 pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
177 pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
178 if os.path.splitext(command)[1].lower() in pathexts:
178 if os.path.splitext(command)[1].lower() in pathexts:
179 pathexts = ['']
179 pathexts = ['']
180
180
181 def findexisting(pathcommand):
181 def findexisting(pathcommand):
182 'Will append extension (if needed) and return existing file'
182 'Will append extension (if needed) and return existing file'
183 for ext in pathexts:
183 for ext in pathexts:
184 executable = pathcommand + ext
184 executable = pathcommand + ext
185 if os.path.exists(executable):
185 if os.path.exists(executable):
186 return executable
186 return executable
187 return None
187 return None
188
188
189 if os.sep in command:
189 if os.sep in command:
190 return findexisting(command)
190 return findexisting(command)
191
191
192 for path in os.environ.get('PATH', '').split(os.pathsep):
192 for path in os.environ.get('PATH', '').split(os.pathsep):
193 executable = findexisting(os.path.join(path, command))
193 executable = findexisting(os.path.join(path, command))
194 if executable is not None:
194 if executable is not None:
195 return executable
195 return executable
196 return None
196 return None
197
197
198 def set_signal_handler():
198 def set_signal_handler():
199 try:
199 try:
200 set_signal_handler_win32()
200 set_signal_handler_win32()
201 except NameError:
201 except NameError:
202 pass
202 pass
203
203
204 def statfiles(files):
204 def statfiles(files):
205 '''Stat each file in files and yield stat or None if file does not exist.
205 '''Stat each file in files and yield stat or None if file does not exist.
206 Cluster and cache stat per directory to minimize number of OS stat calls.'''
206 Cluster and cache stat per directory to minimize number of OS stat calls.'''
207 ncase = os.path.normcase
207 ncase = os.path.normcase
208 sep = os.sep
208 sep = os.sep
209 dircache = {} # dirname -> filename -> status | None if file does not exist
209 dircache = {} # dirname -> filename -> status | None if file does not exist
210 for nf in files:
210 for nf in files:
211 nf = ncase(nf)
211 nf = ncase(nf)
212 pos = nf.rfind(sep)
212 dir, base = os.path.split(nf)
213 if pos == -1:
213 if not dir:
214 dir, base = '.', nf
214 dir = '.'
215 else:
216 dir, base = nf[:pos+1], nf[pos+1:]
217 cache = dircache.get(dir, None)
215 cache = dircache.get(dir, None)
218 if cache is None:
216 if cache is None:
219 try:
217 try:
220 dmap = dict([(ncase(n), s)
218 dmap = dict([(ncase(n), s)
221 for n, k, s in osutil.listdir(dir, True)])
219 for n, k, s in osutil.listdir(dir, True)])
222 except OSError, err:
220 except OSError, err:
223 # handle directory not found in Python version prior to 2.5
221 # handle directory not found in Python version prior to 2.5
224 # Python <= 2.4 returns native Windows code 3 in errno
222 # Python <= 2.4 returns native Windows code 3 in errno
225 # Python >= 2.5 returns ENOENT and adds winerror field
223 # Python >= 2.5 returns ENOENT and adds winerror field
226 # EINVAL is raised if dir is not a directory.
224 # EINVAL is raised if dir is not a directory.
227 if err.errno not in (3, errno.ENOENT, errno.EINVAL,
225 if err.errno not in (3, errno.ENOENT, errno.EINVAL,
228 errno.ENOTDIR):
226 errno.ENOTDIR):
229 raise
227 raise
230 dmap = {}
228 dmap = {}
231 cache = dircache.setdefault(dir, dmap)
229 cache = dircache.setdefault(dir, dmap)
232 yield cache.get(base, None)
230 yield cache.get(base, None)
233
231
234 def getuser():
232 def getuser():
235 '''return name of current user'''
233 '''return name of current user'''
236 raise error.Abort(_('user name not available - set USERNAME '
234 raise error.Abort(_('user name not available - set USERNAME '
237 'environment variable'))
235 'environment variable'))
238
236
239 def username(uid=None):
237 def username(uid=None):
240 """Return the name of the user with the given uid.
238 """Return the name of the user with the given uid.
241
239
242 If uid is None, return the name of the current user."""
240 If uid is None, return the name of the current user."""
243 return None
241 return None
244
242
245 def groupname(gid=None):
243 def groupname(gid=None):
246 """Return the name of the group with the given gid.
244 """Return the name of the group with the given gid.
247
245
248 If gid is None, return the name of the current group."""
246 If gid is None, return the name of the current group."""
249 return None
247 return None
250
248
251 def _removedirs(name):
249 def _removedirs(name):
252 """special version of os.removedirs that does not remove symlinked
250 """special version of os.removedirs that does not remove symlinked
253 directories or junction points if they actually contain files"""
251 directories or junction points if they actually contain files"""
254 if osutil.listdir(name):
252 if osutil.listdir(name):
255 return
253 return
256 os.rmdir(name)
254 os.rmdir(name)
257 head, tail = os.path.split(name)
255 head, tail = os.path.split(name)
258 if not tail:
256 if not tail:
259 head, tail = os.path.split(head)
257 head, tail = os.path.split(head)
260 while head and tail:
258 while head and tail:
261 try:
259 try:
262 if osutil.listdir(name):
260 if osutil.listdir(name):
263 return
261 return
264 os.rmdir(head)
262 os.rmdir(head)
265 except:
263 except:
266 break
264 break
267 head, tail = os.path.split(head)
265 head, tail = os.path.split(head)
268
266
269 def unlink(f):
267 def unlink(f):
270 """unlink and remove the directory if it is empty"""
268 """unlink and remove the directory if it is empty"""
271 os.unlink(f)
269 os.unlink(f)
272 # try removing directories that might now be empty
270 # try removing directories that might now be empty
273 try:
271 try:
274 _removedirs(os.path.dirname(f))
272 _removedirs(os.path.dirname(f))
275 except OSError:
273 except OSError:
276 pass
274 pass
277
275
278 try:
276 try:
279 # override functions with win32 versions if possible
277 # override functions with win32 versions if possible
280 from win32 import *
278 from win32 import *
281 except ImportError:
279 except ImportError:
282 pass
280 pass
283
281
284 expandglobs = True
282 expandglobs = True
General Comments 0
You need to be logged in to leave comments. Login now