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