##// END OF EJS Templates
util: add a helper class to compute digests...
Mike Hommey -
r22962:4d58f408 default
parent child Browse files
Show More
@@ -1,2087 +1,2153
1 # util.py - Mercurial utility functions and platform specific implementations
1 # util.py - Mercurial utility functions and platform specific implementations
2 #
2 #
3 # Copyright 2005 K. Thananchayan <thananck@yahoo.com>
3 # Copyright 2005 K. Thananchayan <thananck@yahoo.com>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 """Mercurial utility functions and platform specific implementations.
10 """Mercurial utility functions and platform specific implementations.
11
11
12 This contains helper routines that are independent of the SCM core and
12 This contains helper routines that are independent of the SCM core and
13 hide platform-specific details from the core.
13 hide platform-specific details from the core.
14 """
14 """
15
15
16 import i18n
16 import i18n
17 _ = i18n._
17 _ = i18n._
18 import error, osutil, encoding
18 import error, osutil, encoding
19 import errno, shutil, sys, tempfile, traceback
19 import errno, shutil, sys, tempfile, traceback
20 import re as remod
20 import re as remod
21 import os, time, datetime, calendar, textwrap, signal, collections
21 import os, time, datetime, calendar, textwrap, signal, collections
22 import imp, socket, urllib
22 import imp, socket, urllib
23
23
24 if os.name == 'nt':
24 if os.name == 'nt':
25 import windows as platform
25 import windows as platform
26 else:
26 else:
27 import posix as platform
27 import posix as platform
28
28
29 cachestat = platform.cachestat
29 cachestat = platform.cachestat
30 checkexec = platform.checkexec
30 checkexec = platform.checkexec
31 checklink = platform.checklink
31 checklink = platform.checklink
32 copymode = platform.copymode
32 copymode = platform.copymode
33 executablepath = platform.executablepath
33 executablepath = platform.executablepath
34 expandglobs = platform.expandglobs
34 expandglobs = platform.expandglobs
35 explainexit = platform.explainexit
35 explainexit = platform.explainexit
36 findexe = platform.findexe
36 findexe = platform.findexe
37 gethgcmd = platform.gethgcmd
37 gethgcmd = platform.gethgcmd
38 getuser = platform.getuser
38 getuser = platform.getuser
39 groupmembers = platform.groupmembers
39 groupmembers = platform.groupmembers
40 groupname = platform.groupname
40 groupname = platform.groupname
41 hidewindow = platform.hidewindow
41 hidewindow = platform.hidewindow
42 isexec = platform.isexec
42 isexec = platform.isexec
43 isowner = platform.isowner
43 isowner = platform.isowner
44 localpath = platform.localpath
44 localpath = platform.localpath
45 lookupreg = platform.lookupreg
45 lookupreg = platform.lookupreg
46 makedir = platform.makedir
46 makedir = platform.makedir
47 nlinks = platform.nlinks
47 nlinks = platform.nlinks
48 normpath = platform.normpath
48 normpath = platform.normpath
49 normcase = platform.normcase
49 normcase = platform.normcase
50 openhardlinks = platform.openhardlinks
50 openhardlinks = platform.openhardlinks
51 oslink = platform.oslink
51 oslink = platform.oslink
52 parsepatchoutput = platform.parsepatchoutput
52 parsepatchoutput = platform.parsepatchoutput
53 pconvert = platform.pconvert
53 pconvert = platform.pconvert
54 popen = platform.popen
54 popen = platform.popen
55 posixfile = platform.posixfile
55 posixfile = platform.posixfile
56 quotecommand = platform.quotecommand
56 quotecommand = platform.quotecommand
57 readpipe = platform.readpipe
57 readpipe = platform.readpipe
58 rename = platform.rename
58 rename = platform.rename
59 samedevice = platform.samedevice
59 samedevice = platform.samedevice
60 samefile = platform.samefile
60 samefile = platform.samefile
61 samestat = platform.samestat
61 samestat = platform.samestat
62 setbinary = platform.setbinary
62 setbinary = platform.setbinary
63 setflags = platform.setflags
63 setflags = platform.setflags
64 setsignalhandler = platform.setsignalhandler
64 setsignalhandler = platform.setsignalhandler
65 shellquote = platform.shellquote
65 shellquote = platform.shellquote
66 spawndetached = platform.spawndetached
66 spawndetached = platform.spawndetached
67 split = platform.split
67 split = platform.split
68 sshargs = platform.sshargs
68 sshargs = platform.sshargs
69 statfiles = getattr(osutil, 'statfiles', platform.statfiles)
69 statfiles = getattr(osutil, 'statfiles', platform.statfiles)
70 statisexec = platform.statisexec
70 statisexec = platform.statisexec
71 statislink = platform.statislink
71 statislink = platform.statislink
72 termwidth = platform.termwidth
72 termwidth = platform.termwidth
73 testpid = platform.testpid
73 testpid = platform.testpid
74 umask = platform.umask
74 umask = platform.umask
75 unlink = platform.unlink
75 unlink = platform.unlink
76 unlinkpath = platform.unlinkpath
76 unlinkpath = platform.unlinkpath
77 username = platform.username
77 username = platform.username
78
78
79 # Python compatibility
79 # Python compatibility
80
80
81 _notset = object()
81 _notset = object()
82
82
83 def safehasattr(thing, attr):
83 def safehasattr(thing, attr):
84 return getattr(thing, attr, _notset) is not _notset
84 return getattr(thing, attr, _notset) is not _notset
85
85
86 def sha1(s=''):
86 def sha1(s=''):
87 '''
87 '''
88 Low-overhead wrapper around Python's SHA support
88 Low-overhead wrapper around Python's SHA support
89
89
90 >>> f = _fastsha1
90 >>> f = _fastsha1
91 >>> a = sha1()
91 >>> a = sha1()
92 >>> a = f()
92 >>> a = f()
93 >>> a.hexdigest()
93 >>> a.hexdigest()
94 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
94 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
95 '''
95 '''
96
96
97 return _fastsha1(s)
97 return _fastsha1(s)
98
98
99 def _fastsha1(s=''):
99 def _fastsha1(s=''):
100 # This function will import sha1 from hashlib or sha (whichever is
100 # This function will import sha1 from hashlib or sha (whichever is
101 # available) and overwrite itself with it on the first call.
101 # available) and overwrite itself with it on the first call.
102 # Subsequent calls will go directly to the imported function.
102 # Subsequent calls will go directly to the imported function.
103 if sys.version_info >= (2, 5):
103 if sys.version_info >= (2, 5):
104 from hashlib import sha1 as _sha1
104 from hashlib import sha1 as _sha1
105 else:
105 else:
106 from sha import sha as _sha1
106 from sha import sha as _sha1
107 global _fastsha1, sha1
107 global _fastsha1, sha1
108 _fastsha1 = sha1 = _sha1
108 _fastsha1 = sha1 = _sha1
109 return _sha1(s)
109 return _sha1(s)
110
110
111 def md5(s=''):
111 def md5(s=''):
112 try:
112 try:
113 from hashlib import md5 as _md5
113 from hashlib import md5 as _md5
114 except ImportError:
114 except ImportError:
115 from md5 import md5 as _md5
115 from md5 import md5 as _md5
116 global md5
116 global md5
117 md5 = _md5
117 md5 = _md5
118 return _md5(s)
118 return _md5(s)
119
119
120 DIGESTS = {
121 'md5': md5,
122 'sha1': sha1,
123 }
124 # List of digest types from strongest to weakest
125 DIGESTS_BY_STRENGTH = ['sha1', 'md5']
126
127 try:
128 import hashlib
129 DIGESTS.update({
130 'sha512': hashlib.sha512,
131 })
132 DIGESTS_BY_STRENGTH.insert(0, 'sha512')
133 except ImportError:
134 pass
135
136 for k in DIGESTS_BY_STRENGTH:
137 assert k in DIGESTS
138
139 class digester(object):
140 """helper to compute digests.
141
142 This helper can be used to compute one or more digests given their name.
143
144 >>> d = digester(['md5', 'sha1'])
145 >>> d.update('foo')
146 >>> [k for k in sorted(d)]
147 ['md5', 'sha1']
148 >>> d['md5']
149 'acbd18db4cc2f85cedef654fccc4a4d8'
150 >>> d['sha1']
151 '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33'
152 >>> digester.preferred(['md5', 'sha1'])
153 'sha1'
154 """
155
156 def __init__(self, digests, s=''):
157 self._hashes = {}
158 for k in digests:
159 if k not in DIGESTS:
160 raise Abort(_('unknown digest type: %s') % k)
161 self._hashes[k] = DIGESTS[k]()
162 if s:
163 self.update(s)
164
165 def update(self, data):
166 for h in self._hashes.values():
167 h.update(data)
168
169 def __getitem__(self, key):
170 if key not in DIGESTS:
171 raise Abort(_('unknown digest type: %s') % k)
172 return self._hashes[key].hexdigest()
173
174 def __iter__(self):
175 return iter(self._hashes)
176
177 @staticmethod
178 def preferred(supported):
179 """returns the strongest digest type in both supported and DIGESTS."""
180
181 for k in DIGESTS_BY_STRENGTH:
182 if k in supported:
183 return k
184 return None
185
120 try:
186 try:
121 buffer = buffer
187 buffer = buffer
122 except NameError:
188 except NameError:
123 if sys.version_info[0] < 3:
189 if sys.version_info[0] < 3:
124 def buffer(sliceable, offset=0):
190 def buffer(sliceable, offset=0):
125 return sliceable[offset:]
191 return sliceable[offset:]
126 else:
192 else:
127 def buffer(sliceable, offset=0):
193 def buffer(sliceable, offset=0):
128 return memoryview(sliceable)[offset:]
194 return memoryview(sliceable)[offset:]
129
195
130 import subprocess
196 import subprocess
131 closefds = os.name == 'posix'
197 closefds = os.name == 'posix'
132
198
133 def popen2(cmd, env=None, newlines=False):
199 def popen2(cmd, env=None, newlines=False):
134 # Setting bufsize to -1 lets the system decide the buffer size.
200 # Setting bufsize to -1 lets the system decide the buffer size.
135 # The default for bufsize is 0, meaning unbuffered. This leads to
201 # The default for bufsize is 0, meaning unbuffered. This leads to
136 # poor performance on Mac OS X: http://bugs.python.org/issue4194
202 # poor performance on Mac OS X: http://bugs.python.org/issue4194
137 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
203 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
138 close_fds=closefds,
204 close_fds=closefds,
139 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
205 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
140 universal_newlines=newlines,
206 universal_newlines=newlines,
141 env=env)
207 env=env)
142 return p.stdin, p.stdout
208 return p.stdin, p.stdout
143
209
144 def popen3(cmd, env=None, newlines=False):
210 def popen3(cmd, env=None, newlines=False):
145 stdin, stdout, stderr, p = popen4(cmd, env, newlines)
211 stdin, stdout, stderr, p = popen4(cmd, env, newlines)
146 return stdin, stdout, stderr
212 return stdin, stdout, stderr
147
213
148 def popen4(cmd, env=None, newlines=False):
214 def popen4(cmd, env=None, newlines=False):
149 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
215 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
150 close_fds=closefds,
216 close_fds=closefds,
151 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
217 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
152 stderr=subprocess.PIPE,
218 stderr=subprocess.PIPE,
153 universal_newlines=newlines,
219 universal_newlines=newlines,
154 env=env)
220 env=env)
155 return p.stdin, p.stdout, p.stderr, p
221 return p.stdin, p.stdout, p.stderr, p
156
222
157 def version():
223 def version():
158 """Return version information if available."""
224 """Return version information if available."""
159 try:
225 try:
160 import __version__
226 import __version__
161 return __version__.version
227 return __version__.version
162 except ImportError:
228 except ImportError:
163 return 'unknown'
229 return 'unknown'
164
230
165 # used by parsedate
231 # used by parsedate
166 defaultdateformats = (
232 defaultdateformats = (
167 '%Y-%m-%d %H:%M:%S',
233 '%Y-%m-%d %H:%M:%S',
168 '%Y-%m-%d %I:%M:%S%p',
234 '%Y-%m-%d %I:%M:%S%p',
169 '%Y-%m-%d %H:%M',
235 '%Y-%m-%d %H:%M',
170 '%Y-%m-%d %I:%M%p',
236 '%Y-%m-%d %I:%M%p',
171 '%Y-%m-%d',
237 '%Y-%m-%d',
172 '%m-%d',
238 '%m-%d',
173 '%m/%d',
239 '%m/%d',
174 '%m/%d/%y',
240 '%m/%d/%y',
175 '%m/%d/%Y',
241 '%m/%d/%Y',
176 '%a %b %d %H:%M:%S %Y',
242 '%a %b %d %H:%M:%S %Y',
177 '%a %b %d %I:%M:%S%p %Y',
243 '%a %b %d %I:%M:%S%p %Y',
178 '%a, %d %b %Y %H:%M:%S', # GNU coreutils "/bin/date --rfc-2822"
244 '%a, %d %b %Y %H:%M:%S', # GNU coreutils "/bin/date --rfc-2822"
179 '%b %d %H:%M:%S %Y',
245 '%b %d %H:%M:%S %Y',
180 '%b %d %I:%M:%S%p %Y',
246 '%b %d %I:%M:%S%p %Y',
181 '%b %d %H:%M:%S',
247 '%b %d %H:%M:%S',
182 '%b %d %I:%M:%S%p',
248 '%b %d %I:%M:%S%p',
183 '%b %d %H:%M',
249 '%b %d %H:%M',
184 '%b %d %I:%M%p',
250 '%b %d %I:%M%p',
185 '%b %d %Y',
251 '%b %d %Y',
186 '%b %d',
252 '%b %d',
187 '%H:%M:%S',
253 '%H:%M:%S',
188 '%I:%M:%S%p',
254 '%I:%M:%S%p',
189 '%H:%M',
255 '%H:%M',
190 '%I:%M%p',
256 '%I:%M%p',
191 )
257 )
192
258
193 extendeddateformats = defaultdateformats + (
259 extendeddateformats = defaultdateformats + (
194 "%Y",
260 "%Y",
195 "%Y-%m",
261 "%Y-%m",
196 "%b",
262 "%b",
197 "%b %Y",
263 "%b %Y",
198 )
264 )
199
265
200 def cachefunc(func):
266 def cachefunc(func):
201 '''cache the result of function calls'''
267 '''cache the result of function calls'''
202 # XXX doesn't handle keywords args
268 # XXX doesn't handle keywords args
203 if func.func_code.co_argcount == 0:
269 if func.func_code.co_argcount == 0:
204 cache = []
270 cache = []
205 def f():
271 def f():
206 if len(cache) == 0:
272 if len(cache) == 0:
207 cache.append(func())
273 cache.append(func())
208 return cache[0]
274 return cache[0]
209 return f
275 return f
210 cache = {}
276 cache = {}
211 if func.func_code.co_argcount == 1:
277 if func.func_code.co_argcount == 1:
212 # we gain a small amount of time because
278 # we gain a small amount of time because
213 # we don't need to pack/unpack the list
279 # we don't need to pack/unpack the list
214 def f(arg):
280 def f(arg):
215 if arg not in cache:
281 if arg not in cache:
216 cache[arg] = func(arg)
282 cache[arg] = func(arg)
217 return cache[arg]
283 return cache[arg]
218 else:
284 else:
219 def f(*args):
285 def f(*args):
220 if args not in cache:
286 if args not in cache:
221 cache[args] = func(*args)
287 cache[args] = func(*args)
222 return cache[args]
288 return cache[args]
223
289
224 return f
290 return f
225
291
226 try:
292 try:
227 collections.deque.remove
293 collections.deque.remove
228 deque = collections.deque
294 deque = collections.deque
229 except AttributeError:
295 except AttributeError:
230 # python 2.4 lacks deque.remove
296 # python 2.4 lacks deque.remove
231 class deque(collections.deque):
297 class deque(collections.deque):
232 def remove(self, val):
298 def remove(self, val):
233 for i, v in enumerate(self):
299 for i, v in enumerate(self):
234 if v == val:
300 if v == val:
235 del self[i]
301 del self[i]
236 break
302 break
237
303
238 class sortdict(dict):
304 class sortdict(dict):
239 '''a simple sorted dictionary'''
305 '''a simple sorted dictionary'''
240 def __init__(self, data=None):
306 def __init__(self, data=None):
241 self._list = []
307 self._list = []
242 if data:
308 if data:
243 self.update(data)
309 self.update(data)
244 def copy(self):
310 def copy(self):
245 return sortdict(self)
311 return sortdict(self)
246 def __setitem__(self, key, val):
312 def __setitem__(self, key, val):
247 if key in self:
313 if key in self:
248 self._list.remove(key)
314 self._list.remove(key)
249 self._list.append(key)
315 self._list.append(key)
250 dict.__setitem__(self, key, val)
316 dict.__setitem__(self, key, val)
251 def __iter__(self):
317 def __iter__(self):
252 return self._list.__iter__()
318 return self._list.__iter__()
253 def update(self, src):
319 def update(self, src):
254 for k in src:
320 for k in src:
255 self[k] = src[k]
321 self[k] = src[k]
256 def clear(self):
322 def clear(self):
257 dict.clear(self)
323 dict.clear(self)
258 self._list = []
324 self._list = []
259 def items(self):
325 def items(self):
260 return [(k, self[k]) for k in self._list]
326 return [(k, self[k]) for k in self._list]
261 def __delitem__(self, key):
327 def __delitem__(self, key):
262 dict.__delitem__(self, key)
328 dict.__delitem__(self, key)
263 self._list.remove(key)
329 self._list.remove(key)
264 def pop(self, key, *args, **kwargs):
330 def pop(self, key, *args, **kwargs):
265 dict.pop(self, key, *args, **kwargs)
331 dict.pop(self, key, *args, **kwargs)
266 try:
332 try:
267 self._list.remove(key)
333 self._list.remove(key)
268 except ValueError:
334 except ValueError:
269 pass
335 pass
270 def keys(self):
336 def keys(self):
271 return self._list
337 return self._list
272 def iterkeys(self):
338 def iterkeys(self):
273 return self._list.__iter__()
339 return self._list.__iter__()
274
340
275 class lrucachedict(object):
341 class lrucachedict(object):
276 '''cache most recent gets from or sets to this dictionary'''
342 '''cache most recent gets from or sets to this dictionary'''
277 def __init__(self, maxsize):
343 def __init__(self, maxsize):
278 self._cache = {}
344 self._cache = {}
279 self._maxsize = maxsize
345 self._maxsize = maxsize
280 self._order = deque()
346 self._order = deque()
281
347
282 def __getitem__(self, key):
348 def __getitem__(self, key):
283 value = self._cache[key]
349 value = self._cache[key]
284 self._order.remove(key)
350 self._order.remove(key)
285 self._order.append(key)
351 self._order.append(key)
286 return value
352 return value
287
353
288 def __setitem__(self, key, value):
354 def __setitem__(self, key, value):
289 if key not in self._cache:
355 if key not in self._cache:
290 if len(self._cache) >= self._maxsize:
356 if len(self._cache) >= self._maxsize:
291 del self._cache[self._order.popleft()]
357 del self._cache[self._order.popleft()]
292 else:
358 else:
293 self._order.remove(key)
359 self._order.remove(key)
294 self._cache[key] = value
360 self._cache[key] = value
295 self._order.append(key)
361 self._order.append(key)
296
362
297 def __contains__(self, key):
363 def __contains__(self, key):
298 return key in self._cache
364 return key in self._cache
299
365
300 def clear(self):
366 def clear(self):
301 self._cache.clear()
367 self._cache.clear()
302 self._order = deque()
368 self._order = deque()
303
369
304 def lrucachefunc(func):
370 def lrucachefunc(func):
305 '''cache most recent results of function calls'''
371 '''cache most recent results of function calls'''
306 cache = {}
372 cache = {}
307 order = deque()
373 order = deque()
308 if func.func_code.co_argcount == 1:
374 if func.func_code.co_argcount == 1:
309 def f(arg):
375 def f(arg):
310 if arg not in cache:
376 if arg not in cache:
311 if len(cache) > 20:
377 if len(cache) > 20:
312 del cache[order.popleft()]
378 del cache[order.popleft()]
313 cache[arg] = func(arg)
379 cache[arg] = func(arg)
314 else:
380 else:
315 order.remove(arg)
381 order.remove(arg)
316 order.append(arg)
382 order.append(arg)
317 return cache[arg]
383 return cache[arg]
318 else:
384 else:
319 def f(*args):
385 def f(*args):
320 if args not in cache:
386 if args not in cache:
321 if len(cache) > 20:
387 if len(cache) > 20:
322 del cache[order.popleft()]
388 del cache[order.popleft()]
323 cache[args] = func(*args)
389 cache[args] = func(*args)
324 else:
390 else:
325 order.remove(args)
391 order.remove(args)
326 order.append(args)
392 order.append(args)
327 return cache[args]
393 return cache[args]
328
394
329 return f
395 return f
330
396
331 class propertycache(object):
397 class propertycache(object):
332 def __init__(self, func):
398 def __init__(self, func):
333 self.func = func
399 self.func = func
334 self.name = func.__name__
400 self.name = func.__name__
335 def __get__(self, obj, type=None):
401 def __get__(self, obj, type=None):
336 result = self.func(obj)
402 result = self.func(obj)
337 self.cachevalue(obj, result)
403 self.cachevalue(obj, result)
338 return result
404 return result
339
405
340 def cachevalue(self, obj, value):
406 def cachevalue(self, obj, value):
341 # __dict__ assignment required to bypass __setattr__ (eg: repoview)
407 # __dict__ assignment required to bypass __setattr__ (eg: repoview)
342 obj.__dict__[self.name] = value
408 obj.__dict__[self.name] = value
343
409
344 def pipefilter(s, cmd):
410 def pipefilter(s, cmd):
345 '''filter string S through command CMD, returning its output'''
411 '''filter string S through command CMD, returning its output'''
346 p = subprocess.Popen(cmd, shell=True, close_fds=closefds,
412 p = subprocess.Popen(cmd, shell=True, close_fds=closefds,
347 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
413 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
348 pout, perr = p.communicate(s)
414 pout, perr = p.communicate(s)
349 return pout
415 return pout
350
416
351 def tempfilter(s, cmd):
417 def tempfilter(s, cmd):
352 '''filter string S through a pair of temporary files with CMD.
418 '''filter string S through a pair of temporary files with CMD.
353 CMD is used as a template to create the real command to be run,
419 CMD is used as a template to create the real command to be run,
354 with the strings INFILE and OUTFILE replaced by the real names of
420 with the strings INFILE and OUTFILE replaced by the real names of
355 the temporary files generated.'''
421 the temporary files generated.'''
356 inname, outname = None, None
422 inname, outname = None, None
357 try:
423 try:
358 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
424 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
359 fp = os.fdopen(infd, 'wb')
425 fp = os.fdopen(infd, 'wb')
360 fp.write(s)
426 fp.write(s)
361 fp.close()
427 fp.close()
362 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
428 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
363 os.close(outfd)
429 os.close(outfd)
364 cmd = cmd.replace('INFILE', inname)
430 cmd = cmd.replace('INFILE', inname)
365 cmd = cmd.replace('OUTFILE', outname)
431 cmd = cmd.replace('OUTFILE', outname)
366 code = os.system(cmd)
432 code = os.system(cmd)
367 if sys.platform == 'OpenVMS' and code & 1:
433 if sys.platform == 'OpenVMS' and code & 1:
368 code = 0
434 code = 0
369 if code:
435 if code:
370 raise Abort(_("command '%s' failed: %s") %
436 raise Abort(_("command '%s' failed: %s") %
371 (cmd, explainexit(code)))
437 (cmd, explainexit(code)))
372 fp = open(outname, 'rb')
438 fp = open(outname, 'rb')
373 r = fp.read()
439 r = fp.read()
374 fp.close()
440 fp.close()
375 return r
441 return r
376 finally:
442 finally:
377 try:
443 try:
378 if inname:
444 if inname:
379 os.unlink(inname)
445 os.unlink(inname)
380 except OSError:
446 except OSError:
381 pass
447 pass
382 try:
448 try:
383 if outname:
449 if outname:
384 os.unlink(outname)
450 os.unlink(outname)
385 except OSError:
451 except OSError:
386 pass
452 pass
387
453
388 filtertable = {
454 filtertable = {
389 'tempfile:': tempfilter,
455 'tempfile:': tempfilter,
390 'pipe:': pipefilter,
456 'pipe:': pipefilter,
391 }
457 }
392
458
393 def filter(s, cmd):
459 def filter(s, cmd):
394 "filter a string through a command that transforms its input to its output"
460 "filter a string through a command that transforms its input to its output"
395 for name, fn in filtertable.iteritems():
461 for name, fn in filtertable.iteritems():
396 if cmd.startswith(name):
462 if cmd.startswith(name):
397 return fn(s, cmd[len(name):].lstrip())
463 return fn(s, cmd[len(name):].lstrip())
398 return pipefilter(s, cmd)
464 return pipefilter(s, cmd)
399
465
400 def binary(s):
466 def binary(s):
401 """return true if a string is binary data"""
467 """return true if a string is binary data"""
402 return bool(s and '\0' in s)
468 return bool(s and '\0' in s)
403
469
404 def increasingchunks(source, min=1024, max=65536):
470 def increasingchunks(source, min=1024, max=65536):
405 '''return no less than min bytes per chunk while data remains,
471 '''return no less than min bytes per chunk while data remains,
406 doubling min after each chunk until it reaches max'''
472 doubling min after each chunk until it reaches max'''
407 def log2(x):
473 def log2(x):
408 if not x:
474 if not x:
409 return 0
475 return 0
410 i = 0
476 i = 0
411 while x:
477 while x:
412 x >>= 1
478 x >>= 1
413 i += 1
479 i += 1
414 return i - 1
480 return i - 1
415
481
416 buf = []
482 buf = []
417 blen = 0
483 blen = 0
418 for chunk in source:
484 for chunk in source:
419 buf.append(chunk)
485 buf.append(chunk)
420 blen += len(chunk)
486 blen += len(chunk)
421 if blen >= min:
487 if blen >= min:
422 if min < max:
488 if min < max:
423 min = min << 1
489 min = min << 1
424 nmin = 1 << log2(blen)
490 nmin = 1 << log2(blen)
425 if nmin > min:
491 if nmin > min:
426 min = nmin
492 min = nmin
427 if min > max:
493 if min > max:
428 min = max
494 min = max
429 yield ''.join(buf)
495 yield ''.join(buf)
430 blen = 0
496 blen = 0
431 buf = []
497 buf = []
432 if buf:
498 if buf:
433 yield ''.join(buf)
499 yield ''.join(buf)
434
500
435 Abort = error.Abort
501 Abort = error.Abort
436
502
437 def always(fn):
503 def always(fn):
438 return True
504 return True
439
505
440 def never(fn):
506 def never(fn):
441 return False
507 return False
442
508
443 def pathto(root, n1, n2):
509 def pathto(root, n1, n2):
444 '''return the relative path from one place to another.
510 '''return the relative path from one place to another.
445 root should use os.sep to separate directories
511 root should use os.sep to separate directories
446 n1 should use os.sep to separate directories
512 n1 should use os.sep to separate directories
447 n2 should use "/" to separate directories
513 n2 should use "/" to separate directories
448 returns an os.sep-separated path.
514 returns an os.sep-separated path.
449
515
450 If n1 is a relative path, it's assumed it's
516 If n1 is a relative path, it's assumed it's
451 relative to root.
517 relative to root.
452 n2 should always be relative to root.
518 n2 should always be relative to root.
453 '''
519 '''
454 if not n1:
520 if not n1:
455 return localpath(n2)
521 return localpath(n2)
456 if os.path.isabs(n1):
522 if os.path.isabs(n1):
457 if os.path.splitdrive(root)[0] != os.path.splitdrive(n1)[0]:
523 if os.path.splitdrive(root)[0] != os.path.splitdrive(n1)[0]:
458 return os.path.join(root, localpath(n2))
524 return os.path.join(root, localpath(n2))
459 n2 = '/'.join((pconvert(root), n2))
525 n2 = '/'.join((pconvert(root), n2))
460 a, b = splitpath(n1), n2.split('/')
526 a, b = splitpath(n1), n2.split('/')
461 a.reverse()
527 a.reverse()
462 b.reverse()
528 b.reverse()
463 while a and b and a[-1] == b[-1]:
529 while a and b and a[-1] == b[-1]:
464 a.pop()
530 a.pop()
465 b.pop()
531 b.pop()
466 b.reverse()
532 b.reverse()
467 return os.sep.join((['..'] * len(a)) + b) or '.'
533 return os.sep.join((['..'] * len(a)) + b) or '.'
468
534
469 def mainfrozen():
535 def mainfrozen():
470 """return True if we are a frozen executable.
536 """return True if we are a frozen executable.
471
537
472 The code supports py2exe (most common, Windows only) and tools/freeze
538 The code supports py2exe (most common, Windows only) and tools/freeze
473 (portable, not much used).
539 (portable, not much used).
474 """
540 """
475 return (safehasattr(sys, "frozen") or # new py2exe
541 return (safehasattr(sys, "frozen") or # new py2exe
476 safehasattr(sys, "importers") or # old py2exe
542 safehasattr(sys, "importers") or # old py2exe
477 imp.is_frozen("__main__")) # tools/freeze
543 imp.is_frozen("__main__")) # tools/freeze
478
544
479 # the location of data files matching the source code
545 # the location of data files matching the source code
480 if mainfrozen():
546 if mainfrozen():
481 # executable version (py2exe) doesn't support __file__
547 # executable version (py2exe) doesn't support __file__
482 datapath = os.path.dirname(sys.executable)
548 datapath = os.path.dirname(sys.executable)
483 else:
549 else:
484 datapath = os.path.dirname(__file__)
550 datapath = os.path.dirname(__file__)
485
551
486 i18n.setdatapath(datapath)
552 i18n.setdatapath(datapath)
487
553
488 _hgexecutable = None
554 _hgexecutable = None
489
555
490 def hgexecutable():
556 def hgexecutable():
491 """return location of the 'hg' executable.
557 """return location of the 'hg' executable.
492
558
493 Defaults to $HG or 'hg' in the search path.
559 Defaults to $HG or 'hg' in the search path.
494 """
560 """
495 if _hgexecutable is None:
561 if _hgexecutable is None:
496 hg = os.environ.get('HG')
562 hg = os.environ.get('HG')
497 mainmod = sys.modules['__main__']
563 mainmod = sys.modules['__main__']
498 if hg:
564 if hg:
499 _sethgexecutable(hg)
565 _sethgexecutable(hg)
500 elif mainfrozen():
566 elif mainfrozen():
501 _sethgexecutable(sys.executable)
567 _sethgexecutable(sys.executable)
502 elif os.path.basename(getattr(mainmod, '__file__', '')) == 'hg':
568 elif os.path.basename(getattr(mainmod, '__file__', '')) == 'hg':
503 _sethgexecutable(mainmod.__file__)
569 _sethgexecutable(mainmod.__file__)
504 else:
570 else:
505 exe = findexe('hg') or os.path.basename(sys.argv[0])
571 exe = findexe('hg') or os.path.basename(sys.argv[0])
506 _sethgexecutable(exe)
572 _sethgexecutable(exe)
507 return _hgexecutable
573 return _hgexecutable
508
574
509 def _sethgexecutable(path):
575 def _sethgexecutable(path):
510 """set location of the 'hg' executable"""
576 """set location of the 'hg' executable"""
511 global _hgexecutable
577 global _hgexecutable
512 _hgexecutable = path
578 _hgexecutable = path
513
579
514 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None, out=None):
580 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None, out=None):
515 '''enhanced shell command execution.
581 '''enhanced shell command execution.
516 run with environment maybe modified, maybe in different dir.
582 run with environment maybe modified, maybe in different dir.
517
583
518 if command fails and onerr is None, return status. if ui object,
584 if command fails and onerr is None, return status. if ui object,
519 print error message and return status, else raise onerr object as
585 print error message and return status, else raise onerr object as
520 exception.
586 exception.
521
587
522 if out is specified, it is assumed to be a file-like object that has a
588 if out is specified, it is assumed to be a file-like object that has a
523 write() method. stdout and stderr will be redirected to out.'''
589 write() method. stdout and stderr will be redirected to out.'''
524 try:
590 try:
525 sys.stdout.flush()
591 sys.stdout.flush()
526 except Exception:
592 except Exception:
527 pass
593 pass
528 def py2shell(val):
594 def py2shell(val):
529 'convert python object into string that is useful to shell'
595 'convert python object into string that is useful to shell'
530 if val is None or val is False:
596 if val is None or val is False:
531 return '0'
597 return '0'
532 if val is True:
598 if val is True:
533 return '1'
599 return '1'
534 return str(val)
600 return str(val)
535 origcmd = cmd
601 origcmd = cmd
536 cmd = quotecommand(cmd)
602 cmd = quotecommand(cmd)
537 if sys.platform == 'plan9' and (sys.version_info[0] == 2
603 if sys.platform == 'plan9' and (sys.version_info[0] == 2
538 and sys.version_info[1] < 7):
604 and sys.version_info[1] < 7):
539 # subprocess kludge to work around issues in half-baked Python
605 # subprocess kludge to work around issues in half-baked Python
540 # ports, notably bichued/python:
606 # ports, notably bichued/python:
541 if not cwd is None:
607 if not cwd is None:
542 os.chdir(cwd)
608 os.chdir(cwd)
543 rc = os.system(cmd)
609 rc = os.system(cmd)
544 else:
610 else:
545 env = dict(os.environ)
611 env = dict(os.environ)
546 env.update((k, py2shell(v)) for k, v in environ.iteritems())
612 env.update((k, py2shell(v)) for k, v in environ.iteritems())
547 env['HG'] = hgexecutable()
613 env['HG'] = hgexecutable()
548 if out is None or out == sys.__stdout__:
614 if out is None or out == sys.__stdout__:
549 rc = subprocess.call(cmd, shell=True, close_fds=closefds,
615 rc = subprocess.call(cmd, shell=True, close_fds=closefds,
550 env=env, cwd=cwd)
616 env=env, cwd=cwd)
551 else:
617 else:
552 proc = subprocess.Popen(cmd, shell=True, close_fds=closefds,
618 proc = subprocess.Popen(cmd, shell=True, close_fds=closefds,
553 env=env, cwd=cwd, stdout=subprocess.PIPE,
619 env=env, cwd=cwd, stdout=subprocess.PIPE,
554 stderr=subprocess.STDOUT)
620 stderr=subprocess.STDOUT)
555 for line in proc.stdout:
621 for line in proc.stdout:
556 out.write(line)
622 out.write(line)
557 proc.wait()
623 proc.wait()
558 rc = proc.returncode
624 rc = proc.returncode
559 if sys.platform == 'OpenVMS' and rc & 1:
625 if sys.platform == 'OpenVMS' and rc & 1:
560 rc = 0
626 rc = 0
561 if rc and onerr:
627 if rc and onerr:
562 errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
628 errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
563 explainexit(rc)[0])
629 explainexit(rc)[0])
564 if errprefix:
630 if errprefix:
565 errmsg = '%s: %s' % (errprefix, errmsg)
631 errmsg = '%s: %s' % (errprefix, errmsg)
566 try:
632 try:
567 onerr.warn(errmsg + '\n')
633 onerr.warn(errmsg + '\n')
568 except AttributeError:
634 except AttributeError:
569 raise onerr(errmsg)
635 raise onerr(errmsg)
570 return rc
636 return rc
571
637
572 def checksignature(func):
638 def checksignature(func):
573 '''wrap a function with code to check for calling errors'''
639 '''wrap a function with code to check for calling errors'''
574 def check(*args, **kwargs):
640 def check(*args, **kwargs):
575 try:
641 try:
576 return func(*args, **kwargs)
642 return func(*args, **kwargs)
577 except TypeError:
643 except TypeError:
578 if len(traceback.extract_tb(sys.exc_info()[2])) == 1:
644 if len(traceback.extract_tb(sys.exc_info()[2])) == 1:
579 raise error.SignatureError
645 raise error.SignatureError
580 raise
646 raise
581
647
582 return check
648 return check
583
649
584 def copyfile(src, dest):
650 def copyfile(src, dest):
585 "copy a file, preserving mode and atime/mtime"
651 "copy a file, preserving mode and atime/mtime"
586 if os.path.lexists(dest):
652 if os.path.lexists(dest):
587 unlink(dest)
653 unlink(dest)
588 if os.path.islink(src):
654 if os.path.islink(src):
589 os.symlink(os.readlink(src), dest)
655 os.symlink(os.readlink(src), dest)
590 else:
656 else:
591 try:
657 try:
592 shutil.copyfile(src, dest)
658 shutil.copyfile(src, dest)
593 shutil.copymode(src, dest)
659 shutil.copymode(src, dest)
594 except shutil.Error, inst:
660 except shutil.Error, inst:
595 raise Abort(str(inst))
661 raise Abort(str(inst))
596
662
597 def copyfiles(src, dst, hardlink=None):
663 def copyfiles(src, dst, hardlink=None):
598 """Copy a directory tree using hardlinks if possible"""
664 """Copy a directory tree using hardlinks if possible"""
599
665
600 if hardlink is None:
666 if hardlink is None:
601 hardlink = (os.stat(src).st_dev ==
667 hardlink = (os.stat(src).st_dev ==
602 os.stat(os.path.dirname(dst)).st_dev)
668 os.stat(os.path.dirname(dst)).st_dev)
603
669
604 num = 0
670 num = 0
605 if os.path.isdir(src):
671 if os.path.isdir(src):
606 os.mkdir(dst)
672 os.mkdir(dst)
607 for name, kind in osutil.listdir(src):
673 for name, kind in osutil.listdir(src):
608 srcname = os.path.join(src, name)
674 srcname = os.path.join(src, name)
609 dstname = os.path.join(dst, name)
675 dstname = os.path.join(dst, name)
610 hardlink, n = copyfiles(srcname, dstname, hardlink)
676 hardlink, n = copyfiles(srcname, dstname, hardlink)
611 num += n
677 num += n
612 else:
678 else:
613 if hardlink:
679 if hardlink:
614 try:
680 try:
615 oslink(src, dst)
681 oslink(src, dst)
616 except (IOError, OSError):
682 except (IOError, OSError):
617 hardlink = False
683 hardlink = False
618 shutil.copy(src, dst)
684 shutil.copy(src, dst)
619 else:
685 else:
620 shutil.copy(src, dst)
686 shutil.copy(src, dst)
621 num += 1
687 num += 1
622
688
623 return hardlink, num
689 return hardlink, num
624
690
625 _winreservednames = '''con prn aux nul
691 _winreservednames = '''con prn aux nul
626 com1 com2 com3 com4 com5 com6 com7 com8 com9
692 com1 com2 com3 com4 com5 com6 com7 com8 com9
627 lpt1 lpt2 lpt3 lpt4 lpt5 lpt6 lpt7 lpt8 lpt9'''.split()
693 lpt1 lpt2 lpt3 lpt4 lpt5 lpt6 lpt7 lpt8 lpt9'''.split()
628 _winreservedchars = ':*?"<>|'
694 _winreservedchars = ':*?"<>|'
629 def checkwinfilename(path):
695 def checkwinfilename(path):
630 r'''Check that the base-relative path is a valid filename on Windows.
696 r'''Check that the base-relative path is a valid filename on Windows.
631 Returns None if the path is ok, or a UI string describing the problem.
697 Returns None if the path is ok, or a UI string describing the problem.
632
698
633 >>> checkwinfilename("just/a/normal/path")
699 >>> checkwinfilename("just/a/normal/path")
634 >>> checkwinfilename("foo/bar/con.xml")
700 >>> checkwinfilename("foo/bar/con.xml")
635 "filename contains 'con', which is reserved on Windows"
701 "filename contains 'con', which is reserved on Windows"
636 >>> checkwinfilename("foo/con.xml/bar")
702 >>> checkwinfilename("foo/con.xml/bar")
637 "filename contains 'con', which is reserved on Windows"
703 "filename contains 'con', which is reserved on Windows"
638 >>> checkwinfilename("foo/bar/xml.con")
704 >>> checkwinfilename("foo/bar/xml.con")
639 >>> checkwinfilename("foo/bar/AUX/bla.txt")
705 >>> checkwinfilename("foo/bar/AUX/bla.txt")
640 "filename contains 'AUX', which is reserved on Windows"
706 "filename contains 'AUX', which is reserved on Windows"
641 >>> checkwinfilename("foo/bar/bla:.txt")
707 >>> checkwinfilename("foo/bar/bla:.txt")
642 "filename contains ':', which is reserved on Windows"
708 "filename contains ':', which is reserved on Windows"
643 >>> checkwinfilename("foo/bar/b\07la.txt")
709 >>> checkwinfilename("foo/bar/b\07la.txt")
644 "filename contains '\\x07', which is invalid on Windows"
710 "filename contains '\\x07', which is invalid on Windows"
645 >>> checkwinfilename("foo/bar/bla ")
711 >>> checkwinfilename("foo/bar/bla ")
646 "filename ends with ' ', which is not allowed on Windows"
712 "filename ends with ' ', which is not allowed on Windows"
647 >>> checkwinfilename("../bar")
713 >>> checkwinfilename("../bar")
648 >>> checkwinfilename("foo\\")
714 >>> checkwinfilename("foo\\")
649 "filename ends with '\\', which is invalid on Windows"
715 "filename ends with '\\', which is invalid on Windows"
650 >>> checkwinfilename("foo\\/bar")
716 >>> checkwinfilename("foo\\/bar")
651 "directory name ends with '\\', which is invalid on Windows"
717 "directory name ends with '\\', which is invalid on Windows"
652 '''
718 '''
653 if path.endswith('\\'):
719 if path.endswith('\\'):
654 return _("filename ends with '\\', which is invalid on Windows")
720 return _("filename ends with '\\', which is invalid on Windows")
655 if '\\/' in path:
721 if '\\/' in path:
656 return _("directory name ends with '\\', which is invalid on Windows")
722 return _("directory name ends with '\\', which is invalid on Windows")
657 for n in path.replace('\\', '/').split('/'):
723 for n in path.replace('\\', '/').split('/'):
658 if not n:
724 if not n:
659 continue
725 continue
660 for c in n:
726 for c in n:
661 if c in _winreservedchars:
727 if c in _winreservedchars:
662 return _("filename contains '%s', which is reserved "
728 return _("filename contains '%s', which is reserved "
663 "on Windows") % c
729 "on Windows") % c
664 if ord(c) <= 31:
730 if ord(c) <= 31:
665 return _("filename contains %r, which is invalid "
731 return _("filename contains %r, which is invalid "
666 "on Windows") % c
732 "on Windows") % c
667 base = n.split('.')[0]
733 base = n.split('.')[0]
668 if base and base.lower() in _winreservednames:
734 if base and base.lower() in _winreservednames:
669 return _("filename contains '%s', which is reserved "
735 return _("filename contains '%s', which is reserved "
670 "on Windows") % base
736 "on Windows") % base
671 t = n[-1]
737 t = n[-1]
672 if t in '. ' and n not in '..':
738 if t in '. ' and n not in '..':
673 return _("filename ends with '%s', which is not allowed "
739 return _("filename ends with '%s', which is not allowed "
674 "on Windows") % t
740 "on Windows") % t
675
741
676 if os.name == 'nt':
742 if os.name == 'nt':
677 checkosfilename = checkwinfilename
743 checkosfilename = checkwinfilename
678 else:
744 else:
679 checkosfilename = platform.checkosfilename
745 checkosfilename = platform.checkosfilename
680
746
681 def makelock(info, pathname):
747 def makelock(info, pathname):
682 try:
748 try:
683 return os.symlink(info, pathname)
749 return os.symlink(info, pathname)
684 except OSError, why:
750 except OSError, why:
685 if why.errno == errno.EEXIST:
751 if why.errno == errno.EEXIST:
686 raise
752 raise
687 except AttributeError: # no symlink in os
753 except AttributeError: # no symlink in os
688 pass
754 pass
689
755
690 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
756 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
691 os.write(ld, info)
757 os.write(ld, info)
692 os.close(ld)
758 os.close(ld)
693
759
694 def readlock(pathname):
760 def readlock(pathname):
695 try:
761 try:
696 return os.readlink(pathname)
762 return os.readlink(pathname)
697 except OSError, why:
763 except OSError, why:
698 if why.errno not in (errno.EINVAL, errno.ENOSYS):
764 if why.errno not in (errno.EINVAL, errno.ENOSYS):
699 raise
765 raise
700 except AttributeError: # no symlink in os
766 except AttributeError: # no symlink in os
701 pass
767 pass
702 fp = posixfile(pathname)
768 fp = posixfile(pathname)
703 r = fp.read()
769 r = fp.read()
704 fp.close()
770 fp.close()
705 return r
771 return r
706
772
707 def fstat(fp):
773 def fstat(fp):
708 '''stat file object that may not have fileno method.'''
774 '''stat file object that may not have fileno method.'''
709 try:
775 try:
710 return os.fstat(fp.fileno())
776 return os.fstat(fp.fileno())
711 except AttributeError:
777 except AttributeError:
712 return os.stat(fp.name)
778 return os.stat(fp.name)
713
779
714 # File system features
780 # File system features
715
781
716 def checkcase(path):
782 def checkcase(path):
717 """
783 """
718 Return true if the given path is on a case-sensitive filesystem
784 Return true if the given path is on a case-sensitive filesystem
719
785
720 Requires a path (like /foo/.hg) ending with a foldable final
786 Requires a path (like /foo/.hg) ending with a foldable final
721 directory component.
787 directory component.
722 """
788 """
723 s1 = os.stat(path)
789 s1 = os.stat(path)
724 d, b = os.path.split(path)
790 d, b = os.path.split(path)
725 b2 = b.upper()
791 b2 = b.upper()
726 if b == b2:
792 if b == b2:
727 b2 = b.lower()
793 b2 = b.lower()
728 if b == b2:
794 if b == b2:
729 return True # no evidence against case sensitivity
795 return True # no evidence against case sensitivity
730 p2 = os.path.join(d, b2)
796 p2 = os.path.join(d, b2)
731 try:
797 try:
732 s2 = os.stat(p2)
798 s2 = os.stat(p2)
733 if s2 == s1:
799 if s2 == s1:
734 return False
800 return False
735 return True
801 return True
736 except OSError:
802 except OSError:
737 return True
803 return True
738
804
739 try:
805 try:
740 import re2
806 import re2
741 _re2 = None
807 _re2 = None
742 except ImportError:
808 except ImportError:
743 _re2 = False
809 _re2 = False
744
810
745 class _re(object):
811 class _re(object):
746 def _checkre2(self):
812 def _checkre2(self):
747 global _re2
813 global _re2
748 try:
814 try:
749 # check if match works, see issue3964
815 # check if match works, see issue3964
750 _re2 = bool(re2.match(r'\[([^\[]+)\]', '[ui]'))
816 _re2 = bool(re2.match(r'\[([^\[]+)\]', '[ui]'))
751 except ImportError:
817 except ImportError:
752 _re2 = False
818 _re2 = False
753
819
754 def compile(self, pat, flags=0):
820 def compile(self, pat, flags=0):
755 '''Compile a regular expression, using re2 if possible
821 '''Compile a regular expression, using re2 if possible
756
822
757 For best performance, use only re2-compatible regexp features. The
823 For best performance, use only re2-compatible regexp features. The
758 only flags from the re module that are re2-compatible are
824 only flags from the re module that are re2-compatible are
759 IGNORECASE and MULTILINE.'''
825 IGNORECASE and MULTILINE.'''
760 if _re2 is None:
826 if _re2 is None:
761 self._checkre2()
827 self._checkre2()
762 if _re2 and (flags & ~(remod.IGNORECASE | remod.MULTILINE)) == 0:
828 if _re2 and (flags & ~(remod.IGNORECASE | remod.MULTILINE)) == 0:
763 if flags & remod.IGNORECASE:
829 if flags & remod.IGNORECASE:
764 pat = '(?i)' + pat
830 pat = '(?i)' + pat
765 if flags & remod.MULTILINE:
831 if flags & remod.MULTILINE:
766 pat = '(?m)' + pat
832 pat = '(?m)' + pat
767 try:
833 try:
768 return re2.compile(pat)
834 return re2.compile(pat)
769 except re2.error:
835 except re2.error:
770 pass
836 pass
771 return remod.compile(pat, flags)
837 return remod.compile(pat, flags)
772
838
773 @propertycache
839 @propertycache
774 def escape(self):
840 def escape(self):
775 '''Return the version of escape corresponding to self.compile.
841 '''Return the version of escape corresponding to self.compile.
776
842
777 This is imperfect because whether re2 or re is used for a particular
843 This is imperfect because whether re2 or re is used for a particular
778 function depends on the flags, etc, but it's the best we can do.
844 function depends on the flags, etc, but it's the best we can do.
779 '''
845 '''
780 global _re2
846 global _re2
781 if _re2 is None:
847 if _re2 is None:
782 self._checkre2()
848 self._checkre2()
783 if _re2:
849 if _re2:
784 return re2.escape
850 return re2.escape
785 else:
851 else:
786 return remod.escape
852 return remod.escape
787
853
788 re = _re()
854 re = _re()
789
855
790 _fspathcache = {}
856 _fspathcache = {}
791 def fspath(name, root):
857 def fspath(name, root):
792 '''Get name in the case stored in the filesystem
858 '''Get name in the case stored in the filesystem
793
859
794 The name should be relative to root, and be normcase-ed for efficiency.
860 The name should be relative to root, and be normcase-ed for efficiency.
795
861
796 Note that this function is unnecessary, and should not be
862 Note that this function is unnecessary, and should not be
797 called, for case-sensitive filesystems (simply because it's expensive).
863 called, for case-sensitive filesystems (simply because it's expensive).
798
864
799 The root should be normcase-ed, too.
865 The root should be normcase-ed, too.
800 '''
866 '''
801 def find(p, contents):
867 def find(p, contents):
802 for n in contents:
868 for n in contents:
803 if normcase(n) == p:
869 if normcase(n) == p:
804 return n
870 return n
805 return None
871 return None
806
872
807 seps = os.sep
873 seps = os.sep
808 if os.altsep:
874 if os.altsep:
809 seps = seps + os.altsep
875 seps = seps + os.altsep
810 # Protect backslashes. This gets silly very quickly.
876 # Protect backslashes. This gets silly very quickly.
811 seps.replace('\\','\\\\')
877 seps.replace('\\','\\\\')
812 pattern = remod.compile(r'([^%s]+)|([%s]+)' % (seps, seps))
878 pattern = remod.compile(r'([^%s]+)|([%s]+)' % (seps, seps))
813 dir = os.path.normpath(root)
879 dir = os.path.normpath(root)
814 result = []
880 result = []
815 for part, sep in pattern.findall(name):
881 for part, sep in pattern.findall(name):
816 if sep:
882 if sep:
817 result.append(sep)
883 result.append(sep)
818 continue
884 continue
819
885
820 if dir not in _fspathcache:
886 if dir not in _fspathcache:
821 _fspathcache[dir] = os.listdir(dir)
887 _fspathcache[dir] = os.listdir(dir)
822 contents = _fspathcache[dir]
888 contents = _fspathcache[dir]
823
889
824 found = find(part, contents)
890 found = find(part, contents)
825 if not found:
891 if not found:
826 # retry "once per directory" per "dirstate.walk" which
892 # retry "once per directory" per "dirstate.walk" which
827 # may take place for each patches of "hg qpush", for example
893 # may take place for each patches of "hg qpush", for example
828 contents = os.listdir(dir)
894 contents = os.listdir(dir)
829 _fspathcache[dir] = contents
895 _fspathcache[dir] = contents
830 found = find(part, contents)
896 found = find(part, contents)
831
897
832 result.append(found or part)
898 result.append(found or part)
833 dir = os.path.join(dir, part)
899 dir = os.path.join(dir, part)
834
900
835 return ''.join(result)
901 return ''.join(result)
836
902
837 def checknlink(testfile):
903 def checknlink(testfile):
838 '''check whether hardlink count reporting works properly'''
904 '''check whether hardlink count reporting works properly'''
839
905
840 # testfile may be open, so we need a separate file for checking to
906 # testfile may be open, so we need a separate file for checking to
841 # work around issue2543 (or testfile may get lost on Samba shares)
907 # work around issue2543 (or testfile may get lost on Samba shares)
842 f1 = testfile + ".hgtmp1"
908 f1 = testfile + ".hgtmp1"
843 if os.path.lexists(f1):
909 if os.path.lexists(f1):
844 return False
910 return False
845 try:
911 try:
846 posixfile(f1, 'w').close()
912 posixfile(f1, 'w').close()
847 except IOError:
913 except IOError:
848 return False
914 return False
849
915
850 f2 = testfile + ".hgtmp2"
916 f2 = testfile + ".hgtmp2"
851 fd = None
917 fd = None
852 try:
918 try:
853 try:
919 try:
854 oslink(f1, f2)
920 oslink(f1, f2)
855 except OSError:
921 except OSError:
856 return False
922 return False
857
923
858 # nlinks() may behave differently for files on Windows shares if
924 # nlinks() may behave differently for files on Windows shares if
859 # the file is open.
925 # the file is open.
860 fd = posixfile(f2)
926 fd = posixfile(f2)
861 return nlinks(f2) > 1
927 return nlinks(f2) > 1
862 finally:
928 finally:
863 if fd is not None:
929 if fd is not None:
864 fd.close()
930 fd.close()
865 for f in (f1, f2):
931 for f in (f1, f2):
866 try:
932 try:
867 os.unlink(f)
933 os.unlink(f)
868 except OSError:
934 except OSError:
869 pass
935 pass
870
936
871 def endswithsep(path):
937 def endswithsep(path):
872 '''Check path ends with os.sep or os.altsep.'''
938 '''Check path ends with os.sep or os.altsep.'''
873 return path.endswith(os.sep) or os.altsep and path.endswith(os.altsep)
939 return path.endswith(os.sep) or os.altsep and path.endswith(os.altsep)
874
940
875 def splitpath(path):
941 def splitpath(path):
876 '''Split path by os.sep.
942 '''Split path by os.sep.
877 Note that this function does not use os.altsep because this is
943 Note that this function does not use os.altsep because this is
878 an alternative of simple "xxx.split(os.sep)".
944 an alternative of simple "xxx.split(os.sep)".
879 It is recommended to use os.path.normpath() before using this
945 It is recommended to use os.path.normpath() before using this
880 function if need.'''
946 function if need.'''
881 return path.split(os.sep)
947 return path.split(os.sep)
882
948
883 def gui():
949 def gui():
884 '''Are we running in a GUI?'''
950 '''Are we running in a GUI?'''
885 if sys.platform == 'darwin':
951 if sys.platform == 'darwin':
886 if 'SSH_CONNECTION' in os.environ:
952 if 'SSH_CONNECTION' in os.environ:
887 # handle SSH access to a box where the user is logged in
953 # handle SSH access to a box where the user is logged in
888 return False
954 return False
889 elif getattr(osutil, 'isgui', None):
955 elif getattr(osutil, 'isgui', None):
890 # check if a CoreGraphics session is available
956 # check if a CoreGraphics session is available
891 return osutil.isgui()
957 return osutil.isgui()
892 else:
958 else:
893 # pure build; use a safe default
959 # pure build; use a safe default
894 return True
960 return True
895 else:
961 else:
896 return os.name == "nt" or os.environ.get("DISPLAY")
962 return os.name == "nt" or os.environ.get("DISPLAY")
897
963
898 def mktempcopy(name, emptyok=False, createmode=None):
964 def mktempcopy(name, emptyok=False, createmode=None):
899 """Create a temporary file with the same contents from name
965 """Create a temporary file with the same contents from name
900
966
901 The permission bits are copied from the original file.
967 The permission bits are copied from the original file.
902
968
903 If the temporary file is going to be truncated immediately, you
969 If the temporary file is going to be truncated immediately, you
904 can use emptyok=True as an optimization.
970 can use emptyok=True as an optimization.
905
971
906 Returns the name of the temporary file.
972 Returns the name of the temporary file.
907 """
973 """
908 d, fn = os.path.split(name)
974 d, fn = os.path.split(name)
909 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
975 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
910 os.close(fd)
976 os.close(fd)
911 # Temporary files are created with mode 0600, which is usually not
977 # Temporary files are created with mode 0600, which is usually not
912 # what we want. If the original file already exists, just copy
978 # what we want. If the original file already exists, just copy
913 # its mode. Otherwise, manually obey umask.
979 # its mode. Otherwise, manually obey umask.
914 copymode(name, temp, createmode)
980 copymode(name, temp, createmode)
915 if emptyok:
981 if emptyok:
916 return temp
982 return temp
917 try:
983 try:
918 try:
984 try:
919 ifp = posixfile(name, "rb")
985 ifp = posixfile(name, "rb")
920 except IOError, inst:
986 except IOError, inst:
921 if inst.errno == errno.ENOENT:
987 if inst.errno == errno.ENOENT:
922 return temp
988 return temp
923 if not getattr(inst, 'filename', None):
989 if not getattr(inst, 'filename', None):
924 inst.filename = name
990 inst.filename = name
925 raise
991 raise
926 ofp = posixfile(temp, "wb")
992 ofp = posixfile(temp, "wb")
927 for chunk in filechunkiter(ifp):
993 for chunk in filechunkiter(ifp):
928 ofp.write(chunk)
994 ofp.write(chunk)
929 ifp.close()
995 ifp.close()
930 ofp.close()
996 ofp.close()
931 except: # re-raises
997 except: # re-raises
932 try: os.unlink(temp)
998 try: os.unlink(temp)
933 except OSError: pass
999 except OSError: pass
934 raise
1000 raise
935 return temp
1001 return temp
936
1002
937 class atomictempfile(object):
1003 class atomictempfile(object):
938 '''writable file object that atomically updates a file
1004 '''writable file object that atomically updates a file
939
1005
940 All writes will go to a temporary copy of the original file. Call
1006 All writes will go to a temporary copy of the original file. Call
941 close() when you are done writing, and atomictempfile will rename
1007 close() when you are done writing, and atomictempfile will rename
942 the temporary copy to the original name, making the changes
1008 the temporary copy to the original name, making the changes
943 visible. If the object is destroyed without being closed, all your
1009 visible. If the object is destroyed without being closed, all your
944 writes are discarded.
1010 writes are discarded.
945 '''
1011 '''
946 def __init__(self, name, mode='w+b', createmode=None):
1012 def __init__(self, name, mode='w+b', createmode=None):
947 self.__name = name # permanent name
1013 self.__name = name # permanent name
948 self._tempname = mktempcopy(name, emptyok=('w' in mode),
1014 self._tempname = mktempcopy(name, emptyok=('w' in mode),
949 createmode=createmode)
1015 createmode=createmode)
950 self._fp = posixfile(self._tempname, mode)
1016 self._fp = posixfile(self._tempname, mode)
951
1017
952 # delegated methods
1018 # delegated methods
953 self.write = self._fp.write
1019 self.write = self._fp.write
954 self.seek = self._fp.seek
1020 self.seek = self._fp.seek
955 self.tell = self._fp.tell
1021 self.tell = self._fp.tell
956 self.fileno = self._fp.fileno
1022 self.fileno = self._fp.fileno
957
1023
958 def close(self):
1024 def close(self):
959 if not self._fp.closed:
1025 if not self._fp.closed:
960 self._fp.close()
1026 self._fp.close()
961 rename(self._tempname, localpath(self.__name))
1027 rename(self._tempname, localpath(self.__name))
962
1028
963 def discard(self):
1029 def discard(self):
964 if not self._fp.closed:
1030 if not self._fp.closed:
965 try:
1031 try:
966 os.unlink(self._tempname)
1032 os.unlink(self._tempname)
967 except OSError:
1033 except OSError:
968 pass
1034 pass
969 self._fp.close()
1035 self._fp.close()
970
1036
971 def __del__(self):
1037 def __del__(self):
972 if safehasattr(self, '_fp'): # constructor actually did something
1038 if safehasattr(self, '_fp'): # constructor actually did something
973 self.discard()
1039 self.discard()
974
1040
975 def makedirs(name, mode=None, notindexed=False):
1041 def makedirs(name, mode=None, notindexed=False):
976 """recursive directory creation with parent mode inheritance"""
1042 """recursive directory creation with parent mode inheritance"""
977 try:
1043 try:
978 makedir(name, notindexed)
1044 makedir(name, notindexed)
979 except OSError, err:
1045 except OSError, err:
980 if err.errno == errno.EEXIST:
1046 if err.errno == errno.EEXIST:
981 return
1047 return
982 if err.errno != errno.ENOENT or not name:
1048 if err.errno != errno.ENOENT or not name:
983 raise
1049 raise
984 parent = os.path.dirname(os.path.abspath(name))
1050 parent = os.path.dirname(os.path.abspath(name))
985 if parent == name:
1051 if parent == name:
986 raise
1052 raise
987 makedirs(parent, mode, notindexed)
1053 makedirs(parent, mode, notindexed)
988 makedir(name, notindexed)
1054 makedir(name, notindexed)
989 if mode is not None:
1055 if mode is not None:
990 os.chmod(name, mode)
1056 os.chmod(name, mode)
991
1057
992 def ensuredirs(name, mode=None):
1058 def ensuredirs(name, mode=None):
993 """race-safe recursive directory creation"""
1059 """race-safe recursive directory creation"""
994 if os.path.isdir(name):
1060 if os.path.isdir(name):
995 return
1061 return
996 parent = os.path.dirname(os.path.abspath(name))
1062 parent = os.path.dirname(os.path.abspath(name))
997 if parent != name:
1063 if parent != name:
998 ensuredirs(parent, mode)
1064 ensuredirs(parent, mode)
999 try:
1065 try:
1000 os.mkdir(name)
1066 os.mkdir(name)
1001 except OSError, err:
1067 except OSError, err:
1002 if err.errno == errno.EEXIST and os.path.isdir(name):
1068 if err.errno == errno.EEXIST and os.path.isdir(name):
1003 # someone else seems to have won a directory creation race
1069 # someone else seems to have won a directory creation race
1004 return
1070 return
1005 raise
1071 raise
1006 if mode is not None:
1072 if mode is not None:
1007 os.chmod(name, mode)
1073 os.chmod(name, mode)
1008
1074
1009 def readfile(path):
1075 def readfile(path):
1010 fp = open(path, 'rb')
1076 fp = open(path, 'rb')
1011 try:
1077 try:
1012 return fp.read()
1078 return fp.read()
1013 finally:
1079 finally:
1014 fp.close()
1080 fp.close()
1015
1081
1016 def writefile(path, text):
1082 def writefile(path, text):
1017 fp = open(path, 'wb')
1083 fp = open(path, 'wb')
1018 try:
1084 try:
1019 fp.write(text)
1085 fp.write(text)
1020 finally:
1086 finally:
1021 fp.close()
1087 fp.close()
1022
1088
1023 def appendfile(path, text):
1089 def appendfile(path, text):
1024 fp = open(path, 'ab')
1090 fp = open(path, 'ab')
1025 try:
1091 try:
1026 fp.write(text)
1092 fp.write(text)
1027 finally:
1093 finally:
1028 fp.close()
1094 fp.close()
1029
1095
1030 class chunkbuffer(object):
1096 class chunkbuffer(object):
1031 """Allow arbitrary sized chunks of data to be efficiently read from an
1097 """Allow arbitrary sized chunks of data to be efficiently read from an
1032 iterator over chunks of arbitrary size."""
1098 iterator over chunks of arbitrary size."""
1033
1099
1034 def __init__(self, in_iter):
1100 def __init__(self, in_iter):
1035 """in_iter is the iterator that's iterating over the input chunks.
1101 """in_iter is the iterator that's iterating over the input chunks.
1036 targetsize is how big a buffer to try to maintain."""
1102 targetsize is how big a buffer to try to maintain."""
1037 def splitbig(chunks):
1103 def splitbig(chunks):
1038 for chunk in chunks:
1104 for chunk in chunks:
1039 if len(chunk) > 2**20:
1105 if len(chunk) > 2**20:
1040 pos = 0
1106 pos = 0
1041 while pos < len(chunk):
1107 while pos < len(chunk):
1042 end = pos + 2 ** 18
1108 end = pos + 2 ** 18
1043 yield chunk[pos:end]
1109 yield chunk[pos:end]
1044 pos = end
1110 pos = end
1045 else:
1111 else:
1046 yield chunk
1112 yield chunk
1047 self.iter = splitbig(in_iter)
1113 self.iter = splitbig(in_iter)
1048 self._queue = deque()
1114 self._queue = deque()
1049
1115
1050 def read(self, l=None):
1116 def read(self, l=None):
1051 """Read L bytes of data from the iterator of chunks of data.
1117 """Read L bytes of data from the iterator of chunks of data.
1052 Returns less than L bytes if the iterator runs dry.
1118 Returns less than L bytes if the iterator runs dry.
1053
1119
1054 If size parameter is ommited, read everything"""
1120 If size parameter is ommited, read everything"""
1055 left = l
1121 left = l
1056 buf = []
1122 buf = []
1057 queue = self._queue
1123 queue = self._queue
1058 while left is None or left > 0:
1124 while left is None or left > 0:
1059 # refill the queue
1125 # refill the queue
1060 if not queue:
1126 if not queue:
1061 target = 2**18
1127 target = 2**18
1062 for chunk in self.iter:
1128 for chunk in self.iter:
1063 queue.append(chunk)
1129 queue.append(chunk)
1064 target -= len(chunk)
1130 target -= len(chunk)
1065 if target <= 0:
1131 if target <= 0:
1066 break
1132 break
1067 if not queue:
1133 if not queue:
1068 break
1134 break
1069
1135
1070 chunk = queue.popleft()
1136 chunk = queue.popleft()
1071 if left is not None:
1137 if left is not None:
1072 left -= len(chunk)
1138 left -= len(chunk)
1073 if left is not None and left < 0:
1139 if left is not None and left < 0:
1074 queue.appendleft(chunk[left:])
1140 queue.appendleft(chunk[left:])
1075 buf.append(chunk[:left])
1141 buf.append(chunk[:left])
1076 else:
1142 else:
1077 buf.append(chunk)
1143 buf.append(chunk)
1078
1144
1079 return ''.join(buf)
1145 return ''.join(buf)
1080
1146
1081 def filechunkiter(f, size=65536, limit=None):
1147 def filechunkiter(f, size=65536, limit=None):
1082 """Create a generator that produces the data in the file size
1148 """Create a generator that produces the data in the file size
1083 (default 65536) bytes at a time, up to optional limit (default is
1149 (default 65536) bytes at a time, up to optional limit (default is
1084 to read all data). Chunks may be less than size bytes if the
1150 to read all data). Chunks may be less than size bytes if the
1085 chunk is the last chunk in the file, or the file is a socket or
1151 chunk is the last chunk in the file, or the file is a socket or
1086 some other type of file that sometimes reads less data than is
1152 some other type of file that sometimes reads less data than is
1087 requested."""
1153 requested."""
1088 assert size >= 0
1154 assert size >= 0
1089 assert limit is None or limit >= 0
1155 assert limit is None or limit >= 0
1090 while True:
1156 while True:
1091 if limit is None:
1157 if limit is None:
1092 nbytes = size
1158 nbytes = size
1093 else:
1159 else:
1094 nbytes = min(limit, size)
1160 nbytes = min(limit, size)
1095 s = nbytes and f.read(nbytes)
1161 s = nbytes and f.read(nbytes)
1096 if not s:
1162 if not s:
1097 break
1163 break
1098 if limit:
1164 if limit:
1099 limit -= len(s)
1165 limit -= len(s)
1100 yield s
1166 yield s
1101
1167
1102 def makedate(timestamp=None):
1168 def makedate(timestamp=None):
1103 '''Return a unix timestamp (or the current time) as a (unixtime,
1169 '''Return a unix timestamp (or the current time) as a (unixtime,
1104 offset) tuple based off the local timezone.'''
1170 offset) tuple based off the local timezone.'''
1105 if timestamp is None:
1171 if timestamp is None:
1106 timestamp = time.time()
1172 timestamp = time.time()
1107 if timestamp < 0:
1173 if timestamp < 0:
1108 hint = _("check your clock")
1174 hint = _("check your clock")
1109 raise Abort(_("negative timestamp: %d") % timestamp, hint=hint)
1175 raise Abort(_("negative timestamp: %d") % timestamp, hint=hint)
1110 delta = (datetime.datetime.utcfromtimestamp(timestamp) -
1176 delta = (datetime.datetime.utcfromtimestamp(timestamp) -
1111 datetime.datetime.fromtimestamp(timestamp))
1177 datetime.datetime.fromtimestamp(timestamp))
1112 tz = delta.days * 86400 + delta.seconds
1178 tz = delta.days * 86400 + delta.seconds
1113 return timestamp, tz
1179 return timestamp, tz
1114
1180
1115 def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'):
1181 def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'):
1116 """represent a (unixtime, offset) tuple as a localized time.
1182 """represent a (unixtime, offset) tuple as a localized time.
1117 unixtime is seconds since the epoch, and offset is the time zone's
1183 unixtime is seconds since the epoch, and offset is the time zone's
1118 number of seconds away from UTC. if timezone is false, do not
1184 number of seconds away from UTC. if timezone is false, do not
1119 append time zone to string."""
1185 append time zone to string."""
1120 t, tz = date or makedate()
1186 t, tz = date or makedate()
1121 if t < 0:
1187 if t < 0:
1122 t = 0 # time.gmtime(lt) fails on Windows for lt < -43200
1188 t = 0 # time.gmtime(lt) fails on Windows for lt < -43200
1123 tz = 0
1189 tz = 0
1124 if "%1" in format or "%2" in format or "%z" in format:
1190 if "%1" in format or "%2" in format or "%z" in format:
1125 sign = (tz > 0) and "-" or "+"
1191 sign = (tz > 0) and "-" or "+"
1126 minutes = abs(tz) // 60
1192 minutes = abs(tz) // 60
1127 format = format.replace("%z", "%1%2")
1193 format = format.replace("%z", "%1%2")
1128 format = format.replace("%1", "%c%02d" % (sign, minutes // 60))
1194 format = format.replace("%1", "%c%02d" % (sign, minutes // 60))
1129 format = format.replace("%2", "%02d" % (minutes % 60))
1195 format = format.replace("%2", "%02d" % (minutes % 60))
1130 try:
1196 try:
1131 t = time.gmtime(float(t) - tz)
1197 t = time.gmtime(float(t) - tz)
1132 except ValueError:
1198 except ValueError:
1133 # time was out of range
1199 # time was out of range
1134 t = time.gmtime(sys.maxint)
1200 t = time.gmtime(sys.maxint)
1135 s = time.strftime(format, t)
1201 s = time.strftime(format, t)
1136 return s
1202 return s
1137
1203
1138 def shortdate(date=None):
1204 def shortdate(date=None):
1139 """turn (timestamp, tzoff) tuple into iso 8631 date."""
1205 """turn (timestamp, tzoff) tuple into iso 8631 date."""
1140 return datestr(date, format='%Y-%m-%d')
1206 return datestr(date, format='%Y-%m-%d')
1141
1207
1142 def strdate(string, format, defaults=[]):
1208 def strdate(string, format, defaults=[]):
1143 """parse a localized time string and return a (unixtime, offset) tuple.
1209 """parse a localized time string and return a (unixtime, offset) tuple.
1144 if the string cannot be parsed, ValueError is raised."""
1210 if the string cannot be parsed, ValueError is raised."""
1145 def timezone(string):
1211 def timezone(string):
1146 tz = string.split()[-1]
1212 tz = string.split()[-1]
1147 if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
1213 if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
1148 sign = (tz[0] == "+") and 1 or -1
1214 sign = (tz[0] == "+") and 1 or -1
1149 hours = int(tz[1:3])
1215 hours = int(tz[1:3])
1150 minutes = int(tz[3:5])
1216 minutes = int(tz[3:5])
1151 return -sign * (hours * 60 + minutes) * 60
1217 return -sign * (hours * 60 + minutes) * 60
1152 if tz == "GMT" or tz == "UTC":
1218 if tz == "GMT" or tz == "UTC":
1153 return 0
1219 return 0
1154 return None
1220 return None
1155
1221
1156 # NOTE: unixtime = localunixtime + offset
1222 # NOTE: unixtime = localunixtime + offset
1157 offset, date = timezone(string), string
1223 offset, date = timezone(string), string
1158 if offset is not None:
1224 if offset is not None:
1159 date = " ".join(string.split()[:-1])
1225 date = " ".join(string.split()[:-1])
1160
1226
1161 # add missing elements from defaults
1227 # add missing elements from defaults
1162 usenow = False # default to using biased defaults
1228 usenow = False # default to using biased defaults
1163 for part in ("S", "M", "HI", "d", "mb", "yY"): # decreasing specificity
1229 for part in ("S", "M", "HI", "d", "mb", "yY"): # decreasing specificity
1164 found = [True for p in part if ("%"+p) in format]
1230 found = [True for p in part if ("%"+p) in format]
1165 if not found:
1231 if not found:
1166 date += "@" + defaults[part][usenow]
1232 date += "@" + defaults[part][usenow]
1167 format += "@%" + part[0]
1233 format += "@%" + part[0]
1168 else:
1234 else:
1169 # We've found a specific time element, less specific time
1235 # We've found a specific time element, less specific time
1170 # elements are relative to today
1236 # elements are relative to today
1171 usenow = True
1237 usenow = True
1172
1238
1173 timetuple = time.strptime(date, format)
1239 timetuple = time.strptime(date, format)
1174 localunixtime = int(calendar.timegm(timetuple))
1240 localunixtime = int(calendar.timegm(timetuple))
1175 if offset is None:
1241 if offset is None:
1176 # local timezone
1242 # local timezone
1177 unixtime = int(time.mktime(timetuple))
1243 unixtime = int(time.mktime(timetuple))
1178 offset = unixtime - localunixtime
1244 offset = unixtime - localunixtime
1179 else:
1245 else:
1180 unixtime = localunixtime + offset
1246 unixtime = localunixtime + offset
1181 return unixtime, offset
1247 return unixtime, offset
1182
1248
1183 def parsedate(date, formats=None, bias={}):
1249 def parsedate(date, formats=None, bias={}):
1184 """parse a localized date/time and return a (unixtime, offset) tuple.
1250 """parse a localized date/time and return a (unixtime, offset) tuple.
1185
1251
1186 The date may be a "unixtime offset" string or in one of the specified
1252 The date may be a "unixtime offset" string or in one of the specified
1187 formats. If the date already is a (unixtime, offset) tuple, it is returned.
1253 formats. If the date already is a (unixtime, offset) tuple, it is returned.
1188
1254
1189 >>> parsedate(' today ') == parsedate(\
1255 >>> parsedate(' today ') == parsedate(\
1190 datetime.date.today().strftime('%b %d'))
1256 datetime.date.today().strftime('%b %d'))
1191 True
1257 True
1192 >>> parsedate( 'yesterday ') == parsedate((datetime.date.today() -\
1258 >>> parsedate( 'yesterday ') == parsedate((datetime.date.today() -\
1193 datetime.timedelta(days=1)\
1259 datetime.timedelta(days=1)\
1194 ).strftime('%b %d'))
1260 ).strftime('%b %d'))
1195 True
1261 True
1196 >>> now, tz = makedate()
1262 >>> now, tz = makedate()
1197 >>> strnow, strtz = parsedate('now')
1263 >>> strnow, strtz = parsedate('now')
1198 >>> (strnow - now) < 1
1264 >>> (strnow - now) < 1
1199 True
1265 True
1200 >>> tz == strtz
1266 >>> tz == strtz
1201 True
1267 True
1202 """
1268 """
1203 if not date:
1269 if not date:
1204 return 0, 0
1270 return 0, 0
1205 if isinstance(date, tuple) and len(date) == 2:
1271 if isinstance(date, tuple) and len(date) == 2:
1206 return date
1272 return date
1207 if not formats:
1273 if not formats:
1208 formats = defaultdateformats
1274 formats = defaultdateformats
1209 date = date.strip()
1275 date = date.strip()
1210
1276
1211 if date == _('now'):
1277 if date == _('now'):
1212 return makedate()
1278 return makedate()
1213 if date == _('today'):
1279 if date == _('today'):
1214 date = datetime.date.today().strftime('%b %d')
1280 date = datetime.date.today().strftime('%b %d')
1215 elif date == _('yesterday'):
1281 elif date == _('yesterday'):
1216 date = (datetime.date.today() -
1282 date = (datetime.date.today() -
1217 datetime.timedelta(days=1)).strftime('%b %d')
1283 datetime.timedelta(days=1)).strftime('%b %d')
1218
1284
1219 try:
1285 try:
1220 when, offset = map(int, date.split(' '))
1286 when, offset = map(int, date.split(' '))
1221 except ValueError:
1287 except ValueError:
1222 # fill out defaults
1288 # fill out defaults
1223 now = makedate()
1289 now = makedate()
1224 defaults = {}
1290 defaults = {}
1225 for part in ("d", "mb", "yY", "HI", "M", "S"):
1291 for part in ("d", "mb", "yY", "HI", "M", "S"):
1226 # this piece is for rounding the specific end of unknowns
1292 # this piece is for rounding the specific end of unknowns
1227 b = bias.get(part)
1293 b = bias.get(part)
1228 if b is None:
1294 if b is None:
1229 if part[0] in "HMS":
1295 if part[0] in "HMS":
1230 b = "00"
1296 b = "00"
1231 else:
1297 else:
1232 b = "0"
1298 b = "0"
1233
1299
1234 # this piece is for matching the generic end to today's date
1300 # this piece is for matching the generic end to today's date
1235 n = datestr(now, "%" + part[0])
1301 n = datestr(now, "%" + part[0])
1236
1302
1237 defaults[part] = (b, n)
1303 defaults[part] = (b, n)
1238
1304
1239 for format in formats:
1305 for format in formats:
1240 try:
1306 try:
1241 when, offset = strdate(date, format, defaults)
1307 when, offset = strdate(date, format, defaults)
1242 except (ValueError, OverflowError):
1308 except (ValueError, OverflowError):
1243 pass
1309 pass
1244 else:
1310 else:
1245 break
1311 break
1246 else:
1312 else:
1247 raise Abort(_('invalid date: %r') % date)
1313 raise Abort(_('invalid date: %r') % date)
1248 # validate explicit (probably user-specified) date and
1314 # validate explicit (probably user-specified) date and
1249 # time zone offset. values must fit in signed 32 bits for
1315 # time zone offset. values must fit in signed 32 bits for
1250 # current 32-bit linux runtimes. timezones go from UTC-12
1316 # current 32-bit linux runtimes. timezones go from UTC-12
1251 # to UTC+14
1317 # to UTC+14
1252 if abs(when) > 0x7fffffff:
1318 if abs(when) > 0x7fffffff:
1253 raise Abort(_('date exceeds 32 bits: %d') % when)
1319 raise Abort(_('date exceeds 32 bits: %d') % when)
1254 if when < 0:
1320 if when < 0:
1255 raise Abort(_('negative date value: %d') % when)
1321 raise Abort(_('negative date value: %d') % when)
1256 if offset < -50400 or offset > 43200:
1322 if offset < -50400 or offset > 43200:
1257 raise Abort(_('impossible time zone offset: %d') % offset)
1323 raise Abort(_('impossible time zone offset: %d') % offset)
1258 return when, offset
1324 return when, offset
1259
1325
1260 def matchdate(date):
1326 def matchdate(date):
1261 """Return a function that matches a given date match specifier
1327 """Return a function that matches a given date match specifier
1262
1328
1263 Formats include:
1329 Formats include:
1264
1330
1265 '{date}' match a given date to the accuracy provided
1331 '{date}' match a given date to the accuracy provided
1266
1332
1267 '<{date}' on or before a given date
1333 '<{date}' on or before a given date
1268
1334
1269 '>{date}' on or after a given date
1335 '>{date}' on or after a given date
1270
1336
1271 >>> p1 = parsedate("10:29:59")
1337 >>> p1 = parsedate("10:29:59")
1272 >>> p2 = parsedate("10:30:00")
1338 >>> p2 = parsedate("10:30:00")
1273 >>> p3 = parsedate("10:30:59")
1339 >>> p3 = parsedate("10:30:59")
1274 >>> p4 = parsedate("10:31:00")
1340 >>> p4 = parsedate("10:31:00")
1275 >>> p5 = parsedate("Sep 15 10:30:00 1999")
1341 >>> p5 = parsedate("Sep 15 10:30:00 1999")
1276 >>> f = matchdate("10:30")
1342 >>> f = matchdate("10:30")
1277 >>> f(p1[0])
1343 >>> f(p1[0])
1278 False
1344 False
1279 >>> f(p2[0])
1345 >>> f(p2[0])
1280 True
1346 True
1281 >>> f(p3[0])
1347 >>> f(p3[0])
1282 True
1348 True
1283 >>> f(p4[0])
1349 >>> f(p4[0])
1284 False
1350 False
1285 >>> f(p5[0])
1351 >>> f(p5[0])
1286 False
1352 False
1287 """
1353 """
1288
1354
1289 def lower(date):
1355 def lower(date):
1290 d = {'mb': "1", 'd': "1"}
1356 d = {'mb': "1", 'd': "1"}
1291 return parsedate(date, extendeddateformats, d)[0]
1357 return parsedate(date, extendeddateformats, d)[0]
1292
1358
1293 def upper(date):
1359 def upper(date):
1294 d = {'mb': "12", 'HI': "23", 'M': "59", 'S': "59"}
1360 d = {'mb': "12", 'HI': "23", 'M': "59", 'S': "59"}
1295 for days in ("31", "30", "29"):
1361 for days in ("31", "30", "29"):
1296 try:
1362 try:
1297 d["d"] = days
1363 d["d"] = days
1298 return parsedate(date, extendeddateformats, d)[0]
1364 return parsedate(date, extendeddateformats, d)[0]
1299 except Abort:
1365 except Abort:
1300 pass
1366 pass
1301 d["d"] = "28"
1367 d["d"] = "28"
1302 return parsedate(date, extendeddateformats, d)[0]
1368 return parsedate(date, extendeddateformats, d)[0]
1303
1369
1304 date = date.strip()
1370 date = date.strip()
1305
1371
1306 if not date:
1372 if not date:
1307 raise Abort(_("dates cannot consist entirely of whitespace"))
1373 raise Abort(_("dates cannot consist entirely of whitespace"))
1308 elif date[0] == "<":
1374 elif date[0] == "<":
1309 if not date[1:]:
1375 if not date[1:]:
1310 raise Abort(_("invalid day spec, use '<DATE'"))
1376 raise Abort(_("invalid day spec, use '<DATE'"))
1311 when = upper(date[1:])
1377 when = upper(date[1:])
1312 return lambda x: x <= when
1378 return lambda x: x <= when
1313 elif date[0] == ">":
1379 elif date[0] == ">":
1314 if not date[1:]:
1380 if not date[1:]:
1315 raise Abort(_("invalid day spec, use '>DATE'"))
1381 raise Abort(_("invalid day spec, use '>DATE'"))
1316 when = lower(date[1:])
1382 when = lower(date[1:])
1317 return lambda x: x >= when
1383 return lambda x: x >= when
1318 elif date[0] == "-":
1384 elif date[0] == "-":
1319 try:
1385 try:
1320 days = int(date[1:])
1386 days = int(date[1:])
1321 except ValueError:
1387 except ValueError:
1322 raise Abort(_("invalid day spec: %s") % date[1:])
1388 raise Abort(_("invalid day spec: %s") % date[1:])
1323 if days < 0:
1389 if days < 0:
1324 raise Abort(_("%s must be nonnegative (see 'hg help dates')")
1390 raise Abort(_("%s must be nonnegative (see 'hg help dates')")
1325 % date[1:])
1391 % date[1:])
1326 when = makedate()[0] - days * 3600 * 24
1392 when = makedate()[0] - days * 3600 * 24
1327 return lambda x: x >= when
1393 return lambda x: x >= when
1328 elif " to " in date:
1394 elif " to " in date:
1329 a, b = date.split(" to ")
1395 a, b = date.split(" to ")
1330 start, stop = lower(a), upper(b)
1396 start, stop = lower(a), upper(b)
1331 return lambda x: x >= start and x <= stop
1397 return lambda x: x >= start and x <= stop
1332 else:
1398 else:
1333 start, stop = lower(date), upper(date)
1399 start, stop = lower(date), upper(date)
1334 return lambda x: x >= start and x <= stop
1400 return lambda x: x >= start and x <= stop
1335
1401
1336 def shortuser(user):
1402 def shortuser(user):
1337 """Return a short representation of a user name or email address."""
1403 """Return a short representation of a user name or email address."""
1338 f = user.find('@')
1404 f = user.find('@')
1339 if f >= 0:
1405 if f >= 0:
1340 user = user[:f]
1406 user = user[:f]
1341 f = user.find('<')
1407 f = user.find('<')
1342 if f >= 0:
1408 if f >= 0:
1343 user = user[f + 1:]
1409 user = user[f + 1:]
1344 f = user.find(' ')
1410 f = user.find(' ')
1345 if f >= 0:
1411 if f >= 0:
1346 user = user[:f]
1412 user = user[:f]
1347 f = user.find('.')
1413 f = user.find('.')
1348 if f >= 0:
1414 if f >= 0:
1349 user = user[:f]
1415 user = user[:f]
1350 return user
1416 return user
1351
1417
1352 def emailuser(user):
1418 def emailuser(user):
1353 """Return the user portion of an email address."""
1419 """Return the user portion of an email address."""
1354 f = user.find('@')
1420 f = user.find('@')
1355 if f >= 0:
1421 if f >= 0:
1356 user = user[:f]
1422 user = user[:f]
1357 f = user.find('<')
1423 f = user.find('<')
1358 if f >= 0:
1424 if f >= 0:
1359 user = user[f + 1:]
1425 user = user[f + 1:]
1360 return user
1426 return user
1361
1427
1362 def email(author):
1428 def email(author):
1363 '''get email of author.'''
1429 '''get email of author.'''
1364 r = author.find('>')
1430 r = author.find('>')
1365 if r == -1:
1431 if r == -1:
1366 r = None
1432 r = None
1367 return author[author.find('<') + 1:r]
1433 return author[author.find('<') + 1:r]
1368
1434
1369 def ellipsis(text, maxlength=400):
1435 def ellipsis(text, maxlength=400):
1370 """Trim string to at most maxlength (default: 400) columns in display."""
1436 """Trim string to at most maxlength (default: 400) columns in display."""
1371 return encoding.trim(text, maxlength, ellipsis='...')
1437 return encoding.trim(text, maxlength, ellipsis='...')
1372
1438
1373 def unitcountfn(*unittable):
1439 def unitcountfn(*unittable):
1374 '''return a function that renders a readable count of some quantity'''
1440 '''return a function that renders a readable count of some quantity'''
1375
1441
1376 def go(count):
1442 def go(count):
1377 for multiplier, divisor, format in unittable:
1443 for multiplier, divisor, format in unittable:
1378 if count >= divisor * multiplier:
1444 if count >= divisor * multiplier:
1379 return format % (count / float(divisor))
1445 return format % (count / float(divisor))
1380 return unittable[-1][2] % count
1446 return unittable[-1][2] % count
1381
1447
1382 return go
1448 return go
1383
1449
1384 bytecount = unitcountfn(
1450 bytecount = unitcountfn(
1385 (100, 1 << 30, _('%.0f GB')),
1451 (100, 1 << 30, _('%.0f GB')),
1386 (10, 1 << 30, _('%.1f GB')),
1452 (10, 1 << 30, _('%.1f GB')),
1387 (1, 1 << 30, _('%.2f GB')),
1453 (1, 1 << 30, _('%.2f GB')),
1388 (100, 1 << 20, _('%.0f MB')),
1454 (100, 1 << 20, _('%.0f MB')),
1389 (10, 1 << 20, _('%.1f MB')),
1455 (10, 1 << 20, _('%.1f MB')),
1390 (1, 1 << 20, _('%.2f MB')),
1456 (1, 1 << 20, _('%.2f MB')),
1391 (100, 1 << 10, _('%.0f KB')),
1457 (100, 1 << 10, _('%.0f KB')),
1392 (10, 1 << 10, _('%.1f KB')),
1458 (10, 1 << 10, _('%.1f KB')),
1393 (1, 1 << 10, _('%.2f KB')),
1459 (1, 1 << 10, _('%.2f KB')),
1394 (1, 1, _('%.0f bytes')),
1460 (1, 1, _('%.0f bytes')),
1395 )
1461 )
1396
1462
1397 def uirepr(s):
1463 def uirepr(s):
1398 # Avoid double backslash in Windows path repr()
1464 # Avoid double backslash in Windows path repr()
1399 return repr(s).replace('\\\\', '\\')
1465 return repr(s).replace('\\\\', '\\')
1400
1466
1401 # delay import of textwrap
1467 # delay import of textwrap
1402 def MBTextWrapper(**kwargs):
1468 def MBTextWrapper(**kwargs):
1403 class tw(textwrap.TextWrapper):
1469 class tw(textwrap.TextWrapper):
1404 """
1470 """
1405 Extend TextWrapper for width-awareness.
1471 Extend TextWrapper for width-awareness.
1406
1472
1407 Neither number of 'bytes' in any encoding nor 'characters' is
1473 Neither number of 'bytes' in any encoding nor 'characters' is
1408 appropriate to calculate terminal columns for specified string.
1474 appropriate to calculate terminal columns for specified string.
1409
1475
1410 Original TextWrapper implementation uses built-in 'len()' directly,
1476 Original TextWrapper implementation uses built-in 'len()' directly,
1411 so overriding is needed to use width information of each characters.
1477 so overriding is needed to use width information of each characters.
1412
1478
1413 In addition, characters classified into 'ambiguous' width are
1479 In addition, characters classified into 'ambiguous' width are
1414 treated as wide in East Asian area, but as narrow in other.
1480 treated as wide in East Asian area, but as narrow in other.
1415
1481
1416 This requires use decision to determine width of such characters.
1482 This requires use decision to determine width of such characters.
1417 """
1483 """
1418 def __init__(self, **kwargs):
1484 def __init__(self, **kwargs):
1419 textwrap.TextWrapper.__init__(self, **kwargs)
1485 textwrap.TextWrapper.__init__(self, **kwargs)
1420
1486
1421 # for compatibility between 2.4 and 2.6
1487 # for compatibility between 2.4 and 2.6
1422 if getattr(self, 'drop_whitespace', None) is None:
1488 if getattr(self, 'drop_whitespace', None) is None:
1423 self.drop_whitespace = kwargs.get('drop_whitespace', True)
1489 self.drop_whitespace = kwargs.get('drop_whitespace', True)
1424
1490
1425 def _cutdown(self, ucstr, space_left):
1491 def _cutdown(self, ucstr, space_left):
1426 l = 0
1492 l = 0
1427 colwidth = encoding.ucolwidth
1493 colwidth = encoding.ucolwidth
1428 for i in xrange(len(ucstr)):
1494 for i in xrange(len(ucstr)):
1429 l += colwidth(ucstr[i])
1495 l += colwidth(ucstr[i])
1430 if space_left < l:
1496 if space_left < l:
1431 return (ucstr[:i], ucstr[i:])
1497 return (ucstr[:i], ucstr[i:])
1432 return ucstr, ''
1498 return ucstr, ''
1433
1499
1434 # overriding of base class
1500 # overriding of base class
1435 def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
1501 def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
1436 space_left = max(width - cur_len, 1)
1502 space_left = max(width - cur_len, 1)
1437
1503
1438 if self.break_long_words:
1504 if self.break_long_words:
1439 cut, res = self._cutdown(reversed_chunks[-1], space_left)
1505 cut, res = self._cutdown(reversed_chunks[-1], space_left)
1440 cur_line.append(cut)
1506 cur_line.append(cut)
1441 reversed_chunks[-1] = res
1507 reversed_chunks[-1] = res
1442 elif not cur_line:
1508 elif not cur_line:
1443 cur_line.append(reversed_chunks.pop())
1509 cur_line.append(reversed_chunks.pop())
1444
1510
1445 # this overriding code is imported from TextWrapper of python 2.6
1511 # this overriding code is imported from TextWrapper of python 2.6
1446 # to calculate columns of string by 'encoding.ucolwidth()'
1512 # to calculate columns of string by 'encoding.ucolwidth()'
1447 def _wrap_chunks(self, chunks):
1513 def _wrap_chunks(self, chunks):
1448 colwidth = encoding.ucolwidth
1514 colwidth = encoding.ucolwidth
1449
1515
1450 lines = []
1516 lines = []
1451 if self.width <= 0:
1517 if self.width <= 0:
1452 raise ValueError("invalid width %r (must be > 0)" % self.width)
1518 raise ValueError("invalid width %r (must be > 0)" % self.width)
1453
1519
1454 # Arrange in reverse order so items can be efficiently popped
1520 # Arrange in reverse order so items can be efficiently popped
1455 # from a stack of chucks.
1521 # from a stack of chucks.
1456 chunks.reverse()
1522 chunks.reverse()
1457
1523
1458 while chunks:
1524 while chunks:
1459
1525
1460 # Start the list of chunks that will make up the current line.
1526 # Start the list of chunks that will make up the current line.
1461 # cur_len is just the length of all the chunks in cur_line.
1527 # cur_len is just the length of all the chunks in cur_line.
1462 cur_line = []
1528 cur_line = []
1463 cur_len = 0
1529 cur_len = 0
1464
1530
1465 # Figure out which static string will prefix this line.
1531 # Figure out which static string will prefix this line.
1466 if lines:
1532 if lines:
1467 indent = self.subsequent_indent
1533 indent = self.subsequent_indent
1468 else:
1534 else:
1469 indent = self.initial_indent
1535 indent = self.initial_indent
1470
1536
1471 # Maximum width for this line.
1537 # Maximum width for this line.
1472 width = self.width - len(indent)
1538 width = self.width - len(indent)
1473
1539
1474 # First chunk on line is whitespace -- drop it, unless this
1540 # First chunk on line is whitespace -- drop it, unless this
1475 # is the very beginning of the text (i.e. no lines started yet).
1541 # is the very beginning of the text (i.e. no lines started yet).
1476 if self.drop_whitespace and chunks[-1].strip() == '' and lines:
1542 if self.drop_whitespace and chunks[-1].strip() == '' and lines:
1477 del chunks[-1]
1543 del chunks[-1]
1478
1544
1479 while chunks:
1545 while chunks:
1480 l = colwidth(chunks[-1])
1546 l = colwidth(chunks[-1])
1481
1547
1482 # Can at least squeeze this chunk onto the current line.
1548 # Can at least squeeze this chunk onto the current line.
1483 if cur_len + l <= width:
1549 if cur_len + l <= width:
1484 cur_line.append(chunks.pop())
1550 cur_line.append(chunks.pop())
1485 cur_len += l
1551 cur_len += l
1486
1552
1487 # Nope, this line is full.
1553 # Nope, this line is full.
1488 else:
1554 else:
1489 break
1555 break
1490
1556
1491 # The current line is full, and the next chunk is too big to
1557 # The current line is full, and the next chunk is too big to
1492 # fit on *any* line (not just this one).
1558 # fit on *any* line (not just this one).
1493 if chunks and colwidth(chunks[-1]) > width:
1559 if chunks and colwidth(chunks[-1]) > width:
1494 self._handle_long_word(chunks, cur_line, cur_len, width)
1560 self._handle_long_word(chunks, cur_line, cur_len, width)
1495
1561
1496 # If the last chunk on this line is all whitespace, drop it.
1562 # If the last chunk on this line is all whitespace, drop it.
1497 if (self.drop_whitespace and
1563 if (self.drop_whitespace and
1498 cur_line and cur_line[-1].strip() == ''):
1564 cur_line and cur_line[-1].strip() == ''):
1499 del cur_line[-1]
1565 del cur_line[-1]
1500
1566
1501 # Convert current line back to a string and store it in list
1567 # Convert current line back to a string and store it in list
1502 # of all lines (return value).
1568 # of all lines (return value).
1503 if cur_line:
1569 if cur_line:
1504 lines.append(indent + ''.join(cur_line))
1570 lines.append(indent + ''.join(cur_line))
1505
1571
1506 return lines
1572 return lines
1507
1573
1508 global MBTextWrapper
1574 global MBTextWrapper
1509 MBTextWrapper = tw
1575 MBTextWrapper = tw
1510 return tw(**kwargs)
1576 return tw(**kwargs)
1511
1577
1512 def wrap(line, width, initindent='', hangindent=''):
1578 def wrap(line, width, initindent='', hangindent=''):
1513 maxindent = max(len(hangindent), len(initindent))
1579 maxindent = max(len(hangindent), len(initindent))
1514 if width <= maxindent:
1580 if width <= maxindent:
1515 # adjust for weird terminal size
1581 # adjust for weird terminal size
1516 width = max(78, maxindent + 1)
1582 width = max(78, maxindent + 1)
1517 line = line.decode(encoding.encoding, encoding.encodingmode)
1583 line = line.decode(encoding.encoding, encoding.encodingmode)
1518 initindent = initindent.decode(encoding.encoding, encoding.encodingmode)
1584 initindent = initindent.decode(encoding.encoding, encoding.encodingmode)
1519 hangindent = hangindent.decode(encoding.encoding, encoding.encodingmode)
1585 hangindent = hangindent.decode(encoding.encoding, encoding.encodingmode)
1520 wrapper = MBTextWrapper(width=width,
1586 wrapper = MBTextWrapper(width=width,
1521 initial_indent=initindent,
1587 initial_indent=initindent,
1522 subsequent_indent=hangindent)
1588 subsequent_indent=hangindent)
1523 return wrapper.fill(line).encode(encoding.encoding)
1589 return wrapper.fill(line).encode(encoding.encoding)
1524
1590
1525 def iterlines(iterator):
1591 def iterlines(iterator):
1526 for chunk in iterator:
1592 for chunk in iterator:
1527 for line in chunk.splitlines():
1593 for line in chunk.splitlines():
1528 yield line
1594 yield line
1529
1595
1530 def expandpath(path):
1596 def expandpath(path):
1531 return os.path.expanduser(os.path.expandvars(path))
1597 return os.path.expanduser(os.path.expandvars(path))
1532
1598
1533 def hgcmd():
1599 def hgcmd():
1534 """Return the command used to execute current hg
1600 """Return the command used to execute current hg
1535
1601
1536 This is different from hgexecutable() because on Windows we want
1602 This is different from hgexecutable() because on Windows we want
1537 to avoid things opening new shell windows like batch files, so we
1603 to avoid things opening new shell windows like batch files, so we
1538 get either the python call or current executable.
1604 get either the python call or current executable.
1539 """
1605 """
1540 if mainfrozen():
1606 if mainfrozen():
1541 return [sys.executable]
1607 return [sys.executable]
1542 return gethgcmd()
1608 return gethgcmd()
1543
1609
1544 def rundetached(args, condfn):
1610 def rundetached(args, condfn):
1545 """Execute the argument list in a detached process.
1611 """Execute the argument list in a detached process.
1546
1612
1547 condfn is a callable which is called repeatedly and should return
1613 condfn is a callable which is called repeatedly and should return
1548 True once the child process is known to have started successfully.
1614 True once the child process is known to have started successfully.
1549 At this point, the child process PID is returned. If the child
1615 At this point, the child process PID is returned. If the child
1550 process fails to start or finishes before condfn() evaluates to
1616 process fails to start or finishes before condfn() evaluates to
1551 True, return -1.
1617 True, return -1.
1552 """
1618 """
1553 # Windows case is easier because the child process is either
1619 # Windows case is easier because the child process is either
1554 # successfully starting and validating the condition or exiting
1620 # successfully starting and validating the condition or exiting
1555 # on failure. We just poll on its PID. On Unix, if the child
1621 # on failure. We just poll on its PID. On Unix, if the child
1556 # process fails to start, it will be left in a zombie state until
1622 # process fails to start, it will be left in a zombie state until
1557 # the parent wait on it, which we cannot do since we expect a long
1623 # the parent wait on it, which we cannot do since we expect a long
1558 # running process on success. Instead we listen for SIGCHLD telling
1624 # running process on success. Instead we listen for SIGCHLD telling
1559 # us our child process terminated.
1625 # us our child process terminated.
1560 terminated = set()
1626 terminated = set()
1561 def handler(signum, frame):
1627 def handler(signum, frame):
1562 terminated.add(os.wait())
1628 terminated.add(os.wait())
1563 prevhandler = None
1629 prevhandler = None
1564 SIGCHLD = getattr(signal, 'SIGCHLD', None)
1630 SIGCHLD = getattr(signal, 'SIGCHLD', None)
1565 if SIGCHLD is not None:
1631 if SIGCHLD is not None:
1566 prevhandler = signal.signal(SIGCHLD, handler)
1632 prevhandler = signal.signal(SIGCHLD, handler)
1567 try:
1633 try:
1568 pid = spawndetached(args)
1634 pid = spawndetached(args)
1569 while not condfn():
1635 while not condfn():
1570 if ((pid in terminated or not testpid(pid))
1636 if ((pid in terminated or not testpid(pid))
1571 and not condfn()):
1637 and not condfn()):
1572 return -1
1638 return -1
1573 time.sleep(0.1)
1639 time.sleep(0.1)
1574 return pid
1640 return pid
1575 finally:
1641 finally:
1576 if prevhandler is not None:
1642 if prevhandler is not None:
1577 signal.signal(signal.SIGCHLD, prevhandler)
1643 signal.signal(signal.SIGCHLD, prevhandler)
1578
1644
1579 try:
1645 try:
1580 any, all = any, all
1646 any, all = any, all
1581 except NameError:
1647 except NameError:
1582 def any(iterable):
1648 def any(iterable):
1583 for i in iterable:
1649 for i in iterable:
1584 if i:
1650 if i:
1585 return True
1651 return True
1586 return False
1652 return False
1587
1653
1588 def all(iterable):
1654 def all(iterable):
1589 for i in iterable:
1655 for i in iterable:
1590 if not i:
1656 if not i:
1591 return False
1657 return False
1592 return True
1658 return True
1593
1659
1594 def interpolate(prefix, mapping, s, fn=None, escape_prefix=False):
1660 def interpolate(prefix, mapping, s, fn=None, escape_prefix=False):
1595 """Return the result of interpolating items in the mapping into string s.
1661 """Return the result of interpolating items in the mapping into string s.
1596
1662
1597 prefix is a single character string, or a two character string with
1663 prefix is a single character string, or a two character string with
1598 a backslash as the first character if the prefix needs to be escaped in
1664 a backslash as the first character if the prefix needs to be escaped in
1599 a regular expression.
1665 a regular expression.
1600
1666
1601 fn is an optional function that will be applied to the replacement text
1667 fn is an optional function that will be applied to the replacement text
1602 just before replacement.
1668 just before replacement.
1603
1669
1604 escape_prefix is an optional flag that allows using doubled prefix for
1670 escape_prefix is an optional flag that allows using doubled prefix for
1605 its escaping.
1671 its escaping.
1606 """
1672 """
1607 fn = fn or (lambda s: s)
1673 fn = fn or (lambda s: s)
1608 patterns = '|'.join(mapping.keys())
1674 patterns = '|'.join(mapping.keys())
1609 if escape_prefix:
1675 if escape_prefix:
1610 patterns += '|' + prefix
1676 patterns += '|' + prefix
1611 if len(prefix) > 1:
1677 if len(prefix) > 1:
1612 prefix_char = prefix[1:]
1678 prefix_char = prefix[1:]
1613 else:
1679 else:
1614 prefix_char = prefix
1680 prefix_char = prefix
1615 mapping[prefix_char] = prefix_char
1681 mapping[prefix_char] = prefix_char
1616 r = remod.compile(r'%s(%s)' % (prefix, patterns))
1682 r = remod.compile(r'%s(%s)' % (prefix, patterns))
1617 return r.sub(lambda x: fn(mapping[x.group()[1:]]), s)
1683 return r.sub(lambda x: fn(mapping[x.group()[1:]]), s)
1618
1684
1619 def getport(port):
1685 def getport(port):
1620 """Return the port for a given network service.
1686 """Return the port for a given network service.
1621
1687
1622 If port is an integer, it's returned as is. If it's a string, it's
1688 If port is an integer, it's returned as is. If it's a string, it's
1623 looked up using socket.getservbyname(). If there's no matching
1689 looked up using socket.getservbyname(). If there's no matching
1624 service, util.Abort is raised.
1690 service, util.Abort is raised.
1625 """
1691 """
1626 try:
1692 try:
1627 return int(port)
1693 return int(port)
1628 except ValueError:
1694 except ValueError:
1629 pass
1695 pass
1630
1696
1631 try:
1697 try:
1632 return socket.getservbyname(port)
1698 return socket.getservbyname(port)
1633 except socket.error:
1699 except socket.error:
1634 raise Abort(_("no port number associated with service '%s'") % port)
1700 raise Abort(_("no port number associated with service '%s'") % port)
1635
1701
1636 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True, 'always': True,
1702 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True, 'always': True,
1637 '0': False, 'no': False, 'false': False, 'off': False,
1703 '0': False, 'no': False, 'false': False, 'off': False,
1638 'never': False}
1704 'never': False}
1639
1705
1640 def parsebool(s):
1706 def parsebool(s):
1641 """Parse s into a boolean.
1707 """Parse s into a boolean.
1642
1708
1643 If s is not a valid boolean, returns None.
1709 If s is not a valid boolean, returns None.
1644 """
1710 """
1645 return _booleans.get(s.lower(), None)
1711 return _booleans.get(s.lower(), None)
1646
1712
1647 _hexdig = '0123456789ABCDEFabcdef'
1713 _hexdig = '0123456789ABCDEFabcdef'
1648 _hextochr = dict((a + b, chr(int(a + b, 16)))
1714 _hextochr = dict((a + b, chr(int(a + b, 16)))
1649 for a in _hexdig for b in _hexdig)
1715 for a in _hexdig for b in _hexdig)
1650
1716
1651 def _urlunquote(s):
1717 def _urlunquote(s):
1652 """Decode HTTP/HTML % encoding.
1718 """Decode HTTP/HTML % encoding.
1653
1719
1654 >>> _urlunquote('abc%20def')
1720 >>> _urlunquote('abc%20def')
1655 'abc def'
1721 'abc def'
1656 """
1722 """
1657 res = s.split('%')
1723 res = s.split('%')
1658 # fastpath
1724 # fastpath
1659 if len(res) == 1:
1725 if len(res) == 1:
1660 return s
1726 return s
1661 s = res[0]
1727 s = res[0]
1662 for item in res[1:]:
1728 for item in res[1:]:
1663 try:
1729 try:
1664 s += _hextochr[item[:2]] + item[2:]
1730 s += _hextochr[item[:2]] + item[2:]
1665 except KeyError:
1731 except KeyError:
1666 s += '%' + item
1732 s += '%' + item
1667 except UnicodeDecodeError:
1733 except UnicodeDecodeError:
1668 s += unichr(int(item[:2], 16)) + item[2:]
1734 s += unichr(int(item[:2], 16)) + item[2:]
1669 return s
1735 return s
1670
1736
1671 class url(object):
1737 class url(object):
1672 r"""Reliable URL parser.
1738 r"""Reliable URL parser.
1673
1739
1674 This parses URLs and provides attributes for the following
1740 This parses URLs and provides attributes for the following
1675 components:
1741 components:
1676
1742
1677 <scheme>://<user>:<passwd>@<host>:<port>/<path>?<query>#<fragment>
1743 <scheme>://<user>:<passwd>@<host>:<port>/<path>?<query>#<fragment>
1678
1744
1679 Missing components are set to None. The only exception is
1745 Missing components are set to None. The only exception is
1680 fragment, which is set to '' if present but empty.
1746 fragment, which is set to '' if present but empty.
1681
1747
1682 If parsefragment is False, fragment is included in query. If
1748 If parsefragment is False, fragment is included in query. If
1683 parsequery is False, query is included in path. If both are
1749 parsequery is False, query is included in path. If both are
1684 False, both fragment and query are included in path.
1750 False, both fragment and query are included in path.
1685
1751
1686 See http://www.ietf.org/rfc/rfc2396.txt for more information.
1752 See http://www.ietf.org/rfc/rfc2396.txt for more information.
1687
1753
1688 Note that for backward compatibility reasons, bundle URLs do not
1754 Note that for backward compatibility reasons, bundle URLs do not
1689 take host names. That means 'bundle://../' has a path of '../'.
1755 take host names. That means 'bundle://../' has a path of '../'.
1690
1756
1691 Examples:
1757 Examples:
1692
1758
1693 >>> url('http://www.ietf.org/rfc/rfc2396.txt')
1759 >>> url('http://www.ietf.org/rfc/rfc2396.txt')
1694 <url scheme: 'http', host: 'www.ietf.org', path: 'rfc/rfc2396.txt'>
1760 <url scheme: 'http', host: 'www.ietf.org', path: 'rfc/rfc2396.txt'>
1695 >>> url('ssh://[::1]:2200//home/joe/repo')
1761 >>> url('ssh://[::1]:2200//home/joe/repo')
1696 <url scheme: 'ssh', host: '[::1]', port: '2200', path: '/home/joe/repo'>
1762 <url scheme: 'ssh', host: '[::1]', port: '2200', path: '/home/joe/repo'>
1697 >>> url('file:///home/joe/repo')
1763 >>> url('file:///home/joe/repo')
1698 <url scheme: 'file', path: '/home/joe/repo'>
1764 <url scheme: 'file', path: '/home/joe/repo'>
1699 >>> url('file:///c:/temp/foo/')
1765 >>> url('file:///c:/temp/foo/')
1700 <url scheme: 'file', path: 'c:/temp/foo/'>
1766 <url scheme: 'file', path: 'c:/temp/foo/'>
1701 >>> url('bundle:foo')
1767 >>> url('bundle:foo')
1702 <url scheme: 'bundle', path: 'foo'>
1768 <url scheme: 'bundle', path: 'foo'>
1703 >>> url('bundle://../foo')
1769 >>> url('bundle://../foo')
1704 <url scheme: 'bundle', path: '../foo'>
1770 <url scheme: 'bundle', path: '../foo'>
1705 >>> url(r'c:\foo\bar')
1771 >>> url(r'c:\foo\bar')
1706 <url path: 'c:\\foo\\bar'>
1772 <url path: 'c:\\foo\\bar'>
1707 >>> url(r'\\blah\blah\blah')
1773 >>> url(r'\\blah\blah\blah')
1708 <url path: '\\\\blah\\blah\\blah'>
1774 <url path: '\\\\blah\\blah\\blah'>
1709 >>> url(r'\\blah\blah\blah#baz')
1775 >>> url(r'\\blah\blah\blah#baz')
1710 <url path: '\\\\blah\\blah\\blah', fragment: 'baz'>
1776 <url path: '\\\\blah\\blah\\blah', fragment: 'baz'>
1711 >>> url(r'file:///C:\users\me')
1777 >>> url(r'file:///C:\users\me')
1712 <url scheme: 'file', path: 'C:\\users\\me'>
1778 <url scheme: 'file', path: 'C:\\users\\me'>
1713
1779
1714 Authentication credentials:
1780 Authentication credentials:
1715
1781
1716 >>> url('ssh://joe:xyz@x/repo')
1782 >>> url('ssh://joe:xyz@x/repo')
1717 <url scheme: 'ssh', user: 'joe', passwd: 'xyz', host: 'x', path: 'repo'>
1783 <url scheme: 'ssh', user: 'joe', passwd: 'xyz', host: 'x', path: 'repo'>
1718 >>> url('ssh://joe@x/repo')
1784 >>> url('ssh://joe@x/repo')
1719 <url scheme: 'ssh', user: 'joe', host: 'x', path: 'repo'>
1785 <url scheme: 'ssh', user: 'joe', host: 'x', path: 'repo'>
1720
1786
1721 Query strings and fragments:
1787 Query strings and fragments:
1722
1788
1723 >>> url('http://host/a?b#c')
1789 >>> url('http://host/a?b#c')
1724 <url scheme: 'http', host: 'host', path: 'a', query: 'b', fragment: 'c'>
1790 <url scheme: 'http', host: 'host', path: 'a', query: 'b', fragment: 'c'>
1725 >>> url('http://host/a?b#c', parsequery=False, parsefragment=False)
1791 >>> url('http://host/a?b#c', parsequery=False, parsefragment=False)
1726 <url scheme: 'http', host: 'host', path: 'a?b#c'>
1792 <url scheme: 'http', host: 'host', path: 'a?b#c'>
1727 """
1793 """
1728
1794
1729 _safechars = "!~*'()+"
1795 _safechars = "!~*'()+"
1730 _safepchars = "/!~*'()+:\\"
1796 _safepchars = "/!~*'()+:\\"
1731 _matchscheme = remod.compile(r'^[a-zA-Z0-9+.\-]+:').match
1797 _matchscheme = remod.compile(r'^[a-zA-Z0-9+.\-]+:').match
1732
1798
1733 def __init__(self, path, parsequery=True, parsefragment=True):
1799 def __init__(self, path, parsequery=True, parsefragment=True):
1734 # We slowly chomp away at path until we have only the path left
1800 # We slowly chomp away at path until we have only the path left
1735 self.scheme = self.user = self.passwd = self.host = None
1801 self.scheme = self.user = self.passwd = self.host = None
1736 self.port = self.path = self.query = self.fragment = None
1802 self.port = self.path = self.query = self.fragment = None
1737 self._localpath = True
1803 self._localpath = True
1738 self._hostport = ''
1804 self._hostport = ''
1739 self._origpath = path
1805 self._origpath = path
1740
1806
1741 if parsefragment and '#' in path:
1807 if parsefragment and '#' in path:
1742 path, self.fragment = path.split('#', 1)
1808 path, self.fragment = path.split('#', 1)
1743 if not path:
1809 if not path:
1744 path = None
1810 path = None
1745
1811
1746 # special case for Windows drive letters and UNC paths
1812 # special case for Windows drive letters and UNC paths
1747 if hasdriveletter(path) or path.startswith(r'\\'):
1813 if hasdriveletter(path) or path.startswith(r'\\'):
1748 self.path = path
1814 self.path = path
1749 return
1815 return
1750
1816
1751 # For compatibility reasons, we can't handle bundle paths as
1817 # For compatibility reasons, we can't handle bundle paths as
1752 # normal URLS
1818 # normal URLS
1753 if path.startswith('bundle:'):
1819 if path.startswith('bundle:'):
1754 self.scheme = 'bundle'
1820 self.scheme = 'bundle'
1755 path = path[7:]
1821 path = path[7:]
1756 if path.startswith('//'):
1822 if path.startswith('//'):
1757 path = path[2:]
1823 path = path[2:]
1758 self.path = path
1824 self.path = path
1759 return
1825 return
1760
1826
1761 if self._matchscheme(path):
1827 if self._matchscheme(path):
1762 parts = path.split(':', 1)
1828 parts = path.split(':', 1)
1763 if parts[0]:
1829 if parts[0]:
1764 self.scheme, path = parts
1830 self.scheme, path = parts
1765 self._localpath = False
1831 self._localpath = False
1766
1832
1767 if not path:
1833 if not path:
1768 path = None
1834 path = None
1769 if self._localpath:
1835 if self._localpath:
1770 self.path = ''
1836 self.path = ''
1771 return
1837 return
1772 else:
1838 else:
1773 if self._localpath:
1839 if self._localpath:
1774 self.path = path
1840 self.path = path
1775 return
1841 return
1776
1842
1777 if parsequery and '?' in path:
1843 if parsequery and '?' in path:
1778 path, self.query = path.split('?', 1)
1844 path, self.query = path.split('?', 1)
1779 if not path:
1845 if not path:
1780 path = None
1846 path = None
1781 if not self.query:
1847 if not self.query:
1782 self.query = None
1848 self.query = None
1783
1849
1784 # // is required to specify a host/authority
1850 # // is required to specify a host/authority
1785 if path and path.startswith('//'):
1851 if path and path.startswith('//'):
1786 parts = path[2:].split('/', 1)
1852 parts = path[2:].split('/', 1)
1787 if len(parts) > 1:
1853 if len(parts) > 1:
1788 self.host, path = parts
1854 self.host, path = parts
1789 else:
1855 else:
1790 self.host = parts[0]
1856 self.host = parts[0]
1791 path = None
1857 path = None
1792 if not self.host:
1858 if not self.host:
1793 self.host = None
1859 self.host = None
1794 # path of file:///d is /d
1860 # path of file:///d is /d
1795 # path of file:///d:/ is d:/, not /d:/
1861 # path of file:///d:/ is d:/, not /d:/
1796 if path and not hasdriveletter(path):
1862 if path and not hasdriveletter(path):
1797 path = '/' + path
1863 path = '/' + path
1798
1864
1799 if self.host and '@' in self.host:
1865 if self.host and '@' in self.host:
1800 self.user, self.host = self.host.rsplit('@', 1)
1866 self.user, self.host = self.host.rsplit('@', 1)
1801 if ':' in self.user:
1867 if ':' in self.user:
1802 self.user, self.passwd = self.user.split(':', 1)
1868 self.user, self.passwd = self.user.split(':', 1)
1803 if not self.host:
1869 if not self.host:
1804 self.host = None
1870 self.host = None
1805
1871
1806 # Don't split on colons in IPv6 addresses without ports
1872 # Don't split on colons in IPv6 addresses without ports
1807 if (self.host and ':' in self.host and
1873 if (self.host and ':' in self.host and
1808 not (self.host.startswith('[') and self.host.endswith(']'))):
1874 not (self.host.startswith('[') and self.host.endswith(']'))):
1809 self._hostport = self.host
1875 self._hostport = self.host
1810 self.host, self.port = self.host.rsplit(':', 1)
1876 self.host, self.port = self.host.rsplit(':', 1)
1811 if not self.host:
1877 if not self.host:
1812 self.host = None
1878 self.host = None
1813
1879
1814 if (self.host and self.scheme == 'file' and
1880 if (self.host and self.scheme == 'file' and
1815 self.host not in ('localhost', '127.0.0.1', '[::1]')):
1881 self.host not in ('localhost', '127.0.0.1', '[::1]')):
1816 raise Abort(_('file:// URLs can only refer to localhost'))
1882 raise Abort(_('file:// URLs can only refer to localhost'))
1817
1883
1818 self.path = path
1884 self.path = path
1819
1885
1820 # leave the query string escaped
1886 # leave the query string escaped
1821 for a in ('user', 'passwd', 'host', 'port',
1887 for a in ('user', 'passwd', 'host', 'port',
1822 'path', 'fragment'):
1888 'path', 'fragment'):
1823 v = getattr(self, a)
1889 v = getattr(self, a)
1824 if v is not None:
1890 if v is not None:
1825 setattr(self, a, _urlunquote(v))
1891 setattr(self, a, _urlunquote(v))
1826
1892
1827 def __repr__(self):
1893 def __repr__(self):
1828 attrs = []
1894 attrs = []
1829 for a in ('scheme', 'user', 'passwd', 'host', 'port', 'path',
1895 for a in ('scheme', 'user', 'passwd', 'host', 'port', 'path',
1830 'query', 'fragment'):
1896 'query', 'fragment'):
1831 v = getattr(self, a)
1897 v = getattr(self, a)
1832 if v is not None:
1898 if v is not None:
1833 attrs.append('%s: %r' % (a, v))
1899 attrs.append('%s: %r' % (a, v))
1834 return '<url %s>' % ', '.join(attrs)
1900 return '<url %s>' % ', '.join(attrs)
1835
1901
1836 def __str__(self):
1902 def __str__(self):
1837 r"""Join the URL's components back into a URL string.
1903 r"""Join the URL's components back into a URL string.
1838
1904
1839 Examples:
1905 Examples:
1840
1906
1841 >>> str(url('http://user:pw@host:80/c:/bob?fo:oo#ba:ar'))
1907 >>> str(url('http://user:pw@host:80/c:/bob?fo:oo#ba:ar'))
1842 'http://user:pw@host:80/c:/bob?fo:oo#ba:ar'
1908 'http://user:pw@host:80/c:/bob?fo:oo#ba:ar'
1843 >>> str(url('http://user:pw@host:80/?foo=bar&baz=42'))
1909 >>> str(url('http://user:pw@host:80/?foo=bar&baz=42'))
1844 'http://user:pw@host:80/?foo=bar&baz=42'
1910 'http://user:pw@host:80/?foo=bar&baz=42'
1845 >>> str(url('http://user:pw@host:80/?foo=bar%3dbaz'))
1911 >>> str(url('http://user:pw@host:80/?foo=bar%3dbaz'))
1846 'http://user:pw@host:80/?foo=bar%3dbaz'
1912 'http://user:pw@host:80/?foo=bar%3dbaz'
1847 >>> str(url('ssh://user:pw@[::1]:2200//home/joe#'))
1913 >>> str(url('ssh://user:pw@[::1]:2200//home/joe#'))
1848 'ssh://user:pw@[::1]:2200//home/joe#'
1914 'ssh://user:pw@[::1]:2200//home/joe#'
1849 >>> str(url('http://localhost:80//'))
1915 >>> str(url('http://localhost:80//'))
1850 'http://localhost:80//'
1916 'http://localhost:80//'
1851 >>> str(url('http://localhost:80/'))
1917 >>> str(url('http://localhost:80/'))
1852 'http://localhost:80/'
1918 'http://localhost:80/'
1853 >>> str(url('http://localhost:80'))
1919 >>> str(url('http://localhost:80'))
1854 'http://localhost:80/'
1920 'http://localhost:80/'
1855 >>> str(url('bundle:foo'))
1921 >>> str(url('bundle:foo'))
1856 'bundle:foo'
1922 'bundle:foo'
1857 >>> str(url('bundle://../foo'))
1923 >>> str(url('bundle://../foo'))
1858 'bundle:../foo'
1924 'bundle:../foo'
1859 >>> str(url('path'))
1925 >>> str(url('path'))
1860 'path'
1926 'path'
1861 >>> str(url('file:///tmp/foo/bar'))
1927 >>> str(url('file:///tmp/foo/bar'))
1862 'file:///tmp/foo/bar'
1928 'file:///tmp/foo/bar'
1863 >>> str(url('file:///c:/tmp/foo/bar'))
1929 >>> str(url('file:///c:/tmp/foo/bar'))
1864 'file:///c:/tmp/foo/bar'
1930 'file:///c:/tmp/foo/bar'
1865 >>> print url(r'bundle:foo\bar')
1931 >>> print url(r'bundle:foo\bar')
1866 bundle:foo\bar
1932 bundle:foo\bar
1867 >>> print url(r'file:///D:\data\hg')
1933 >>> print url(r'file:///D:\data\hg')
1868 file:///D:\data\hg
1934 file:///D:\data\hg
1869 """
1935 """
1870 if self._localpath:
1936 if self._localpath:
1871 s = self.path
1937 s = self.path
1872 if self.scheme == 'bundle':
1938 if self.scheme == 'bundle':
1873 s = 'bundle:' + s
1939 s = 'bundle:' + s
1874 if self.fragment:
1940 if self.fragment:
1875 s += '#' + self.fragment
1941 s += '#' + self.fragment
1876 return s
1942 return s
1877
1943
1878 s = self.scheme + ':'
1944 s = self.scheme + ':'
1879 if self.user or self.passwd or self.host:
1945 if self.user or self.passwd or self.host:
1880 s += '//'
1946 s += '//'
1881 elif self.scheme and (not self.path or self.path.startswith('/')
1947 elif self.scheme and (not self.path or self.path.startswith('/')
1882 or hasdriveletter(self.path)):
1948 or hasdriveletter(self.path)):
1883 s += '//'
1949 s += '//'
1884 if hasdriveletter(self.path):
1950 if hasdriveletter(self.path):
1885 s += '/'
1951 s += '/'
1886 if self.user:
1952 if self.user:
1887 s += urllib.quote(self.user, safe=self._safechars)
1953 s += urllib.quote(self.user, safe=self._safechars)
1888 if self.passwd:
1954 if self.passwd:
1889 s += ':' + urllib.quote(self.passwd, safe=self._safechars)
1955 s += ':' + urllib.quote(self.passwd, safe=self._safechars)
1890 if self.user or self.passwd:
1956 if self.user or self.passwd:
1891 s += '@'
1957 s += '@'
1892 if self.host:
1958 if self.host:
1893 if not (self.host.startswith('[') and self.host.endswith(']')):
1959 if not (self.host.startswith('[') and self.host.endswith(']')):
1894 s += urllib.quote(self.host)
1960 s += urllib.quote(self.host)
1895 else:
1961 else:
1896 s += self.host
1962 s += self.host
1897 if self.port:
1963 if self.port:
1898 s += ':' + urllib.quote(self.port)
1964 s += ':' + urllib.quote(self.port)
1899 if self.host:
1965 if self.host:
1900 s += '/'
1966 s += '/'
1901 if self.path:
1967 if self.path:
1902 # TODO: similar to the query string, we should not unescape the
1968 # TODO: similar to the query string, we should not unescape the
1903 # path when we store it, the path might contain '%2f' = '/',
1969 # path when we store it, the path might contain '%2f' = '/',
1904 # which we should *not* escape.
1970 # which we should *not* escape.
1905 s += urllib.quote(self.path, safe=self._safepchars)
1971 s += urllib.quote(self.path, safe=self._safepchars)
1906 if self.query:
1972 if self.query:
1907 # we store the query in escaped form.
1973 # we store the query in escaped form.
1908 s += '?' + self.query
1974 s += '?' + self.query
1909 if self.fragment is not None:
1975 if self.fragment is not None:
1910 s += '#' + urllib.quote(self.fragment, safe=self._safepchars)
1976 s += '#' + urllib.quote(self.fragment, safe=self._safepchars)
1911 return s
1977 return s
1912
1978
1913 def authinfo(self):
1979 def authinfo(self):
1914 user, passwd = self.user, self.passwd
1980 user, passwd = self.user, self.passwd
1915 try:
1981 try:
1916 self.user, self.passwd = None, None
1982 self.user, self.passwd = None, None
1917 s = str(self)
1983 s = str(self)
1918 finally:
1984 finally:
1919 self.user, self.passwd = user, passwd
1985 self.user, self.passwd = user, passwd
1920 if not self.user:
1986 if not self.user:
1921 return (s, None)
1987 return (s, None)
1922 # authinfo[1] is passed to urllib2 password manager, and its
1988 # authinfo[1] is passed to urllib2 password manager, and its
1923 # URIs must not contain credentials. The host is passed in the
1989 # URIs must not contain credentials. The host is passed in the
1924 # URIs list because Python < 2.4.3 uses only that to search for
1990 # URIs list because Python < 2.4.3 uses only that to search for
1925 # a password.
1991 # a password.
1926 return (s, (None, (s, self.host),
1992 return (s, (None, (s, self.host),
1927 self.user, self.passwd or ''))
1993 self.user, self.passwd or ''))
1928
1994
1929 def isabs(self):
1995 def isabs(self):
1930 if self.scheme and self.scheme != 'file':
1996 if self.scheme and self.scheme != 'file':
1931 return True # remote URL
1997 return True # remote URL
1932 if hasdriveletter(self.path):
1998 if hasdriveletter(self.path):
1933 return True # absolute for our purposes - can't be joined()
1999 return True # absolute for our purposes - can't be joined()
1934 if self.path.startswith(r'\\'):
2000 if self.path.startswith(r'\\'):
1935 return True # Windows UNC path
2001 return True # Windows UNC path
1936 if self.path.startswith('/'):
2002 if self.path.startswith('/'):
1937 return True # POSIX-style
2003 return True # POSIX-style
1938 return False
2004 return False
1939
2005
1940 def localpath(self):
2006 def localpath(self):
1941 if self.scheme == 'file' or self.scheme == 'bundle':
2007 if self.scheme == 'file' or self.scheme == 'bundle':
1942 path = self.path or '/'
2008 path = self.path or '/'
1943 # For Windows, we need to promote hosts containing drive
2009 # For Windows, we need to promote hosts containing drive
1944 # letters to paths with drive letters.
2010 # letters to paths with drive letters.
1945 if hasdriveletter(self._hostport):
2011 if hasdriveletter(self._hostport):
1946 path = self._hostport + '/' + self.path
2012 path = self._hostport + '/' + self.path
1947 elif (self.host is not None and self.path
2013 elif (self.host is not None and self.path
1948 and not hasdriveletter(path)):
2014 and not hasdriveletter(path)):
1949 path = '/' + path
2015 path = '/' + path
1950 return path
2016 return path
1951 return self._origpath
2017 return self._origpath
1952
2018
1953 def islocal(self):
2019 def islocal(self):
1954 '''whether localpath will return something that posixfile can open'''
2020 '''whether localpath will return something that posixfile can open'''
1955 return (not self.scheme or self.scheme == 'file'
2021 return (not self.scheme or self.scheme == 'file'
1956 or self.scheme == 'bundle')
2022 or self.scheme == 'bundle')
1957
2023
1958 def hasscheme(path):
2024 def hasscheme(path):
1959 return bool(url(path).scheme)
2025 return bool(url(path).scheme)
1960
2026
1961 def hasdriveletter(path):
2027 def hasdriveletter(path):
1962 return path and path[1:2] == ':' and path[0:1].isalpha()
2028 return path and path[1:2] == ':' and path[0:1].isalpha()
1963
2029
1964 def urllocalpath(path):
2030 def urllocalpath(path):
1965 return url(path, parsequery=False, parsefragment=False).localpath()
2031 return url(path, parsequery=False, parsefragment=False).localpath()
1966
2032
1967 def hidepassword(u):
2033 def hidepassword(u):
1968 '''hide user credential in a url string'''
2034 '''hide user credential in a url string'''
1969 u = url(u)
2035 u = url(u)
1970 if u.passwd:
2036 if u.passwd:
1971 u.passwd = '***'
2037 u.passwd = '***'
1972 return str(u)
2038 return str(u)
1973
2039
1974 def removeauth(u):
2040 def removeauth(u):
1975 '''remove all authentication information from a url string'''
2041 '''remove all authentication information from a url string'''
1976 u = url(u)
2042 u = url(u)
1977 u.user = u.passwd = None
2043 u.user = u.passwd = None
1978 return str(u)
2044 return str(u)
1979
2045
1980 def isatty(fd):
2046 def isatty(fd):
1981 try:
2047 try:
1982 return fd.isatty()
2048 return fd.isatty()
1983 except AttributeError:
2049 except AttributeError:
1984 return False
2050 return False
1985
2051
1986 timecount = unitcountfn(
2052 timecount = unitcountfn(
1987 (1, 1e3, _('%.0f s')),
2053 (1, 1e3, _('%.0f s')),
1988 (100, 1, _('%.1f s')),
2054 (100, 1, _('%.1f s')),
1989 (10, 1, _('%.2f s')),
2055 (10, 1, _('%.2f s')),
1990 (1, 1, _('%.3f s')),
2056 (1, 1, _('%.3f s')),
1991 (100, 0.001, _('%.1f ms')),
2057 (100, 0.001, _('%.1f ms')),
1992 (10, 0.001, _('%.2f ms')),
2058 (10, 0.001, _('%.2f ms')),
1993 (1, 0.001, _('%.3f ms')),
2059 (1, 0.001, _('%.3f ms')),
1994 (100, 0.000001, _('%.1f us')),
2060 (100, 0.000001, _('%.1f us')),
1995 (10, 0.000001, _('%.2f us')),
2061 (10, 0.000001, _('%.2f us')),
1996 (1, 0.000001, _('%.3f us')),
2062 (1, 0.000001, _('%.3f us')),
1997 (100, 0.000000001, _('%.1f ns')),
2063 (100, 0.000000001, _('%.1f ns')),
1998 (10, 0.000000001, _('%.2f ns')),
2064 (10, 0.000000001, _('%.2f ns')),
1999 (1, 0.000000001, _('%.3f ns')),
2065 (1, 0.000000001, _('%.3f ns')),
2000 )
2066 )
2001
2067
2002 _timenesting = [0]
2068 _timenesting = [0]
2003
2069
2004 def timed(func):
2070 def timed(func):
2005 '''Report the execution time of a function call to stderr.
2071 '''Report the execution time of a function call to stderr.
2006
2072
2007 During development, use as a decorator when you need to measure
2073 During development, use as a decorator when you need to measure
2008 the cost of a function, e.g. as follows:
2074 the cost of a function, e.g. as follows:
2009
2075
2010 @util.timed
2076 @util.timed
2011 def foo(a, b, c):
2077 def foo(a, b, c):
2012 pass
2078 pass
2013 '''
2079 '''
2014
2080
2015 def wrapper(*args, **kwargs):
2081 def wrapper(*args, **kwargs):
2016 start = time.time()
2082 start = time.time()
2017 indent = 2
2083 indent = 2
2018 _timenesting[0] += indent
2084 _timenesting[0] += indent
2019 try:
2085 try:
2020 return func(*args, **kwargs)
2086 return func(*args, **kwargs)
2021 finally:
2087 finally:
2022 elapsed = time.time() - start
2088 elapsed = time.time() - start
2023 _timenesting[0] -= indent
2089 _timenesting[0] -= indent
2024 sys.stderr.write('%s%s: %s\n' %
2090 sys.stderr.write('%s%s: %s\n' %
2025 (' ' * _timenesting[0], func.__name__,
2091 (' ' * _timenesting[0], func.__name__,
2026 timecount(elapsed)))
2092 timecount(elapsed)))
2027 return wrapper
2093 return wrapper
2028
2094
2029 _sizeunits = (('m', 2**20), ('k', 2**10), ('g', 2**30),
2095 _sizeunits = (('m', 2**20), ('k', 2**10), ('g', 2**30),
2030 ('kb', 2**10), ('mb', 2**20), ('gb', 2**30), ('b', 1))
2096 ('kb', 2**10), ('mb', 2**20), ('gb', 2**30), ('b', 1))
2031
2097
2032 def sizetoint(s):
2098 def sizetoint(s):
2033 '''Convert a space specifier to a byte count.
2099 '''Convert a space specifier to a byte count.
2034
2100
2035 >>> sizetoint('30')
2101 >>> sizetoint('30')
2036 30
2102 30
2037 >>> sizetoint('2.2kb')
2103 >>> sizetoint('2.2kb')
2038 2252
2104 2252
2039 >>> sizetoint('6M')
2105 >>> sizetoint('6M')
2040 6291456
2106 6291456
2041 '''
2107 '''
2042 t = s.strip().lower()
2108 t = s.strip().lower()
2043 try:
2109 try:
2044 for k, u in _sizeunits:
2110 for k, u in _sizeunits:
2045 if t.endswith(k):
2111 if t.endswith(k):
2046 return int(float(t[:-len(k)]) * u)
2112 return int(float(t[:-len(k)]) * u)
2047 return int(t)
2113 return int(t)
2048 except ValueError:
2114 except ValueError:
2049 raise error.ParseError(_("couldn't parse size: %s") % s)
2115 raise error.ParseError(_("couldn't parse size: %s") % s)
2050
2116
2051 class hooks(object):
2117 class hooks(object):
2052 '''A collection of hook functions that can be used to extend a
2118 '''A collection of hook functions that can be used to extend a
2053 function's behaviour. Hooks are called in lexicographic order,
2119 function's behaviour. Hooks are called in lexicographic order,
2054 based on the names of their sources.'''
2120 based on the names of their sources.'''
2055
2121
2056 def __init__(self):
2122 def __init__(self):
2057 self._hooks = []
2123 self._hooks = []
2058
2124
2059 def add(self, source, hook):
2125 def add(self, source, hook):
2060 self._hooks.append((source, hook))
2126 self._hooks.append((source, hook))
2061
2127
2062 def __call__(self, *args):
2128 def __call__(self, *args):
2063 self._hooks.sort(key=lambda x: x[0])
2129 self._hooks.sort(key=lambda x: x[0])
2064 results = []
2130 results = []
2065 for source, hook in self._hooks:
2131 for source, hook in self._hooks:
2066 results.append(hook(*args))
2132 results.append(hook(*args))
2067 return results
2133 return results
2068
2134
2069 def debugstacktrace(msg='stacktrace', skip=0, f=sys.stderr, otherf=sys.stdout):
2135 def debugstacktrace(msg='stacktrace', skip=0, f=sys.stderr, otherf=sys.stdout):
2070 '''Writes a message to f (stderr) with a nicely formatted stacktrace.
2136 '''Writes a message to f (stderr) with a nicely formatted stacktrace.
2071 Skips the 'skip' last entries. By default it will flush stdout first.
2137 Skips the 'skip' last entries. By default it will flush stdout first.
2072 It can be used everywhere and do intentionally not require an ui object.
2138 It can be used everywhere and do intentionally not require an ui object.
2073 Not be used in production code but very convenient while developing.
2139 Not be used in production code but very convenient while developing.
2074 '''
2140 '''
2075 if otherf:
2141 if otherf:
2076 otherf.flush()
2142 otherf.flush()
2077 f.write('%s at:\n' % msg)
2143 f.write('%s at:\n' % msg)
2078 entries = [('%s:%s' % (fn, ln), func)
2144 entries = [('%s:%s' % (fn, ln), func)
2079 for fn, ln, func, _text in traceback.extract_stack()[:-skip - 1]]
2145 for fn, ln, func, _text in traceback.extract_stack()[:-skip - 1]]
2080 if entries:
2146 if entries:
2081 fnmax = max(len(entry[0]) for entry in entries)
2147 fnmax = max(len(entry[0]) for entry in entries)
2082 for fnln, func in entries:
2148 for fnln, func in entries:
2083 f.write(' %-*s in %s\n' % (fnmax, fnln, func))
2149 f.write(' %-*s in %s\n' % (fnmax, fnln, func))
2084 f.flush()
2150 f.flush()
2085
2151
2086 # convenient shortcut
2152 # convenient shortcut
2087 dst = debugstacktrace
2153 dst = debugstacktrace
General Comments 0
You need to be logged in to leave comments. Login now