##// END OF EJS Templates
win32: move lookupreg() to windows.py...
Adrian Buehlmann -
r16807:80142f38 default
parent child Browse files
Show More
@@ -1,418 +1,396
1 1 # win32.py - utility functions that use win32 API
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 import encoding
9 import ctypes, errno, os, subprocess, random, _winreg
8 import ctypes, errno, os, subprocess, random
10 9
11 10 _kernel32 = ctypes.windll.kernel32
12 11 _advapi32 = ctypes.windll.advapi32
13 12 _user32 = ctypes.windll.user32
14 13
15 14 _BOOL = ctypes.c_long
16 15 _WORD = ctypes.c_ushort
17 16 _DWORD = ctypes.c_ulong
18 17 _UINT = ctypes.c_uint
19 18 _LONG = ctypes.c_long
20 19 _LPCSTR = _LPSTR = ctypes.c_char_p
21 20 _HANDLE = ctypes.c_void_p
22 21 _HWND = _HANDLE
23 22
24 23 _INVALID_HANDLE_VALUE = _HANDLE(-1).value
25 24
26 25 # GetLastError
27 26 _ERROR_SUCCESS = 0
28 27 _ERROR_INVALID_PARAMETER = 87
29 28 _ERROR_INSUFFICIENT_BUFFER = 122
30 29
31 30 # WPARAM is defined as UINT_PTR (unsigned type)
32 31 # LPARAM is defined as LONG_PTR (signed type)
33 32 if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
34 33 _WPARAM = ctypes.c_ulong
35 34 _LPARAM = ctypes.c_long
36 35 elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
37 36 _WPARAM = ctypes.c_ulonglong
38 37 _LPARAM = ctypes.c_longlong
39 38
40 39 class _FILETIME(ctypes.Structure):
41 40 _fields_ = [('dwLowDateTime', _DWORD),
42 41 ('dwHighDateTime', _DWORD)]
43 42
44 43 class _BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
45 44 _fields_ = [('dwFileAttributes', _DWORD),
46 45 ('ftCreationTime', _FILETIME),
47 46 ('ftLastAccessTime', _FILETIME),
48 47 ('ftLastWriteTime', _FILETIME),
49 48 ('dwVolumeSerialNumber', _DWORD),
50 49 ('nFileSizeHigh', _DWORD),
51 50 ('nFileSizeLow', _DWORD),
52 51 ('nNumberOfLinks', _DWORD),
53 52 ('nFileIndexHigh', _DWORD),
54 53 ('nFileIndexLow', _DWORD)]
55 54
56 55 # CreateFile
57 56 _FILE_SHARE_READ = 0x00000001
58 57 _FILE_SHARE_WRITE = 0x00000002
59 58 _FILE_SHARE_DELETE = 0x00000004
60 59
61 60 _OPEN_EXISTING = 3
62 61
63 62 # SetFileAttributes
64 63 _FILE_ATTRIBUTE_NORMAL = 0x80
65 64 _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
66 65
67 66 # Process Security and Access Rights
68 67 _PROCESS_QUERY_INFORMATION = 0x0400
69 68
70 69 # GetExitCodeProcess
71 70 _STILL_ACTIVE = 259
72 71
73 72 class _STARTUPINFO(ctypes.Structure):
74 73 _fields_ = [('cb', _DWORD),
75 74 ('lpReserved', _LPSTR),
76 75 ('lpDesktop', _LPSTR),
77 76 ('lpTitle', _LPSTR),
78 77 ('dwX', _DWORD),
79 78 ('dwY', _DWORD),
80 79 ('dwXSize', _DWORD),
81 80 ('dwYSize', _DWORD),
82 81 ('dwXCountChars', _DWORD),
83 82 ('dwYCountChars', _DWORD),
84 83 ('dwFillAttribute', _DWORD),
85 84 ('dwFlags', _DWORD),
86 85 ('wShowWindow', _WORD),
87 86 ('cbReserved2', _WORD),
88 87 ('lpReserved2', ctypes.c_char_p),
89 88 ('hStdInput', _HANDLE),
90 89 ('hStdOutput', _HANDLE),
91 90 ('hStdError', _HANDLE)]
92 91
93 92 class _PROCESS_INFORMATION(ctypes.Structure):
94 93 _fields_ = [('hProcess', _HANDLE),
95 94 ('hThread', _HANDLE),
96 95 ('dwProcessId', _DWORD),
97 96 ('dwThreadId', _DWORD)]
98 97
99 98 _DETACHED_PROCESS = 0x00000008
100 99 _STARTF_USESHOWWINDOW = 0x00000001
101 100 _SW_HIDE = 0
102 101
103 102 class _COORD(ctypes.Structure):
104 103 _fields_ = [('X', ctypes.c_short),
105 104 ('Y', ctypes.c_short)]
106 105
107 106 class _SMALL_RECT(ctypes.Structure):
108 107 _fields_ = [('Left', ctypes.c_short),
109 108 ('Top', ctypes.c_short),
110 109 ('Right', ctypes.c_short),
111 110 ('Bottom', ctypes.c_short)]
112 111
113 112 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
114 113 _fields_ = [('dwSize', _COORD),
115 114 ('dwCursorPosition', _COORD),
116 115 ('wAttributes', _WORD),
117 116 ('srWindow', _SMALL_RECT),
118 117 ('dwMaximumWindowSize', _COORD)]
119 118
120 119 _STD_ERROR_HANDLE = _DWORD(-12).value
121 120
122 121 # types of parameters of C functions used (required by pypy)
123 122
124 123 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
125 124 _DWORD, _DWORD, _HANDLE]
126 125 _kernel32.CreateFileA.restype = _HANDLE
127 126
128 127 _kernel32.GetFileInformationByHandle.argtypes = [_HANDLE, ctypes.c_void_p]
129 128 _kernel32.GetFileInformationByHandle.restype = _BOOL
130 129
131 130 _kernel32.CloseHandle.argtypes = [_HANDLE]
132 131 _kernel32.CloseHandle.restype = _BOOL
133 132
134 133 try:
135 134 _kernel32.CreateHardLinkA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p]
136 135 _kernel32.CreateHardLinkA.restype = _BOOL
137 136 except AttributeError:
138 137 pass
139 138
140 139 _kernel32.SetFileAttributesA.argtypes = [_LPCSTR, _DWORD]
141 140 _kernel32.SetFileAttributesA.restype = _BOOL
142 141
143 142 _kernel32.OpenProcess.argtypes = [_DWORD, _BOOL, _DWORD]
144 143 _kernel32.OpenProcess.restype = _HANDLE
145 144
146 145 _kernel32.GetExitCodeProcess.argtypes = [_HANDLE, ctypes.c_void_p]
147 146 _kernel32.GetExitCodeProcess.restype = _BOOL
148 147
149 148 _kernel32.GetLastError.argtypes = []
150 149 _kernel32.GetLastError.restype = _DWORD
151 150
152 151 _kernel32.GetModuleFileNameA.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD]
153 152 _kernel32.GetModuleFileNameA.restype = _DWORD
154 153
155 154 _kernel32.CreateProcessA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p,
156 155 ctypes.c_void_p, _BOOL, _DWORD, ctypes.c_void_p, _LPCSTR, ctypes.c_void_p,
157 156 ctypes.c_void_p]
158 157 _kernel32.CreateProcessA.restype = _BOOL
159 158
160 159 _kernel32.ExitProcess.argtypes = [_UINT]
161 160 _kernel32.ExitProcess.restype = None
162 161
163 162 _kernel32.GetCurrentProcessId.argtypes = []
164 163 _kernel32.GetCurrentProcessId.restype = _DWORD
165 164
166 165 _SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
167 166 _kernel32.SetConsoleCtrlHandler.argtypes = [_SIGNAL_HANDLER, _BOOL]
168 167 _kernel32.SetConsoleCtrlHandler.restype = _BOOL
169 168
170 169 _kernel32.GetStdHandle.argtypes = [_DWORD]
171 170 _kernel32.GetStdHandle.restype = _HANDLE
172 171
173 172 _kernel32.GetConsoleScreenBufferInfo.argtypes = [_HANDLE, ctypes.c_void_p]
174 173 _kernel32.GetConsoleScreenBufferInfo.restype = _BOOL
175 174
176 175 _advapi32.GetUserNameA.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
177 176 _advapi32.GetUserNameA.restype = _BOOL
178 177
179 178 _user32.GetWindowThreadProcessId.argtypes = [_HANDLE, ctypes.c_void_p]
180 179 _user32.GetWindowThreadProcessId.restype = _DWORD
181 180
182 181 _user32.ShowWindow.argtypes = [_HANDLE, ctypes.c_int]
183 182 _user32.ShowWindow.restype = _BOOL
184 183
185 184 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
186 185 _user32.EnumWindows.argtypes = [_WNDENUMPROC, _LPARAM]
187 186 _user32.EnumWindows.restype = _BOOL
188 187
189 188 def _raiseoserror(name):
190 189 err = ctypes.WinError()
191 190 raise OSError(err.errno, '%s: %s' % (name, err.strerror))
192 191
193 192 def _getfileinfo(name):
194 193 fh = _kernel32.CreateFileA(name, 0,
195 194 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
196 195 None, _OPEN_EXISTING, 0, None)
197 196 if fh == _INVALID_HANDLE_VALUE:
198 197 _raiseoserror(name)
199 198 try:
200 199 fi = _BY_HANDLE_FILE_INFORMATION()
201 200 if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
202 201 _raiseoserror(name)
203 202 return fi
204 203 finally:
205 204 _kernel32.CloseHandle(fh)
206 205
207 206 def oslink(src, dst):
208 207 try:
209 208 if not _kernel32.CreateHardLinkA(dst, src, None):
210 209 _raiseoserror(src)
211 210 except AttributeError: # Wine doesn't support this function
212 211 _raiseoserror(src)
213 212
214 213 def nlinks(name):
215 214 '''return number of hardlinks for the given file'''
216 215 return _getfileinfo(name).nNumberOfLinks
217 216
218 217 def samefile(fpath1, fpath2):
219 218 '''Returns whether fpath1 and fpath2 refer to the same file. This is only
220 219 guaranteed to work for files, not directories.'''
221 220 res1 = _getfileinfo(fpath1)
222 221 res2 = _getfileinfo(fpath2)
223 222 return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
224 223 and res1.nFileIndexHigh == res2.nFileIndexHigh
225 224 and res1.nFileIndexLow == res2.nFileIndexLow)
226 225
227 226 def samedevice(fpath1, fpath2):
228 227 '''Returns whether fpath1 and fpath2 are on the same device. This is only
229 228 guaranteed to work for files, not directories.'''
230 229 res1 = _getfileinfo(fpath1)
231 230 res2 = _getfileinfo(fpath2)
232 231 return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
233 232
234 233 def testpid(pid):
235 234 '''return True if pid is still running or unable to
236 235 determine, False otherwise'''
237 236 h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
238 237 if h:
239 238 try:
240 239 status = _DWORD()
241 240 if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
242 241 return status.value == _STILL_ACTIVE
243 242 finally:
244 243 _kernel32.CloseHandle(h)
245 244 return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
246 245
247 def lookupreg(key, valname=None, scope=None):
248 ''' Look up a key/value name in the Windows registry.
249
250 valname: value name. If unspecified, the default value for the key
251 is used.
252 scope: optionally specify scope for registry lookup, this can be
253 a sequence of scopes to look up in order. Default (CURRENT_USER,
254 LOCAL_MACHINE).
255 '''
256 if scope is None:
257 scope = (_winreg.HKEY_CURRENT_USER, _winreg.HKEY_LOCAL_MACHINE)
258 elif not isinstance(scope, (list, tuple)):
259 scope = (scope,)
260 for s in scope:
261 try:
262 val = _winreg.QueryValueEx(_winreg.OpenKey(s, key), valname)[0]
263 # never let a Unicode string escape into the wild
264 return encoding.tolocal(val.encode('UTF-8'))
265 except EnvironmentError:
266 pass
267
268 246 def executablepath():
269 247 '''return full path of hg.exe'''
270 248 size = 600
271 249 buf = ctypes.create_string_buffer(size + 1)
272 250 len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
273 251 if len == 0:
274 252 raise ctypes.WinError
275 253 elif len == size:
276 254 raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
277 255 return buf.value
278 256
279 257 def getuser():
280 258 '''return name of current user'''
281 259 size = _DWORD(300)
282 260 buf = ctypes.create_string_buffer(size.value + 1)
283 261 if not _advapi32.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
284 262 raise ctypes.WinError
285 263 return buf.value
286 264
287 265 _signalhandler = []
288 266
289 267 def setsignalhandler():
290 268 '''Register a termination handler for console events including
291 269 CTRL+C. python signal handlers do not work well with socket
292 270 operations.
293 271 '''
294 272 def handler(event):
295 273 _kernel32.ExitProcess(1)
296 274
297 275 if _signalhandler:
298 276 return # already registered
299 277 h = _SIGNAL_HANDLER(handler)
300 278 _signalhandler.append(h) # needed to prevent garbage collection
301 279 if not _kernel32.SetConsoleCtrlHandler(h, True):
302 280 raise ctypes.WinError
303 281
304 282 def hidewindow():
305 283
306 284 def callback(hwnd, pid):
307 285 wpid = _DWORD()
308 286 _user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
309 287 if pid == wpid.value:
310 288 _user32.ShowWindow(hwnd, _SW_HIDE)
311 289 return False # stop enumerating windows
312 290 return True
313 291
314 292 pid = _kernel32.GetCurrentProcessId()
315 293 _user32.EnumWindows(_WNDENUMPROC(callback), pid)
316 294
317 295 def termwidth():
318 296 # cmd.exe does not handle CR like a unix console, the CR is
319 297 # counted in the line length. On 80 columns consoles, if 80
320 298 # characters are written, the following CR won't apply on the
321 299 # current line but on the new one. Keep room for it.
322 300 width = 79
323 301 # Query stderr to avoid problems with redirections
324 302 screenbuf = _kernel32.GetStdHandle(
325 303 _STD_ERROR_HANDLE) # don't close the handle returned
326 304 if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
327 305 return width
328 306 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
329 307 if not _kernel32.GetConsoleScreenBufferInfo(
330 308 screenbuf, ctypes.byref(csbi)):
331 309 return width
332 310 width = csbi.srWindow.Right - csbi.srWindow.Left
333 311 return width
334 312
335 313 def spawndetached(args):
336 314 # No standard library function really spawns a fully detached
337 315 # process under win32 because they allocate pipes or other objects
338 316 # to handle standard streams communications. Passing these objects
339 317 # to the child process requires handle inheritance to be enabled
340 318 # which makes really detached processes impossible.
341 319 si = _STARTUPINFO()
342 320 si.cb = ctypes.sizeof(_STARTUPINFO)
343 321 si.dwFlags = _STARTF_USESHOWWINDOW
344 322 si.wShowWindow = _SW_HIDE
345 323
346 324 pi = _PROCESS_INFORMATION()
347 325
348 326 env = ''
349 327 for k in os.environ:
350 328 env += "%s=%s\0" % (k, os.environ[k])
351 329 if not env:
352 330 env = '\0'
353 331 env += '\0'
354 332
355 333 args = subprocess.list2cmdline(args)
356 334 # Not running the command in shell mode makes python26 hang when
357 335 # writing to hgweb output socket.
358 336 comspec = os.environ.get("COMSPEC", "cmd.exe")
359 337 args = comspec + " /c " + args
360 338
361 339 res = _kernel32.CreateProcessA(
362 340 None, args, None, None, False, _DETACHED_PROCESS,
363 341 env, os.getcwd(), ctypes.byref(si), ctypes.byref(pi))
364 342 if not res:
365 343 raise ctypes.WinError
366 344
367 345 return pi.dwProcessId
368 346
369 347 def unlink(f):
370 348 '''try to implement POSIX' unlink semantics on Windows'''
371 349
372 350 # POSIX allows to unlink and rename open files. Windows has serious
373 351 # problems with doing that:
374 352 # - Calling os.unlink (or os.rename) on a file f fails if f or any
375 353 # hardlinked copy of f has been opened with Python's open(). There is no
376 354 # way such a file can be deleted or renamed on Windows (other than
377 355 # scheduling the delete or rename for the next reboot).
378 356 # - Calling os.unlink on a file that has been opened with Mercurial's
379 357 # posixfile (or comparable methods) will delay the actual deletion of
380 358 # the file for as long as the file is held open. The filename is blocked
381 359 # during that time and cannot be used for recreating a new file under
382 360 # that same name ("zombie file"). Directories containing such zombie files
383 361 # cannot be removed or moved.
384 362 # A file that has been opened with posixfile can be renamed, so we rename
385 363 # f to a random temporary name before calling os.unlink on it. This allows
386 364 # callers to recreate f immediately while having other readers do their
387 365 # implicit zombie filename blocking on a temporary name.
388 366
389 367 for tries in xrange(10):
390 368 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
391 369 try:
392 370 os.rename(f, temp) # raises OSError EEXIST if temp exists
393 371 break
394 372 except OSError, e:
395 373 if e.errno != errno.EEXIST:
396 374 raise
397 375 else:
398 376 raise IOError, (errno.EEXIST, "No usable temporary filename found")
399 377
400 378 try:
401 379 os.unlink(temp)
402 380 except OSError:
403 381 # The unlink might have failed because the READONLY attribute may heave
404 382 # been set on the original file. Rename works fine with READONLY set,
405 383 # but not os.unlink. Reset all attributes and try again.
406 384 _kernel32.SetFileAttributesA(temp, _FILE_ATTRIBUTE_NORMAL)
407 385 try:
408 386 os.unlink(temp)
409 387 except OSError:
410 388 # The unlink might have failed due to some very rude AV-Scanners.
411 389 # Leaking a tempfile is the lesser evil than aborting here and
412 390 # leaving some potentially serious inconsistencies.
413 391 pass
414 392
415 393 def makedir(path, notindexed):
416 394 os.mkdir(path)
417 395 if notindexed:
418 396 _kernel32.SetFileAttributesA(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
@@ -1,319 +1,339
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 import osutil
10 import errno, msvcrt, os, re, sys
9 import osutil, encoding
10 import errno, msvcrt, os, re, sys, _winreg
11 11
12 12 import win32
13 13 executablepath = win32.executablepath
14 14 getuser = win32.getuser
15 15 hidewindow = win32.hidewindow
16 lookupreg = win32.lookupreg
17 16 makedir = win32.makedir
18 17 nlinks = win32.nlinks
19 18 oslink = win32.oslink
20 19 samedevice = win32.samedevice
21 20 samefile = win32.samefile
22 21 setsignalhandler = win32.setsignalhandler
23 22 spawndetached = win32.spawndetached
24 23 termwidth = win32.termwidth
25 24 testpid = win32.testpid
26 25 unlink = win32.unlink
27 26
28 27 nulldev = 'NUL:'
29 28 umask = 0022
30 29
31 30 # wrap osutil.posixfile to provide friendlier exceptions
32 31 def posixfile(name, mode='r', buffering=-1):
33 32 try:
34 33 return osutil.posixfile(name, mode, buffering)
35 34 except WindowsError, err:
36 35 raise IOError(err.errno, '%s: %s' % (name, err.strerror))
37 36 posixfile.__doc__ = osutil.posixfile.__doc__
38 37
39 38 class winstdout(object):
40 39 '''stdout on windows misbehaves if sent through a pipe'''
41 40
42 41 def __init__(self, fp):
43 42 self.fp = fp
44 43
45 44 def __getattr__(self, key):
46 45 return getattr(self.fp, key)
47 46
48 47 def close(self):
49 48 try:
50 49 self.fp.close()
51 50 except IOError:
52 51 pass
53 52
54 53 def write(self, s):
55 54 try:
56 55 # This is workaround for "Not enough space" error on
57 56 # writing large size of data to console.
58 57 limit = 16000
59 58 l = len(s)
60 59 start = 0
61 60 self.softspace = 0
62 61 while start < l:
63 62 end = start + limit
64 63 self.fp.write(s[start:end])
65 64 start = end
66 65 except IOError, inst:
67 66 if inst.errno != 0:
68 67 raise
69 68 self.close()
70 69 raise IOError(errno.EPIPE, 'Broken pipe')
71 70
72 71 def flush(self):
73 72 try:
74 73 return self.fp.flush()
75 74 except IOError, inst:
76 75 if inst.errno != errno.EINVAL:
77 76 raise
78 77 self.close()
79 78 raise IOError(errno.EPIPE, 'Broken pipe')
80 79
81 80 sys.__stdout__ = sys.stdout = winstdout(sys.stdout)
82 81
83 82 def _is_win_9x():
84 83 '''return true if run on windows 95, 98 or me.'''
85 84 try:
86 85 return sys.getwindowsversion()[3] == 1
87 86 except AttributeError:
88 87 return 'command' in os.environ.get('comspec', '')
89 88
90 89 def openhardlinks():
91 90 return not _is_win_9x()
92 91
93 92 def parsepatchoutput(output_line):
94 93 """parses the output produced by patch and returns the filename"""
95 94 pf = output_line[14:]
96 95 if pf[0] == '`':
97 96 pf = pf[1:-1] # Remove the quotes
98 97 return pf
99 98
100 99 def sshargs(sshcmd, host, user, port):
101 100 '''Build argument list for ssh or Plink'''
102 101 pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
103 102 args = user and ("%s@%s" % (user, host)) or host
104 103 return port and ("%s %s %s" % (args, pflag, port)) or args
105 104
106 105 def setflags(f, l, x):
107 106 pass
108 107
109 108 def copymode(src, dst, mode=None):
110 109 pass
111 110
112 111 def checkexec(path):
113 112 return False
114 113
115 114 def checklink(path):
116 115 return False
117 116
118 117 def setbinary(fd):
119 118 # When run without console, pipes may expose invalid
120 119 # fileno(), usually set to -1.
121 120 fno = getattr(fd, 'fileno', None)
122 121 if fno is not None and fno() >= 0:
123 122 msvcrt.setmode(fno(), os.O_BINARY)
124 123
125 124 def pconvert(path):
126 125 return path.replace(os.sep, '/')
127 126
128 127 def localpath(path):
129 128 return path.replace('/', '\\')
130 129
131 130 def normpath(path):
132 131 return pconvert(os.path.normpath(path))
133 132
134 133 encodinglower = None
135 134 encodingupper = None
136 135
137 136 def normcase(path):
138 137 return encodingupper(path)
139 138
140 139 def realpath(path):
141 140 '''
142 141 Returns the true, canonical file system path equivalent to the given
143 142 path.
144 143 '''
145 144 # TODO: There may be a more clever way to do this that also handles other,
146 145 # less common file systems.
147 146 return os.path.normpath(normcase(os.path.realpath(path)))
148 147
149 148 def samestat(s1, s2):
150 149 return False
151 150
152 151 # A sequence of backslashes is special iff it precedes a double quote:
153 152 # - if there's an even number of backslashes, the double quote is not
154 153 # quoted (i.e. it ends the quoted region)
155 154 # - if there's an odd number of backslashes, the double quote is quoted
156 155 # - in both cases, every pair of backslashes is unquoted into a single
157 156 # backslash
158 157 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
159 158 # So, to quote a string, we must surround it in double quotes, double
160 159 # the number of backslashes that preceed double quotes and add another
161 160 # backslash before every double quote (being careful with the double
162 161 # quote we've appended to the end)
163 162 _quotere = None
164 163 def shellquote(s):
165 164 global _quotere
166 165 if _quotere is None:
167 166 _quotere = re.compile(r'(\\*)("|\\$)')
168 167 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
169 168
170 169 def quotecommand(cmd):
171 170 """Build a command string suitable for os.popen* calls."""
172 171 if sys.version_info < (2, 7, 1):
173 172 # Python versions since 2.7.1 do this extra quoting themselves
174 173 return '"' + cmd + '"'
175 174 return cmd
176 175
177 176 def popen(command, mode='r'):
178 177 # Work around "popen spawned process may not write to stdout
179 178 # under windows"
180 179 # http://bugs.python.org/issue1366
181 180 command += " 2> %s" % nulldev
182 181 return os.popen(quotecommand(command), mode)
183 182
184 183 def explainexit(code):
185 184 return _("exited with status %d") % code, code
186 185
187 186 # if you change this stub into a real check, please try to implement the
188 187 # username and groupname functions above, too.
189 188 def isowner(st):
190 189 return True
191 190
192 191 def findexe(command):
193 192 '''Find executable for command searching like cmd.exe does.
194 193 If command is a basename then PATH is searched for command.
195 194 PATH isn't searched if command is an absolute or relative path.
196 195 An extension from PATHEXT is found and added if not present.
197 196 If command isn't found None is returned.'''
198 197 pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
199 198 pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
200 199 if os.path.splitext(command)[1].lower() in pathexts:
201 200 pathexts = ['']
202 201
203 202 def findexisting(pathcommand):
204 203 'Will append extension (if needed) and return existing file'
205 204 for ext in pathexts:
206 205 executable = pathcommand + ext
207 206 if os.path.exists(executable):
208 207 return executable
209 208 return None
210 209
211 210 if os.sep in command:
212 211 return findexisting(command)
213 212
214 213 for path in os.environ.get('PATH', '').split(os.pathsep):
215 214 executable = findexisting(os.path.join(path, command))
216 215 if executable is not None:
217 216 return executable
218 217 return findexisting(os.path.expanduser(os.path.expandvars(command)))
219 218
220 219 def statfiles(files):
221 220 '''Stat each file in files and yield stat or None if file does not exist.
222 221 Cluster and cache stat per directory to minimize number of OS stat calls.'''
223 222 dircache = {} # dirname -> filename -> status | None if file does not exist
224 223 for nf in files:
225 224 nf = normcase(nf)
226 225 dir, base = os.path.split(nf)
227 226 if not dir:
228 227 dir = '.'
229 228 cache = dircache.get(dir, None)
230 229 if cache is None:
231 230 try:
232 231 dmap = dict([(normcase(n), s)
233 232 for n, k, s in osutil.listdir(dir, True)])
234 233 except OSError, err:
235 234 # handle directory not found in Python version prior to 2.5
236 235 # Python <= 2.4 returns native Windows code 3 in errno
237 236 # Python >= 2.5 returns ENOENT and adds winerror field
238 237 # EINVAL is raised if dir is not a directory.
239 238 if err.errno not in (3, errno.ENOENT, errno.EINVAL,
240 239 errno.ENOTDIR):
241 240 raise
242 241 dmap = {}
243 242 cache = dircache.setdefault(dir, dmap)
244 243 yield cache.get(base, None)
245 244
246 245 def username(uid=None):
247 246 """Return the name of the user with the given uid.
248 247
249 248 If uid is None, return the name of the current user."""
250 249 return None
251 250
252 251 def groupname(gid=None):
253 252 """Return the name of the group with the given gid.
254 253
255 254 If gid is None, return the name of the current group."""
256 255 return None
257 256
258 257 def _removedirs(name):
259 258 """special version of os.removedirs that does not remove symlinked
260 259 directories or junction points if they actually contain files"""
261 260 if osutil.listdir(name):
262 261 return
263 262 os.rmdir(name)
264 263 head, tail = os.path.split(name)
265 264 if not tail:
266 265 head, tail = os.path.split(head)
267 266 while head and tail:
268 267 try:
269 268 if osutil.listdir(head):
270 269 return
271 270 os.rmdir(head)
272 271 except (ValueError, OSError):
273 272 break
274 273 head, tail = os.path.split(head)
275 274
276 275 def unlinkpath(f):
277 276 """unlink and remove the directory if it is empty"""
278 277 unlink(f)
279 278 # try removing directories that might now be empty
280 279 try:
281 280 _removedirs(os.path.dirname(f))
282 281 except OSError:
283 282 pass
284 283
285 284 def rename(src, dst):
286 285 '''atomically rename file src to dst, replacing dst if it exists'''
287 286 try:
288 287 os.rename(src, dst)
289 288 except OSError, e:
290 289 if e.errno != errno.EEXIST:
291 290 raise
292 291 unlink(dst)
293 292 os.rename(src, dst)
294 293
295 294 def gethgcmd():
296 295 return [sys.executable] + sys.argv[:1]
297 296
298 297 def termwidth():
299 298 # cmd.exe does not handle CR like a unix console, the CR is
300 299 # counted in the line length. On 80 columns consoles, if 80
301 300 # characters are written, the following CR won't apply on the
302 301 # current line but on the new one. Keep room for it.
303 302 return 79
304 303
305 304 def groupmembers(name):
306 305 # Don't support groups on Windows for now
307 306 raise KeyError
308 307
309 308 def isexec(f):
310 309 return False
311 310
312 311 class cachestat(object):
313 312 def __init__(self, path):
314 313 pass
315 314
316 315 def cacheable(self):
317 316 return False
318 317
318 def lookupreg(key, valname=None, scope=None):
319 ''' Look up a key/value name in the Windows registry.
320
321 valname: value name. If unspecified, the default value for the key
322 is used.
323 scope: optionally specify scope for registry lookup, this can be
324 a sequence of scopes to look up in order. Default (CURRENT_USER,
325 LOCAL_MACHINE).
326 '''
327 if scope is None:
328 scope = (_winreg.HKEY_CURRENT_USER, _winreg.HKEY_LOCAL_MACHINE)
329 elif not isinstance(scope, (list, tuple)):
330 scope = (scope,)
331 for s in scope:
332 try:
333 val = _winreg.QueryValueEx(_winreg.OpenKey(s, key), valname)[0]
334 # never let a Unicode string escape into the wild
335 return encoding.tolocal(val.encode('UTF-8'))
336 except EnvironmentError:
337 pass
338
319 339 expandglobs = True
General Comments 0
You need to be logged in to leave comments. Login now