##// END OF EJS Templates
setup: remove spurious posix import
setup: remove spurious posix import

File last commit:

r7913:1b1b3dd6 default
r7946:9d36291f default
Show More
util.py
1568 lines | 48.9 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 _
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 import cStringIO, errno, re, shutil, sys, tempfile, traceback, error
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396 import os, stat, threading, time, calendar, ConfigParser, locale, glob, osutil
Shun-ichi GOTO
Also find correct column width of wide characters....
r7695 import imp, unicodedata
Matt Mackall
Add encoding detection
r3769
Dirkjan Ochtman
python 2.6 compatibility: compatibility wrappers for hash functions
r6470 # Python compatibility
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
Dirkjan Ochtman
python 2.6 compatibility: compatibility wrappers for hash functions
r6470 _md5 = None
def md5(s):
global _md5
if _md5 is None:
try:
import hashlib
_md5 = hashlib.md5
except ImportError:
import md5
_md5 = md5.md5
return _md5(s)
_sha1 = None
def sha1(s):
global _sha1
if _sha1 is None:
try:
import hashlib
_sha1 = hashlib.sha1
except ImportError:
import sha
_sha1 = sha.sha
return _sha1(s)
Eric Hopper
Provide a version independent way to use the set datatype.
r4647 try:
Dirkjan Ochtman
python2.6: use subprocess if available
r7106 import subprocess
Thomas Arendsen Hein
Fix util.popen2 for Python 2.3...
r7163 subprocess.Popen # trigger ImportError early
Patrick Mezard
util: subprocess close_fds option is unix only
r7123 closefds = os.name == 'posix'
Dirkjan Ochtman
python2.6: use subprocess if available
r7106 def popen2(cmd, mode='t', bufsize=-1):
Patrick Mezard
util: subprocess close_fds option is unix only
r7123 p = subprocess.Popen(cmd, shell=True, bufsize=bufsize,
close_fds=closefds,
Dirkjan Ochtman
python2.6: use subprocess if available
r7106 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
return p.stdin, p.stdout
def popen3(cmd, mode='t', bufsize=-1):
Patrick Mezard
util: subprocess close_fds option is unix only
r7123 p = subprocess.Popen(cmd, shell=True, bufsize=bufsize,
close_fds=closefds,
Dirkjan Ochtman
python2.6: use subprocess if available
r7106 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
return p.stdin, p.stdout, p.stderr
def Popen3(cmd, capturestderr=False, bufsize=-1):
stderr = capturestderr and subprocess.PIPE or None
Patrick Mezard
util: subprocess close_fds option is unix only
r7123 p = subprocess.Popen(cmd, shell=True, bufsize=bufsize,
close_fds=closefds,
Dirkjan Ochtman
python2.6: use subprocess if available
r7106 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=stderr)
p.fromchild = p.stdout
p.tochild = p.stdin
p.childerr = p.stderr
return p
except ImportError:
subprocess = None
Thomas Arendsen Hein
Add util.popen3 fallback, simplify import of Popen3
r7164 from popen2 import Popen3
Thomas Arendsen Hein
Fix util.popen2 for Python 2.3...
r7163 popen2 = os.popen2
Thomas Arendsen Hein
Add util.popen3 fallback, simplify import of Popen3
r7164 popen3 = os.popen3
Dirkjan Ochtman
python2.6: use subprocess if available
r7106
Matt Mackall
encoding: normalize some silly encoding names
r7461 _encodingfixup = {'646': 'ascii', 'ANSI_X3.4-1968': 'ascii'}
Eric Hopper
Provide a version independent way to use the set datatype.
r4647 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'
Matt Mackall
encoding: normalize some silly encoding names
r7461 _encoding = _encodingfixup.get(_encoding, _encoding)
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
Shun-ichi GOTO
Also find correct column width of wide characters....
r7695 def colwidth(s):
Matt Mackall
simplify colwidth a bit
r7696 "Find the column width of a UTF-8 string for display"
d = s.decode(_encoding, 'replace')
if hasattr(unicodedata, 'east_asian_width'):
w = unicodedata.east_asian_width
return sum([w(c) in 'WF' and 2 or 1 for c in d])
return len(d)
Matt Mackall
Add functions for transcoding and manipulating multibyte strings
r3770
Matt Mackall
refactor version code...
r7632 def version():
"""Return version information if available."""
try:
import __version__
return __version__.version
except ImportError:
return 'unknown'
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
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'''
Dirkjan Ochtman
python2.6: use subprocess if available
r7106 (pin, pout) = 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):
Christian Ebert
Let util.binary check entire data for \0 (issue1066, issue1079)
r6507 """return true if a string is binary data"""
if s and '\0' in s:
mpm@selenic.com
Add automatic binary file detection to diff and export...
r1015 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"""
Matt Mackall
util: simplify unique
r5881 return dict.fromkeys(g).keys()
mpm@selenic.com
Move dirstate.uniq to util.unique...
r556
Matt Mackall
util: add sort helper
r6762 def sort(l):
if not isinstance(l, list):
l = list(l)
l.sort()
return l
Brendan Cully
templater: return data in increasing chunk sizes...
r7396 def increasingchunks(source, min=1024, max=65536):
'''return no less than min bytes per chunk while data remains,
doubling min after each chunk until it reaches max'''
def log2(x):
if not x:
return 0
i = 0
while x:
x >>= 1
i += 1
return i - 1
buf = []
blen = 0
for chunk in source:
buf.append(chunk)
blen += len(chunk)
if blen >= min:
if min < max:
min = min << 1
nmin = 1 << log2(blen)
if nmin > min:
min = nmin
if min > max:
min = max
yield ''.join(buf)
blen = 0
buf = []
if buf:
yield ''.join(buf)
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
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
Matt Mackall
remove default arg from patkind
r6595 def patkind(name, default):
Robin Farine
export patkind() from util
r1563 """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)
Matt Mackall
remove default arg from patkind
r6595 return default, name
Robin Farine
export patkind() from util
r1563
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 = ''
Jesse Glick
Permit glob patterns to use nested curly braces.
r5949 group = 0
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724 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 == '{':
Jesse Glick
Permit glob patterns to use nested curly braces.
r5949 group += 1
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724 res += '(?:'
elif c == '}' and group:
res += ')'
Jesse Glick
Permit glob patterns to use nested curly braces.
r5949 group -= 1
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724 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))
Shun-ichi GOTO
Add util.splitpath() and use it instead of using os.sep directly....
r5844 a, b = splitpath(n1), 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()
Alexis S. L. Carvalho
util.pathto: return '.' instead of an empty string...
r6111 return os.sep.join((['..'] * len(a)) + b) or '.'
Bryan O'Sullivan
Fix walk code for files that do not exist anywhere, and unhandled types....
r884
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
Shun-ichi GOTO
Add endswithsep() and use it instead of using os.sep and os.altsep directly....
r5843 elif endswithsep(root):
Manpreet Singh
Make it possible to use the root directory as the root of a repository.
r2271 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
Matt Mackall
walk: kill util.cmdmatcher and _matcher
r6575 def matcher(canonroot, cwd='', names=[], inc=[], exc=[], src=None, dflt_pat='glob'):
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])
Matt Mackall
ignore: split up huge patterns...
r6074 if len(pat) > 20000:
raise OverflowError()
Bryan O'Sullivan
util._matcher: speed up regexp matching....
r4371 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
Benoit Boissinot
explicitely use integer division
r5454 a, b = matchfn(pats[:l//2], tail), matchfn(pats[l//2:], tail)
Matt Mackall
match: handle large regexes...
r5201 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, '(?:/|$)')
Mads Kiilerich
util: use existing never() instead of custom lambda
r7430 excmatch = never
mpm@selenic.com
Fix bug with empty inc and exc...
r897 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
"Paul Moore "
Added hgexecutable support for py2exe/frozen scripts
r6499 def main_is_frozen():
"""return True if we are a frozen executable.
The code supports py2exe (most common, Windows only) and tools/freeze
(portable, not much used).
"""
return (hasattr(sys, "frozen") or # new py2exe
hasattr(sys, "importers") or # old py2exe
imp.is_frozen("__main__")) # tools/freeze
Thomas Arendsen Hein
Simplify/correct finding the hg executable (fixes issue644)...
r5062 def hgexecutable():
"""return location of the 'hg' executable.
Defaults to $HG or 'hg' in the search path.
"""
if _hgexecutable is None:
Bryan O'Sullivan
Tidy code, fix typo
r6500 hg = os.environ.get('HG')
if hg:
set_hgexecutable(hg)
"Paul Moore "
Added hgexecutable support for py2exe/frozen scripts
r6499 elif main_is_frozen():
set_hgexecutable(sys.executable)
else:
Mads Kiilerich
Make util.find_exe alway returns existing file, fixing issue1459...
r7732 set_hgexecutable(find_exe('hg') or 'hg')
Thomas Arendsen Hein
Simplify/correct finding the hg executable (fixes issue644)...
r5062 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)
Matt Mackall
dispatch: generalize signature checking for extension command wrapping
r7388 def checksignature(func):
'''wrap a function with code to check for calling errors'''
def check(*args, **kwargs):
try:
return func(*args, **kwargs)
except TypeError:
if len(traceback.extract_tb(sys.exc_info()[2])) == 1:
Matt Mackall
error: move SignatureError
r7646 raise error.SignatureError
Matt Mackall
dispatch: generalize signature checking for extension command wrapping
r7388 raise
return check
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
Matt Mackall
rename: simplify forced renaming...
r7780 # happens immediately even for open files, so we rename
# destination to a temporary name, then delete that. then
# rename is safe to do.
temp = dst + "-force-rename"
Vadim Gelfer
fix file handling bugs on windows....
r2176 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):
Will Maier
Use shutil.copystat in copyfile().
r7767 "copy a file, preserving mode and atime/mtime"
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)
Will Maier
Use shutil.copystat in copyfile().
r7767 shutil.copystat(src, dest)
Eric St-Jean
fix util.copyfile to deal with symlinks
r4271 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)
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396 for name, kind in osutil.listdir(src):
mpm@selenic.com
Rewrite copytree as copyfiles...
r1207 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)
Shun-ichi GOTO
Add util.splitpath() and use it instead of using os.sep directly....
r5844 parts = splitpath(normpath)
Matt Mackall
audit: check for casefolding of .hg (issue1450)
r7784 if (os.path.splitdrive(path)[0]
or parts[0].lower() in ('.hg', '.hg.', '')
Bryan O'Sullivan
Make audit_path more stringent....
r5158 or os.pardir in parts):
raise Abort(_("path contains illegal component: %s") % path)
Matt Mackall
audit: check for casefolding of .hg (issue1450)
r7784 if '.hg' in path.lower():
lparts = [p.lower() for p in parts]
Matt Mackall
audit: reject paths with .hg (issue 1450)...
r7553 for p in '.hg', '.hg.':
Matt Mackall
audit: be even pickier (issue1450)
r7820 if p in lparts[1:]:
Matt Mackall
audit: check for casefolding of .hg (issue1450)
r7784 pos = lparts.index(p)
Matt Mackall
audit: reject paths with .hg (issue 1450)...
r7553 base = os.path.join(*parts[:pos])
raise Abort(_('path %r is inside repo %r') % (path, base))
Bryan O'Sullivan
Make audit_path more stringent....
r5158 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.
Maxim Dounin
Fix file-changed-to-dir and dir-to-file commits (issue660)....
r5487 if err.errno not in (errno.ENOENT, errno.ENOTDIR, 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))
Shun-ichi GOTO
Fix not to use os.sep directly....
r5845 parts.pop()
Alexis S. L. Carvalho
path_auditor: cache names of audited directories...
r5200 prefixes = []
Shun-ichi GOTO
Fix not to use os.sep directly....
r5845 for n in range(len(parts)):
prefix = os.sep.join(parts)
Alexis S. L. Carvalho
path_auditor: cache names of audited directories...
r5200 if prefix in self.auditeddir:
break
check(prefix)
prefixes.append(prefix)
Shun-ichi GOTO
Fix not to use os.sep directly....
r5845 parts.pop()
Alexis S. L. Carvalho
path_auditor: cache names of audited directories...
r5200
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
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 if os.name == 'nt':
from windows import *
Steve Borho
windows: hoist expand_glob() back into util.py...
r7913 def expand_glob(pats):
'''On Windows, expand the implicit globs in a list of patterns'''
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
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 else:
from posix import *
def makelock(info, pathname):
try:
return os.symlink(info, pathname)
except OSError, why:
if why.errno == errno.EEXIST:
raise
except AttributeError: # no symlink in os
pass
Thomas Arendsen Hein
Make makelock and readlock work on filesystems without symlink support....
r704 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
os.write(ld, info)
os.close(ld)
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 def readlock(pathname):
try:
return os.readlink(pathname)
except OSError, why:
if why.errno not in (errno.EINVAL, errno.ENOSYS):
raise
except AttributeError: # no symlink in os
pass
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)
Matt Mackall
imported patch folding
r3784 # File system features
Matt Mackall
rename checkfolding to checkcase
r6746 def checkcase(path):
Matt Mackall
imported patch folding
r3784 """
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
Paul Moore
Add a new function, fspath...
r6676 _fspathcache = {}
def fspath(name, root):
'''Get name in the case stored in the filesystem
The name is either relative to root, or it is an absolute path starting
with root. Note that this function is unnecessary, and should not be
called, for case-sensitive filesystems (simply because it's expensive).
'''
# If name is absolute, make it relative
if name.lower().startswith(root.lower()):
l = len(root)
if name[l] == os.sep or name[l] == os.altsep:
l = l + 1
name = name[l:]
if not os.path.exists(os.path.join(root, name)):
return None
seps = os.sep
if os.altsep:
seps = seps + os.altsep
# Protect backslashes. This gets silly very quickly.
seps.replace('\\','\\\\')
pattern = re.compile(r'([^%s]+)|([%s]+)' % (seps, seps))
dir = os.path.normcase(os.path.normpath(root))
result = []
for part, sep in pattern.findall(name):
if sep:
result.append(sep)
continue
if dir not in _fspathcache:
_fspathcache[dir] = os.listdir(dir)
contents = _fspathcache[dir]
lpart = part.lower()
for n in contents:
if n.lower() == lpart:
result.append(n)
break
else:
# Cannot happen, as the file exists!
result.append(part)
dir = os.path.join(dir, lpart)
return ''.join(result)
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)
"""
Matt Mackall
checkexec: fix VFAT tempfile droppings with more modern Linux kernels...
r5739
# VFAT on some Linux versions can flip mode but it doesn't persist
# a FS remount. Frequently we can detect it if files are created
# with exec bit on.
Benoit Boissinot
check exec: return fallback in case of error during the check...
r5212 try:
Rafael Villar Burke
Execution bit detection fixes for VFAT on Linux...
r5420 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
Benoit Boissinot
check exec: return fallback in case of error during the check...
r5212 fh, fn = tempfile.mkstemp("", "", path)
Matt Mackall
checkexec: fix VFAT tempfile droppings with more modern Linux kernels...
r5739 try:
os.close(fh)
m = os.stat(fn).st_mode & 0777
new_file_has_exec = m & EXECFLAGS
os.chmod(fn, m ^ EXECFLAGS)
Patrick Mezard
util: filter all st_mode with 0777 in checkexec
r5759 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
Matt Mackall
checkexec: fix VFAT tempfile droppings with more modern Linux kernels...
r5739 finally:
os.unlink(fn)
except (IOError, OSError):
Benoit Boissinot
check exec: return fallback in case of error during the check...
r5212 # we don't care, the user probably won't be able to commit anyway
return False
Rafael Villar Burke
Execution bit detection fixes for VFAT on Linux...
r5420 return not (new_file_has_exec or exec_flags_cannot_flip)
Matt Mackall
exec: checkexec checks whether filesystem supports exec flags
r3994
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
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'
Shun-ichi GOTO
Add endswithsep() and use it instead of using os.sep and os.altsep directly....
r5843 def endswithsep(path):
'''Check path ends with os.sep or os.altsep.'''
return path.endswith(os.sep) or os.altsep and path.endswith(os.altsep)
Shun-ichi GOTO
Add util.splitpath() and use it instead of using os.sep directly....
r5844 def splitpath(path):
'''Split path by os.sep.
Note that this function does not use os.altsep because this is
an alternative of simple "xxx.split(os.sep)".
It is recommended to use os.path.normpath() before using this
function if need.'''
return path.split(os.sep)
Matt Mackall
filemerge: add config item for GUI tools...
r6007 def gui():
'''Are we running in a GUI?'''
return os.name == "nt" or os.name == "mac" or os.environ.get("DISPLAY")
Patrick Mezard
util: always define a dummy lookup_reg()
r6132 def lookup_reg(key, name=None, scope=None):
return None
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 def mktempcopy(name, emptyok=False, createmode=None):
Alexis S. L. Carvalho
turn util.opener into a class
r4827 """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:
Matt Mackall
atomictempfile: avoid chmod weirdness on Linux vfat
r5740 st_mode = os.lstat(name).st_mode & 0777
Alexis S. L. Carvalho
turn util.opener into a class
r4827 except OSError, inst:
if inst.errno != errno.ENOENT:
raise
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 st_mode = createmode
if st_mode is None:
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 st_mode = ~umask
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 st_mode &= 0666
Alexis S. L. Carvalho
turn util.opener into a class
r4827 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.
"""
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 def __init__(self, name, mode, createmode):
Alexis S. L. Carvalho
turn util.opener into a class
r4827 self.__name = name
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 self.temp = mktempcopy(name, emptyok=('w' in mode),
createmode=createmode)
Alexis S. L. Carvalho
turn util.opener into a class
r4827 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)
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 def makedirs(name, mode=None):
"""recursive directory creation with parent mode inheritance"""
try:
os.mkdir(name)
if mode is not None:
os.chmod(name, mode)
return
except OSError, err:
if err.errno == errno.EEXIST:
return
if err.errno != errno.ENOENT:
raise
parent = os.path.abspath(os.path.dirname(name))
makedirs(parent, mode)
makedirs(name, mode)
Alexis S. L. Carvalho
turn util.opener into a class
r4827 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
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 self.createmode = None
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
Make files in .hg inherit the permissions from .hg/store
r6062 def _fixfilemode(self, name):
if self.createmode is None:
return
os.chmod(name, self.createmode & 0666)
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
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 nlink = -1
Benoit Boissinot
make mq and tags hardlink safe...
r6835 if mode not in ("r", "rb"):
Vadim Gelfer
fix file handling bugs on windows....
r2176 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):
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 makedirs(d, self.createmode)
Alexis S. L. Carvalho
Remove atomicfile class....
r4508 if atomictemp:
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 return atomictempfile(f, mode, self.createmode)
Alexis S. L. Carvalho
util.opener: if requested, use atomicfile even if the file doesn't exist...
r4328 if nlink > 1:
rename(mktempcopy(f), f)
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 fp = posixfile(f, mode)
if nlink == 0:
self._fixfilemode(f)
return fp
Vadim Gelfer
fix file handling bugs on windows....
r2176
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):
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 makedirs(dirname, self.createmode)
Alexis S. L. Carvalho
Add symlink method to util.opener....
r4828
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()
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 self._fixfilemode(dst)
Alexis S. L. Carvalho
Add symlink method to util.opener....
r4828
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
Matt Mackall
chunkbuffer: removed unused method and arg
r5446 def __init__(self, in_iter):
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 """in_iter is the iterator that's iterating over the input chunks.
targetsize is how big a buffer to try to maintain."""
Matt Mackall
chunkiter: simplify iter logic
r5447 self.iter = iter(in_iter)
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 self.buf = ''
Matt Mackall
chunkbuffer: removed unused method and arg
r5446 self.targetsize = 2**16
Bryan O'Sullivan
Minor cleanups.
r1200
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 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."""
Matt Mackall
chunkiter: simplify iter logic
r5447 if l > len(self.buf) and self.iter:
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 # Clamp to a multiple of self.targetsize
Matt Mackall
chunkiter: handle large reads more efficiently...
r5449 targetsize = max(l, self.targetsize)
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 collector = cStringIO.StringIO()
collector.write(self.buf)
collected = len(self.buf)
Matt Mackall
chunkiter: simplify iter logic
r5447 for chunk in self.iter:
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 collector.write(chunk)
collected += len(chunk)
if collected >= targetsize:
break
if collected < targetsize:
Matt Mackall
chunkiter: simplify iter logic
r5447 self.iter = False
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 self.buf = collector.getvalue()
Matt Mackall
chunkiter: handle large reads more efficiently...
r5449 if len(self.buf) == l:
Matt Mackall
revlog: fix caching of buffer objects
r5450 s, self.buf = str(self.buf), ''
Matt Mackall
chunkiter: handle large reads more efficiently...
r5449 else:
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
Matt Mackall
dates: improve timezone handling...
r6229 def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'):
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()
Matt Mackall
dates: improve timezone handling...
r6229 if "%1" in format or "%2" in format:
sign = (tz > 0) and "-" or "+"
minutes = abs(tz) / 60
format = format.replace("%1", "%c%02d" % (sign, minutes / 60))
format = format.replace("%2", "%02d" % (minutes % 60))
Vadim Gelfer
add changelog style to command line template....
r1987 s = time.strftime(format, time.gmtime(float(t) - tz))
return s
Vadim Gelfer
hgwebdir: export collections of repos...
r1829
Thomas Arendsen Hein
Make annotae/grep print short dates with -q/--quiet....
r6134 def shortdate(date=None):
"""turn (timestamp, tzoff) tuple into iso 8631 date."""
Matt Mackall
dates: improve timezone handling...
r6229 return datestr(date, format='%Y-%m-%d')
Thomas Arendsen Hein
Make annotae/grep print short dates with -q/--quiet....
r6134
Bryan O'Sullivan
util: add default argument to strdate
r5357 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():
Matt Mackall
dates: improve timezone handling...
r6229 sign = (tz[0] == "+") and 1 or -1
hours = int(tz[1:3])
minutes = int(tz[3:5])
return -sign * (hours * 60 + minutes) * 60
Matt Mackall
parsedate: add UTC and GMT timezones
r3809 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
Thomas Arendsen Hein
Fix bad behaviour when specifying an invalid date (issue700)...
r6139 def parsedate(date, formats=None, defaults=None):
"""parse a localized date/time string and return a (unixtime, offset) tuple.
Jose M. Prieto
Allow the use of human readable dates (issue 251)
r2522 The date may be a "unixtime offset" string or in one of the specified
Thomas Arendsen Hein
Fix bad behaviour when specifying an invalid date (issue700)...
r6139 formats. If the date already is a (unixtime, offset) tuple, it is returned.
"""
if not date:
Matt Mackall
parsedate: allow '' for epoch
r3807 return 0, 0
Matt Mackall
dates: Fix bare times to be relative to "today"
r6230 if isinstance(date, tuple) and len(date) == 2:
Thomas Arendsen Hein
Fix bad behaviour when specifying an invalid date (issue700)...
r6139 return date
Chris Mason
util.parsedate should understand dates from hg export
r2609 if not formats:
formats = defaultdateformats
Thomas Arendsen Hein
Fix bad behaviour when specifying an invalid date (issue700)...
r6139 date = date.strip()
Jose M. Prieto
Allow the use of human readable dates (issue 251)
r2522 try:
Thomas Arendsen Hein
Fix bad behaviour when specifying an invalid date (issue700)...
r6139 when, offset = map(int, date.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"
else:
Matt Mackall
dates: improve timezone handling...
r6229 defaults[part] = datestr(now, "%" + part[0])
Matt Mackall
Add date matching support...
r3812
Benoit Boissinot
validate the resulting date in parsedate
r2523 for format in formats:
try:
Thomas Arendsen Hein
Fix bad behaviour when specifying an invalid date (issue700)...
r6139 when, offset = strdate(date, format, defaults)
Dirkjan Ochtman
better handle errors with date parsing (issue983)...
r6087 except (ValueError, OverflowError):
Benoit Boissinot
validate the resulting date in parsedate
r2523 pass
else:
break
else:
Thomas Arendsen Hein
Fix bad behaviour when specifying an invalid date (issue700)...
r6139 raise Abort(_('invalid date: %r ') % date)
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):
Matt Mackall
dates: Fix bare times to be relative to "today"
r6230 d = dict(mb="1", d="1")
return parsedate(date, extendeddateformats, d)[0]
Matt Mackall
Add date matching support...
r3812
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
Matt Mackall
templater: move email function to util
r5975 def email(author):
'''get email of author.'''
r = author.find('>')
if r == -1: r = None
return author[author.find('<')+1:r]
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])
Benoit Allard
hgweb: recurse down collections only if ** in [paths]...
r7523 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
Vadim Gelfer
hgwebdir: export collections of repos...
r1829 '''yield every hg repository under path, recursively.'''
def errhandler(err):
if err.filename == path:
raise err
Eric Hopper
Allow hgwebdir collections to follow symlinks.
r6284 if followsym and hasattr(os.path, 'samestat'):
def _add_dir_if_not_there(dirlst, dirname):
match = False
samestat = os.path.samestat
dirstat = os.stat(dirname)
for lstdirstat in dirlst:
if samestat(dirstat, lstdirstat):
match = True
break
if not match:
dirlst.append(dirstat)
return not match
else:
Eric Hopper
hgwebdir: Tiny fix for webdir on non-symlink capable platforms.
r6317 followsym = False
Vadim Gelfer
hgwebdir: export collections of repos...
r1829
Eric Hopper
Allow hgwebdir collections to follow symlinks.
r6284 if (seen_dirs is None) and followsym:
seen_dirs = []
_add_dir_if_not_there(seen_dirs, path)
for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
Walter Doerwald
Simplify utils.walkrepos().
r6140 if '.hg' in dirs:
yield root # found a repository
Dirkjan Ochtman
hgweb: mq repos should be in non-recursive collections, too
r7525 qroot = os.path.join(root, '.hg', 'patches')
if os.path.isdir(os.path.join(qroot, '.hg')):
yield qroot # we have a patch queue repo here
Benoit Allard
hgweb: recurse down collections only if ** in [paths]...
r7523 if recurse:
# avoid recursing inside the .hg directory
dirs.remove('.hg')
else:
dirs[:] = [] # don't descend further
Eric Hopper
Allow hgwebdir collections to follow symlinks.
r6284 elif followsym:
newdirs = []
for d in dirs:
fname = os.path.join(root, d)
if _add_dir_if_not_there(seen_dirs, fname):
if os.path.islink(fname):
for hgname in walkrepos(fname, True, seen_dirs):
yield hgname
else:
newdirs.append(d)
dirs[:] = newdirs
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):
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396 for f, kind in osutil.listdir(p):
Vadim Gelfer
add HGRCPATH env var, list of places to look for hgrc files....
r1951 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
Patrick Mezard
extdiff: avoid repr() doubling paths backslashes under Windows
r5291
def uirepr(s):
# Avoid double backslash in Windows path repr()
return repr(s).replace('\\\\', '\\')
Alexander Solovyov
python implementation of diffstat...
r7547
def termwidth():
if 'COLUMNS' in os.environ:
try:
return int(os.environ['COLUMNS'])
except ValueError:
pass
try:
import termios, array, fcntl
for dev in (sys.stdout, sys.stdin):
try:
fd = dev.fileno()
if not os.isatty(fd):
continue
arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8)
return array.array('h', arri)[1]
except ValueError:
pass
except ImportError:
pass
return 80
Alexander Solovyov <piranha at piranha.org.ua>
templater: ability to display diffstat for log-like commands
r7879
def iterlines(iterator):
for chunk in iterator:
for line in chunk.splitlines():
yield line