##// END OF EJS Templates
windows: get Abort from error
Matt Mackall -
r7949:443c0c86 default
parent child Browse files
Show More
@@ -1,254 +1,253 b''
1 """
1 """
2 windows.py - Windows utility function implementations for Mercurial
2 windows.py - Windows utility function implementations for Mercurial
3
3
4 Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
5
5
6 This software may be used and distributed according to the terms of
6 This software may be used and distributed according to the terms of
7 the GNU General Public License version 2, incorporated herein by
7 the GNU General Public License version 2, incorporated herein by
8 reference.
8 reference.
9 """
9 """
10
10
11 import util
12 from i18n import _
11 from i18n import _
13 import errno, msvcrt, os, osutil, re, sys
12 import errno, msvcrt, os, osutil, re, sys, error
14 nulldev = 'NUL:'
13 nulldev = 'NUL:'
15
14
16 umask = 002
15 umask = 002
17
16
18 class winstdout:
17 class winstdout:
19 '''stdout on windows misbehaves if sent through a pipe'''
18 '''stdout on windows misbehaves if sent through a pipe'''
20
19
21 def __init__(self, fp):
20 def __init__(self, fp):
22 self.fp = fp
21 self.fp = fp
23
22
24 def __getattr__(self, key):
23 def __getattr__(self, key):
25 return getattr(self.fp, key)
24 return getattr(self.fp, key)
26
25
27 def close(self):
26 def close(self):
28 try:
27 try:
29 self.fp.close()
28 self.fp.close()
30 except: pass
29 except: pass
31
30
32 def write(self, s):
31 def write(self, s):
33 try:
32 try:
34 # This is workaround for "Not enough space" error on
33 # This is workaround for "Not enough space" error on
35 # writing large size of data to console.
34 # writing large size of data to console.
36 limit = 16000
35 limit = 16000
37 l = len(s)
36 l = len(s)
38 start = 0
37 start = 0
39 while start < l:
38 while start < l:
40 end = start + limit
39 end = start + limit
41 self.fp.write(s[start:end])
40 self.fp.write(s[start:end])
42 start = end
41 start = end
43 except IOError, inst:
42 except IOError, inst:
44 if inst.errno != 0: raise
43 if inst.errno != 0: raise
45 self.close()
44 self.close()
46 raise IOError(errno.EPIPE, 'Broken pipe')
45 raise IOError(errno.EPIPE, 'Broken pipe')
47
46
48 def flush(self):
47 def flush(self):
49 try:
48 try:
50 return self.fp.flush()
49 return self.fp.flush()
51 except IOError, inst:
50 except IOError, inst:
52 if inst.errno != errno.EINVAL: raise
51 if inst.errno != errno.EINVAL: raise
53 self.close()
52 self.close()
54 raise IOError(errno.EPIPE, 'Broken pipe')
53 raise IOError(errno.EPIPE, 'Broken pipe')
55
54
56 sys.stdout = winstdout(sys.stdout)
55 sys.stdout = winstdout(sys.stdout)
57
56
58 def _is_win_9x():
57 def _is_win_9x():
59 '''return true if run on windows 95, 98 or me.'''
58 '''return true if run on windows 95, 98 or me.'''
60 try:
59 try:
61 return sys.getwindowsversion()[3] == 1
60 return sys.getwindowsversion()[3] == 1
62 except AttributeError:
61 except AttributeError:
63 return 'command' in os.environ.get('comspec', '')
62 return 'command' in os.environ.get('comspec', '')
64
63
65 def openhardlinks():
64 def openhardlinks():
66 return not _is_win_9x and "win32api" in locals()
65 return not _is_win_9x and "win32api" in locals()
67
66
68 def system_rcpath():
67 def system_rcpath():
69 try:
68 try:
70 return system_rcpath_win32()
69 return system_rcpath_win32()
71 except:
70 except:
72 return [r'c:\mercurial\mercurial.ini']
71 return [r'c:\mercurial\mercurial.ini']
73
72
74 def user_rcpath():
73 def user_rcpath():
75 '''return os-specific hgrc search path to the user dir'''
74 '''return os-specific hgrc search path to the user dir'''
76 try:
75 try:
77 path = user_rcpath_win32()
76 path = user_rcpath_win32()
78 except:
77 except:
79 home = os.path.expanduser('~')
78 home = os.path.expanduser('~')
80 path = [os.path.join(home, 'mercurial.ini'),
79 path = [os.path.join(home, 'mercurial.ini'),
81 os.path.join(home, '.hgrc')]
80 os.path.join(home, '.hgrc')]
82 userprofile = os.environ.get('USERPROFILE')
81 userprofile = os.environ.get('USERPROFILE')
83 if userprofile:
82 if userprofile:
84 path.append(os.path.join(userprofile, 'mercurial.ini'))
83 path.append(os.path.join(userprofile, 'mercurial.ini'))
85 path.append(os.path.join(userprofile, '.hgrc'))
84 path.append(os.path.join(userprofile, '.hgrc'))
86 return path
85 return path
87
86
88 def parse_patch_output(output_line):
87 def parse_patch_output(output_line):
89 """parses the output produced by patch and returns the file name"""
88 """parses the output produced by patch and returns the file name"""
90 pf = output_line[14:]
89 pf = output_line[14:]
91 if pf[0] == '`':
90 if pf[0] == '`':
92 pf = pf[1:-1] # Remove the quotes
91 pf = pf[1:-1] # Remove the quotes
93 return pf
92 return pf
94
93
95 def sshargs(sshcmd, host, user, port):
94 def sshargs(sshcmd, host, user, port):
96 '''Build argument list for ssh or Plink'''
95 '''Build argument list for ssh or Plink'''
97 pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
96 pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
98 args = user and ("%s@%s" % (user, host)) or host
97 args = user and ("%s@%s" % (user, host)) or host
99 return port and ("%s %s %s" % (args, pflag, port)) or args
98 return port and ("%s %s %s" % (args, pflag, port)) or args
100
99
101 def testpid(pid):
100 def testpid(pid):
102 '''return False if pid dead, True if running or not known'''
101 '''return False if pid dead, True if running or not known'''
103 return True
102 return True
104
103
105 def set_flags(f, l, x):
104 def set_flags(f, l, x):
106 pass
105 pass
107
106
108 def set_binary(fd):
107 def set_binary(fd):
109 # When run without console, pipes may expose invalid
108 # When run without console, pipes may expose invalid
110 # fileno(), usually set to -1.
109 # fileno(), usually set to -1.
111 if hasattr(fd, 'fileno') and fd.fileno() >= 0:
110 if hasattr(fd, 'fileno') and fd.fileno() >= 0:
112 msvcrt.setmode(fd.fileno(), os.O_BINARY)
111 msvcrt.setmode(fd.fileno(), os.O_BINARY)
113
112
114 def pconvert(path):
113 def pconvert(path):
115 return '/'.join(path.split(os.sep))
114 return '/'.join(path.split(os.sep))
116
115
117 def localpath(path):
116 def localpath(path):
118 return path.replace('/', '\\')
117 return path.replace('/', '\\')
119
118
120 def normpath(path):
119 def normpath(path):
121 return pconvert(os.path.normpath(path))
120 return pconvert(os.path.normpath(path))
122
121
123 def samestat(s1, s2):
122 def samestat(s1, s2):
124 return False
123 return False
125
124
126 # A sequence of backslashes is special iff it precedes a double quote:
125 # A sequence of backslashes is special iff it precedes a double quote:
127 # - if there's an even number of backslashes, the double quote is not
126 # - if there's an even number of backslashes, the double quote is not
128 # quoted (i.e. it ends the quoted region)
127 # quoted (i.e. it ends the quoted region)
129 # - if there's an odd number of backslashes, the double quote is quoted
128 # - if there's an odd number of backslashes, the double quote is quoted
130 # - in both cases, every pair of backslashes is unquoted into a single
129 # - in both cases, every pair of backslashes is unquoted into a single
131 # backslash
130 # backslash
132 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
131 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
133 # So, to quote a string, we must surround it in double quotes, double
132 # So, to quote a string, we must surround it in double quotes, double
134 # the number of backslashes that preceed double quotes and add another
133 # the number of backslashes that preceed double quotes and add another
135 # backslash before every double quote (being careful with the double
134 # backslash before every double quote (being careful with the double
136 # quote we've appended to the end)
135 # quote we've appended to the end)
137 _quotere = None
136 _quotere = None
138 def shellquote(s):
137 def shellquote(s):
139 global _quotere
138 global _quotere
140 if _quotere is None:
139 if _quotere is None:
141 _quotere = re.compile(r'(\\*)("|\\$)')
140 _quotere = re.compile(r'(\\*)("|\\$)')
142 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
141 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
143
142
144 def quotecommand(cmd):
143 def quotecommand(cmd):
145 """Build a command string suitable for os.popen* calls."""
144 """Build a command string suitable for os.popen* calls."""
146 # The extra quotes are needed because popen* runs the command
145 # The extra quotes are needed because popen* runs the command
147 # through the current COMSPEC. cmd.exe suppress enclosing quotes.
146 # through the current COMSPEC. cmd.exe suppress enclosing quotes.
148 return '"' + cmd + '"'
147 return '"' + cmd + '"'
149
148
150 def popen(command, mode='r'):
149 def popen(command, mode='r'):
151 # Work around "popen spawned process may not write to stdout
150 # Work around "popen spawned process may not write to stdout
152 # under windows"
151 # under windows"
153 # http://bugs.python.org/issue1366
152 # http://bugs.python.org/issue1366
154 command += " 2> %s" % nulldev
153 command += " 2> %s" % nulldev
155 return os.popen(quotecommand(command), mode)
154 return os.popen(quotecommand(command), mode)
156
155
157 def explain_exit(code):
156 def explain_exit(code):
158 return _("exited with status %d") % code, code
157 return _("exited with status %d") % code, code
159
158
160 # if you change this stub into a real check, please try to implement the
159 # if you change this stub into a real check, please try to implement the
161 # username and groupname functions above, too.
160 # username and groupname functions above, too.
162 def isowner(fp, st=None):
161 def isowner(fp, st=None):
163 return True
162 return True
164
163
165 def find_exe(command):
164 def find_exe(command):
166 '''Find executable for command searching like cmd.exe does.
165 '''Find executable for command searching like cmd.exe does.
167 If command is a basename then PATH is searched for command.
166 If command is a basename then PATH is searched for command.
168 PATH isn't searched if command is an absolute or relative path.
167 PATH isn't searched if command is an absolute or relative path.
169 An extension from PATHEXT is found and added if not present.
168 An extension from PATHEXT is found and added if not present.
170 If command isn't found None is returned.'''
169 If command isn't found None is returned.'''
171 pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
170 pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
172 pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
171 pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
173 if os.path.splitext(command)[1].lower() in pathexts:
172 if os.path.splitext(command)[1].lower() in pathexts:
174 pathexts = ['']
173 pathexts = ['']
175
174
176 def findexisting(pathcommand):
175 def findexisting(pathcommand):
177 'Will append extension (if needed) and return existing file'
176 'Will append extension (if needed) and return existing file'
178 for ext in pathexts:
177 for ext in pathexts:
179 executable = pathcommand + ext
178 executable = pathcommand + ext
180 if os.path.exists(executable):
179 if os.path.exists(executable):
181 return executable
180 return executable
182 return None
181 return None
183
182
184 if os.sep in command:
183 if os.sep in command:
185 return findexisting(command)
184 return findexisting(command)
186
185
187 for path in os.environ.get('PATH', '').split(os.pathsep):
186 for path in os.environ.get('PATH', '').split(os.pathsep):
188 executable = findexisting(os.path.join(path, command))
187 executable = findexisting(os.path.join(path, command))
189 if executable is not None:
188 if executable is not None:
190 return executable
189 return executable
191 return None
190 return None
192
191
193 def set_signal_handler():
192 def set_signal_handler():
194 try:
193 try:
195 set_signal_handler_win32()
194 set_signal_handler_win32()
196 except NameError:
195 except NameError:
197 pass
196 pass
198
197
199 def statfiles(files):
198 def statfiles(files):
200 '''Stat each file in files and yield stat or None if file does not exist.
199 '''Stat each file in files and yield stat or None if file does not exist.
201 Cluster and cache stat per directory to minimize number of OS stat calls.'''
200 Cluster and cache stat per directory to minimize number of OS stat calls.'''
202 ncase = os.path.normcase
201 ncase = os.path.normcase
203 sep = os.sep
202 sep = os.sep
204 dircache = {} # dirname -> filename -> status | None if file does not exist
203 dircache = {} # dirname -> filename -> status | None if file does not exist
205 for nf in files:
204 for nf in files:
206 nf = ncase(nf)
205 nf = ncase(nf)
207 pos = nf.rfind(sep)
206 pos = nf.rfind(sep)
208 if pos == -1:
207 if pos == -1:
209 dir, base = '.', nf
208 dir, base = '.', nf
210 else:
209 else:
211 dir, base = nf[:pos+1], nf[pos+1:]
210 dir, base = nf[:pos+1], nf[pos+1:]
212 cache = dircache.get(dir, None)
211 cache = dircache.get(dir, None)
213 if cache is None:
212 if cache is None:
214 try:
213 try:
215 dmap = dict([(ncase(n), s)
214 dmap = dict([(ncase(n), s)
216 for n, k, s in osutil.listdir(dir, True)])
215 for n, k, s in osutil.listdir(dir, True)])
217 except OSError, err:
216 except OSError, err:
218 # handle directory not found in Python version prior to 2.5
217 # handle directory not found in Python version prior to 2.5
219 # Python <= 2.4 returns native Windows code 3 in errno
218 # Python <= 2.4 returns native Windows code 3 in errno
220 # Python >= 2.5 returns ENOENT and adds winerror field
219 # Python >= 2.5 returns ENOENT and adds winerror field
221 # EINVAL is raised if dir is not a directory.
220 # EINVAL is raised if dir is not a directory.
222 if err.errno not in (3, errno.ENOENT, errno.EINVAL,
221 if err.errno not in (3, errno.ENOENT, errno.EINVAL,
223 errno.ENOTDIR):
222 errno.ENOTDIR):
224 raise
223 raise
225 dmap = {}
224 dmap = {}
226 cache = dircache.setdefault(dir, dmap)
225 cache = dircache.setdefault(dir, dmap)
227 yield cache.get(base, None)
226 yield cache.get(base, None)
228
227
229 def getuser():
228 def getuser():
230 '''return name of current user'''
229 '''return name of current user'''
231 raise util.Abort(_('user name not available - set USERNAME '
230 raise error.Abort(_('user name not available - set USERNAME '
232 'environment variable'))
231 'environment variable'))
233
232
234 def username(uid=None):
233 def username(uid=None):
235 """Return the name of the user with the given uid.
234 """Return the name of the user with the given uid.
236
235
237 If uid is None, return the name of the current user."""
236 If uid is None, return the name of the current user."""
238 return None
237 return None
239
238
240 def groupname(gid=None):
239 def groupname(gid=None):
241 """Return the name of the group with the given gid.
240 """Return the name of the group with the given gid.
242
241
243 If gid is None, return the name of the current group."""
242 If gid is None, return the name of the current group."""
244 return None
243 return None
245
244
246 posixfile = file
245 posixfile = file
247 try:
246 try:
248 # override functions with win32 versions if possible
247 # override functions with win32 versions if possible
249 from win32 import *
248 from win32 import *
250 if not _is_win_9x():
249 if not _is_win_9x():
251 posixfile = posixfile_nt
250 posixfile = posixfile_nt
252 except ImportError:
251 except ImportError:
253 pass
252 pass
254
253
General Comments 0
You need to be logged in to leave comments. Login now