##// END OF EJS Templates
windows: adjust doc string and comments of posixfile()...
Adrian Buehlmann -
r24069:c6666395 default
parent child Browse files
Show More
@@ -1,371 +1,371 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 or any later version.
7 7
8 8 from i18n import _
9 9 import osutil, encoding
10 10 import errno, msvcrt, os, re, stat, sys, _winreg
11 11
12 12 import win32
13 13 executablepath = win32.executablepath
14 14 getuser = win32.getuser
15 15 hidewindow = win32.hidewindow
16 16 makedir = win32.makedir
17 17 nlinks = win32.nlinks
18 18 oslink = win32.oslink
19 19 samedevice = win32.samedevice
20 20 samefile = win32.samefile
21 21 setsignalhandler = win32.setsignalhandler
22 22 spawndetached = win32.spawndetached
23 23 split = os.path.split
24 24 termwidth = win32.termwidth
25 25 testpid = win32.testpid
26 26 unlink = win32.unlink
27 27
28 28 umask = 0022
29 29 _SEEK_END = 2 # os.SEEK_END was introduced in Python 2.5
30 30
31 # wrap osutil.posixfile to provide friendlier exceptions
32 31 def posixfile(name, mode='r', buffering=-1):
32 '''Open a file with even more POSIX-like semantics'''
33 33 try:
34 fp = osutil.posixfile(name, mode, buffering)
34 fp = osutil.posixfile(name, mode, buffering) # may raise WindowsError
35 35
36 36 # The position when opening in append mode is implementation defined, so
37 37 # make it consistent with other platforms, which position at EOF.
38 38 if 'a' in mode:
39 39 fp.seek(0, _SEEK_END)
40 40
41 41 return fp
42 42 except WindowsError, err:
43 # convert to a friendlier exception
43 44 raise IOError(err.errno, '%s: %s' % (name, err.strerror))
44 posixfile.__doc__ = osutil.posixfile.__doc__
45 45
46 46 class winstdout(object):
47 47 '''stdout on windows misbehaves if sent through a pipe'''
48 48
49 49 def __init__(self, fp):
50 50 self.fp = fp
51 51
52 52 def __getattr__(self, key):
53 53 return getattr(self.fp, key)
54 54
55 55 def close(self):
56 56 try:
57 57 self.fp.close()
58 58 except IOError:
59 59 pass
60 60
61 61 def write(self, s):
62 62 try:
63 63 # This is workaround for "Not enough space" error on
64 64 # writing large size of data to console.
65 65 limit = 16000
66 66 l = len(s)
67 67 start = 0
68 68 self.softspace = 0
69 69 while start < l:
70 70 end = start + limit
71 71 self.fp.write(s[start:end])
72 72 start = end
73 73 except IOError, inst:
74 74 if inst.errno != 0:
75 75 raise
76 76 self.close()
77 77 raise IOError(errno.EPIPE, 'Broken pipe')
78 78
79 79 def flush(self):
80 80 try:
81 81 return self.fp.flush()
82 82 except IOError, inst:
83 83 if inst.errno != errno.EINVAL:
84 84 raise
85 85 self.close()
86 86 raise IOError(errno.EPIPE, 'Broken pipe')
87 87
88 88 sys.__stdout__ = sys.stdout = winstdout(sys.stdout)
89 89
90 90 def _is_win_9x():
91 91 '''return true if run on windows 95, 98 or me.'''
92 92 try:
93 93 return sys.getwindowsversion()[3] == 1
94 94 except AttributeError:
95 95 return 'command' in os.environ.get('comspec', '')
96 96
97 97 def openhardlinks():
98 98 return not _is_win_9x()
99 99
100 100 def parsepatchoutput(output_line):
101 101 """parses the output produced by patch and returns the filename"""
102 102 pf = output_line[14:]
103 103 if pf[0] == '`':
104 104 pf = pf[1:-1] # Remove the quotes
105 105 return pf
106 106
107 107 def sshargs(sshcmd, host, user, port):
108 108 '''Build argument list for ssh or Plink'''
109 109 pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
110 110 args = user and ("%s@%s" % (user, host)) or host
111 111 return port and ("%s %s %s" % (args, pflag, port)) or args
112 112
113 113 def setflags(f, l, x):
114 114 pass
115 115
116 116 def copymode(src, dst, mode=None):
117 117 pass
118 118
119 119 def checkexec(path):
120 120 return False
121 121
122 122 def checklink(path):
123 123 return False
124 124
125 125 def setbinary(fd):
126 126 # When run without console, pipes may expose invalid
127 127 # fileno(), usually set to -1.
128 128 fno = getattr(fd, 'fileno', None)
129 129 if fno is not None and fno() >= 0:
130 130 msvcrt.setmode(fno(), os.O_BINARY)
131 131
132 132 def pconvert(path):
133 133 return path.replace(os.sep, '/')
134 134
135 135 def localpath(path):
136 136 return path.replace('/', '\\')
137 137
138 138 def normpath(path):
139 139 return pconvert(os.path.normpath(path))
140 140
141 141 def normcase(path):
142 142 return encoding.upper(path)
143 143
144 144 def samestat(s1, s2):
145 145 return False
146 146
147 147 # A sequence of backslashes is special iff it precedes a double quote:
148 148 # - if there's an even number of backslashes, the double quote is not
149 149 # quoted (i.e. it ends the quoted region)
150 150 # - if there's an odd number of backslashes, the double quote is quoted
151 151 # - in both cases, every pair of backslashes is unquoted into a single
152 152 # backslash
153 153 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
154 154 # So, to quote a string, we must surround it in double quotes, double
155 155 # the number of backslashes that precede double quotes and add another
156 156 # backslash before every double quote (being careful with the double
157 157 # quote we've appended to the end)
158 158 _quotere = None
159 159 _needsshellquote = None
160 160 def shellquote(s):
161 161 global _quotere
162 162 if _quotere is None:
163 163 _quotere = re.compile(r'(\\*)("|\\$)')
164 164 global _needsshellquote
165 165 if _needsshellquote is None:
166 166 # ":" and "\\" are also treated as "safe character", because
167 167 # they are used as a part of path name (and the latter doesn't
168 168 # work as "escape character", like one on posix) on Windows
169 169 _needsshellquote = re.compile(r'[^a-zA-Z0-9._:/\\-]').search
170 170 if not _needsshellquote(s) and not _quotere.search(s):
171 171 # "s" shouldn't have to be quoted
172 172 return s
173 173 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
174 174
175 175 def quotecommand(cmd):
176 176 """Build a command string suitable for os.popen* calls."""
177 177 if sys.version_info < (2, 7, 1):
178 178 # Python versions since 2.7.1 do this extra quoting themselves
179 179 return '"' + cmd + '"'
180 180 return cmd
181 181
182 182 def popen(command, mode='r'):
183 183 # Work around "popen spawned process may not write to stdout
184 184 # under windows"
185 185 # http://bugs.python.org/issue1366
186 186 command += " 2> %s" % os.devnull
187 187 return os.popen(quotecommand(command), mode)
188 188
189 189 def explainexit(code):
190 190 return _("exited with status %d") % code, code
191 191
192 192 # if you change this stub into a real check, please try to implement the
193 193 # username and groupname functions above, too.
194 194 def isowner(st):
195 195 return True
196 196
197 197 def findexe(command):
198 198 '''Find executable for command searching like cmd.exe does.
199 199 If command is a basename then PATH is searched for command.
200 200 PATH isn't searched if command is an absolute or relative path.
201 201 An extension from PATHEXT is found and added if not present.
202 202 If command isn't found None is returned.'''
203 203 pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
204 204 pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
205 205 if os.path.splitext(command)[1].lower() in pathexts:
206 206 pathexts = ['']
207 207
208 208 def findexisting(pathcommand):
209 209 'Will append extension (if needed) and return existing file'
210 210 for ext in pathexts:
211 211 executable = pathcommand + ext
212 212 if os.path.exists(executable):
213 213 return executable
214 214 return None
215 215
216 216 if os.sep in command:
217 217 return findexisting(command)
218 218
219 219 for path in os.environ.get('PATH', '').split(os.pathsep):
220 220 executable = findexisting(os.path.join(path, command))
221 221 if executable is not None:
222 222 return executable
223 223 return findexisting(os.path.expanduser(os.path.expandvars(command)))
224 224
225 225 _wantedkinds = set([stat.S_IFREG, stat.S_IFLNK])
226 226
227 227 def statfiles(files):
228 228 '''Stat each file in files. Yield each stat, or None if a file
229 229 does not exist or has a type we don't care about.
230 230
231 231 Cluster and cache stat per directory to minimize number of OS stat calls.'''
232 232 dircache = {} # dirname -> filename -> status | None if file does not exist
233 233 getkind = stat.S_IFMT
234 234 for nf in files:
235 235 nf = normcase(nf)
236 236 dir, base = os.path.split(nf)
237 237 if not dir:
238 238 dir = '.'
239 239 cache = dircache.get(dir, None)
240 240 if cache is None:
241 241 try:
242 242 dmap = dict([(normcase(n), s)
243 243 for n, k, s in osutil.listdir(dir, True)
244 244 if getkind(s.st_mode) in _wantedkinds])
245 245 except OSError, err:
246 246 # handle directory not found in Python version prior to 2.5
247 247 # Python <= 2.4 returns native Windows code 3 in errno
248 248 # Python >= 2.5 returns ENOENT and adds winerror field
249 249 # EINVAL is raised if dir is not a directory.
250 250 if err.errno not in (3, errno.ENOENT, errno.EINVAL,
251 251 errno.ENOTDIR):
252 252 raise
253 253 dmap = {}
254 254 cache = dircache.setdefault(dir, dmap)
255 255 yield cache.get(base, None)
256 256
257 257 def username(uid=None):
258 258 """Return the name of the user with the given uid.
259 259
260 260 If uid is None, return the name of the current user."""
261 261 return None
262 262
263 263 def groupname(gid=None):
264 264 """Return the name of the group with the given gid.
265 265
266 266 If gid is None, return the name of the current group."""
267 267 return None
268 268
269 269 def _removedirs(name):
270 270 """special version of os.removedirs that does not remove symlinked
271 271 directories or junction points if they actually contain files"""
272 272 if osutil.listdir(name):
273 273 return
274 274 os.rmdir(name)
275 275 head, tail = os.path.split(name)
276 276 if not tail:
277 277 head, tail = os.path.split(head)
278 278 while head and tail:
279 279 try:
280 280 if osutil.listdir(head):
281 281 return
282 282 os.rmdir(head)
283 283 except (ValueError, OSError):
284 284 break
285 285 head, tail = os.path.split(head)
286 286
287 287 def unlinkpath(f, ignoremissing=False):
288 288 """unlink and remove the directory if it is empty"""
289 289 try:
290 290 unlink(f)
291 291 except OSError, e:
292 292 if not (ignoremissing and e.errno == errno.ENOENT):
293 293 raise
294 294 # try removing directories that might now be empty
295 295 try:
296 296 _removedirs(os.path.dirname(f))
297 297 except OSError:
298 298 pass
299 299
300 300 def rename(src, dst):
301 301 '''atomically rename file src to dst, replacing dst if it exists'''
302 302 try:
303 303 os.rename(src, dst)
304 304 except OSError, e:
305 305 if e.errno != errno.EEXIST:
306 306 raise
307 307 unlink(dst)
308 308 os.rename(src, dst)
309 309
310 310 def gethgcmd():
311 311 return [sys.executable] + sys.argv[:1]
312 312
313 313 def groupmembers(name):
314 314 # Don't support groups on Windows for now
315 315 raise KeyError
316 316
317 317 def isexec(f):
318 318 return False
319 319
320 320 class cachestat(object):
321 321 def __init__(self, path):
322 322 pass
323 323
324 324 def cacheable(self):
325 325 return False
326 326
327 327 def lookupreg(key, valname=None, scope=None):
328 328 ''' Look up a key/value name in the Windows registry.
329 329
330 330 valname: value name. If unspecified, the default value for the key
331 331 is used.
332 332 scope: optionally specify scope for registry lookup, this can be
333 333 a sequence of scopes to look up in order. Default (CURRENT_USER,
334 334 LOCAL_MACHINE).
335 335 '''
336 336 if scope is None:
337 337 scope = (_winreg.HKEY_CURRENT_USER, _winreg.HKEY_LOCAL_MACHINE)
338 338 elif not isinstance(scope, (list, tuple)):
339 339 scope = (scope,)
340 340 for s in scope:
341 341 try:
342 342 val = _winreg.QueryValueEx(_winreg.OpenKey(s, key), valname)[0]
343 343 # never let a Unicode string escape into the wild
344 344 return encoding.tolocal(val.encode('UTF-8'))
345 345 except EnvironmentError:
346 346 pass
347 347
348 348 expandglobs = True
349 349
350 350 def statislink(st):
351 351 '''check whether a stat result is a symlink'''
352 352 return False
353 353
354 354 def statisexec(st):
355 355 '''check whether a stat result is an executable file'''
356 356 return False
357 357
358 358 def readpipe(pipe):
359 359 """Read all available data from a pipe."""
360 360 chunks = []
361 361 while True:
362 362 size = os.fstat(pipe.fileno()).st_size
363 363 if not size:
364 364 break
365 365
366 366 s = pipe.read(size)
367 367 if not s:
368 368 break
369 369 chunks.append(s)
370 370
371 371 return ''.join(chunks)
General Comments 0
You need to be logged in to leave comments. Login now