##// END OF EJS Templates
Merge with crew-stable
Merge with crew-stable

File last commit:

r5236:335696e2 merge default
r5247:20770c5d merge default
Show More
util.py
1683 lines | 52.2 KiB | text/x-python | PythonLexer
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 """
util.py - Mercurial utility functions and platform specfic implementations
Copyright 2005 K. Thananchayan <thananck@yahoo.com>
Thomas Arendsen Hein
Updated copyright notices and add "and others" to "hg version"
r4635 Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
Vadim Gelfer
update copyrights.
r2859 Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
This contains helper routines that are independent of the SCM core and hide
platform-specific details from the core.
"""
mpm@selenic.com
[PATCH] file seperator handling for the other 'OS'...
r419
Matt Mackall
Simplify i18n imports
r3891 from i18n import _
Bryan O'Sullivan
Make audit_path more stringent....
r5158 import cStringIO, errno, getpass, popen2, re, shutil, sys, tempfile, strutil
import os, stat, threading, time, calendar, ConfigParser, locale, glob
Matt Mackall
Add encoding detection
r3769
Alexis S. L. Carvalho
Fallback to ascii if getpreferredencoding raises an exception...
r4057 try:
Eric Hopper
Provide a version independent way to use the set datatype.
r4647 set = set
frozenset = frozenset
except NameError:
from sets import Set as set, ImmutableSet as frozenset
try:
Brendan Cully
Respect locale environment variables on darwin....
r4540 _encoding = os.environ.get("HGENCODING")
if sys.platform == 'darwin' and not _encoding:
# On darwin, getpreferredencoding ignores the locale environment and
# always returns mac-roman. We override this if the environment is
# not C (has been customized by the user).
locale.setlocale(locale.LC_CTYPE, '')
_encoding = locale.getlocale()[1]
if not _encoding:
_encoding = locale.getpreferredencoding() or 'ascii'
Alexis S. L. Carvalho
Fallback to ascii if getpreferredencoding raises an exception...
r4057 except locale.Error:
_encoding = 'ascii'
Matt Mackall
Add functions for transcoding and manipulating multibyte strings
r3770 _encodingmode = os.environ.get("HGENCODINGMODE", "strict")
Alexis S. L. Carvalho
Allow the user to specify the fallback encoding for the changelog...
r3835 _fallbackencoding = 'ISO-8859-1'
Matt Mackall
Add functions for transcoding and manipulating multibyte strings
r3770
def tolocal(s):
"""
Convert a string from internal UTF-8 to local encoding
All internal strings should be UTF-8 but some repos before the
implementation of locale support may contain latin1 or possibly
other character sets. We attempt to decode everything strictly
using UTF-8, then Latin-1, and failing that, we use UTF-8 and
replace unknown characters.
"""
Alexis S. L. Carvalho
Allow the user to specify the fallback encoding for the changelog...
r3835 for e in ('UTF-8', _fallbackencoding):
Matt Mackall
Add functions for transcoding and manipulating multibyte strings
r3770 try:
u = s.decode(e) # attempt strict decoding
return u.encode(_encoding, "replace")
Matt Mackall
make transcoding more robust...
r3843 except LookupError, k:
raise Abort(_("%s, please check your locale settings") % k)
Matt Mackall
Add functions for transcoding and manipulating multibyte strings
r3770 except UnicodeDecodeError:
pass
u = s.decode("utf-8", "replace") # last ditch
return u.encode(_encoding, "replace")
def fromlocal(s):
"""
Convert a string from the local character encoding to UTF-8
We attempt to decode strings using the encoding mode set by
Jesse Glick
typo fix
r4876 HGENCODINGMODE, which defaults to 'strict'. In this mode, unknown
Matt Mackall
Add functions for transcoding and manipulating multibyte strings
r3770 characters will cause an error message. Other modes include
'replace', which replaces unknown characters with a special
Unicode character, and 'ignore', which drops the character.
"""
try:
return s.decode(_encoding, _encodingmode).encode("utf-8")
except UnicodeDecodeError, inst:
sub = s[max(0, inst.start-10):inst.start+10]
Matt Mackall
make transcoding more robust...
r3843 raise Abort("decoding near '%s': %s!" % (sub, inst))
except LookupError, k:
raise Abort(_("%s, please check your locale settings") % k)
Matt Mackall
Add functions for transcoding and manipulating multibyte strings
r3770
def locallen(s):
"""Find the length in characters of a local string"""
return len(s.decode(_encoding, "replace"))
def localsub(s, a, b=None):
try:
u = s.decode(_encoding, _encodingmode)
if b is not None:
u = u[a:b]
else:
u = u[:a]
return u.encode(_encoding, _encodingmode)
except UnicodeDecodeError, inst:
sub = s[max(0, inst.start-10), inst.start+10]
Thomas Arendsen Hein
Removed trailing \n in calls to util.Abort()
r4533 raise Abort(_("decoding near '%s': %s!") % (sub, inst))
mpm@selenic.com
Add file encoding/decoding support
r1258
Chris Mason
util.parsedate should understand dates from hg export
r2609 # used by parsedate
Matt Mackall
improve date parsing for numerous new date formats...
r3808 defaultdateformats = (
'%Y-%m-%d %H:%M:%S',
'%Y-%m-%d %I:%M:%S%p',
'%Y-%m-%d %H:%M',
'%Y-%m-%d %I:%M%p',
'%Y-%m-%d',
'%m-%d',
'%m/%d',
'%m/%d/%y',
'%m/%d/%Y',
'%a %b %d %H:%M:%S %Y',
'%a %b %d %I:%M:%S%p %Y',
Markus F.X.J. Oberhumer
Add support for RFC2822 to util.parsedate().
r4708 '%a, %d %b %Y %H:%M:%S', # GNU coreutils "/bin/date --rfc-2822"
Matt Mackall
improve date parsing for numerous new date formats...
r3808 '%b %d %H:%M:%S %Y',
Matt Mackall
Add date matching support...
r3812 '%b %d %I:%M:%S%p %Y',
'%b %d %H:%M:%S',
Matt Mackall
improve date parsing for numerous new date formats...
r3808 '%b %d %I:%M:%S%p',
'%b %d %H:%M',
'%b %d %I:%M%p',
'%b %d %Y',
'%b %d',
'%H:%M:%S',
'%I:%M:%SP',
'%H:%M',
'%I:%M%p',
)
Chris Mason
util.parsedate should understand dates from hg export
r2609
Matt Mackall
Add date matching support...
r3812 extendeddateformats = defaultdateformats + (
"%Y",
"%Y-%m",
"%b",
"%b %Y",
)
Chris Mason
util.parsedate should understand dates from hg export
r2609
Vadim Gelfer
move SignalInterrupt class into util module.
r2153 class SignalInterrupt(Exception):
"""Exception raised on SIGTERM and SIGHUP."""
Alexis S. L. Carvalho
allow values that aren't strings in util.configparser
r4069 # differences from SafeConfigParser:
# - case-sensitive keys
# - allows values that are not strings (this means that you may not
# be able to save the configuration to a file)
Alexis S. L. Carvalho
Use a case-sensitive version of SafeConfigParser everywhere...
r3425 class configparser(ConfigParser.SafeConfigParser):
def optionxform(self, optionstr):
return optionstr
Alexis S. L. Carvalho
allow values that aren't strings in util.configparser
r4069 def set(self, section, option, value):
return ConfigParser.ConfigParser.set(self, section, option, value)
def _interpolate(self, section, option, rawval, vars):
if not isinstance(rawval, basestring):
return rawval
return ConfigParser.SafeConfigParser._interpolate(self, section,
option, rawval, vars)
Brendan Cully
Add cachefunc to abstract function call cache
r3145 def cachefunc(func):
'''cache the result of function calls'''
Benoit Boissinot
add comments in cachefunc
r3147 # XXX doesn't handle keywords args
Brendan Cully
Add cachefunc to abstract function call cache
r3145 cache = {}
if func.func_code.co_argcount == 1:
Benoit Boissinot
add comments in cachefunc
r3147 # we gain a small amount of time because
# we don't need to pack/unpack the list
Brendan Cully
Add cachefunc to abstract function call cache
r3145 def f(arg):
if arg not in cache:
cache[arg] = func(arg)
return cache[arg]
else:
def f(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return f
Bryan O'Sullivan
Enhance the file filtering capabilities....
r1293 def pipefilter(s, cmd):
'''filter string S through command CMD, returning its output'''
Brendan Cully
Work around heisenbug in Popen3.__del__
r4625 (pin, pout) = os.popen2(cmd, 'b')
mpm@selenic.com
Add file encoding/decoding support
r1258 def writer():
Alexis S. L. Carvalho
Ignore EPIPE in pipefilter...
r2096 try:
pin.write(s)
pin.close()
except IOError, inst:
if inst.errno != errno.EPIPE:
raise
mpm@selenic.com
Add file encoding/decoding support
r1258
# we should use select instead on UNIX, but this will work on most
# systems, including Windows
w = threading.Thread(target=writer)
w.start()
f = pout.read()
pout.close()
w.join()
return f
mpm@selenic.com
[PATCH] file seperator handling for the other 'OS'...
r419
Bryan O'Sullivan
Enhance the file filtering capabilities....
r1293 def tempfilter(s, cmd):
'''filter string S through a pair of temporary files with CMD.
CMD is used as a template to create the real command to be run,
with the strings INFILE and OUTFILE replaced by the real names of
the temporary files generated.'''
inname, outname = None, None
try:
Thomas Arendsen Hein
Use better names (hg-{usage}-{random}.{suffix}) for temporary files.
r2165 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
Bryan O'Sullivan
Enhance the file filtering capabilities....
r1293 fp = os.fdopen(infd, 'wb')
fp.write(s)
fp.close()
Thomas Arendsen Hein
Use better names (hg-{usage}-{random}.{suffix}) for temporary files.
r2165 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
Bryan O'Sullivan
Enhance the file filtering capabilities....
r1293 os.close(outfd)
cmd = cmd.replace('INFILE', inname)
cmd = cmd.replace('OUTFILE', outname)
code = os.system(cmd)
Jean-Francois PIERONNE
OpenVMS patches
r4720 if sys.platform == 'OpenVMS' and code & 1:
code = 0
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 if code: raise Abort(_("command '%s' failed: %s") %
Bryan O'Sullivan
Enhance the file filtering capabilities....
r1293 (cmd, explain_exit(code)))
return open(outname, 'rb').read()
finally:
try:
if inname: os.unlink(inname)
except: pass
try:
if outname: os.unlink(outname)
except: pass
filtertable = {
'tempfile:': tempfilter,
'pipe:': pipefilter,
}
def filter(s, cmd):
"filter a string through a command that transforms its input to its output"
for name, fn in filtertable.iteritems():
if cmd.startswith(name):
return fn(s, cmd[len(name):].lstrip())
return pipefilter(s, cmd)
mpm@selenic.com
Add automatic binary file detection to diff and export...
r1015 def binary(s):
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 """return true if a string is binary data using diff's heuristic"""
mpm@selenic.com
Add automatic binary file detection to diff and export...
r1015 if s and '\0' in s[:4096]:
return True
return False
mpm@selenic.com
Move dirstate.uniq to util.unique...
r556 def unique(g):
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 """return the uniq elements of iterable g"""
mpm@selenic.com
Move dirstate.uniq to util.unique...
r556 seen = {}
Matt Mackall
Make util.unique return a list
r3535 l = []
mpm@selenic.com
Move dirstate.uniq to util.unique...
r556 for f in g:
if f not in seen:
seen[f] = 1
Matt Mackall
Make util.unique return a list
r3535 l.append(f)
return l
mpm@selenic.com
Move dirstate.uniq to util.unique...
r556
Bryan O'Sullivan
Teach walk code about absolute paths....
r870 class Abort(Exception):
"""Raised if a command needs to print an error and exit."""
mpm@selenic.com
[PATCH] Harden os.system...
r508
Thomas Arendsen Hein
New UnexpectedOutput exception to catch server errors in localrepo.stream_in...
r3564 class UnexpectedOutput(Abort):
"""Raised to print an error with part of output and exit."""
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724 def always(fn): return True
def never(fn): return False
Alexis S. L. Carvalho
Explicitly expand globs on Windows
r4054 def expand_glob(pats):
'''On Windows, expand the implicit globs in a list of patterns'''
if os.name != 'nt':
return list(pats)
ret = []
for p in pats:
kind, name = patkind(p, None)
if kind is None:
globbed = glob.glob(name)
if globbed:
ret.extend(globbed)
continue
# if we couldn't expand the glob, just keep it around
ret.append(p)
return ret
Robin Farine
export patkind() from util
r1563 def patkind(name, dflt_pat='glob'):
"""Split a string into an optional pattern kind prefix and the
actual pattern."""
for prefix in 're', 'glob', 'path', 'relglob', 'relpath', 'relre':
if name.startswith(prefix + ':'): return name.split(':', 1)
return dflt_pat, name
benoit.boissinot@ens-lyon.fr
pep-0008 cleanup...
r1062 def globre(pat, head='^', tail='$'):
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724 "convert a glob pattern into a regexp"
i, n = 0, len(pat)
res = ''
group = False
def peek(): return i < n and pat[i]
while i < n:
c = pat[i]
i = i+1
if c == '*':
if peek() == '*':
i += 1
res += '.*'
else:
res += '[^/]*'
elif c == '?':
res += '.'
elif c == '[':
j = i
if j < n and pat[j] in '!]':
j += 1
while j < n and pat[j] != ']':
j += 1
if j >= n:
res += '\\['
else:
stuff = pat[i:j].replace('\\','\\\\')
i = j + 1
if stuff[0] == '!':
stuff = '^' + stuff[1:]
elif stuff[0] == '^':
stuff = '\\' + stuff
res = '%s[%s]' % (res, stuff)
elif c == '{':
group = True
res += '(?:'
elif c == '}' and group:
res += ')'
group = False
elif c == ',' and group:
res += '|'
Benoit Boissinot
make it possible to escape characters in a glob expression
r1990 elif c == '\\':
p = peek()
if p:
i += 1
res += re.escape(p)
else:
res += re.escape(c)
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724 else:
res += re.escape(c)
return head + res + tail
Bryan O'Sullivan
Reduce the amount of stat traffic generated by a walk....
r812 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
Alexis S. L. Carvalho
pass repo.root to util.pathto() in preparation for the next patch
r4229 def pathto(root, n1, n2):
Bryan O'Sullivan
Fix walk path handling on Windows
r886 '''return the relative path from one place to another.
Alexis S. L. Carvalho
pass repo.root to util.pathto() in preparation for the next patch
r4229 root should use os.sep to separate directories
Alexis S. L. Carvalho
fix util.pathto...
r3669 n1 should use os.sep to separate directories
n2 should use "/" to separate directories
returns an os.sep-separated path.
Alexis S. L. Carvalho
pass repo.root to util.pathto() in preparation for the next patch
r4229
If n1 is a relative path, it's assumed it's
relative to root.
n2 should always be relative to root.
Alexis S. L. Carvalho
fix util.pathto...
r3669 '''
Bryan O'Sullivan
Fix walk path handling on Windows
r886 if not n1: return localpath(n2)
Alexis S. L. Carvalho
Fix handling of paths when run outside the repo....
r4230 if os.path.isabs(n1):
if os.path.splitdrive(root)[0] != os.path.splitdrive(n1)[0]:
return os.path.join(root, localpath(n2))
n2 = '/'.join((pconvert(root), n2))
Alexis S. L. Carvalho
fix util.pathto...
r3669 a, b = n1.split(os.sep), n2.split('/')
twaldmann@thinkmo.de
fixed some stuff pychecker shows, marked unclear/wrong stuff with XXX
r1541 a.reverse()
b.reverse()
Bryan O'Sullivan
Fix walk code for files that do not exist anywhere, and unhandled types....
r884 while a and b and a[-1] == b[-1]:
twaldmann@thinkmo.de
fixed some stuff pychecker shows, marked unclear/wrong stuff with XXX
r1541 a.pop()
b.pop()
Bryan O'Sullivan
Fix walk code for files that do not exist anywhere, and unhandled types....
r884 b.reverse()
return os.sep.join((['..'] * len(a)) + b)
mpm@selenic.com
Change canonpath to not know about repo objects...
r1081 def canonpath(root, cwd, myname):
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 """return the canonical path of myname, given cwd and root"""
Arun Sharma
Handle hg under /
r1566 if root == os.sep:
rootsep = os.sep
Manpreet Singh
Make it possible to use the root directory as the root of a repository.
r2271 elif root.endswith(os.sep):
rootsep = root
Arun Sharma
Handle hg under /
r1566 else:
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 rootsep = root + os.sep
Bryan O'Sullivan
Teach walk code about absolute paths....
r870 name = myname
Vadim Gelfer
fix util.canonpath on windows....
r2090 if not os.path.isabs(name):
mpm@selenic.com
Change canonpath to not know about repo objects...
r1081 name = os.path.join(root, cwd, name)
Bryan O'Sullivan
Teach walk code about absolute paths....
r870 name = os.path.normpath(name)
Bryan O'Sullivan
Make audit_path more stringent....
r5158 audit_path = path_auditor(root)
Manpreet Singh
Make hg status work for repositories in root directory on windows (issue 228)
r2278 if name != rootsep and name.startswith(rootsep):
Thomas Arendsen Hein
Enable path validation for copy, rename, debugwalk and other canonpath users....
r1976 name = name[len(rootsep):]
audit_path(name)
return pconvert(name)
mpm@selenic.com
Change canonpath to not know about repo objects...
r1081 elif name == root:
Bryan O'Sullivan
Teach walk code about absolute paths....
r870 return ''
else:
Jim Meyering
Fix issue 165: `hg status' with abs path containing a symlink-to-dir fails
r2115 # Determine whether `name' is in the hierarchy at or beneath `root',
# by iterating name=dirname(name) until that causes no change (can't
# check name == '/', because that doesn't work on windows). For each
# `name', compare dev/inode numbers. If they match, the list `rel'
# holds the reversed list of components making up the relative file
# name we want.
root_st = os.stat(root)
rel = []
while True:
try:
name_st = os.stat(name)
except OSError:
break
Vadim Gelfer
add util.samestat function for windows....
r2193 if samestat(name_st, root_st):
Jun Inoue
Fix accessing the repo through a symlink.
r4086 if not rel:
# name was actually the same as root (maybe a symlink)
return ''
Jim Meyering
Fix issue 165: `hg status' with abs path containing a symlink-to-dir fails
r2115 rel.reverse()
name = os.path.join(*rel)
audit_path(name)
return pconvert(name)
dirname, basename = os.path.split(name)
rel.append(basename)
if dirname == name:
break
name = dirname
mpm@selenic.com
Change canonpath to not know about repo objects...
r1081 raise Abort('%s not under root' % myname)
mpm@selenic.com
Fix bug with empty inc and exc...
r897
Alexis S. L. Carvalho
remove unused "head" hack from util._matcher
r4197 def matcher(canonroot, cwd='', names=[], inc=[], exc=[], src=None):
return _matcher(canonroot, cwd, names, inc, exc, 'glob', src)
Benoit Boissinot
Do not use 'glob' expansion by default on OS != 'nt'
r1413
Alexis S. L. Carvalho
remove unused "head" hack from util._matcher
r4197 def cmdmatcher(canonroot, cwd='', names=[], inc=[], exc=[], src=None,
globbed=False, default=None):
Alexis S. L. Carvalho
change locate to use relglobs by default...
r4195 default = default or 'relpath'
if default == 'relpath' and not globbed:
Alexis S. L. Carvalho
docopy: deal with globs on windows in a better way
r4055 names = expand_glob(names)
Alexis S. L. Carvalho
remove unused "head" hack from util._matcher
r4197 return _matcher(canonroot, cwd, names, inc, exc, default, src)
Benoit Boissinot
Do not use 'glob' expansion by default on OS != 'nt'
r1413
Alexis S. L. Carvalho
remove unused "head" hack from util._matcher
r4197 def _matcher(canonroot, cwd, names, inc, exc, dflt_pat, src):
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 """build a function to match a set of file patterns
arguments:
canonroot - the canonical root of the tree you're matching against
cwd - the current working directory, if relevant
names - patterns to find
inc - patterns to include
exc - patterns to exclude
Alexis S. L. Carvalho
util._matcher: update comments...
r4185 dflt_pat - if a pattern in names has no explicit type, assume this one
src - where these patterns came from (e.g. .hgignore)
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082
a pattern is one of:
Alexis S. L. Carvalho
util._matcher: update comments...
r4185 'glob:<glob>' - a glob relative to cwd
're:<regexp>' - a regular expression
'path:<path>' - a path relative to canonroot
'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs)
'relpath:<path>' - a path relative to cwd
'relre:<regexp>' - a regexp that doesn't have to match the start of a name
'<something>' - one of the cases above, selected by the dflt_pat argument
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082
returns:
a 3-tuple containing
Alexis S. L. Carvalho
util._matcher: update comments...
r4185 - list of roots (places where one should start a recursive walk of the fs);
this often matches the explicit non-pattern names passed in, but also
includes the initial part of glob: patterns that has no glob characters
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 - a bool match(filename) function
- a bool indicating if any patterns were passed in
"""
Alexis S. L. Carvalho
Optimize return value of util._matcher for common command line case...
r4198 # a common case: no patterns at all
if not names and not inc and not exc:
return [], always, False
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082
Benoit Boissinot
Do not use 'glob' expansion by default on OS != 'nt'
r1413 def contains_glob(name):
Bryan O'Sullivan
Reduce the amount of stat traffic generated by a walk....
r812 for c in name:
Benoit Boissinot
Do not use 'glob' expansion by default on OS != 'nt'
r1413 if c in _globchars: return True
return False
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820
Bryan O'Sullivan
Fix up handling of regexp paths.
r888 def regex(kind, name, tail):
mpm@selenic.com
Refactor matchpats and walk...
r742 '''convert a pattern into a regular expression'''
Alexis S. L. Carvalho
util.*matcher: change default "names" argument...
r4190 if not name:
return ''
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820 if kind == 're':
return name
elif kind == 'path':
Bryan O'Sullivan
Fix up handling of regexp paths.
r888 return '^' + re.escape(name) + '(?:/|$)'
Bryan O'Sullivan
Switch to new syntax for .hgignore files....
r1270 elif kind == 'relglob':
Alexis S. L. Carvalho
change relglob: patterns to be consistent with glob: patterns...
r4307 return globre(name, '(?:|.*/)', tail)
Bryan O'Sullivan
Fix up handling of regexp paths.
r888 elif kind == 'relpath':
Alexis S. L. Carvalho
remove unused "head" hack from util._matcher
r4197 return re.escape(name) + '(?:/|$)'
Bryan O'Sullivan
Switch to new syntax for .hgignore files....
r1270 elif kind == 'relre':
if name.startswith('^'):
return name
return '.*' + name
Alexis S. L. Carvalho
Revert changeset ef1f1a4b2efb; add another test for glob: patterns...
r4306 return globre(name, '', tail)
mpm@selenic.com
Refactor matchpats and walk...
r742
def matchfn(pats, tail):
"""build a matching function from a set of patterns"""
Benoit Boissinot
further fix traceback on invalid .hgignore patterns...
r1454 if not pats:
return
Bryan O'Sullivan
util._matcher: speed up regexp matching....
r4371 try:
pat = '(?:%s)' % '|'.join([regex(k, p, tail) for (k, p) in pats])
return re.compile(pat).match
Matt Mackall
match: handle large regexes...
r5201 except OverflowError:
# We're using a Python with a tiny regex engine and we
# made it explode, so we'll divide the pattern list in two
# until it works
l = len(pats)
if l < 2:
raise
a, b = matchfn(pats[:l/2], tail), matchfn(pats[l/2:], tail)
return lambda s: a(s) or b(s)
Bryan O'Sullivan
util._matcher: speed up regexp matching....
r4371 except re.error:
for k, p in pats:
try:
re.compile('(?:%s)' % regex(k, p, tail))
except re.error:
if src:
raise Abort("%s: invalid pattern (%s): %s" %
(src, k, p))
else:
raise Abort("invalid pattern (%s): %s" % (k, p))
raise Abort("invalid pattern")
mpm@selenic.com
Refactor matchpats and walk...
r742
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820 def globprefix(pat):
'''return the non-glob prefix of a path, e.g. foo/* -> foo'''
root = []
Alexis S. L. Carvalho
small globprefix fix
r4183 for p in pat.split('/'):
Benoit Boissinot
Do not use 'glob' expansion by default on OS != 'nt'
r1413 if contains_glob(p): break
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820 root.append(p)
Alexis S. L. Carvalho
A 'glob:foo?bar' pattern determines a root - the tree root
r4187 return '/'.join(root) or '.'
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820
Alexis S. L. Carvalho
util._matcher: unify pattern normalization...
r4192 def normalizepats(names, default):
pats = []
roots = []
anypats = False
for kind, name in [patkind(p, default) for p in names]:
if kind in ('glob', 'relpath'):
name = canonpath(canonroot, cwd, name)
elif kind in ('relglob', 'path'):
name = normpath(name)
Alexis S. L. Carvalho
util._matcher: remove superfluous variable
r4236
pats.append((kind, name))
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820
Alexis S. L. Carvalho
util._matcher: unify pattern normalization...
r4192 if kind in ('glob', 're', 'relglob', 'relre'):
anypats = True
Alexis S. L. Carvalho
util._matcher: remove superfluous variable
r4236
Alexis S. L. Carvalho
util._matcher: unify pattern normalization...
r4192 if kind == 'glob':
root = globprefix(name)
roots.append(root)
elif kind in ('relpath', 'path'):
Alexis S. L. Carvalho
util._matcher: use "." as the root of empty {rel,}path patterns...
r4233 roots.append(name or '.')
Alexis S. L. Carvalho
util._matcher: unify pattern normalization...
r4192 elif kind == 'relglob':
roots.append('.')
Alexis S. L. Carvalho
util._matcher: remove superfluous variable
r4236 return roots, pats, anypats
Alexis S. L. Carvalho
util._matcher: unify pattern normalization...
r4192
roots, pats, anypats = normalizepats(names, dflt_pat)
mpm@selenic.com
Fix bug with empty inc and exc...
r897
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820 patmatch = matchfn(pats, '$') or always
mpm@selenic.com
Fix bug with empty inc and exc...
r897 incmatch = always
if inc:
Alexis S. L. Carvalho
util._matcher: unify pattern normalization...
r4192 dummy, inckinds, dummy = normalizepats(inc, 'glob')
Vadim Gelfer
fix -I/-X when relative paths used or in subdir
r2480 incmatch = matchfn(inckinds, '(?:/|$)')
mpm@selenic.com
Fix bug with empty inc and exc...
r897 excmatch = lambda fn: False
if exc:
Alexis S. L. Carvalho
util._matcher: unify pattern normalization...
r4192 dummy, exckinds, dummy = normalizepats(exc, 'glob')
Vadim Gelfer
fix -I/-X when relative paths used or in subdir
r2480 excmatch = matchfn(exckinds, '(?:/|$)')
mpm@selenic.com
Refactor matchpats and walk...
r742
Alexis S. L. Carvalho
Optimize return value of util._matcher for hgignore case
r4199 if not names and inc and not exc:
# common case: hgignore patterns
match = incmatch
else:
match = lambda fn: incmatch(fn) and not excmatch(fn) and patmatch(fn)
return (roots, match, (inc or exc or anypats) and True)
mpm@selenic.com
Refactor matchpats and walk...
r742
Thomas Arendsen Hein
Simplify/correct finding the hg executable (fixes issue644)...
r5062 _hgexecutable = None
def hgexecutable():
"""return location of the 'hg' executable.
Defaults to $HG or 'hg' in the search path.
"""
if _hgexecutable is None:
set_hgexecutable(os.environ.get('HG') or find_exe('hg', 'hg'))
return _hgexecutable
Thomas Arendsen Hein
Remember path to 'hg' executable and pass to external tools and hooks as $HG.
r4686
def set_hgexecutable(path):
Thomas Arendsen Hein
Simplify/correct finding the hg executable (fixes issue644)...
r5062 """set location of the 'hg' executable"""
Thomas Arendsen Hein
Remember path to 'hg' executable and pass to external tools and hooks as $HG.
r4686 global _hgexecutable
Thomas Arendsen Hein
Simplify/correct finding the hg executable (fixes issue644)...
r5062 _hgexecutable = path
Thomas Arendsen Hein
Remember path to 'hg' executable and pass to external tools and hooks as $HG.
r4686
Vadim Gelfer
merge util.esystem and util.system.
r1882 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
'''enhanced shell command execution.
run with environment maybe modified, maybe in different dir.
mpm@selenic.com
[PATCH] Harden os.system...
r508
Vadim Gelfer
merge util.esystem and util.system.
r1882 if command fails and onerr is None, return status. if ui object,
print error message and return status, else raise onerr object as
exception.'''
Vadim Gelfer
move most of tag code to localrepository class.
r2601 def py2shell(val):
'convert python object into string that is useful to shell'
if val in (None, False):
return '0'
if val == True:
return '1'
return str(val)
Vadim Gelfer
fix broken environment save/restore when a hook runs....
r1880 oldenv = {}
for k in environ:
oldenv[k] = os.environ.get(k)
if cwd is not None:
oldcwd = os.getcwd()
Alexis S. L. Carvalho
util.system: fix quoting on windows
r3905 origcmd = cmd
if os.name == 'nt':
cmd = '"%s"' % cmd
Vadim Gelfer
fix broken environment save/restore when a hook runs....
r1880 try:
for k, v in environ.iteritems():
Vadim Gelfer
move most of tag code to localrepository class.
r2601 os.environ[k] = py2shell(v)
Thomas Arendsen Hein
Simplify/correct finding the hg executable (fixes issue644)...
r5062 os.environ['HG'] = hgexecutable()
Vadim Gelfer
fix broken environment save/restore when a hook runs....
r1880 if cwd is not None and oldcwd != cwd:
os.chdir(cwd)
Vadim Gelfer
merge util.esystem and util.system.
r1882 rc = os.system(cmd)
Jean-Francois PIERONNE
OpenVMS patches
r4720 if sys.platform == 'OpenVMS' and rc & 1:
rc = 0
Vadim Gelfer
merge util.esystem and util.system.
r1882 if rc and onerr:
Alexis S. L. Carvalho
util.system: fix quoting on windows
r3905 errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
Vadim Gelfer
merge util.esystem and util.system.
r1882 explain_exit(rc)[0])
if errprefix:
errmsg = '%s: %s' % (errprefix, errmsg)
try:
onerr.warn(errmsg + '\n')
except AttributeError:
raise onerr(errmsg)
return rc
Vadim Gelfer
fix broken environment save/restore when a hook runs....
r1880 finally:
for k, v in oldenv.iteritems():
if v is None:
del os.environ[k]
else:
os.environ[k] = v
if cwd is not None and oldcwd != cwd:
os.chdir(oldcwd)
Alexis S. L. Carvalho
add util.lexists
r4281 # os.path.lexists is not available on python2.3
def lexists(filename):
"test whether a file with this name exists. does not follow symlinks"
try:
os.lstat(filename)
except:
return False
return True
mpm@selenic.com
[PATCH] rename under the other OS...
r421 def rename(src, dst):
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 """forcibly rename a file"""
mpm@selenic.com
[PATCH] rename under the other OS...
r421 try:
os.rename(src, dst)
Benoit Boissinot
fix unused variables reported by pychecker
r4956 except OSError, err: # FIXME: check err (EEXIST ?)
Vadim Gelfer
fix file handling bugs on windows....
r2176 # on windows, rename to existing file is not allowed, so we
# must delete destination first. but if file is open, unlink
# schedules it for delete but does not delete it. rename
# happens immediately even for open files, so we create
# temporary file, delete it, rename destination to that name,
# then delete that. then rename is safe to do.
fd, temp = tempfile.mkstemp(dir=os.path.dirname(dst) or '.')
os.close(fd)
os.unlink(temp)
os.rename(dst, temp)
os.unlink(temp)
mpm@selenic.com
[PATCH] rename under the other OS...
r421 os.rename(src, dst)
Benoit Boissinot
refactor some unlink/remove code and make sure we prune empty dir
r1415 def unlink(f):
"""unlink and remove the directory if it is empty"""
os.unlink(f)
# try removing directories that might now be empty
Vadim Gelfer
util.unlink should only catch OSError.
r2064 try:
os.removedirs(os.path.dirname(f))
except OSError:
pass
Benoit Boissinot
refactor some unlink/remove code and make sure we prune empty dir
r1415
Matt Mackall
util: add copyfile function
r3629 def copyfile(src, dest):
"copy a file, preserving mode"
Eric St-Jean
fix util.copyfile to deal with symlinks
r4271 if os.path.islink(src):
try:
os.unlink(dest)
except:
pass
os.symlink(os.readlink(src), dest)
else:
try:
shutil.copyfile(src, dest)
shutil.copymode(src, dest)
except shutil.Error, inst:
raise Abort(str(inst))
Matt Mackall
util: add copyfile function
r3629
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241 def copyfiles(src, dst, hardlink=None):
"""Copy a directory tree using hardlinks if possible"""
if hardlink is None:
hardlink = (os.stat(src).st_dev ==
os.stat(os.path.dirname(dst)).st_dev)
Thomas Arendsen Hein
Use python function instead of external 'cp' command when cloning repos....
r698
mpm@selenic.com
Rewrite copytree as copyfiles...
r1207 if os.path.isdir(src):
os.mkdir(dst)
for name in os.listdir(src):
srcname = os.path.join(src, name)
dstname = os.path.join(dst, name)
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241 copyfiles(srcname, dstname, hardlink)
mpm@selenic.com
Rewrite copytree as copyfiles...
r1207 else:
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241 if hardlink:
try:
os_link(src, dst)
Vadim Gelfer
util.copyfiles: only switch to copy if hardlink raises IOError or OSError....
r2050 except (IOError, OSError):
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241 hardlink = False
Benoit Boissinot
do not copy atime and mtime in util.copyfiles...
r1591 shutil.copy(src, dst)
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241 else:
Benoit Boissinot
do not copy atime and mtime in util.copyfiles...
r1591 shutil.copy(src, dst)
Thomas Arendsen Hein
Use python function instead of external 'cp' command when cloning repos....
r698
Bryan O'Sullivan
Make audit_path more stringent....
r5158 class path_auditor(object):
'''ensure that a filesystem path contains no banned components.
the following properties of a path are checked:
- under top-level .hg
- starts at the root of a windows drive
- contains ".."
- traverses a symlink (e.g. a/symlink_here/b)
- inside a nested repository'''
def __init__(self, root):
Alexis S. L. Carvalho
path_auditor: cache names of audited directories...
r5200 self.audited = set()
self.auditeddir = set()
Bryan O'Sullivan
Make audit_path more stringent....
r5158 self.root = root
def __call__(self, path):
if path in self.audited:
return
Bryan O'Sullivan
Make a few portability improvements to path auditing code.
r5159 normpath = os.path.normcase(path)
parts = normpath.split(os.sep)
Bryan O'Sullivan
Make audit_path more stringent....
r5158 if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '')
or os.pardir in parts):
raise Abort(_("path contains illegal component: %s") % path)
def check(prefix):
curpath = os.path.join(self.root, prefix)
try:
st = os.lstat(curpath)
except OSError, err:
Patrick Mezard
util: ignore invalid path errors in path_auditor.
r5162 # EINVAL can be raised as invalid path syntax under win32.
# They must be ignored for patterns can be checked too.
if err.errno not in (errno.ENOENT, errno.EINVAL):
Bryan O'Sullivan
Make audit_path more stringent....
r5158 raise
else:
if stat.S_ISLNK(st.st_mode):
raise Abort(_('path %r traverses symbolic link %r') %
(path, prefix))
Bryan O'Sullivan
Make a few portability improvements to path auditing code.
r5159 elif (stat.S_ISDIR(st.st_mode) and
os.path.isdir(os.path.join(curpath, '.hg'))):
Bryan O'Sullivan
Make audit_path more stringent....
r5158 raise Abort(_('path %r is inside repo %r') %
(path, prefix))
Alexis S. L. Carvalho
path_auditor: cache names of audited directories...
r5200
prefixes = []
Bryan O'Sullivan
Make a few portability improvements to path auditing code.
r5159 for c in strutil.rfindall(normpath, os.sep):
Alexis S. L. Carvalho
path_auditor: cache names of audited directories...
r5200 prefix = normpath[:c]
if prefix in self.auditeddir:
break
check(prefix)
prefixes.append(prefix)
self.audited.add(path)
# only add prefixes to the cache after checking everything: we don't
# want to add "foo/bar/baz" before checking if there's a "foo/.hg"
self.auditeddir.update(prefixes)
Thomas Arendsen Hein
Validate paths before reading or writing files in repository or working dir....
r1835
Thomas Arendsen Hein
Make makelock and readlock work on filesystems without symlink support....
r704 def _makelock_file(info, pathname):
ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
os.write(ld, info)
os.close(ld)
def _readlock_file(pathname):
Vadim Gelfer
fix file handling bugs on windows....
r2176 return posixfile(pathname).read()
Thomas Arendsen Hein
Make makelock and readlock work on filesystems without symlink support....
r704
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241 def nlinks(pathname):
"""Return number of hardlinks for the given file."""
Vadim Gelfer
replace os.stat with os.lstat in some where.
r2448 return os.lstat(pathname).st_nlink
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241
if hasattr(os, 'link'):
os_link = os.link
else:
def os_link(src, dst):
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 raise OSError(0, _("Hardlinks not supported"))
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241
Vadim Gelfer
fix file handling bugs on windows....
r2176 def fstat(fp):
'''stat file object that may not have fileno method.'''
try:
return os.fstat(fp.fileno())
except AttributeError:
return os.stat(fp.name)
posixfile = file
Vadim Gelfer
windows: revlog.lazyparser not always safe to use....
r2250 def is_win_9x():
'''return true if run on windows 95, 98 or me.'''
try:
return sys.getwindowsversion()[3] == 1
except AttributeError:
return os.name == 'nt' and 'command' in os.environ.get('comspec', '')
Benoit Boissinot
only print a warning when no username is specified...
r3721 getuser_fallback = None
def getuser():
'''return name of current user'''
try:
return getpass.getuser()
except ImportError:
# import of pwd will fail on windows - try fallback
if getuser_fallback:
return getuser_fallback()
# raised if win32api not available
raise Abort(_('user name not available - set USERNAME '
'environment variable'))
Alexis S. L. Carvalho
Only read .hg/hgrc files from trusted users/groups...
r3551 def username(uid=None):
"""Return the name of the user with the given uid.
If uid is None, return the name of the current user."""
try:
import pwd
if uid is None:
uid = os.getuid()
try:
return pwd.getpwuid(uid)[0]
except KeyError:
return str(uid)
except ImportError:
return None
def groupname(gid=None):
"""Return the name of the group with the given gid.
If gid is None, return the name of the current group."""
try:
import grp
if gid is None:
gid = os.getgid()
try:
return grp.getgrgid(gid)[0]
except KeyError:
return str(gid)
except ImportError:
return None
Matt Mackall
imported patch folding
r3784 # File system features
def checkfolding(path):
"""
Check whether the given path is on a case-sensitive filesystem
Requires a path (like /foo/.hg) ending with a foldable final
directory component.
"""
s1 = os.stat(path)
d, b = os.path.split(path)
p2 = os.path.join(d, b.upper())
if path == p2:
p2 = os.path.join(d, b.lower())
try:
s2 = os.stat(p2)
if s2 == s1:
return False
return True
except:
return True
Matt Mackall
exec: checkexec checks whether filesystem supports exec flags
r3994 def checkexec(path):
"""
Check whether the given path is on a filesystem with UNIX-like exec flags
Requires a directory (like /foo/.hg)
"""
Benoit Boissinot
check exec: return fallback in case of error during the check...
r5212 try:
fh, fn = tempfile.mkstemp("", "", path)
os.close(fh)
m = os.stat(fn).st_mode
os.chmod(fn, m ^ 0111)
r = (os.stat(fn).st_mode != m)
os.unlink(fn)
except (IOError,OSError):
# we don't care, the user probably won't be able to commit anyway
return False
Matt Mackall
exec: checkexec checks whether filesystem supports exec flags
r3994 return r
Matt Mackall
exec: add execfunc to simplify exec flag support on non-exec filesystems
r3996 def execfunc(path, fallback):
'''return an is_exec() function with default to fallback'''
if checkexec(path):
Matt Mackall
exec: remove last flag from is_exec
r3997 return lambda x: is_exec(os.path.join(path, x))
Matt Mackall
exec: add execfunc to simplify exec flag support on non-exec filesystems
r3996 return fallback
Matt Mackall
symlinks: use is_link wherever is_exec is used
r4002 def checklink(path):
Matt Mackall
symlinks: check whether a filesystem supports symlinks
r3998 """check whether the given path is on a symlink-capable filesystem"""
# mktemp is not racy because symlink creation will fail if the
# file already exists
name = tempfile.mktemp(dir=path)
try:
os.symlink(".", name)
os.unlink(name)
return True
Alexis S. L. Carvalho
catch AttributeError in util.checklink...
r4017 except (OSError, AttributeError):
Matt Mackall
symlinks: check whether a filesystem supports symlinks
r3998 return False
Matt Mackall
symlinks: add a linkfunc
r4000 def linkfunc(path, fallback):
'''return an is_link() function with default to fallback'''
if checklink(path):
Alexis S. L. Carvalho
use os.path.islink instead of util.is_link; remove util.is_link
r4275 return lambda x: os.path.islink(os.path.join(path, x))
Matt Mackall
symlinks: add a linkfunc
r4000 return fallback
Alexis S. L. Carvalho
cache os.umask even on windows
r4327 _umask = os.umask(0)
os.umask(_umask)
Patrick Mezard
Fix issue483 - mq does not work under windows with gnu-win32 patch....
r4434 def needbinarypatch():
"""return True if patches should be applied in binary mode by default."""
return os.name == 'nt'
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 # Platform specific variants
mpm@selenic.com
[PATCH] file seperator handling for the other 'OS'...
r419 if os.name == 'nt':
Matt Mackall
Replace demandload with new demandimport
r3877 import msvcrt
mpm@selenic.com
[PATCH] /dev/null for other OS...
r461 nulldev = 'NUL:'
Vadim Gelfer
eliminate backtrace when piping output on windows....
r1609
class winstdout:
'''stdout on windows misbehaves if sent through a pipe'''
def __init__(self, fp):
self.fp = fp
def __getattr__(self, key):
return getattr(self.fp, key)
def close(self):
try:
self.fp.close()
except: pass
def write(self, s):
try:
return self.fp.write(s)
except IOError, inst:
if inst.errno != 0: raise
self.close()
raise IOError(errno.EPIPE, 'Broken pipe')
Thomas Arendsen Hein
Removed trailing whitespace and tabs from python files
r4516
Patrick Mezard
stdout raises EINVAL when flush() is called on a closed pipe under win32....
r4129 def flush(self):
try:
return self.fp.flush()
except IOError, inst:
if inst.errno != errno.EINVAL: raise
self.close()
raise IOError(errno.EPIPE, 'Broken pipe')
Vadim Gelfer
eliminate backtrace when piping output on windows....
r1609
sys.stdout = winstdout(sys.stdout)
Vadim Gelfer
fix exception handling on windows....
r2054 def system_rcpath():
Vadim Gelfer
fix issue 217....
r2117 try:
return system_rcpath_win32()
except:
return [r'c:\mercurial\mercurial.ini']
Vadim Gelfer
fix exception handling on windows....
r2054
Shane Holloway
Unified *_rcpath so the interface is similar across operating systems...
r4083 def user_rcpath():
'''return os-specific hgrc search path to the user dir'''
Alexis S. L. Carvalho
util_win32.py: fix user_rcpath...
r4098 try:
userrc = user_rcpath_win32()
except:
userrc = os.path.join(os.path.expanduser('~'), 'mercurial.ini')
path = [userrc]
Thomas Arendsen Hein
On Windows look for mercurial.ini in $USERPROFILE, too, if available...
r2280 userprofile = os.environ.get('USERPROFILE')
if userprofile:
path.append(os.path.join(userprofile, 'mercurial.ini'))
return path
Bryan O'Sullivan
Use platform-appropriate rc file names.
r1292
Volker Kleinfeld
Make 'hg import' platform independent....
r1285 def parse_patch_output(output_line):
"""parses the output produced by patch and returns the file name"""
pf = output_line[14:]
if pf[0] == '`':
pf = pf[1:-1] # Remove the quotes
return pf
Vadim Gelfer
fix exception handling on windows....
r2054 def testpid(pid):
'''return False if pid dead, True if running or not known'''
return True
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241
mpm@selenic.com
Permission handling for the other OS...
r441 def set_exec(f, mode):
pass
Matt Mackall
symlinks: add basic symlink functions to util.py
r3999 def set_link(f, mode):
mpm@selenic.com
Permission handling for the other OS...
r441 pass
mpm@selenic.com
Whitespace cleanups...
r515
olivier.maquelin@intel.com
Avoid insertion/deletion of CRs on stdio during hg serve
r1420 def set_binary(fd):
msvcrt.setmode(fd.fileno(), os.O_BINARY)
mpm@selenic.com
[PATCH] file seperator handling for the other 'OS'...
r419 def pconvert(path):
return path.replace("\\", "/")
mpm@selenic.com
[PATCH] Enables lock work under the other 'OS'...
r422
Bryan O'Sullivan
Fix walk path handling on Windows
r886 def localpath(path):
return path.replace('/', '\\')
def normpath(path):
return pconvert(os.path.normpath(path))
Thomas Arendsen Hein
Make makelock and readlock work on filesystems without symlink support....
r704 makelock = _makelock_file
readlock = _readlock_file
mpm@selenic.com
[PATCH] /dev/null for other OS...
r461
Vadim Gelfer
add util.samestat function for windows....
r2193 def samestat(s1, s2):
return False
Alexis S. L. Carvalho
Fix util.shellquote on windows.
r4087 # A sequence of backslashes is special iff it precedes a double quote:
# - if there's an even number of backslashes, the double quote is not
# quoted (i.e. it ends the quoted region)
# - if there's an odd number of backslashes, the double quote is quoted
# - in both cases, every pair of backslashes is unquoted into a single
# backslash
# (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
# So, to quote a string, we must surround it in double quotes, double
# the number of backslashes that preceed double quotes and add another
# backslash before every double quote (being careful with the double
# quote we've appended to the end)
_quotere = None
Brendan Cully
Add portable shell-quoting function; teach mq to use it.
r2791 def shellquote(s):
Alexis S. L. Carvalho
Fix util.shellquote on windows.
r4087 global _quotere
if _quotere is None:
_quotere = re.compile(r'(\\*)("|\\$)')
return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
Brendan Cully
Add portable shell-quoting function; teach mq to use it.
r2791
thananck@yahoo.com
Provided platform dependent implementations for explain_exit...
r782 def explain_exit(code):
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 return _("exited with status %d") % code, code
thananck@yahoo.com
Provided platform dependent implementations for explain_exit...
r782
Alexis S. L. Carvalho
Avoid looking up usernames if the current user owns the .hgrc file...
r3677 # if you change this stub into a real check, please try to implement the
# username and groupname functions above, too.
def isowner(fp, st=None):
return True
Thomas Arendsen Hein
Removed trailing whitespace and tabs from python files
r4516
Patrick Mezard
Move win32 find_in_files from util_win32 to util.
r4407 def find_in_path(name, path, default=None):
'''find name in search path. path can be string (will be split
with os.pathsep), or iterable thing that returns strings. if name
found, return path to name. else return default. name is looked up
using cmd.exe rules, using PATHEXT.'''
if isinstance(path, str):
path = path.split(os.pathsep)
Thomas Arendsen Hein
Removed trailing whitespace and tabs from python files
r4516
Patrick Mezard
Move win32 find_in_files from util_win32 to util.
r4407 pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
pathext = pathext.lower().split(os.pathsep)
isexec = os.path.splitext(name)[1].lower() in pathext
Thomas Arendsen Hein
Removed trailing whitespace and tabs from python files
r4516
Patrick Mezard
Move win32 find_in_files from util_win32 to util.
r4407 for p in path:
p_name = os.path.join(p, name)
Thomas Arendsen Hein
Removed trailing whitespace and tabs from python files
r4516
Patrick Mezard
Move win32 find_in_files from util_win32 to util.
r4407 if isexec and os.path.exists(p_name):
return p_name
Thomas Arendsen Hein
Removed trailing whitespace and tabs from python files
r4516
Patrick Mezard
Move win32 find_in_files from util_win32 to util.
r4407 for ext in pathext:
p_name_ext = p_name + ext
if os.path.exists(p_name_ext):
return p_name_ext
return default
Alexis S. L. Carvalho
Avoid looking up usernames if the current user owns the .hgrc file...
r3677
Nathan Jones
Fix serve on Windows without win32* modules.
r4803 def set_signal_handler():
try:
set_signal_handler_win32()
except NameError:
pass
Vadim Gelfer
fix exception handling on windows....
r2054 try:
# override functions with win32 versions if possible
from util_win32 import *
Vadim Gelfer
windows: revlog.lazyparser not always safe to use....
r2250 if not is_win_9x():
posixfile = posixfile_nt
Vadim Gelfer
fix exception handling on windows....
r2054 except ImportError:
pass
mpm@selenic.com
[PATCH] file seperator handling for the other 'OS'...
r419 else:
mpm@selenic.com
[PATCH] /dev/null for other OS...
r461 nulldev = '/dev/null'
Vadim Gelfer
make mercurial look in more places for config files....
r1583 def rcfiles(path):
rcs = [os.path.join(path, 'hgrc')]
rcdir = os.path.join(path, 'hgrc.d')
try:
rcs.extend([os.path.join(rcdir, f) for f in os.listdir(rcdir)
if f.endswith(".rc")])
Benoit Boissinot
fix warnings spotted by pychecker
r3131 except OSError:
pass
Vadim Gelfer
make mercurial look in more places for config files....
r1583 return rcs
Vadim Gelfer
add HGRCPATH env var, list of places to look for hgrc files....
r1951
Shane Holloway
Unified *_rcpath so the interface is similar across operating systems...
r4083 def system_rcpath():
Vadim Gelfer
add HGRCPATH env var, list of places to look for hgrc files....
r1951 path = []
Vadim Gelfer
make reason for sys.argv change obvious in code.
r2263 # old mod_python does not set sys.argv
Shun-ichi GOTO
Check existance of sys.argv for the use from mod_python.
r2261 if len(getattr(sys, 'argv', [])) > 0:
Vadim Gelfer
add HGRCPATH env var, list of places to look for hgrc files....
r1951 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
'/../etc/mercurial'))
path.extend(rcfiles('/etc/mercurial'))
return path
Bryan O'Sullivan
Use platform-appropriate rc file names.
r1292
Shane Holloway
Unified *_rcpath so the interface is similar across operating systems...
r4083 def user_rcpath():
return [os.path.expanduser('~/.hgrc')]
Volker Kleinfeld
Make 'hg import' platform independent....
r1285 def parse_patch_output(output_line):
"""parses the output produced by patch and returns the file name"""
Benoit Boissinot
if a filename contains spaces, patch adds quote around it
r1593 pf = output_line[14:]
Jean-Francois PIERONNE
OpenVMS patches
r4720 if os.sys.platform == 'OpenVMS':
if pf[0] == '`':
pf = pf[1:-1] # Remove the quotes
else:
if pf.startswith("'") and pf.endswith("'") and " " in pf:
pf = pf[1:-1] # Remove the quotes
Benoit Boissinot
if a filename contains spaces, patch adds quote around it
r1593 return pf
Volker Kleinfeld
Make 'hg import' platform independent....
r1285
Matt Mackall
exec: remove last flag from is_exec
r3997 def is_exec(f):
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 """check whether a file is executable"""
Vadim Gelfer
replace os.stat with os.lstat in some where.
r2448 return (os.lstat(f).st_mode & 0100 != 0)
mpm@selenic.com
Permission handling for the other OS...
r441
def set_exec(f, mode):
Vadim Gelfer
replace os.stat with os.lstat in some where.
r2448 s = os.lstat(f).st_mode
mpm@selenic.com
Permission handling for the other OS...
r441 if (s & 0100 != 0) == mode:
return
if mode:
# Turn on +x for every +r bit when making a file executable
# and obey umask.
Matt Mackall
pull umask-checking up
r4326 os.chmod(f, s | (s & 0444) >> 2 & ~_umask)
mpm@selenic.com
Permission handling for the other OS...
r441 else:
os.chmod(f, s & 0666)
Matt Mackall
symlinks: add basic symlink functions to util.py
r3999 def set_link(f, mode):
"""make a file a symbolic link/regular file
if a file is changed to a link, its contents become the link data
if a link is changed to a file, its link data become its contents
"""
Alexis S. L. Carvalho
use os.path.islink instead of util.is_link; remove util.is_link
r4275 m = os.path.islink(f)
Matt Mackall
symlinks: add basic symlink functions to util.py
r3999 if m == bool(mode):
return
if mode: # switch file to link
data = file(f).read()
os.unlink(f)
os.symlink(data, f)
else:
data = os.readlink(f)
os.unlink(f)
file(f, "w").write(data)
olivier.maquelin@intel.com
Avoid insertion/deletion of CRs on stdio during hg serve
r1420 def set_binary(fd):
pass
mpm@selenic.com
[PATCH] file seperator handling for the other 'OS'...
r419 def pconvert(path):
return path
Bryan O'Sullivan
Fix walk path handling on Windows
r886 def localpath(path):
return path
normpath = os.path.normpath
Vadim Gelfer
add util.samestat function for windows....
r2193 samestat = os.path.samestat
Bryan O'Sullivan
Fix walk path handling on Windows
r886
mpm@selenic.com
[PATCH] Enables lock work under the other 'OS'...
r422 def makelock(info, pathname):
Thomas Arendsen Hein
Make makelock and readlock work on filesystems without symlink support....
r704 try:
os.symlink(info, pathname)
except OSError, why:
if why.errno == errno.EEXIST:
raise
else:
_makelock_file(info, pathname)
mpm@selenic.com
[PATCH] Enables lock work under the other 'OS'...
r422
def readlock(pathname):
Thomas Arendsen Hein
Make makelock and readlock work on filesystems without symlink support....
r704 try:
return os.readlink(pathname)
except OSError, why:
Jean-Francois PIERONNE
OpenVMS patches
r4720 if why.errno in (errno.EINVAL, errno.ENOSYS):
Thomas Arendsen Hein
Make makelock and readlock work on filesystems without symlink support....
r704 return _readlock_file(pathname)
else:
raise
thananck@yahoo.com
Provided platform dependent implementations for explain_exit...
r782
Brendan Cully
Add portable shell-quoting function; teach mq to use it.
r2791 def shellquote(s):
Jean-Francois PIERONNE
OpenVMS patches
r4720 if os.sys.platform == 'OpenVMS':
return '"%s"' % s
else:
return "'%s'" % s.replace("'", "'\\''")
Brendan Cully
Add portable shell-quoting function; teach mq to use it.
r2791
Vadim Gelfer
change lock format to let us detect and break stale locks....
r1877 def testpid(pid):
'''return False if pid dead, True if running or not sure'''
Jean-Francois PIERONNE
OpenVMS patches
r4720 if os.sys.platform == 'OpenVMS':
return True
Vadim Gelfer
change lock format to let us detect and break stale locks....
r1877 try:
os.kill(pid, 0)
return True
except OSError, inst:
return inst.errno != errno.ESRCH
thananck@yahoo.com
Provided platform dependent implementations for explain_exit...
r782 def explain_exit(code):
"""return a 2-tuple (desc, code) describing a process's status"""
if os.WIFEXITED(code):
val = os.WEXITSTATUS(code)
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 return _("exited with status %d") % val, val
thananck@yahoo.com
Provided platform dependent implementations for explain_exit...
r782 elif os.WIFSIGNALED(code):
val = os.WTERMSIG(code)
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 return _("killed by signal %d") % val, val
thananck@yahoo.com
Provided platform dependent implementations for explain_exit...
r782 elif os.WIFSTOPPED(code):
mark.williamson@cl.cam.ac.uk
Minor tweak: os.STOPSIG -> os.WSTOPSIG. Pychecker spotted this one.
r912 val = os.WSTOPSIG(code)
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 return _("stopped by signal %d") % val, val
raise ValueError(_("invalid exit code"))
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199
Alexis S. L. Carvalho
Avoid looking up usernames if the current user owns the .hgrc file...
r3677 def isowner(fp, st=None):
"""Return True if the file object f belongs to the current user.
The return value of a util.fstat(f) may be passed as the st argument.
"""
if st is None:
Benoit Boissinot
fix errors spotted by pychecker
r3859 st = fstat(fp)
Alexis S. L. Carvalho
Avoid looking up usernames if the current user owns the .hgrc file...
r3677 return st.st_uid == os.getuid()
Thomas Arendsen Hein
Removed trailing whitespace and tabs from python files
r4516
Patrick Mezard
Move win32 find_in_files from util_win32 to util.
r4407 def find_in_path(name, path, default=None):
'''find name in search path. path can be string (will be split
with os.pathsep), or iterable thing that returns strings. if name
found, return path to name. else return default.'''
if isinstance(path, str):
path = path.split(os.pathsep)
for p in path:
p_name = os.path.join(p, name)
if os.path.exists(p_name):
return p_name
return default
Alexis S. L. Carvalho
Avoid looking up usernames if the current user owns the .hgrc file...
r3677
Marcos Chaves
Handle CTRL+C in serve under Windows.
r4672 def set_signal_handler():
pass
Bryan O'Sullivan
Introduce find_exe. Use instead of find_in_path for programs....
r4488 def find_exe(name, default=None):
'''find path of an executable.
if name contains a path component, return it as is. otherwise,
use normal executable search path.'''
Jean-Francois PIERONNE
OpenVMS patches
r4720 if os.sep in name or sys.platform == 'OpenVMS':
Bryan O'Sullivan
Introduce find_exe. Use instead of find_in_path for programs....
r4488 # don't check the executable bit. if the file isn't
# executable, whoever tries to actually run it will give a
# much more useful error message.
return name
return find_in_path(name, os.environ.get('PATH', ''), default=default)
Benoit Boissinot
create the encode and decode functions for the store
r3852 def _buildencodefun():
e = '_'
Benoit Boissinot
fix reserved char on windows, '[]+' are allowed
r3860 win_reserved = [ord(x) for x in '\\:*?"<>|']
Benoit Boissinot
create the encode and decode functions for the store
r3852 cmap = dict([ (chr(x), chr(x)) for x in xrange(127) ])
for x in (range(32) + range(126, 256) + win_reserved):
cmap[chr(x)] = "~%02x" % x
for x in range(ord("A"), ord("Z")+1) + [ord(e)]:
cmap[chr(x)] = e + chr(x).lower()
dmap = {}
for k, v in cmap.iteritems():
dmap[v] = k
def decode(s):
i = 0
while i < len(s):
for l in xrange(1, 4):
try:
yield dmap[s[i:i+l]]
i += l
break
except KeyError:
pass
else:
raise KeyError
return (lambda s: "".join([cmap[c] for c in s]),
lambda s: "".join(list(decode(s))))
encodefilename, decodefilename = _buildencodefun()
Benoit Boissinot
switch to the .hg/store layout, fix the tests
r3853 def encodedopener(openerfn, fn):
def o(path, *args, **kw):
return openerfn(fn(path), *args, **kw)
return o
Alexis S. L. Carvalho
Avoid looking up usernames if the current user owns the .hgrc file...
r3677
Alexis S. L. Carvalho
turn util.opener into a class
r4827 def mktempcopy(name, emptyok=False):
"""Create a temporary file with the same contents from name
The permission bits are copied from the original file.
If the temporary file is going to be truncated immediately, you
can use emptyok=True as an optimization.
Returns the name of the temporary file.
Vadim Gelfer
fix file handling bugs on windows....
r2176 """
Alexis S. L. Carvalho
turn util.opener into a class
r4827 d, fn = os.path.split(name)
fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
os.close(fd)
# Temporary files are created with mode 0600, which is usually not
# what we want. If the original file already exists, just copy
# its mode. Otherwise, manually obey umask.
try:
st_mode = os.lstat(name).st_mode
except OSError, inst:
if inst.errno != errno.ENOENT:
raise
st_mode = 0666 & ~_umask
os.chmod(temp, st_mode)
if emptyok:
return temp
try:
try:
ifp = posixfile(name, "rb")
except IOError, inst:
if inst.errno == errno.ENOENT:
return temp
if not getattr(inst, 'filename', None):
inst.filename = name
raise
ofp = posixfile(temp, "wb")
for chunk in filechunkiter(ifp):
ofp.write(chunk)
ifp.close()
ofp.close()
except:
try: os.unlink(temp)
except: pass
raise
return temp
Vadim Gelfer
fix file handling bugs on windows....
r2176
Alexis S. L. Carvalho
turn util.opener into a class
r4827 class atomictempfile(posixfile):
"""file-like object that atomically updates a file
All writes will be redirected to a temporary copy of the original
file. When rename is called, the copy is renamed to the original
name, making the changes visible.
"""
def __init__(self, name, mode):
self.__name = name
self.temp = mktempcopy(name, emptyok=('w' in mode))
posixfile.__init__(self, self.temp, mode)
def rename(self):
if not self.closed:
posixfile.close(self)
rename(self.temp, localpath(self.__name))
def __del__(self):
if not self.closed:
try:
os.unlink(self.temp)
except: pass
posixfile.close(self)
class opener(object):
"""Open files relative to a base directory
This class is used to hide the details of COW semantics and
Vadim Gelfer
fix file handling bugs on windows....
r2176 remote file access from higher level code.
"""
Alexis S. L. Carvalho
turn util.opener into a class
r4827 def __init__(self, base, audit=True):
self.base = base
Bryan O'Sullivan
Make audit_path more stringent....
r5158 if audit:
self.audit_path = path_auditor(base)
else:
self.audit_path = always
Vadim Gelfer
fix file handling bugs on windows....
r2176
Alexis S. L. Carvalho
Add symlink method to util.opener....
r4828 def __getattr__(self, name):
if name == '_can_symlink':
self._can_symlink = checklink(self.base)
return self._can_symlink
raise AttributeError(name)
Alexis S. L. Carvalho
turn util.opener into a class
r4827 def __call__(self, path, mode="r", text=False, atomictemp=False):
Bryan O'Sullivan
Make audit_path more stringent....
r5158 self.audit_path(path)
Alexis S. L. Carvalho
turn util.opener into a class
r4827 f = os.path.join(self.base, path)
Vadim Gelfer
fix file handling bugs on windows....
r2176
Jean-Francois PIERONNE
OpenVMS patches
r4720 if not text and "b" not in mode:
Vadim Gelfer
fix file handling bugs on windows....
r2176 mode += "b" # for that other OS
if mode[0] != "r":
try:
nlink = nlinks(f)
except OSError:
Alexis S. L. Carvalho
util.opener: if requested, use atomicfile even if the file doesn't exist...
r4328 nlink = 0
Vadim Gelfer
fix file handling bugs on windows....
r2176 d = os.path.dirname(f)
if not os.path.isdir(d):
os.makedirs(d)
Alexis S. L. Carvalho
Remove atomicfile class....
r4508 if atomictemp:
Alexis S. L. Carvalho
util.opener: if requested, use atomicfile even if the file doesn't exist...
r4328 return atomictempfile(f, mode)
if nlink > 1:
rename(mktempcopy(f), f)
Vadim Gelfer
fix file handling bugs on windows....
r2176 return posixfile(f, mode)
Alexis S. L. Carvalho
Add symlink method to util.opener....
r4828 def symlink(self, src, dst):
Bryan O'Sullivan
Make audit_path more stringent....
r5158 self.audit_path(dst)
Alexis S. L. Carvalho
Add symlink method to util.opener....
r4828 linkname = os.path.join(self.base, dst)
try:
os.unlink(linkname)
except OSError:
pass
dirname = os.path.dirname(linkname)
if not os.path.exists(dirname):
os.makedirs(dirname)
if self._can_symlink:
Bryan O'Sullivan
Print meaningful error message if os.symlink fails
r4948 try:
os.symlink(src, linkname)
except OSError, err:
raise OSError(err.errno, _('could not symlink to %r: %s') %
(src, err.strerror), linkname)
Alexis S. L. Carvalho
Add symlink method to util.opener....
r4828 else:
Patrick Mezard
Fix issue 653: symlinks checkout failure on non-supporting platforms
r5077 f = self(dst, "w")
Alexis S. L. Carvalho
Add symlink method to util.opener....
r4828 f.write(src)
f.close()
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 class chunkbuffer(object):
"""Allow arbitrary sized chunks of data to be efficiently read from an
iterator over chunks of arbitrary size."""
Bryan O'Sullivan
Minor cleanups.
r1200
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 def __init__(self, in_iter, targetsize = 2**16):
"""in_iter is the iterator that's iterating over the input chunks.
targetsize is how big a buffer to try to maintain."""
self.in_iter = iter(in_iter)
self.buf = ''
self.targetsize = int(targetsize)
Bryan O'Sullivan
Minor cleanups.
r1200 if self.targetsize <= 0:
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 raise ValueError(_("targetsize must be greater than 0, was %d") %
Bryan O'Sullivan
Minor cleanups.
r1200 targetsize)
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 self.iterempty = False
Bryan O'Sullivan
Minor cleanups.
r1200
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 def fillbuf(self):
Bryan O'Sullivan
Minor cleanups.
r1200 """Ignore target size; read every chunk from iterator until empty."""
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 if not self.iterempty:
collector = cStringIO.StringIO()
collector.write(self.buf)
for ch in self.in_iter:
collector.write(ch)
self.buf = collector.getvalue()
self.iterempty = True
def read(self, l):
Bryan O'Sullivan
Minor cleanups.
r1200 """Read L bytes of data from the iterator of chunks of data.
Thomas Arendsen Hein
Cleanup of tabs and trailing spaces.
r1308 Returns less than L bytes if the iterator runs dry."""
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 if l > len(self.buf) and not self.iterempty:
# Clamp to a multiple of self.targetsize
targetsize = self.targetsize * ((l // self.targetsize) + 1)
collector = cStringIO.StringIO()
collector.write(self.buf)
collected = len(self.buf)
for chunk in self.in_iter:
collector.write(chunk)
collected += len(chunk)
if collected >= targetsize:
break
if collected < targetsize:
self.iterempty = True
self.buf = collector.getvalue()
Bryan O'Sullivan
Minor cleanups.
r1200 s, self.buf = self.buf[:l], buffer(self.buf, l)
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 return s
Vadim Gelfer
util: add limit to amount filechunkiter will read
r2462 def filechunkiter(f, size=65536, limit=None):
"""Create a generator that produces the data in the file size
(default 65536) bytes at a time, up to optional limit (default is
to read all data). Chunks may be less than size bytes if the
chunk is the last chunk in the file, or the file is a socket or
some other type of file that sometimes reads less data than is
requested."""
assert size >= 0
assert limit is None or limit >= 0
while True:
if limit is None: nbytes = size
else: nbytes = min(limit, size)
s = nbytes and f.read(nbytes)
if not s: break
if limit: limit -= len(s)
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 yield s
Bryan O'Sullivan
Fix up representation of dates in hgweb....
r1320
Bryan O'Sullivan
Clean up date and timezone handling....
r1321 def makedate():
Benoit Boissinot
fix handling of daylight saving time
r1482 lt = time.localtime()
if lt[8] == 1 and time.daylight:
tz = time.altzone
else:
tz = time.timezone
return time.mktime(lt), tz
Bryan O'Sullivan
Allow files to be opened in text mode, even on Windows.
r1329
Vadim Gelfer
add changelog style to command line template....
r1987 def datestr(date=None, format='%a %b %d %H:%M:%S %Y', timezone=True):
Bryan O'Sullivan
Clean up date and timezone handling....
r1321 """represent a (unixtime, offset) tuple as a localized time.
unixtime is seconds since the epoch, and offset is the time zone's
Vadim Gelfer
add changelog style to command line template....
r1987 number of seconds away from UTC. if timezone is false, do not
append time zone to string."""
Bryan O'Sullivan
Clean up date and timezone handling....
r1321 t, tz = date or makedate()
Vadim Gelfer
add changelog style to command line template....
r1987 s = time.strftime(format, time.gmtime(float(t) - tz))
if timezone:
s += " %+03d%02d" % (-tz / 3600, ((-tz % 3600) / 60))
return s
Vadim Gelfer
hgwebdir: export collections of repos...
r1829
Matt Mackall
Add date matching support...
r3812 def strdate(string, format, defaults):
Jose M. Prieto
Allow the use of human readable dates (issue 251)
r2522 """parse a localized time string and return a (unixtime, offset) tuple.
if the string cannot be parsed, ValueError is raised."""
Matt Mackall
parsedate: add UTC and GMT timezones
r3809 def timezone(string):
tz = string.split()[-1]
if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
tz = int(tz)
offset = - 3600 * (tz / 100) - 60 * (tz % 100)
return offset
if tz == "GMT" or tz == "UTC":
return 0
return None
Jose M. Prieto
Allow the use of human readable dates (issue 251)
r2522
Jose M. Prieto
util.strdate: compute timestamp using UTC, not local timezone
r3255 # NOTE: unixtime = localunixtime + offset
Matt Mackall
parsedate: add UTC and GMT timezones
r3809 offset, date = timezone(string), string
if offset != None:
date = " ".join(string.split()[:-1])
Matt Mackall
improve date parsing for numerous new date formats...
r3808
Matt Mackall
Add date matching support...
r3812 # add missing elements from defaults
for part in defaults:
found = [True for p in part if ("%"+p) in format]
if not found:
date += "@" + defaults[part]
format += "@%" + part[0]
Matt Mackall
improve date parsing for numerous new date formats...
r3808
Jose M. Prieto
util.strdate: assume local time when no timezone specified
r3256 timetuple = time.strptime(date, format)
localunixtime = int(calendar.timegm(timetuple))
if offset is None:
# local timezone
unixtime = int(time.mktime(timetuple))
offset = unixtime - localunixtime
else:
unixtime = localunixtime + offset
Jose M. Prieto
util.strdate: compute timestamp using UTC, not local timezone
r3255 return unixtime, offset
Jose M. Prieto
Allow the use of human readable dates (issue 251)
r2522
Matt Mackall
Add date matching support...
r3812 def parsedate(string, formats=None, defaults=None):
Jose M. Prieto
Allow the use of human readable dates (issue 251)
r2522 """parse a localized time string and return a (unixtime, offset) tuple.
The date may be a "unixtime offset" string or in one of the specified
formats."""
Matt Mackall
parsedate: allow '' for epoch
r3807 if not string:
return 0, 0
Chris Mason
util.parsedate should understand dates from hg export
r2609 if not formats:
formats = defaultdateformats
Matt Mackall
improve date parsing for numerous new date formats...
r3808 string = string.strip()
Jose M. Prieto
Allow the use of human readable dates (issue 251)
r2522 try:
when, offset = map(int, string.split(' '))
Benoit Boissinot
validate the resulting date in parsedate
r2523 except ValueError:
Matt Mackall
Add date matching support...
r3812 # fill out defaults
if not defaults:
defaults = {}
now = makedate()
for part in "d mb yY HI M S".split():
if part not in defaults:
if part[0] in "HMS":
defaults[part] = "00"
elif part[0] in "dm":
defaults[part] = "1"
else:
defaults[part] = datestr(now, "%" + part[0], False)
Benoit Boissinot
validate the resulting date in parsedate
r2523 for format in formats:
try:
Matt Mackall
Add date matching support...
r3812 when, offset = strdate(string, format, defaults)
Benoit Boissinot
validate the resulting date in parsedate
r2523 except ValueError:
pass
else:
break
else:
Matt Mackall
parsedate: use Abort rather than ValueError
r3806 raise Abort(_('invalid date: %r ') % string)
Benoit Boissinot
validate the resulting date in parsedate
r2523 # validate explicit (probably user-specified) date and
# time zone offset. values must fit in signed 32 bits for
# current 32-bit linux runtimes. timezones go from UTC-12
# to UTC+14
if abs(when) > 0x7fffffff:
Matt Mackall
parsedate: use Abort rather than ValueError
r3806 raise Abort(_('date exceeds 32 bits: %d') % when)
Benoit Boissinot
validate the resulting date in parsedate
r2523 if offset < -50400 or offset > 43200:
Matt Mackall
parsedate: use Abort rather than ValueError
r3806 raise Abort(_('impossible time zone offset: %d') % offset)
Benoit Boissinot
validate the resulting date in parsedate
r2523 return when, offset
Jose M. Prieto
Allow the use of human readable dates (issue 251)
r2522
Matt Mackall
Add date matching support...
r3812 def matchdate(date):
"""Return a function that matches a given date match specifier
Formats include:
'{date}' match a given date to the accuracy provided
'<{date}' on or before a given date
'>{date}' on or after a given date
"""
def lower(date):
return parsedate(date, extendeddateformats)[0]
def upper(date):
d = dict(mb="12", HI="23", M="59", S="59")
for days in "31 30 29".split():
try:
d["d"] = days
return parsedate(date, extendeddateformats, d)[0]
except:
pass
d["d"] = "28"
return parsedate(date, extendeddateformats, d)[0]
if date[0] == "<":
when = upper(date[1:])
return lambda x: x <= when
elif date[0] == ">":
when = lower(date[1:])
return lambda x: x >= when
elif date[0] == "-":
try:
days = int(date[1:])
except ValueError:
raise Abort(_("invalid day spec: %s") % date[1:])
when = makedate()[0] - days * 3600 * 24
Matt Mackall
Add --date support to log...
r3813 return lambda x: x >= when
Matt Mackall
Add date matching support...
r3812 elif " to " in date:
a, b = date.split(" to ")
start, stop = lower(a), upper(b)
return lambda x: x >= start and x <= stop
else:
start, stop = lower(date), upper(date)
return lambda x: x >= start and x <= stop
Vadim Gelfer
move shortuser into util module.
r1903 def shortuser(user):
"""Return a short representation of a user name or email address."""
f = user.find('@')
if f >= 0:
user = user[:f]
f = user.find('<')
if f >= 0:
user = user[f+1:]
Thomas Arendsen Hein
shortuser should stop before the first space character....
r3176 f = user.find(' ')
if f >= 0:
user = user[:f]
Matt Mackall
shortname: truncate at '.' too
r3533 f = user.find('.')
if f >= 0:
user = user[:f]
Vadim Gelfer
move shortuser into util module.
r1903 return user
Vadim Gelfer
merge with crew.
r1920
Thomas Arendsen Hein
Move ellipsis code to util.ellipsis() and improve maxlength handling.
r3767 def ellipsis(text, maxlength=400):
"""Trim string to at most maxlength (default: 400) characters."""
if len(text) <= maxlength:
return text
else:
return "%s..." % (text[:maxlength-3])
Vadim Gelfer
hgwebdir: export collections of repos...
r1829 def walkrepos(path):
'''yield every hg repository under path, recursively.'''
def errhandler(err):
if err.filename == path:
raise err
for root, dirs, files in os.walk(path, onerror=errhandler):
for d in dirs:
if d == '.hg':
yield root
dirs[:] = []
break
Vadim Gelfer
add HGRCPATH env var, list of places to look for hgrc files....
r1951
_rcpath = None
Shane Holloway
Combined the two os_rcpath methods into a single one near rcpath in mercurial/util.py...
r4097 def os_rcpath():
'''return default os-specific hgrc search path'''
path = system_rcpath()
path.extend(user_rcpath())
path = [os.path.normpath(f) for f in path]
return path
Vadim Gelfer
add HGRCPATH env var, list of places to look for hgrc files....
r1951 def rcpath():
'''return hgrc search path. if env var HGRCPATH is set, use it.
for each item in path, if directory, use files ending in .rc,
else use item.
make HGRCPATH empty to only look in .hg/hgrc of current repo.
if no HGRCPATH, use default os-specific path.'''
global _rcpath
if _rcpath is None:
if 'HGRCPATH' in os.environ:
_rcpath = []
for p in os.environ['HGRCPATH'].split(os.pathsep):
if not p: continue
Benoit Boissinot
use a proper test instead of catching every exception
r1956 if os.path.isdir(p):
Vadim Gelfer
add HGRCPATH env var, list of places to look for hgrc files....
r1951 for f in os.listdir(p):
if f.endswith('.rc'):
_rcpath.append(os.path.join(p, f))
Benoit Boissinot
use a proper test instead of catching every exception
r1956 else:
_rcpath.append(p)
Vadim Gelfer
add HGRCPATH env var, list of places to look for hgrc files....
r1951 else:
_rcpath = os_rcpath()
return _rcpath
Vadim Gelfer
add support for streaming clone....
r2612
def bytecount(nbytes):
'''return byte count formatted as readable string, with units'''
units = (
(100, 1<<30, _('%.0f GB')),
(10, 1<<30, _('%.1f GB')),
(1, 1<<30, _('%.2f GB')),
(100, 1<<20, _('%.0f MB')),
(10, 1<<20, _('%.1f MB')),
(1, 1<<20, _('%.2f MB')),
(100, 1<<10, _('%.0f KB')),
(10, 1<<10, _('%.1f KB')),
(1, 1<<10, _('%.2f KB')),
(1, 1, _('%.0f bytes')),
)
for multiplier, divisor, format in units:
if nbytes >= divisor * multiplier:
return format % (nbytes / float(divisor))
return units[-1][2] % nbytes
Vadim Gelfer
clean up hg.py: move repo constructor code into each repo module
r2740
def drop_scheme(scheme, path):
sc = scheme + ':'
if path.startswith(sc):
path = path[len(sc):]
if path.startswith('//'):
path = path[2:]
return path