##// END OF EJS Templates
util: move checklink() to posix.py and return False on Windows...
Adrian Buehlmann -
r13890:31eb145b default
parent child Browse files
Show More
@@ -1,336 +1,348 b''
1 # posix.py - Posix utility function implementations for Mercurial
1 # posix.py - Posix 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 os, sys, errno, stat, getpass, pwd, grp, tempfile
10 import os, sys, errno, stat, getpass, pwd, grp, tempfile
11
11
12 posixfile = open
12 posixfile = open
13 nulldev = '/dev/null'
13 nulldev = '/dev/null'
14 normpath = os.path.normpath
14 normpath = os.path.normpath
15 samestat = os.path.samestat
15 samestat = os.path.samestat
16 os_link = os.link
16 os_link = os.link
17 unlink = os.unlink
17 unlink = os.unlink
18 rename = os.rename
18 rename = os.rename
19 expandglobs = False
19 expandglobs = False
20
20
21 umask = os.umask(0)
21 umask = os.umask(0)
22 os.umask(umask)
22 os.umask(umask)
23
23
24 def openhardlinks():
24 def openhardlinks():
25 '''return true if it is safe to hold open file handles to hardlinks'''
25 '''return true if it is safe to hold open file handles to hardlinks'''
26 return True
26 return True
27
27
28 def nlinks(name):
28 def nlinks(name):
29 '''return number of hardlinks for the given file'''
29 '''return number of hardlinks for the given file'''
30 return os.lstat(name).st_nlink
30 return os.lstat(name).st_nlink
31
31
32 def rcfiles(path):
32 def rcfiles(path):
33 rcs = [os.path.join(path, 'hgrc')]
33 rcs = [os.path.join(path, 'hgrc')]
34 rcdir = os.path.join(path, 'hgrc.d')
34 rcdir = os.path.join(path, 'hgrc.d')
35 try:
35 try:
36 rcs.extend([os.path.join(rcdir, f)
36 rcs.extend([os.path.join(rcdir, f)
37 for f, kind in osutil.listdir(rcdir)
37 for f, kind in osutil.listdir(rcdir)
38 if f.endswith(".rc")])
38 if f.endswith(".rc")])
39 except OSError:
39 except OSError:
40 pass
40 pass
41 return rcs
41 return rcs
42
42
43 def system_rcpath():
43 def system_rcpath():
44 path = []
44 path = []
45 # old mod_python does not set sys.argv
45 # old mod_python does not set sys.argv
46 if len(getattr(sys, 'argv', [])) > 0:
46 if len(getattr(sys, 'argv', [])) > 0:
47 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
47 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
48 '/../etc/mercurial'))
48 '/../etc/mercurial'))
49 path.extend(rcfiles('/etc/mercurial'))
49 path.extend(rcfiles('/etc/mercurial'))
50 return path
50 return path
51
51
52 def user_rcpath():
52 def user_rcpath():
53 return [os.path.expanduser('~/.hgrc')]
53 return [os.path.expanduser('~/.hgrc')]
54
54
55 def parse_patch_output(output_line):
55 def parse_patch_output(output_line):
56 """parses the output produced by patch and returns the filename"""
56 """parses the output produced by patch and returns the filename"""
57 pf = output_line[14:]
57 pf = output_line[14:]
58 if os.sys.platform == 'OpenVMS':
58 if os.sys.platform == 'OpenVMS':
59 if pf[0] == '`':
59 if pf[0] == '`':
60 pf = pf[1:-1] # Remove the quotes
60 pf = pf[1:-1] # Remove the quotes
61 else:
61 else:
62 if pf.startswith("'") and pf.endswith("'") and " " in pf:
62 if pf.startswith("'") and pf.endswith("'") and " " in pf:
63 pf = pf[1:-1] # Remove the quotes
63 pf = pf[1:-1] # Remove the quotes
64 return pf
64 return pf
65
65
66 def sshargs(sshcmd, host, user, port):
66 def sshargs(sshcmd, host, user, port):
67 '''Build argument list for ssh'''
67 '''Build argument list for ssh'''
68 args = user and ("%s@%s" % (user, host)) or host
68 args = user and ("%s@%s" % (user, host)) or host
69 return port and ("%s -p %s" % (args, port)) or args
69 return port and ("%s -p %s" % (args, port)) or args
70
70
71 def is_exec(f):
71 def is_exec(f):
72 """check whether a file is executable"""
72 """check whether a file is executable"""
73 return (os.lstat(f).st_mode & 0100 != 0)
73 return (os.lstat(f).st_mode & 0100 != 0)
74
74
75 def set_flags(f, l, x):
75 def set_flags(f, l, x):
76 s = os.lstat(f).st_mode
76 s = os.lstat(f).st_mode
77 if l:
77 if l:
78 if not stat.S_ISLNK(s):
78 if not stat.S_ISLNK(s):
79 # switch file to link
79 # switch file to link
80 fp = open(f)
80 fp = open(f)
81 data = fp.read()
81 data = fp.read()
82 fp.close()
82 fp.close()
83 os.unlink(f)
83 os.unlink(f)
84 try:
84 try:
85 os.symlink(data, f)
85 os.symlink(data, f)
86 except:
86 except:
87 # failed to make a link, rewrite file
87 # failed to make a link, rewrite file
88 fp = open(f, "w")
88 fp = open(f, "w")
89 fp.write(data)
89 fp.write(data)
90 fp.close()
90 fp.close()
91 # no chmod needed at this point
91 # no chmod needed at this point
92 return
92 return
93 if stat.S_ISLNK(s):
93 if stat.S_ISLNK(s):
94 # switch link to file
94 # switch link to file
95 data = os.readlink(f)
95 data = os.readlink(f)
96 os.unlink(f)
96 os.unlink(f)
97 fp = open(f, "w")
97 fp = open(f, "w")
98 fp.write(data)
98 fp.write(data)
99 fp.close()
99 fp.close()
100 s = 0666 & ~umask # avoid restatting for chmod
100 s = 0666 & ~umask # avoid restatting for chmod
101
101
102 sx = s & 0100
102 sx = s & 0100
103 if x and not sx:
103 if x and not sx:
104 # Turn on +x for every +r bit when making a file executable
104 # Turn on +x for every +r bit when making a file executable
105 # and obey umask.
105 # and obey umask.
106 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
106 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
107 elif not x and sx:
107 elif not x and sx:
108 # Turn off all +x bits
108 # Turn off all +x bits
109 os.chmod(f, s & 0666)
109 os.chmod(f, s & 0666)
110
110
111 def checkexec(path):
111 def checkexec(path):
112 """
112 """
113 Check whether the given path is on a filesystem with UNIX-like exec flags
113 Check whether the given path is on a filesystem with UNIX-like exec flags
114
114
115 Requires a directory (like /foo/.hg)
115 Requires a directory (like /foo/.hg)
116 """
116 """
117
117
118 # VFAT on some Linux versions can flip mode but it doesn't persist
118 # VFAT on some Linux versions can flip mode but it doesn't persist
119 # a FS remount. Frequently we can detect it if files are created
119 # a FS remount. Frequently we can detect it if files are created
120 # with exec bit on.
120 # with exec bit on.
121
121
122 try:
122 try:
123 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
123 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
124 fh, fn = tempfile.mkstemp(dir=path, prefix='hg-checkexec-')
124 fh, fn = tempfile.mkstemp(dir=path, prefix='hg-checkexec-')
125 try:
125 try:
126 os.close(fh)
126 os.close(fh)
127 m = os.stat(fn).st_mode & 0777
127 m = os.stat(fn).st_mode & 0777
128 new_file_has_exec = m & EXECFLAGS
128 new_file_has_exec = m & EXECFLAGS
129 os.chmod(fn, m ^ EXECFLAGS)
129 os.chmod(fn, m ^ EXECFLAGS)
130 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
130 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
131 finally:
131 finally:
132 os.unlink(fn)
132 os.unlink(fn)
133 except (IOError, OSError):
133 except (IOError, OSError):
134 # we don't care, the user probably won't be able to commit anyway
134 # we don't care, the user probably won't be able to commit anyway
135 return False
135 return False
136 return not (new_file_has_exec or exec_flags_cannot_flip)
136 return not (new_file_has_exec or exec_flags_cannot_flip)
137
137
138 def checklink(path):
139 """check whether the given path is on a symlink-capable filesystem"""
140 # mktemp is not racy because symlink creation will fail if the
141 # file already exists
142 name = tempfile.mktemp(dir=path, prefix='hg-checklink-')
143 try:
144 os.symlink(".", name)
145 os.unlink(name)
146 return True
147 except (OSError, AttributeError):
148 return False
149
138 def set_binary(fd):
150 def set_binary(fd):
139 pass
151 pass
140
152
141 def pconvert(path):
153 def pconvert(path):
142 return path
154 return path
143
155
144 def localpath(path):
156 def localpath(path):
145 return path
157 return path
146
158
147 def samefile(fpath1, fpath2):
159 def samefile(fpath1, fpath2):
148 """Returns whether path1 and path2 refer to the same file. This is only
160 """Returns whether path1 and path2 refer to the same file. This is only
149 guaranteed to work for files, not directories."""
161 guaranteed to work for files, not directories."""
150 return os.path.samefile(fpath1, fpath2)
162 return os.path.samefile(fpath1, fpath2)
151
163
152 def samedevice(fpath1, fpath2):
164 def samedevice(fpath1, fpath2):
153 """Returns whether fpath1 and fpath2 are on the same device. This is only
165 """Returns whether fpath1 and fpath2 are on the same device. This is only
154 guaranteed to work for files, not directories."""
166 guaranteed to work for files, not directories."""
155 st1 = os.lstat(fpath1)
167 st1 = os.lstat(fpath1)
156 st2 = os.lstat(fpath2)
168 st2 = os.lstat(fpath2)
157 return st1.st_dev == st2.st_dev
169 return st1.st_dev == st2.st_dev
158
170
159 if sys.platform == 'darwin':
171 if sys.platform == 'darwin':
160 import fcntl # only needed on darwin, missing on jython
172 import fcntl # only needed on darwin, missing on jython
161 def realpath(path):
173 def realpath(path):
162 '''
174 '''
163 Returns the true, canonical file system path equivalent to the given
175 Returns the true, canonical file system path equivalent to the given
164 path.
176 path.
165
177
166 Equivalent means, in this case, resulting in the same, unique
178 Equivalent means, in this case, resulting in the same, unique
167 file system link to the path. Every file system entry, whether a file,
179 file system link to the path. Every file system entry, whether a file,
168 directory, hard link or symbolic link or special, will have a single
180 directory, hard link or symbolic link or special, will have a single
169 path preferred by the system, but may allow multiple, differing path
181 path preferred by the system, but may allow multiple, differing path
170 lookups to point to it.
182 lookups to point to it.
171
183
172 Most regular UNIX file systems only allow a file system entry to be
184 Most regular UNIX file systems only allow a file system entry to be
173 looked up by its distinct path. Obviously, this does not apply to case
185 looked up by its distinct path. Obviously, this does not apply to case
174 insensitive file systems, whether case preserving or not. The most
186 insensitive file systems, whether case preserving or not. The most
175 complex issue to deal with is file systems transparently reencoding the
187 complex issue to deal with is file systems transparently reencoding the
176 path, such as the non-standard Unicode normalisation required for HFS+
188 path, such as the non-standard Unicode normalisation required for HFS+
177 and HFSX.
189 and HFSX.
178 '''
190 '''
179 # Constants copied from /usr/include/sys/fcntl.h
191 # Constants copied from /usr/include/sys/fcntl.h
180 F_GETPATH = 50
192 F_GETPATH = 50
181 O_SYMLINK = 0x200000
193 O_SYMLINK = 0x200000
182
194
183 try:
195 try:
184 fd = os.open(path, O_SYMLINK)
196 fd = os.open(path, O_SYMLINK)
185 except OSError, err:
197 except OSError, err:
186 if err.errno == errno.ENOENT:
198 if err.errno == errno.ENOENT:
187 return path
199 return path
188 raise
200 raise
189
201
190 try:
202 try:
191 return fcntl.fcntl(fd, F_GETPATH, '\0' * 1024).rstrip('\0')
203 return fcntl.fcntl(fd, F_GETPATH, '\0' * 1024).rstrip('\0')
192 finally:
204 finally:
193 os.close(fd)
205 os.close(fd)
194 else:
206 else:
195 # Fallback to the likely inadequate Python builtin function.
207 # Fallback to the likely inadequate Python builtin function.
196 realpath = os.path.realpath
208 realpath = os.path.realpath
197
209
198 def shellquote(s):
210 def shellquote(s):
199 if os.sys.platform == 'OpenVMS':
211 if os.sys.platform == 'OpenVMS':
200 return '"%s"' % s
212 return '"%s"' % s
201 else:
213 else:
202 return "'%s'" % s.replace("'", "'\\''")
214 return "'%s'" % s.replace("'", "'\\''")
203
215
204 def quotecommand(cmd):
216 def quotecommand(cmd):
205 return cmd
217 return cmd
206
218
207 def popen(command, mode='r'):
219 def popen(command, mode='r'):
208 return os.popen(command, mode)
220 return os.popen(command, mode)
209
221
210 def testpid(pid):
222 def testpid(pid):
211 '''return False if pid dead, True if running or not sure'''
223 '''return False if pid dead, True if running or not sure'''
212 if os.sys.platform == 'OpenVMS':
224 if os.sys.platform == 'OpenVMS':
213 return True
225 return True
214 try:
226 try:
215 os.kill(pid, 0)
227 os.kill(pid, 0)
216 return True
228 return True
217 except OSError, inst:
229 except OSError, inst:
218 return inst.errno != errno.ESRCH
230 return inst.errno != errno.ESRCH
219
231
220 def explain_exit(code):
232 def explain_exit(code):
221 """return a 2-tuple (desc, code) describing a subprocess status
233 """return a 2-tuple (desc, code) describing a subprocess status
222 (codes from kill are negative - not os.system/wait encoding)"""
234 (codes from kill are negative - not os.system/wait encoding)"""
223 if code >= 0:
235 if code >= 0:
224 return _("exited with status %d") % code, code
236 return _("exited with status %d") % code, code
225 return _("killed by signal %d") % -code, -code
237 return _("killed by signal %d") % -code, -code
226
238
227 def isowner(st):
239 def isowner(st):
228 """Return True if the stat object st is from the current user."""
240 """Return True if the stat object st is from the current user."""
229 return st.st_uid == os.getuid()
241 return st.st_uid == os.getuid()
230
242
231 def find_exe(command):
243 def find_exe(command):
232 '''Find executable for command searching like which does.
244 '''Find executable for command searching like which does.
233 If command is a basename then PATH is searched for command.
245 If command is a basename then PATH is searched for command.
234 PATH isn't searched if command is an absolute or relative path.
246 PATH isn't searched if command is an absolute or relative path.
235 If command isn't found None is returned.'''
247 If command isn't found None is returned.'''
236 if sys.platform == 'OpenVMS':
248 if sys.platform == 'OpenVMS':
237 return command
249 return command
238
250
239 def findexisting(executable):
251 def findexisting(executable):
240 'Will return executable if existing file'
252 'Will return executable if existing file'
241 if os.path.exists(executable):
253 if os.path.exists(executable):
242 return executable
254 return executable
243 return None
255 return None
244
256
245 if os.sep in command:
257 if os.sep in command:
246 return findexisting(command)
258 return findexisting(command)
247
259
248 for path in os.environ.get('PATH', '').split(os.pathsep):
260 for path in os.environ.get('PATH', '').split(os.pathsep):
249 executable = findexisting(os.path.join(path, command))
261 executable = findexisting(os.path.join(path, command))
250 if executable is not None:
262 if executable is not None:
251 return executable
263 return executable
252 return None
264 return None
253
265
254 def set_signal_handler():
266 def set_signal_handler():
255 pass
267 pass
256
268
257 def statfiles(files):
269 def statfiles(files):
258 'Stat each file in files and yield stat or None if file does not exist.'
270 'Stat each file in files and yield stat or None if file does not exist.'
259 lstat = os.lstat
271 lstat = os.lstat
260 for nf in files:
272 for nf in files:
261 try:
273 try:
262 st = lstat(nf)
274 st = lstat(nf)
263 except OSError, err:
275 except OSError, err:
264 if err.errno not in (errno.ENOENT, errno.ENOTDIR):
276 if err.errno not in (errno.ENOENT, errno.ENOTDIR):
265 raise
277 raise
266 st = None
278 st = None
267 yield st
279 yield st
268
280
269 def getuser():
281 def getuser():
270 '''return name of current user'''
282 '''return name of current user'''
271 return getpass.getuser()
283 return getpass.getuser()
272
284
273 def expand_glob(pats):
285 def expand_glob(pats):
274 '''On Windows, expand the implicit globs in a list of patterns'''
286 '''On Windows, expand the implicit globs in a list of patterns'''
275 return list(pats)
287 return list(pats)
276
288
277 def username(uid=None):
289 def username(uid=None):
278 """Return the name of the user with the given uid.
290 """Return the name of the user with the given uid.
279
291
280 If uid is None, return the name of the current user."""
292 If uid is None, return the name of the current user."""
281
293
282 if uid is None:
294 if uid is None:
283 uid = os.getuid()
295 uid = os.getuid()
284 try:
296 try:
285 return pwd.getpwuid(uid)[0]
297 return pwd.getpwuid(uid)[0]
286 except KeyError:
298 except KeyError:
287 return str(uid)
299 return str(uid)
288
300
289 def groupname(gid=None):
301 def groupname(gid=None):
290 """Return the name of the group with the given gid.
302 """Return the name of the group with the given gid.
291
303
292 If gid is None, return the name of the current group."""
304 If gid is None, return the name of the current group."""
293
305
294 if gid is None:
306 if gid is None:
295 gid = os.getgid()
307 gid = os.getgid()
296 try:
308 try:
297 return grp.getgrgid(gid)[0]
309 return grp.getgrgid(gid)[0]
298 except KeyError:
310 except KeyError:
299 return str(gid)
311 return str(gid)
300
312
301 def groupmembers(name):
313 def groupmembers(name):
302 """Return the list of members of the group with the given
314 """Return the list of members of the group with the given
303 name, KeyError if the group does not exist.
315 name, KeyError if the group does not exist.
304 """
316 """
305 return list(grp.getgrnam(name).gr_mem)
317 return list(grp.getgrnam(name).gr_mem)
306
318
307 def spawndetached(args):
319 def spawndetached(args):
308 return os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
320 return os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
309 args[0], args)
321 args[0], args)
310
322
311 def gethgcmd():
323 def gethgcmd():
312 return sys.argv[:1]
324 return sys.argv[:1]
313
325
314 def termwidth():
326 def termwidth():
315 try:
327 try:
316 import termios, array, fcntl
328 import termios, array, fcntl
317 for dev in (sys.stderr, sys.stdout, sys.stdin):
329 for dev in (sys.stderr, sys.stdout, sys.stdin):
318 try:
330 try:
319 try:
331 try:
320 fd = dev.fileno()
332 fd = dev.fileno()
321 except AttributeError:
333 except AttributeError:
322 continue
334 continue
323 if not os.isatty(fd):
335 if not os.isatty(fd):
324 continue
336 continue
325 arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8)
337 arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8)
326 return array.array('h', arri)[1]
338 return array.array('h', arri)[1]
327 except ValueError:
339 except ValueError:
328 pass
340 pass
329 except IOError, e:
341 except IOError, e:
330 if e[0] == errno.EINVAL:
342 if e[0] == errno.EINVAL:
331 pass
343 pass
332 else:
344 else:
333 raise
345 raise
334 except ImportError:
346 except ImportError:
335 pass
347 pass
336 return 80
348 return 80
@@ -1,1543 +1,1531 b''
1 # util.py - Mercurial utility functions and platform specfic implementations
1 # util.py - Mercurial utility functions and platform specfic implementations
2 #
2 #
3 # Copyright 2005 K. Thananchayan <thananck@yahoo.com>
3 # Copyright 2005 K. Thananchayan <thananck@yahoo.com>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 """Mercurial utility functions and platform specfic implementations.
10 """Mercurial utility functions and platform specfic implementations.
11
11
12 This contains helper routines that are independent of the SCM core and
12 This contains helper routines that are independent of the SCM core and
13 hide platform-specific details from the core.
13 hide platform-specific details from the core.
14 """
14 """
15
15
16 from i18n import _
16 from i18n import _
17 import error, osutil, encoding
17 import error, osutil, encoding
18 import errno, re, shutil, sys, tempfile, traceback
18 import errno, re, shutil, sys, tempfile, traceback
19 import os, stat, time, calendar, textwrap, unicodedata, signal
19 import os, stat, time, calendar, textwrap, unicodedata, signal
20 import imp, socket
20 import imp, socket
21
21
22 # Python compatibility
22 # Python compatibility
23
23
24 def sha1(s):
24 def sha1(s):
25 return _fastsha1(s)
25 return _fastsha1(s)
26
26
27 def _fastsha1(s):
27 def _fastsha1(s):
28 # This function will import sha1 from hashlib or sha (whichever is
28 # This function will import sha1 from hashlib or sha (whichever is
29 # available) and overwrite itself with it on the first call.
29 # available) and overwrite itself with it on the first call.
30 # Subsequent calls will go directly to the imported function.
30 # Subsequent calls will go directly to the imported function.
31 if sys.version_info >= (2, 5):
31 if sys.version_info >= (2, 5):
32 from hashlib import sha1 as _sha1
32 from hashlib import sha1 as _sha1
33 else:
33 else:
34 from sha import sha as _sha1
34 from sha import sha as _sha1
35 global _fastsha1, sha1
35 global _fastsha1, sha1
36 _fastsha1 = sha1 = _sha1
36 _fastsha1 = sha1 = _sha1
37 return _sha1(s)
37 return _sha1(s)
38
38
39 import __builtin__
39 import __builtin__
40
40
41 if sys.version_info[0] < 3:
41 if sys.version_info[0] < 3:
42 def fakebuffer(sliceable, offset=0):
42 def fakebuffer(sliceable, offset=0):
43 return sliceable[offset:]
43 return sliceable[offset:]
44 else:
44 else:
45 def fakebuffer(sliceable, offset=0):
45 def fakebuffer(sliceable, offset=0):
46 return memoryview(sliceable)[offset:]
46 return memoryview(sliceable)[offset:]
47 try:
47 try:
48 buffer
48 buffer
49 except NameError:
49 except NameError:
50 __builtin__.buffer = fakebuffer
50 __builtin__.buffer = fakebuffer
51
51
52 import subprocess
52 import subprocess
53 closefds = os.name == 'posix'
53 closefds = os.name == 'posix'
54
54
55 def popen2(cmd, env=None, newlines=False):
55 def popen2(cmd, env=None, newlines=False):
56 # Setting bufsize to -1 lets the system decide the buffer size.
56 # Setting bufsize to -1 lets the system decide the buffer size.
57 # The default for bufsize is 0, meaning unbuffered. This leads to
57 # The default for bufsize is 0, meaning unbuffered. This leads to
58 # poor performance on Mac OS X: http://bugs.python.org/issue4194
58 # poor performance on Mac OS X: http://bugs.python.org/issue4194
59 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
59 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
60 close_fds=closefds,
60 close_fds=closefds,
61 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
61 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
62 universal_newlines=newlines,
62 universal_newlines=newlines,
63 env=env)
63 env=env)
64 return p.stdin, p.stdout
64 return p.stdin, p.stdout
65
65
66 def popen3(cmd, env=None, newlines=False):
66 def popen3(cmd, env=None, newlines=False):
67 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
67 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
68 close_fds=closefds,
68 close_fds=closefds,
69 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
69 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
70 stderr=subprocess.PIPE,
70 stderr=subprocess.PIPE,
71 universal_newlines=newlines,
71 universal_newlines=newlines,
72 env=env)
72 env=env)
73 return p.stdin, p.stdout, p.stderr
73 return p.stdin, p.stdout, p.stderr
74
74
75 def version():
75 def version():
76 """Return version information if available."""
76 """Return version information if available."""
77 try:
77 try:
78 import __version__
78 import __version__
79 return __version__.version
79 return __version__.version
80 except ImportError:
80 except ImportError:
81 return 'unknown'
81 return 'unknown'
82
82
83 # used by parsedate
83 # used by parsedate
84 defaultdateformats = (
84 defaultdateformats = (
85 '%Y-%m-%d %H:%M:%S',
85 '%Y-%m-%d %H:%M:%S',
86 '%Y-%m-%d %I:%M:%S%p',
86 '%Y-%m-%d %I:%M:%S%p',
87 '%Y-%m-%d %H:%M',
87 '%Y-%m-%d %H:%M',
88 '%Y-%m-%d %I:%M%p',
88 '%Y-%m-%d %I:%M%p',
89 '%Y-%m-%d',
89 '%Y-%m-%d',
90 '%m-%d',
90 '%m-%d',
91 '%m/%d',
91 '%m/%d',
92 '%m/%d/%y',
92 '%m/%d/%y',
93 '%m/%d/%Y',
93 '%m/%d/%Y',
94 '%a %b %d %H:%M:%S %Y',
94 '%a %b %d %H:%M:%S %Y',
95 '%a %b %d %I:%M:%S%p %Y',
95 '%a %b %d %I:%M:%S%p %Y',
96 '%a, %d %b %Y %H:%M:%S', # GNU coreutils "/bin/date --rfc-2822"
96 '%a, %d %b %Y %H:%M:%S', # GNU coreutils "/bin/date --rfc-2822"
97 '%b %d %H:%M:%S %Y',
97 '%b %d %H:%M:%S %Y',
98 '%b %d %I:%M:%S%p %Y',
98 '%b %d %I:%M:%S%p %Y',
99 '%b %d %H:%M:%S',
99 '%b %d %H:%M:%S',
100 '%b %d %I:%M:%S%p',
100 '%b %d %I:%M:%S%p',
101 '%b %d %H:%M',
101 '%b %d %H:%M',
102 '%b %d %I:%M%p',
102 '%b %d %I:%M%p',
103 '%b %d %Y',
103 '%b %d %Y',
104 '%b %d',
104 '%b %d',
105 '%H:%M:%S',
105 '%H:%M:%S',
106 '%I:%M:%S%p',
106 '%I:%M:%S%p',
107 '%H:%M',
107 '%H:%M',
108 '%I:%M%p',
108 '%I:%M%p',
109 )
109 )
110
110
111 extendeddateformats = defaultdateformats + (
111 extendeddateformats = defaultdateformats + (
112 "%Y",
112 "%Y",
113 "%Y-%m",
113 "%Y-%m",
114 "%b",
114 "%b",
115 "%b %Y",
115 "%b %Y",
116 )
116 )
117
117
118 def cachefunc(func):
118 def cachefunc(func):
119 '''cache the result of function calls'''
119 '''cache the result of function calls'''
120 # XXX doesn't handle keywords args
120 # XXX doesn't handle keywords args
121 cache = {}
121 cache = {}
122 if func.func_code.co_argcount == 1:
122 if func.func_code.co_argcount == 1:
123 # we gain a small amount of time because
123 # we gain a small amount of time because
124 # we don't need to pack/unpack the list
124 # we don't need to pack/unpack the list
125 def f(arg):
125 def f(arg):
126 if arg not in cache:
126 if arg not in cache:
127 cache[arg] = func(arg)
127 cache[arg] = func(arg)
128 return cache[arg]
128 return cache[arg]
129 else:
129 else:
130 def f(*args):
130 def f(*args):
131 if args not in cache:
131 if args not in cache:
132 cache[args] = func(*args)
132 cache[args] = func(*args)
133 return cache[args]
133 return cache[args]
134
134
135 return f
135 return f
136
136
137 def lrucachefunc(func):
137 def lrucachefunc(func):
138 '''cache most recent results of function calls'''
138 '''cache most recent results of function calls'''
139 cache = {}
139 cache = {}
140 order = []
140 order = []
141 if func.func_code.co_argcount == 1:
141 if func.func_code.co_argcount == 1:
142 def f(arg):
142 def f(arg):
143 if arg not in cache:
143 if arg not in cache:
144 if len(cache) > 20:
144 if len(cache) > 20:
145 del cache[order.pop(0)]
145 del cache[order.pop(0)]
146 cache[arg] = func(arg)
146 cache[arg] = func(arg)
147 else:
147 else:
148 order.remove(arg)
148 order.remove(arg)
149 order.append(arg)
149 order.append(arg)
150 return cache[arg]
150 return cache[arg]
151 else:
151 else:
152 def f(*args):
152 def f(*args):
153 if args not in cache:
153 if args not in cache:
154 if len(cache) > 20:
154 if len(cache) > 20:
155 del cache[order.pop(0)]
155 del cache[order.pop(0)]
156 cache[args] = func(*args)
156 cache[args] = func(*args)
157 else:
157 else:
158 order.remove(args)
158 order.remove(args)
159 order.append(args)
159 order.append(args)
160 return cache[args]
160 return cache[args]
161
161
162 return f
162 return f
163
163
164 class propertycache(object):
164 class propertycache(object):
165 def __init__(self, func):
165 def __init__(self, func):
166 self.func = func
166 self.func = func
167 self.name = func.__name__
167 self.name = func.__name__
168 def __get__(self, obj, type=None):
168 def __get__(self, obj, type=None):
169 result = self.func(obj)
169 result = self.func(obj)
170 setattr(obj, self.name, result)
170 setattr(obj, self.name, result)
171 return result
171 return result
172
172
173 def pipefilter(s, cmd):
173 def pipefilter(s, cmd):
174 '''filter string S through command CMD, returning its output'''
174 '''filter string S through command CMD, returning its output'''
175 p = subprocess.Popen(cmd, shell=True, close_fds=closefds,
175 p = subprocess.Popen(cmd, shell=True, close_fds=closefds,
176 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
176 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
177 pout, perr = p.communicate(s)
177 pout, perr = p.communicate(s)
178 return pout
178 return pout
179
179
180 def tempfilter(s, cmd):
180 def tempfilter(s, cmd):
181 '''filter string S through a pair of temporary files with CMD.
181 '''filter string S through a pair of temporary files with CMD.
182 CMD is used as a template to create the real command to be run,
182 CMD is used as a template to create the real command to be run,
183 with the strings INFILE and OUTFILE replaced by the real names of
183 with the strings INFILE and OUTFILE replaced by the real names of
184 the temporary files generated.'''
184 the temporary files generated.'''
185 inname, outname = None, None
185 inname, outname = None, None
186 try:
186 try:
187 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
187 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
188 fp = os.fdopen(infd, 'wb')
188 fp = os.fdopen(infd, 'wb')
189 fp.write(s)
189 fp.write(s)
190 fp.close()
190 fp.close()
191 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
191 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
192 os.close(outfd)
192 os.close(outfd)
193 cmd = cmd.replace('INFILE', inname)
193 cmd = cmd.replace('INFILE', inname)
194 cmd = cmd.replace('OUTFILE', outname)
194 cmd = cmd.replace('OUTFILE', outname)
195 code = os.system(cmd)
195 code = os.system(cmd)
196 if sys.platform == 'OpenVMS' and code & 1:
196 if sys.platform == 'OpenVMS' and code & 1:
197 code = 0
197 code = 0
198 if code:
198 if code:
199 raise Abort(_("command '%s' failed: %s") %
199 raise Abort(_("command '%s' failed: %s") %
200 (cmd, explain_exit(code)))
200 (cmd, explain_exit(code)))
201 fp = open(outname, 'rb')
201 fp = open(outname, 'rb')
202 r = fp.read()
202 r = fp.read()
203 fp.close()
203 fp.close()
204 return r
204 return r
205 finally:
205 finally:
206 try:
206 try:
207 if inname:
207 if inname:
208 os.unlink(inname)
208 os.unlink(inname)
209 except:
209 except:
210 pass
210 pass
211 try:
211 try:
212 if outname:
212 if outname:
213 os.unlink(outname)
213 os.unlink(outname)
214 except:
214 except:
215 pass
215 pass
216
216
217 filtertable = {
217 filtertable = {
218 'tempfile:': tempfilter,
218 'tempfile:': tempfilter,
219 'pipe:': pipefilter,
219 'pipe:': pipefilter,
220 }
220 }
221
221
222 def filter(s, cmd):
222 def filter(s, cmd):
223 "filter a string through a command that transforms its input to its output"
223 "filter a string through a command that transforms its input to its output"
224 for name, fn in filtertable.iteritems():
224 for name, fn in filtertable.iteritems():
225 if cmd.startswith(name):
225 if cmd.startswith(name):
226 return fn(s, cmd[len(name):].lstrip())
226 return fn(s, cmd[len(name):].lstrip())
227 return pipefilter(s, cmd)
227 return pipefilter(s, cmd)
228
228
229 def binary(s):
229 def binary(s):
230 """return true if a string is binary data"""
230 """return true if a string is binary data"""
231 return bool(s and '\0' in s)
231 return bool(s and '\0' in s)
232
232
233 def increasingchunks(source, min=1024, max=65536):
233 def increasingchunks(source, min=1024, max=65536):
234 '''return no less than min bytes per chunk while data remains,
234 '''return no less than min bytes per chunk while data remains,
235 doubling min after each chunk until it reaches max'''
235 doubling min after each chunk until it reaches max'''
236 def log2(x):
236 def log2(x):
237 if not x:
237 if not x:
238 return 0
238 return 0
239 i = 0
239 i = 0
240 while x:
240 while x:
241 x >>= 1
241 x >>= 1
242 i += 1
242 i += 1
243 return i - 1
243 return i - 1
244
244
245 buf = []
245 buf = []
246 blen = 0
246 blen = 0
247 for chunk in source:
247 for chunk in source:
248 buf.append(chunk)
248 buf.append(chunk)
249 blen += len(chunk)
249 blen += len(chunk)
250 if blen >= min:
250 if blen >= min:
251 if min < max:
251 if min < max:
252 min = min << 1
252 min = min << 1
253 nmin = 1 << log2(blen)
253 nmin = 1 << log2(blen)
254 if nmin > min:
254 if nmin > min:
255 min = nmin
255 min = nmin
256 if min > max:
256 if min > max:
257 min = max
257 min = max
258 yield ''.join(buf)
258 yield ''.join(buf)
259 blen = 0
259 blen = 0
260 buf = []
260 buf = []
261 if buf:
261 if buf:
262 yield ''.join(buf)
262 yield ''.join(buf)
263
263
264 Abort = error.Abort
264 Abort = error.Abort
265
265
266 def always(fn):
266 def always(fn):
267 return True
267 return True
268
268
269 def never(fn):
269 def never(fn):
270 return False
270 return False
271
271
272 def pathto(root, n1, n2):
272 def pathto(root, n1, n2):
273 '''return the relative path from one place to another.
273 '''return the relative path from one place to another.
274 root should use os.sep to separate directories
274 root should use os.sep to separate directories
275 n1 should use os.sep to separate directories
275 n1 should use os.sep to separate directories
276 n2 should use "/" to separate directories
276 n2 should use "/" to separate directories
277 returns an os.sep-separated path.
277 returns an os.sep-separated path.
278
278
279 If n1 is a relative path, it's assumed it's
279 If n1 is a relative path, it's assumed it's
280 relative to root.
280 relative to root.
281 n2 should always be relative to root.
281 n2 should always be relative to root.
282 '''
282 '''
283 if not n1:
283 if not n1:
284 return localpath(n2)
284 return localpath(n2)
285 if os.path.isabs(n1):
285 if os.path.isabs(n1):
286 if os.path.splitdrive(root)[0] != os.path.splitdrive(n1)[0]:
286 if os.path.splitdrive(root)[0] != os.path.splitdrive(n1)[0]:
287 return os.path.join(root, localpath(n2))
287 return os.path.join(root, localpath(n2))
288 n2 = '/'.join((pconvert(root), n2))
288 n2 = '/'.join((pconvert(root), n2))
289 a, b = splitpath(n1), n2.split('/')
289 a, b = splitpath(n1), n2.split('/')
290 a.reverse()
290 a.reverse()
291 b.reverse()
291 b.reverse()
292 while a and b and a[-1] == b[-1]:
292 while a and b and a[-1] == b[-1]:
293 a.pop()
293 a.pop()
294 b.pop()
294 b.pop()
295 b.reverse()
295 b.reverse()
296 return os.sep.join((['..'] * len(a)) + b) or '.'
296 return os.sep.join((['..'] * len(a)) + b) or '.'
297
297
298 def canonpath(root, cwd, myname, auditor=None):
298 def canonpath(root, cwd, myname, auditor=None):
299 """return the canonical path of myname, given cwd and root"""
299 """return the canonical path of myname, given cwd and root"""
300 if endswithsep(root):
300 if endswithsep(root):
301 rootsep = root
301 rootsep = root
302 else:
302 else:
303 rootsep = root + os.sep
303 rootsep = root + os.sep
304 name = myname
304 name = myname
305 if not os.path.isabs(name):
305 if not os.path.isabs(name):
306 name = os.path.join(root, cwd, name)
306 name = os.path.join(root, cwd, name)
307 name = os.path.normpath(name)
307 name = os.path.normpath(name)
308 if auditor is None:
308 if auditor is None:
309 auditor = path_auditor(root)
309 auditor = path_auditor(root)
310 if name != rootsep and name.startswith(rootsep):
310 if name != rootsep and name.startswith(rootsep):
311 name = name[len(rootsep):]
311 name = name[len(rootsep):]
312 auditor(name)
312 auditor(name)
313 return pconvert(name)
313 return pconvert(name)
314 elif name == root:
314 elif name == root:
315 return ''
315 return ''
316 else:
316 else:
317 # Determine whether `name' is in the hierarchy at or beneath `root',
317 # Determine whether `name' is in the hierarchy at or beneath `root',
318 # by iterating name=dirname(name) until that causes no change (can't
318 # by iterating name=dirname(name) until that causes no change (can't
319 # check name == '/', because that doesn't work on windows). For each
319 # check name == '/', because that doesn't work on windows). For each
320 # `name', compare dev/inode numbers. If they match, the list `rel'
320 # `name', compare dev/inode numbers. If they match, the list `rel'
321 # holds the reversed list of components making up the relative file
321 # holds the reversed list of components making up the relative file
322 # name we want.
322 # name we want.
323 root_st = os.stat(root)
323 root_st = os.stat(root)
324 rel = []
324 rel = []
325 while True:
325 while True:
326 try:
326 try:
327 name_st = os.stat(name)
327 name_st = os.stat(name)
328 except OSError:
328 except OSError:
329 break
329 break
330 if samestat(name_st, root_st):
330 if samestat(name_st, root_st):
331 if not rel:
331 if not rel:
332 # name was actually the same as root (maybe a symlink)
332 # name was actually the same as root (maybe a symlink)
333 return ''
333 return ''
334 rel.reverse()
334 rel.reverse()
335 name = os.path.join(*rel)
335 name = os.path.join(*rel)
336 auditor(name)
336 auditor(name)
337 return pconvert(name)
337 return pconvert(name)
338 dirname, basename = os.path.split(name)
338 dirname, basename = os.path.split(name)
339 rel.append(basename)
339 rel.append(basename)
340 if dirname == name:
340 if dirname == name:
341 break
341 break
342 name = dirname
342 name = dirname
343
343
344 raise Abort('%s not under root' % myname)
344 raise Abort('%s not under root' % myname)
345
345
346 _hgexecutable = None
346 _hgexecutable = None
347
347
348 def main_is_frozen():
348 def main_is_frozen():
349 """return True if we are a frozen executable.
349 """return True if we are a frozen executable.
350
350
351 The code supports py2exe (most common, Windows only) and tools/freeze
351 The code supports py2exe (most common, Windows only) and tools/freeze
352 (portable, not much used).
352 (portable, not much used).
353 """
353 """
354 return (hasattr(sys, "frozen") or # new py2exe
354 return (hasattr(sys, "frozen") or # new py2exe
355 hasattr(sys, "importers") or # old py2exe
355 hasattr(sys, "importers") or # old py2exe
356 imp.is_frozen("__main__")) # tools/freeze
356 imp.is_frozen("__main__")) # tools/freeze
357
357
358 def hgexecutable():
358 def hgexecutable():
359 """return location of the 'hg' executable.
359 """return location of the 'hg' executable.
360
360
361 Defaults to $HG or 'hg' in the search path.
361 Defaults to $HG or 'hg' in the search path.
362 """
362 """
363 if _hgexecutable is None:
363 if _hgexecutable is None:
364 hg = os.environ.get('HG')
364 hg = os.environ.get('HG')
365 if hg:
365 if hg:
366 set_hgexecutable(hg)
366 set_hgexecutable(hg)
367 elif main_is_frozen():
367 elif main_is_frozen():
368 set_hgexecutable(sys.executable)
368 set_hgexecutable(sys.executable)
369 else:
369 else:
370 exe = find_exe('hg') or os.path.basename(sys.argv[0])
370 exe = find_exe('hg') or os.path.basename(sys.argv[0])
371 set_hgexecutable(exe)
371 set_hgexecutable(exe)
372 return _hgexecutable
372 return _hgexecutable
373
373
374 def set_hgexecutable(path):
374 def set_hgexecutable(path):
375 """set location of the 'hg' executable"""
375 """set location of the 'hg' executable"""
376 global _hgexecutable
376 global _hgexecutable
377 _hgexecutable = path
377 _hgexecutable = path
378
378
379 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None, out=None):
379 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None, out=None):
380 '''enhanced shell command execution.
380 '''enhanced shell command execution.
381 run with environment maybe modified, maybe in different dir.
381 run with environment maybe modified, maybe in different dir.
382
382
383 if command fails and onerr is None, return status. if ui object,
383 if command fails and onerr is None, return status. if ui object,
384 print error message and return status, else raise onerr object as
384 print error message and return status, else raise onerr object as
385 exception.
385 exception.
386
386
387 if out is specified, it is assumed to be a file-like object that has a
387 if out is specified, it is assumed to be a file-like object that has a
388 write() method. stdout and stderr will be redirected to out.'''
388 write() method. stdout and stderr will be redirected to out.'''
389 try:
389 try:
390 sys.stdout.flush()
390 sys.stdout.flush()
391 except Exception:
391 except Exception:
392 pass
392 pass
393 def py2shell(val):
393 def py2shell(val):
394 'convert python object into string that is useful to shell'
394 'convert python object into string that is useful to shell'
395 if val is None or val is False:
395 if val is None or val is False:
396 return '0'
396 return '0'
397 if val is True:
397 if val is True:
398 return '1'
398 return '1'
399 return str(val)
399 return str(val)
400 origcmd = cmd
400 origcmd = cmd
401 cmd = quotecommand(cmd)
401 cmd = quotecommand(cmd)
402 env = dict(os.environ)
402 env = dict(os.environ)
403 env.update((k, py2shell(v)) for k, v in environ.iteritems())
403 env.update((k, py2shell(v)) for k, v in environ.iteritems())
404 env['HG'] = hgexecutable()
404 env['HG'] = hgexecutable()
405 if out is None:
405 if out is None:
406 rc = subprocess.call(cmd, shell=True, close_fds=closefds,
406 rc = subprocess.call(cmd, shell=True, close_fds=closefds,
407 env=env, cwd=cwd)
407 env=env, cwd=cwd)
408 else:
408 else:
409 proc = subprocess.Popen(cmd, shell=True, close_fds=closefds,
409 proc = subprocess.Popen(cmd, shell=True, close_fds=closefds,
410 env=env, cwd=cwd, stdout=subprocess.PIPE,
410 env=env, cwd=cwd, stdout=subprocess.PIPE,
411 stderr=subprocess.STDOUT)
411 stderr=subprocess.STDOUT)
412 for line in proc.stdout:
412 for line in proc.stdout:
413 out.write(line)
413 out.write(line)
414 proc.wait()
414 proc.wait()
415 rc = proc.returncode
415 rc = proc.returncode
416 if sys.platform == 'OpenVMS' and rc & 1:
416 if sys.platform == 'OpenVMS' and rc & 1:
417 rc = 0
417 rc = 0
418 if rc and onerr:
418 if rc and onerr:
419 errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
419 errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
420 explain_exit(rc)[0])
420 explain_exit(rc)[0])
421 if errprefix:
421 if errprefix:
422 errmsg = '%s: %s' % (errprefix, errmsg)
422 errmsg = '%s: %s' % (errprefix, errmsg)
423 try:
423 try:
424 onerr.warn(errmsg + '\n')
424 onerr.warn(errmsg + '\n')
425 except AttributeError:
425 except AttributeError:
426 raise onerr(errmsg)
426 raise onerr(errmsg)
427 return rc
427 return rc
428
428
429 def checksignature(func):
429 def checksignature(func):
430 '''wrap a function with code to check for calling errors'''
430 '''wrap a function with code to check for calling errors'''
431 def check(*args, **kwargs):
431 def check(*args, **kwargs):
432 try:
432 try:
433 return func(*args, **kwargs)
433 return func(*args, **kwargs)
434 except TypeError:
434 except TypeError:
435 if len(traceback.extract_tb(sys.exc_info()[2])) == 1:
435 if len(traceback.extract_tb(sys.exc_info()[2])) == 1:
436 raise error.SignatureError
436 raise error.SignatureError
437 raise
437 raise
438
438
439 return check
439 return check
440
440
441 def makedir(path, notindexed):
441 def makedir(path, notindexed):
442 os.mkdir(path)
442 os.mkdir(path)
443
443
444 def unlinkpath(f):
444 def unlinkpath(f):
445 """unlink and remove the directory if it is empty"""
445 """unlink and remove the directory if it is empty"""
446 os.unlink(f)
446 os.unlink(f)
447 # try removing directories that might now be empty
447 # try removing directories that might now be empty
448 try:
448 try:
449 os.removedirs(os.path.dirname(f))
449 os.removedirs(os.path.dirname(f))
450 except OSError:
450 except OSError:
451 pass
451 pass
452
452
453 def copyfile(src, dest):
453 def copyfile(src, dest):
454 "copy a file, preserving mode and atime/mtime"
454 "copy a file, preserving mode and atime/mtime"
455 if os.path.islink(src):
455 if os.path.islink(src):
456 try:
456 try:
457 os.unlink(dest)
457 os.unlink(dest)
458 except:
458 except:
459 pass
459 pass
460 os.symlink(os.readlink(src), dest)
460 os.symlink(os.readlink(src), dest)
461 else:
461 else:
462 try:
462 try:
463 shutil.copyfile(src, dest)
463 shutil.copyfile(src, dest)
464 shutil.copymode(src, dest)
464 shutil.copymode(src, dest)
465 except shutil.Error, inst:
465 except shutil.Error, inst:
466 raise Abort(str(inst))
466 raise Abort(str(inst))
467
467
468 def copyfiles(src, dst, hardlink=None):
468 def copyfiles(src, dst, hardlink=None):
469 """Copy a directory tree using hardlinks if possible"""
469 """Copy a directory tree using hardlinks if possible"""
470
470
471 if hardlink is None:
471 if hardlink is None:
472 hardlink = (os.stat(src).st_dev ==
472 hardlink = (os.stat(src).st_dev ==
473 os.stat(os.path.dirname(dst)).st_dev)
473 os.stat(os.path.dirname(dst)).st_dev)
474
474
475 num = 0
475 num = 0
476 if os.path.isdir(src):
476 if os.path.isdir(src):
477 os.mkdir(dst)
477 os.mkdir(dst)
478 for name, kind in osutil.listdir(src):
478 for name, kind in osutil.listdir(src):
479 srcname = os.path.join(src, name)
479 srcname = os.path.join(src, name)
480 dstname = os.path.join(dst, name)
480 dstname = os.path.join(dst, name)
481 hardlink, n = copyfiles(srcname, dstname, hardlink)
481 hardlink, n = copyfiles(srcname, dstname, hardlink)
482 num += n
482 num += n
483 else:
483 else:
484 if hardlink:
484 if hardlink:
485 try:
485 try:
486 os_link(src, dst)
486 os_link(src, dst)
487 except (IOError, OSError):
487 except (IOError, OSError):
488 hardlink = False
488 hardlink = False
489 shutil.copy(src, dst)
489 shutil.copy(src, dst)
490 else:
490 else:
491 shutil.copy(src, dst)
491 shutil.copy(src, dst)
492 num += 1
492 num += 1
493
493
494 return hardlink, num
494 return hardlink, num
495
495
496 class path_auditor(object):
496 class path_auditor(object):
497 '''ensure that a filesystem path contains no banned components.
497 '''ensure that a filesystem path contains no banned components.
498 the following properties of a path are checked:
498 the following properties of a path are checked:
499
499
500 - ends with a directory separator
500 - ends with a directory separator
501 - under top-level .hg
501 - under top-level .hg
502 - starts at the root of a windows drive
502 - starts at the root of a windows drive
503 - contains ".."
503 - contains ".."
504 - traverses a symlink (e.g. a/symlink_here/b)
504 - traverses a symlink (e.g. a/symlink_here/b)
505 - inside a nested repository (a callback can be used to approve
505 - inside a nested repository (a callback can be used to approve
506 some nested repositories, e.g., subrepositories)
506 some nested repositories, e.g., subrepositories)
507 '''
507 '''
508
508
509 def __init__(self, root, callback=None):
509 def __init__(self, root, callback=None):
510 self.audited = set()
510 self.audited = set()
511 self.auditeddir = set()
511 self.auditeddir = set()
512 self.root = root
512 self.root = root
513 self.callback = callback
513 self.callback = callback
514
514
515 def __call__(self, path):
515 def __call__(self, path):
516 if path in self.audited:
516 if path in self.audited:
517 return
517 return
518 # AIX ignores "/" at end of path, others raise EISDIR.
518 # AIX ignores "/" at end of path, others raise EISDIR.
519 if endswithsep(path):
519 if endswithsep(path):
520 raise Abort(_("path ends in directory separator: %s") % path)
520 raise Abort(_("path ends in directory separator: %s") % path)
521 normpath = os.path.normcase(path)
521 normpath = os.path.normcase(path)
522 parts = splitpath(normpath)
522 parts = splitpath(normpath)
523 if (os.path.splitdrive(path)[0]
523 if (os.path.splitdrive(path)[0]
524 or parts[0].lower() in ('.hg', '.hg.', '')
524 or parts[0].lower() in ('.hg', '.hg.', '')
525 or os.pardir in parts):
525 or os.pardir in parts):
526 raise Abort(_("path contains illegal component: %s") % path)
526 raise Abort(_("path contains illegal component: %s") % path)
527 if '.hg' in path.lower():
527 if '.hg' in path.lower():
528 lparts = [p.lower() for p in parts]
528 lparts = [p.lower() for p in parts]
529 for p in '.hg', '.hg.':
529 for p in '.hg', '.hg.':
530 if p in lparts[1:]:
530 if p in lparts[1:]:
531 pos = lparts.index(p)
531 pos = lparts.index(p)
532 base = os.path.join(*parts[:pos])
532 base = os.path.join(*parts[:pos])
533 raise Abort(_('path %r is inside repo %r') % (path, base))
533 raise Abort(_('path %r is inside repo %r') % (path, base))
534 def check(prefix):
534 def check(prefix):
535 curpath = os.path.join(self.root, prefix)
535 curpath = os.path.join(self.root, prefix)
536 try:
536 try:
537 st = os.lstat(curpath)
537 st = os.lstat(curpath)
538 except OSError, err:
538 except OSError, err:
539 # EINVAL can be raised as invalid path syntax under win32.
539 # EINVAL can be raised as invalid path syntax under win32.
540 # They must be ignored for patterns can be checked too.
540 # They must be ignored for patterns can be checked too.
541 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
541 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
542 raise
542 raise
543 else:
543 else:
544 if stat.S_ISLNK(st.st_mode):
544 if stat.S_ISLNK(st.st_mode):
545 raise Abort(_('path %r traverses symbolic link %r') %
545 raise Abort(_('path %r traverses symbolic link %r') %
546 (path, prefix))
546 (path, prefix))
547 elif (stat.S_ISDIR(st.st_mode) and
547 elif (stat.S_ISDIR(st.st_mode) and
548 os.path.isdir(os.path.join(curpath, '.hg'))):
548 os.path.isdir(os.path.join(curpath, '.hg'))):
549 if not self.callback or not self.callback(curpath):
549 if not self.callback or not self.callback(curpath):
550 raise Abort(_('path %r is inside repo %r') %
550 raise Abort(_('path %r is inside repo %r') %
551 (path, prefix))
551 (path, prefix))
552 parts.pop()
552 parts.pop()
553 prefixes = []
553 prefixes = []
554 while parts:
554 while parts:
555 prefix = os.sep.join(parts)
555 prefix = os.sep.join(parts)
556 if prefix in self.auditeddir:
556 if prefix in self.auditeddir:
557 break
557 break
558 check(prefix)
558 check(prefix)
559 prefixes.append(prefix)
559 prefixes.append(prefix)
560 parts.pop()
560 parts.pop()
561
561
562 self.audited.add(path)
562 self.audited.add(path)
563 # only add prefixes to the cache after checking everything: we don't
563 # only add prefixes to the cache after checking everything: we don't
564 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
564 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
565 self.auditeddir.update(prefixes)
565 self.auditeddir.update(prefixes)
566
566
567 def lookup_reg(key, name=None, scope=None):
567 def lookup_reg(key, name=None, scope=None):
568 return None
568 return None
569
569
570 def hidewindow():
570 def hidewindow():
571 """Hide current shell window.
571 """Hide current shell window.
572
572
573 Used to hide the window opened when starting asynchronous
573 Used to hide the window opened when starting asynchronous
574 child process under Windows, unneeded on other systems.
574 child process under Windows, unneeded on other systems.
575 """
575 """
576 pass
576 pass
577
577
578 if os.name == 'nt':
578 if os.name == 'nt':
579 from windows import *
579 from windows import *
580 else:
580 else:
581 from posix import *
581 from posix import *
582
582
583 def makelock(info, pathname):
583 def makelock(info, pathname):
584 try:
584 try:
585 return os.symlink(info, pathname)
585 return os.symlink(info, pathname)
586 except OSError, why:
586 except OSError, why:
587 if why.errno == errno.EEXIST:
587 if why.errno == errno.EEXIST:
588 raise
588 raise
589 except AttributeError: # no symlink in os
589 except AttributeError: # no symlink in os
590 pass
590 pass
591
591
592 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
592 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
593 os.write(ld, info)
593 os.write(ld, info)
594 os.close(ld)
594 os.close(ld)
595
595
596 def readlock(pathname):
596 def readlock(pathname):
597 try:
597 try:
598 return os.readlink(pathname)
598 return os.readlink(pathname)
599 except OSError, why:
599 except OSError, why:
600 if why.errno not in (errno.EINVAL, errno.ENOSYS):
600 if why.errno not in (errno.EINVAL, errno.ENOSYS):
601 raise
601 raise
602 except AttributeError: # no symlink in os
602 except AttributeError: # no symlink in os
603 pass
603 pass
604 fp = posixfile(pathname)
604 fp = posixfile(pathname)
605 r = fp.read()
605 r = fp.read()
606 fp.close()
606 fp.close()
607 return r
607 return r
608
608
609 def fstat(fp):
609 def fstat(fp):
610 '''stat file object that may not have fileno method.'''
610 '''stat file object that may not have fileno method.'''
611 try:
611 try:
612 return os.fstat(fp.fileno())
612 return os.fstat(fp.fileno())
613 except AttributeError:
613 except AttributeError:
614 return os.stat(fp.name)
614 return os.stat(fp.name)
615
615
616 # File system features
616 # File system features
617
617
618 def checkcase(path):
618 def checkcase(path):
619 """
619 """
620 Check whether the given path is on a case-sensitive filesystem
620 Check whether the given path is on a case-sensitive filesystem
621
621
622 Requires a path (like /foo/.hg) ending with a foldable final
622 Requires a path (like /foo/.hg) ending with a foldable final
623 directory component.
623 directory component.
624 """
624 """
625 s1 = os.stat(path)
625 s1 = os.stat(path)
626 d, b = os.path.split(path)
626 d, b = os.path.split(path)
627 p2 = os.path.join(d, b.upper())
627 p2 = os.path.join(d, b.upper())
628 if path == p2:
628 if path == p2:
629 p2 = os.path.join(d, b.lower())
629 p2 = os.path.join(d, b.lower())
630 try:
630 try:
631 s2 = os.stat(p2)
631 s2 = os.stat(p2)
632 if s2 == s1:
632 if s2 == s1:
633 return False
633 return False
634 return True
634 return True
635 except:
635 except:
636 return True
636 return True
637
637
638 _fspathcache = {}
638 _fspathcache = {}
639 def fspath(name, root):
639 def fspath(name, root):
640 '''Get name in the case stored in the filesystem
640 '''Get name in the case stored in the filesystem
641
641
642 The name is either relative to root, or it is an absolute path starting
642 The name is either relative to root, or it is an absolute path starting
643 with root. Note that this function is unnecessary, and should not be
643 with root. Note that this function is unnecessary, and should not be
644 called, for case-sensitive filesystems (simply because it's expensive).
644 called, for case-sensitive filesystems (simply because it's expensive).
645 '''
645 '''
646 # If name is absolute, make it relative
646 # If name is absolute, make it relative
647 if name.lower().startswith(root.lower()):
647 if name.lower().startswith(root.lower()):
648 l = len(root)
648 l = len(root)
649 if name[l] == os.sep or name[l] == os.altsep:
649 if name[l] == os.sep or name[l] == os.altsep:
650 l = l + 1
650 l = l + 1
651 name = name[l:]
651 name = name[l:]
652
652
653 if not os.path.lexists(os.path.join(root, name)):
653 if not os.path.lexists(os.path.join(root, name)):
654 return None
654 return None
655
655
656 seps = os.sep
656 seps = os.sep
657 if os.altsep:
657 if os.altsep:
658 seps = seps + os.altsep
658 seps = seps + os.altsep
659 # Protect backslashes. This gets silly very quickly.
659 # Protect backslashes. This gets silly very quickly.
660 seps.replace('\\','\\\\')
660 seps.replace('\\','\\\\')
661 pattern = re.compile(r'([^%s]+)|([%s]+)' % (seps, seps))
661 pattern = re.compile(r'([^%s]+)|([%s]+)' % (seps, seps))
662 dir = os.path.normcase(os.path.normpath(root))
662 dir = os.path.normcase(os.path.normpath(root))
663 result = []
663 result = []
664 for part, sep in pattern.findall(name):
664 for part, sep in pattern.findall(name):
665 if sep:
665 if sep:
666 result.append(sep)
666 result.append(sep)
667 continue
667 continue
668
668
669 if dir not in _fspathcache:
669 if dir not in _fspathcache:
670 _fspathcache[dir] = os.listdir(dir)
670 _fspathcache[dir] = os.listdir(dir)
671 contents = _fspathcache[dir]
671 contents = _fspathcache[dir]
672
672
673 lpart = part.lower()
673 lpart = part.lower()
674 lenp = len(part)
674 lenp = len(part)
675 for n in contents:
675 for n in contents:
676 if lenp == len(n) and n.lower() == lpart:
676 if lenp == len(n) and n.lower() == lpart:
677 result.append(n)
677 result.append(n)
678 break
678 break
679 else:
679 else:
680 # Cannot happen, as the file exists!
680 # Cannot happen, as the file exists!
681 result.append(part)
681 result.append(part)
682 dir = os.path.join(dir, lpart)
682 dir = os.path.join(dir, lpart)
683
683
684 return ''.join(result)
684 return ''.join(result)
685
685
686 def checklink(path):
687 """check whether the given path is on a symlink-capable filesystem"""
688 # mktemp is not racy because symlink creation will fail if the
689 # file already exists
690 name = tempfile.mktemp(dir=path, prefix='hg-checklink-')
691 try:
692 os.symlink(".", name)
693 os.unlink(name)
694 return True
695 except (OSError, AttributeError):
696 return False
697
698 def checknlink(testfile):
686 def checknlink(testfile):
699 '''check whether hardlink count reporting works properly'''
687 '''check whether hardlink count reporting works properly'''
700
688
701 # testfile may be open, so we need a separate file for checking to
689 # testfile may be open, so we need a separate file for checking to
702 # work around issue2543 (or testfile may get lost on Samba shares)
690 # work around issue2543 (or testfile may get lost on Samba shares)
703 f1 = testfile + ".hgtmp1"
691 f1 = testfile + ".hgtmp1"
704 if os.path.lexists(f1):
692 if os.path.lexists(f1):
705 return False
693 return False
706 try:
694 try:
707 posixfile(f1, 'w').close()
695 posixfile(f1, 'w').close()
708 except IOError:
696 except IOError:
709 return False
697 return False
710
698
711 f2 = testfile + ".hgtmp2"
699 f2 = testfile + ".hgtmp2"
712 fd = None
700 fd = None
713 try:
701 try:
714 try:
702 try:
715 os_link(f1, f2)
703 os_link(f1, f2)
716 except OSError:
704 except OSError:
717 return False
705 return False
718
706
719 # nlinks() may behave differently for files on Windows shares if
707 # nlinks() may behave differently for files on Windows shares if
720 # the file is open.
708 # the file is open.
721 fd = posixfile(f2)
709 fd = posixfile(f2)
722 return nlinks(f2) > 1
710 return nlinks(f2) > 1
723 finally:
711 finally:
724 if fd is not None:
712 if fd is not None:
725 fd.close()
713 fd.close()
726 for f in (f1, f2):
714 for f in (f1, f2):
727 try:
715 try:
728 os.unlink(f)
716 os.unlink(f)
729 except OSError:
717 except OSError:
730 pass
718 pass
731
719
732 return False
720 return False
733
721
734 def endswithsep(path):
722 def endswithsep(path):
735 '''Check path ends with os.sep or os.altsep.'''
723 '''Check path ends with os.sep or os.altsep.'''
736 return path.endswith(os.sep) or os.altsep and path.endswith(os.altsep)
724 return path.endswith(os.sep) or os.altsep and path.endswith(os.altsep)
737
725
738 def splitpath(path):
726 def splitpath(path):
739 '''Split path by os.sep.
727 '''Split path by os.sep.
740 Note that this function does not use os.altsep because this is
728 Note that this function does not use os.altsep because this is
741 an alternative of simple "xxx.split(os.sep)".
729 an alternative of simple "xxx.split(os.sep)".
742 It is recommended to use os.path.normpath() before using this
730 It is recommended to use os.path.normpath() before using this
743 function if need.'''
731 function if need.'''
744 return path.split(os.sep)
732 return path.split(os.sep)
745
733
746 def gui():
734 def gui():
747 '''Are we running in a GUI?'''
735 '''Are we running in a GUI?'''
748 if sys.platform == 'darwin':
736 if sys.platform == 'darwin':
749 if 'SSH_CONNECTION' in os.environ:
737 if 'SSH_CONNECTION' in os.environ:
750 # handle SSH access to a box where the user is logged in
738 # handle SSH access to a box where the user is logged in
751 return False
739 return False
752 elif getattr(osutil, 'isgui', None):
740 elif getattr(osutil, 'isgui', None):
753 # check if a CoreGraphics session is available
741 # check if a CoreGraphics session is available
754 return osutil.isgui()
742 return osutil.isgui()
755 else:
743 else:
756 # pure build; use a safe default
744 # pure build; use a safe default
757 return True
745 return True
758 else:
746 else:
759 return os.name == "nt" or os.environ.get("DISPLAY")
747 return os.name == "nt" or os.environ.get("DISPLAY")
760
748
761 def mktempcopy(name, emptyok=False, createmode=None):
749 def mktempcopy(name, emptyok=False, createmode=None):
762 """Create a temporary file with the same contents from name
750 """Create a temporary file with the same contents from name
763
751
764 The permission bits are copied from the original file.
752 The permission bits are copied from the original file.
765
753
766 If the temporary file is going to be truncated immediately, you
754 If the temporary file is going to be truncated immediately, you
767 can use emptyok=True as an optimization.
755 can use emptyok=True as an optimization.
768
756
769 Returns the name of the temporary file.
757 Returns the name of the temporary file.
770 """
758 """
771 d, fn = os.path.split(name)
759 d, fn = os.path.split(name)
772 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
760 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
773 os.close(fd)
761 os.close(fd)
774 # Temporary files are created with mode 0600, which is usually not
762 # Temporary files are created with mode 0600, which is usually not
775 # what we want. If the original file already exists, just copy
763 # what we want. If the original file already exists, just copy
776 # its mode. Otherwise, manually obey umask.
764 # its mode. Otherwise, manually obey umask.
777 try:
765 try:
778 st_mode = os.lstat(name).st_mode & 0777
766 st_mode = os.lstat(name).st_mode & 0777
779 except OSError, inst:
767 except OSError, inst:
780 if inst.errno != errno.ENOENT:
768 if inst.errno != errno.ENOENT:
781 raise
769 raise
782 st_mode = createmode
770 st_mode = createmode
783 if st_mode is None:
771 if st_mode is None:
784 st_mode = ~umask
772 st_mode = ~umask
785 st_mode &= 0666
773 st_mode &= 0666
786 os.chmod(temp, st_mode)
774 os.chmod(temp, st_mode)
787 if emptyok:
775 if emptyok:
788 return temp
776 return temp
789 try:
777 try:
790 try:
778 try:
791 ifp = posixfile(name, "rb")
779 ifp = posixfile(name, "rb")
792 except IOError, inst:
780 except IOError, inst:
793 if inst.errno == errno.ENOENT:
781 if inst.errno == errno.ENOENT:
794 return temp
782 return temp
795 if not getattr(inst, 'filename', None):
783 if not getattr(inst, 'filename', None):
796 inst.filename = name
784 inst.filename = name
797 raise
785 raise
798 ofp = posixfile(temp, "wb")
786 ofp = posixfile(temp, "wb")
799 for chunk in filechunkiter(ifp):
787 for chunk in filechunkiter(ifp):
800 ofp.write(chunk)
788 ofp.write(chunk)
801 ifp.close()
789 ifp.close()
802 ofp.close()
790 ofp.close()
803 except:
791 except:
804 try: os.unlink(temp)
792 try: os.unlink(temp)
805 except: pass
793 except: pass
806 raise
794 raise
807 return temp
795 return temp
808
796
809 class atomictempfile(object):
797 class atomictempfile(object):
810 """file-like object that atomically updates a file
798 """file-like object that atomically updates a file
811
799
812 All writes will be redirected to a temporary copy of the original
800 All writes will be redirected to a temporary copy of the original
813 file. When rename is called, the copy is renamed to the original
801 file. When rename is called, the copy is renamed to the original
814 name, making the changes visible.
802 name, making the changes visible.
815 """
803 """
816 def __init__(self, name, mode='w+b', createmode=None):
804 def __init__(self, name, mode='w+b', createmode=None):
817 self.__name = name
805 self.__name = name
818 self._fp = None
806 self._fp = None
819 self.temp = mktempcopy(name, emptyok=('w' in mode),
807 self.temp = mktempcopy(name, emptyok=('w' in mode),
820 createmode=createmode)
808 createmode=createmode)
821 self._fp = posixfile(self.temp, mode)
809 self._fp = posixfile(self.temp, mode)
822
810
823 def __getattr__(self, name):
811 def __getattr__(self, name):
824 return getattr(self._fp, name)
812 return getattr(self._fp, name)
825
813
826 def rename(self):
814 def rename(self):
827 if not self._fp.closed:
815 if not self._fp.closed:
828 self._fp.close()
816 self._fp.close()
829 rename(self.temp, localpath(self.__name))
817 rename(self.temp, localpath(self.__name))
830
818
831 def close(self):
819 def close(self):
832 if not self._fp:
820 if not self._fp:
833 return
821 return
834 if not self._fp.closed:
822 if not self._fp.closed:
835 try:
823 try:
836 os.unlink(self.temp)
824 os.unlink(self.temp)
837 except: pass
825 except: pass
838 self._fp.close()
826 self._fp.close()
839
827
840 def __del__(self):
828 def __del__(self):
841 self.close()
829 self.close()
842
830
843 def makedirs(name, mode=None):
831 def makedirs(name, mode=None):
844 """recursive directory creation with parent mode inheritance"""
832 """recursive directory creation with parent mode inheritance"""
845 parent = os.path.abspath(os.path.dirname(name))
833 parent = os.path.abspath(os.path.dirname(name))
846 try:
834 try:
847 os.mkdir(name)
835 os.mkdir(name)
848 if mode is not None:
836 if mode is not None:
849 os.chmod(name, mode)
837 os.chmod(name, mode)
850 return
838 return
851 except OSError, err:
839 except OSError, err:
852 if err.errno == errno.EEXIST:
840 if err.errno == errno.EEXIST:
853 return
841 return
854 if not name or parent == name or err.errno != errno.ENOENT:
842 if not name or parent == name or err.errno != errno.ENOENT:
855 raise
843 raise
856 makedirs(parent, mode)
844 makedirs(parent, mode)
857 makedirs(name, mode)
845 makedirs(name, mode)
858
846
859 class opener(object):
847 class opener(object):
860 """Open files relative to a base directory
848 """Open files relative to a base directory
861
849
862 This class is used to hide the details of COW semantics and
850 This class is used to hide the details of COW semantics and
863 remote file access from higher level code.
851 remote file access from higher level code.
864 """
852 """
865 def __init__(self, base, audit=True):
853 def __init__(self, base, audit=True):
866 self.base = base
854 self.base = base
867 if audit:
855 if audit:
868 self.auditor = path_auditor(base)
856 self.auditor = path_auditor(base)
869 else:
857 else:
870 self.auditor = always
858 self.auditor = always
871 self.createmode = None
859 self.createmode = None
872 self._trustnlink = None
860 self._trustnlink = None
873
861
874 @propertycache
862 @propertycache
875 def _can_symlink(self):
863 def _can_symlink(self):
876 return checklink(self.base)
864 return checklink(self.base)
877
865
878 def _fixfilemode(self, name):
866 def _fixfilemode(self, name):
879 if self.createmode is None:
867 if self.createmode is None:
880 return
868 return
881 os.chmod(name, self.createmode & 0666)
869 os.chmod(name, self.createmode & 0666)
882
870
883 def __call__(self, path, mode="r", text=False, atomictemp=False):
871 def __call__(self, path, mode="r", text=False, atomictemp=False):
884 self.auditor(path)
872 self.auditor(path)
885 f = os.path.join(self.base, path)
873 f = os.path.join(self.base, path)
886
874
887 if not text and "b" not in mode:
875 if not text and "b" not in mode:
888 mode += "b" # for that other OS
876 mode += "b" # for that other OS
889
877
890 nlink = -1
878 nlink = -1
891 dirname, basename = os.path.split(f)
879 dirname, basename = os.path.split(f)
892 # If basename is empty, then the path is malformed because it points
880 # If basename is empty, then the path is malformed because it points
893 # to a directory. Let the posixfile() call below raise IOError.
881 # to a directory. Let the posixfile() call below raise IOError.
894 if basename and mode not in ('r', 'rb'):
882 if basename and mode not in ('r', 'rb'):
895 if atomictemp:
883 if atomictemp:
896 if not os.path.isdir(dirname):
884 if not os.path.isdir(dirname):
897 makedirs(dirname, self.createmode)
885 makedirs(dirname, self.createmode)
898 return atomictempfile(f, mode, self.createmode)
886 return atomictempfile(f, mode, self.createmode)
899 try:
887 try:
900 if 'w' in mode:
888 if 'w' in mode:
901 unlink(f)
889 unlink(f)
902 nlink = 0
890 nlink = 0
903 else:
891 else:
904 # nlinks() may behave differently for files on Windows
892 # nlinks() may behave differently for files on Windows
905 # shares if the file is open.
893 # shares if the file is open.
906 fd = posixfile(f)
894 fd = posixfile(f)
907 nlink = nlinks(f)
895 nlink = nlinks(f)
908 if nlink < 1:
896 if nlink < 1:
909 nlink = 2 # force mktempcopy (issue1922)
897 nlink = 2 # force mktempcopy (issue1922)
910 fd.close()
898 fd.close()
911 except (OSError, IOError), e:
899 except (OSError, IOError), e:
912 if e.errno != errno.ENOENT:
900 if e.errno != errno.ENOENT:
913 raise
901 raise
914 nlink = 0
902 nlink = 0
915 if not os.path.isdir(dirname):
903 if not os.path.isdir(dirname):
916 makedirs(dirname, self.createmode)
904 makedirs(dirname, self.createmode)
917 if nlink > 0:
905 if nlink > 0:
918 if self._trustnlink is None:
906 if self._trustnlink is None:
919 self._trustnlink = nlink > 1 or checknlink(f)
907 self._trustnlink = nlink > 1 or checknlink(f)
920 if nlink > 1 or not self._trustnlink:
908 if nlink > 1 or not self._trustnlink:
921 rename(mktempcopy(f), f)
909 rename(mktempcopy(f), f)
922 fp = posixfile(f, mode)
910 fp = posixfile(f, mode)
923 if nlink == 0:
911 if nlink == 0:
924 self._fixfilemode(f)
912 self._fixfilemode(f)
925 return fp
913 return fp
926
914
927 def symlink(self, src, dst):
915 def symlink(self, src, dst):
928 self.auditor(dst)
916 self.auditor(dst)
929 linkname = os.path.join(self.base, dst)
917 linkname = os.path.join(self.base, dst)
930 try:
918 try:
931 os.unlink(linkname)
919 os.unlink(linkname)
932 except OSError:
920 except OSError:
933 pass
921 pass
934
922
935 dirname = os.path.dirname(linkname)
923 dirname = os.path.dirname(linkname)
936 if not os.path.exists(dirname):
924 if not os.path.exists(dirname):
937 makedirs(dirname, self.createmode)
925 makedirs(dirname, self.createmode)
938
926
939 if self._can_symlink:
927 if self._can_symlink:
940 try:
928 try:
941 os.symlink(src, linkname)
929 os.symlink(src, linkname)
942 except OSError, err:
930 except OSError, err:
943 raise OSError(err.errno, _('could not symlink to %r: %s') %
931 raise OSError(err.errno, _('could not symlink to %r: %s') %
944 (src, err.strerror), linkname)
932 (src, err.strerror), linkname)
945 else:
933 else:
946 f = self(dst, "w")
934 f = self(dst, "w")
947 f.write(src)
935 f.write(src)
948 f.close()
936 f.close()
949 self._fixfilemode(dst)
937 self._fixfilemode(dst)
950
938
951 class chunkbuffer(object):
939 class chunkbuffer(object):
952 """Allow arbitrary sized chunks of data to be efficiently read from an
940 """Allow arbitrary sized chunks of data to be efficiently read from an
953 iterator over chunks of arbitrary size."""
941 iterator over chunks of arbitrary size."""
954
942
955 def __init__(self, in_iter):
943 def __init__(self, in_iter):
956 """in_iter is the iterator that's iterating over the input chunks.
944 """in_iter is the iterator that's iterating over the input chunks.
957 targetsize is how big a buffer to try to maintain."""
945 targetsize is how big a buffer to try to maintain."""
958 def splitbig(chunks):
946 def splitbig(chunks):
959 for chunk in chunks:
947 for chunk in chunks:
960 if len(chunk) > 2**20:
948 if len(chunk) > 2**20:
961 pos = 0
949 pos = 0
962 while pos < len(chunk):
950 while pos < len(chunk):
963 end = pos + 2 ** 18
951 end = pos + 2 ** 18
964 yield chunk[pos:end]
952 yield chunk[pos:end]
965 pos = end
953 pos = end
966 else:
954 else:
967 yield chunk
955 yield chunk
968 self.iter = splitbig(in_iter)
956 self.iter = splitbig(in_iter)
969 self._queue = []
957 self._queue = []
970
958
971 def read(self, l):
959 def read(self, l):
972 """Read L bytes of data from the iterator of chunks of data.
960 """Read L bytes of data from the iterator of chunks of data.
973 Returns less than L bytes if the iterator runs dry."""
961 Returns less than L bytes if the iterator runs dry."""
974 left = l
962 left = l
975 buf = ''
963 buf = ''
976 queue = self._queue
964 queue = self._queue
977 while left > 0:
965 while left > 0:
978 # refill the queue
966 # refill the queue
979 if not queue:
967 if not queue:
980 target = 2**18
968 target = 2**18
981 for chunk in self.iter:
969 for chunk in self.iter:
982 queue.append(chunk)
970 queue.append(chunk)
983 target -= len(chunk)
971 target -= len(chunk)
984 if target <= 0:
972 if target <= 0:
985 break
973 break
986 if not queue:
974 if not queue:
987 break
975 break
988
976
989 chunk = queue.pop(0)
977 chunk = queue.pop(0)
990 left -= len(chunk)
978 left -= len(chunk)
991 if left < 0:
979 if left < 0:
992 queue.insert(0, chunk[left:])
980 queue.insert(0, chunk[left:])
993 buf += chunk[:left]
981 buf += chunk[:left]
994 else:
982 else:
995 buf += chunk
983 buf += chunk
996
984
997 return buf
985 return buf
998
986
999 def filechunkiter(f, size=65536, limit=None):
987 def filechunkiter(f, size=65536, limit=None):
1000 """Create a generator that produces the data in the file size
988 """Create a generator that produces the data in the file size
1001 (default 65536) bytes at a time, up to optional limit (default is
989 (default 65536) bytes at a time, up to optional limit (default is
1002 to read all data). Chunks may be less than size bytes if the
990 to read all data). Chunks may be less than size bytes if the
1003 chunk is the last chunk in the file, or the file is a socket or
991 chunk is the last chunk in the file, or the file is a socket or
1004 some other type of file that sometimes reads less data than is
992 some other type of file that sometimes reads less data than is
1005 requested."""
993 requested."""
1006 assert size >= 0
994 assert size >= 0
1007 assert limit is None or limit >= 0
995 assert limit is None or limit >= 0
1008 while True:
996 while True:
1009 if limit is None:
997 if limit is None:
1010 nbytes = size
998 nbytes = size
1011 else:
999 else:
1012 nbytes = min(limit, size)
1000 nbytes = min(limit, size)
1013 s = nbytes and f.read(nbytes)
1001 s = nbytes and f.read(nbytes)
1014 if not s:
1002 if not s:
1015 break
1003 break
1016 if limit:
1004 if limit:
1017 limit -= len(s)
1005 limit -= len(s)
1018 yield s
1006 yield s
1019
1007
1020 def makedate():
1008 def makedate():
1021 lt = time.localtime()
1009 lt = time.localtime()
1022 if lt[8] == 1 and time.daylight:
1010 if lt[8] == 1 and time.daylight:
1023 tz = time.altzone
1011 tz = time.altzone
1024 else:
1012 else:
1025 tz = time.timezone
1013 tz = time.timezone
1026 t = time.mktime(lt)
1014 t = time.mktime(lt)
1027 if t < 0:
1015 if t < 0:
1028 hint = _("check your clock")
1016 hint = _("check your clock")
1029 raise Abort(_("negative timestamp: %d") % t, hint=hint)
1017 raise Abort(_("negative timestamp: %d") % t, hint=hint)
1030 return t, tz
1018 return t, tz
1031
1019
1032 def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'):
1020 def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'):
1033 """represent a (unixtime, offset) tuple as a localized time.
1021 """represent a (unixtime, offset) tuple as a localized time.
1034 unixtime is seconds since the epoch, and offset is the time zone's
1022 unixtime is seconds since the epoch, and offset is the time zone's
1035 number of seconds away from UTC. if timezone is false, do not
1023 number of seconds away from UTC. if timezone is false, do not
1036 append time zone to string."""
1024 append time zone to string."""
1037 t, tz = date or makedate()
1025 t, tz = date or makedate()
1038 if t < 0:
1026 if t < 0:
1039 t = 0 # time.gmtime(lt) fails on Windows for lt < -43200
1027 t = 0 # time.gmtime(lt) fails on Windows for lt < -43200
1040 tz = 0
1028 tz = 0
1041 if "%1" in format or "%2" in format:
1029 if "%1" in format or "%2" in format:
1042 sign = (tz > 0) and "-" or "+"
1030 sign = (tz > 0) and "-" or "+"
1043 minutes = abs(tz) // 60
1031 minutes = abs(tz) // 60
1044 format = format.replace("%1", "%c%02d" % (sign, minutes // 60))
1032 format = format.replace("%1", "%c%02d" % (sign, minutes // 60))
1045 format = format.replace("%2", "%02d" % (minutes % 60))
1033 format = format.replace("%2", "%02d" % (minutes % 60))
1046 s = time.strftime(format, time.gmtime(float(t) - tz))
1034 s = time.strftime(format, time.gmtime(float(t) - tz))
1047 return s
1035 return s
1048
1036
1049 def shortdate(date=None):
1037 def shortdate(date=None):
1050 """turn (timestamp, tzoff) tuple into iso 8631 date."""
1038 """turn (timestamp, tzoff) tuple into iso 8631 date."""
1051 return datestr(date, format='%Y-%m-%d')
1039 return datestr(date, format='%Y-%m-%d')
1052
1040
1053 def strdate(string, format, defaults=[]):
1041 def strdate(string, format, defaults=[]):
1054 """parse a localized time string and return a (unixtime, offset) tuple.
1042 """parse a localized time string and return a (unixtime, offset) tuple.
1055 if the string cannot be parsed, ValueError is raised."""
1043 if the string cannot be parsed, ValueError is raised."""
1056 def timezone(string):
1044 def timezone(string):
1057 tz = string.split()[-1]
1045 tz = string.split()[-1]
1058 if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
1046 if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
1059 sign = (tz[0] == "+") and 1 or -1
1047 sign = (tz[0] == "+") and 1 or -1
1060 hours = int(tz[1:3])
1048 hours = int(tz[1:3])
1061 minutes = int(tz[3:5])
1049 minutes = int(tz[3:5])
1062 return -sign * (hours * 60 + minutes) * 60
1050 return -sign * (hours * 60 + minutes) * 60
1063 if tz == "GMT" or tz == "UTC":
1051 if tz == "GMT" or tz == "UTC":
1064 return 0
1052 return 0
1065 return None
1053 return None
1066
1054
1067 # NOTE: unixtime = localunixtime + offset
1055 # NOTE: unixtime = localunixtime + offset
1068 offset, date = timezone(string), string
1056 offset, date = timezone(string), string
1069 if offset is not None:
1057 if offset is not None:
1070 date = " ".join(string.split()[:-1])
1058 date = " ".join(string.split()[:-1])
1071
1059
1072 # add missing elements from defaults
1060 # add missing elements from defaults
1073 usenow = False # default to using biased defaults
1061 usenow = False # default to using biased defaults
1074 for part in ("S", "M", "HI", "d", "mb", "yY"): # decreasing specificity
1062 for part in ("S", "M", "HI", "d", "mb", "yY"): # decreasing specificity
1075 found = [True for p in part if ("%"+p) in format]
1063 found = [True for p in part if ("%"+p) in format]
1076 if not found:
1064 if not found:
1077 date += "@" + defaults[part][usenow]
1065 date += "@" + defaults[part][usenow]
1078 format += "@%" + part[0]
1066 format += "@%" + part[0]
1079 else:
1067 else:
1080 # We've found a specific time element, less specific time
1068 # We've found a specific time element, less specific time
1081 # elements are relative to today
1069 # elements are relative to today
1082 usenow = True
1070 usenow = True
1083
1071
1084 timetuple = time.strptime(date, format)
1072 timetuple = time.strptime(date, format)
1085 localunixtime = int(calendar.timegm(timetuple))
1073 localunixtime = int(calendar.timegm(timetuple))
1086 if offset is None:
1074 if offset is None:
1087 # local timezone
1075 # local timezone
1088 unixtime = int(time.mktime(timetuple))
1076 unixtime = int(time.mktime(timetuple))
1089 offset = unixtime - localunixtime
1077 offset = unixtime - localunixtime
1090 else:
1078 else:
1091 unixtime = localunixtime + offset
1079 unixtime = localunixtime + offset
1092 return unixtime, offset
1080 return unixtime, offset
1093
1081
1094 def parsedate(date, formats=None, bias={}):
1082 def parsedate(date, formats=None, bias={}):
1095 """parse a localized date/time and return a (unixtime, offset) tuple.
1083 """parse a localized date/time and return a (unixtime, offset) tuple.
1096
1084
1097 The date may be a "unixtime offset" string or in one of the specified
1085 The date may be a "unixtime offset" string or in one of the specified
1098 formats. If the date already is a (unixtime, offset) tuple, it is returned.
1086 formats. If the date already is a (unixtime, offset) tuple, it is returned.
1099 """
1087 """
1100 if not date:
1088 if not date:
1101 return 0, 0
1089 return 0, 0
1102 if isinstance(date, tuple) and len(date) == 2:
1090 if isinstance(date, tuple) and len(date) == 2:
1103 return date
1091 return date
1104 if not formats:
1092 if not formats:
1105 formats = defaultdateformats
1093 formats = defaultdateformats
1106 date = date.strip()
1094 date = date.strip()
1107 try:
1095 try:
1108 when, offset = map(int, date.split(' '))
1096 when, offset = map(int, date.split(' '))
1109 except ValueError:
1097 except ValueError:
1110 # fill out defaults
1098 # fill out defaults
1111 now = makedate()
1099 now = makedate()
1112 defaults = {}
1100 defaults = {}
1113 nowmap = {}
1101 nowmap = {}
1114 for part in ("d", "mb", "yY", "HI", "M", "S"):
1102 for part in ("d", "mb", "yY", "HI", "M", "S"):
1115 # this piece is for rounding the specific end of unknowns
1103 # this piece is for rounding the specific end of unknowns
1116 b = bias.get(part)
1104 b = bias.get(part)
1117 if b is None:
1105 if b is None:
1118 if part[0] in "HMS":
1106 if part[0] in "HMS":
1119 b = "00"
1107 b = "00"
1120 else:
1108 else:
1121 b = "0"
1109 b = "0"
1122
1110
1123 # this piece is for matching the generic end to today's date
1111 # this piece is for matching the generic end to today's date
1124 n = datestr(now, "%" + part[0])
1112 n = datestr(now, "%" + part[0])
1125
1113
1126 defaults[part] = (b, n)
1114 defaults[part] = (b, n)
1127
1115
1128 for format in formats:
1116 for format in formats:
1129 try:
1117 try:
1130 when, offset = strdate(date, format, defaults)
1118 when, offset = strdate(date, format, defaults)
1131 except (ValueError, OverflowError):
1119 except (ValueError, OverflowError):
1132 pass
1120 pass
1133 else:
1121 else:
1134 break
1122 break
1135 else:
1123 else:
1136 raise Abort(_('invalid date: %r') % date)
1124 raise Abort(_('invalid date: %r') % date)
1137 # validate explicit (probably user-specified) date and
1125 # validate explicit (probably user-specified) date and
1138 # time zone offset. values must fit in signed 32 bits for
1126 # time zone offset. values must fit in signed 32 bits for
1139 # current 32-bit linux runtimes. timezones go from UTC-12
1127 # current 32-bit linux runtimes. timezones go from UTC-12
1140 # to UTC+14
1128 # to UTC+14
1141 if abs(when) > 0x7fffffff:
1129 if abs(when) > 0x7fffffff:
1142 raise Abort(_('date exceeds 32 bits: %d') % when)
1130 raise Abort(_('date exceeds 32 bits: %d') % when)
1143 if when < 0:
1131 if when < 0:
1144 raise Abort(_('negative date value: %d') % when)
1132 raise Abort(_('negative date value: %d') % when)
1145 if offset < -50400 or offset > 43200:
1133 if offset < -50400 or offset > 43200:
1146 raise Abort(_('impossible time zone offset: %d') % offset)
1134 raise Abort(_('impossible time zone offset: %d') % offset)
1147 return when, offset
1135 return when, offset
1148
1136
1149 def matchdate(date):
1137 def matchdate(date):
1150 """Return a function that matches a given date match specifier
1138 """Return a function that matches a given date match specifier
1151
1139
1152 Formats include:
1140 Formats include:
1153
1141
1154 '{date}' match a given date to the accuracy provided
1142 '{date}' match a given date to the accuracy provided
1155
1143
1156 '<{date}' on or before a given date
1144 '<{date}' on or before a given date
1157
1145
1158 '>{date}' on or after a given date
1146 '>{date}' on or after a given date
1159
1147
1160 >>> p1 = parsedate("10:29:59")
1148 >>> p1 = parsedate("10:29:59")
1161 >>> p2 = parsedate("10:30:00")
1149 >>> p2 = parsedate("10:30:00")
1162 >>> p3 = parsedate("10:30:59")
1150 >>> p3 = parsedate("10:30:59")
1163 >>> p4 = parsedate("10:31:00")
1151 >>> p4 = parsedate("10:31:00")
1164 >>> p5 = parsedate("Sep 15 10:30:00 1999")
1152 >>> p5 = parsedate("Sep 15 10:30:00 1999")
1165 >>> f = matchdate("10:30")
1153 >>> f = matchdate("10:30")
1166 >>> f(p1[0])
1154 >>> f(p1[0])
1167 False
1155 False
1168 >>> f(p2[0])
1156 >>> f(p2[0])
1169 True
1157 True
1170 >>> f(p3[0])
1158 >>> f(p3[0])
1171 True
1159 True
1172 >>> f(p4[0])
1160 >>> f(p4[0])
1173 False
1161 False
1174 >>> f(p5[0])
1162 >>> f(p5[0])
1175 False
1163 False
1176 """
1164 """
1177
1165
1178 def lower(date):
1166 def lower(date):
1179 d = dict(mb="1", d="1")
1167 d = dict(mb="1", d="1")
1180 return parsedate(date, extendeddateformats, d)[0]
1168 return parsedate(date, extendeddateformats, d)[0]
1181
1169
1182 def upper(date):
1170 def upper(date):
1183 d = dict(mb="12", HI="23", M="59", S="59")
1171 d = dict(mb="12", HI="23", M="59", S="59")
1184 for days in ("31", "30", "29"):
1172 for days in ("31", "30", "29"):
1185 try:
1173 try:
1186 d["d"] = days
1174 d["d"] = days
1187 return parsedate(date, extendeddateformats, d)[0]
1175 return parsedate(date, extendeddateformats, d)[0]
1188 except:
1176 except:
1189 pass
1177 pass
1190 d["d"] = "28"
1178 d["d"] = "28"
1191 return parsedate(date, extendeddateformats, d)[0]
1179 return parsedate(date, extendeddateformats, d)[0]
1192
1180
1193 date = date.strip()
1181 date = date.strip()
1194
1182
1195 if not date:
1183 if not date:
1196 raise Abort(_("dates cannot consist entirely of whitespace"))
1184 raise Abort(_("dates cannot consist entirely of whitespace"))
1197 elif date[0] == "<":
1185 elif date[0] == "<":
1198 if not date[1:]:
1186 if not date[1:]:
1199 raise Abort(_("invalid day spec, use '<DATE'"))
1187 raise Abort(_("invalid day spec, use '<DATE'"))
1200 when = upper(date[1:])
1188 when = upper(date[1:])
1201 return lambda x: x <= when
1189 return lambda x: x <= when
1202 elif date[0] == ">":
1190 elif date[0] == ">":
1203 if not date[1:]:
1191 if not date[1:]:
1204 raise Abort(_("invalid day spec, use '>DATE'"))
1192 raise Abort(_("invalid day spec, use '>DATE'"))
1205 when = lower(date[1:])
1193 when = lower(date[1:])
1206 return lambda x: x >= when
1194 return lambda x: x >= when
1207 elif date[0] == "-":
1195 elif date[0] == "-":
1208 try:
1196 try:
1209 days = int(date[1:])
1197 days = int(date[1:])
1210 except ValueError:
1198 except ValueError:
1211 raise Abort(_("invalid day spec: %s") % date[1:])
1199 raise Abort(_("invalid day spec: %s") % date[1:])
1212 if days < 0:
1200 if days < 0:
1213 raise Abort(_("%s must be nonnegative (see 'hg help dates')")
1201 raise Abort(_("%s must be nonnegative (see 'hg help dates')")
1214 % date[1:])
1202 % date[1:])
1215 when = makedate()[0] - days * 3600 * 24
1203 when = makedate()[0] - days * 3600 * 24
1216 return lambda x: x >= when
1204 return lambda x: x >= when
1217 elif " to " in date:
1205 elif " to " in date:
1218 a, b = date.split(" to ")
1206 a, b = date.split(" to ")
1219 start, stop = lower(a), upper(b)
1207 start, stop = lower(a), upper(b)
1220 return lambda x: x >= start and x <= stop
1208 return lambda x: x >= start and x <= stop
1221 else:
1209 else:
1222 start, stop = lower(date), upper(date)
1210 start, stop = lower(date), upper(date)
1223 return lambda x: x >= start and x <= stop
1211 return lambda x: x >= start and x <= stop
1224
1212
1225 def shortuser(user):
1213 def shortuser(user):
1226 """Return a short representation of a user name or email address."""
1214 """Return a short representation of a user name or email address."""
1227 f = user.find('@')
1215 f = user.find('@')
1228 if f >= 0:
1216 if f >= 0:
1229 user = user[:f]
1217 user = user[:f]
1230 f = user.find('<')
1218 f = user.find('<')
1231 if f >= 0:
1219 if f >= 0:
1232 user = user[f + 1:]
1220 user = user[f + 1:]
1233 f = user.find(' ')
1221 f = user.find(' ')
1234 if f >= 0:
1222 if f >= 0:
1235 user = user[:f]
1223 user = user[:f]
1236 f = user.find('.')
1224 f = user.find('.')
1237 if f >= 0:
1225 if f >= 0:
1238 user = user[:f]
1226 user = user[:f]
1239 return user
1227 return user
1240
1228
1241 def email(author):
1229 def email(author):
1242 '''get email of author.'''
1230 '''get email of author.'''
1243 r = author.find('>')
1231 r = author.find('>')
1244 if r == -1:
1232 if r == -1:
1245 r = None
1233 r = None
1246 return author[author.find('<') + 1:r]
1234 return author[author.find('<') + 1:r]
1247
1235
1248 def _ellipsis(text, maxlength):
1236 def _ellipsis(text, maxlength):
1249 if len(text) <= maxlength:
1237 if len(text) <= maxlength:
1250 return text, False
1238 return text, False
1251 else:
1239 else:
1252 return "%s..." % (text[:maxlength - 3]), True
1240 return "%s..." % (text[:maxlength - 3]), True
1253
1241
1254 def ellipsis(text, maxlength=400):
1242 def ellipsis(text, maxlength=400):
1255 """Trim string to at most maxlength (default: 400) characters."""
1243 """Trim string to at most maxlength (default: 400) characters."""
1256 try:
1244 try:
1257 # use unicode not to split at intermediate multi-byte sequence
1245 # use unicode not to split at intermediate multi-byte sequence
1258 utext, truncated = _ellipsis(text.decode(encoding.encoding),
1246 utext, truncated = _ellipsis(text.decode(encoding.encoding),
1259 maxlength)
1247 maxlength)
1260 if not truncated:
1248 if not truncated:
1261 return text
1249 return text
1262 return utext.encode(encoding.encoding)
1250 return utext.encode(encoding.encoding)
1263 except (UnicodeDecodeError, UnicodeEncodeError):
1251 except (UnicodeDecodeError, UnicodeEncodeError):
1264 return _ellipsis(text, maxlength)[0]
1252 return _ellipsis(text, maxlength)[0]
1265
1253
1266 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
1254 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
1267 '''yield every hg repository under path, recursively.'''
1255 '''yield every hg repository under path, recursively.'''
1268 def errhandler(err):
1256 def errhandler(err):
1269 if err.filename == path:
1257 if err.filename == path:
1270 raise err
1258 raise err
1271 if followsym and hasattr(os.path, 'samestat'):
1259 if followsym and hasattr(os.path, 'samestat'):
1272 def _add_dir_if_not_there(dirlst, dirname):
1260 def _add_dir_if_not_there(dirlst, dirname):
1273 match = False
1261 match = False
1274 samestat = os.path.samestat
1262 samestat = os.path.samestat
1275 dirstat = os.stat(dirname)
1263 dirstat = os.stat(dirname)
1276 for lstdirstat in dirlst:
1264 for lstdirstat in dirlst:
1277 if samestat(dirstat, lstdirstat):
1265 if samestat(dirstat, lstdirstat):
1278 match = True
1266 match = True
1279 break
1267 break
1280 if not match:
1268 if not match:
1281 dirlst.append(dirstat)
1269 dirlst.append(dirstat)
1282 return not match
1270 return not match
1283 else:
1271 else:
1284 followsym = False
1272 followsym = False
1285
1273
1286 if (seen_dirs is None) and followsym:
1274 if (seen_dirs is None) and followsym:
1287 seen_dirs = []
1275 seen_dirs = []
1288 _add_dir_if_not_there(seen_dirs, path)
1276 _add_dir_if_not_there(seen_dirs, path)
1289 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
1277 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
1290 dirs.sort()
1278 dirs.sort()
1291 if '.hg' in dirs:
1279 if '.hg' in dirs:
1292 yield root # found a repository
1280 yield root # found a repository
1293 qroot = os.path.join(root, '.hg', 'patches')
1281 qroot = os.path.join(root, '.hg', 'patches')
1294 if os.path.isdir(os.path.join(qroot, '.hg')):
1282 if os.path.isdir(os.path.join(qroot, '.hg')):
1295 yield qroot # we have a patch queue repo here
1283 yield qroot # we have a patch queue repo here
1296 if recurse:
1284 if recurse:
1297 # avoid recursing inside the .hg directory
1285 # avoid recursing inside the .hg directory
1298 dirs.remove('.hg')
1286 dirs.remove('.hg')
1299 else:
1287 else:
1300 dirs[:] = [] # don't descend further
1288 dirs[:] = [] # don't descend further
1301 elif followsym:
1289 elif followsym:
1302 newdirs = []
1290 newdirs = []
1303 for d in dirs:
1291 for d in dirs:
1304 fname = os.path.join(root, d)
1292 fname = os.path.join(root, d)
1305 if _add_dir_if_not_there(seen_dirs, fname):
1293 if _add_dir_if_not_there(seen_dirs, fname):
1306 if os.path.islink(fname):
1294 if os.path.islink(fname):
1307 for hgname in walkrepos(fname, True, seen_dirs):
1295 for hgname in walkrepos(fname, True, seen_dirs):
1308 yield hgname
1296 yield hgname
1309 else:
1297 else:
1310 newdirs.append(d)
1298 newdirs.append(d)
1311 dirs[:] = newdirs
1299 dirs[:] = newdirs
1312
1300
1313 _rcpath = None
1301 _rcpath = None
1314
1302
1315 def os_rcpath():
1303 def os_rcpath():
1316 '''return default os-specific hgrc search path'''
1304 '''return default os-specific hgrc search path'''
1317 path = system_rcpath()
1305 path = system_rcpath()
1318 path.extend(user_rcpath())
1306 path.extend(user_rcpath())
1319 path = [os.path.normpath(f) for f in path]
1307 path = [os.path.normpath(f) for f in path]
1320 return path
1308 return path
1321
1309
1322 def rcpath():
1310 def rcpath():
1323 '''return hgrc search path. if env var HGRCPATH is set, use it.
1311 '''return hgrc search path. if env var HGRCPATH is set, use it.
1324 for each item in path, if directory, use files ending in .rc,
1312 for each item in path, if directory, use files ending in .rc,
1325 else use item.
1313 else use item.
1326 make HGRCPATH empty to only look in .hg/hgrc of current repo.
1314 make HGRCPATH empty to only look in .hg/hgrc of current repo.
1327 if no HGRCPATH, use default os-specific path.'''
1315 if no HGRCPATH, use default os-specific path.'''
1328 global _rcpath
1316 global _rcpath
1329 if _rcpath is None:
1317 if _rcpath is None:
1330 if 'HGRCPATH' in os.environ:
1318 if 'HGRCPATH' in os.environ:
1331 _rcpath = []
1319 _rcpath = []
1332 for p in os.environ['HGRCPATH'].split(os.pathsep):
1320 for p in os.environ['HGRCPATH'].split(os.pathsep):
1333 if not p:
1321 if not p:
1334 continue
1322 continue
1335 p = expandpath(p)
1323 p = expandpath(p)
1336 if os.path.isdir(p):
1324 if os.path.isdir(p):
1337 for f, kind in osutil.listdir(p):
1325 for f, kind in osutil.listdir(p):
1338 if f.endswith('.rc'):
1326 if f.endswith('.rc'):
1339 _rcpath.append(os.path.join(p, f))
1327 _rcpath.append(os.path.join(p, f))
1340 else:
1328 else:
1341 _rcpath.append(p)
1329 _rcpath.append(p)
1342 else:
1330 else:
1343 _rcpath = os_rcpath()
1331 _rcpath = os_rcpath()
1344 return _rcpath
1332 return _rcpath
1345
1333
1346 def bytecount(nbytes):
1334 def bytecount(nbytes):
1347 '''return byte count formatted as readable string, with units'''
1335 '''return byte count formatted as readable string, with units'''
1348
1336
1349 units = (
1337 units = (
1350 (100, 1 << 30, _('%.0f GB')),
1338 (100, 1 << 30, _('%.0f GB')),
1351 (10, 1 << 30, _('%.1f GB')),
1339 (10, 1 << 30, _('%.1f GB')),
1352 (1, 1 << 30, _('%.2f GB')),
1340 (1, 1 << 30, _('%.2f GB')),
1353 (100, 1 << 20, _('%.0f MB')),
1341 (100, 1 << 20, _('%.0f MB')),
1354 (10, 1 << 20, _('%.1f MB')),
1342 (10, 1 << 20, _('%.1f MB')),
1355 (1, 1 << 20, _('%.2f MB')),
1343 (1, 1 << 20, _('%.2f MB')),
1356 (100, 1 << 10, _('%.0f KB')),
1344 (100, 1 << 10, _('%.0f KB')),
1357 (10, 1 << 10, _('%.1f KB')),
1345 (10, 1 << 10, _('%.1f KB')),
1358 (1, 1 << 10, _('%.2f KB')),
1346 (1, 1 << 10, _('%.2f KB')),
1359 (1, 1, _('%.0f bytes')),
1347 (1, 1, _('%.0f bytes')),
1360 )
1348 )
1361
1349
1362 for multiplier, divisor, format in units:
1350 for multiplier, divisor, format in units:
1363 if nbytes >= divisor * multiplier:
1351 if nbytes >= divisor * multiplier:
1364 return format % (nbytes / float(divisor))
1352 return format % (nbytes / float(divisor))
1365 return units[-1][2] % nbytes
1353 return units[-1][2] % nbytes
1366
1354
1367 def uirepr(s):
1355 def uirepr(s):
1368 # Avoid double backslash in Windows path repr()
1356 # Avoid double backslash in Windows path repr()
1369 return repr(s).replace('\\\\', '\\')
1357 return repr(s).replace('\\\\', '\\')
1370
1358
1371 # delay import of textwrap
1359 # delay import of textwrap
1372 def MBTextWrapper(**kwargs):
1360 def MBTextWrapper(**kwargs):
1373 class tw(textwrap.TextWrapper):
1361 class tw(textwrap.TextWrapper):
1374 """
1362 """
1375 Extend TextWrapper for double-width characters.
1363 Extend TextWrapper for double-width characters.
1376
1364
1377 Some Asian characters use two terminal columns instead of one.
1365 Some Asian characters use two terminal columns instead of one.
1378 A good example of this behavior can be seen with u'\u65e5\u672c',
1366 A good example of this behavior can be seen with u'\u65e5\u672c',
1379 the two Japanese characters for "Japan":
1367 the two Japanese characters for "Japan":
1380 len() returns 2, but when printed to a terminal, they eat 4 columns.
1368 len() returns 2, but when printed to a terminal, they eat 4 columns.
1381
1369
1382 (Note that this has nothing to do whatsoever with unicode
1370 (Note that this has nothing to do whatsoever with unicode
1383 representation, or encoding of the underlying string)
1371 representation, or encoding of the underlying string)
1384 """
1372 """
1385 def __init__(self, **kwargs):
1373 def __init__(self, **kwargs):
1386 textwrap.TextWrapper.__init__(self, **kwargs)
1374 textwrap.TextWrapper.__init__(self, **kwargs)
1387
1375
1388 def _cutdown(self, str, space_left):
1376 def _cutdown(self, str, space_left):
1389 l = 0
1377 l = 0
1390 ucstr = unicode(str, encoding.encoding)
1378 ucstr = unicode(str, encoding.encoding)
1391 colwidth = unicodedata.east_asian_width
1379 colwidth = unicodedata.east_asian_width
1392 for i in xrange(len(ucstr)):
1380 for i in xrange(len(ucstr)):
1393 l += colwidth(ucstr[i]) in 'WFA' and 2 or 1
1381 l += colwidth(ucstr[i]) in 'WFA' and 2 or 1
1394 if space_left < l:
1382 if space_left < l:
1395 return (ucstr[:i].encode(encoding.encoding),
1383 return (ucstr[:i].encode(encoding.encoding),
1396 ucstr[i:].encode(encoding.encoding))
1384 ucstr[i:].encode(encoding.encoding))
1397 return str, ''
1385 return str, ''
1398
1386
1399 # overriding of base class
1387 # overriding of base class
1400 def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
1388 def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
1401 space_left = max(width - cur_len, 1)
1389 space_left = max(width - cur_len, 1)
1402
1390
1403 if self.break_long_words:
1391 if self.break_long_words:
1404 cut, res = self._cutdown(reversed_chunks[-1], space_left)
1392 cut, res = self._cutdown(reversed_chunks[-1], space_left)
1405 cur_line.append(cut)
1393 cur_line.append(cut)
1406 reversed_chunks[-1] = res
1394 reversed_chunks[-1] = res
1407 elif not cur_line:
1395 elif not cur_line:
1408 cur_line.append(reversed_chunks.pop())
1396 cur_line.append(reversed_chunks.pop())
1409
1397
1410 global MBTextWrapper
1398 global MBTextWrapper
1411 MBTextWrapper = tw
1399 MBTextWrapper = tw
1412 return tw(**kwargs)
1400 return tw(**kwargs)
1413
1401
1414 def wrap(line, width, initindent='', hangindent=''):
1402 def wrap(line, width, initindent='', hangindent=''):
1415 maxindent = max(len(hangindent), len(initindent))
1403 maxindent = max(len(hangindent), len(initindent))
1416 if width <= maxindent:
1404 if width <= maxindent:
1417 # adjust for weird terminal size
1405 # adjust for weird terminal size
1418 width = max(78, maxindent + 1)
1406 width = max(78, maxindent + 1)
1419 wrapper = MBTextWrapper(width=width,
1407 wrapper = MBTextWrapper(width=width,
1420 initial_indent=initindent,
1408 initial_indent=initindent,
1421 subsequent_indent=hangindent)
1409 subsequent_indent=hangindent)
1422 return wrapper.fill(line)
1410 return wrapper.fill(line)
1423
1411
1424 def iterlines(iterator):
1412 def iterlines(iterator):
1425 for chunk in iterator:
1413 for chunk in iterator:
1426 for line in chunk.splitlines():
1414 for line in chunk.splitlines():
1427 yield line
1415 yield line
1428
1416
1429 def expandpath(path):
1417 def expandpath(path):
1430 return os.path.expanduser(os.path.expandvars(path))
1418 return os.path.expanduser(os.path.expandvars(path))
1431
1419
1432 def hgcmd():
1420 def hgcmd():
1433 """Return the command used to execute current hg
1421 """Return the command used to execute current hg
1434
1422
1435 This is different from hgexecutable() because on Windows we want
1423 This is different from hgexecutable() because on Windows we want
1436 to avoid things opening new shell windows like batch files, so we
1424 to avoid things opening new shell windows like batch files, so we
1437 get either the python call or current executable.
1425 get either the python call or current executable.
1438 """
1426 """
1439 if main_is_frozen():
1427 if main_is_frozen():
1440 return [sys.executable]
1428 return [sys.executable]
1441 return gethgcmd()
1429 return gethgcmd()
1442
1430
1443 def rundetached(args, condfn):
1431 def rundetached(args, condfn):
1444 """Execute the argument list in a detached process.
1432 """Execute the argument list in a detached process.
1445
1433
1446 condfn is a callable which is called repeatedly and should return
1434 condfn is a callable which is called repeatedly and should return
1447 True once the child process is known to have started successfully.
1435 True once the child process is known to have started successfully.
1448 At this point, the child process PID is returned. If the child
1436 At this point, the child process PID is returned. If the child
1449 process fails to start or finishes before condfn() evaluates to
1437 process fails to start or finishes before condfn() evaluates to
1450 True, return -1.
1438 True, return -1.
1451 """
1439 """
1452 # Windows case is easier because the child process is either
1440 # Windows case is easier because the child process is either
1453 # successfully starting and validating the condition or exiting
1441 # successfully starting and validating the condition or exiting
1454 # on failure. We just poll on its PID. On Unix, if the child
1442 # on failure. We just poll on its PID. On Unix, if the child
1455 # process fails to start, it will be left in a zombie state until
1443 # process fails to start, it will be left in a zombie state until
1456 # the parent wait on it, which we cannot do since we expect a long
1444 # the parent wait on it, which we cannot do since we expect a long
1457 # running process on success. Instead we listen for SIGCHLD telling
1445 # running process on success. Instead we listen for SIGCHLD telling
1458 # us our child process terminated.
1446 # us our child process terminated.
1459 terminated = set()
1447 terminated = set()
1460 def handler(signum, frame):
1448 def handler(signum, frame):
1461 terminated.add(os.wait())
1449 terminated.add(os.wait())
1462 prevhandler = None
1450 prevhandler = None
1463 if hasattr(signal, 'SIGCHLD'):
1451 if hasattr(signal, 'SIGCHLD'):
1464 prevhandler = signal.signal(signal.SIGCHLD, handler)
1452 prevhandler = signal.signal(signal.SIGCHLD, handler)
1465 try:
1453 try:
1466 pid = spawndetached(args)
1454 pid = spawndetached(args)
1467 while not condfn():
1455 while not condfn():
1468 if ((pid in terminated or not testpid(pid))
1456 if ((pid in terminated or not testpid(pid))
1469 and not condfn()):
1457 and not condfn()):
1470 return -1
1458 return -1
1471 time.sleep(0.1)
1459 time.sleep(0.1)
1472 return pid
1460 return pid
1473 finally:
1461 finally:
1474 if prevhandler is not None:
1462 if prevhandler is not None:
1475 signal.signal(signal.SIGCHLD, prevhandler)
1463 signal.signal(signal.SIGCHLD, prevhandler)
1476
1464
1477 try:
1465 try:
1478 any, all = any, all
1466 any, all = any, all
1479 except NameError:
1467 except NameError:
1480 def any(iterable):
1468 def any(iterable):
1481 for i in iterable:
1469 for i in iterable:
1482 if i:
1470 if i:
1483 return True
1471 return True
1484 return False
1472 return False
1485
1473
1486 def all(iterable):
1474 def all(iterable):
1487 for i in iterable:
1475 for i in iterable:
1488 if not i:
1476 if not i:
1489 return False
1477 return False
1490 return True
1478 return True
1491
1479
1492 def interpolate(prefix, mapping, s, fn=None, escape_prefix=False):
1480 def interpolate(prefix, mapping, s, fn=None, escape_prefix=False):
1493 """Return the result of interpolating items in the mapping into string s.
1481 """Return the result of interpolating items in the mapping into string s.
1494
1482
1495 prefix is a single character string, or a two character string with
1483 prefix is a single character string, or a two character string with
1496 a backslash as the first character if the prefix needs to be escaped in
1484 a backslash as the first character if the prefix needs to be escaped in
1497 a regular expression.
1485 a regular expression.
1498
1486
1499 fn is an optional function that will be applied to the replacement text
1487 fn is an optional function that will be applied to the replacement text
1500 just before replacement.
1488 just before replacement.
1501
1489
1502 escape_prefix is an optional flag that allows using doubled prefix for
1490 escape_prefix is an optional flag that allows using doubled prefix for
1503 its escaping.
1491 its escaping.
1504 """
1492 """
1505 fn = fn or (lambda s: s)
1493 fn = fn or (lambda s: s)
1506 patterns = '|'.join(mapping.keys())
1494 patterns = '|'.join(mapping.keys())
1507 if escape_prefix:
1495 if escape_prefix:
1508 patterns += '|' + prefix
1496 patterns += '|' + prefix
1509 if len(prefix) > 1:
1497 if len(prefix) > 1:
1510 prefix_char = prefix[1:]
1498 prefix_char = prefix[1:]
1511 else:
1499 else:
1512 prefix_char = prefix
1500 prefix_char = prefix
1513 mapping[prefix_char] = prefix_char
1501 mapping[prefix_char] = prefix_char
1514 r = re.compile(r'%s(%s)' % (prefix, patterns))
1502 r = re.compile(r'%s(%s)' % (prefix, patterns))
1515 return r.sub(lambda x: fn(mapping[x.group()[1:]]), s)
1503 return r.sub(lambda x: fn(mapping[x.group()[1:]]), s)
1516
1504
1517 def getport(port):
1505 def getport(port):
1518 """Return the port for a given network service.
1506 """Return the port for a given network service.
1519
1507
1520 If port is an integer, it's returned as is. If it's a string, it's
1508 If port is an integer, it's returned as is. If it's a string, it's
1521 looked up using socket.getservbyname(). If there's no matching
1509 looked up using socket.getservbyname(). If there's no matching
1522 service, util.Abort is raised.
1510 service, util.Abort is raised.
1523 """
1511 """
1524 try:
1512 try:
1525 return int(port)
1513 return int(port)
1526 except ValueError:
1514 except ValueError:
1527 pass
1515 pass
1528
1516
1529 try:
1517 try:
1530 return socket.getservbyname(port)
1518 return socket.getservbyname(port)
1531 except socket.error:
1519 except socket.error:
1532 raise Abort(_("no port number associated with service '%s'") % port)
1520 raise Abort(_("no port number associated with service '%s'") % port)
1533
1521
1534 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True, 'always': True,
1522 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True, 'always': True,
1535 '0': False, 'no': False, 'false': False, 'off': False,
1523 '0': False, 'no': False, 'false': False, 'off': False,
1536 'never': False}
1524 'never': False}
1537
1525
1538 def parsebool(s):
1526 def parsebool(s):
1539 """Parse s into a boolean.
1527 """Parse s into a boolean.
1540
1528
1541 If s is not a valid boolean, returns None.
1529 If s is not a valid boolean, returns None.
1542 """
1530 """
1543 return _booleans.get(s.lower(), None)
1531 return _booleans.get(s.lower(), None)
@@ -1,325 +1,328 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, error
9 import osutil, error
10 import errno, msvcrt, os, re, sys, subprocess
10 import errno, msvcrt, os, re, sys, subprocess
11
11
12 nulldev = 'NUL:'
12 nulldev = 'NUL:'
13 umask = 002
13 umask = 002
14
14
15 # wrap osutil.posixfile to provide friendlier exceptions
15 # wrap osutil.posixfile to provide friendlier exceptions
16 def posixfile(name, mode='r', buffering=-1):
16 def posixfile(name, mode='r', buffering=-1):
17 try:
17 try:
18 return osutil.posixfile(name, mode, buffering)
18 return osutil.posixfile(name, mode, buffering)
19 except WindowsError, err:
19 except WindowsError, err:
20 raise IOError(err.errno, '%s: %s' % (name, err.strerror))
20 raise IOError(err.errno, '%s: %s' % (name, err.strerror))
21 posixfile.__doc__ = osutil.posixfile.__doc__
21 posixfile.__doc__ = osutil.posixfile.__doc__
22
22
23 class winstdout(object):
23 class winstdout(object):
24 '''stdout on windows misbehaves if sent through a pipe'''
24 '''stdout on windows misbehaves if sent through a pipe'''
25
25
26 def __init__(self, fp):
26 def __init__(self, fp):
27 self.fp = fp
27 self.fp = fp
28
28
29 def __getattr__(self, key):
29 def __getattr__(self, key):
30 return getattr(self.fp, key)
30 return getattr(self.fp, key)
31
31
32 def close(self):
32 def close(self):
33 try:
33 try:
34 self.fp.close()
34 self.fp.close()
35 except: pass
35 except: pass
36
36
37 def write(self, s):
37 def write(self, s):
38 try:
38 try:
39 # This is workaround for "Not enough space" error on
39 # This is workaround for "Not enough space" error on
40 # writing large size of data to console.
40 # writing large size of data to console.
41 limit = 16000
41 limit = 16000
42 l = len(s)
42 l = len(s)
43 start = 0
43 start = 0
44 self.softspace = 0
44 self.softspace = 0
45 while start < l:
45 while start < l:
46 end = start + limit
46 end = start + limit
47 self.fp.write(s[start:end])
47 self.fp.write(s[start:end])
48 start = end
48 start = end
49 except IOError, inst:
49 except IOError, inst:
50 if inst.errno != 0:
50 if inst.errno != 0:
51 raise
51 raise
52 self.close()
52 self.close()
53 raise IOError(errno.EPIPE, 'Broken pipe')
53 raise IOError(errno.EPIPE, 'Broken pipe')
54
54
55 def flush(self):
55 def flush(self):
56 try:
56 try:
57 return self.fp.flush()
57 return self.fp.flush()
58 except IOError, inst:
58 except IOError, inst:
59 if inst.errno != errno.EINVAL:
59 if inst.errno != errno.EINVAL:
60 raise
60 raise
61 self.close()
61 self.close()
62 raise IOError(errno.EPIPE, 'Broken pipe')
62 raise IOError(errno.EPIPE, 'Broken pipe')
63
63
64 sys.stdout = winstdout(sys.stdout)
64 sys.stdout = winstdout(sys.stdout)
65
65
66 def _is_win_9x():
66 def _is_win_9x():
67 '''return true if run on windows 95, 98 or me.'''
67 '''return true if run on windows 95, 98 or me.'''
68 try:
68 try:
69 return sys.getwindowsversion()[3] == 1
69 return sys.getwindowsversion()[3] == 1
70 except AttributeError:
70 except AttributeError:
71 return 'command' in os.environ.get('comspec', '')
71 return 'command' in os.environ.get('comspec', '')
72
72
73 def openhardlinks():
73 def openhardlinks():
74 return not _is_win_9x()
74 return not _is_win_9x()
75
75
76 _HKEY_LOCAL_MACHINE = 0x80000002L
76 _HKEY_LOCAL_MACHINE = 0x80000002L
77
77
78 def system_rcpath():
78 def system_rcpath():
79 '''return default os-specific hgrc search path'''
79 '''return default os-specific hgrc search path'''
80 rcpath = []
80 rcpath = []
81 filename = executable_path()
81 filename = executable_path()
82 # Use mercurial.ini found in directory with hg.exe
82 # Use mercurial.ini found in directory with hg.exe
83 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
83 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
84 if os.path.isfile(progrc):
84 if os.path.isfile(progrc):
85 rcpath.append(progrc)
85 rcpath.append(progrc)
86 return rcpath
86 return rcpath
87 # Use hgrc.d found in directory with hg.exe
87 # Use hgrc.d found in directory with hg.exe
88 progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
88 progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
89 if os.path.isdir(progrcd):
89 if os.path.isdir(progrcd):
90 for f, kind in osutil.listdir(progrcd):
90 for f, kind in osutil.listdir(progrcd):
91 if f.endswith('.rc'):
91 if f.endswith('.rc'):
92 rcpath.append(os.path.join(progrcd, f))
92 rcpath.append(os.path.join(progrcd, f))
93 return rcpath
93 return rcpath
94 # else look for a system rcpath in the registry
94 # else look for a system rcpath in the registry
95 value = lookup_reg('SOFTWARE\\Mercurial', None, _HKEY_LOCAL_MACHINE)
95 value = lookup_reg('SOFTWARE\\Mercurial', None, _HKEY_LOCAL_MACHINE)
96 if not isinstance(value, str) or not value:
96 if not isinstance(value, str) or not value:
97 return rcpath
97 return rcpath
98 value = value.replace('/', os.sep)
98 value = value.replace('/', os.sep)
99 for p in value.split(os.pathsep):
99 for p in value.split(os.pathsep):
100 if p.lower().endswith('mercurial.ini'):
100 if p.lower().endswith('mercurial.ini'):
101 rcpath.append(p)
101 rcpath.append(p)
102 elif os.path.isdir(p):
102 elif os.path.isdir(p):
103 for f, kind in osutil.listdir(p):
103 for f, kind in osutil.listdir(p):
104 if f.endswith('.rc'):
104 if f.endswith('.rc'):
105 rcpath.append(os.path.join(p, f))
105 rcpath.append(os.path.join(p, f))
106 return rcpath
106 return rcpath
107
107
108 def user_rcpath():
108 def user_rcpath():
109 '''return os-specific hgrc search path to the user dir'''
109 '''return os-specific hgrc search path to the user dir'''
110 home = os.path.expanduser('~')
110 home = os.path.expanduser('~')
111 path = [os.path.join(home, 'mercurial.ini'),
111 path = [os.path.join(home, 'mercurial.ini'),
112 os.path.join(home, '.hgrc')]
112 os.path.join(home, '.hgrc')]
113 userprofile = os.environ.get('USERPROFILE')
113 userprofile = os.environ.get('USERPROFILE')
114 if userprofile:
114 if userprofile:
115 path.append(os.path.join(userprofile, 'mercurial.ini'))
115 path.append(os.path.join(userprofile, 'mercurial.ini'))
116 path.append(os.path.join(userprofile, '.hgrc'))
116 path.append(os.path.join(userprofile, '.hgrc'))
117 return path
117 return path
118
118
119 def parse_patch_output(output_line):
119 def parse_patch_output(output_line):
120 """parses the output produced by patch and returns the filename"""
120 """parses the output produced by patch and returns the filename"""
121 pf = output_line[14:]
121 pf = output_line[14:]
122 if pf[0] == '`':
122 if pf[0] == '`':
123 pf = pf[1:-1] # Remove the quotes
123 pf = pf[1:-1] # Remove the quotes
124 return pf
124 return pf
125
125
126 def sshargs(sshcmd, host, user, port):
126 def sshargs(sshcmd, host, user, port):
127 '''Build argument list for ssh or Plink'''
127 '''Build argument list for ssh or Plink'''
128 pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
128 pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
129 args = user and ("%s@%s" % (user, host)) or host
129 args = user and ("%s@%s" % (user, host)) or host
130 return port and ("%s %s %s" % (args, pflag, port)) or args
130 return port and ("%s %s %s" % (args, pflag, port)) or args
131
131
132 def set_flags(f, l, x):
132 def set_flags(f, l, x):
133 pass
133 pass
134
134
135 def checkexec(path):
135 def checkexec(path):
136 return False
136 return False
137
137
138 def checklink(path):
139 return False
140
138 def set_binary(fd):
141 def set_binary(fd):
139 # When run without console, pipes may expose invalid
142 # When run without console, pipes may expose invalid
140 # fileno(), usually set to -1.
143 # fileno(), usually set to -1.
141 if hasattr(fd, 'fileno') and fd.fileno() >= 0:
144 if hasattr(fd, 'fileno') and fd.fileno() >= 0:
142 msvcrt.setmode(fd.fileno(), os.O_BINARY)
145 msvcrt.setmode(fd.fileno(), os.O_BINARY)
143
146
144 def pconvert(path):
147 def pconvert(path):
145 return '/'.join(path.split(os.sep))
148 return '/'.join(path.split(os.sep))
146
149
147 def localpath(path):
150 def localpath(path):
148 return path.replace('/', '\\')
151 return path.replace('/', '\\')
149
152
150 def normpath(path):
153 def normpath(path):
151 return pconvert(os.path.normpath(path))
154 return pconvert(os.path.normpath(path))
152
155
153 def realpath(path):
156 def realpath(path):
154 '''
157 '''
155 Returns the true, canonical file system path equivalent to the given
158 Returns the true, canonical file system path equivalent to the given
156 path.
159 path.
157 '''
160 '''
158 # TODO: There may be a more clever way to do this that also handles other,
161 # TODO: There may be a more clever way to do this that also handles other,
159 # less common file systems.
162 # less common file systems.
160 return os.path.normpath(os.path.normcase(os.path.realpath(path)))
163 return os.path.normpath(os.path.normcase(os.path.realpath(path)))
161
164
162 def samestat(s1, s2):
165 def samestat(s1, s2):
163 return False
166 return False
164
167
165 # A sequence of backslashes is special iff it precedes a double quote:
168 # A sequence of backslashes is special iff it precedes a double quote:
166 # - if there's an even number of backslashes, the double quote is not
169 # - if there's an even number of backslashes, the double quote is not
167 # quoted (i.e. it ends the quoted region)
170 # quoted (i.e. it ends the quoted region)
168 # - if there's an odd number of backslashes, the double quote is quoted
171 # - if there's an odd number of backslashes, the double quote is quoted
169 # - in both cases, every pair of backslashes is unquoted into a single
172 # - in both cases, every pair of backslashes is unquoted into a single
170 # backslash
173 # backslash
171 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
174 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
172 # So, to quote a string, we must surround it in double quotes, double
175 # So, to quote a string, we must surround it in double quotes, double
173 # the number of backslashes that preceed double quotes and add another
176 # the number of backslashes that preceed double quotes and add another
174 # backslash before every double quote (being careful with the double
177 # backslash before every double quote (being careful with the double
175 # quote we've appended to the end)
178 # quote we've appended to the end)
176 _quotere = None
179 _quotere = None
177 def shellquote(s):
180 def shellquote(s):
178 global _quotere
181 global _quotere
179 if _quotere is None:
182 if _quotere is None:
180 _quotere = re.compile(r'(\\*)("|\\$)')
183 _quotere = re.compile(r'(\\*)("|\\$)')
181 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
184 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
182
185
183 def quotecommand(cmd):
186 def quotecommand(cmd):
184 """Build a command string suitable for os.popen* calls."""
187 """Build a command string suitable for os.popen* calls."""
185 if sys.version_info < (2, 7, 1):
188 if sys.version_info < (2, 7, 1):
186 # Python versions since 2.7.1 do this extra quoting themselves
189 # Python versions since 2.7.1 do this extra quoting themselves
187 return '"' + cmd + '"'
190 return '"' + cmd + '"'
188 return cmd
191 return cmd
189
192
190 def popen(command, mode='r'):
193 def popen(command, mode='r'):
191 # Work around "popen spawned process may not write to stdout
194 # Work around "popen spawned process may not write to stdout
192 # under windows"
195 # under windows"
193 # http://bugs.python.org/issue1366
196 # http://bugs.python.org/issue1366
194 command += " 2> %s" % nulldev
197 command += " 2> %s" % nulldev
195 return os.popen(quotecommand(command), mode)
198 return os.popen(quotecommand(command), mode)
196
199
197 def explain_exit(code):
200 def explain_exit(code):
198 return _("exited with status %d") % code, code
201 return _("exited with status %d") % code, code
199
202
200 # if you change this stub into a real check, please try to implement the
203 # if you change this stub into a real check, please try to implement the
201 # username and groupname functions above, too.
204 # username and groupname functions above, too.
202 def isowner(st):
205 def isowner(st):
203 return True
206 return True
204
207
205 def find_exe(command):
208 def find_exe(command):
206 '''Find executable for command searching like cmd.exe does.
209 '''Find executable for command searching like cmd.exe does.
207 If command is a basename then PATH is searched for command.
210 If command is a basename then PATH is searched for command.
208 PATH isn't searched if command is an absolute or relative path.
211 PATH isn't searched if command is an absolute or relative path.
209 An extension from PATHEXT is found and added if not present.
212 An extension from PATHEXT is found and added if not present.
210 If command isn't found None is returned.'''
213 If command isn't found None is returned.'''
211 pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
214 pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
212 pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
215 pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
213 if os.path.splitext(command)[1].lower() in pathexts:
216 if os.path.splitext(command)[1].lower() in pathexts:
214 pathexts = ['']
217 pathexts = ['']
215
218
216 def findexisting(pathcommand):
219 def findexisting(pathcommand):
217 'Will append extension (if needed) and return existing file'
220 'Will append extension (if needed) and return existing file'
218 for ext in pathexts:
221 for ext in pathexts:
219 executable = pathcommand + ext
222 executable = pathcommand + ext
220 if os.path.exists(executable):
223 if os.path.exists(executable):
221 return executable
224 return executable
222 return None
225 return None
223
226
224 if os.sep in command:
227 if os.sep in command:
225 return findexisting(command)
228 return findexisting(command)
226
229
227 for path in os.environ.get('PATH', '').split(os.pathsep):
230 for path in os.environ.get('PATH', '').split(os.pathsep):
228 executable = findexisting(os.path.join(path, command))
231 executable = findexisting(os.path.join(path, command))
229 if executable is not None:
232 if executable is not None:
230 return executable
233 return executable
231 return findexisting(os.path.expanduser(os.path.expandvars(command)))
234 return findexisting(os.path.expanduser(os.path.expandvars(command)))
232
235
233 def statfiles(files):
236 def statfiles(files):
234 '''Stat each file in files and yield stat or None if file does not exist.
237 '''Stat each file in files and yield stat or None if file does not exist.
235 Cluster and cache stat per directory to minimize number of OS stat calls.'''
238 Cluster and cache stat per directory to minimize number of OS stat calls.'''
236 ncase = os.path.normcase
239 ncase = os.path.normcase
237 dircache = {} # dirname -> filename -> status | None if file does not exist
240 dircache = {} # dirname -> filename -> status | None if file does not exist
238 for nf in files:
241 for nf in files:
239 nf = ncase(nf)
242 nf = ncase(nf)
240 dir, base = os.path.split(nf)
243 dir, base = os.path.split(nf)
241 if not dir:
244 if not dir:
242 dir = '.'
245 dir = '.'
243 cache = dircache.get(dir, None)
246 cache = dircache.get(dir, None)
244 if cache is None:
247 if cache is None:
245 try:
248 try:
246 dmap = dict([(ncase(n), s)
249 dmap = dict([(ncase(n), s)
247 for n, k, s in osutil.listdir(dir, True)])
250 for n, k, s in osutil.listdir(dir, True)])
248 except OSError, err:
251 except OSError, err:
249 # handle directory not found in Python version prior to 2.5
252 # handle directory not found in Python version prior to 2.5
250 # Python <= 2.4 returns native Windows code 3 in errno
253 # Python <= 2.4 returns native Windows code 3 in errno
251 # Python >= 2.5 returns ENOENT and adds winerror field
254 # Python >= 2.5 returns ENOENT and adds winerror field
252 # EINVAL is raised if dir is not a directory.
255 # EINVAL is raised if dir is not a directory.
253 if err.errno not in (3, errno.ENOENT, errno.EINVAL,
256 if err.errno not in (3, errno.ENOENT, errno.EINVAL,
254 errno.ENOTDIR):
257 errno.ENOTDIR):
255 raise
258 raise
256 dmap = {}
259 dmap = {}
257 cache = dircache.setdefault(dir, dmap)
260 cache = dircache.setdefault(dir, dmap)
258 yield cache.get(base, None)
261 yield cache.get(base, None)
259
262
260 def username(uid=None):
263 def username(uid=None):
261 """Return the name of the user with the given uid.
264 """Return the name of the user with the given uid.
262
265
263 If uid is None, return the name of the current user."""
266 If uid is None, return the name of the current user."""
264 return None
267 return None
265
268
266 def groupname(gid=None):
269 def groupname(gid=None):
267 """Return the name of the group with the given gid.
270 """Return the name of the group with the given gid.
268
271
269 If gid is None, return the name of the current group."""
272 If gid is None, return the name of the current group."""
270 return None
273 return None
271
274
272 def _removedirs(name):
275 def _removedirs(name):
273 """special version of os.removedirs that does not remove symlinked
276 """special version of os.removedirs that does not remove symlinked
274 directories or junction points if they actually contain files"""
277 directories or junction points if they actually contain files"""
275 if osutil.listdir(name):
278 if osutil.listdir(name):
276 return
279 return
277 os.rmdir(name)
280 os.rmdir(name)
278 head, tail = os.path.split(name)
281 head, tail = os.path.split(name)
279 if not tail:
282 if not tail:
280 head, tail = os.path.split(head)
283 head, tail = os.path.split(head)
281 while head and tail:
284 while head and tail:
282 try:
285 try:
283 if osutil.listdir(head):
286 if osutil.listdir(head):
284 return
287 return
285 os.rmdir(head)
288 os.rmdir(head)
286 except:
289 except:
287 break
290 break
288 head, tail = os.path.split(head)
291 head, tail = os.path.split(head)
289
292
290 def unlinkpath(f):
293 def unlinkpath(f):
291 """unlink and remove the directory if it is empty"""
294 """unlink and remove the directory if it is empty"""
292 unlink(f)
295 unlink(f)
293 # try removing directories that might now be empty
296 # try removing directories that might now be empty
294 try:
297 try:
295 _removedirs(os.path.dirname(f))
298 _removedirs(os.path.dirname(f))
296 except OSError:
299 except OSError:
297 pass
300 pass
298
301
299 def rename(src, dst):
302 def rename(src, dst):
300 '''atomically rename file src to dst, replacing dst if it exists'''
303 '''atomically rename file src to dst, replacing dst if it exists'''
301 try:
304 try:
302 os.rename(src, dst)
305 os.rename(src, dst)
303 except OSError, e:
306 except OSError, e:
304 if e.errno != errno.EEXIST:
307 if e.errno != errno.EEXIST:
305 raise
308 raise
306 unlink(dst)
309 unlink(dst)
307 os.rename(src, dst)
310 os.rename(src, dst)
308
311
309 def gethgcmd():
312 def gethgcmd():
310 return [sys.executable] + sys.argv[:1]
313 return [sys.executable] + sys.argv[:1]
311
314
312 def termwidth():
315 def termwidth():
313 # cmd.exe does not handle CR like a unix console, the CR is
316 # cmd.exe does not handle CR like a unix console, the CR is
314 # counted in the line length. On 80 columns consoles, if 80
317 # counted in the line length. On 80 columns consoles, if 80
315 # characters are written, the following CR won't apply on the
318 # characters are written, the following CR won't apply on the
316 # current line but on the new one. Keep room for it.
319 # current line but on the new one. Keep room for it.
317 return 79
320 return 79
318
321
319 def groupmembers(name):
322 def groupmembers(name):
320 # Don't support groups on Windows for now
323 # Don't support groups on Windows for now
321 raise KeyError()
324 raise KeyError()
322
325
323 from win32 import *
326 from win32 import *
324
327
325 expandglobs = True
328 expandglobs = True
General Comments 0
You need to be logged in to leave comments. Login now