##// END OF EJS Templates
Add functions for transcoding and manipulating multibyte strings
Matt Mackall -
r3770:f96c158e default
parent child Browse files
Show More
@@ -1,1108 +1,1160 b''
1 """
1 """
2 util.py - Mercurial utility functions and platform specfic implementations
2 util.py - Mercurial utility functions and platform specfic implementations
3
3
4 Copyright 2005 K. Thananchayan <thananck@yahoo.com>
4 Copyright 2005 K. Thananchayan <thananck@yahoo.com>
5 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
6 Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
6 Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
7
7
8 This software may be used and distributed according to the terms
8 This software may be used and distributed according to the terms
9 of the GNU General Public License, incorporated herein by reference.
9 of the GNU General Public License, incorporated herein by reference.
10
10
11 This contains helper routines that are independent of the SCM core and hide
11 This contains helper routines that are independent of the SCM core and hide
12 platform-specific details from the core.
12 platform-specific details from the core.
13 """
13 """
14
14
15 from i18n import gettext as _
15 from i18n import gettext as _
16 from demandload import *
16 from demandload import *
17 demandload(globals(), "cStringIO errno getpass popen2 re shutil sys tempfile")
17 demandload(globals(), "cStringIO errno getpass popen2 re shutil sys tempfile")
18 demandload(globals(), "os threading time calendar ConfigParser locale")
18 demandload(globals(), "os threading time calendar ConfigParser locale")
19
19
20 _encoding = os.environ.get("HGENCODING") or locale.getpreferredencoding()
20 _encoding = os.environ.get("HGENCODING") or locale.getpreferredencoding()
21 _encodingmode = os.environ.get("HGENCODINGMODE", "strict")
22
23 def tolocal(s):
24 """
25 Convert a string from internal UTF-8 to local encoding
26
27 All internal strings should be UTF-8 but some repos before the
28 implementation of locale support may contain latin1 or possibly
29 other character sets. We attempt to decode everything strictly
30 using UTF-8, then Latin-1, and failing that, we use UTF-8 and
31 replace unknown characters.
32 """
33 for e in "utf-8 latin1".split():
34 try:
35 u = s.decode(e) # attempt strict decoding
36 return u.encode(_encoding, "replace")
37 except UnicodeDecodeError:
38 pass
39 u = s.decode("utf-8", "replace") # last ditch
40 return u.encode(_encoding, "replace")
41
42 def fromlocal(s):
43 """
44 Convert a string from the local character encoding to UTF-8
45
46 We attempt to decode strings using the encoding mode set by
47 HG_ENCODINGMODE, which defaults to 'strict'. In this mode, unknown
48 characters will cause an error message. Other modes include
49 'replace', which replaces unknown characters with a special
50 Unicode character, and 'ignore', which drops the character.
51 """
52 try:
53 return s.decode(_encoding, _encodingmode).encode("utf-8")
54 except UnicodeDecodeError, inst:
55 sub = s[max(0, inst.start-10):inst.start+10]
56 raise Abort("decoding near '%s': %s!\n" % (sub, inst))
57
58 def locallen(s):
59 """Find the length in characters of a local string"""
60 return len(s.decode(_encoding, "replace"))
61
62 def localsub(s, a, b=None):
63 try:
64 u = s.decode(_encoding, _encodingmode)
65 if b is not None:
66 u = u[a:b]
67 else:
68 u = u[:a]
69 return u.encode(_encoding, _encodingmode)
70 except UnicodeDecodeError, inst:
71 sub = s[max(0, inst.start-10), inst.start+10]
72 raise Abort("decoding near '%s': %s!\n" % (sub, inst))
21
73
22 # used by parsedate
74 # used by parsedate
23 defaultdateformats = ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M',
75 defaultdateformats = ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M',
24 '%a %b %d %H:%M:%S %Y')
76 '%a %b %d %H:%M:%S %Y')
25
77
26 class SignalInterrupt(Exception):
78 class SignalInterrupt(Exception):
27 """Exception raised on SIGTERM and SIGHUP."""
79 """Exception raised on SIGTERM and SIGHUP."""
28
80
29 # like SafeConfigParser but with case-sensitive keys
81 # like SafeConfigParser but with case-sensitive keys
30 class configparser(ConfigParser.SafeConfigParser):
82 class configparser(ConfigParser.SafeConfigParser):
31 def optionxform(self, optionstr):
83 def optionxform(self, optionstr):
32 return optionstr
84 return optionstr
33
85
34 def cachefunc(func):
86 def cachefunc(func):
35 '''cache the result of function calls'''
87 '''cache the result of function calls'''
36 # XXX doesn't handle keywords args
88 # XXX doesn't handle keywords args
37 cache = {}
89 cache = {}
38 if func.func_code.co_argcount == 1:
90 if func.func_code.co_argcount == 1:
39 # we gain a small amount of time because
91 # we gain a small amount of time because
40 # we don't need to pack/unpack the list
92 # we don't need to pack/unpack the list
41 def f(arg):
93 def f(arg):
42 if arg not in cache:
94 if arg not in cache:
43 cache[arg] = func(arg)
95 cache[arg] = func(arg)
44 return cache[arg]
96 return cache[arg]
45 else:
97 else:
46 def f(*args):
98 def f(*args):
47 if args not in cache:
99 if args not in cache:
48 cache[args] = func(*args)
100 cache[args] = func(*args)
49 return cache[args]
101 return cache[args]
50
102
51 return f
103 return f
52
104
53 def pipefilter(s, cmd):
105 def pipefilter(s, cmd):
54 '''filter string S through command CMD, returning its output'''
106 '''filter string S through command CMD, returning its output'''
55 (pout, pin) = popen2.popen2(cmd, -1, 'b')
107 (pout, pin) = popen2.popen2(cmd, -1, 'b')
56 def writer():
108 def writer():
57 try:
109 try:
58 pin.write(s)
110 pin.write(s)
59 pin.close()
111 pin.close()
60 except IOError, inst:
112 except IOError, inst:
61 if inst.errno != errno.EPIPE:
113 if inst.errno != errno.EPIPE:
62 raise
114 raise
63
115
64 # we should use select instead on UNIX, but this will work on most
116 # we should use select instead on UNIX, but this will work on most
65 # systems, including Windows
117 # systems, including Windows
66 w = threading.Thread(target=writer)
118 w = threading.Thread(target=writer)
67 w.start()
119 w.start()
68 f = pout.read()
120 f = pout.read()
69 pout.close()
121 pout.close()
70 w.join()
122 w.join()
71 return f
123 return f
72
124
73 def tempfilter(s, cmd):
125 def tempfilter(s, cmd):
74 '''filter string S through a pair of temporary files with CMD.
126 '''filter string S through a pair of temporary files with CMD.
75 CMD is used as a template to create the real command to be run,
127 CMD is used as a template to create the real command to be run,
76 with the strings INFILE and OUTFILE replaced by the real names of
128 with the strings INFILE and OUTFILE replaced by the real names of
77 the temporary files generated.'''
129 the temporary files generated.'''
78 inname, outname = None, None
130 inname, outname = None, None
79 try:
131 try:
80 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
132 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
81 fp = os.fdopen(infd, 'wb')
133 fp = os.fdopen(infd, 'wb')
82 fp.write(s)
134 fp.write(s)
83 fp.close()
135 fp.close()
84 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
136 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
85 os.close(outfd)
137 os.close(outfd)
86 cmd = cmd.replace('INFILE', inname)
138 cmd = cmd.replace('INFILE', inname)
87 cmd = cmd.replace('OUTFILE', outname)
139 cmd = cmd.replace('OUTFILE', outname)
88 code = os.system(cmd)
140 code = os.system(cmd)
89 if code: raise Abort(_("command '%s' failed: %s") %
141 if code: raise Abort(_("command '%s' failed: %s") %
90 (cmd, explain_exit(code)))
142 (cmd, explain_exit(code)))
91 return open(outname, 'rb').read()
143 return open(outname, 'rb').read()
92 finally:
144 finally:
93 try:
145 try:
94 if inname: os.unlink(inname)
146 if inname: os.unlink(inname)
95 except: pass
147 except: pass
96 try:
148 try:
97 if outname: os.unlink(outname)
149 if outname: os.unlink(outname)
98 except: pass
150 except: pass
99
151
100 filtertable = {
152 filtertable = {
101 'tempfile:': tempfilter,
153 'tempfile:': tempfilter,
102 'pipe:': pipefilter,
154 'pipe:': pipefilter,
103 }
155 }
104
156
105 def filter(s, cmd):
157 def filter(s, cmd):
106 "filter a string through a command that transforms its input to its output"
158 "filter a string through a command that transforms its input to its output"
107 for name, fn in filtertable.iteritems():
159 for name, fn in filtertable.iteritems():
108 if cmd.startswith(name):
160 if cmd.startswith(name):
109 return fn(s, cmd[len(name):].lstrip())
161 return fn(s, cmd[len(name):].lstrip())
110 return pipefilter(s, cmd)
162 return pipefilter(s, cmd)
111
163
112 def find_in_path(name, path, default=None):
164 def find_in_path(name, path, default=None):
113 '''find name in search path. path can be string (will be split
165 '''find name in search path. path can be string (will be split
114 with os.pathsep), or iterable thing that returns strings. if name
166 with os.pathsep), or iterable thing that returns strings. if name
115 found, return path to name. else return default.'''
167 found, return path to name. else return default.'''
116 if isinstance(path, str):
168 if isinstance(path, str):
117 path = path.split(os.pathsep)
169 path = path.split(os.pathsep)
118 for p in path:
170 for p in path:
119 p_name = os.path.join(p, name)
171 p_name = os.path.join(p, name)
120 if os.path.exists(p_name):
172 if os.path.exists(p_name):
121 return p_name
173 return p_name
122 return default
174 return default
123
175
124 def binary(s):
176 def binary(s):
125 """return true if a string is binary data using diff's heuristic"""
177 """return true if a string is binary data using diff's heuristic"""
126 if s and '\0' in s[:4096]:
178 if s and '\0' in s[:4096]:
127 return True
179 return True
128 return False
180 return False
129
181
130 def unique(g):
182 def unique(g):
131 """return the uniq elements of iterable g"""
183 """return the uniq elements of iterable g"""
132 seen = {}
184 seen = {}
133 l = []
185 l = []
134 for f in g:
186 for f in g:
135 if f not in seen:
187 if f not in seen:
136 seen[f] = 1
188 seen[f] = 1
137 l.append(f)
189 l.append(f)
138 return l
190 return l
139
191
140 class Abort(Exception):
192 class Abort(Exception):
141 """Raised if a command needs to print an error and exit."""
193 """Raised if a command needs to print an error and exit."""
142
194
143 class UnexpectedOutput(Abort):
195 class UnexpectedOutput(Abort):
144 """Raised to print an error with part of output and exit."""
196 """Raised to print an error with part of output and exit."""
145
197
146 def always(fn): return True
198 def always(fn): return True
147 def never(fn): return False
199 def never(fn): return False
148
200
149 def patkind(name, dflt_pat='glob'):
201 def patkind(name, dflt_pat='glob'):
150 """Split a string into an optional pattern kind prefix and the
202 """Split a string into an optional pattern kind prefix and the
151 actual pattern."""
203 actual pattern."""
152 for prefix in 're', 'glob', 'path', 'relglob', 'relpath', 'relre':
204 for prefix in 're', 'glob', 'path', 'relglob', 'relpath', 'relre':
153 if name.startswith(prefix + ':'): return name.split(':', 1)
205 if name.startswith(prefix + ':'): return name.split(':', 1)
154 return dflt_pat, name
206 return dflt_pat, name
155
207
156 def globre(pat, head='^', tail='$'):
208 def globre(pat, head='^', tail='$'):
157 "convert a glob pattern into a regexp"
209 "convert a glob pattern into a regexp"
158 i, n = 0, len(pat)
210 i, n = 0, len(pat)
159 res = ''
211 res = ''
160 group = False
212 group = False
161 def peek(): return i < n and pat[i]
213 def peek(): return i < n and pat[i]
162 while i < n:
214 while i < n:
163 c = pat[i]
215 c = pat[i]
164 i = i+1
216 i = i+1
165 if c == '*':
217 if c == '*':
166 if peek() == '*':
218 if peek() == '*':
167 i += 1
219 i += 1
168 res += '.*'
220 res += '.*'
169 else:
221 else:
170 res += '[^/]*'
222 res += '[^/]*'
171 elif c == '?':
223 elif c == '?':
172 res += '.'
224 res += '.'
173 elif c == '[':
225 elif c == '[':
174 j = i
226 j = i
175 if j < n and pat[j] in '!]':
227 if j < n and pat[j] in '!]':
176 j += 1
228 j += 1
177 while j < n and pat[j] != ']':
229 while j < n and pat[j] != ']':
178 j += 1
230 j += 1
179 if j >= n:
231 if j >= n:
180 res += '\\['
232 res += '\\['
181 else:
233 else:
182 stuff = pat[i:j].replace('\\','\\\\')
234 stuff = pat[i:j].replace('\\','\\\\')
183 i = j + 1
235 i = j + 1
184 if stuff[0] == '!':
236 if stuff[0] == '!':
185 stuff = '^' + stuff[1:]
237 stuff = '^' + stuff[1:]
186 elif stuff[0] == '^':
238 elif stuff[0] == '^':
187 stuff = '\\' + stuff
239 stuff = '\\' + stuff
188 res = '%s[%s]' % (res, stuff)
240 res = '%s[%s]' % (res, stuff)
189 elif c == '{':
241 elif c == '{':
190 group = True
242 group = True
191 res += '(?:'
243 res += '(?:'
192 elif c == '}' and group:
244 elif c == '}' and group:
193 res += ')'
245 res += ')'
194 group = False
246 group = False
195 elif c == ',' and group:
247 elif c == ',' and group:
196 res += '|'
248 res += '|'
197 elif c == '\\':
249 elif c == '\\':
198 p = peek()
250 p = peek()
199 if p:
251 if p:
200 i += 1
252 i += 1
201 res += re.escape(p)
253 res += re.escape(p)
202 else:
254 else:
203 res += re.escape(c)
255 res += re.escape(c)
204 else:
256 else:
205 res += re.escape(c)
257 res += re.escape(c)
206 return head + res + tail
258 return head + res + tail
207
259
208 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
260 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
209
261
210 def pathto(n1, n2):
262 def pathto(n1, n2):
211 '''return the relative path from one place to another.
263 '''return the relative path from one place to another.
212 n1 should use os.sep to separate directories
264 n1 should use os.sep to separate directories
213 n2 should use "/" to separate directories
265 n2 should use "/" to separate directories
214 returns an os.sep-separated path.
266 returns an os.sep-separated path.
215 '''
267 '''
216 if not n1: return localpath(n2)
268 if not n1: return localpath(n2)
217 a, b = n1.split(os.sep), n2.split('/')
269 a, b = n1.split(os.sep), n2.split('/')
218 a.reverse()
270 a.reverse()
219 b.reverse()
271 b.reverse()
220 while a and b and a[-1] == b[-1]:
272 while a and b and a[-1] == b[-1]:
221 a.pop()
273 a.pop()
222 b.pop()
274 b.pop()
223 b.reverse()
275 b.reverse()
224 return os.sep.join((['..'] * len(a)) + b)
276 return os.sep.join((['..'] * len(a)) + b)
225
277
226 def canonpath(root, cwd, myname):
278 def canonpath(root, cwd, myname):
227 """return the canonical path of myname, given cwd and root"""
279 """return the canonical path of myname, given cwd and root"""
228 if root == os.sep:
280 if root == os.sep:
229 rootsep = os.sep
281 rootsep = os.sep
230 elif root.endswith(os.sep):
282 elif root.endswith(os.sep):
231 rootsep = root
283 rootsep = root
232 else:
284 else:
233 rootsep = root + os.sep
285 rootsep = root + os.sep
234 name = myname
286 name = myname
235 if not os.path.isabs(name):
287 if not os.path.isabs(name):
236 name = os.path.join(root, cwd, name)
288 name = os.path.join(root, cwd, name)
237 name = os.path.normpath(name)
289 name = os.path.normpath(name)
238 if name != rootsep and name.startswith(rootsep):
290 if name != rootsep and name.startswith(rootsep):
239 name = name[len(rootsep):]
291 name = name[len(rootsep):]
240 audit_path(name)
292 audit_path(name)
241 return pconvert(name)
293 return pconvert(name)
242 elif name == root:
294 elif name == root:
243 return ''
295 return ''
244 else:
296 else:
245 # Determine whether `name' is in the hierarchy at or beneath `root',
297 # Determine whether `name' is in the hierarchy at or beneath `root',
246 # by iterating name=dirname(name) until that causes no change (can't
298 # by iterating name=dirname(name) until that causes no change (can't
247 # check name == '/', because that doesn't work on windows). For each
299 # check name == '/', because that doesn't work on windows). For each
248 # `name', compare dev/inode numbers. If they match, the list `rel'
300 # `name', compare dev/inode numbers. If they match, the list `rel'
249 # holds the reversed list of components making up the relative file
301 # holds the reversed list of components making up the relative file
250 # name we want.
302 # name we want.
251 root_st = os.stat(root)
303 root_st = os.stat(root)
252 rel = []
304 rel = []
253 while True:
305 while True:
254 try:
306 try:
255 name_st = os.stat(name)
307 name_st = os.stat(name)
256 except OSError:
308 except OSError:
257 break
309 break
258 if samestat(name_st, root_st):
310 if samestat(name_st, root_st):
259 rel.reverse()
311 rel.reverse()
260 name = os.path.join(*rel)
312 name = os.path.join(*rel)
261 audit_path(name)
313 audit_path(name)
262 return pconvert(name)
314 return pconvert(name)
263 dirname, basename = os.path.split(name)
315 dirname, basename = os.path.split(name)
264 rel.append(basename)
316 rel.append(basename)
265 if dirname == name:
317 if dirname == name:
266 break
318 break
267 name = dirname
319 name = dirname
268
320
269 raise Abort('%s not under root' % myname)
321 raise Abort('%s not under root' % myname)
270
322
271 def matcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None):
323 def matcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None):
272 return _matcher(canonroot, cwd, names, inc, exc, head, 'glob', src)
324 return _matcher(canonroot, cwd, names, inc, exc, head, 'glob', src)
273
325
274 def cmdmatcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None):
326 def cmdmatcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None):
275 if os.name == 'nt':
327 if os.name == 'nt':
276 dflt_pat = 'glob'
328 dflt_pat = 'glob'
277 else:
329 else:
278 dflt_pat = 'relpath'
330 dflt_pat = 'relpath'
279 return _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src)
331 return _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src)
280
332
281 def _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src):
333 def _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src):
282 """build a function to match a set of file patterns
334 """build a function to match a set of file patterns
283
335
284 arguments:
336 arguments:
285 canonroot - the canonical root of the tree you're matching against
337 canonroot - the canonical root of the tree you're matching against
286 cwd - the current working directory, if relevant
338 cwd - the current working directory, if relevant
287 names - patterns to find
339 names - patterns to find
288 inc - patterns to include
340 inc - patterns to include
289 exc - patterns to exclude
341 exc - patterns to exclude
290 head - a regex to prepend to patterns to control whether a match is rooted
342 head - a regex to prepend to patterns to control whether a match is rooted
291
343
292 a pattern is one of:
344 a pattern is one of:
293 'glob:<rooted glob>'
345 'glob:<rooted glob>'
294 're:<rooted regexp>'
346 're:<rooted regexp>'
295 'path:<rooted path>'
347 'path:<rooted path>'
296 'relglob:<relative glob>'
348 'relglob:<relative glob>'
297 'relpath:<relative path>'
349 'relpath:<relative path>'
298 'relre:<relative regexp>'
350 'relre:<relative regexp>'
299 '<rooted path or regexp>'
351 '<rooted path or regexp>'
300
352
301 returns:
353 returns:
302 a 3-tuple containing
354 a 3-tuple containing
303 - list of explicit non-pattern names passed in
355 - list of explicit non-pattern names passed in
304 - a bool match(filename) function
356 - a bool match(filename) function
305 - a bool indicating if any patterns were passed in
357 - a bool indicating if any patterns were passed in
306
358
307 todo:
359 todo:
308 make head regex a rooted bool
360 make head regex a rooted bool
309 """
361 """
310
362
311 def contains_glob(name):
363 def contains_glob(name):
312 for c in name:
364 for c in name:
313 if c in _globchars: return True
365 if c in _globchars: return True
314 return False
366 return False
315
367
316 def regex(kind, name, tail):
368 def regex(kind, name, tail):
317 '''convert a pattern into a regular expression'''
369 '''convert a pattern into a regular expression'''
318 if kind == 're':
370 if kind == 're':
319 return name
371 return name
320 elif kind == 'path':
372 elif kind == 'path':
321 return '^' + re.escape(name) + '(?:/|$)'
373 return '^' + re.escape(name) + '(?:/|$)'
322 elif kind == 'relglob':
374 elif kind == 'relglob':
323 return head + globre(name, '(?:|.*/)', tail)
375 return head + globre(name, '(?:|.*/)', tail)
324 elif kind == 'relpath':
376 elif kind == 'relpath':
325 return head + re.escape(name) + tail
377 return head + re.escape(name) + tail
326 elif kind == 'relre':
378 elif kind == 'relre':
327 if name.startswith('^'):
379 if name.startswith('^'):
328 return name
380 return name
329 return '.*' + name
381 return '.*' + name
330 return head + globre(name, '', tail)
382 return head + globre(name, '', tail)
331
383
332 def matchfn(pats, tail):
384 def matchfn(pats, tail):
333 """build a matching function from a set of patterns"""
385 """build a matching function from a set of patterns"""
334 if not pats:
386 if not pats:
335 return
387 return
336 matches = []
388 matches = []
337 for k, p in pats:
389 for k, p in pats:
338 try:
390 try:
339 pat = '(?:%s)' % regex(k, p, tail)
391 pat = '(?:%s)' % regex(k, p, tail)
340 matches.append(re.compile(pat).match)
392 matches.append(re.compile(pat).match)
341 except re.error:
393 except re.error:
342 if src: raise Abort("%s: invalid pattern (%s): %s" % (src, k, p))
394 if src: raise Abort("%s: invalid pattern (%s): %s" % (src, k, p))
343 else: raise Abort("invalid pattern (%s): %s" % (k, p))
395 else: raise Abort("invalid pattern (%s): %s" % (k, p))
344
396
345 def buildfn(text):
397 def buildfn(text):
346 for m in matches:
398 for m in matches:
347 r = m(text)
399 r = m(text)
348 if r:
400 if r:
349 return r
401 return r
350
402
351 return buildfn
403 return buildfn
352
404
353 def globprefix(pat):
405 def globprefix(pat):
354 '''return the non-glob prefix of a path, e.g. foo/* -> foo'''
406 '''return the non-glob prefix of a path, e.g. foo/* -> foo'''
355 root = []
407 root = []
356 for p in pat.split(os.sep):
408 for p in pat.split(os.sep):
357 if contains_glob(p): break
409 if contains_glob(p): break
358 root.append(p)
410 root.append(p)
359 return '/'.join(root)
411 return '/'.join(root)
360
412
361 pats = []
413 pats = []
362 files = []
414 files = []
363 roots = []
415 roots = []
364 for kind, name in [patkind(p, dflt_pat) for p in names]:
416 for kind, name in [patkind(p, dflt_pat) for p in names]:
365 if kind in ('glob', 'relpath'):
417 if kind in ('glob', 'relpath'):
366 name = canonpath(canonroot, cwd, name)
418 name = canonpath(canonroot, cwd, name)
367 if name == '':
419 if name == '':
368 kind, name = 'glob', '**'
420 kind, name = 'glob', '**'
369 if kind in ('glob', 'path', 're'):
421 if kind in ('glob', 'path', 're'):
370 pats.append((kind, name))
422 pats.append((kind, name))
371 if kind == 'glob':
423 if kind == 'glob':
372 root = globprefix(name)
424 root = globprefix(name)
373 if root: roots.append(root)
425 if root: roots.append(root)
374 elif kind == 'relpath':
426 elif kind == 'relpath':
375 files.append((kind, name))
427 files.append((kind, name))
376 roots.append(name)
428 roots.append(name)
377
429
378 patmatch = matchfn(pats, '$') or always
430 patmatch = matchfn(pats, '$') or always
379 filematch = matchfn(files, '(?:/|$)') or always
431 filematch = matchfn(files, '(?:/|$)') or always
380 incmatch = always
432 incmatch = always
381 if inc:
433 if inc:
382 inckinds = [patkind(canonpath(canonroot, cwd, i)) for i in inc]
434 inckinds = [patkind(canonpath(canonroot, cwd, i)) for i in inc]
383 incmatch = matchfn(inckinds, '(?:/|$)')
435 incmatch = matchfn(inckinds, '(?:/|$)')
384 excmatch = lambda fn: False
436 excmatch = lambda fn: False
385 if exc:
437 if exc:
386 exckinds = [patkind(canonpath(canonroot, cwd, x)) for x in exc]
438 exckinds = [patkind(canonpath(canonroot, cwd, x)) for x in exc]
387 excmatch = matchfn(exckinds, '(?:/|$)')
439 excmatch = matchfn(exckinds, '(?:/|$)')
388
440
389 return (roots,
441 return (roots,
390 lambda fn: (incmatch(fn) and not excmatch(fn) and
442 lambda fn: (incmatch(fn) and not excmatch(fn) and
391 (fn.endswith('/') or
443 (fn.endswith('/') or
392 (not pats and not files) or
444 (not pats and not files) or
393 (pats and patmatch(fn)) or
445 (pats and patmatch(fn)) or
394 (files and filematch(fn)))),
446 (files and filematch(fn)))),
395 (inc or exc or (pats and pats != [('glob', '**')])) and True)
447 (inc or exc or (pats and pats != [('glob', '**')])) and True)
396
448
397 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
449 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
398 '''enhanced shell command execution.
450 '''enhanced shell command execution.
399 run with environment maybe modified, maybe in different dir.
451 run with environment maybe modified, maybe in different dir.
400
452
401 if command fails and onerr is None, return status. if ui object,
453 if command fails and onerr is None, return status. if ui object,
402 print error message and return status, else raise onerr object as
454 print error message and return status, else raise onerr object as
403 exception.'''
455 exception.'''
404 def py2shell(val):
456 def py2shell(val):
405 'convert python object into string that is useful to shell'
457 'convert python object into string that is useful to shell'
406 if val in (None, False):
458 if val in (None, False):
407 return '0'
459 return '0'
408 if val == True:
460 if val == True:
409 return '1'
461 return '1'
410 return str(val)
462 return str(val)
411 oldenv = {}
463 oldenv = {}
412 for k in environ:
464 for k in environ:
413 oldenv[k] = os.environ.get(k)
465 oldenv[k] = os.environ.get(k)
414 if cwd is not None:
466 if cwd is not None:
415 oldcwd = os.getcwd()
467 oldcwd = os.getcwd()
416 try:
468 try:
417 for k, v in environ.iteritems():
469 for k, v in environ.iteritems():
418 os.environ[k] = py2shell(v)
470 os.environ[k] = py2shell(v)
419 if cwd is not None and oldcwd != cwd:
471 if cwd is not None and oldcwd != cwd:
420 os.chdir(cwd)
472 os.chdir(cwd)
421 rc = os.system(cmd)
473 rc = os.system(cmd)
422 if rc and onerr:
474 if rc and onerr:
423 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
475 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
424 explain_exit(rc)[0])
476 explain_exit(rc)[0])
425 if errprefix:
477 if errprefix:
426 errmsg = '%s: %s' % (errprefix, errmsg)
478 errmsg = '%s: %s' % (errprefix, errmsg)
427 try:
479 try:
428 onerr.warn(errmsg + '\n')
480 onerr.warn(errmsg + '\n')
429 except AttributeError:
481 except AttributeError:
430 raise onerr(errmsg)
482 raise onerr(errmsg)
431 return rc
483 return rc
432 finally:
484 finally:
433 for k, v in oldenv.iteritems():
485 for k, v in oldenv.iteritems():
434 if v is None:
486 if v is None:
435 del os.environ[k]
487 del os.environ[k]
436 else:
488 else:
437 os.environ[k] = v
489 os.environ[k] = v
438 if cwd is not None and oldcwd != cwd:
490 if cwd is not None and oldcwd != cwd:
439 os.chdir(oldcwd)
491 os.chdir(oldcwd)
440
492
441 def rename(src, dst):
493 def rename(src, dst):
442 """forcibly rename a file"""
494 """forcibly rename a file"""
443 try:
495 try:
444 os.rename(src, dst)
496 os.rename(src, dst)
445 except OSError, err:
497 except OSError, err:
446 # on windows, rename to existing file is not allowed, so we
498 # on windows, rename to existing file is not allowed, so we
447 # must delete destination first. but if file is open, unlink
499 # must delete destination first. but if file is open, unlink
448 # schedules it for delete but does not delete it. rename
500 # schedules it for delete but does not delete it. rename
449 # happens immediately even for open files, so we create
501 # happens immediately even for open files, so we create
450 # temporary file, delete it, rename destination to that name,
502 # temporary file, delete it, rename destination to that name,
451 # then delete that. then rename is safe to do.
503 # then delete that. then rename is safe to do.
452 fd, temp = tempfile.mkstemp(dir=os.path.dirname(dst) or '.')
504 fd, temp = tempfile.mkstemp(dir=os.path.dirname(dst) or '.')
453 os.close(fd)
505 os.close(fd)
454 os.unlink(temp)
506 os.unlink(temp)
455 os.rename(dst, temp)
507 os.rename(dst, temp)
456 os.unlink(temp)
508 os.unlink(temp)
457 os.rename(src, dst)
509 os.rename(src, dst)
458
510
459 def unlink(f):
511 def unlink(f):
460 """unlink and remove the directory if it is empty"""
512 """unlink and remove the directory if it is empty"""
461 os.unlink(f)
513 os.unlink(f)
462 # try removing directories that might now be empty
514 # try removing directories that might now be empty
463 try:
515 try:
464 os.removedirs(os.path.dirname(f))
516 os.removedirs(os.path.dirname(f))
465 except OSError:
517 except OSError:
466 pass
518 pass
467
519
468 def copyfile(src, dest):
520 def copyfile(src, dest):
469 "copy a file, preserving mode"
521 "copy a file, preserving mode"
470 try:
522 try:
471 shutil.copyfile(src, dest)
523 shutil.copyfile(src, dest)
472 shutil.copymode(src, dest)
524 shutil.copymode(src, dest)
473 except shutil.Error, inst:
525 except shutil.Error, inst:
474 raise util.Abort(str(inst))
526 raise util.Abort(str(inst))
475
527
476 def copyfiles(src, dst, hardlink=None):
528 def copyfiles(src, dst, hardlink=None):
477 """Copy a directory tree using hardlinks if possible"""
529 """Copy a directory tree using hardlinks if possible"""
478
530
479 if hardlink is None:
531 if hardlink is None:
480 hardlink = (os.stat(src).st_dev ==
532 hardlink = (os.stat(src).st_dev ==
481 os.stat(os.path.dirname(dst)).st_dev)
533 os.stat(os.path.dirname(dst)).st_dev)
482
534
483 if os.path.isdir(src):
535 if os.path.isdir(src):
484 os.mkdir(dst)
536 os.mkdir(dst)
485 for name in os.listdir(src):
537 for name in os.listdir(src):
486 srcname = os.path.join(src, name)
538 srcname = os.path.join(src, name)
487 dstname = os.path.join(dst, name)
539 dstname = os.path.join(dst, name)
488 copyfiles(srcname, dstname, hardlink)
540 copyfiles(srcname, dstname, hardlink)
489 else:
541 else:
490 if hardlink:
542 if hardlink:
491 try:
543 try:
492 os_link(src, dst)
544 os_link(src, dst)
493 except (IOError, OSError):
545 except (IOError, OSError):
494 hardlink = False
546 hardlink = False
495 shutil.copy(src, dst)
547 shutil.copy(src, dst)
496 else:
548 else:
497 shutil.copy(src, dst)
549 shutil.copy(src, dst)
498
550
499 def audit_path(path):
551 def audit_path(path):
500 """Abort if path contains dangerous components"""
552 """Abort if path contains dangerous components"""
501 parts = os.path.normcase(path).split(os.sep)
553 parts = os.path.normcase(path).split(os.sep)
502 if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '')
554 if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '')
503 or os.pardir in parts):
555 or os.pardir in parts):
504 raise Abort(_("path contains illegal component: %s\n") % path)
556 raise Abort(_("path contains illegal component: %s\n") % path)
505
557
506 def _makelock_file(info, pathname):
558 def _makelock_file(info, pathname):
507 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
559 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
508 os.write(ld, info)
560 os.write(ld, info)
509 os.close(ld)
561 os.close(ld)
510
562
511 def _readlock_file(pathname):
563 def _readlock_file(pathname):
512 return posixfile(pathname).read()
564 return posixfile(pathname).read()
513
565
514 def nlinks(pathname):
566 def nlinks(pathname):
515 """Return number of hardlinks for the given file."""
567 """Return number of hardlinks for the given file."""
516 return os.lstat(pathname).st_nlink
568 return os.lstat(pathname).st_nlink
517
569
518 if hasattr(os, 'link'):
570 if hasattr(os, 'link'):
519 os_link = os.link
571 os_link = os.link
520 else:
572 else:
521 def os_link(src, dst):
573 def os_link(src, dst):
522 raise OSError(0, _("Hardlinks not supported"))
574 raise OSError(0, _("Hardlinks not supported"))
523
575
524 def fstat(fp):
576 def fstat(fp):
525 '''stat file object that may not have fileno method.'''
577 '''stat file object that may not have fileno method.'''
526 try:
578 try:
527 return os.fstat(fp.fileno())
579 return os.fstat(fp.fileno())
528 except AttributeError:
580 except AttributeError:
529 return os.stat(fp.name)
581 return os.stat(fp.name)
530
582
531 posixfile = file
583 posixfile = file
532
584
533 def is_win_9x():
585 def is_win_9x():
534 '''return true if run on windows 95, 98 or me.'''
586 '''return true if run on windows 95, 98 or me.'''
535 try:
587 try:
536 return sys.getwindowsversion()[3] == 1
588 return sys.getwindowsversion()[3] == 1
537 except AttributeError:
589 except AttributeError:
538 return os.name == 'nt' and 'command' in os.environ.get('comspec', '')
590 return os.name == 'nt' and 'command' in os.environ.get('comspec', '')
539
591
540 getuser_fallback = None
592 getuser_fallback = None
541
593
542 def getuser():
594 def getuser():
543 '''return name of current user'''
595 '''return name of current user'''
544 try:
596 try:
545 return getpass.getuser()
597 return getpass.getuser()
546 except ImportError:
598 except ImportError:
547 # import of pwd will fail on windows - try fallback
599 # import of pwd will fail on windows - try fallback
548 if getuser_fallback:
600 if getuser_fallback:
549 return getuser_fallback()
601 return getuser_fallback()
550 # raised if win32api not available
602 # raised if win32api not available
551 raise Abort(_('user name not available - set USERNAME '
603 raise Abort(_('user name not available - set USERNAME '
552 'environment variable'))
604 'environment variable'))
553
605
554 def username(uid=None):
606 def username(uid=None):
555 """Return the name of the user with the given uid.
607 """Return the name of the user with the given uid.
556
608
557 If uid is None, return the name of the current user."""
609 If uid is None, return the name of the current user."""
558 try:
610 try:
559 import pwd
611 import pwd
560 if uid is None:
612 if uid is None:
561 uid = os.getuid()
613 uid = os.getuid()
562 try:
614 try:
563 return pwd.getpwuid(uid)[0]
615 return pwd.getpwuid(uid)[0]
564 except KeyError:
616 except KeyError:
565 return str(uid)
617 return str(uid)
566 except ImportError:
618 except ImportError:
567 return None
619 return None
568
620
569 def groupname(gid=None):
621 def groupname(gid=None):
570 """Return the name of the group with the given gid.
622 """Return the name of the group with the given gid.
571
623
572 If gid is None, return the name of the current group."""
624 If gid is None, return the name of the current group."""
573 try:
625 try:
574 import grp
626 import grp
575 if gid is None:
627 if gid is None:
576 gid = os.getgid()
628 gid = os.getgid()
577 try:
629 try:
578 return grp.getgrgid(gid)[0]
630 return grp.getgrgid(gid)[0]
579 except KeyError:
631 except KeyError:
580 return str(gid)
632 return str(gid)
581 except ImportError:
633 except ImportError:
582 return None
634 return None
583
635
584 # Platform specific variants
636 # Platform specific variants
585 if os.name == 'nt':
637 if os.name == 'nt':
586 demandload(globals(), "msvcrt")
638 demandload(globals(), "msvcrt")
587 nulldev = 'NUL:'
639 nulldev = 'NUL:'
588
640
589 class winstdout:
641 class winstdout:
590 '''stdout on windows misbehaves if sent through a pipe'''
642 '''stdout on windows misbehaves if sent through a pipe'''
591
643
592 def __init__(self, fp):
644 def __init__(self, fp):
593 self.fp = fp
645 self.fp = fp
594
646
595 def __getattr__(self, key):
647 def __getattr__(self, key):
596 return getattr(self.fp, key)
648 return getattr(self.fp, key)
597
649
598 def close(self):
650 def close(self):
599 try:
651 try:
600 self.fp.close()
652 self.fp.close()
601 except: pass
653 except: pass
602
654
603 def write(self, s):
655 def write(self, s):
604 try:
656 try:
605 return self.fp.write(s)
657 return self.fp.write(s)
606 except IOError, inst:
658 except IOError, inst:
607 if inst.errno != 0: raise
659 if inst.errno != 0: raise
608 self.close()
660 self.close()
609 raise IOError(errno.EPIPE, 'Broken pipe')
661 raise IOError(errno.EPIPE, 'Broken pipe')
610
662
611 sys.stdout = winstdout(sys.stdout)
663 sys.stdout = winstdout(sys.stdout)
612
664
613 def system_rcpath():
665 def system_rcpath():
614 try:
666 try:
615 return system_rcpath_win32()
667 return system_rcpath_win32()
616 except:
668 except:
617 return [r'c:\mercurial\mercurial.ini']
669 return [r'c:\mercurial\mercurial.ini']
618
670
619 def os_rcpath():
671 def os_rcpath():
620 '''return default os-specific hgrc search path'''
672 '''return default os-specific hgrc search path'''
621 path = system_rcpath()
673 path = system_rcpath()
622 path.append(user_rcpath())
674 path.append(user_rcpath())
623 userprofile = os.environ.get('USERPROFILE')
675 userprofile = os.environ.get('USERPROFILE')
624 if userprofile:
676 if userprofile:
625 path.append(os.path.join(userprofile, 'mercurial.ini'))
677 path.append(os.path.join(userprofile, 'mercurial.ini'))
626 return path
678 return path
627
679
628 def user_rcpath():
680 def user_rcpath():
629 '''return os-specific hgrc search path to the user dir'''
681 '''return os-specific hgrc search path to the user dir'''
630 return os.path.join(os.path.expanduser('~'), 'mercurial.ini')
682 return os.path.join(os.path.expanduser('~'), 'mercurial.ini')
631
683
632 def parse_patch_output(output_line):
684 def parse_patch_output(output_line):
633 """parses the output produced by patch and returns the file name"""
685 """parses the output produced by patch and returns the file name"""
634 pf = output_line[14:]
686 pf = output_line[14:]
635 if pf[0] == '`':
687 if pf[0] == '`':
636 pf = pf[1:-1] # Remove the quotes
688 pf = pf[1:-1] # Remove the quotes
637 return pf
689 return pf
638
690
639 def testpid(pid):
691 def testpid(pid):
640 '''return False if pid dead, True if running or not known'''
692 '''return False if pid dead, True if running or not known'''
641 return True
693 return True
642
694
643 def is_exec(f, last):
695 def is_exec(f, last):
644 return last
696 return last
645
697
646 def set_exec(f, mode):
698 def set_exec(f, mode):
647 pass
699 pass
648
700
649 def set_binary(fd):
701 def set_binary(fd):
650 msvcrt.setmode(fd.fileno(), os.O_BINARY)
702 msvcrt.setmode(fd.fileno(), os.O_BINARY)
651
703
652 def pconvert(path):
704 def pconvert(path):
653 return path.replace("\\", "/")
705 return path.replace("\\", "/")
654
706
655 def localpath(path):
707 def localpath(path):
656 return path.replace('/', '\\')
708 return path.replace('/', '\\')
657
709
658 def normpath(path):
710 def normpath(path):
659 return pconvert(os.path.normpath(path))
711 return pconvert(os.path.normpath(path))
660
712
661 makelock = _makelock_file
713 makelock = _makelock_file
662 readlock = _readlock_file
714 readlock = _readlock_file
663
715
664 def samestat(s1, s2):
716 def samestat(s1, s2):
665 return False
717 return False
666
718
667 def shellquote(s):
719 def shellquote(s):
668 return '"%s"' % s.replace('"', '\\"')
720 return '"%s"' % s.replace('"', '\\"')
669
721
670 def explain_exit(code):
722 def explain_exit(code):
671 return _("exited with status %d") % code, code
723 return _("exited with status %d") % code, code
672
724
673 # if you change this stub into a real check, please try to implement the
725 # if you change this stub into a real check, please try to implement the
674 # username and groupname functions above, too.
726 # username and groupname functions above, too.
675 def isowner(fp, st=None):
727 def isowner(fp, st=None):
676 return True
728 return True
677
729
678 try:
730 try:
679 # override functions with win32 versions if possible
731 # override functions with win32 versions if possible
680 from util_win32 import *
732 from util_win32 import *
681 if not is_win_9x():
733 if not is_win_9x():
682 posixfile = posixfile_nt
734 posixfile = posixfile_nt
683 except ImportError:
735 except ImportError:
684 pass
736 pass
685
737
686 else:
738 else:
687 nulldev = '/dev/null'
739 nulldev = '/dev/null'
688
740
689 def rcfiles(path):
741 def rcfiles(path):
690 rcs = [os.path.join(path, 'hgrc')]
742 rcs = [os.path.join(path, 'hgrc')]
691 rcdir = os.path.join(path, 'hgrc.d')
743 rcdir = os.path.join(path, 'hgrc.d')
692 try:
744 try:
693 rcs.extend([os.path.join(rcdir, f) for f in os.listdir(rcdir)
745 rcs.extend([os.path.join(rcdir, f) for f in os.listdir(rcdir)
694 if f.endswith(".rc")])
746 if f.endswith(".rc")])
695 except OSError:
747 except OSError:
696 pass
748 pass
697 return rcs
749 return rcs
698
750
699 def os_rcpath():
751 def os_rcpath():
700 '''return default os-specific hgrc search path'''
752 '''return default os-specific hgrc search path'''
701 path = []
753 path = []
702 # old mod_python does not set sys.argv
754 # old mod_python does not set sys.argv
703 if len(getattr(sys, 'argv', [])) > 0:
755 if len(getattr(sys, 'argv', [])) > 0:
704 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
756 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
705 '/../etc/mercurial'))
757 '/../etc/mercurial'))
706 path.extend(rcfiles('/etc/mercurial'))
758 path.extend(rcfiles('/etc/mercurial'))
707 path.append(os.path.expanduser('~/.hgrc'))
759 path.append(os.path.expanduser('~/.hgrc'))
708 path = [os.path.normpath(f) for f in path]
760 path = [os.path.normpath(f) for f in path]
709 return path
761 return path
710
762
711 def parse_patch_output(output_line):
763 def parse_patch_output(output_line):
712 """parses the output produced by patch and returns the file name"""
764 """parses the output produced by patch and returns the file name"""
713 pf = output_line[14:]
765 pf = output_line[14:]
714 if pf.startswith("'") and pf.endswith("'") and " " in pf:
766 if pf.startswith("'") and pf.endswith("'") and " " in pf:
715 pf = pf[1:-1] # Remove the quotes
767 pf = pf[1:-1] # Remove the quotes
716 return pf
768 return pf
717
769
718 def is_exec(f, last):
770 def is_exec(f, last):
719 """check whether a file is executable"""
771 """check whether a file is executable"""
720 return (os.lstat(f).st_mode & 0100 != 0)
772 return (os.lstat(f).st_mode & 0100 != 0)
721
773
722 def set_exec(f, mode):
774 def set_exec(f, mode):
723 s = os.lstat(f).st_mode
775 s = os.lstat(f).st_mode
724 if (s & 0100 != 0) == mode:
776 if (s & 0100 != 0) == mode:
725 return
777 return
726 if mode:
778 if mode:
727 # Turn on +x for every +r bit when making a file executable
779 # Turn on +x for every +r bit when making a file executable
728 # and obey umask.
780 # and obey umask.
729 umask = os.umask(0)
781 umask = os.umask(0)
730 os.umask(umask)
782 os.umask(umask)
731 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
783 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
732 else:
784 else:
733 os.chmod(f, s & 0666)
785 os.chmod(f, s & 0666)
734
786
735 def set_binary(fd):
787 def set_binary(fd):
736 pass
788 pass
737
789
738 def pconvert(path):
790 def pconvert(path):
739 return path
791 return path
740
792
741 def localpath(path):
793 def localpath(path):
742 return path
794 return path
743
795
744 normpath = os.path.normpath
796 normpath = os.path.normpath
745 samestat = os.path.samestat
797 samestat = os.path.samestat
746
798
747 def makelock(info, pathname):
799 def makelock(info, pathname):
748 try:
800 try:
749 os.symlink(info, pathname)
801 os.symlink(info, pathname)
750 except OSError, why:
802 except OSError, why:
751 if why.errno == errno.EEXIST:
803 if why.errno == errno.EEXIST:
752 raise
804 raise
753 else:
805 else:
754 _makelock_file(info, pathname)
806 _makelock_file(info, pathname)
755
807
756 def readlock(pathname):
808 def readlock(pathname):
757 try:
809 try:
758 return os.readlink(pathname)
810 return os.readlink(pathname)
759 except OSError, why:
811 except OSError, why:
760 if why.errno == errno.EINVAL:
812 if why.errno == errno.EINVAL:
761 return _readlock_file(pathname)
813 return _readlock_file(pathname)
762 else:
814 else:
763 raise
815 raise
764
816
765 def shellquote(s):
817 def shellquote(s):
766 return "'%s'" % s.replace("'", "'\\''")
818 return "'%s'" % s.replace("'", "'\\''")
767
819
768 def testpid(pid):
820 def testpid(pid):
769 '''return False if pid dead, True if running or not sure'''
821 '''return False if pid dead, True if running or not sure'''
770 try:
822 try:
771 os.kill(pid, 0)
823 os.kill(pid, 0)
772 return True
824 return True
773 except OSError, inst:
825 except OSError, inst:
774 return inst.errno != errno.ESRCH
826 return inst.errno != errno.ESRCH
775
827
776 def explain_exit(code):
828 def explain_exit(code):
777 """return a 2-tuple (desc, code) describing a process's status"""
829 """return a 2-tuple (desc, code) describing a process's status"""
778 if os.WIFEXITED(code):
830 if os.WIFEXITED(code):
779 val = os.WEXITSTATUS(code)
831 val = os.WEXITSTATUS(code)
780 return _("exited with status %d") % val, val
832 return _("exited with status %d") % val, val
781 elif os.WIFSIGNALED(code):
833 elif os.WIFSIGNALED(code):
782 val = os.WTERMSIG(code)
834 val = os.WTERMSIG(code)
783 return _("killed by signal %d") % val, val
835 return _("killed by signal %d") % val, val
784 elif os.WIFSTOPPED(code):
836 elif os.WIFSTOPPED(code):
785 val = os.WSTOPSIG(code)
837 val = os.WSTOPSIG(code)
786 return _("stopped by signal %d") % val, val
838 return _("stopped by signal %d") % val, val
787 raise ValueError(_("invalid exit code"))
839 raise ValueError(_("invalid exit code"))
788
840
789 def isowner(fp, st=None):
841 def isowner(fp, st=None):
790 """Return True if the file object f belongs to the current user.
842 """Return True if the file object f belongs to the current user.
791
843
792 The return value of a util.fstat(f) may be passed as the st argument.
844 The return value of a util.fstat(f) may be passed as the st argument.
793 """
845 """
794 if st is None:
846 if st is None:
795 st = fstat(f)
847 st = fstat(f)
796 return st.st_uid == os.getuid()
848 return st.st_uid == os.getuid()
797
849
798
850
799 def opener(base, audit=True):
851 def opener(base, audit=True):
800 """
852 """
801 return a function that opens files relative to base
853 return a function that opens files relative to base
802
854
803 this function is used to hide the details of COW semantics and
855 this function is used to hide the details of COW semantics and
804 remote file access from higher level code.
856 remote file access from higher level code.
805 """
857 """
806 p = base
858 p = base
807 audit_p = audit
859 audit_p = audit
808
860
809 def mktempcopy(name):
861 def mktempcopy(name):
810 d, fn = os.path.split(name)
862 d, fn = os.path.split(name)
811 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
863 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
812 os.close(fd)
864 os.close(fd)
813 ofp = posixfile(temp, "wb")
865 ofp = posixfile(temp, "wb")
814 try:
866 try:
815 try:
867 try:
816 ifp = posixfile(name, "rb")
868 ifp = posixfile(name, "rb")
817 except IOError, inst:
869 except IOError, inst:
818 if not getattr(inst, 'filename', None):
870 if not getattr(inst, 'filename', None):
819 inst.filename = name
871 inst.filename = name
820 raise
872 raise
821 for chunk in filechunkiter(ifp):
873 for chunk in filechunkiter(ifp):
822 ofp.write(chunk)
874 ofp.write(chunk)
823 ifp.close()
875 ifp.close()
824 ofp.close()
876 ofp.close()
825 except:
877 except:
826 try: os.unlink(temp)
878 try: os.unlink(temp)
827 except: pass
879 except: pass
828 raise
880 raise
829 st = os.lstat(name)
881 st = os.lstat(name)
830 os.chmod(temp, st.st_mode)
882 os.chmod(temp, st.st_mode)
831 return temp
883 return temp
832
884
833 class atomictempfile(posixfile):
885 class atomictempfile(posixfile):
834 """the file will only be copied when rename is called"""
886 """the file will only be copied when rename is called"""
835 def __init__(self, name, mode):
887 def __init__(self, name, mode):
836 self.__name = name
888 self.__name = name
837 self.temp = mktempcopy(name)
889 self.temp = mktempcopy(name)
838 posixfile.__init__(self, self.temp, mode)
890 posixfile.__init__(self, self.temp, mode)
839 def rename(self):
891 def rename(self):
840 if not self.closed:
892 if not self.closed:
841 posixfile.close(self)
893 posixfile.close(self)
842 rename(self.temp, localpath(self.__name))
894 rename(self.temp, localpath(self.__name))
843 def __del__(self):
895 def __del__(self):
844 if not self.closed:
896 if not self.closed:
845 try:
897 try:
846 os.unlink(self.temp)
898 os.unlink(self.temp)
847 except: pass
899 except: pass
848 posixfile.close(self)
900 posixfile.close(self)
849
901
850 class atomicfile(atomictempfile):
902 class atomicfile(atomictempfile):
851 """the file will only be copied on close"""
903 """the file will only be copied on close"""
852 def __init__(self, name, mode):
904 def __init__(self, name, mode):
853 atomictempfile.__init__(self, name, mode)
905 atomictempfile.__init__(self, name, mode)
854 def close(self):
906 def close(self):
855 self.rename()
907 self.rename()
856 def __del__(self):
908 def __del__(self):
857 self.rename()
909 self.rename()
858
910
859 def o(path, mode="r", text=False, atomic=False, atomictemp=False):
911 def o(path, mode="r", text=False, atomic=False, atomictemp=False):
860 if audit_p:
912 if audit_p:
861 audit_path(path)
913 audit_path(path)
862 f = os.path.join(p, path)
914 f = os.path.join(p, path)
863
915
864 if not text:
916 if not text:
865 mode += "b" # for that other OS
917 mode += "b" # for that other OS
866
918
867 if mode[0] != "r":
919 if mode[0] != "r":
868 try:
920 try:
869 nlink = nlinks(f)
921 nlink = nlinks(f)
870 except OSError:
922 except OSError:
871 d = os.path.dirname(f)
923 d = os.path.dirname(f)
872 if not os.path.isdir(d):
924 if not os.path.isdir(d):
873 os.makedirs(d)
925 os.makedirs(d)
874 else:
926 else:
875 if atomic:
927 if atomic:
876 return atomicfile(f, mode)
928 return atomicfile(f, mode)
877 elif atomictemp:
929 elif atomictemp:
878 return atomictempfile(f, mode)
930 return atomictempfile(f, mode)
879 if nlink > 1:
931 if nlink > 1:
880 rename(mktempcopy(f), f)
932 rename(mktempcopy(f), f)
881 return posixfile(f, mode)
933 return posixfile(f, mode)
882
934
883 return o
935 return o
884
936
885 class chunkbuffer(object):
937 class chunkbuffer(object):
886 """Allow arbitrary sized chunks of data to be efficiently read from an
938 """Allow arbitrary sized chunks of data to be efficiently read from an
887 iterator over chunks of arbitrary size."""
939 iterator over chunks of arbitrary size."""
888
940
889 def __init__(self, in_iter, targetsize = 2**16):
941 def __init__(self, in_iter, targetsize = 2**16):
890 """in_iter is the iterator that's iterating over the input chunks.
942 """in_iter is the iterator that's iterating over the input chunks.
891 targetsize is how big a buffer to try to maintain."""
943 targetsize is how big a buffer to try to maintain."""
892 self.in_iter = iter(in_iter)
944 self.in_iter = iter(in_iter)
893 self.buf = ''
945 self.buf = ''
894 self.targetsize = int(targetsize)
946 self.targetsize = int(targetsize)
895 if self.targetsize <= 0:
947 if self.targetsize <= 0:
896 raise ValueError(_("targetsize must be greater than 0, was %d") %
948 raise ValueError(_("targetsize must be greater than 0, was %d") %
897 targetsize)
949 targetsize)
898 self.iterempty = False
950 self.iterempty = False
899
951
900 def fillbuf(self):
952 def fillbuf(self):
901 """Ignore target size; read every chunk from iterator until empty."""
953 """Ignore target size; read every chunk from iterator until empty."""
902 if not self.iterempty:
954 if not self.iterempty:
903 collector = cStringIO.StringIO()
955 collector = cStringIO.StringIO()
904 collector.write(self.buf)
956 collector.write(self.buf)
905 for ch in self.in_iter:
957 for ch in self.in_iter:
906 collector.write(ch)
958 collector.write(ch)
907 self.buf = collector.getvalue()
959 self.buf = collector.getvalue()
908 self.iterempty = True
960 self.iterempty = True
909
961
910 def read(self, l):
962 def read(self, l):
911 """Read L bytes of data from the iterator of chunks of data.
963 """Read L bytes of data from the iterator of chunks of data.
912 Returns less than L bytes if the iterator runs dry."""
964 Returns less than L bytes if the iterator runs dry."""
913 if l > len(self.buf) and not self.iterempty:
965 if l > len(self.buf) and not self.iterempty:
914 # Clamp to a multiple of self.targetsize
966 # Clamp to a multiple of self.targetsize
915 targetsize = self.targetsize * ((l // self.targetsize) + 1)
967 targetsize = self.targetsize * ((l // self.targetsize) + 1)
916 collector = cStringIO.StringIO()
968 collector = cStringIO.StringIO()
917 collector.write(self.buf)
969 collector.write(self.buf)
918 collected = len(self.buf)
970 collected = len(self.buf)
919 for chunk in self.in_iter:
971 for chunk in self.in_iter:
920 collector.write(chunk)
972 collector.write(chunk)
921 collected += len(chunk)
973 collected += len(chunk)
922 if collected >= targetsize:
974 if collected >= targetsize:
923 break
975 break
924 if collected < targetsize:
976 if collected < targetsize:
925 self.iterempty = True
977 self.iterempty = True
926 self.buf = collector.getvalue()
978 self.buf = collector.getvalue()
927 s, self.buf = self.buf[:l], buffer(self.buf, l)
979 s, self.buf = self.buf[:l], buffer(self.buf, l)
928 return s
980 return s
929
981
930 def filechunkiter(f, size=65536, limit=None):
982 def filechunkiter(f, size=65536, limit=None):
931 """Create a generator that produces the data in the file size
983 """Create a generator that produces the data in the file size
932 (default 65536) bytes at a time, up to optional limit (default is
984 (default 65536) bytes at a time, up to optional limit (default is
933 to read all data). Chunks may be less than size bytes if the
985 to read all data). Chunks may be less than size bytes if the
934 chunk is the last chunk in the file, or the file is a socket or
986 chunk is the last chunk in the file, or the file is a socket or
935 some other type of file that sometimes reads less data than is
987 some other type of file that sometimes reads less data than is
936 requested."""
988 requested."""
937 assert size >= 0
989 assert size >= 0
938 assert limit is None or limit >= 0
990 assert limit is None or limit >= 0
939 while True:
991 while True:
940 if limit is None: nbytes = size
992 if limit is None: nbytes = size
941 else: nbytes = min(limit, size)
993 else: nbytes = min(limit, size)
942 s = nbytes and f.read(nbytes)
994 s = nbytes and f.read(nbytes)
943 if not s: break
995 if not s: break
944 if limit: limit -= len(s)
996 if limit: limit -= len(s)
945 yield s
997 yield s
946
998
947 def makedate():
999 def makedate():
948 lt = time.localtime()
1000 lt = time.localtime()
949 if lt[8] == 1 and time.daylight:
1001 if lt[8] == 1 and time.daylight:
950 tz = time.altzone
1002 tz = time.altzone
951 else:
1003 else:
952 tz = time.timezone
1004 tz = time.timezone
953 return time.mktime(lt), tz
1005 return time.mktime(lt), tz
954
1006
955 def datestr(date=None, format='%a %b %d %H:%M:%S %Y', timezone=True):
1007 def datestr(date=None, format='%a %b %d %H:%M:%S %Y', timezone=True):
956 """represent a (unixtime, offset) tuple as a localized time.
1008 """represent a (unixtime, offset) tuple as a localized time.
957 unixtime is seconds since the epoch, and offset is the time zone's
1009 unixtime is seconds since the epoch, and offset is the time zone's
958 number of seconds away from UTC. if timezone is false, do not
1010 number of seconds away from UTC. if timezone is false, do not
959 append time zone to string."""
1011 append time zone to string."""
960 t, tz = date or makedate()
1012 t, tz = date or makedate()
961 s = time.strftime(format, time.gmtime(float(t) - tz))
1013 s = time.strftime(format, time.gmtime(float(t) - tz))
962 if timezone:
1014 if timezone:
963 s += " %+03d%02d" % (-tz / 3600, ((-tz % 3600) / 60))
1015 s += " %+03d%02d" % (-tz / 3600, ((-tz % 3600) / 60))
964 return s
1016 return s
965
1017
966 def strdate(string, format='%a %b %d %H:%M:%S %Y'):
1018 def strdate(string, format='%a %b %d %H:%M:%S %Y'):
967 """parse a localized time string and return a (unixtime, offset) tuple.
1019 """parse a localized time string and return a (unixtime, offset) tuple.
968 if the string cannot be parsed, ValueError is raised."""
1020 if the string cannot be parsed, ValueError is raised."""
969 def hastimezone(string):
1021 def hastimezone(string):
970 return (string[-4:].isdigit() and
1022 return (string[-4:].isdigit() and
971 (string[-5] == '+' or string[-5] == '-') and
1023 (string[-5] == '+' or string[-5] == '-') and
972 string[-6].isspace())
1024 string[-6].isspace())
973
1025
974 # NOTE: unixtime = localunixtime + offset
1026 # NOTE: unixtime = localunixtime + offset
975 if hastimezone(string):
1027 if hastimezone(string):
976 date, tz = string[:-6], string[-5:]
1028 date, tz = string[:-6], string[-5:]
977 tz = int(tz)
1029 tz = int(tz)
978 offset = - 3600 * (tz / 100) - 60 * (tz % 100)
1030 offset = - 3600 * (tz / 100) - 60 * (tz % 100)
979 else:
1031 else:
980 date, offset = string, None
1032 date, offset = string, None
981 timetuple = time.strptime(date, format)
1033 timetuple = time.strptime(date, format)
982 localunixtime = int(calendar.timegm(timetuple))
1034 localunixtime = int(calendar.timegm(timetuple))
983 if offset is None:
1035 if offset is None:
984 # local timezone
1036 # local timezone
985 unixtime = int(time.mktime(timetuple))
1037 unixtime = int(time.mktime(timetuple))
986 offset = unixtime - localunixtime
1038 offset = unixtime - localunixtime
987 else:
1039 else:
988 unixtime = localunixtime + offset
1040 unixtime = localunixtime + offset
989 return unixtime, offset
1041 return unixtime, offset
990
1042
991 def parsedate(string, formats=None):
1043 def parsedate(string, formats=None):
992 """parse a localized time string and return a (unixtime, offset) tuple.
1044 """parse a localized time string and return a (unixtime, offset) tuple.
993 The date may be a "unixtime offset" string or in one of the specified
1045 The date may be a "unixtime offset" string or in one of the specified
994 formats."""
1046 formats."""
995 if not formats:
1047 if not formats:
996 formats = defaultdateformats
1048 formats = defaultdateformats
997 try:
1049 try:
998 when, offset = map(int, string.split(' '))
1050 when, offset = map(int, string.split(' '))
999 except ValueError:
1051 except ValueError:
1000 for format in formats:
1052 for format in formats:
1001 try:
1053 try:
1002 when, offset = strdate(string, format)
1054 when, offset = strdate(string, format)
1003 except ValueError:
1055 except ValueError:
1004 pass
1056 pass
1005 else:
1057 else:
1006 break
1058 break
1007 else:
1059 else:
1008 raise ValueError(_('invalid date: %r '
1060 raise ValueError(_('invalid date: %r '
1009 'see hg(1) manual page for details')
1061 'see hg(1) manual page for details')
1010 % string)
1062 % string)
1011 # validate explicit (probably user-specified) date and
1063 # validate explicit (probably user-specified) date and
1012 # time zone offset. values must fit in signed 32 bits for
1064 # time zone offset. values must fit in signed 32 bits for
1013 # current 32-bit linux runtimes. timezones go from UTC-12
1065 # current 32-bit linux runtimes. timezones go from UTC-12
1014 # to UTC+14
1066 # to UTC+14
1015 if abs(when) > 0x7fffffff:
1067 if abs(when) > 0x7fffffff:
1016 raise ValueError(_('date exceeds 32 bits: %d') % when)
1068 raise ValueError(_('date exceeds 32 bits: %d') % when)
1017 if offset < -50400 or offset > 43200:
1069 if offset < -50400 or offset > 43200:
1018 raise ValueError(_('impossible time zone offset: %d') % offset)
1070 raise ValueError(_('impossible time zone offset: %d') % offset)
1019 return when, offset
1071 return when, offset
1020
1072
1021 def shortuser(user):
1073 def shortuser(user):
1022 """Return a short representation of a user name or email address."""
1074 """Return a short representation of a user name or email address."""
1023 f = user.find('@')
1075 f = user.find('@')
1024 if f >= 0:
1076 if f >= 0:
1025 user = user[:f]
1077 user = user[:f]
1026 f = user.find('<')
1078 f = user.find('<')
1027 if f >= 0:
1079 if f >= 0:
1028 user = user[f+1:]
1080 user = user[f+1:]
1029 f = user.find(' ')
1081 f = user.find(' ')
1030 if f >= 0:
1082 if f >= 0:
1031 user = user[:f]
1083 user = user[:f]
1032 f = user.find('.')
1084 f = user.find('.')
1033 if f >= 0:
1085 if f >= 0:
1034 user = user[:f]
1086 user = user[:f]
1035 return user
1087 return user
1036
1088
1037 def ellipsis(text, maxlength=400):
1089 def ellipsis(text, maxlength=400):
1038 """Trim string to at most maxlength (default: 400) characters."""
1090 """Trim string to at most maxlength (default: 400) characters."""
1039 if len(text) <= maxlength:
1091 if len(text) <= maxlength:
1040 return text
1092 return text
1041 else:
1093 else:
1042 return "%s..." % (text[:maxlength-3])
1094 return "%s..." % (text[:maxlength-3])
1043
1095
1044 def walkrepos(path):
1096 def walkrepos(path):
1045 '''yield every hg repository under path, recursively.'''
1097 '''yield every hg repository under path, recursively.'''
1046 def errhandler(err):
1098 def errhandler(err):
1047 if err.filename == path:
1099 if err.filename == path:
1048 raise err
1100 raise err
1049
1101
1050 for root, dirs, files in os.walk(path, onerror=errhandler):
1102 for root, dirs, files in os.walk(path, onerror=errhandler):
1051 for d in dirs:
1103 for d in dirs:
1052 if d == '.hg':
1104 if d == '.hg':
1053 yield root
1105 yield root
1054 dirs[:] = []
1106 dirs[:] = []
1055 break
1107 break
1056
1108
1057 _rcpath = None
1109 _rcpath = None
1058
1110
1059 def rcpath():
1111 def rcpath():
1060 '''return hgrc search path. if env var HGRCPATH is set, use it.
1112 '''return hgrc search path. if env var HGRCPATH is set, use it.
1061 for each item in path, if directory, use files ending in .rc,
1113 for each item in path, if directory, use files ending in .rc,
1062 else use item.
1114 else use item.
1063 make HGRCPATH empty to only look in .hg/hgrc of current repo.
1115 make HGRCPATH empty to only look in .hg/hgrc of current repo.
1064 if no HGRCPATH, use default os-specific path.'''
1116 if no HGRCPATH, use default os-specific path.'''
1065 global _rcpath
1117 global _rcpath
1066 if _rcpath is None:
1118 if _rcpath is None:
1067 if 'HGRCPATH' in os.environ:
1119 if 'HGRCPATH' in os.environ:
1068 _rcpath = []
1120 _rcpath = []
1069 for p in os.environ['HGRCPATH'].split(os.pathsep):
1121 for p in os.environ['HGRCPATH'].split(os.pathsep):
1070 if not p: continue
1122 if not p: continue
1071 if os.path.isdir(p):
1123 if os.path.isdir(p):
1072 for f in os.listdir(p):
1124 for f in os.listdir(p):
1073 if f.endswith('.rc'):
1125 if f.endswith('.rc'):
1074 _rcpath.append(os.path.join(p, f))
1126 _rcpath.append(os.path.join(p, f))
1075 else:
1127 else:
1076 _rcpath.append(p)
1128 _rcpath.append(p)
1077 else:
1129 else:
1078 _rcpath = os_rcpath()
1130 _rcpath = os_rcpath()
1079 return _rcpath
1131 return _rcpath
1080
1132
1081 def bytecount(nbytes):
1133 def bytecount(nbytes):
1082 '''return byte count formatted as readable string, with units'''
1134 '''return byte count formatted as readable string, with units'''
1083
1135
1084 units = (
1136 units = (
1085 (100, 1<<30, _('%.0f GB')),
1137 (100, 1<<30, _('%.0f GB')),
1086 (10, 1<<30, _('%.1f GB')),
1138 (10, 1<<30, _('%.1f GB')),
1087 (1, 1<<30, _('%.2f GB')),
1139 (1, 1<<30, _('%.2f GB')),
1088 (100, 1<<20, _('%.0f MB')),
1140 (100, 1<<20, _('%.0f MB')),
1089 (10, 1<<20, _('%.1f MB')),
1141 (10, 1<<20, _('%.1f MB')),
1090 (1, 1<<20, _('%.2f MB')),
1142 (1, 1<<20, _('%.2f MB')),
1091 (100, 1<<10, _('%.0f KB')),
1143 (100, 1<<10, _('%.0f KB')),
1092 (10, 1<<10, _('%.1f KB')),
1144 (10, 1<<10, _('%.1f KB')),
1093 (1, 1<<10, _('%.2f KB')),
1145 (1, 1<<10, _('%.2f KB')),
1094 (1, 1, _('%.0f bytes')),
1146 (1, 1, _('%.0f bytes')),
1095 )
1147 )
1096
1148
1097 for multiplier, divisor, format in units:
1149 for multiplier, divisor, format in units:
1098 if nbytes >= divisor * multiplier:
1150 if nbytes >= divisor * multiplier:
1099 return format % (nbytes / float(divisor))
1151 return format % (nbytes / float(divisor))
1100 return units[-1][2] % nbytes
1152 return units[-1][2] % nbytes
1101
1153
1102 def drop_scheme(scheme, path):
1154 def drop_scheme(scheme, path):
1103 sc = scheme + ':'
1155 sc = scheme + ':'
1104 if path.startswith(sc):
1156 if path.startswith(sc):
1105 path = path[len(sc):]
1157 path = path[len(sc):]
1106 if path.startswith('//'):
1158 if path.startswith('//'):
1107 path = path[2:]
1159 path = path[2:]
1108 return path
1160 return path
General Comments 0
You need to be logged in to leave comments. Login now