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