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