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