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