##// END OF EJS Templates
path_auditor: check filenames for basic platform validity (issue2755)...
Adrian Buehlmann -
r13916:98ee3dd5 default
parent child Browse files
Show More
@@ -1,348 +1,353 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):
138 def checklink(path):
139 """check whether the given path is on a symlink-capable filesystem"""
139 """check whether the given path is on a symlink-capable filesystem"""
140 # mktemp is not racy because symlink creation will fail if the
140 # mktemp is not racy because symlink creation will fail if the
141 # file already exists
141 # file already exists
142 name = tempfile.mktemp(dir=path, prefix='hg-checklink-')
142 name = tempfile.mktemp(dir=path, prefix='hg-checklink-')
143 try:
143 try:
144 os.symlink(".", name)
144 os.symlink(".", name)
145 os.unlink(name)
145 os.unlink(name)
146 return True
146 return True
147 except (OSError, AttributeError):
147 except (OSError, AttributeError):
148 return False
148 return False
149
149
150 def checkosfilename(path):
151 '''Check that the base-relative path is a valid filename on this platform.
152 Returns None if the path is ok, or a UI string describing the problem.'''
153 pass # on posix platforms, every path is ok
154
150 def set_binary(fd):
155 def set_binary(fd):
151 pass
156 pass
152
157
153 def pconvert(path):
158 def pconvert(path):
154 return path
159 return path
155
160
156 def localpath(path):
161 def localpath(path):
157 return path
162 return path
158
163
159 def samefile(fpath1, fpath2):
164 def samefile(fpath1, fpath2):
160 """Returns whether path1 and path2 refer to the same file. This is only
165 """Returns whether path1 and path2 refer to the same file. This is only
161 guaranteed to work for files, not directories."""
166 guaranteed to work for files, not directories."""
162 return os.path.samefile(fpath1, fpath2)
167 return os.path.samefile(fpath1, fpath2)
163
168
164 def samedevice(fpath1, fpath2):
169 def samedevice(fpath1, fpath2):
165 """Returns whether fpath1 and fpath2 are on the same device. This is only
170 """Returns whether fpath1 and fpath2 are on the same device. This is only
166 guaranteed to work for files, not directories."""
171 guaranteed to work for files, not directories."""
167 st1 = os.lstat(fpath1)
172 st1 = os.lstat(fpath1)
168 st2 = os.lstat(fpath2)
173 st2 = os.lstat(fpath2)
169 return st1.st_dev == st2.st_dev
174 return st1.st_dev == st2.st_dev
170
175
171 if sys.platform == 'darwin':
176 if sys.platform == 'darwin':
172 import fcntl # only needed on darwin, missing on jython
177 import fcntl # only needed on darwin, missing on jython
173 def realpath(path):
178 def realpath(path):
174 '''
179 '''
175 Returns the true, canonical file system path equivalent to the given
180 Returns the true, canonical file system path equivalent to the given
176 path.
181 path.
177
182
178 Equivalent means, in this case, resulting in the same, unique
183 Equivalent means, in this case, resulting in the same, unique
179 file system link to the path. Every file system entry, whether a file,
184 file system link to the path. Every file system entry, whether a file,
180 directory, hard link or symbolic link or special, will have a single
185 directory, hard link or symbolic link or special, will have a single
181 path preferred by the system, but may allow multiple, differing path
186 path preferred by the system, but may allow multiple, differing path
182 lookups to point to it.
187 lookups to point to it.
183
188
184 Most regular UNIX file systems only allow a file system entry to be
189 Most regular UNIX file systems only allow a file system entry to be
185 looked up by its distinct path. Obviously, this does not apply to case
190 looked up by its distinct path. Obviously, this does not apply to case
186 insensitive file systems, whether case preserving or not. The most
191 insensitive file systems, whether case preserving or not. The most
187 complex issue to deal with is file systems transparently reencoding the
192 complex issue to deal with is file systems transparently reencoding the
188 path, such as the non-standard Unicode normalisation required for HFS+
193 path, such as the non-standard Unicode normalisation required for HFS+
189 and HFSX.
194 and HFSX.
190 '''
195 '''
191 # Constants copied from /usr/include/sys/fcntl.h
196 # Constants copied from /usr/include/sys/fcntl.h
192 F_GETPATH = 50
197 F_GETPATH = 50
193 O_SYMLINK = 0x200000
198 O_SYMLINK = 0x200000
194
199
195 try:
200 try:
196 fd = os.open(path, O_SYMLINK)
201 fd = os.open(path, O_SYMLINK)
197 except OSError, err:
202 except OSError, err:
198 if err.errno == errno.ENOENT:
203 if err.errno == errno.ENOENT:
199 return path
204 return path
200 raise
205 raise
201
206
202 try:
207 try:
203 return fcntl.fcntl(fd, F_GETPATH, '\0' * 1024).rstrip('\0')
208 return fcntl.fcntl(fd, F_GETPATH, '\0' * 1024).rstrip('\0')
204 finally:
209 finally:
205 os.close(fd)
210 os.close(fd)
206 else:
211 else:
207 # Fallback to the likely inadequate Python builtin function.
212 # Fallback to the likely inadequate Python builtin function.
208 realpath = os.path.realpath
213 realpath = os.path.realpath
209
214
210 def shellquote(s):
215 def shellquote(s):
211 if os.sys.platform == 'OpenVMS':
216 if os.sys.platform == 'OpenVMS':
212 return '"%s"' % s
217 return '"%s"' % s
213 else:
218 else:
214 return "'%s'" % s.replace("'", "'\\''")
219 return "'%s'" % s.replace("'", "'\\''")
215
220
216 def quotecommand(cmd):
221 def quotecommand(cmd):
217 return cmd
222 return cmd
218
223
219 def popen(command, mode='r'):
224 def popen(command, mode='r'):
220 return os.popen(command, mode)
225 return os.popen(command, mode)
221
226
222 def testpid(pid):
227 def testpid(pid):
223 '''return False if pid dead, True if running or not sure'''
228 '''return False if pid dead, True if running or not sure'''
224 if os.sys.platform == 'OpenVMS':
229 if os.sys.platform == 'OpenVMS':
225 return True
230 return True
226 try:
231 try:
227 os.kill(pid, 0)
232 os.kill(pid, 0)
228 return True
233 return True
229 except OSError, inst:
234 except OSError, inst:
230 return inst.errno != errno.ESRCH
235 return inst.errno != errno.ESRCH
231
236
232 def explain_exit(code):
237 def explain_exit(code):
233 """return a 2-tuple (desc, code) describing a subprocess status
238 """return a 2-tuple (desc, code) describing a subprocess status
234 (codes from kill are negative - not os.system/wait encoding)"""
239 (codes from kill are negative - not os.system/wait encoding)"""
235 if code >= 0:
240 if code >= 0:
236 return _("exited with status %d") % code, code
241 return _("exited with status %d") % code, code
237 return _("killed by signal %d") % -code, -code
242 return _("killed by signal %d") % -code, -code
238
243
239 def isowner(st):
244 def isowner(st):
240 """Return True if the stat object st is from the current user."""
245 """Return True if the stat object st is from the current user."""
241 return st.st_uid == os.getuid()
246 return st.st_uid == os.getuid()
242
247
243 def find_exe(command):
248 def find_exe(command):
244 '''Find executable for command searching like which does.
249 '''Find executable for command searching like which does.
245 If command is a basename then PATH is searched for command.
250 If command is a basename then PATH is searched for command.
246 PATH isn't searched if command is an absolute or relative path.
251 PATH isn't searched if command is an absolute or relative path.
247 If command isn't found None is returned.'''
252 If command isn't found None is returned.'''
248 if sys.platform == 'OpenVMS':
253 if sys.platform == 'OpenVMS':
249 return command
254 return command
250
255
251 def findexisting(executable):
256 def findexisting(executable):
252 'Will return executable if existing file'
257 'Will return executable if existing file'
253 if os.path.exists(executable):
258 if os.path.exists(executable):
254 return executable
259 return executable
255 return None
260 return None
256
261
257 if os.sep in command:
262 if os.sep in command:
258 return findexisting(command)
263 return findexisting(command)
259
264
260 for path in os.environ.get('PATH', '').split(os.pathsep):
265 for path in os.environ.get('PATH', '').split(os.pathsep):
261 executable = findexisting(os.path.join(path, command))
266 executable = findexisting(os.path.join(path, command))
262 if executable is not None:
267 if executable is not None:
263 return executable
268 return executable
264 return None
269 return None
265
270
266 def set_signal_handler():
271 def set_signal_handler():
267 pass
272 pass
268
273
269 def statfiles(files):
274 def statfiles(files):
270 'Stat each file in files and yield stat or None if file does not exist.'
275 'Stat each file in files and yield stat or None if file does not exist.'
271 lstat = os.lstat
276 lstat = os.lstat
272 for nf in files:
277 for nf in files:
273 try:
278 try:
274 st = lstat(nf)
279 st = lstat(nf)
275 except OSError, err:
280 except OSError, err:
276 if err.errno not in (errno.ENOENT, errno.ENOTDIR):
281 if err.errno not in (errno.ENOENT, errno.ENOTDIR):
277 raise
282 raise
278 st = None
283 st = None
279 yield st
284 yield st
280
285
281 def getuser():
286 def getuser():
282 '''return name of current user'''
287 '''return name of current user'''
283 return getpass.getuser()
288 return getpass.getuser()
284
289
285 def expand_glob(pats):
290 def expand_glob(pats):
286 '''On Windows, expand the implicit globs in a list of patterns'''
291 '''On Windows, expand the implicit globs in a list of patterns'''
287 return list(pats)
292 return list(pats)
288
293
289 def username(uid=None):
294 def username(uid=None):
290 """Return the name of the user with the given uid.
295 """Return the name of the user with the given uid.
291
296
292 If uid is None, return the name of the current user."""
297 If uid is None, return the name of the current user."""
293
298
294 if uid is None:
299 if uid is None:
295 uid = os.getuid()
300 uid = os.getuid()
296 try:
301 try:
297 return pwd.getpwuid(uid)[0]
302 return pwd.getpwuid(uid)[0]
298 except KeyError:
303 except KeyError:
299 return str(uid)
304 return str(uid)
300
305
301 def groupname(gid=None):
306 def groupname(gid=None):
302 """Return the name of the group with the given gid.
307 """Return the name of the group with the given gid.
303
308
304 If gid is None, return the name of the current group."""
309 If gid is None, return the name of the current group."""
305
310
306 if gid is None:
311 if gid is None:
307 gid = os.getgid()
312 gid = os.getgid()
308 try:
313 try:
309 return grp.getgrgid(gid)[0]
314 return grp.getgrgid(gid)[0]
310 except KeyError:
315 except KeyError:
311 return str(gid)
316 return str(gid)
312
317
313 def groupmembers(name):
318 def groupmembers(name):
314 """Return the list of members of the group with the given
319 """Return the list of members of the group with the given
315 name, KeyError if the group does not exist.
320 name, KeyError if the group does not exist.
316 """
321 """
317 return list(grp.getgrnam(name).gr_mem)
322 return list(grp.getgrnam(name).gr_mem)
318
323
319 def spawndetached(args):
324 def spawndetached(args):
320 return os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
325 return os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
321 args[0], args)
326 args[0], args)
322
327
323 def gethgcmd():
328 def gethgcmd():
324 return sys.argv[:1]
329 return sys.argv[:1]
325
330
326 def termwidth():
331 def termwidth():
327 try:
332 try:
328 import termios, array, fcntl
333 import termios, array, fcntl
329 for dev in (sys.stderr, sys.stdout, sys.stdin):
334 for dev in (sys.stderr, sys.stdout, sys.stdin):
330 try:
335 try:
331 try:
336 try:
332 fd = dev.fileno()
337 fd = dev.fileno()
333 except AttributeError:
338 except AttributeError:
334 continue
339 continue
335 if not os.isatty(fd):
340 if not os.isatty(fd):
336 continue
341 continue
337 arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8)
342 arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8)
338 return array.array('h', arri)[1]
343 return array.array('h', arri)[1]
339 except ValueError:
344 except ValueError:
340 pass
345 pass
341 except IOError, e:
346 except IOError, e:
342 if e[0] == errno.EINVAL:
347 if e[0] == errno.EINVAL:
343 pass
348 pass
344 else:
349 else:
345 raise
350 raise
346 except ImportError:
351 except ImportError:
347 pass
352 pass
348 return 80
353 return 80
@@ -1,1532 +1,1578 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 _windows_reserved_filenames = '''con prn aux nul
497 com1 com2 com3 com4 com5 com6 com7 com8 com9
498 lpt1 lpt2 lpt3 lpt4 lpt5 lpt6 lpt7 lpt8 lpt9'''.split()
499 _windows_reserved_chars = ':*?"<>|'
500 def checkwinfilename(path):
501 '''Check that the base-relative path is a valid filename on Windows.
502 Returns None if the path is ok, or a UI string describing the problem.
503
504 >>> checkwinfilename("just/a/normal/path")
505 >>> checkwinfilename("foo/bar/con.xml")
506 "filename contains 'con', which is reserved on Windows"
507 >>> checkwinfilename("foo/con.xml/bar")
508 "filename contains 'con', which is reserved on Windows"
509 >>> checkwinfilename("foo/bar/xml.con")
510 >>> checkwinfilename("foo/bar/AUX/bla.txt")
511 "filename contains 'AUX', which is reserved on Windows"
512 >>> checkwinfilename("foo/bar/bla:.txt")
513 "filename contains ':', which is reserved on Windows"
514 >>> checkwinfilename("foo/bar/b\07la.txt")
515 "filename contains '\\x07', which is invalid on Windows"
516 >>> checkwinfilename("foo/bar/bla ")
517 "filename ends with ' ', which is not allowed on Windows"
518 '''
519 for n in path.replace('\\', '/').split('/'):
520 if not n:
521 continue
522 for c in n:
523 if c in _windows_reserved_chars:
524 return _("filename contains '%s', which is reserved "
525 "on Windows") % c
526 if ord(c) <= 31:
527 return _("filename contains '%s', which is invalid "
528 "on Windows") % c
529 base = n.split('.')[0]
530 if base and base.lower() in _windows_reserved_filenames:
531 return _("filename contains '%s', which is reserved "
532 "on Windows") % base
533 t = n[-1]
534 if t in '. ':
535 return _("filename ends with '%s', which is not allowed "
536 "on Windows") % t
537
496 class path_auditor(object):
538 class path_auditor(object):
497 '''ensure that a filesystem path contains no banned components.
539 '''ensure that a filesystem path contains no banned components.
498 the following properties of a path are checked:
540 the following properties of a path are checked:
499
541
500 - ends with a directory separator
542 - ends with a directory separator
501 - under top-level .hg
543 - under top-level .hg
502 - starts at the root of a windows drive
544 - starts at the root of a windows drive
503 - contains ".."
545 - contains ".."
504 - traverses a symlink (e.g. a/symlink_here/b)
546 - traverses a symlink (e.g. a/symlink_here/b)
505 - inside a nested repository (a callback can be used to approve
547 - inside a nested repository (a callback can be used to approve
506 some nested repositories, e.g., subrepositories)
548 some nested repositories, e.g., subrepositories)
507 '''
549 '''
508
550
509 def __init__(self, root, callback=None):
551 def __init__(self, root, callback=None):
510 self.audited = set()
552 self.audited = set()
511 self.auditeddir = set()
553 self.auditeddir = set()
512 self.root = root
554 self.root = root
513 self.callback = callback
555 self.callback = callback
514
556
515 def __call__(self, path):
557 def __call__(self, path):
516 if path in self.audited:
558 if path in self.audited:
517 return
559 return
518 # AIX ignores "/" at end of path, others raise EISDIR.
560 # AIX ignores "/" at end of path, others raise EISDIR.
519 if endswithsep(path):
561 if endswithsep(path):
520 raise Abort(_("path ends in directory separator: %s") % path)
562 raise Abort(_("path ends in directory separator: %s") % path)
521 normpath = os.path.normcase(path)
563 normpath = os.path.normcase(path)
522 parts = splitpath(normpath)
564 parts = splitpath(normpath)
523 if (os.path.splitdrive(path)[0]
565 if (os.path.splitdrive(path)[0]
524 or parts[0].lower() in ('.hg', '.hg.', '')
566 or parts[0].lower() in ('.hg', '.hg.', '')
525 or os.pardir in parts):
567 or os.pardir in parts):
526 raise Abort(_("path contains illegal component: %s") % path)
568 raise Abort(_("path contains illegal component: %s") % path)
527 if '.hg' in path.lower():
569 if '.hg' in path.lower():
528 lparts = [p.lower() for p in parts]
570 lparts = [p.lower() for p in parts]
529 for p in '.hg', '.hg.':
571 for p in '.hg', '.hg.':
530 if p in lparts[1:]:
572 if p in lparts[1:]:
531 pos = lparts.index(p)
573 pos = lparts.index(p)
532 base = os.path.join(*parts[:pos])
574 base = os.path.join(*parts[:pos])
533 raise Abort(_('path %r is inside nested repo %r')
575 raise Abort(_('path %r is inside nested repo %r')
534 % (path, base))
576 % (path, base))
535 def check(prefix):
577 def check(prefix):
536 curpath = os.path.join(self.root, prefix)
578 curpath = os.path.join(self.root, prefix)
537 try:
579 try:
538 st = os.lstat(curpath)
580 st = os.lstat(curpath)
539 except OSError, err:
581 except OSError, err:
540 # EINVAL can be raised as invalid path syntax under win32.
582 # EINVAL can be raised as invalid path syntax under win32.
541 # They must be ignored for patterns can be checked too.
583 # They must be ignored for patterns can be checked too.
542 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
584 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
543 raise
585 raise
544 else:
586 else:
545 if stat.S_ISLNK(st.st_mode):
587 if stat.S_ISLNK(st.st_mode):
546 raise Abort(_('path %r traverses symbolic link %r') %
588 raise Abort(_('path %r traverses symbolic link %r') %
547 (path, prefix))
589 (path, prefix))
548 elif (stat.S_ISDIR(st.st_mode) and
590 elif (stat.S_ISDIR(st.st_mode) and
549 os.path.isdir(os.path.join(curpath, '.hg'))):
591 os.path.isdir(os.path.join(curpath, '.hg'))):
550 if not self.callback or not self.callback(curpath):
592 if not self.callback or not self.callback(curpath):
551 raise Abort(_('path %r is inside nested repo %r') %
593 raise Abort(_('path %r is inside nested repo %r') %
552 (path, prefix))
594 (path, prefix))
553 parts.pop()
595 parts.pop()
554 prefixes = []
596 prefixes = []
555 while parts:
597 while parts:
556 prefix = os.sep.join(parts)
598 prefix = os.sep.join(parts)
557 if prefix in self.auditeddir:
599 if prefix in self.auditeddir:
558 break
600 break
559 check(prefix)
601 check(prefix)
560 prefixes.append(prefix)
602 prefixes.append(prefix)
561 parts.pop()
603 parts.pop()
562
604
605 r = checkosfilename(path)
606 if r:
607 raise Abort("%s: %s" % (r, path))
563 self.audited.add(path)
608 self.audited.add(path)
564 # only add prefixes to the cache after checking everything: we don't
609 # only add prefixes to the cache after checking everything: we don't
565 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
610 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
566 self.auditeddir.update(prefixes)
611 self.auditeddir.update(prefixes)
567
612
568 def lookup_reg(key, name=None, scope=None):
613 def lookup_reg(key, name=None, scope=None):
569 return None
614 return None
570
615
571 def hidewindow():
616 def hidewindow():
572 """Hide current shell window.
617 """Hide current shell window.
573
618
574 Used to hide the window opened when starting asynchronous
619 Used to hide the window opened when starting asynchronous
575 child process under Windows, unneeded on other systems.
620 child process under Windows, unneeded on other systems.
576 """
621 """
577 pass
622 pass
578
623
579 if os.name == 'nt':
624 if os.name == 'nt':
625 checkosfilename = checkwinfilename
580 from windows import *
626 from windows import *
581 else:
627 else:
582 from posix import *
628 from posix import *
583
629
584 def makelock(info, pathname):
630 def makelock(info, pathname):
585 try:
631 try:
586 return os.symlink(info, pathname)
632 return os.symlink(info, pathname)
587 except OSError, why:
633 except OSError, why:
588 if why.errno == errno.EEXIST:
634 if why.errno == errno.EEXIST:
589 raise
635 raise
590 except AttributeError: # no symlink in os
636 except AttributeError: # no symlink in os
591 pass
637 pass
592
638
593 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
639 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
594 os.write(ld, info)
640 os.write(ld, info)
595 os.close(ld)
641 os.close(ld)
596
642
597 def readlock(pathname):
643 def readlock(pathname):
598 try:
644 try:
599 return os.readlink(pathname)
645 return os.readlink(pathname)
600 except OSError, why:
646 except OSError, why:
601 if why.errno not in (errno.EINVAL, errno.ENOSYS):
647 if why.errno not in (errno.EINVAL, errno.ENOSYS):
602 raise
648 raise
603 except AttributeError: # no symlink in os
649 except AttributeError: # no symlink in os
604 pass
650 pass
605 fp = posixfile(pathname)
651 fp = posixfile(pathname)
606 r = fp.read()
652 r = fp.read()
607 fp.close()
653 fp.close()
608 return r
654 return r
609
655
610 def fstat(fp):
656 def fstat(fp):
611 '''stat file object that may not have fileno method.'''
657 '''stat file object that may not have fileno method.'''
612 try:
658 try:
613 return os.fstat(fp.fileno())
659 return os.fstat(fp.fileno())
614 except AttributeError:
660 except AttributeError:
615 return os.stat(fp.name)
661 return os.stat(fp.name)
616
662
617 # File system features
663 # File system features
618
664
619 def checkcase(path):
665 def checkcase(path):
620 """
666 """
621 Check whether the given path is on a case-sensitive filesystem
667 Check whether the given path is on a case-sensitive filesystem
622
668
623 Requires a path (like /foo/.hg) ending with a foldable final
669 Requires a path (like /foo/.hg) ending with a foldable final
624 directory component.
670 directory component.
625 """
671 """
626 s1 = os.stat(path)
672 s1 = os.stat(path)
627 d, b = os.path.split(path)
673 d, b = os.path.split(path)
628 p2 = os.path.join(d, b.upper())
674 p2 = os.path.join(d, b.upper())
629 if path == p2:
675 if path == p2:
630 p2 = os.path.join(d, b.lower())
676 p2 = os.path.join(d, b.lower())
631 try:
677 try:
632 s2 = os.stat(p2)
678 s2 = os.stat(p2)
633 if s2 == s1:
679 if s2 == s1:
634 return False
680 return False
635 return True
681 return True
636 except:
682 except:
637 return True
683 return True
638
684
639 _fspathcache = {}
685 _fspathcache = {}
640 def fspath(name, root):
686 def fspath(name, root):
641 '''Get name in the case stored in the filesystem
687 '''Get name in the case stored in the filesystem
642
688
643 The name is either relative to root, or it is an absolute path starting
689 The name is either relative to root, or it is an absolute path starting
644 with root. Note that this function is unnecessary, and should not be
690 with root. Note that this function is unnecessary, and should not be
645 called, for case-sensitive filesystems (simply because it's expensive).
691 called, for case-sensitive filesystems (simply because it's expensive).
646 '''
692 '''
647 # If name is absolute, make it relative
693 # If name is absolute, make it relative
648 if name.lower().startswith(root.lower()):
694 if name.lower().startswith(root.lower()):
649 l = len(root)
695 l = len(root)
650 if name[l] == os.sep or name[l] == os.altsep:
696 if name[l] == os.sep or name[l] == os.altsep:
651 l = l + 1
697 l = l + 1
652 name = name[l:]
698 name = name[l:]
653
699
654 if not os.path.lexists(os.path.join(root, name)):
700 if not os.path.lexists(os.path.join(root, name)):
655 return None
701 return None
656
702
657 seps = os.sep
703 seps = os.sep
658 if os.altsep:
704 if os.altsep:
659 seps = seps + os.altsep
705 seps = seps + os.altsep
660 # Protect backslashes. This gets silly very quickly.
706 # Protect backslashes. This gets silly very quickly.
661 seps.replace('\\','\\\\')
707 seps.replace('\\','\\\\')
662 pattern = re.compile(r'([^%s]+)|([%s]+)' % (seps, seps))
708 pattern = re.compile(r'([^%s]+)|([%s]+)' % (seps, seps))
663 dir = os.path.normcase(os.path.normpath(root))
709 dir = os.path.normcase(os.path.normpath(root))
664 result = []
710 result = []
665 for part, sep in pattern.findall(name):
711 for part, sep in pattern.findall(name):
666 if sep:
712 if sep:
667 result.append(sep)
713 result.append(sep)
668 continue
714 continue
669
715
670 if dir not in _fspathcache:
716 if dir not in _fspathcache:
671 _fspathcache[dir] = os.listdir(dir)
717 _fspathcache[dir] = os.listdir(dir)
672 contents = _fspathcache[dir]
718 contents = _fspathcache[dir]
673
719
674 lpart = part.lower()
720 lpart = part.lower()
675 lenp = len(part)
721 lenp = len(part)
676 for n in contents:
722 for n in contents:
677 if lenp == len(n) and n.lower() == lpart:
723 if lenp == len(n) and n.lower() == lpart:
678 result.append(n)
724 result.append(n)
679 break
725 break
680 else:
726 else:
681 # Cannot happen, as the file exists!
727 # Cannot happen, as the file exists!
682 result.append(part)
728 result.append(part)
683 dir = os.path.join(dir, lpart)
729 dir = os.path.join(dir, lpart)
684
730
685 return ''.join(result)
731 return ''.join(result)
686
732
687 def checknlink(testfile):
733 def checknlink(testfile):
688 '''check whether hardlink count reporting works properly'''
734 '''check whether hardlink count reporting works properly'''
689
735
690 # testfile may be open, so we need a separate file for checking to
736 # testfile may be open, so we need a separate file for checking to
691 # work around issue2543 (or testfile may get lost on Samba shares)
737 # work around issue2543 (or testfile may get lost on Samba shares)
692 f1 = testfile + ".hgtmp1"
738 f1 = testfile + ".hgtmp1"
693 if os.path.lexists(f1):
739 if os.path.lexists(f1):
694 return False
740 return False
695 try:
741 try:
696 posixfile(f1, 'w').close()
742 posixfile(f1, 'w').close()
697 except IOError:
743 except IOError:
698 return False
744 return False
699
745
700 f2 = testfile + ".hgtmp2"
746 f2 = testfile + ".hgtmp2"
701 fd = None
747 fd = None
702 try:
748 try:
703 try:
749 try:
704 os_link(f1, f2)
750 os_link(f1, f2)
705 except OSError:
751 except OSError:
706 return False
752 return False
707
753
708 # nlinks() may behave differently for files on Windows shares if
754 # nlinks() may behave differently for files on Windows shares if
709 # the file is open.
755 # the file is open.
710 fd = posixfile(f2)
756 fd = posixfile(f2)
711 return nlinks(f2) > 1
757 return nlinks(f2) > 1
712 finally:
758 finally:
713 if fd is not None:
759 if fd is not None:
714 fd.close()
760 fd.close()
715 for f in (f1, f2):
761 for f in (f1, f2):
716 try:
762 try:
717 os.unlink(f)
763 os.unlink(f)
718 except OSError:
764 except OSError:
719 pass
765 pass
720
766
721 return False
767 return False
722
768
723 def endswithsep(path):
769 def endswithsep(path):
724 '''Check path ends with os.sep or os.altsep.'''
770 '''Check path ends with os.sep or os.altsep.'''
725 return path.endswith(os.sep) or os.altsep and path.endswith(os.altsep)
771 return path.endswith(os.sep) or os.altsep and path.endswith(os.altsep)
726
772
727 def splitpath(path):
773 def splitpath(path):
728 '''Split path by os.sep.
774 '''Split path by os.sep.
729 Note that this function does not use os.altsep because this is
775 Note that this function does not use os.altsep because this is
730 an alternative of simple "xxx.split(os.sep)".
776 an alternative of simple "xxx.split(os.sep)".
731 It is recommended to use os.path.normpath() before using this
777 It is recommended to use os.path.normpath() before using this
732 function if need.'''
778 function if need.'''
733 return path.split(os.sep)
779 return path.split(os.sep)
734
780
735 def gui():
781 def gui():
736 '''Are we running in a GUI?'''
782 '''Are we running in a GUI?'''
737 if sys.platform == 'darwin':
783 if sys.platform == 'darwin':
738 if 'SSH_CONNECTION' in os.environ:
784 if 'SSH_CONNECTION' in os.environ:
739 # handle SSH access to a box where the user is logged in
785 # handle SSH access to a box where the user is logged in
740 return False
786 return False
741 elif getattr(osutil, 'isgui', None):
787 elif getattr(osutil, 'isgui', None):
742 # check if a CoreGraphics session is available
788 # check if a CoreGraphics session is available
743 return osutil.isgui()
789 return osutil.isgui()
744 else:
790 else:
745 # pure build; use a safe default
791 # pure build; use a safe default
746 return True
792 return True
747 else:
793 else:
748 return os.name == "nt" or os.environ.get("DISPLAY")
794 return os.name == "nt" or os.environ.get("DISPLAY")
749
795
750 def mktempcopy(name, emptyok=False, createmode=None):
796 def mktempcopy(name, emptyok=False, createmode=None):
751 """Create a temporary file with the same contents from name
797 """Create a temporary file with the same contents from name
752
798
753 The permission bits are copied from the original file.
799 The permission bits are copied from the original file.
754
800
755 If the temporary file is going to be truncated immediately, you
801 If the temporary file is going to be truncated immediately, you
756 can use emptyok=True as an optimization.
802 can use emptyok=True as an optimization.
757
803
758 Returns the name of the temporary file.
804 Returns the name of the temporary file.
759 """
805 """
760 d, fn = os.path.split(name)
806 d, fn = os.path.split(name)
761 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
807 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
762 os.close(fd)
808 os.close(fd)
763 # Temporary files are created with mode 0600, which is usually not
809 # Temporary files are created with mode 0600, which is usually not
764 # what we want. If the original file already exists, just copy
810 # what we want. If the original file already exists, just copy
765 # its mode. Otherwise, manually obey umask.
811 # its mode. Otherwise, manually obey umask.
766 try:
812 try:
767 st_mode = os.lstat(name).st_mode & 0777
813 st_mode = os.lstat(name).st_mode & 0777
768 except OSError, inst:
814 except OSError, inst:
769 if inst.errno != errno.ENOENT:
815 if inst.errno != errno.ENOENT:
770 raise
816 raise
771 st_mode = createmode
817 st_mode = createmode
772 if st_mode is None:
818 if st_mode is None:
773 st_mode = ~umask
819 st_mode = ~umask
774 st_mode &= 0666
820 st_mode &= 0666
775 os.chmod(temp, st_mode)
821 os.chmod(temp, st_mode)
776 if emptyok:
822 if emptyok:
777 return temp
823 return temp
778 try:
824 try:
779 try:
825 try:
780 ifp = posixfile(name, "rb")
826 ifp = posixfile(name, "rb")
781 except IOError, inst:
827 except IOError, inst:
782 if inst.errno == errno.ENOENT:
828 if inst.errno == errno.ENOENT:
783 return temp
829 return temp
784 if not getattr(inst, 'filename', None):
830 if not getattr(inst, 'filename', None):
785 inst.filename = name
831 inst.filename = name
786 raise
832 raise
787 ofp = posixfile(temp, "wb")
833 ofp = posixfile(temp, "wb")
788 for chunk in filechunkiter(ifp):
834 for chunk in filechunkiter(ifp):
789 ofp.write(chunk)
835 ofp.write(chunk)
790 ifp.close()
836 ifp.close()
791 ofp.close()
837 ofp.close()
792 except:
838 except:
793 try: os.unlink(temp)
839 try: os.unlink(temp)
794 except: pass
840 except: pass
795 raise
841 raise
796 return temp
842 return temp
797
843
798 class atomictempfile(object):
844 class atomictempfile(object):
799 """file-like object that atomically updates a file
845 """file-like object that atomically updates a file
800
846
801 All writes will be redirected to a temporary copy of the original
847 All writes will be redirected to a temporary copy of the original
802 file. When rename is called, the copy is renamed to the original
848 file. When rename is called, the copy is renamed to the original
803 name, making the changes visible.
849 name, making the changes visible.
804 """
850 """
805 def __init__(self, name, mode='w+b', createmode=None):
851 def __init__(self, name, mode='w+b', createmode=None):
806 self.__name = name
852 self.__name = name
807 self._fp = None
853 self._fp = None
808 self.temp = mktempcopy(name, emptyok=('w' in mode),
854 self.temp = mktempcopy(name, emptyok=('w' in mode),
809 createmode=createmode)
855 createmode=createmode)
810 self._fp = posixfile(self.temp, mode)
856 self._fp = posixfile(self.temp, mode)
811
857
812 def __getattr__(self, name):
858 def __getattr__(self, name):
813 return getattr(self._fp, name)
859 return getattr(self._fp, name)
814
860
815 def rename(self):
861 def rename(self):
816 if not self._fp.closed:
862 if not self._fp.closed:
817 self._fp.close()
863 self._fp.close()
818 rename(self.temp, localpath(self.__name))
864 rename(self.temp, localpath(self.__name))
819
865
820 def close(self):
866 def close(self):
821 if not self._fp:
867 if not self._fp:
822 return
868 return
823 if not self._fp.closed:
869 if not self._fp.closed:
824 try:
870 try:
825 os.unlink(self.temp)
871 os.unlink(self.temp)
826 except: pass
872 except: pass
827 self._fp.close()
873 self._fp.close()
828
874
829 def __del__(self):
875 def __del__(self):
830 self.close()
876 self.close()
831
877
832 def makedirs(name, mode=None):
878 def makedirs(name, mode=None):
833 """recursive directory creation with parent mode inheritance"""
879 """recursive directory creation with parent mode inheritance"""
834 parent = os.path.abspath(os.path.dirname(name))
880 parent = os.path.abspath(os.path.dirname(name))
835 try:
881 try:
836 os.mkdir(name)
882 os.mkdir(name)
837 if mode is not None:
883 if mode is not None:
838 os.chmod(name, mode)
884 os.chmod(name, mode)
839 return
885 return
840 except OSError, err:
886 except OSError, err:
841 if err.errno == errno.EEXIST:
887 if err.errno == errno.EEXIST:
842 return
888 return
843 if not name or parent == name or err.errno != errno.ENOENT:
889 if not name or parent == name or err.errno != errno.ENOENT:
844 raise
890 raise
845 makedirs(parent, mode)
891 makedirs(parent, mode)
846 makedirs(name, mode)
892 makedirs(name, mode)
847
893
848 class opener(object):
894 class opener(object):
849 """Open files relative to a base directory
895 """Open files relative to a base directory
850
896
851 This class is used to hide the details of COW semantics and
897 This class is used to hide the details of COW semantics and
852 remote file access from higher level code.
898 remote file access from higher level code.
853 """
899 """
854 def __init__(self, base, audit=True):
900 def __init__(self, base, audit=True):
855 self.base = base
901 self.base = base
856 if audit:
902 if audit:
857 self.auditor = path_auditor(base)
903 self.auditor = path_auditor(base)
858 else:
904 else:
859 self.auditor = always
905 self.auditor = always
860 self.createmode = None
906 self.createmode = None
861 self._trustnlink = None
907 self._trustnlink = None
862
908
863 @propertycache
909 @propertycache
864 def _can_symlink(self):
910 def _can_symlink(self):
865 return checklink(self.base)
911 return checklink(self.base)
866
912
867 def _fixfilemode(self, name):
913 def _fixfilemode(self, name):
868 if self.createmode is None:
914 if self.createmode is None:
869 return
915 return
870 os.chmod(name, self.createmode & 0666)
916 os.chmod(name, self.createmode & 0666)
871
917
872 def __call__(self, path, mode="r", text=False, atomictemp=False):
918 def __call__(self, path, mode="r", text=False, atomictemp=False):
873 self.auditor(path)
919 self.auditor(path)
874 f = os.path.join(self.base, path)
920 f = os.path.join(self.base, path)
875
921
876 if not text and "b" not in mode:
922 if not text and "b" not in mode:
877 mode += "b" # for that other OS
923 mode += "b" # for that other OS
878
924
879 nlink = -1
925 nlink = -1
880 dirname, basename = os.path.split(f)
926 dirname, basename = os.path.split(f)
881 # If basename is empty, then the path is malformed because it points
927 # If basename is empty, then the path is malformed because it points
882 # to a directory. Let the posixfile() call below raise IOError.
928 # to a directory. Let the posixfile() call below raise IOError.
883 if basename and mode not in ('r', 'rb'):
929 if basename and mode not in ('r', 'rb'):
884 if atomictemp:
930 if atomictemp:
885 if not os.path.isdir(dirname):
931 if not os.path.isdir(dirname):
886 makedirs(dirname, self.createmode)
932 makedirs(dirname, self.createmode)
887 return atomictempfile(f, mode, self.createmode)
933 return atomictempfile(f, mode, self.createmode)
888 try:
934 try:
889 if 'w' in mode:
935 if 'w' in mode:
890 unlink(f)
936 unlink(f)
891 nlink = 0
937 nlink = 0
892 else:
938 else:
893 # nlinks() may behave differently for files on Windows
939 # nlinks() may behave differently for files on Windows
894 # shares if the file is open.
940 # shares if the file is open.
895 fd = posixfile(f)
941 fd = posixfile(f)
896 nlink = nlinks(f)
942 nlink = nlinks(f)
897 if nlink < 1:
943 if nlink < 1:
898 nlink = 2 # force mktempcopy (issue1922)
944 nlink = 2 # force mktempcopy (issue1922)
899 fd.close()
945 fd.close()
900 except (OSError, IOError), e:
946 except (OSError, IOError), e:
901 if e.errno != errno.ENOENT:
947 if e.errno != errno.ENOENT:
902 raise
948 raise
903 nlink = 0
949 nlink = 0
904 if not os.path.isdir(dirname):
950 if not os.path.isdir(dirname):
905 makedirs(dirname, self.createmode)
951 makedirs(dirname, self.createmode)
906 if nlink > 0:
952 if nlink > 0:
907 if self._trustnlink is None:
953 if self._trustnlink is None:
908 self._trustnlink = nlink > 1 or checknlink(f)
954 self._trustnlink = nlink > 1 or checknlink(f)
909 if nlink > 1 or not self._trustnlink:
955 if nlink > 1 or not self._trustnlink:
910 rename(mktempcopy(f), f)
956 rename(mktempcopy(f), f)
911 fp = posixfile(f, mode)
957 fp = posixfile(f, mode)
912 if nlink == 0:
958 if nlink == 0:
913 self._fixfilemode(f)
959 self._fixfilemode(f)
914 return fp
960 return fp
915
961
916 def symlink(self, src, dst):
962 def symlink(self, src, dst):
917 self.auditor(dst)
963 self.auditor(dst)
918 linkname = os.path.join(self.base, dst)
964 linkname = os.path.join(self.base, dst)
919 try:
965 try:
920 os.unlink(linkname)
966 os.unlink(linkname)
921 except OSError:
967 except OSError:
922 pass
968 pass
923
969
924 dirname = os.path.dirname(linkname)
970 dirname = os.path.dirname(linkname)
925 if not os.path.exists(dirname):
971 if not os.path.exists(dirname):
926 makedirs(dirname, self.createmode)
972 makedirs(dirname, self.createmode)
927
973
928 if self._can_symlink:
974 if self._can_symlink:
929 try:
975 try:
930 os.symlink(src, linkname)
976 os.symlink(src, linkname)
931 except OSError, err:
977 except OSError, err:
932 raise OSError(err.errno, _('could not symlink to %r: %s') %
978 raise OSError(err.errno, _('could not symlink to %r: %s') %
933 (src, err.strerror), linkname)
979 (src, err.strerror), linkname)
934 else:
980 else:
935 f = self(dst, "w")
981 f = self(dst, "w")
936 f.write(src)
982 f.write(src)
937 f.close()
983 f.close()
938 self._fixfilemode(dst)
984 self._fixfilemode(dst)
939
985
940 class chunkbuffer(object):
986 class chunkbuffer(object):
941 """Allow arbitrary sized chunks of data to be efficiently read from an
987 """Allow arbitrary sized chunks of data to be efficiently read from an
942 iterator over chunks of arbitrary size."""
988 iterator over chunks of arbitrary size."""
943
989
944 def __init__(self, in_iter):
990 def __init__(self, in_iter):
945 """in_iter is the iterator that's iterating over the input chunks.
991 """in_iter is the iterator that's iterating over the input chunks.
946 targetsize is how big a buffer to try to maintain."""
992 targetsize is how big a buffer to try to maintain."""
947 def splitbig(chunks):
993 def splitbig(chunks):
948 for chunk in chunks:
994 for chunk in chunks:
949 if len(chunk) > 2**20:
995 if len(chunk) > 2**20:
950 pos = 0
996 pos = 0
951 while pos < len(chunk):
997 while pos < len(chunk):
952 end = pos + 2 ** 18
998 end = pos + 2 ** 18
953 yield chunk[pos:end]
999 yield chunk[pos:end]
954 pos = end
1000 pos = end
955 else:
1001 else:
956 yield chunk
1002 yield chunk
957 self.iter = splitbig(in_iter)
1003 self.iter = splitbig(in_iter)
958 self._queue = []
1004 self._queue = []
959
1005
960 def read(self, l):
1006 def read(self, l):
961 """Read L bytes of data from the iterator of chunks of data.
1007 """Read L bytes of data from the iterator of chunks of data.
962 Returns less than L bytes if the iterator runs dry."""
1008 Returns less than L bytes if the iterator runs dry."""
963 left = l
1009 left = l
964 buf = ''
1010 buf = ''
965 queue = self._queue
1011 queue = self._queue
966 while left > 0:
1012 while left > 0:
967 # refill the queue
1013 # refill the queue
968 if not queue:
1014 if not queue:
969 target = 2**18
1015 target = 2**18
970 for chunk in self.iter:
1016 for chunk in self.iter:
971 queue.append(chunk)
1017 queue.append(chunk)
972 target -= len(chunk)
1018 target -= len(chunk)
973 if target <= 0:
1019 if target <= 0:
974 break
1020 break
975 if not queue:
1021 if not queue:
976 break
1022 break
977
1023
978 chunk = queue.pop(0)
1024 chunk = queue.pop(0)
979 left -= len(chunk)
1025 left -= len(chunk)
980 if left < 0:
1026 if left < 0:
981 queue.insert(0, chunk[left:])
1027 queue.insert(0, chunk[left:])
982 buf += chunk[:left]
1028 buf += chunk[:left]
983 else:
1029 else:
984 buf += chunk
1030 buf += chunk
985
1031
986 return buf
1032 return buf
987
1033
988 def filechunkiter(f, size=65536, limit=None):
1034 def filechunkiter(f, size=65536, limit=None):
989 """Create a generator that produces the data in the file size
1035 """Create a generator that produces the data in the file size
990 (default 65536) bytes at a time, up to optional limit (default is
1036 (default 65536) bytes at a time, up to optional limit (default is
991 to read all data). Chunks may be less than size bytes if the
1037 to read all data). Chunks may be less than size bytes if the
992 chunk is the last chunk in the file, or the file is a socket or
1038 chunk is the last chunk in the file, or the file is a socket or
993 some other type of file that sometimes reads less data than is
1039 some other type of file that sometimes reads less data than is
994 requested."""
1040 requested."""
995 assert size >= 0
1041 assert size >= 0
996 assert limit is None or limit >= 0
1042 assert limit is None or limit >= 0
997 while True:
1043 while True:
998 if limit is None:
1044 if limit is None:
999 nbytes = size
1045 nbytes = size
1000 else:
1046 else:
1001 nbytes = min(limit, size)
1047 nbytes = min(limit, size)
1002 s = nbytes and f.read(nbytes)
1048 s = nbytes and f.read(nbytes)
1003 if not s:
1049 if not s:
1004 break
1050 break
1005 if limit:
1051 if limit:
1006 limit -= len(s)
1052 limit -= len(s)
1007 yield s
1053 yield s
1008
1054
1009 def makedate():
1055 def makedate():
1010 lt = time.localtime()
1056 lt = time.localtime()
1011 if lt[8] == 1 and time.daylight:
1057 if lt[8] == 1 and time.daylight:
1012 tz = time.altzone
1058 tz = time.altzone
1013 else:
1059 else:
1014 tz = time.timezone
1060 tz = time.timezone
1015 t = time.mktime(lt)
1061 t = time.mktime(lt)
1016 if t < 0:
1062 if t < 0:
1017 hint = _("check your clock")
1063 hint = _("check your clock")
1018 raise Abort(_("negative timestamp: %d") % t, hint=hint)
1064 raise Abort(_("negative timestamp: %d") % t, hint=hint)
1019 return t, tz
1065 return t, tz
1020
1066
1021 def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'):
1067 def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'):
1022 """represent a (unixtime, offset) tuple as a localized time.
1068 """represent a (unixtime, offset) tuple as a localized time.
1023 unixtime is seconds since the epoch, and offset is the time zone's
1069 unixtime is seconds since the epoch, and offset is the time zone's
1024 number of seconds away from UTC. if timezone is false, do not
1070 number of seconds away from UTC. if timezone is false, do not
1025 append time zone to string."""
1071 append time zone to string."""
1026 t, tz = date or makedate()
1072 t, tz = date or makedate()
1027 if t < 0:
1073 if t < 0:
1028 t = 0 # time.gmtime(lt) fails on Windows for lt < -43200
1074 t = 0 # time.gmtime(lt) fails on Windows for lt < -43200
1029 tz = 0
1075 tz = 0
1030 if "%1" in format or "%2" in format:
1076 if "%1" in format or "%2" in format:
1031 sign = (tz > 0) and "-" or "+"
1077 sign = (tz > 0) and "-" or "+"
1032 minutes = abs(tz) // 60
1078 minutes = abs(tz) // 60
1033 format = format.replace("%1", "%c%02d" % (sign, minutes // 60))
1079 format = format.replace("%1", "%c%02d" % (sign, minutes // 60))
1034 format = format.replace("%2", "%02d" % (minutes % 60))
1080 format = format.replace("%2", "%02d" % (minutes % 60))
1035 s = time.strftime(format, time.gmtime(float(t) - tz))
1081 s = time.strftime(format, time.gmtime(float(t) - tz))
1036 return s
1082 return s
1037
1083
1038 def shortdate(date=None):
1084 def shortdate(date=None):
1039 """turn (timestamp, tzoff) tuple into iso 8631 date."""
1085 """turn (timestamp, tzoff) tuple into iso 8631 date."""
1040 return datestr(date, format='%Y-%m-%d')
1086 return datestr(date, format='%Y-%m-%d')
1041
1087
1042 def strdate(string, format, defaults=[]):
1088 def strdate(string, format, defaults=[]):
1043 """parse a localized time string and return a (unixtime, offset) tuple.
1089 """parse a localized time string and return a (unixtime, offset) tuple.
1044 if the string cannot be parsed, ValueError is raised."""
1090 if the string cannot be parsed, ValueError is raised."""
1045 def timezone(string):
1091 def timezone(string):
1046 tz = string.split()[-1]
1092 tz = string.split()[-1]
1047 if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
1093 if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
1048 sign = (tz[0] == "+") and 1 or -1
1094 sign = (tz[0] == "+") and 1 or -1
1049 hours = int(tz[1:3])
1095 hours = int(tz[1:3])
1050 minutes = int(tz[3:5])
1096 minutes = int(tz[3:5])
1051 return -sign * (hours * 60 + minutes) * 60
1097 return -sign * (hours * 60 + minutes) * 60
1052 if tz == "GMT" or tz == "UTC":
1098 if tz == "GMT" or tz == "UTC":
1053 return 0
1099 return 0
1054 return None
1100 return None
1055
1101
1056 # NOTE: unixtime = localunixtime + offset
1102 # NOTE: unixtime = localunixtime + offset
1057 offset, date = timezone(string), string
1103 offset, date = timezone(string), string
1058 if offset is not None:
1104 if offset is not None:
1059 date = " ".join(string.split()[:-1])
1105 date = " ".join(string.split()[:-1])
1060
1106
1061 # add missing elements from defaults
1107 # add missing elements from defaults
1062 usenow = False # default to using biased defaults
1108 usenow = False # default to using biased defaults
1063 for part in ("S", "M", "HI", "d", "mb", "yY"): # decreasing specificity
1109 for part in ("S", "M", "HI", "d", "mb", "yY"): # decreasing specificity
1064 found = [True for p in part if ("%"+p) in format]
1110 found = [True for p in part if ("%"+p) in format]
1065 if not found:
1111 if not found:
1066 date += "@" + defaults[part][usenow]
1112 date += "@" + defaults[part][usenow]
1067 format += "@%" + part[0]
1113 format += "@%" + part[0]
1068 else:
1114 else:
1069 # We've found a specific time element, less specific time
1115 # We've found a specific time element, less specific time
1070 # elements are relative to today
1116 # elements are relative to today
1071 usenow = True
1117 usenow = True
1072
1118
1073 timetuple = time.strptime(date, format)
1119 timetuple = time.strptime(date, format)
1074 localunixtime = int(calendar.timegm(timetuple))
1120 localunixtime = int(calendar.timegm(timetuple))
1075 if offset is None:
1121 if offset is None:
1076 # local timezone
1122 # local timezone
1077 unixtime = int(time.mktime(timetuple))
1123 unixtime = int(time.mktime(timetuple))
1078 offset = unixtime - localunixtime
1124 offset = unixtime - localunixtime
1079 else:
1125 else:
1080 unixtime = localunixtime + offset
1126 unixtime = localunixtime + offset
1081 return unixtime, offset
1127 return unixtime, offset
1082
1128
1083 def parsedate(date, formats=None, bias={}):
1129 def parsedate(date, formats=None, bias={}):
1084 """parse a localized date/time and return a (unixtime, offset) tuple.
1130 """parse a localized date/time and return a (unixtime, offset) tuple.
1085
1131
1086 The date may be a "unixtime offset" string or in one of the specified
1132 The date may be a "unixtime offset" string or in one of the specified
1087 formats. If the date already is a (unixtime, offset) tuple, it is returned.
1133 formats. If the date already is a (unixtime, offset) tuple, it is returned.
1088 """
1134 """
1089 if not date:
1135 if not date:
1090 return 0, 0
1136 return 0, 0
1091 if isinstance(date, tuple) and len(date) == 2:
1137 if isinstance(date, tuple) and len(date) == 2:
1092 return date
1138 return date
1093 if not formats:
1139 if not formats:
1094 formats = defaultdateformats
1140 formats = defaultdateformats
1095 date = date.strip()
1141 date = date.strip()
1096 try:
1142 try:
1097 when, offset = map(int, date.split(' '))
1143 when, offset = map(int, date.split(' '))
1098 except ValueError:
1144 except ValueError:
1099 # fill out defaults
1145 # fill out defaults
1100 now = makedate()
1146 now = makedate()
1101 defaults = {}
1147 defaults = {}
1102 nowmap = {}
1148 nowmap = {}
1103 for part in ("d", "mb", "yY", "HI", "M", "S"):
1149 for part in ("d", "mb", "yY", "HI", "M", "S"):
1104 # this piece is for rounding the specific end of unknowns
1150 # this piece is for rounding the specific end of unknowns
1105 b = bias.get(part)
1151 b = bias.get(part)
1106 if b is None:
1152 if b is None:
1107 if part[0] in "HMS":
1153 if part[0] in "HMS":
1108 b = "00"
1154 b = "00"
1109 else:
1155 else:
1110 b = "0"
1156 b = "0"
1111
1157
1112 # this piece is for matching the generic end to today's date
1158 # this piece is for matching the generic end to today's date
1113 n = datestr(now, "%" + part[0])
1159 n = datestr(now, "%" + part[0])
1114
1160
1115 defaults[part] = (b, n)
1161 defaults[part] = (b, n)
1116
1162
1117 for format in formats:
1163 for format in formats:
1118 try:
1164 try:
1119 when, offset = strdate(date, format, defaults)
1165 when, offset = strdate(date, format, defaults)
1120 except (ValueError, OverflowError):
1166 except (ValueError, OverflowError):
1121 pass
1167 pass
1122 else:
1168 else:
1123 break
1169 break
1124 else:
1170 else:
1125 raise Abort(_('invalid date: %r') % date)
1171 raise Abort(_('invalid date: %r') % date)
1126 # validate explicit (probably user-specified) date and
1172 # validate explicit (probably user-specified) date and
1127 # time zone offset. values must fit in signed 32 bits for
1173 # time zone offset. values must fit in signed 32 bits for
1128 # current 32-bit linux runtimes. timezones go from UTC-12
1174 # current 32-bit linux runtimes. timezones go from UTC-12
1129 # to UTC+14
1175 # to UTC+14
1130 if abs(when) > 0x7fffffff:
1176 if abs(when) > 0x7fffffff:
1131 raise Abort(_('date exceeds 32 bits: %d') % when)
1177 raise Abort(_('date exceeds 32 bits: %d') % when)
1132 if when < 0:
1178 if when < 0:
1133 raise Abort(_('negative date value: %d') % when)
1179 raise Abort(_('negative date value: %d') % when)
1134 if offset < -50400 or offset > 43200:
1180 if offset < -50400 or offset > 43200:
1135 raise Abort(_('impossible time zone offset: %d') % offset)
1181 raise Abort(_('impossible time zone offset: %d') % offset)
1136 return when, offset
1182 return when, offset
1137
1183
1138 def matchdate(date):
1184 def matchdate(date):
1139 """Return a function that matches a given date match specifier
1185 """Return a function that matches a given date match specifier
1140
1186
1141 Formats include:
1187 Formats include:
1142
1188
1143 '{date}' match a given date to the accuracy provided
1189 '{date}' match a given date to the accuracy provided
1144
1190
1145 '<{date}' on or before a given date
1191 '<{date}' on or before a given date
1146
1192
1147 '>{date}' on or after a given date
1193 '>{date}' on or after a given date
1148
1194
1149 >>> p1 = parsedate("10:29:59")
1195 >>> p1 = parsedate("10:29:59")
1150 >>> p2 = parsedate("10:30:00")
1196 >>> p2 = parsedate("10:30:00")
1151 >>> p3 = parsedate("10:30:59")
1197 >>> p3 = parsedate("10:30:59")
1152 >>> p4 = parsedate("10:31:00")
1198 >>> p4 = parsedate("10:31:00")
1153 >>> p5 = parsedate("Sep 15 10:30:00 1999")
1199 >>> p5 = parsedate("Sep 15 10:30:00 1999")
1154 >>> f = matchdate("10:30")
1200 >>> f = matchdate("10:30")
1155 >>> f(p1[0])
1201 >>> f(p1[0])
1156 False
1202 False
1157 >>> f(p2[0])
1203 >>> f(p2[0])
1158 True
1204 True
1159 >>> f(p3[0])
1205 >>> f(p3[0])
1160 True
1206 True
1161 >>> f(p4[0])
1207 >>> f(p4[0])
1162 False
1208 False
1163 >>> f(p5[0])
1209 >>> f(p5[0])
1164 False
1210 False
1165 """
1211 """
1166
1212
1167 def lower(date):
1213 def lower(date):
1168 d = dict(mb="1", d="1")
1214 d = dict(mb="1", d="1")
1169 return parsedate(date, extendeddateformats, d)[0]
1215 return parsedate(date, extendeddateformats, d)[0]
1170
1216
1171 def upper(date):
1217 def upper(date):
1172 d = dict(mb="12", HI="23", M="59", S="59")
1218 d = dict(mb="12", HI="23", M="59", S="59")
1173 for days in ("31", "30", "29"):
1219 for days in ("31", "30", "29"):
1174 try:
1220 try:
1175 d["d"] = days
1221 d["d"] = days
1176 return parsedate(date, extendeddateformats, d)[0]
1222 return parsedate(date, extendeddateformats, d)[0]
1177 except:
1223 except:
1178 pass
1224 pass
1179 d["d"] = "28"
1225 d["d"] = "28"
1180 return parsedate(date, extendeddateformats, d)[0]
1226 return parsedate(date, extendeddateformats, d)[0]
1181
1227
1182 date = date.strip()
1228 date = date.strip()
1183
1229
1184 if not date:
1230 if not date:
1185 raise Abort(_("dates cannot consist entirely of whitespace"))
1231 raise Abort(_("dates cannot consist entirely of whitespace"))
1186 elif date[0] == "<":
1232 elif date[0] == "<":
1187 if not date[1:]:
1233 if not date[1:]:
1188 raise Abort(_("invalid day spec, use '<DATE'"))
1234 raise Abort(_("invalid day spec, use '<DATE'"))
1189 when = upper(date[1:])
1235 when = upper(date[1:])
1190 return lambda x: x <= when
1236 return lambda x: x <= when
1191 elif date[0] == ">":
1237 elif date[0] == ">":
1192 if not date[1:]:
1238 if not date[1:]:
1193 raise Abort(_("invalid day spec, use '>DATE'"))
1239 raise Abort(_("invalid day spec, use '>DATE'"))
1194 when = lower(date[1:])
1240 when = lower(date[1:])
1195 return lambda x: x >= when
1241 return lambda x: x >= when
1196 elif date[0] == "-":
1242 elif date[0] == "-":
1197 try:
1243 try:
1198 days = int(date[1:])
1244 days = int(date[1:])
1199 except ValueError:
1245 except ValueError:
1200 raise Abort(_("invalid day spec: %s") % date[1:])
1246 raise Abort(_("invalid day spec: %s") % date[1:])
1201 if days < 0:
1247 if days < 0:
1202 raise Abort(_("%s must be nonnegative (see 'hg help dates')")
1248 raise Abort(_("%s must be nonnegative (see 'hg help dates')")
1203 % date[1:])
1249 % date[1:])
1204 when = makedate()[0] - days * 3600 * 24
1250 when = makedate()[0] - days * 3600 * 24
1205 return lambda x: x >= when
1251 return lambda x: x >= when
1206 elif " to " in date:
1252 elif " to " in date:
1207 a, b = date.split(" to ")
1253 a, b = date.split(" to ")
1208 start, stop = lower(a), upper(b)
1254 start, stop = lower(a), upper(b)
1209 return lambda x: x >= start and x <= stop
1255 return lambda x: x >= start and x <= stop
1210 else:
1256 else:
1211 start, stop = lower(date), upper(date)
1257 start, stop = lower(date), upper(date)
1212 return lambda x: x >= start and x <= stop
1258 return lambda x: x >= start and x <= stop
1213
1259
1214 def shortuser(user):
1260 def shortuser(user):
1215 """Return a short representation of a user name or email address."""
1261 """Return a short representation of a user name or email address."""
1216 f = user.find('@')
1262 f = user.find('@')
1217 if f >= 0:
1263 if f >= 0:
1218 user = user[:f]
1264 user = user[:f]
1219 f = user.find('<')
1265 f = user.find('<')
1220 if f >= 0:
1266 if f >= 0:
1221 user = user[f + 1:]
1267 user = user[f + 1:]
1222 f = user.find(' ')
1268 f = user.find(' ')
1223 if f >= 0:
1269 if f >= 0:
1224 user = user[:f]
1270 user = user[:f]
1225 f = user.find('.')
1271 f = user.find('.')
1226 if f >= 0:
1272 if f >= 0:
1227 user = user[:f]
1273 user = user[:f]
1228 return user
1274 return user
1229
1275
1230 def email(author):
1276 def email(author):
1231 '''get email of author.'''
1277 '''get email of author.'''
1232 r = author.find('>')
1278 r = author.find('>')
1233 if r == -1:
1279 if r == -1:
1234 r = None
1280 r = None
1235 return author[author.find('<') + 1:r]
1281 return author[author.find('<') + 1:r]
1236
1282
1237 def _ellipsis(text, maxlength):
1283 def _ellipsis(text, maxlength):
1238 if len(text) <= maxlength:
1284 if len(text) <= maxlength:
1239 return text, False
1285 return text, False
1240 else:
1286 else:
1241 return "%s..." % (text[:maxlength - 3]), True
1287 return "%s..." % (text[:maxlength - 3]), True
1242
1288
1243 def ellipsis(text, maxlength=400):
1289 def ellipsis(text, maxlength=400):
1244 """Trim string to at most maxlength (default: 400) characters."""
1290 """Trim string to at most maxlength (default: 400) characters."""
1245 try:
1291 try:
1246 # use unicode not to split at intermediate multi-byte sequence
1292 # use unicode not to split at intermediate multi-byte sequence
1247 utext, truncated = _ellipsis(text.decode(encoding.encoding),
1293 utext, truncated = _ellipsis(text.decode(encoding.encoding),
1248 maxlength)
1294 maxlength)
1249 if not truncated:
1295 if not truncated:
1250 return text
1296 return text
1251 return utext.encode(encoding.encoding)
1297 return utext.encode(encoding.encoding)
1252 except (UnicodeDecodeError, UnicodeEncodeError):
1298 except (UnicodeDecodeError, UnicodeEncodeError):
1253 return _ellipsis(text, maxlength)[0]
1299 return _ellipsis(text, maxlength)[0]
1254
1300
1255 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
1301 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
1256 '''yield every hg repository under path, recursively.'''
1302 '''yield every hg repository under path, recursively.'''
1257 def errhandler(err):
1303 def errhandler(err):
1258 if err.filename == path:
1304 if err.filename == path:
1259 raise err
1305 raise err
1260 if followsym and hasattr(os.path, 'samestat'):
1306 if followsym and hasattr(os.path, 'samestat'):
1261 def _add_dir_if_not_there(dirlst, dirname):
1307 def _add_dir_if_not_there(dirlst, dirname):
1262 match = False
1308 match = False
1263 samestat = os.path.samestat
1309 samestat = os.path.samestat
1264 dirstat = os.stat(dirname)
1310 dirstat = os.stat(dirname)
1265 for lstdirstat in dirlst:
1311 for lstdirstat in dirlst:
1266 if samestat(dirstat, lstdirstat):
1312 if samestat(dirstat, lstdirstat):
1267 match = True
1313 match = True
1268 break
1314 break
1269 if not match:
1315 if not match:
1270 dirlst.append(dirstat)
1316 dirlst.append(dirstat)
1271 return not match
1317 return not match
1272 else:
1318 else:
1273 followsym = False
1319 followsym = False
1274
1320
1275 if (seen_dirs is None) and followsym:
1321 if (seen_dirs is None) and followsym:
1276 seen_dirs = []
1322 seen_dirs = []
1277 _add_dir_if_not_there(seen_dirs, path)
1323 _add_dir_if_not_there(seen_dirs, path)
1278 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
1324 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
1279 dirs.sort()
1325 dirs.sort()
1280 if '.hg' in dirs:
1326 if '.hg' in dirs:
1281 yield root # found a repository
1327 yield root # found a repository
1282 qroot = os.path.join(root, '.hg', 'patches')
1328 qroot = os.path.join(root, '.hg', 'patches')
1283 if os.path.isdir(os.path.join(qroot, '.hg')):
1329 if os.path.isdir(os.path.join(qroot, '.hg')):
1284 yield qroot # we have a patch queue repo here
1330 yield qroot # we have a patch queue repo here
1285 if recurse:
1331 if recurse:
1286 # avoid recursing inside the .hg directory
1332 # avoid recursing inside the .hg directory
1287 dirs.remove('.hg')
1333 dirs.remove('.hg')
1288 else:
1334 else:
1289 dirs[:] = [] # don't descend further
1335 dirs[:] = [] # don't descend further
1290 elif followsym:
1336 elif followsym:
1291 newdirs = []
1337 newdirs = []
1292 for d in dirs:
1338 for d in dirs:
1293 fname = os.path.join(root, d)
1339 fname = os.path.join(root, d)
1294 if _add_dir_if_not_there(seen_dirs, fname):
1340 if _add_dir_if_not_there(seen_dirs, fname):
1295 if os.path.islink(fname):
1341 if os.path.islink(fname):
1296 for hgname in walkrepos(fname, True, seen_dirs):
1342 for hgname in walkrepos(fname, True, seen_dirs):
1297 yield hgname
1343 yield hgname
1298 else:
1344 else:
1299 newdirs.append(d)
1345 newdirs.append(d)
1300 dirs[:] = newdirs
1346 dirs[:] = newdirs
1301
1347
1302 _rcpath = None
1348 _rcpath = None
1303
1349
1304 def os_rcpath():
1350 def os_rcpath():
1305 '''return default os-specific hgrc search path'''
1351 '''return default os-specific hgrc search path'''
1306 path = system_rcpath()
1352 path = system_rcpath()
1307 path.extend(user_rcpath())
1353 path.extend(user_rcpath())
1308 path = [os.path.normpath(f) for f in path]
1354 path = [os.path.normpath(f) for f in path]
1309 return path
1355 return path
1310
1356
1311 def rcpath():
1357 def rcpath():
1312 '''return hgrc search path. if env var HGRCPATH is set, use it.
1358 '''return hgrc search path. if env var HGRCPATH is set, use it.
1313 for each item in path, if directory, use files ending in .rc,
1359 for each item in path, if directory, use files ending in .rc,
1314 else use item.
1360 else use item.
1315 make HGRCPATH empty to only look in .hg/hgrc of current repo.
1361 make HGRCPATH empty to only look in .hg/hgrc of current repo.
1316 if no HGRCPATH, use default os-specific path.'''
1362 if no HGRCPATH, use default os-specific path.'''
1317 global _rcpath
1363 global _rcpath
1318 if _rcpath is None:
1364 if _rcpath is None:
1319 if 'HGRCPATH' in os.environ:
1365 if 'HGRCPATH' in os.environ:
1320 _rcpath = []
1366 _rcpath = []
1321 for p in os.environ['HGRCPATH'].split(os.pathsep):
1367 for p in os.environ['HGRCPATH'].split(os.pathsep):
1322 if not p:
1368 if not p:
1323 continue
1369 continue
1324 p = expandpath(p)
1370 p = expandpath(p)
1325 if os.path.isdir(p):
1371 if os.path.isdir(p):
1326 for f, kind in osutil.listdir(p):
1372 for f, kind in osutil.listdir(p):
1327 if f.endswith('.rc'):
1373 if f.endswith('.rc'):
1328 _rcpath.append(os.path.join(p, f))
1374 _rcpath.append(os.path.join(p, f))
1329 else:
1375 else:
1330 _rcpath.append(p)
1376 _rcpath.append(p)
1331 else:
1377 else:
1332 _rcpath = os_rcpath()
1378 _rcpath = os_rcpath()
1333 return _rcpath
1379 return _rcpath
1334
1380
1335 def bytecount(nbytes):
1381 def bytecount(nbytes):
1336 '''return byte count formatted as readable string, with units'''
1382 '''return byte count formatted as readable string, with units'''
1337
1383
1338 units = (
1384 units = (
1339 (100, 1 << 30, _('%.0f GB')),
1385 (100, 1 << 30, _('%.0f GB')),
1340 (10, 1 << 30, _('%.1f GB')),
1386 (10, 1 << 30, _('%.1f GB')),
1341 (1, 1 << 30, _('%.2f GB')),
1387 (1, 1 << 30, _('%.2f GB')),
1342 (100, 1 << 20, _('%.0f MB')),
1388 (100, 1 << 20, _('%.0f MB')),
1343 (10, 1 << 20, _('%.1f MB')),
1389 (10, 1 << 20, _('%.1f MB')),
1344 (1, 1 << 20, _('%.2f MB')),
1390 (1, 1 << 20, _('%.2f MB')),
1345 (100, 1 << 10, _('%.0f KB')),
1391 (100, 1 << 10, _('%.0f KB')),
1346 (10, 1 << 10, _('%.1f KB')),
1392 (10, 1 << 10, _('%.1f KB')),
1347 (1, 1 << 10, _('%.2f KB')),
1393 (1, 1 << 10, _('%.2f KB')),
1348 (1, 1, _('%.0f bytes')),
1394 (1, 1, _('%.0f bytes')),
1349 )
1395 )
1350
1396
1351 for multiplier, divisor, format in units:
1397 for multiplier, divisor, format in units:
1352 if nbytes >= divisor * multiplier:
1398 if nbytes >= divisor * multiplier:
1353 return format % (nbytes / float(divisor))
1399 return format % (nbytes / float(divisor))
1354 return units[-1][2] % nbytes
1400 return units[-1][2] % nbytes
1355
1401
1356 def uirepr(s):
1402 def uirepr(s):
1357 # Avoid double backslash in Windows path repr()
1403 # Avoid double backslash in Windows path repr()
1358 return repr(s).replace('\\\\', '\\')
1404 return repr(s).replace('\\\\', '\\')
1359
1405
1360 # delay import of textwrap
1406 # delay import of textwrap
1361 def MBTextWrapper(**kwargs):
1407 def MBTextWrapper(**kwargs):
1362 class tw(textwrap.TextWrapper):
1408 class tw(textwrap.TextWrapper):
1363 """
1409 """
1364 Extend TextWrapper for double-width characters.
1410 Extend TextWrapper for double-width characters.
1365
1411
1366 Some Asian characters use two terminal columns instead of one.
1412 Some Asian characters use two terminal columns instead of one.
1367 A good example of this behavior can be seen with u'\u65e5\u672c',
1413 A good example of this behavior can be seen with u'\u65e5\u672c',
1368 the two Japanese characters for "Japan":
1414 the two Japanese characters for "Japan":
1369 len() returns 2, but when printed to a terminal, they eat 4 columns.
1415 len() returns 2, but when printed to a terminal, they eat 4 columns.
1370
1416
1371 (Note that this has nothing to do whatsoever with unicode
1417 (Note that this has nothing to do whatsoever with unicode
1372 representation, or encoding of the underlying string)
1418 representation, or encoding of the underlying string)
1373 """
1419 """
1374 def __init__(self, **kwargs):
1420 def __init__(self, **kwargs):
1375 textwrap.TextWrapper.__init__(self, **kwargs)
1421 textwrap.TextWrapper.__init__(self, **kwargs)
1376
1422
1377 def _cutdown(self, str, space_left):
1423 def _cutdown(self, str, space_left):
1378 l = 0
1424 l = 0
1379 ucstr = unicode(str, encoding.encoding)
1425 ucstr = unicode(str, encoding.encoding)
1380 colwidth = unicodedata.east_asian_width
1426 colwidth = unicodedata.east_asian_width
1381 for i in xrange(len(ucstr)):
1427 for i in xrange(len(ucstr)):
1382 l += colwidth(ucstr[i]) in 'WFA' and 2 or 1
1428 l += colwidth(ucstr[i]) in 'WFA' and 2 or 1
1383 if space_left < l:
1429 if space_left < l:
1384 return (ucstr[:i].encode(encoding.encoding),
1430 return (ucstr[:i].encode(encoding.encoding),
1385 ucstr[i:].encode(encoding.encoding))
1431 ucstr[i:].encode(encoding.encoding))
1386 return str, ''
1432 return str, ''
1387
1433
1388 # overriding of base class
1434 # overriding of base class
1389 def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
1435 def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
1390 space_left = max(width - cur_len, 1)
1436 space_left = max(width - cur_len, 1)
1391
1437
1392 if self.break_long_words:
1438 if self.break_long_words:
1393 cut, res = self._cutdown(reversed_chunks[-1], space_left)
1439 cut, res = self._cutdown(reversed_chunks[-1], space_left)
1394 cur_line.append(cut)
1440 cur_line.append(cut)
1395 reversed_chunks[-1] = res
1441 reversed_chunks[-1] = res
1396 elif not cur_line:
1442 elif not cur_line:
1397 cur_line.append(reversed_chunks.pop())
1443 cur_line.append(reversed_chunks.pop())
1398
1444
1399 global MBTextWrapper
1445 global MBTextWrapper
1400 MBTextWrapper = tw
1446 MBTextWrapper = tw
1401 return tw(**kwargs)
1447 return tw(**kwargs)
1402
1448
1403 def wrap(line, width, initindent='', hangindent=''):
1449 def wrap(line, width, initindent='', hangindent=''):
1404 maxindent = max(len(hangindent), len(initindent))
1450 maxindent = max(len(hangindent), len(initindent))
1405 if width <= maxindent:
1451 if width <= maxindent:
1406 # adjust for weird terminal size
1452 # adjust for weird terminal size
1407 width = max(78, maxindent + 1)
1453 width = max(78, maxindent + 1)
1408 wrapper = MBTextWrapper(width=width,
1454 wrapper = MBTextWrapper(width=width,
1409 initial_indent=initindent,
1455 initial_indent=initindent,
1410 subsequent_indent=hangindent)
1456 subsequent_indent=hangindent)
1411 return wrapper.fill(line)
1457 return wrapper.fill(line)
1412
1458
1413 def iterlines(iterator):
1459 def iterlines(iterator):
1414 for chunk in iterator:
1460 for chunk in iterator:
1415 for line in chunk.splitlines():
1461 for line in chunk.splitlines():
1416 yield line
1462 yield line
1417
1463
1418 def expandpath(path):
1464 def expandpath(path):
1419 return os.path.expanduser(os.path.expandvars(path))
1465 return os.path.expanduser(os.path.expandvars(path))
1420
1466
1421 def hgcmd():
1467 def hgcmd():
1422 """Return the command used to execute current hg
1468 """Return the command used to execute current hg
1423
1469
1424 This is different from hgexecutable() because on Windows we want
1470 This is different from hgexecutable() because on Windows we want
1425 to avoid things opening new shell windows like batch files, so we
1471 to avoid things opening new shell windows like batch files, so we
1426 get either the python call or current executable.
1472 get either the python call or current executable.
1427 """
1473 """
1428 if main_is_frozen():
1474 if main_is_frozen():
1429 return [sys.executable]
1475 return [sys.executable]
1430 return gethgcmd()
1476 return gethgcmd()
1431
1477
1432 def rundetached(args, condfn):
1478 def rundetached(args, condfn):
1433 """Execute the argument list in a detached process.
1479 """Execute the argument list in a detached process.
1434
1480
1435 condfn is a callable which is called repeatedly and should return
1481 condfn is a callable which is called repeatedly and should return
1436 True once the child process is known to have started successfully.
1482 True once the child process is known to have started successfully.
1437 At this point, the child process PID is returned. If the child
1483 At this point, the child process PID is returned. If the child
1438 process fails to start or finishes before condfn() evaluates to
1484 process fails to start or finishes before condfn() evaluates to
1439 True, return -1.
1485 True, return -1.
1440 """
1486 """
1441 # Windows case is easier because the child process is either
1487 # Windows case is easier because the child process is either
1442 # successfully starting and validating the condition or exiting
1488 # successfully starting and validating the condition or exiting
1443 # on failure. We just poll on its PID. On Unix, if the child
1489 # on failure. We just poll on its PID. On Unix, if the child
1444 # process fails to start, it will be left in a zombie state until
1490 # process fails to start, it will be left in a zombie state until
1445 # the parent wait on it, which we cannot do since we expect a long
1491 # the parent wait on it, which we cannot do since we expect a long
1446 # running process on success. Instead we listen for SIGCHLD telling
1492 # running process on success. Instead we listen for SIGCHLD telling
1447 # us our child process terminated.
1493 # us our child process terminated.
1448 terminated = set()
1494 terminated = set()
1449 def handler(signum, frame):
1495 def handler(signum, frame):
1450 terminated.add(os.wait())
1496 terminated.add(os.wait())
1451 prevhandler = None
1497 prevhandler = None
1452 if hasattr(signal, 'SIGCHLD'):
1498 if hasattr(signal, 'SIGCHLD'):
1453 prevhandler = signal.signal(signal.SIGCHLD, handler)
1499 prevhandler = signal.signal(signal.SIGCHLD, handler)
1454 try:
1500 try:
1455 pid = spawndetached(args)
1501 pid = spawndetached(args)
1456 while not condfn():
1502 while not condfn():
1457 if ((pid in terminated or not testpid(pid))
1503 if ((pid in terminated or not testpid(pid))
1458 and not condfn()):
1504 and not condfn()):
1459 return -1
1505 return -1
1460 time.sleep(0.1)
1506 time.sleep(0.1)
1461 return pid
1507 return pid
1462 finally:
1508 finally:
1463 if prevhandler is not None:
1509 if prevhandler is not None:
1464 signal.signal(signal.SIGCHLD, prevhandler)
1510 signal.signal(signal.SIGCHLD, prevhandler)
1465
1511
1466 try:
1512 try:
1467 any, all = any, all
1513 any, all = any, all
1468 except NameError:
1514 except NameError:
1469 def any(iterable):
1515 def any(iterable):
1470 for i in iterable:
1516 for i in iterable:
1471 if i:
1517 if i:
1472 return True
1518 return True
1473 return False
1519 return False
1474
1520
1475 def all(iterable):
1521 def all(iterable):
1476 for i in iterable:
1522 for i in iterable:
1477 if not i:
1523 if not i:
1478 return False
1524 return False
1479 return True
1525 return True
1480
1526
1481 def interpolate(prefix, mapping, s, fn=None, escape_prefix=False):
1527 def interpolate(prefix, mapping, s, fn=None, escape_prefix=False):
1482 """Return the result of interpolating items in the mapping into string s.
1528 """Return the result of interpolating items in the mapping into string s.
1483
1529
1484 prefix is a single character string, or a two character string with
1530 prefix is a single character string, or a two character string with
1485 a backslash as the first character if the prefix needs to be escaped in
1531 a backslash as the first character if the prefix needs to be escaped in
1486 a regular expression.
1532 a regular expression.
1487
1533
1488 fn is an optional function that will be applied to the replacement text
1534 fn is an optional function that will be applied to the replacement text
1489 just before replacement.
1535 just before replacement.
1490
1536
1491 escape_prefix is an optional flag that allows using doubled prefix for
1537 escape_prefix is an optional flag that allows using doubled prefix for
1492 its escaping.
1538 its escaping.
1493 """
1539 """
1494 fn = fn or (lambda s: s)
1540 fn = fn or (lambda s: s)
1495 patterns = '|'.join(mapping.keys())
1541 patterns = '|'.join(mapping.keys())
1496 if escape_prefix:
1542 if escape_prefix:
1497 patterns += '|' + prefix
1543 patterns += '|' + prefix
1498 if len(prefix) > 1:
1544 if len(prefix) > 1:
1499 prefix_char = prefix[1:]
1545 prefix_char = prefix[1:]
1500 else:
1546 else:
1501 prefix_char = prefix
1547 prefix_char = prefix
1502 mapping[prefix_char] = prefix_char
1548 mapping[prefix_char] = prefix_char
1503 r = re.compile(r'%s(%s)' % (prefix, patterns))
1549 r = re.compile(r'%s(%s)' % (prefix, patterns))
1504 return r.sub(lambda x: fn(mapping[x.group()[1:]]), s)
1550 return r.sub(lambda x: fn(mapping[x.group()[1:]]), s)
1505
1551
1506 def getport(port):
1552 def getport(port):
1507 """Return the port for a given network service.
1553 """Return the port for a given network service.
1508
1554
1509 If port is an integer, it's returned as is. If it's a string, it's
1555 If port is an integer, it's returned as is. If it's a string, it's
1510 looked up using socket.getservbyname(). If there's no matching
1556 looked up using socket.getservbyname(). If there's no matching
1511 service, util.Abort is raised.
1557 service, util.Abort is raised.
1512 """
1558 """
1513 try:
1559 try:
1514 return int(port)
1560 return int(port)
1515 except ValueError:
1561 except ValueError:
1516 pass
1562 pass
1517
1563
1518 try:
1564 try:
1519 return socket.getservbyname(port)
1565 return socket.getservbyname(port)
1520 except socket.error:
1566 except socket.error:
1521 raise Abort(_("no port number associated with service '%s'") % port)
1567 raise Abort(_("no port number associated with service '%s'") % port)
1522
1568
1523 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True, 'always': True,
1569 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True, 'always': True,
1524 '0': False, 'no': False, 'false': False, 'off': False,
1570 '0': False, 'no': False, 'false': False, 'off': False,
1525 'never': False}
1571 'never': False}
1526
1572
1527 def parsebool(s):
1573 def parsebool(s):
1528 """Parse s into a boolean.
1574 """Parse s into a boolean.
1529
1575
1530 If s is not a valid boolean, returns None.
1576 If s is not a valid boolean, returns None.
1531 """
1577 """
1532 return _booleans.get(s.lower(), None)
1578 return _booleans.get(s.lower(), None)
General Comments 0
You need to be logged in to leave comments. Login now