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