##// END OF EJS Templates
Merge
Bryan O'Sullivan -
r6501:4f7feeb6 merge default
parent child Browse files
Show More
@@ -1,1850 +1,1866 b''
1 """
1 """
2 util.py - Mercurial utility functions and platform specfic implementations
2 util.py - Mercurial utility functions and platform specfic implementations
3
3
4 Copyright 2005 K. Thananchayan <thananck@yahoo.com>
4 Copyright 2005 K. Thananchayan <thananck@yahoo.com>
5 Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
6 Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
6 Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
7
7
8 This software may be used and distributed according to the terms
8 This software may be used and distributed according to the terms
9 of the GNU General Public License, incorporated herein by reference.
9 of the GNU General Public License, incorporated herein by reference.
10
10
11 This contains helper routines that are independent of the SCM core and hide
11 This contains helper routines that are independent of the SCM core and hide
12 platform-specific details from the core.
12 platform-specific details from the core.
13 """
13 """
14
14
15 from i18n import _
15 from i18n import _
16 import cStringIO, errno, getpass, re, shutil, sys, tempfile
16 import cStringIO, errno, getpass, re, shutil, sys, tempfile
17 import os, stat, threading, time, calendar, ConfigParser, locale, glob, osutil
17 import os, stat, threading, time, calendar, ConfigParser, locale, glob, osutil
18 import urlparse
18 import imp, urlparse
19
19
20 # Python compatibility
20 # Python compatibility
21
21
22 try:
22 try:
23 set = set
23 set = set
24 frozenset = frozenset
24 frozenset = frozenset
25 except NameError:
25 except NameError:
26 from sets import Set as set, ImmutableSet as frozenset
26 from sets import Set as set, ImmutableSet as frozenset
27
27
28 _md5 = None
28 _md5 = None
29 def md5(s):
29 def md5(s):
30 global _md5
30 global _md5
31 if _md5 is None:
31 if _md5 is None:
32 try:
32 try:
33 import hashlib
33 import hashlib
34 _md5 = hashlib.md5
34 _md5 = hashlib.md5
35 except ImportError:
35 except ImportError:
36 import md5
36 import md5
37 _md5 = md5.md5
37 _md5 = md5.md5
38 return _md5(s)
38 return _md5(s)
39
39
40 _sha1 = None
40 _sha1 = None
41 def sha1(s):
41 def sha1(s):
42 global _sha1
42 global _sha1
43 if _sha1 is None:
43 if _sha1 is None:
44 try:
44 try:
45 import hashlib
45 import hashlib
46 _sha1 = hashlib.sha1
46 _sha1 = hashlib.sha1
47 except ImportError:
47 except ImportError:
48 import sha
48 import sha
49 _sha1 = sha.sha
49 _sha1 = sha.sha
50 return _sha1(s)
50 return _sha1(s)
51
51
52 try:
52 try:
53 _encoding = os.environ.get("HGENCODING")
53 _encoding = os.environ.get("HGENCODING")
54 if sys.platform == 'darwin' and not _encoding:
54 if sys.platform == 'darwin' and not _encoding:
55 # On darwin, getpreferredencoding ignores the locale environment and
55 # On darwin, getpreferredencoding ignores the locale environment and
56 # always returns mac-roman. We override this if the environment is
56 # always returns mac-roman. We override this if the environment is
57 # not C (has been customized by the user).
57 # not C (has been customized by the user).
58 locale.setlocale(locale.LC_CTYPE, '')
58 locale.setlocale(locale.LC_CTYPE, '')
59 _encoding = locale.getlocale()[1]
59 _encoding = locale.getlocale()[1]
60 if not _encoding:
60 if not _encoding:
61 _encoding = locale.getpreferredencoding() or 'ascii'
61 _encoding = locale.getpreferredencoding() or 'ascii'
62 except locale.Error:
62 except locale.Error:
63 _encoding = 'ascii'
63 _encoding = 'ascii'
64 _encodingmode = os.environ.get("HGENCODINGMODE", "strict")
64 _encodingmode = os.environ.get("HGENCODINGMODE", "strict")
65 _fallbackencoding = 'ISO-8859-1'
65 _fallbackencoding = 'ISO-8859-1'
66
66
67 def tolocal(s):
67 def tolocal(s):
68 """
68 """
69 Convert a string from internal UTF-8 to local encoding
69 Convert a string from internal UTF-8 to local encoding
70
70
71 All internal strings should be UTF-8 but some repos before the
71 All internal strings should be UTF-8 but some repos before the
72 implementation of locale support may contain latin1 or possibly
72 implementation of locale support may contain latin1 or possibly
73 other character sets. We attempt to decode everything strictly
73 other character sets. We attempt to decode everything strictly
74 using UTF-8, then Latin-1, and failing that, we use UTF-8 and
74 using UTF-8, then Latin-1, and failing that, we use UTF-8 and
75 replace unknown characters.
75 replace unknown characters.
76 """
76 """
77 for e in ('UTF-8', _fallbackencoding):
77 for e in ('UTF-8', _fallbackencoding):
78 try:
78 try:
79 u = s.decode(e) # attempt strict decoding
79 u = s.decode(e) # attempt strict decoding
80 return u.encode(_encoding, "replace")
80 return u.encode(_encoding, "replace")
81 except LookupError, k:
81 except LookupError, k:
82 raise Abort(_("%s, please check your locale settings") % k)
82 raise Abort(_("%s, please check your locale settings") % k)
83 except UnicodeDecodeError:
83 except UnicodeDecodeError:
84 pass
84 pass
85 u = s.decode("utf-8", "replace") # last ditch
85 u = s.decode("utf-8", "replace") # last ditch
86 return u.encode(_encoding, "replace")
86 return u.encode(_encoding, "replace")
87
87
88 def fromlocal(s):
88 def fromlocal(s):
89 """
89 """
90 Convert a string from the local character encoding to UTF-8
90 Convert a string from the local character encoding to UTF-8
91
91
92 We attempt to decode strings using the encoding mode set by
92 We attempt to decode strings using the encoding mode set by
93 HGENCODINGMODE, which defaults to 'strict'. In this mode, unknown
93 HGENCODINGMODE, which defaults to 'strict'. In this mode, unknown
94 characters will cause an error message. Other modes include
94 characters will cause an error message. Other modes include
95 'replace', which replaces unknown characters with a special
95 'replace', which replaces unknown characters with a special
96 Unicode character, and 'ignore', which drops the character.
96 Unicode character, and 'ignore', which drops the character.
97 """
97 """
98 try:
98 try:
99 return s.decode(_encoding, _encodingmode).encode("utf-8")
99 return s.decode(_encoding, _encodingmode).encode("utf-8")
100 except UnicodeDecodeError, inst:
100 except UnicodeDecodeError, inst:
101 sub = s[max(0, inst.start-10):inst.start+10]
101 sub = s[max(0, inst.start-10):inst.start+10]
102 raise Abort("decoding near '%s': %s!" % (sub, inst))
102 raise Abort("decoding near '%s': %s!" % (sub, inst))
103 except LookupError, k:
103 except LookupError, k:
104 raise Abort(_("%s, please check your locale settings") % k)
104 raise Abort(_("%s, please check your locale settings") % k)
105
105
106 def locallen(s):
106 def locallen(s):
107 """Find the length in characters of a local string"""
107 """Find the length in characters of a local string"""
108 return len(s.decode(_encoding, "replace"))
108 return len(s.decode(_encoding, "replace"))
109
109
110 # used by parsedate
110 # used by parsedate
111 defaultdateformats = (
111 defaultdateformats = (
112 '%Y-%m-%d %H:%M:%S',
112 '%Y-%m-%d %H:%M:%S',
113 '%Y-%m-%d %I:%M:%S%p',
113 '%Y-%m-%d %I:%M:%S%p',
114 '%Y-%m-%d %H:%M',
114 '%Y-%m-%d %H:%M',
115 '%Y-%m-%d %I:%M%p',
115 '%Y-%m-%d %I:%M%p',
116 '%Y-%m-%d',
116 '%Y-%m-%d',
117 '%m-%d',
117 '%m-%d',
118 '%m/%d',
118 '%m/%d',
119 '%m/%d/%y',
119 '%m/%d/%y',
120 '%m/%d/%Y',
120 '%m/%d/%Y',
121 '%a %b %d %H:%M:%S %Y',
121 '%a %b %d %H:%M:%S %Y',
122 '%a %b %d %I:%M:%S%p %Y',
122 '%a %b %d %I:%M:%S%p %Y',
123 '%a, %d %b %Y %H:%M:%S', # GNU coreutils "/bin/date --rfc-2822"
123 '%a, %d %b %Y %H:%M:%S', # GNU coreutils "/bin/date --rfc-2822"
124 '%b %d %H:%M:%S %Y',
124 '%b %d %H:%M:%S %Y',
125 '%b %d %I:%M:%S%p %Y',
125 '%b %d %I:%M:%S%p %Y',
126 '%b %d %H:%M:%S',
126 '%b %d %H:%M:%S',
127 '%b %d %I:%M:%S%p',
127 '%b %d %I:%M:%S%p',
128 '%b %d %H:%M',
128 '%b %d %H:%M',
129 '%b %d %I:%M%p',
129 '%b %d %I:%M%p',
130 '%b %d %Y',
130 '%b %d %Y',
131 '%b %d',
131 '%b %d',
132 '%H:%M:%S',
132 '%H:%M:%S',
133 '%I:%M:%SP',
133 '%I:%M:%SP',
134 '%H:%M',
134 '%H:%M',
135 '%I:%M%p',
135 '%I:%M%p',
136 )
136 )
137
137
138 extendeddateformats = defaultdateformats + (
138 extendeddateformats = defaultdateformats + (
139 "%Y",
139 "%Y",
140 "%Y-%m",
140 "%Y-%m",
141 "%b",
141 "%b",
142 "%b %Y",
142 "%b %Y",
143 )
143 )
144
144
145 class SignalInterrupt(Exception):
145 class SignalInterrupt(Exception):
146 """Exception raised on SIGTERM and SIGHUP."""
146 """Exception raised on SIGTERM and SIGHUP."""
147
147
148 # differences from SafeConfigParser:
148 # differences from SafeConfigParser:
149 # - case-sensitive keys
149 # - case-sensitive keys
150 # - allows values that are not strings (this means that you may not
150 # - allows values that are not strings (this means that you may not
151 # be able to save the configuration to a file)
151 # be able to save the configuration to a file)
152 class configparser(ConfigParser.SafeConfigParser):
152 class configparser(ConfigParser.SafeConfigParser):
153 def optionxform(self, optionstr):
153 def optionxform(self, optionstr):
154 return optionstr
154 return optionstr
155
155
156 def set(self, section, option, value):
156 def set(self, section, option, value):
157 return ConfigParser.ConfigParser.set(self, section, option, value)
157 return ConfigParser.ConfigParser.set(self, section, option, value)
158
158
159 def _interpolate(self, section, option, rawval, vars):
159 def _interpolate(self, section, option, rawval, vars):
160 if not isinstance(rawval, basestring):
160 if not isinstance(rawval, basestring):
161 return rawval
161 return rawval
162 return ConfigParser.SafeConfigParser._interpolate(self, section,
162 return ConfigParser.SafeConfigParser._interpolate(self, section,
163 option, rawval, vars)
163 option, rawval, vars)
164
164
165 def cachefunc(func):
165 def cachefunc(func):
166 '''cache the result of function calls'''
166 '''cache the result of function calls'''
167 # XXX doesn't handle keywords args
167 # XXX doesn't handle keywords args
168 cache = {}
168 cache = {}
169 if func.func_code.co_argcount == 1:
169 if func.func_code.co_argcount == 1:
170 # we gain a small amount of time because
170 # we gain a small amount of time because
171 # we don't need to pack/unpack the list
171 # we don't need to pack/unpack the list
172 def f(arg):
172 def f(arg):
173 if arg not in cache:
173 if arg not in cache:
174 cache[arg] = func(arg)
174 cache[arg] = func(arg)
175 return cache[arg]
175 return cache[arg]
176 else:
176 else:
177 def f(*args):
177 def f(*args):
178 if args not in cache:
178 if args not in cache:
179 cache[args] = func(*args)
179 cache[args] = func(*args)
180 return cache[args]
180 return cache[args]
181
181
182 return f
182 return f
183
183
184 def pipefilter(s, cmd):
184 def pipefilter(s, cmd):
185 '''filter string S through command CMD, returning its output'''
185 '''filter string S through command CMD, returning its output'''
186 (pin, pout) = os.popen2(cmd, 'b')
186 (pin, pout) = os.popen2(cmd, 'b')
187 def writer():
187 def writer():
188 try:
188 try:
189 pin.write(s)
189 pin.write(s)
190 pin.close()
190 pin.close()
191 except IOError, inst:
191 except IOError, inst:
192 if inst.errno != errno.EPIPE:
192 if inst.errno != errno.EPIPE:
193 raise
193 raise
194
194
195 # we should use select instead on UNIX, but this will work on most
195 # we should use select instead on UNIX, but this will work on most
196 # systems, including Windows
196 # systems, including Windows
197 w = threading.Thread(target=writer)
197 w = threading.Thread(target=writer)
198 w.start()
198 w.start()
199 f = pout.read()
199 f = pout.read()
200 pout.close()
200 pout.close()
201 w.join()
201 w.join()
202 return f
202 return f
203
203
204 def tempfilter(s, cmd):
204 def tempfilter(s, cmd):
205 '''filter string S through a pair of temporary files with CMD.
205 '''filter string S through a pair of temporary files with CMD.
206 CMD is used as a template to create the real command to be run,
206 CMD is used as a template to create the real command to be run,
207 with the strings INFILE and OUTFILE replaced by the real names of
207 with the strings INFILE and OUTFILE replaced by the real names of
208 the temporary files generated.'''
208 the temporary files generated.'''
209 inname, outname = None, None
209 inname, outname = None, None
210 try:
210 try:
211 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
211 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
212 fp = os.fdopen(infd, 'wb')
212 fp = os.fdopen(infd, 'wb')
213 fp.write(s)
213 fp.write(s)
214 fp.close()
214 fp.close()
215 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
215 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
216 os.close(outfd)
216 os.close(outfd)
217 cmd = cmd.replace('INFILE', inname)
217 cmd = cmd.replace('INFILE', inname)
218 cmd = cmd.replace('OUTFILE', outname)
218 cmd = cmd.replace('OUTFILE', outname)
219 code = os.system(cmd)
219 code = os.system(cmd)
220 if sys.platform == 'OpenVMS' and code & 1:
220 if sys.platform == 'OpenVMS' and code & 1:
221 code = 0
221 code = 0
222 if code: raise Abort(_("command '%s' failed: %s") %
222 if code: raise Abort(_("command '%s' failed: %s") %
223 (cmd, explain_exit(code)))
223 (cmd, explain_exit(code)))
224 return open(outname, 'rb').read()
224 return open(outname, 'rb').read()
225 finally:
225 finally:
226 try:
226 try:
227 if inname: os.unlink(inname)
227 if inname: os.unlink(inname)
228 except: pass
228 except: pass
229 try:
229 try:
230 if outname: os.unlink(outname)
230 if outname: os.unlink(outname)
231 except: pass
231 except: pass
232
232
233 filtertable = {
233 filtertable = {
234 'tempfile:': tempfilter,
234 'tempfile:': tempfilter,
235 'pipe:': pipefilter,
235 'pipe:': pipefilter,
236 }
236 }
237
237
238 def filter(s, cmd):
238 def filter(s, cmd):
239 "filter a string through a command that transforms its input to its output"
239 "filter a string through a command that transforms its input to its output"
240 for name, fn in filtertable.iteritems():
240 for name, fn in filtertable.iteritems():
241 if cmd.startswith(name):
241 if cmd.startswith(name):
242 return fn(s, cmd[len(name):].lstrip())
242 return fn(s, cmd[len(name):].lstrip())
243 return pipefilter(s, cmd)
243 return pipefilter(s, cmd)
244
244
245 def binary(s):
245 def binary(s):
246 """return true if a string is binary data using diff's heuristic"""
246 """return true if a string is binary data using diff's heuristic"""
247 if s and '\0' in s[:4096]:
247 if s and '\0' in s[:4096]:
248 return True
248 return True
249 return False
249 return False
250
250
251 def unique(g):
251 def unique(g):
252 """return the uniq elements of iterable g"""
252 """return the uniq elements of iterable g"""
253 return dict.fromkeys(g).keys()
253 return dict.fromkeys(g).keys()
254
254
255 class Abort(Exception):
255 class Abort(Exception):
256 """Raised if a command needs to print an error and exit."""
256 """Raised if a command needs to print an error and exit."""
257
257
258 class UnexpectedOutput(Abort):
258 class UnexpectedOutput(Abort):
259 """Raised to print an error with part of output and exit."""
259 """Raised to print an error with part of output and exit."""
260
260
261 def always(fn): return True
261 def always(fn): return True
262 def never(fn): return False
262 def never(fn): return False
263
263
264 def expand_glob(pats):
264 def expand_glob(pats):
265 '''On Windows, expand the implicit globs in a list of patterns'''
265 '''On Windows, expand the implicit globs in a list of patterns'''
266 if os.name != 'nt':
266 if os.name != 'nt':
267 return list(pats)
267 return list(pats)
268 ret = []
268 ret = []
269 for p in pats:
269 for p in pats:
270 kind, name = patkind(p, None)
270 kind, name = patkind(p, None)
271 if kind is None:
271 if kind is None:
272 globbed = glob.glob(name)
272 globbed = glob.glob(name)
273 if globbed:
273 if globbed:
274 ret.extend(globbed)
274 ret.extend(globbed)
275 continue
275 continue
276 # if we couldn't expand the glob, just keep it around
276 # if we couldn't expand the glob, just keep it around
277 ret.append(p)
277 ret.append(p)
278 return ret
278 return ret
279
279
280 def patkind(name, dflt_pat='glob'):
280 def patkind(name, dflt_pat='glob'):
281 """Split a string into an optional pattern kind prefix and the
281 """Split a string into an optional pattern kind prefix and the
282 actual pattern."""
282 actual pattern."""
283 for prefix in 're', 'glob', 'path', 'relglob', 'relpath', 'relre':
283 for prefix in 're', 'glob', 'path', 'relglob', 'relpath', 'relre':
284 if name.startswith(prefix + ':'): return name.split(':', 1)
284 if name.startswith(prefix + ':'): return name.split(':', 1)
285 return dflt_pat, name
285 return dflt_pat, name
286
286
287 def globre(pat, head='^', tail='$'):
287 def globre(pat, head='^', tail='$'):
288 "convert a glob pattern into a regexp"
288 "convert a glob pattern into a regexp"
289 i, n = 0, len(pat)
289 i, n = 0, len(pat)
290 res = ''
290 res = ''
291 group = 0
291 group = 0
292 def peek(): return i < n and pat[i]
292 def peek(): return i < n and pat[i]
293 while i < n:
293 while i < n:
294 c = pat[i]
294 c = pat[i]
295 i = i+1
295 i = i+1
296 if c == '*':
296 if c == '*':
297 if peek() == '*':
297 if peek() == '*':
298 i += 1
298 i += 1
299 res += '.*'
299 res += '.*'
300 else:
300 else:
301 res += '[^/]*'
301 res += '[^/]*'
302 elif c == '?':
302 elif c == '?':
303 res += '.'
303 res += '.'
304 elif c == '[':
304 elif c == '[':
305 j = i
305 j = i
306 if j < n and pat[j] in '!]':
306 if j < n and pat[j] in '!]':
307 j += 1
307 j += 1
308 while j < n and pat[j] != ']':
308 while j < n and pat[j] != ']':
309 j += 1
309 j += 1
310 if j >= n:
310 if j >= n:
311 res += '\\['
311 res += '\\['
312 else:
312 else:
313 stuff = pat[i:j].replace('\\','\\\\')
313 stuff = pat[i:j].replace('\\','\\\\')
314 i = j + 1
314 i = j + 1
315 if stuff[0] == '!':
315 if stuff[0] == '!':
316 stuff = '^' + stuff[1:]
316 stuff = '^' + stuff[1:]
317 elif stuff[0] == '^':
317 elif stuff[0] == '^':
318 stuff = '\\' + stuff
318 stuff = '\\' + stuff
319 res = '%s[%s]' % (res, stuff)
319 res = '%s[%s]' % (res, stuff)
320 elif c == '{':
320 elif c == '{':
321 group += 1
321 group += 1
322 res += '(?:'
322 res += '(?:'
323 elif c == '}' and group:
323 elif c == '}' and group:
324 res += ')'
324 res += ')'
325 group -= 1
325 group -= 1
326 elif c == ',' and group:
326 elif c == ',' and group:
327 res += '|'
327 res += '|'
328 elif c == '\\':
328 elif c == '\\':
329 p = peek()
329 p = peek()
330 if p:
330 if p:
331 i += 1
331 i += 1
332 res += re.escape(p)
332 res += re.escape(p)
333 else:
333 else:
334 res += re.escape(c)
334 res += re.escape(c)
335 else:
335 else:
336 res += re.escape(c)
336 res += re.escape(c)
337 return head + res + tail
337 return head + res + tail
338
338
339 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
339 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
340
340
341 def pathto(root, n1, n2):
341 def pathto(root, n1, n2):
342 '''return the relative path from one place to another.
342 '''return the relative path from one place to another.
343 root should use os.sep to separate directories
343 root should use os.sep to separate directories
344 n1 should use os.sep to separate directories
344 n1 should use os.sep to separate directories
345 n2 should use "/" to separate directories
345 n2 should use "/" to separate directories
346 returns an os.sep-separated path.
346 returns an os.sep-separated path.
347
347
348 If n1 is a relative path, it's assumed it's
348 If n1 is a relative path, it's assumed it's
349 relative to root.
349 relative to root.
350 n2 should always be relative to root.
350 n2 should always be relative to root.
351 '''
351 '''
352 if not n1: return localpath(n2)
352 if not n1: return localpath(n2)
353 if os.path.isabs(n1):
353 if os.path.isabs(n1):
354 if os.path.splitdrive(root)[0] != os.path.splitdrive(n1)[0]:
354 if os.path.splitdrive(root)[0] != os.path.splitdrive(n1)[0]:
355 return os.path.join(root, localpath(n2))
355 return os.path.join(root, localpath(n2))
356 n2 = '/'.join((pconvert(root), n2))
356 n2 = '/'.join((pconvert(root), n2))
357 a, b = splitpath(n1), n2.split('/')
357 a, b = splitpath(n1), n2.split('/')
358 a.reverse()
358 a.reverse()
359 b.reverse()
359 b.reverse()
360 while a and b and a[-1] == b[-1]:
360 while a and b and a[-1] == b[-1]:
361 a.pop()
361 a.pop()
362 b.pop()
362 b.pop()
363 b.reverse()
363 b.reverse()
364 return os.sep.join((['..'] * len(a)) + b) or '.'
364 return os.sep.join((['..'] * len(a)) + b) or '.'
365
365
366 def canonpath(root, cwd, myname):
366 def canonpath(root, cwd, myname):
367 """return the canonical path of myname, given cwd and root"""
367 """return the canonical path of myname, given cwd and root"""
368 if root == os.sep:
368 if root == os.sep:
369 rootsep = os.sep
369 rootsep = os.sep
370 elif endswithsep(root):
370 elif endswithsep(root):
371 rootsep = root
371 rootsep = root
372 else:
372 else:
373 rootsep = root + os.sep
373 rootsep = root + os.sep
374 name = myname
374 name = myname
375 if not os.path.isabs(name):
375 if not os.path.isabs(name):
376 name = os.path.join(root, cwd, name)
376 name = os.path.join(root, cwd, name)
377 name = os.path.normpath(name)
377 name = os.path.normpath(name)
378 audit_path = path_auditor(root)
378 audit_path = path_auditor(root)
379 if name != rootsep and name.startswith(rootsep):
379 if name != rootsep and name.startswith(rootsep):
380 name = name[len(rootsep):]
380 name = name[len(rootsep):]
381 audit_path(name)
381 audit_path(name)
382 return pconvert(name)
382 return pconvert(name)
383 elif name == root:
383 elif name == root:
384 return ''
384 return ''
385 else:
385 else:
386 # Determine whether `name' is in the hierarchy at or beneath `root',
386 # Determine whether `name' is in the hierarchy at or beneath `root',
387 # by iterating name=dirname(name) until that causes no change (can't
387 # by iterating name=dirname(name) until that causes no change (can't
388 # check name == '/', because that doesn't work on windows). For each
388 # check name == '/', because that doesn't work on windows). For each
389 # `name', compare dev/inode numbers. If they match, the list `rel'
389 # `name', compare dev/inode numbers. If they match, the list `rel'
390 # holds the reversed list of components making up the relative file
390 # holds the reversed list of components making up the relative file
391 # name we want.
391 # name we want.
392 root_st = os.stat(root)
392 root_st = os.stat(root)
393 rel = []
393 rel = []
394 while True:
394 while True:
395 try:
395 try:
396 name_st = os.stat(name)
396 name_st = os.stat(name)
397 except OSError:
397 except OSError:
398 break
398 break
399 if samestat(name_st, root_st):
399 if samestat(name_st, root_st):
400 if not rel:
400 if not rel:
401 # name was actually the same as root (maybe a symlink)
401 # name was actually the same as root (maybe a symlink)
402 return ''
402 return ''
403 rel.reverse()
403 rel.reverse()
404 name = os.path.join(*rel)
404 name = os.path.join(*rel)
405 audit_path(name)
405 audit_path(name)
406 return pconvert(name)
406 return pconvert(name)
407 dirname, basename = os.path.split(name)
407 dirname, basename = os.path.split(name)
408 rel.append(basename)
408 rel.append(basename)
409 if dirname == name:
409 if dirname == name:
410 break
410 break
411 name = dirname
411 name = dirname
412
412
413 raise Abort('%s not under root' % myname)
413 raise Abort('%s not under root' % myname)
414
414
415 def matcher(canonroot, cwd='', names=[], inc=[], exc=[], src=None):
415 def matcher(canonroot, cwd='', names=[], inc=[], exc=[], src=None):
416 return _matcher(canonroot, cwd, names, inc, exc, 'glob', src)
416 return _matcher(canonroot, cwd, names, inc, exc, 'glob', src)
417
417
418 def cmdmatcher(canonroot, cwd='', names=[], inc=[], exc=[], src=None,
418 def cmdmatcher(canonroot, cwd='', names=[], inc=[], exc=[], src=None,
419 globbed=False, default=None):
419 globbed=False, default=None):
420 default = default or 'relpath'
420 default = default or 'relpath'
421 if default == 'relpath' and not globbed:
421 if default == 'relpath' and not globbed:
422 names = expand_glob(names)
422 names = expand_glob(names)
423 return _matcher(canonroot, cwd, names, inc, exc, default, src)
423 return _matcher(canonroot, cwd, names, inc, exc, default, src)
424
424
425 def _matcher(canonroot, cwd, names, inc, exc, dflt_pat, src):
425 def _matcher(canonroot, cwd, names, inc, exc, dflt_pat, src):
426 """build a function to match a set of file patterns
426 """build a function to match a set of file patterns
427
427
428 arguments:
428 arguments:
429 canonroot - the canonical root of the tree you're matching against
429 canonroot - the canonical root of the tree you're matching against
430 cwd - the current working directory, if relevant
430 cwd - the current working directory, if relevant
431 names - patterns to find
431 names - patterns to find
432 inc - patterns to include
432 inc - patterns to include
433 exc - patterns to exclude
433 exc - patterns to exclude
434 dflt_pat - if a pattern in names has no explicit type, assume this one
434 dflt_pat - if a pattern in names has no explicit type, assume this one
435 src - where these patterns came from (e.g. .hgignore)
435 src - where these patterns came from (e.g. .hgignore)
436
436
437 a pattern is one of:
437 a pattern is one of:
438 'glob:<glob>' - a glob relative to cwd
438 'glob:<glob>' - a glob relative to cwd
439 're:<regexp>' - a regular expression
439 're:<regexp>' - a regular expression
440 'path:<path>' - a path relative to canonroot
440 'path:<path>' - a path relative to canonroot
441 'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs)
441 'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs)
442 'relpath:<path>' - a path relative to cwd
442 'relpath:<path>' - a path relative to cwd
443 'relre:<regexp>' - a regexp that doesn't have to match the start of a name
443 'relre:<regexp>' - a regexp that doesn't have to match the start of a name
444 '<something>' - one of the cases above, selected by the dflt_pat argument
444 '<something>' - one of the cases above, selected by the dflt_pat argument
445
445
446 returns:
446 returns:
447 a 3-tuple containing
447 a 3-tuple containing
448 - list of roots (places where one should start a recursive walk of the fs);
448 - list of roots (places where one should start a recursive walk of the fs);
449 this often matches the explicit non-pattern names passed in, but also
449 this often matches the explicit non-pattern names passed in, but also
450 includes the initial part of glob: patterns that has no glob characters
450 includes the initial part of glob: patterns that has no glob characters
451 - a bool match(filename) function
451 - a bool match(filename) function
452 - a bool indicating if any patterns were passed in
452 - a bool indicating if any patterns were passed in
453 """
453 """
454
454
455 # a common case: no patterns at all
455 # a common case: no patterns at all
456 if not names and not inc and not exc:
456 if not names and not inc and not exc:
457 return [], always, False
457 return [], always, False
458
458
459 def contains_glob(name):
459 def contains_glob(name):
460 for c in name:
460 for c in name:
461 if c in _globchars: return True
461 if c in _globchars: return True
462 return False
462 return False
463
463
464 def regex(kind, name, tail):
464 def regex(kind, name, tail):
465 '''convert a pattern into a regular expression'''
465 '''convert a pattern into a regular expression'''
466 if not name:
466 if not name:
467 return ''
467 return ''
468 if kind == 're':
468 if kind == 're':
469 return name
469 return name
470 elif kind == 'path':
470 elif kind == 'path':
471 return '^' + re.escape(name) + '(?:/|$)'
471 return '^' + re.escape(name) + '(?:/|$)'
472 elif kind == 'relglob':
472 elif kind == 'relglob':
473 return globre(name, '(?:|.*/)', tail)
473 return globre(name, '(?:|.*/)', tail)
474 elif kind == 'relpath':
474 elif kind == 'relpath':
475 return re.escape(name) + '(?:/|$)'
475 return re.escape(name) + '(?:/|$)'
476 elif kind == 'relre':
476 elif kind == 'relre':
477 if name.startswith('^'):
477 if name.startswith('^'):
478 return name
478 return name
479 return '.*' + name
479 return '.*' + name
480 return globre(name, '', tail)
480 return globre(name, '', tail)
481
481
482 def matchfn(pats, tail):
482 def matchfn(pats, tail):
483 """build a matching function from a set of patterns"""
483 """build a matching function from a set of patterns"""
484 if not pats:
484 if not pats:
485 return
485 return
486 try:
486 try:
487 pat = '(?:%s)' % '|'.join([regex(k, p, tail) for (k, p) in pats])
487 pat = '(?:%s)' % '|'.join([regex(k, p, tail) for (k, p) in pats])
488 if len(pat) > 20000:
488 if len(pat) > 20000:
489 raise OverflowError()
489 raise OverflowError()
490 return re.compile(pat).match
490 return re.compile(pat).match
491 except OverflowError:
491 except OverflowError:
492 # We're using a Python with a tiny regex engine and we
492 # We're using a Python with a tiny regex engine and we
493 # made it explode, so we'll divide the pattern list in two
493 # made it explode, so we'll divide the pattern list in two
494 # until it works
494 # until it works
495 l = len(pats)
495 l = len(pats)
496 if l < 2:
496 if l < 2:
497 raise
497 raise
498 a, b = matchfn(pats[:l//2], tail), matchfn(pats[l//2:], tail)
498 a, b = matchfn(pats[:l//2], tail), matchfn(pats[l//2:], tail)
499 return lambda s: a(s) or b(s)
499 return lambda s: a(s) or b(s)
500 except re.error:
500 except re.error:
501 for k, p in pats:
501 for k, p in pats:
502 try:
502 try:
503 re.compile('(?:%s)' % regex(k, p, tail))
503 re.compile('(?:%s)' % regex(k, p, tail))
504 except re.error:
504 except re.error:
505 if src:
505 if src:
506 raise Abort("%s: invalid pattern (%s): %s" %
506 raise Abort("%s: invalid pattern (%s): %s" %
507 (src, k, p))
507 (src, k, p))
508 else:
508 else:
509 raise Abort("invalid pattern (%s): %s" % (k, p))
509 raise Abort("invalid pattern (%s): %s" % (k, p))
510 raise Abort("invalid pattern")
510 raise Abort("invalid pattern")
511
511
512 def globprefix(pat):
512 def globprefix(pat):
513 '''return the non-glob prefix of a path, e.g. foo/* -> foo'''
513 '''return the non-glob prefix of a path, e.g. foo/* -> foo'''
514 root = []
514 root = []
515 for p in pat.split('/'):
515 for p in pat.split('/'):
516 if contains_glob(p): break
516 if contains_glob(p): break
517 root.append(p)
517 root.append(p)
518 return '/'.join(root) or '.'
518 return '/'.join(root) or '.'
519
519
520 def normalizepats(names, default):
520 def normalizepats(names, default):
521 pats = []
521 pats = []
522 roots = []
522 roots = []
523 anypats = False
523 anypats = False
524 for kind, name in [patkind(p, default) for p in names]:
524 for kind, name in [patkind(p, default) for p in names]:
525 if kind in ('glob', 'relpath'):
525 if kind in ('glob', 'relpath'):
526 name = canonpath(canonroot, cwd, name)
526 name = canonpath(canonroot, cwd, name)
527 elif kind in ('relglob', 'path'):
527 elif kind in ('relglob', 'path'):
528 name = normpath(name)
528 name = normpath(name)
529
529
530 pats.append((kind, name))
530 pats.append((kind, name))
531
531
532 if kind in ('glob', 're', 'relglob', 'relre'):
532 if kind in ('glob', 're', 'relglob', 'relre'):
533 anypats = True
533 anypats = True
534
534
535 if kind == 'glob':
535 if kind == 'glob':
536 root = globprefix(name)
536 root = globprefix(name)
537 roots.append(root)
537 roots.append(root)
538 elif kind in ('relpath', 'path'):
538 elif kind in ('relpath', 'path'):
539 roots.append(name or '.')
539 roots.append(name or '.')
540 elif kind == 'relglob':
540 elif kind == 'relglob':
541 roots.append('.')
541 roots.append('.')
542 return roots, pats, anypats
542 return roots, pats, anypats
543
543
544 roots, pats, anypats = normalizepats(names, dflt_pat)
544 roots, pats, anypats = normalizepats(names, dflt_pat)
545
545
546 patmatch = matchfn(pats, '$') or always
546 patmatch = matchfn(pats, '$') or always
547 incmatch = always
547 incmatch = always
548 if inc:
548 if inc:
549 dummy, inckinds, dummy = normalizepats(inc, 'glob')
549 dummy, inckinds, dummy = normalizepats(inc, 'glob')
550 incmatch = matchfn(inckinds, '(?:/|$)')
550 incmatch = matchfn(inckinds, '(?:/|$)')
551 excmatch = lambda fn: False
551 excmatch = lambda fn: False
552 if exc:
552 if exc:
553 dummy, exckinds, dummy = normalizepats(exc, 'glob')
553 dummy, exckinds, dummy = normalizepats(exc, 'glob')
554 excmatch = matchfn(exckinds, '(?:/|$)')
554 excmatch = matchfn(exckinds, '(?:/|$)')
555
555
556 if not names and inc and not exc:
556 if not names and inc and not exc:
557 # common case: hgignore patterns
557 # common case: hgignore patterns
558 match = incmatch
558 match = incmatch
559 else:
559 else:
560 match = lambda fn: incmatch(fn) and not excmatch(fn) and patmatch(fn)
560 match = lambda fn: incmatch(fn) and not excmatch(fn) and patmatch(fn)
561
561
562 return (roots, match, (inc or exc or anypats) and True)
562 return (roots, match, (inc or exc or anypats) and True)
563
563
564 _hgexecutable = None
564 _hgexecutable = None
565
565
566 def main_is_frozen():
567 """return True if we are a frozen executable.
568
569 The code supports py2exe (most common, Windows only) and tools/freeze
570 (portable, not much used).
571 """
572 return (hasattr(sys, "frozen") or # new py2exe
573 hasattr(sys, "importers") or # old py2exe
574 imp.is_frozen("__main__")) # tools/freeze
575
566 def hgexecutable():
576 def hgexecutable():
567 """return location of the 'hg' executable.
577 """return location of the 'hg' executable.
568
578
569 Defaults to $HG or 'hg' in the search path.
579 Defaults to $HG or 'hg' in the search path.
570 """
580 """
571 if _hgexecutable is None:
581 if _hgexecutable is None:
572 set_hgexecutable(os.environ.get('HG') or find_exe('hg', 'hg'))
582 hg = os.environ.get('HG')
583 if hg:
584 set_hgexecutable(hg)
585 elif main_is_frozen():
586 set_hgexecutable(sys.executable)
587 else:
588 set_hgexecutable(find_exe('hg', 'hg'))
573 return _hgexecutable
589 return _hgexecutable
574
590
575 def set_hgexecutable(path):
591 def set_hgexecutable(path):
576 """set location of the 'hg' executable"""
592 """set location of the 'hg' executable"""
577 global _hgexecutable
593 global _hgexecutable
578 _hgexecutable = path
594 _hgexecutable = path
579
595
580 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
596 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
581 '''enhanced shell command execution.
597 '''enhanced shell command execution.
582 run with environment maybe modified, maybe in different dir.
598 run with environment maybe modified, maybe in different dir.
583
599
584 if command fails and onerr is None, return status. if ui object,
600 if command fails and onerr is None, return status. if ui object,
585 print error message and return status, else raise onerr object as
601 print error message and return status, else raise onerr object as
586 exception.'''
602 exception.'''
587 def py2shell(val):
603 def py2shell(val):
588 'convert python object into string that is useful to shell'
604 'convert python object into string that is useful to shell'
589 if val in (None, False):
605 if val in (None, False):
590 return '0'
606 return '0'
591 if val == True:
607 if val == True:
592 return '1'
608 return '1'
593 return str(val)
609 return str(val)
594 oldenv = {}
610 oldenv = {}
595 for k in environ:
611 for k in environ:
596 oldenv[k] = os.environ.get(k)
612 oldenv[k] = os.environ.get(k)
597 if cwd is not None:
613 if cwd is not None:
598 oldcwd = os.getcwd()
614 oldcwd = os.getcwd()
599 origcmd = cmd
615 origcmd = cmd
600 if os.name == 'nt':
616 if os.name == 'nt':
601 cmd = '"%s"' % cmd
617 cmd = '"%s"' % cmd
602 try:
618 try:
603 for k, v in environ.iteritems():
619 for k, v in environ.iteritems():
604 os.environ[k] = py2shell(v)
620 os.environ[k] = py2shell(v)
605 os.environ['HG'] = hgexecutable()
621 os.environ['HG'] = hgexecutable()
606 if cwd is not None and oldcwd != cwd:
622 if cwd is not None and oldcwd != cwd:
607 os.chdir(cwd)
623 os.chdir(cwd)
608 rc = os.system(cmd)
624 rc = os.system(cmd)
609 if sys.platform == 'OpenVMS' and rc & 1:
625 if sys.platform == 'OpenVMS' and rc & 1:
610 rc = 0
626 rc = 0
611 if rc and onerr:
627 if rc and onerr:
612 errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
628 errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
613 explain_exit(rc)[0])
629 explain_exit(rc)[0])
614 if errprefix:
630 if errprefix:
615 errmsg = '%s: %s' % (errprefix, errmsg)
631 errmsg = '%s: %s' % (errprefix, errmsg)
616 try:
632 try:
617 onerr.warn(errmsg + '\n')
633 onerr.warn(errmsg + '\n')
618 except AttributeError:
634 except AttributeError:
619 raise onerr(errmsg)
635 raise onerr(errmsg)
620 return rc
636 return rc
621 finally:
637 finally:
622 for k, v in oldenv.iteritems():
638 for k, v in oldenv.iteritems():
623 if v is None:
639 if v is None:
624 del os.environ[k]
640 del os.environ[k]
625 else:
641 else:
626 os.environ[k] = v
642 os.environ[k] = v
627 if cwd is not None and oldcwd != cwd:
643 if cwd is not None and oldcwd != cwd:
628 os.chdir(oldcwd)
644 os.chdir(oldcwd)
629
645
630 # os.path.lexists is not available on python2.3
646 # os.path.lexists is not available on python2.3
631 def lexists(filename):
647 def lexists(filename):
632 "test whether a file with this name exists. does not follow symlinks"
648 "test whether a file with this name exists. does not follow symlinks"
633 try:
649 try:
634 os.lstat(filename)
650 os.lstat(filename)
635 except:
651 except:
636 return False
652 return False
637 return True
653 return True
638
654
639 def rename(src, dst):
655 def rename(src, dst):
640 """forcibly rename a file"""
656 """forcibly rename a file"""
641 try:
657 try:
642 os.rename(src, dst)
658 os.rename(src, dst)
643 except OSError, err: # FIXME: check err (EEXIST ?)
659 except OSError, err: # FIXME: check err (EEXIST ?)
644 # on windows, rename to existing file is not allowed, so we
660 # on windows, rename to existing file is not allowed, so we
645 # must delete destination first. but if file is open, unlink
661 # must delete destination first. but if file is open, unlink
646 # schedules it for delete but does not delete it. rename
662 # schedules it for delete but does not delete it. rename
647 # happens immediately even for open files, so we create
663 # happens immediately even for open files, so we create
648 # temporary file, delete it, rename destination to that name,
664 # temporary file, delete it, rename destination to that name,
649 # then delete that. then rename is safe to do.
665 # then delete that. then rename is safe to do.
650 fd, temp = tempfile.mkstemp(dir=os.path.dirname(dst) or '.')
666 fd, temp = tempfile.mkstemp(dir=os.path.dirname(dst) or '.')
651 os.close(fd)
667 os.close(fd)
652 os.unlink(temp)
668 os.unlink(temp)
653 os.rename(dst, temp)
669 os.rename(dst, temp)
654 os.unlink(temp)
670 os.unlink(temp)
655 os.rename(src, dst)
671 os.rename(src, dst)
656
672
657 def unlink(f):
673 def unlink(f):
658 """unlink and remove the directory if it is empty"""
674 """unlink and remove the directory if it is empty"""
659 os.unlink(f)
675 os.unlink(f)
660 # try removing directories that might now be empty
676 # try removing directories that might now be empty
661 try:
677 try:
662 os.removedirs(os.path.dirname(f))
678 os.removedirs(os.path.dirname(f))
663 except OSError:
679 except OSError:
664 pass
680 pass
665
681
666 def copyfile(src, dest):
682 def copyfile(src, dest):
667 "copy a file, preserving mode"
683 "copy a file, preserving mode"
668 if os.path.islink(src):
684 if os.path.islink(src):
669 try:
685 try:
670 os.unlink(dest)
686 os.unlink(dest)
671 except:
687 except:
672 pass
688 pass
673 os.symlink(os.readlink(src), dest)
689 os.symlink(os.readlink(src), dest)
674 else:
690 else:
675 try:
691 try:
676 shutil.copyfile(src, dest)
692 shutil.copyfile(src, dest)
677 shutil.copymode(src, dest)
693 shutil.copymode(src, dest)
678 except shutil.Error, inst:
694 except shutil.Error, inst:
679 raise Abort(str(inst))
695 raise Abort(str(inst))
680
696
681 def copyfiles(src, dst, hardlink=None):
697 def copyfiles(src, dst, hardlink=None):
682 """Copy a directory tree using hardlinks if possible"""
698 """Copy a directory tree using hardlinks if possible"""
683
699
684 if hardlink is None:
700 if hardlink is None:
685 hardlink = (os.stat(src).st_dev ==
701 hardlink = (os.stat(src).st_dev ==
686 os.stat(os.path.dirname(dst)).st_dev)
702 os.stat(os.path.dirname(dst)).st_dev)
687
703
688 if os.path.isdir(src):
704 if os.path.isdir(src):
689 os.mkdir(dst)
705 os.mkdir(dst)
690 for name, kind in osutil.listdir(src):
706 for name, kind in osutil.listdir(src):
691 srcname = os.path.join(src, name)
707 srcname = os.path.join(src, name)
692 dstname = os.path.join(dst, name)
708 dstname = os.path.join(dst, name)
693 copyfiles(srcname, dstname, hardlink)
709 copyfiles(srcname, dstname, hardlink)
694 else:
710 else:
695 if hardlink:
711 if hardlink:
696 try:
712 try:
697 os_link(src, dst)
713 os_link(src, dst)
698 except (IOError, OSError):
714 except (IOError, OSError):
699 hardlink = False
715 hardlink = False
700 shutil.copy(src, dst)
716 shutil.copy(src, dst)
701 else:
717 else:
702 shutil.copy(src, dst)
718 shutil.copy(src, dst)
703
719
704 class path_auditor(object):
720 class path_auditor(object):
705 '''ensure that a filesystem path contains no banned components.
721 '''ensure that a filesystem path contains no banned components.
706 the following properties of a path are checked:
722 the following properties of a path are checked:
707
723
708 - under top-level .hg
724 - under top-level .hg
709 - starts at the root of a windows drive
725 - starts at the root of a windows drive
710 - contains ".."
726 - contains ".."
711 - traverses a symlink (e.g. a/symlink_here/b)
727 - traverses a symlink (e.g. a/symlink_here/b)
712 - inside a nested repository'''
728 - inside a nested repository'''
713
729
714 def __init__(self, root):
730 def __init__(self, root):
715 self.audited = set()
731 self.audited = set()
716 self.auditeddir = set()
732 self.auditeddir = set()
717 self.root = root
733 self.root = root
718
734
719 def __call__(self, path):
735 def __call__(self, path):
720 if path in self.audited:
736 if path in self.audited:
721 return
737 return
722 normpath = os.path.normcase(path)
738 normpath = os.path.normcase(path)
723 parts = splitpath(normpath)
739 parts = splitpath(normpath)
724 if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '')
740 if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '')
725 or os.pardir in parts):
741 or os.pardir in parts):
726 raise Abort(_("path contains illegal component: %s") % path)
742 raise Abort(_("path contains illegal component: %s") % path)
727 def check(prefix):
743 def check(prefix):
728 curpath = os.path.join(self.root, prefix)
744 curpath = os.path.join(self.root, prefix)
729 try:
745 try:
730 st = os.lstat(curpath)
746 st = os.lstat(curpath)
731 except OSError, err:
747 except OSError, err:
732 # EINVAL can be raised as invalid path syntax under win32.
748 # EINVAL can be raised as invalid path syntax under win32.
733 # They must be ignored for patterns can be checked too.
749 # They must be ignored for patterns can be checked too.
734 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
750 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
735 raise
751 raise
736 else:
752 else:
737 if stat.S_ISLNK(st.st_mode):
753 if stat.S_ISLNK(st.st_mode):
738 raise Abort(_('path %r traverses symbolic link %r') %
754 raise Abort(_('path %r traverses symbolic link %r') %
739 (path, prefix))
755 (path, prefix))
740 elif (stat.S_ISDIR(st.st_mode) and
756 elif (stat.S_ISDIR(st.st_mode) and
741 os.path.isdir(os.path.join(curpath, '.hg'))):
757 os.path.isdir(os.path.join(curpath, '.hg'))):
742 raise Abort(_('path %r is inside repo %r') %
758 raise Abort(_('path %r is inside repo %r') %
743 (path, prefix))
759 (path, prefix))
744 parts.pop()
760 parts.pop()
745 prefixes = []
761 prefixes = []
746 for n in range(len(parts)):
762 for n in range(len(parts)):
747 prefix = os.sep.join(parts)
763 prefix = os.sep.join(parts)
748 if prefix in self.auditeddir:
764 if prefix in self.auditeddir:
749 break
765 break
750 check(prefix)
766 check(prefix)
751 prefixes.append(prefix)
767 prefixes.append(prefix)
752 parts.pop()
768 parts.pop()
753
769
754 self.audited.add(path)
770 self.audited.add(path)
755 # only add prefixes to the cache after checking everything: we don't
771 # only add prefixes to the cache after checking everything: we don't
756 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
772 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
757 self.auditeddir.update(prefixes)
773 self.auditeddir.update(prefixes)
758
774
759 def _makelock_file(info, pathname):
775 def _makelock_file(info, pathname):
760 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
776 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
761 os.write(ld, info)
777 os.write(ld, info)
762 os.close(ld)
778 os.close(ld)
763
779
764 def _readlock_file(pathname):
780 def _readlock_file(pathname):
765 return posixfile(pathname).read()
781 return posixfile(pathname).read()
766
782
767 def nlinks(pathname):
783 def nlinks(pathname):
768 """Return number of hardlinks for the given file."""
784 """Return number of hardlinks for the given file."""
769 return os.lstat(pathname).st_nlink
785 return os.lstat(pathname).st_nlink
770
786
771 if hasattr(os, 'link'):
787 if hasattr(os, 'link'):
772 os_link = os.link
788 os_link = os.link
773 else:
789 else:
774 def os_link(src, dst):
790 def os_link(src, dst):
775 raise OSError(0, _("Hardlinks not supported"))
791 raise OSError(0, _("Hardlinks not supported"))
776
792
777 def fstat(fp):
793 def fstat(fp):
778 '''stat file object that may not have fileno method.'''
794 '''stat file object that may not have fileno method.'''
779 try:
795 try:
780 return os.fstat(fp.fileno())
796 return os.fstat(fp.fileno())
781 except AttributeError:
797 except AttributeError:
782 return os.stat(fp.name)
798 return os.stat(fp.name)
783
799
784 posixfile = file
800 posixfile = file
785
801
786 def openhardlinks():
802 def openhardlinks():
787 '''return true if it is safe to hold open file handles to hardlinks'''
803 '''return true if it is safe to hold open file handles to hardlinks'''
788 return True
804 return True
789
805
790 getuser_fallback = None
806 getuser_fallback = None
791
807
792 def getuser():
808 def getuser():
793 '''return name of current user'''
809 '''return name of current user'''
794 try:
810 try:
795 return getpass.getuser()
811 return getpass.getuser()
796 except ImportError:
812 except ImportError:
797 # import of pwd will fail on windows - try fallback
813 # import of pwd will fail on windows - try fallback
798 if getuser_fallback:
814 if getuser_fallback:
799 return getuser_fallback()
815 return getuser_fallback()
800 # raised if win32api not available
816 # raised if win32api not available
801 raise Abort(_('user name not available - set USERNAME '
817 raise Abort(_('user name not available - set USERNAME '
802 'environment variable'))
818 'environment variable'))
803
819
804 def username(uid=None):
820 def username(uid=None):
805 """Return the name of the user with the given uid.
821 """Return the name of the user with the given uid.
806
822
807 If uid is None, return the name of the current user."""
823 If uid is None, return the name of the current user."""
808 try:
824 try:
809 import pwd
825 import pwd
810 if uid is None:
826 if uid is None:
811 uid = os.getuid()
827 uid = os.getuid()
812 try:
828 try:
813 return pwd.getpwuid(uid)[0]
829 return pwd.getpwuid(uid)[0]
814 except KeyError:
830 except KeyError:
815 return str(uid)
831 return str(uid)
816 except ImportError:
832 except ImportError:
817 return None
833 return None
818
834
819 def groupname(gid=None):
835 def groupname(gid=None):
820 """Return the name of the group with the given gid.
836 """Return the name of the group with the given gid.
821
837
822 If gid is None, return the name of the current group."""
838 If gid is None, return the name of the current group."""
823 try:
839 try:
824 import grp
840 import grp
825 if gid is None:
841 if gid is None:
826 gid = os.getgid()
842 gid = os.getgid()
827 try:
843 try:
828 return grp.getgrgid(gid)[0]
844 return grp.getgrgid(gid)[0]
829 except KeyError:
845 except KeyError:
830 return str(gid)
846 return str(gid)
831 except ImportError:
847 except ImportError:
832 return None
848 return None
833
849
834 # File system features
850 # File system features
835
851
836 def checkfolding(path):
852 def checkfolding(path):
837 """
853 """
838 Check whether the given path is on a case-sensitive filesystem
854 Check whether the given path is on a case-sensitive filesystem
839
855
840 Requires a path (like /foo/.hg) ending with a foldable final
856 Requires a path (like /foo/.hg) ending with a foldable final
841 directory component.
857 directory component.
842 """
858 """
843 s1 = os.stat(path)
859 s1 = os.stat(path)
844 d, b = os.path.split(path)
860 d, b = os.path.split(path)
845 p2 = os.path.join(d, b.upper())
861 p2 = os.path.join(d, b.upper())
846 if path == p2:
862 if path == p2:
847 p2 = os.path.join(d, b.lower())
863 p2 = os.path.join(d, b.lower())
848 try:
864 try:
849 s2 = os.stat(p2)
865 s2 = os.stat(p2)
850 if s2 == s1:
866 if s2 == s1:
851 return False
867 return False
852 return True
868 return True
853 except:
869 except:
854 return True
870 return True
855
871
856 def checkexec(path):
872 def checkexec(path):
857 """
873 """
858 Check whether the given path is on a filesystem with UNIX-like exec flags
874 Check whether the given path is on a filesystem with UNIX-like exec flags
859
875
860 Requires a directory (like /foo/.hg)
876 Requires a directory (like /foo/.hg)
861 """
877 """
862
878
863 # VFAT on some Linux versions can flip mode but it doesn't persist
879 # VFAT on some Linux versions can flip mode but it doesn't persist
864 # a FS remount. Frequently we can detect it if files are created
880 # a FS remount. Frequently we can detect it if files are created
865 # with exec bit on.
881 # with exec bit on.
866
882
867 try:
883 try:
868 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
884 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
869 fh, fn = tempfile.mkstemp("", "", path)
885 fh, fn = tempfile.mkstemp("", "", path)
870 try:
886 try:
871 os.close(fh)
887 os.close(fh)
872 m = os.stat(fn).st_mode & 0777
888 m = os.stat(fn).st_mode & 0777
873 new_file_has_exec = m & EXECFLAGS
889 new_file_has_exec = m & EXECFLAGS
874 os.chmod(fn, m ^ EXECFLAGS)
890 os.chmod(fn, m ^ EXECFLAGS)
875 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
891 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
876 finally:
892 finally:
877 os.unlink(fn)
893 os.unlink(fn)
878 except (IOError, OSError):
894 except (IOError, OSError):
879 # we don't care, the user probably won't be able to commit anyway
895 # we don't care, the user probably won't be able to commit anyway
880 return False
896 return False
881 return not (new_file_has_exec or exec_flags_cannot_flip)
897 return not (new_file_has_exec or exec_flags_cannot_flip)
882
898
883 def execfunc(path, fallback):
899 def execfunc(path, fallback):
884 '''return an is_exec() function with default to fallback'''
900 '''return an is_exec() function with default to fallback'''
885 if checkexec(path):
901 if checkexec(path):
886 return lambda x: is_exec(os.path.join(path, x))
902 return lambda x: is_exec(os.path.join(path, x))
887 return fallback
903 return fallback
888
904
889 def checklink(path):
905 def checklink(path):
890 """check whether the given path is on a symlink-capable filesystem"""
906 """check whether the given path is on a symlink-capable filesystem"""
891 # mktemp is not racy because symlink creation will fail if the
907 # mktemp is not racy because symlink creation will fail if the
892 # file already exists
908 # file already exists
893 name = tempfile.mktemp(dir=path)
909 name = tempfile.mktemp(dir=path)
894 try:
910 try:
895 os.symlink(".", name)
911 os.symlink(".", name)
896 os.unlink(name)
912 os.unlink(name)
897 return True
913 return True
898 except (OSError, AttributeError):
914 except (OSError, AttributeError):
899 return False
915 return False
900
916
901 def linkfunc(path, fallback):
917 def linkfunc(path, fallback):
902 '''return an is_link() function with default to fallback'''
918 '''return an is_link() function with default to fallback'''
903 if checklink(path):
919 if checklink(path):
904 return lambda x: os.path.islink(os.path.join(path, x))
920 return lambda x: os.path.islink(os.path.join(path, x))
905 return fallback
921 return fallback
906
922
907 _umask = os.umask(0)
923 _umask = os.umask(0)
908 os.umask(_umask)
924 os.umask(_umask)
909
925
910 def needbinarypatch():
926 def needbinarypatch():
911 """return True if patches should be applied in binary mode by default."""
927 """return True if patches should be applied in binary mode by default."""
912 return os.name == 'nt'
928 return os.name == 'nt'
913
929
914 def endswithsep(path):
930 def endswithsep(path):
915 '''Check path ends with os.sep or os.altsep.'''
931 '''Check path ends with os.sep or os.altsep.'''
916 return path.endswith(os.sep) or os.altsep and path.endswith(os.altsep)
932 return path.endswith(os.sep) or os.altsep and path.endswith(os.altsep)
917
933
918 def splitpath(path):
934 def splitpath(path):
919 '''Split path by os.sep.
935 '''Split path by os.sep.
920 Note that this function does not use os.altsep because this is
936 Note that this function does not use os.altsep because this is
921 an alternative of simple "xxx.split(os.sep)".
937 an alternative of simple "xxx.split(os.sep)".
922 It is recommended to use os.path.normpath() before using this
938 It is recommended to use os.path.normpath() before using this
923 function if need.'''
939 function if need.'''
924 return path.split(os.sep)
940 return path.split(os.sep)
925
941
926 def gui():
942 def gui():
927 '''Are we running in a GUI?'''
943 '''Are we running in a GUI?'''
928 return os.name == "nt" or os.name == "mac" or os.environ.get("DISPLAY")
944 return os.name == "nt" or os.name == "mac" or os.environ.get("DISPLAY")
929
945
930 def lookup_reg(key, name=None, scope=None):
946 def lookup_reg(key, name=None, scope=None):
931 return None
947 return None
932
948
933 # Platform specific variants
949 # Platform specific variants
934 if os.name == 'nt':
950 if os.name == 'nt':
935 import msvcrt
951 import msvcrt
936 nulldev = 'NUL:'
952 nulldev = 'NUL:'
937
953
938 class winstdout:
954 class winstdout:
939 '''stdout on windows misbehaves if sent through a pipe'''
955 '''stdout on windows misbehaves if sent through a pipe'''
940
956
941 def __init__(self, fp):
957 def __init__(self, fp):
942 self.fp = fp
958 self.fp = fp
943
959
944 def __getattr__(self, key):
960 def __getattr__(self, key):
945 return getattr(self.fp, key)
961 return getattr(self.fp, key)
946
962
947 def close(self):
963 def close(self):
948 try:
964 try:
949 self.fp.close()
965 self.fp.close()
950 except: pass
966 except: pass
951
967
952 def write(self, s):
968 def write(self, s):
953 try:
969 try:
954 # This is workaround for "Not enough space" error on
970 # This is workaround for "Not enough space" error on
955 # writing large size of data to console.
971 # writing large size of data to console.
956 limit = 16000
972 limit = 16000
957 l = len(s)
973 l = len(s)
958 start = 0
974 start = 0
959 while start < l:
975 while start < l:
960 end = start + limit
976 end = start + limit
961 self.fp.write(s[start:end])
977 self.fp.write(s[start:end])
962 start = end
978 start = end
963 except IOError, inst:
979 except IOError, inst:
964 if inst.errno != 0: raise
980 if inst.errno != 0: raise
965 self.close()
981 self.close()
966 raise IOError(errno.EPIPE, 'Broken pipe')
982 raise IOError(errno.EPIPE, 'Broken pipe')
967
983
968 def flush(self):
984 def flush(self):
969 try:
985 try:
970 return self.fp.flush()
986 return self.fp.flush()
971 except IOError, inst:
987 except IOError, inst:
972 if inst.errno != errno.EINVAL: raise
988 if inst.errno != errno.EINVAL: raise
973 self.close()
989 self.close()
974 raise IOError(errno.EPIPE, 'Broken pipe')
990 raise IOError(errno.EPIPE, 'Broken pipe')
975
991
976 sys.stdout = winstdout(sys.stdout)
992 sys.stdout = winstdout(sys.stdout)
977
993
978 def _is_win_9x():
994 def _is_win_9x():
979 '''return true if run on windows 95, 98 or me.'''
995 '''return true if run on windows 95, 98 or me.'''
980 try:
996 try:
981 return sys.getwindowsversion()[3] == 1
997 return sys.getwindowsversion()[3] == 1
982 except AttributeError:
998 except AttributeError:
983 return 'command' in os.environ.get('comspec', '')
999 return 'command' in os.environ.get('comspec', '')
984
1000
985 def openhardlinks():
1001 def openhardlinks():
986 return not _is_win_9x and "win32api" in locals()
1002 return not _is_win_9x and "win32api" in locals()
987
1003
988 def system_rcpath():
1004 def system_rcpath():
989 try:
1005 try:
990 return system_rcpath_win32()
1006 return system_rcpath_win32()
991 except:
1007 except:
992 return [r'c:\mercurial\mercurial.ini']
1008 return [r'c:\mercurial\mercurial.ini']
993
1009
994 def user_rcpath():
1010 def user_rcpath():
995 '''return os-specific hgrc search path to the user dir'''
1011 '''return os-specific hgrc search path to the user dir'''
996 try:
1012 try:
997 path = user_rcpath_win32()
1013 path = user_rcpath_win32()
998 except:
1014 except:
999 home = os.path.expanduser('~')
1015 home = os.path.expanduser('~')
1000 path = [os.path.join(home, 'mercurial.ini'),
1016 path = [os.path.join(home, 'mercurial.ini'),
1001 os.path.join(home, '.hgrc')]
1017 os.path.join(home, '.hgrc')]
1002 userprofile = os.environ.get('USERPROFILE')
1018 userprofile = os.environ.get('USERPROFILE')
1003 if userprofile:
1019 if userprofile:
1004 path.append(os.path.join(userprofile, 'mercurial.ini'))
1020 path.append(os.path.join(userprofile, 'mercurial.ini'))
1005 path.append(os.path.join(userprofile, '.hgrc'))
1021 path.append(os.path.join(userprofile, '.hgrc'))
1006 return path
1022 return path
1007
1023
1008 def parse_patch_output(output_line):
1024 def parse_patch_output(output_line):
1009 """parses the output produced by patch and returns the file name"""
1025 """parses the output produced by patch and returns the file name"""
1010 pf = output_line[14:]
1026 pf = output_line[14:]
1011 if pf[0] == '`':
1027 if pf[0] == '`':
1012 pf = pf[1:-1] # Remove the quotes
1028 pf = pf[1:-1] # Remove the quotes
1013 return pf
1029 return pf
1014
1030
1015 def sshargs(sshcmd, host, user, port):
1031 def sshargs(sshcmd, host, user, port):
1016 '''Build argument list for ssh or Plink'''
1032 '''Build argument list for ssh or Plink'''
1017 pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
1033 pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
1018 args = user and ("%s@%s" % (user, host)) or host
1034 args = user and ("%s@%s" % (user, host)) or host
1019 return port and ("%s %s %s" % (args, pflag, port)) or args
1035 return port and ("%s %s %s" % (args, pflag, port)) or args
1020
1036
1021 def testpid(pid):
1037 def testpid(pid):
1022 '''return False if pid dead, True if running or not known'''
1038 '''return False if pid dead, True if running or not known'''
1023 return True
1039 return True
1024
1040
1025 def set_flags(f, flags):
1041 def set_flags(f, flags):
1026 pass
1042 pass
1027
1043
1028 def set_binary(fd):
1044 def set_binary(fd):
1029 # When run without console, pipes may expose invalid
1045 # When run without console, pipes may expose invalid
1030 # fileno(), usually set to -1.
1046 # fileno(), usually set to -1.
1031 if hasattr(fd, 'fileno') and fd.fileno() >= 0:
1047 if hasattr(fd, 'fileno') and fd.fileno() >= 0:
1032 msvcrt.setmode(fd.fileno(), os.O_BINARY)
1048 msvcrt.setmode(fd.fileno(), os.O_BINARY)
1033
1049
1034 def pconvert(path):
1050 def pconvert(path):
1035 return '/'.join(splitpath(path))
1051 return '/'.join(splitpath(path))
1036
1052
1037 def localpath(path):
1053 def localpath(path):
1038 return path.replace('/', '\\')
1054 return path.replace('/', '\\')
1039
1055
1040 def normpath(path):
1056 def normpath(path):
1041 return pconvert(os.path.normpath(path))
1057 return pconvert(os.path.normpath(path))
1042
1058
1043 makelock = _makelock_file
1059 makelock = _makelock_file
1044 readlock = _readlock_file
1060 readlock = _readlock_file
1045
1061
1046 def samestat(s1, s2):
1062 def samestat(s1, s2):
1047 return False
1063 return False
1048
1064
1049 # A sequence of backslashes is special iff it precedes a double quote:
1065 # A sequence of backslashes is special iff it precedes a double quote:
1050 # - if there's an even number of backslashes, the double quote is not
1066 # - if there's an even number of backslashes, the double quote is not
1051 # quoted (i.e. it ends the quoted region)
1067 # quoted (i.e. it ends the quoted region)
1052 # - if there's an odd number of backslashes, the double quote is quoted
1068 # - if there's an odd number of backslashes, the double quote is quoted
1053 # - in both cases, every pair of backslashes is unquoted into a single
1069 # - in both cases, every pair of backslashes is unquoted into a single
1054 # backslash
1070 # backslash
1055 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
1071 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
1056 # So, to quote a string, we must surround it in double quotes, double
1072 # So, to quote a string, we must surround it in double quotes, double
1057 # the number of backslashes that preceed double quotes and add another
1073 # the number of backslashes that preceed double quotes and add another
1058 # backslash before every double quote (being careful with the double
1074 # backslash before every double quote (being careful with the double
1059 # quote we've appended to the end)
1075 # quote we've appended to the end)
1060 _quotere = None
1076 _quotere = None
1061 def shellquote(s):
1077 def shellquote(s):
1062 global _quotere
1078 global _quotere
1063 if _quotere is None:
1079 if _quotere is None:
1064 _quotere = re.compile(r'(\\*)("|\\$)')
1080 _quotere = re.compile(r'(\\*)("|\\$)')
1065 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
1081 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
1066
1082
1067 def quotecommand(cmd):
1083 def quotecommand(cmd):
1068 """Build a command string suitable for os.popen* calls."""
1084 """Build a command string suitable for os.popen* calls."""
1069 # The extra quotes are needed because popen* runs the command
1085 # The extra quotes are needed because popen* runs the command
1070 # through the current COMSPEC. cmd.exe suppress enclosing quotes.
1086 # through the current COMSPEC. cmd.exe suppress enclosing quotes.
1071 return '"' + cmd + '"'
1087 return '"' + cmd + '"'
1072
1088
1073 def popen(command):
1089 def popen(command):
1074 # Work around "popen spawned process may not write to stdout
1090 # Work around "popen spawned process may not write to stdout
1075 # under windows"
1091 # under windows"
1076 # http://bugs.python.org/issue1366
1092 # http://bugs.python.org/issue1366
1077 command += " 2> %s" % nulldev
1093 command += " 2> %s" % nulldev
1078 return os.popen(quotecommand(command))
1094 return os.popen(quotecommand(command))
1079
1095
1080 def explain_exit(code):
1096 def explain_exit(code):
1081 return _("exited with status %d") % code, code
1097 return _("exited with status %d") % code, code
1082
1098
1083 # if you change this stub into a real check, please try to implement the
1099 # if you change this stub into a real check, please try to implement the
1084 # username and groupname functions above, too.
1100 # username and groupname functions above, too.
1085 def isowner(fp, st=None):
1101 def isowner(fp, st=None):
1086 return True
1102 return True
1087
1103
1088 def find_in_path(name, path, default=None):
1104 def find_in_path(name, path, default=None):
1089 '''find name in search path. path can be string (will be split
1105 '''find name in search path. path can be string (will be split
1090 with os.pathsep), or iterable thing that returns strings. if name
1106 with os.pathsep), or iterable thing that returns strings. if name
1091 found, return path to name. else return default. name is looked up
1107 found, return path to name. else return default. name is looked up
1092 using cmd.exe rules, using PATHEXT.'''
1108 using cmd.exe rules, using PATHEXT.'''
1093 if isinstance(path, str):
1109 if isinstance(path, str):
1094 path = path.split(os.pathsep)
1110 path = path.split(os.pathsep)
1095
1111
1096 pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
1112 pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
1097 pathext = pathext.lower().split(os.pathsep)
1113 pathext = pathext.lower().split(os.pathsep)
1098 isexec = os.path.splitext(name)[1].lower() in pathext
1114 isexec = os.path.splitext(name)[1].lower() in pathext
1099
1115
1100 for p in path:
1116 for p in path:
1101 p_name = os.path.join(p, name)
1117 p_name = os.path.join(p, name)
1102
1118
1103 if isexec and os.path.exists(p_name):
1119 if isexec and os.path.exists(p_name):
1104 return p_name
1120 return p_name
1105
1121
1106 for ext in pathext:
1122 for ext in pathext:
1107 p_name_ext = p_name + ext
1123 p_name_ext = p_name + ext
1108 if os.path.exists(p_name_ext):
1124 if os.path.exists(p_name_ext):
1109 return p_name_ext
1125 return p_name_ext
1110 return default
1126 return default
1111
1127
1112 def set_signal_handler():
1128 def set_signal_handler():
1113 try:
1129 try:
1114 set_signal_handler_win32()
1130 set_signal_handler_win32()
1115 except NameError:
1131 except NameError:
1116 pass
1132 pass
1117
1133
1118 try:
1134 try:
1119 # override functions with win32 versions if possible
1135 # override functions with win32 versions if possible
1120 from util_win32 import *
1136 from util_win32 import *
1121 if not _is_win_9x():
1137 if not _is_win_9x():
1122 posixfile = posixfile_nt
1138 posixfile = posixfile_nt
1123 except ImportError:
1139 except ImportError:
1124 pass
1140 pass
1125
1141
1126 else:
1142 else:
1127 nulldev = '/dev/null'
1143 nulldev = '/dev/null'
1128
1144
1129 def rcfiles(path):
1145 def rcfiles(path):
1130 rcs = [os.path.join(path, 'hgrc')]
1146 rcs = [os.path.join(path, 'hgrc')]
1131 rcdir = os.path.join(path, 'hgrc.d')
1147 rcdir = os.path.join(path, 'hgrc.d')
1132 try:
1148 try:
1133 rcs.extend([os.path.join(rcdir, f)
1149 rcs.extend([os.path.join(rcdir, f)
1134 for f, kind in osutil.listdir(rcdir)
1150 for f, kind in osutil.listdir(rcdir)
1135 if f.endswith(".rc")])
1151 if f.endswith(".rc")])
1136 except OSError:
1152 except OSError:
1137 pass
1153 pass
1138 return rcs
1154 return rcs
1139
1155
1140 def system_rcpath():
1156 def system_rcpath():
1141 path = []
1157 path = []
1142 # old mod_python does not set sys.argv
1158 # old mod_python does not set sys.argv
1143 if len(getattr(sys, 'argv', [])) > 0:
1159 if len(getattr(sys, 'argv', [])) > 0:
1144 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
1160 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
1145 '/../etc/mercurial'))
1161 '/../etc/mercurial'))
1146 path.extend(rcfiles('/etc/mercurial'))
1162 path.extend(rcfiles('/etc/mercurial'))
1147 return path
1163 return path
1148
1164
1149 def user_rcpath():
1165 def user_rcpath():
1150 return [os.path.expanduser('~/.hgrc')]
1166 return [os.path.expanduser('~/.hgrc')]
1151
1167
1152 def parse_patch_output(output_line):
1168 def parse_patch_output(output_line):
1153 """parses the output produced by patch and returns the file name"""
1169 """parses the output produced by patch and returns the file name"""
1154 pf = output_line[14:]
1170 pf = output_line[14:]
1155 if os.sys.platform == 'OpenVMS':
1171 if os.sys.platform == 'OpenVMS':
1156 if pf[0] == '`':
1172 if pf[0] == '`':
1157 pf = pf[1:-1] # Remove the quotes
1173 pf = pf[1:-1] # Remove the quotes
1158 else:
1174 else:
1159 if pf.startswith("'") and pf.endswith("'") and " " in pf:
1175 if pf.startswith("'") and pf.endswith("'") and " " in pf:
1160 pf = pf[1:-1] # Remove the quotes
1176 pf = pf[1:-1] # Remove the quotes
1161 return pf
1177 return pf
1162
1178
1163 def sshargs(sshcmd, host, user, port):
1179 def sshargs(sshcmd, host, user, port):
1164 '''Build argument list for ssh'''
1180 '''Build argument list for ssh'''
1165 args = user and ("%s@%s" % (user, host)) or host
1181 args = user and ("%s@%s" % (user, host)) or host
1166 return port and ("%s -p %s" % (args, port)) or args
1182 return port and ("%s -p %s" % (args, port)) or args
1167
1183
1168 def is_exec(f):
1184 def is_exec(f):
1169 """check whether a file is executable"""
1185 """check whether a file is executable"""
1170 return (os.lstat(f).st_mode & 0100 != 0)
1186 return (os.lstat(f).st_mode & 0100 != 0)
1171
1187
1172 def set_flags(f, flags):
1188 def set_flags(f, flags):
1173 s = os.lstat(f).st_mode
1189 s = os.lstat(f).st_mode
1174 x = "x" in flags
1190 x = "x" in flags
1175 l = "l" in flags
1191 l = "l" in flags
1176 if l:
1192 if l:
1177 if not stat.S_ISLNK(s):
1193 if not stat.S_ISLNK(s):
1178 # switch file to link
1194 # switch file to link
1179 data = file(f).read()
1195 data = file(f).read()
1180 os.unlink(f)
1196 os.unlink(f)
1181 os.symlink(data, f)
1197 os.symlink(data, f)
1182 # no chmod needed at this point
1198 # no chmod needed at this point
1183 return
1199 return
1184 if stat.S_ISLNK(s):
1200 if stat.S_ISLNK(s):
1185 # switch link to file
1201 # switch link to file
1186 data = os.readlink(f)
1202 data = os.readlink(f)
1187 os.unlink(f)
1203 os.unlink(f)
1188 file(f, "w").write(data)
1204 file(f, "w").write(data)
1189 s = 0666 & ~_umask # avoid restatting for chmod
1205 s = 0666 & ~_umask # avoid restatting for chmod
1190
1206
1191 sx = s & 0100
1207 sx = s & 0100
1192 if x and not sx:
1208 if x and not sx:
1193 # Turn on +x for every +r bit when making a file executable
1209 # Turn on +x for every +r bit when making a file executable
1194 # and obey umask.
1210 # and obey umask.
1195 os.chmod(f, s | (s & 0444) >> 2 & ~_umask)
1211 os.chmod(f, s | (s & 0444) >> 2 & ~_umask)
1196 elif not x and sx:
1212 elif not x and sx:
1197 # Turn off all +x bits
1213 # Turn off all +x bits
1198 os.chmod(f, s & 0666)
1214 os.chmod(f, s & 0666)
1199
1215
1200 def set_binary(fd):
1216 def set_binary(fd):
1201 pass
1217 pass
1202
1218
1203 def pconvert(path):
1219 def pconvert(path):
1204 return path
1220 return path
1205
1221
1206 def localpath(path):
1222 def localpath(path):
1207 return path
1223 return path
1208
1224
1209 normpath = os.path.normpath
1225 normpath = os.path.normpath
1210 samestat = os.path.samestat
1226 samestat = os.path.samestat
1211
1227
1212 def makelock(info, pathname):
1228 def makelock(info, pathname):
1213 try:
1229 try:
1214 os.symlink(info, pathname)
1230 os.symlink(info, pathname)
1215 except OSError, why:
1231 except OSError, why:
1216 if why.errno == errno.EEXIST:
1232 if why.errno == errno.EEXIST:
1217 raise
1233 raise
1218 else:
1234 else:
1219 _makelock_file(info, pathname)
1235 _makelock_file(info, pathname)
1220
1236
1221 def readlock(pathname):
1237 def readlock(pathname):
1222 try:
1238 try:
1223 return os.readlink(pathname)
1239 return os.readlink(pathname)
1224 except OSError, why:
1240 except OSError, why:
1225 if why.errno in (errno.EINVAL, errno.ENOSYS):
1241 if why.errno in (errno.EINVAL, errno.ENOSYS):
1226 return _readlock_file(pathname)
1242 return _readlock_file(pathname)
1227 else:
1243 else:
1228 raise
1244 raise
1229
1245
1230 def shellquote(s):
1246 def shellquote(s):
1231 if os.sys.platform == 'OpenVMS':
1247 if os.sys.platform == 'OpenVMS':
1232 return '"%s"' % s
1248 return '"%s"' % s
1233 else:
1249 else:
1234 return "'%s'" % s.replace("'", "'\\''")
1250 return "'%s'" % s.replace("'", "'\\''")
1235
1251
1236 def quotecommand(cmd):
1252 def quotecommand(cmd):
1237 return cmd
1253 return cmd
1238
1254
1239 def popen(command):
1255 def popen(command):
1240 return os.popen(command)
1256 return os.popen(command)
1241
1257
1242 def testpid(pid):
1258 def testpid(pid):
1243 '''return False if pid dead, True if running or not sure'''
1259 '''return False if pid dead, True if running or not sure'''
1244 if os.sys.platform == 'OpenVMS':
1260 if os.sys.platform == 'OpenVMS':
1245 return True
1261 return True
1246 try:
1262 try:
1247 os.kill(pid, 0)
1263 os.kill(pid, 0)
1248 return True
1264 return True
1249 except OSError, inst:
1265 except OSError, inst:
1250 return inst.errno != errno.ESRCH
1266 return inst.errno != errno.ESRCH
1251
1267
1252 def explain_exit(code):
1268 def explain_exit(code):
1253 """return a 2-tuple (desc, code) describing a process's status"""
1269 """return a 2-tuple (desc, code) describing a process's status"""
1254 if os.WIFEXITED(code):
1270 if os.WIFEXITED(code):
1255 val = os.WEXITSTATUS(code)
1271 val = os.WEXITSTATUS(code)
1256 return _("exited with status %d") % val, val
1272 return _("exited with status %d") % val, val
1257 elif os.WIFSIGNALED(code):
1273 elif os.WIFSIGNALED(code):
1258 val = os.WTERMSIG(code)
1274 val = os.WTERMSIG(code)
1259 return _("killed by signal %d") % val, val
1275 return _("killed by signal %d") % val, val
1260 elif os.WIFSTOPPED(code):
1276 elif os.WIFSTOPPED(code):
1261 val = os.WSTOPSIG(code)
1277 val = os.WSTOPSIG(code)
1262 return _("stopped by signal %d") % val, val
1278 return _("stopped by signal %d") % val, val
1263 raise ValueError(_("invalid exit code"))
1279 raise ValueError(_("invalid exit code"))
1264
1280
1265 def isowner(fp, st=None):
1281 def isowner(fp, st=None):
1266 """Return True if the file object f belongs to the current user.
1282 """Return True if the file object f belongs to the current user.
1267
1283
1268 The return value of a util.fstat(f) may be passed as the st argument.
1284 The return value of a util.fstat(f) may be passed as the st argument.
1269 """
1285 """
1270 if st is None:
1286 if st is None:
1271 st = fstat(fp)
1287 st = fstat(fp)
1272 return st.st_uid == os.getuid()
1288 return st.st_uid == os.getuid()
1273
1289
1274 def find_in_path(name, path, default=None):
1290 def find_in_path(name, path, default=None):
1275 '''find name in search path. path can be string (will be split
1291 '''find name in search path. path can be string (will be split
1276 with os.pathsep), or iterable thing that returns strings. if name
1292 with os.pathsep), or iterable thing that returns strings. if name
1277 found, return path to name. else return default.'''
1293 found, return path to name. else return default.'''
1278 if isinstance(path, str):
1294 if isinstance(path, str):
1279 path = path.split(os.pathsep)
1295 path = path.split(os.pathsep)
1280 for p in path:
1296 for p in path:
1281 p_name = os.path.join(p, name)
1297 p_name = os.path.join(p, name)
1282 if os.path.exists(p_name):
1298 if os.path.exists(p_name):
1283 return p_name
1299 return p_name
1284 return default
1300 return default
1285
1301
1286 def set_signal_handler():
1302 def set_signal_handler():
1287 pass
1303 pass
1288
1304
1289 def find_exe(name, default=None):
1305 def find_exe(name, default=None):
1290 '''find path of an executable.
1306 '''find path of an executable.
1291 if name contains a path component, return it as is. otherwise,
1307 if name contains a path component, return it as is. otherwise,
1292 use normal executable search path.'''
1308 use normal executable search path.'''
1293
1309
1294 if os.sep in name or sys.platform == 'OpenVMS':
1310 if os.sep in name or sys.platform == 'OpenVMS':
1295 # don't check the executable bit. if the file isn't
1311 # don't check the executable bit. if the file isn't
1296 # executable, whoever tries to actually run it will give a
1312 # executable, whoever tries to actually run it will give a
1297 # much more useful error message.
1313 # much more useful error message.
1298 return name
1314 return name
1299 return find_in_path(name, os.environ.get('PATH', ''), default=default)
1315 return find_in_path(name, os.environ.get('PATH', ''), default=default)
1300
1316
1301 def _buildencodefun():
1317 def _buildencodefun():
1302 e = '_'
1318 e = '_'
1303 win_reserved = [ord(x) for x in '\\:*?"<>|']
1319 win_reserved = [ord(x) for x in '\\:*?"<>|']
1304 cmap = dict([ (chr(x), chr(x)) for x in xrange(127) ])
1320 cmap = dict([ (chr(x), chr(x)) for x in xrange(127) ])
1305 for x in (range(32) + range(126, 256) + win_reserved):
1321 for x in (range(32) + range(126, 256) + win_reserved):
1306 cmap[chr(x)] = "~%02x" % x
1322 cmap[chr(x)] = "~%02x" % x
1307 for x in range(ord("A"), ord("Z")+1) + [ord(e)]:
1323 for x in range(ord("A"), ord("Z")+1) + [ord(e)]:
1308 cmap[chr(x)] = e + chr(x).lower()
1324 cmap[chr(x)] = e + chr(x).lower()
1309 dmap = {}
1325 dmap = {}
1310 for k, v in cmap.iteritems():
1326 for k, v in cmap.iteritems():
1311 dmap[v] = k
1327 dmap[v] = k
1312 def decode(s):
1328 def decode(s):
1313 i = 0
1329 i = 0
1314 while i < len(s):
1330 while i < len(s):
1315 for l in xrange(1, 4):
1331 for l in xrange(1, 4):
1316 try:
1332 try:
1317 yield dmap[s[i:i+l]]
1333 yield dmap[s[i:i+l]]
1318 i += l
1334 i += l
1319 break
1335 break
1320 except KeyError:
1336 except KeyError:
1321 pass
1337 pass
1322 else:
1338 else:
1323 raise KeyError
1339 raise KeyError
1324 return (lambda s: "".join([cmap[c] for c in s]),
1340 return (lambda s: "".join([cmap[c] for c in s]),
1325 lambda s: "".join(list(decode(s))))
1341 lambda s: "".join(list(decode(s))))
1326
1342
1327 encodefilename, decodefilename = _buildencodefun()
1343 encodefilename, decodefilename = _buildencodefun()
1328
1344
1329 def encodedopener(openerfn, fn):
1345 def encodedopener(openerfn, fn):
1330 def o(path, *args, **kw):
1346 def o(path, *args, **kw):
1331 return openerfn(fn(path), *args, **kw)
1347 return openerfn(fn(path), *args, **kw)
1332 return o
1348 return o
1333
1349
1334 def mktempcopy(name, emptyok=False, createmode=None):
1350 def mktempcopy(name, emptyok=False, createmode=None):
1335 """Create a temporary file with the same contents from name
1351 """Create a temporary file with the same contents from name
1336
1352
1337 The permission bits are copied from the original file.
1353 The permission bits are copied from the original file.
1338
1354
1339 If the temporary file is going to be truncated immediately, you
1355 If the temporary file is going to be truncated immediately, you
1340 can use emptyok=True as an optimization.
1356 can use emptyok=True as an optimization.
1341
1357
1342 Returns the name of the temporary file.
1358 Returns the name of the temporary file.
1343 """
1359 """
1344 d, fn = os.path.split(name)
1360 d, fn = os.path.split(name)
1345 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
1361 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
1346 os.close(fd)
1362 os.close(fd)
1347 # Temporary files are created with mode 0600, which is usually not
1363 # Temporary files are created with mode 0600, which is usually not
1348 # what we want. If the original file already exists, just copy
1364 # what we want. If the original file already exists, just copy
1349 # its mode. Otherwise, manually obey umask.
1365 # its mode. Otherwise, manually obey umask.
1350 try:
1366 try:
1351 st_mode = os.lstat(name).st_mode & 0777
1367 st_mode = os.lstat(name).st_mode & 0777
1352 except OSError, inst:
1368 except OSError, inst:
1353 if inst.errno != errno.ENOENT:
1369 if inst.errno != errno.ENOENT:
1354 raise
1370 raise
1355 st_mode = createmode
1371 st_mode = createmode
1356 if st_mode is None:
1372 if st_mode is None:
1357 st_mode = ~_umask
1373 st_mode = ~_umask
1358 st_mode &= 0666
1374 st_mode &= 0666
1359 os.chmod(temp, st_mode)
1375 os.chmod(temp, st_mode)
1360 if emptyok:
1376 if emptyok:
1361 return temp
1377 return temp
1362 try:
1378 try:
1363 try:
1379 try:
1364 ifp = posixfile(name, "rb")
1380 ifp = posixfile(name, "rb")
1365 except IOError, inst:
1381 except IOError, inst:
1366 if inst.errno == errno.ENOENT:
1382 if inst.errno == errno.ENOENT:
1367 return temp
1383 return temp
1368 if not getattr(inst, 'filename', None):
1384 if not getattr(inst, 'filename', None):
1369 inst.filename = name
1385 inst.filename = name
1370 raise
1386 raise
1371 ofp = posixfile(temp, "wb")
1387 ofp = posixfile(temp, "wb")
1372 for chunk in filechunkiter(ifp):
1388 for chunk in filechunkiter(ifp):
1373 ofp.write(chunk)
1389 ofp.write(chunk)
1374 ifp.close()
1390 ifp.close()
1375 ofp.close()
1391 ofp.close()
1376 except:
1392 except:
1377 try: os.unlink(temp)
1393 try: os.unlink(temp)
1378 except: pass
1394 except: pass
1379 raise
1395 raise
1380 return temp
1396 return temp
1381
1397
1382 class atomictempfile(posixfile):
1398 class atomictempfile(posixfile):
1383 """file-like object that atomically updates a file
1399 """file-like object that atomically updates a file
1384
1400
1385 All writes will be redirected to a temporary copy of the original
1401 All writes will be redirected to a temporary copy of the original
1386 file. When rename is called, the copy is renamed to the original
1402 file. When rename is called, the copy is renamed to the original
1387 name, making the changes visible.
1403 name, making the changes visible.
1388 """
1404 """
1389 def __init__(self, name, mode, createmode):
1405 def __init__(self, name, mode, createmode):
1390 self.__name = name
1406 self.__name = name
1391 self.temp = mktempcopy(name, emptyok=('w' in mode),
1407 self.temp = mktempcopy(name, emptyok=('w' in mode),
1392 createmode=createmode)
1408 createmode=createmode)
1393 posixfile.__init__(self, self.temp, mode)
1409 posixfile.__init__(self, self.temp, mode)
1394
1410
1395 def rename(self):
1411 def rename(self):
1396 if not self.closed:
1412 if not self.closed:
1397 posixfile.close(self)
1413 posixfile.close(self)
1398 rename(self.temp, localpath(self.__name))
1414 rename(self.temp, localpath(self.__name))
1399
1415
1400 def __del__(self):
1416 def __del__(self):
1401 if not self.closed:
1417 if not self.closed:
1402 try:
1418 try:
1403 os.unlink(self.temp)
1419 os.unlink(self.temp)
1404 except: pass
1420 except: pass
1405 posixfile.close(self)
1421 posixfile.close(self)
1406
1422
1407 def makedirs(name, mode=None):
1423 def makedirs(name, mode=None):
1408 """recursive directory creation with parent mode inheritance"""
1424 """recursive directory creation with parent mode inheritance"""
1409 try:
1425 try:
1410 os.mkdir(name)
1426 os.mkdir(name)
1411 if mode is not None:
1427 if mode is not None:
1412 os.chmod(name, mode)
1428 os.chmod(name, mode)
1413 return
1429 return
1414 except OSError, err:
1430 except OSError, err:
1415 if err.errno == errno.EEXIST:
1431 if err.errno == errno.EEXIST:
1416 return
1432 return
1417 if err.errno != errno.ENOENT:
1433 if err.errno != errno.ENOENT:
1418 raise
1434 raise
1419 parent = os.path.abspath(os.path.dirname(name))
1435 parent = os.path.abspath(os.path.dirname(name))
1420 makedirs(parent, mode)
1436 makedirs(parent, mode)
1421 makedirs(name, mode)
1437 makedirs(name, mode)
1422
1438
1423 class opener(object):
1439 class opener(object):
1424 """Open files relative to a base directory
1440 """Open files relative to a base directory
1425
1441
1426 This class is used to hide the details of COW semantics and
1442 This class is used to hide the details of COW semantics and
1427 remote file access from higher level code.
1443 remote file access from higher level code.
1428 """
1444 """
1429 def __init__(self, base, audit=True):
1445 def __init__(self, base, audit=True):
1430 self.base = base
1446 self.base = base
1431 if audit:
1447 if audit:
1432 self.audit_path = path_auditor(base)
1448 self.audit_path = path_auditor(base)
1433 else:
1449 else:
1434 self.audit_path = always
1450 self.audit_path = always
1435 self.createmode = None
1451 self.createmode = None
1436
1452
1437 def __getattr__(self, name):
1453 def __getattr__(self, name):
1438 if name == '_can_symlink':
1454 if name == '_can_symlink':
1439 self._can_symlink = checklink(self.base)
1455 self._can_symlink = checklink(self.base)
1440 return self._can_symlink
1456 return self._can_symlink
1441 raise AttributeError(name)
1457 raise AttributeError(name)
1442
1458
1443 def _fixfilemode(self, name):
1459 def _fixfilemode(self, name):
1444 if self.createmode is None:
1460 if self.createmode is None:
1445 return
1461 return
1446 os.chmod(name, self.createmode & 0666)
1462 os.chmod(name, self.createmode & 0666)
1447
1463
1448 def __call__(self, path, mode="r", text=False, atomictemp=False):
1464 def __call__(self, path, mode="r", text=False, atomictemp=False):
1449 self.audit_path(path)
1465 self.audit_path(path)
1450 f = os.path.join(self.base, path)
1466 f = os.path.join(self.base, path)
1451
1467
1452 if not text and "b" not in mode:
1468 if not text and "b" not in mode:
1453 mode += "b" # for that other OS
1469 mode += "b" # for that other OS
1454
1470
1455 nlink = -1
1471 nlink = -1
1456 if mode[0] != "r":
1472 if mode[0] != "r":
1457 try:
1473 try:
1458 nlink = nlinks(f)
1474 nlink = nlinks(f)
1459 except OSError:
1475 except OSError:
1460 nlink = 0
1476 nlink = 0
1461 d = os.path.dirname(f)
1477 d = os.path.dirname(f)
1462 if not os.path.isdir(d):
1478 if not os.path.isdir(d):
1463 makedirs(d, self.createmode)
1479 makedirs(d, self.createmode)
1464 if atomictemp:
1480 if atomictemp:
1465 return atomictempfile(f, mode, self.createmode)
1481 return atomictempfile(f, mode, self.createmode)
1466 if nlink > 1:
1482 if nlink > 1:
1467 rename(mktempcopy(f), f)
1483 rename(mktempcopy(f), f)
1468 fp = posixfile(f, mode)
1484 fp = posixfile(f, mode)
1469 if nlink == 0:
1485 if nlink == 0:
1470 self._fixfilemode(f)
1486 self._fixfilemode(f)
1471 return fp
1487 return fp
1472
1488
1473 def symlink(self, src, dst):
1489 def symlink(self, src, dst):
1474 self.audit_path(dst)
1490 self.audit_path(dst)
1475 linkname = os.path.join(self.base, dst)
1491 linkname = os.path.join(self.base, dst)
1476 try:
1492 try:
1477 os.unlink(linkname)
1493 os.unlink(linkname)
1478 except OSError:
1494 except OSError:
1479 pass
1495 pass
1480
1496
1481 dirname = os.path.dirname(linkname)
1497 dirname = os.path.dirname(linkname)
1482 if not os.path.exists(dirname):
1498 if not os.path.exists(dirname):
1483 makedirs(dirname, self.createmode)
1499 makedirs(dirname, self.createmode)
1484
1500
1485 if self._can_symlink:
1501 if self._can_symlink:
1486 try:
1502 try:
1487 os.symlink(src, linkname)
1503 os.symlink(src, linkname)
1488 except OSError, err:
1504 except OSError, err:
1489 raise OSError(err.errno, _('could not symlink to %r: %s') %
1505 raise OSError(err.errno, _('could not symlink to %r: %s') %
1490 (src, err.strerror), linkname)
1506 (src, err.strerror), linkname)
1491 else:
1507 else:
1492 f = self(dst, "w")
1508 f = self(dst, "w")
1493 f.write(src)
1509 f.write(src)
1494 f.close()
1510 f.close()
1495 self._fixfilemode(dst)
1511 self._fixfilemode(dst)
1496
1512
1497 class chunkbuffer(object):
1513 class chunkbuffer(object):
1498 """Allow arbitrary sized chunks of data to be efficiently read from an
1514 """Allow arbitrary sized chunks of data to be efficiently read from an
1499 iterator over chunks of arbitrary size."""
1515 iterator over chunks of arbitrary size."""
1500
1516
1501 def __init__(self, in_iter):
1517 def __init__(self, in_iter):
1502 """in_iter is the iterator that's iterating over the input chunks.
1518 """in_iter is the iterator that's iterating over the input chunks.
1503 targetsize is how big a buffer to try to maintain."""
1519 targetsize is how big a buffer to try to maintain."""
1504 self.iter = iter(in_iter)
1520 self.iter = iter(in_iter)
1505 self.buf = ''
1521 self.buf = ''
1506 self.targetsize = 2**16
1522 self.targetsize = 2**16
1507
1523
1508 def read(self, l):
1524 def read(self, l):
1509 """Read L bytes of data from the iterator of chunks of data.
1525 """Read L bytes of data from the iterator of chunks of data.
1510 Returns less than L bytes if the iterator runs dry."""
1526 Returns less than L bytes if the iterator runs dry."""
1511 if l > len(self.buf) and self.iter:
1527 if l > len(self.buf) and self.iter:
1512 # Clamp to a multiple of self.targetsize
1528 # Clamp to a multiple of self.targetsize
1513 targetsize = max(l, self.targetsize)
1529 targetsize = max(l, self.targetsize)
1514 collector = cStringIO.StringIO()
1530 collector = cStringIO.StringIO()
1515 collector.write(self.buf)
1531 collector.write(self.buf)
1516 collected = len(self.buf)
1532 collected = len(self.buf)
1517 for chunk in self.iter:
1533 for chunk in self.iter:
1518 collector.write(chunk)
1534 collector.write(chunk)
1519 collected += len(chunk)
1535 collected += len(chunk)
1520 if collected >= targetsize:
1536 if collected >= targetsize:
1521 break
1537 break
1522 if collected < targetsize:
1538 if collected < targetsize:
1523 self.iter = False
1539 self.iter = False
1524 self.buf = collector.getvalue()
1540 self.buf = collector.getvalue()
1525 if len(self.buf) == l:
1541 if len(self.buf) == l:
1526 s, self.buf = str(self.buf), ''
1542 s, self.buf = str(self.buf), ''
1527 else:
1543 else:
1528 s, self.buf = self.buf[:l], buffer(self.buf, l)
1544 s, self.buf = self.buf[:l], buffer(self.buf, l)
1529 return s
1545 return s
1530
1546
1531 def filechunkiter(f, size=65536, limit=None):
1547 def filechunkiter(f, size=65536, limit=None):
1532 """Create a generator that produces the data in the file size
1548 """Create a generator that produces the data in the file size
1533 (default 65536) bytes at a time, up to optional limit (default is
1549 (default 65536) bytes at a time, up to optional limit (default is
1534 to read all data). Chunks may be less than size bytes if the
1550 to read all data). Chunks may be less than size bytes if the
1535 chunk is the last chunk in the file, or the file is a socket or
1551 chunk is the last chunk in the file, or the file is a socket or
1536 some other type of file that sometimes reads less data than is
1552 some other type of file that sometimes reads less data than is
1537 requested."""
1553 requested."""
1538 assert size >= 0
1554 assert size >= 0
1539 assert limit is None or limit >= 0
1555 assert limit is None or limit >= 0
1540 while True:
1556 while True:
1541 if limit is None: nbytes = size
1557 if limit is None: nbytes = size
1542 else: nbytes = min(limit, size)
1558 else: nbytes = min(limit, size)
1543 s = nbytes and f.read(nbytes)
1559 s = nbytes and f.read(nbytes)
1544 if not s: break
1560 if not s: break
1545 if limit: limit -= len(s)
1561 if limit: limit -= len(s)
1546 yield s
1562 yield s
1547
1563
1548 def makedate():
1564 def makedate():
1549 lt = time.localtime()
1565 lt = time.localtime()
1550 if lt[8] == 1 and time.daylight:
1566 if lt[8] == 1 and time.daylight:
1551 tz = time.altzone
1567 tz = time.altzone
1552 else:
1568 else:
1553 tz = time.timezone
1569 tz = time.timezone
1554 return time.mktime(lt), tz
1570 return time.mktime(lt), tz
1555
1571
1556 def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'):
1572 def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'):
1557 """represent a (unixtime, offset) tuple as a localized time.
1573 """represent a (unixtime, offset) tuple as a localized time.
1558 unixtime is seconds since the epoch, and offset is the time zone's
1574 unixtime is seconds since the epoch, and offset is the time zone's
1559 number of seconds away from UTC. if timezone is false, do not
1575 number of seconds away from UTC. if timezone is false, do not
1560 append time zone to string."""
1576 append time zone to string."""
1561 t, tz = date or makedate()
1577 t, tz = date or makedate()
1562 if "%1" in format or "%2" in format:
1578 if "%1" in format or "%2" in format:
1563 sign = (tz > 0) and "-" or "+"
1579 sign = (tz > 0) and "-" or "+"
1564 minutes = abs(tz) / 60
1580 minutes = abs(tz) / 60
1565 format = format.replace("%1", "%c%02d" % (sign, minutes / 60))
1581 format = format.replace("%1", "%c%02d" % (sign, minutes / 60))
1566 format = format.replace("%2", "%02d" % (minutes % 60))
1582 format = format.replace("%2", "%02d" % (minutes % 60))
1567 s = time.strftime(format, time.gmtime(float(t) - tz))
1583 s = time.strftime(format, time.gmtime(float(t) - tz))
1568 return s
1584 return s
1569
1585
1570 def shortdate(date=None):
1586 def shortdate(date=None):
1571 """turn (timestamp, tzoff) tuple into iso 8631 date."""
1587 """turn (timestamp, tzoff) tuple into iso 8631 date."""
1572 return datestr(date, format='%Y-%m-%d')
1588 return datestr(date, format='%Y-%m-%d')
1573
1589
1574 def strdate(string, format, defaults=[]):
1590 def strdate(string, format, defaults=[]):
1575 """parse a localized time string and return a (unixtime, offset) tuple.
1591 """parse a localized time string and return a (unixtime, offset) tuple.
1576 if the string cannot be parsed, ValueError is raised."""
1592 if the string cannot be parsed, ValueError is raised."""
1577 def timezone(string):
1593 def timezone(string):
1578 tz = string.split()[-1]
1594 tz = string.split()[-1]
1579 if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
1595 if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
1580 sign = (tz[0] == "+") and 1 or -1
1596 sign = (tz[0] == "+") and 1 or -1
1581 hours = int(tz[1:3])
1597 hours = int(tz[1:3])
1582 minutes = int(tz[3:5])
1598 minutes = int(tz[3:5])
1583 return -sign * (hours * 60 + minutes) * 60
1599 return -sign * (hours * 60 + minutes) * 60
1584 if tz == "GMT" or tz == "UTC":
1600 if tz == "GMT" or tz == "UTC":
1585 return 0
1601 return 0
1586 return None
1602 return None
1587
1603
1588 # NOTE: unixtime = localunixtime + offset
1604 # NOTE: unixtime = localunixtime + offset
1589 offset, date = timezone(string), string
1605 offset, date = timezone(string), string
1590 if offset != None:
1606 if offset != None:
1591 date = " ".join(string.split()[:-1])
1607 date = " ".join(string.split()[:-1])
1592
1608
1593 # add missing elements from defaults
1609 # add missing elements from defaults
1594 for part in defaults:
1610 for part in defaults:
1595 found = [True for p in part if ("%"+p) in format]
1611 found = [True for p in part if ("%"+p) in format]
1596 if not found:
1612 if not found:
1597 date += "@" + defaults[part]
1613 date += "@" + defaults[part]
1598 format += "@%" + part[0]
1614 format += "@%" + part[0]
1599
1615
1600 timetuple = time.strptime(date, format)
1616 timetuple = time.strptime(date, format)
1601 localunixtime = int(calendar.timegm(timetuple))
1617 localunixtime = int(calendar.timegm(timetuple))
1602 if offset is None:
1618 if offset is None:
1603 # local timezone
1619 # local timezone
1604 unixtime = int(time.mktime(timetuple))
1620 unixtime = int(time.mktime(timetuple))
1605 offset = unixtime - localunixtime
1621 offset = unixtime - localunixtime
1606 else:
1622 else:
1607 unixtime = localunixtime + offset
1623 unixtime = localunixtime + offset
1608 return unixtime, offset
1624 return unixtime, offset
1609
1625
1610 def parsedate(date, formats=None, defaults=None):
1626 def parsedate(date, formats=None, defaults=None):
1611 """parse a localized date/time string and return a (unixtime, offset) tuple.
1627 """parse a localized date/time string and return a (unixtime, offset) tuple.
1612
1628
1613 The date may be a "unixtime offset" string or in one of the specified
1629 The date may be a "unixtime offset" string or in one of the specified
1614 formats. If the date already is a (unixtime, offset) tuple, it is returned.
1630 formats. If the date already is a (unixtime, offset) tuple, it is returned.
1615 """
1631 """
1616 if not date:
1632 if not date:
1617 return 0, 0
1633 return 0, 0
1618 if isinstance(date, tuple) and len(date) == 2:
1634 if isinstance(date, tuple) and len(date) == 2:
1619 return date
1635 return date
1620 if not formats:
1636 if not formats:
1621 formats = defaultdateformats
1637 formats = defaultdateformats
1622 date = date.strip()
1638 date = date.strip()
1623 try:
1639 try:
1624 when, offset = map(int, date.split(' '))
1640 when, offset = map(int, date.split(' '))
1625 except ValueError:
1641 except ValueError:
1626 # fill out defaults
1642 # fill out defaults
1627 if not defaults:
1643 if not defaults:
1628 defaults = {}
1644 defaults = {}
1629 now = makedate()
1645 now = makedate()
1630 for part in "d mb yY HI M S".split():
1646 for part in "d mb yY HI M S".split():
1631 if part not in defaults:
1647 if part not in defaults:
1632 if part[0] in "HMS":
1648 if part[0] in "HMS":
1633 defaults[part] = "00"
1649 defaults[part] = "00"
1634 else:
1650 else:
1635 defaults[part] = datestr(now, "%" + part[0])
1651 defaults[part] = datestr(now, "%" + part[0])
1636
1652
1637 for format in formats:
1653 for format in formats:
1638 try:
1654 try:
1639 when, offset = strdate(date, format, defaults)
1655 when, offset = strdate(date, format, defaults)
1640 except (ValueError, OverflowError):
1656 except (ValueError, OverflowError):
1641 pass
1657 pass
1642 else:
1658 else:
1643 break
1659 break
1644 else:
1660 else:
1645 raise Abort(_('invalid date: %r ') % date)
1661 raise Abort(_('invalid date: %r ') % date)
1646 # validate explicit (probably user-specified) date and
1662 # validate explicit (probably user-specified) date and
1647 # time zone offset. values must fit in signed 32 bits for
1663 # time zone offset. values must fit in signed 32 bits for
1648 # current 32-bit linux runtimes. timezones go from UTC-12
1664 # current 32-bit linux runtimes. timezones go from UTC-12
1649 # to UTC+14
1665 # to UTC+14
1650 if abs(when) > 0x7fffffff:
1666 if abs(when) > 0x7fffffff:
1651 raise Abort(_('date exceeds 32 bits: %d') % when)
1667 raise Abort(_('date exceeds 32 bits: %d') % when)
1652 if offset < -50400 or offset > 43200:
1668 if offset < -50400 or offset > 43200:
1653 raise Abort(_('impossible time zone offset: %d') % offset)
1669 raise Abort(_('impossible time zone offset: %d') % offset)
1654 return when, offset
1670 return when, offset
1655
1671
1656 def matchdate(date):
1672 def matchdate(date):
1657 """Return a function that matches a given date match specifier
1673 """Return a function that matches a given date match specifier
1658
1674
1659 Formats include:
1675 Formats include:
1660
1676
1661 '{date}' match a given date to the accuracy provided
1677 '{date}' match a given date to the accuracy provided
1662
1678
1663 '<{date}' on or before a given date
1679 '<{date}' on or before a given date
1664
1680
1665 '>{date}' on or after a given date
1681 '>{date}' on or after a given date
1666
1682
1667 """
1683 """
1668
1684
1669 def lower(date):
1685 def lower(date):
1670 d = dict(mb="1", d="1")
1686 d = dict(mb="1", d="1")
1671 return parsedate(date, extendeddateformats, d)[0]
1687 return parsedate(date, extendeddateformats, d)[0]
1672
1688
1673 def upper(date):
1689 def upper(date):
1674 d = dict(mb="12", HI="23", M="59", S="59")
1690 d = dict(mb="12", HI="23", M="59", S="59")
1675 for days in "31 30 29".split():
1691 for days in "31 30 29".split():
1676 try:
1692 try:
1677 d["d"] = days
1693 d["d"] = days
1678 return parsedate(date, extendeddateformats, d)[0]
1694 return parsedate(date, extendeddateformats, d)[0]
1679 except:
1695 except:
1680 pass
1696 pass
1681 d["d"] = "28"
1697 d["d"] = "28"
1682 return parsedate(date, extendeddateformats, d)[0]
1698 return parsedate(date, extendeddateformats, d)[0]
1683
1699
1684 if date[0] == "<":
1700 if date[0] == "<":
1685 when = upper(date[1:])
1701 when = upper(date[1:])
1686 return lambda x: x <= when
1702 return lambda x: x <= when
1687 elif date[0] == ">":
1703 elif date[0] == ">":
1688 when = lower(date[1:])
1704 when = lower(date[1:])
1689 return lambda x: x >= when
1705 return lambda x: x >= when
1690 elif date[0] == "-":
1706 elif date[0] == "-":
1691 try:
1707 try:
1692 days = int(date[1:])
1708 days = int(date[1:])
1693 except ValueError:
1709 except ValueError:
1694 raise Abort(_("invalid day spec: %s") % date[1:])
1710 raise Abort(_("invalid day spec: %s") % date[1:])
1695 when = makedate()[0] - days * 3600 * 24
1711 when = makedate()[0] - days * 3600 * 24
1696 return lambda x: x >= when
1712 return lambda x: x >= when
1697 elif " to " in date:
1713 elif " to " in date:
1698 a, b = date.split(" to ")
1714 a, b = date.split(" to ")
1699 start, stop = lower(a), upper(b)
1715 start, stop = lower(a), upper(b)
1700 return lambda x: x >= start and x <= stop
1716 return lambda x: x >= start and x <= stop
1701 else:
1717 else:
1702 start, stop = lower(date), upper(date)
1718 start, stop = lower(date), upper(date)
1703 return lambda x: x >= start and x <= stop
1719 return lambda x: x >= start and x <= stop
1704
1720
1705 def shortuser(user):
1721 def shortuser(user):
1706 """Return a short representation of a user name or email address."""
1722 """Return a short representation of a user name or email address."""
1707 f = user.find('@')
1723 f = user.find('@')
1708 if f >= 0:
1724 if f >= 0:
1709 user = user[:f]
1725 user = user[:f]
1710 f = user.find('<')
1726 f = user.find('<')
1711 if f >= 0:
1727 if f >= 0:
1712 user = user[f+1:]
1728 user = user[f+1:]
1713 f = user.find(' ')
1729 f = user.find(' ')
1714 if f >= 0:
1730 if f >= 0:
1715 user = user[:f]
1731 user = user[:f]
1716 f = user.find('.')
1732 f = user.find('.')
1717 if f >= 0:
1733 if f >= 0:
1718 user = user[:f]
1734 user = user[:f]
1719 return user
1735 return user
1720
1736
1721 def email(author):
1737 def email(author):
1722 '''get email of author.'''
1738 '''get email of author.'''
1723 r = author.find('>')
1739 r = author.find('>')
1724 if r == -1: r = None
1740 if r == -1: r = None
1725 return author[author.find('<')+1:r]
1741 return author[author.find('<')+1:r]
1726
1742
1727 def ellipsis(text, maxlength=400):
1743 def ellipsis(text, maxlength=400):
1728 """Trim string to at most maxlength (default: 400) characters."""
1744 """Trim string to at most maxlength (default: 400) characters."""
1729 if len(text) <= maxlength:
1745 if len(text) <= maxlength:
1730 return text
1746 return text
1731 else:
1747 else:
1732 return "%s..." % (text[:maxlength-3])
1748 return "%s..." % (text[:maxlength-3])
1733
1749
1734 def walkrepos(path, followsym=False, seen_dirs=None):
1750 def walkrepos(path, followsym=False, seen_dirs=None):
1735 '''yield every hg repository under path, recursively.'''
1751 '''yield every hg repository under path, recursively.'''
1736 def errhandler(err):
1752 def errhandler(err):
1737 if err.filename == path:
1753 if err.filename == path:
1738 raise err
1754 raise err
1739 if followsym and hasattr(os.path, 'samestat'):
1755 if followsym and hasattr(os.path, 'samestat'):
1740 def _add_dir_if_not_there(dirlst, dirname):
1756 def _add_dir_if_not_there(dirlst, dirname):
1741 match = False
1757 match = False
1742 samestat = os.path.samestat
1758 samestat = os.path.samestat
1743 dirstat = os.stat(dirname)
1759 dirstat = os.stat(dirname)
1744 for lstdirstat in dirlst:
1760 for lstdirstat in dirlst:
1745 if samestat(dirstat, lstdirstat):
1761 if samestat(dirstat, lstdirstat):
1746 match = True
1762 match = True
1747 break
1763 break
1748 if not match:
1764 if not match:
1749 dirlst.append(dirstat)
1765 dirlst.append(dirstat)
1750 return not match
1766 return not match
1751 else:
1767 else:
1752 followsym = False
1768 followsym = False
1753
1769
1754 if (seen_dirs is None) and followsym:
1770 if (seen_dirs is None) and followsym:
1755 seen_dirs = []
1771 seen_dirs = []
1756 _add_dir_if_not_there(seen_dirs, path)
1772 _add_dir_if_not_there(seen_dirs, path)
1757 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
1773 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
1758 if '.hg' in dirs:
1774 if '.hg' in dirs:
1759 dirs[:] = [] # don't descend further
1775 dirs[:] = [] # don't descend further
1760 yield root # found a repository
1776 yield root # found a repository
1761 qroot = os.path.join(root, '.hg', 'patches')
1777 qroot = os.path.join(root, '.hg', 'patches')
1762 if os.path.isdir(os.path.join(qroot, '.hg')):
1778 if os.path.isdir(os.path.join(qroot, '.hg')):
1763 yield qroot # we have a patch queue repo here
1779 yield qroot # we have a patch queue repo here
1764 elif followsym:
1780 elif followsym:
1765 newdirs = []
1781 newdirs = []
1766 for d in dirs:
1782 for d in dirs:
1767 fname = os.path.join(root, d)
1783 fname = os.path.join(root, d)
1768 if _add_dir_if_not_there(seen_dirs, fname):
1784 if _add_dir_if_not_there(seen_dirs, fname):
1769 if os.path.islink(fname):
1785 if os.path.islink(fname):
1770 for hgname in walkrepos(fname, True, seen_dirs):
1786 for hgname in walkrepos(fname, True, seen_dirs):
1771 yield hgname
1787 yield hgname
1772 else:
1788 else:
1773 newdirs.append(d)
1789 newdirs.append(d)
1774 dirs[:] = newdirs
1790 dirs[:] = newdirs
1775
1791
1776 _rcpath = None
1792 _rcpath = None
1777
1793
1778 def os_rcpath():
1794 def os_rcpath():
1779 '''return default os-specific hgrc search path'''
1795 '''return default os-specific hgrc search path'''
1780 path = system_rcpath()
1796 path = system_rcpath()
1781 path.extend(user_rcpath())
1797 path.extend(user_rcpath())
1782 path = [os.path.normpath(f) for f in path]
1798 path = [os.path.normpath(f) for f in path]
1783 return path
1799 return path
1784
1800
1785 def rcpath():
1801 def rcpath():
1786 '''return hgrc search path. if env var HGRCPATH is set, use it.
1802 '''return hgrc search path. if env var HGRCPATH is set, use it.
1787 for each item in path, if directory, use files ending in .rc,
1803 for each item in path, if directory, use files ending in .rc,
1788 else use item.
1804 else use item.
1789 make HGRCPATH empty to only look in .hg/hgrc of current repo.
1805 make HGRCPATH empty to only look in .hg/hgrc of current repo.
1790 if no HGRCPATH, use default os-specific path.'''
1806 if no HGRCPATH, use default os-specific path.'''
1791 global _rcpath
1807 global _rcpath
1792 if _rcpath is None:
1808 if _rcpath is None:
1793 if 'HGRCPATH' in os.environ:
1809 if 'HGRCPATH' in os.environ:
1794 _rcpath = []
1810 _rcpath = []
1795 for p in os.environ['HGRCPATH'].split(os.pathsep):
1811 for p in os.environ['HGRCPATH'].split(os.pathsep):
1796 if not p: continue
1812 if not p: continue
1797 if os.path.isdir(p):
1813 if os.path.isdir(p):
1798 for f, kind in osutil.listdir(p):
1814 for f, kind in osutil.listdir(p):
1799 if f.endswith('.rc'):
1815 if f.endswith('.rc'):
1800 _rcpath.append(os.path.join(p, f))
1816 _rcpath.append(os.path.join(p, f))
1801 else:
1817 else:
1802 _rcpath.append(p)
1818 _rcpath.append(p)
1803 else:
1819 else:
1804 _rcpath = os_rcpath()
1820 _rcpath = os_rcpath()
1805 return _rcpath
1821 return _rcpath
1806
1822
1807 def bytecount(nbytes):
1823 def bytecount(nbytes):
1808 '''return byte count formatted as readable string, with units'''
1824 '''return byte count formatted as readable string, with units'''
1809
1825
1810 units = (
1826 units = (
1811 (100, 1<<30, _('%.0f GB')),
1827 (100, 1<<30, _('%.0f GB')),
1812 (10, 1<<30, _('%.1f GB')),
1828 (10, 1<<30, _('%.1f GB')),
1813 (1, 1<<30, _('%.2f GB')),
1829 (1, 1<<30, _('%.2f GB')),
1814 (100, 1<<20, _('%.0f MB')),
1830 (100, 1<<20, _('%.0f MB')),
1815 (10, 1<<20, _('%.1f MB')),
1831 (10, 1<<20, _('%.1f MB')),
1816 (1, 1<<20, _('%.2f MB')),
1832 (1, 1<<20, _('%.2f MB')),
1817 (100, 1<<10, _('%.0f KB')),
1833 (100, 1<<10, _('%.0f KB')),
1818 (10, 1<<10, _('%.1f KB')),
1834 (10, 1<<10, _('%.1f KB')),
1819 (1, 1<<10, _('%.2f KB')),
1835 (1, 1<<10, _('%.2f KB')),
1820 (1, 1, _('%.0f bytes')),
1836 (1, 1, _('%.0f bytes')),
1821 )
1837 )
1822
1838
1823 for multiplier, divisor, format in units:
1839 for multiplier, divisor, format in units:
1824 if nbytes >= divisor * multiplier:
1840 if nbytes >= divisor * multiplier:
1825 return format % (nbytes / float(divisor))
1841 return format % (nbytes / float(divisor))
1826 return units[-1][2] % nbytes
1842 return units[-1][2] % nbytes
1827
1843
1828 def drop_scheme(scheme, path):
1844 def drop_scheme(scheme, path):
1829 sc = scheme + ':'
1845 sc = scheme + ':'
1830 if path.startswith(sc):
1846 if path.startswith(sc):
1831 path = path[len(sc):]
1847 path = path[len(sc):]
1832 if path.startswith('//'):
1848 if path.startswith('//'):
1833 path = path[2:]
1849 path = path[2:]
1834 return path
1850 return path
1835
1851
1836 def uirepr(s):
1852 def uirepr(s):
1837 # Avoid double backslash in Windows path repr()
1853 # Avoid double backslash in Windows path repr()
1838 return repr(s).replace('\\\\', '\\')
1854 return repr(s).replace('\\\\', '\\')
1839
1855
1840 def hidepassword(url):
1856 def hidepassword(url):
1841 '''hide user credential in a url string'''
1857 '''hide user credential in a url string'''
1842 scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
1858 scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
1843 netloc = re.sub('([^:]*):([^@]*)@(.*)', r'\1:***@\3', netloc)
1859 netloc = re.sub('([^:]*):([^@]*)@(.*)', r'\1:***@\3', netloc)
1844 return urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
1860 return urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
1845
1861
1846 def removeauth(url):
1862 def removeauth(url):
1847 '''remove all authentication information from a url string'''
1863 '''remove all authentication information from a url string'''
1848 scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
1864 scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
1849 netloc = netloc[netloc.find('@')+1:]
1865 netloc = netloc[netloc.find('@')+1:]
1850 return urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
1866 return urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
General Comments 0
You need to be logged in to leave comments. Login now