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