##// END OF EJS Templates
merge with stable
merge with stable

File last commit:

r13947:d2d1ef6a default
r13969:336bb8b5 merge default
Show More
util.py
1585 lines | 49.6 KiB | text/x-python | PythonLexer
Martin Geisler
put license and copyright info into comment blocks
r8226 # util.py - Mercurial utility functions and platform specfic implementations
#
# Copyright 2005 K. Thananchayan <thananck@yahoo.com>
# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
#
# This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082
Martin Geisler
turn some comments back into module docstrings
r8227 """Mercurial utility functions and platform specfic implementations.
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082
Martin Geisler
turn some comments back into module docstrings
r8227 This contains helper routines that are independent of the SCM core and
hide platform-specific details from the core.
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 """
mpm@selenic.com
[PATCH] file seperator handling for the other 'OS'...
r419
Matt Mackall
Simplify i18n imports
r3891 from i18n import _
Martin Geisler
util: do not corrupt multi-byte characters in wrap
r9480 import error, osutil, encoding
Matt Mackall
chunkbuffer: use += rather than cStringIO to reduce memory footprint...
r11758 import errno, re, shutil, sys, tempfile, traceback
FUJIWARA Katsunori
replace Python standard textwrap by MBCS sensitive one for i18n text...
r11297 import os, stat, time, calendar, textwrap, unicodedata, signal
Brodie Rao
mail/hgweb: support service names for ports (issue2350)...
r12076 import imp, socket
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
Dirkjan Ochtman
python 2.6 compatibility: compatibility wrappers for hash functions
r6470 def sha1(s):
Martin Geisler
util: stop overwriting sha1, overwrite _fastsha1 instead...
r8297 return _fastsha1(s)
def _fastsha1(s):
# This function will import sha1 from hashlib or sha (whichever is
# available) and overwrite itself with it on the first call.
# Subsequent calls will go directly to the imported function.
Sol Jerome
util: avoid using hashlib on Python < 2.5 (issue2278)...
r12051 if sys.version_info >= (2, 5):
Martin Geisler
util: stop overwriting sha1, overwrite _fastsha1 instead...
r8297 from hashlib import sha1 as _sha1
Sol Jerome
util: avoid using hashlib on Python < 2.5 (issue2278)...
r12051 else:
Sune Foldager
util: remove warnings when importing md5 and sha
r8295 from sha import sha as _sha1
Simon Heimberg
util: overwrite sha1 and _fastsha1
r8309 global _fastsha1, sha1
_fastsha1 = sha1 = _sha1
Dirkjan Ochtman
python 2.6 compatibility: compatibility wrappers for hash functions
r6470 return _sha1(s)
Ronny Pfannschmidt
util: fake the builtin buffer if it's missing (jython)
r10756 import __builtin__
Renato Cunha
util: use fakebuffer as buffer in py3k...
r11566 if sys.version_info[0] < 3:
def fakebuffer(sliceable, offset=0):
return sliceable[offset:]
else:
def fakebuffer(sliceable, offset=0):
return memoryview(sliceable)[offset:]
Renato Cunha
util: improved the check for the existence of the 'buffer' builtin...
r11565 try:
buffer
except NameError:
Ronny Pfannschmidt
util: fake the builtin buffer if it's missing (jython)
r10756 __builtin__.buffer = fakebuffer
Martin Geisler
util: always use subprocess
r8280 import subprocess
closefds = os.name == 'posix'
Patrick Mezard
subrepo: normalize svn output line-endings
r10197
Patrick Mezard
subrepo: force en_US.UTF-8 locale when calling svn...
r10199 def popen2(cmd, env=None, newlines=False):
Martin Geisler
util: remove unused bufsize argument...
r9089 # Setting bufsize to -1 lets the system decide the buffer size.
# The default for bufsize is 0, meaning unbuffered. This leads to
# poor performance on Mac OS X: http://bugs.python.org/issue4194
p = subprocess.Popen(cmd, shell=True, bufsize=-1,
Bryan O'Sullivan
Backed out changeset fce065538bcf: it caused a 5x performance regression on OS X
r9083 close_fds=closefds,
Patrick Mezard
subrepo: normalize svn output line-endings
r10197 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
Patrick Mezard
subrepo: force en_US.UTF-8 locale when calling svn...
r10199 universal_newlines=newlines,
env=env)
Martin Geisler
util: always use subprocess
r8280 return p.stdin, p.stdout
Patrick Mezard
subrepo: normalize svn output line-endings
r10197
Patrick Mezard
subrepo: force en_US.UTF-8 locale when calling svn...
r10199 def popen3(cmd, env=None, newlines=False):
Martin Geisler
util: remove unused bufsize argument...
r9089 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
Bryan O'Sullivan
Backed out changeset fce065538bcf: it caused a 5x performance regression on OS X
r9083 close_fds=closefds,
Martin Geisler
util: always use subprocess
r8280 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
Patrick Mezard
subrepo: normalize svn output line-endings
r10197 stderr=subprocess.PIPE,
Patrick Mezard
subrepo: force en_US.UTF-8 locale when calling svn...
r10199 universal_newlines=newlines,
env=env)
Martin Geisler
util: always use subprocess
r8280 return p.stdin, p.stdout, p.stderr
Dirkjan Ochtman
python2.6: use subprocess if available
r7106
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',
Carey Evans
util: Fix date format for 12-hour time.
r9383 '%I:%M:%S%p',
Matt Mackall
improve date parsing for numerous new date formats...
r3808 '%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
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
Matt Mackall
fix memory usage of revlog caches by limiting cache size [issue1639]
r9097 def lrucachefunc(func):
'''cache most recent results of function calls'''
cache = {}
order = []
if func.func_code.co_argcount == 1:
def f(arg):
if arg not in cache:
if len(cache) > 20:
del cache[order.pop(0)]
cache[arg] = func(arg)
else:
order.remove(arg)
order.append(arg)
return cache[arg]
else:
def f(*args):
if args not in cache:
if len(cache) > 20:
del cache[order.pop(0)]
cache[args] = func(*args)
else:
order.remove(args)
order.append(args)
return cache[args]
return f
Matt Mackall
util: take propertycache from context.py
r8207 class propertycache(object):
def __init__(self, func):
self.func = func
self.name = func.__name__
def __get__(self, obj, type=None):
result = self.func(obj)
setattr(obj, self.name, result)
return result
Bryan O'Sullivan
Enhance the file filtering capabilities....
r1293 def pipefilter(s, cmd):
'''filter string S through command CMD, returning its output'''
Martin Geisler
util: simplify pipefilter and avoid subprocess race...
r8302 p = subprocess.Popen(cmd, shell=True, close_fds=closefds,
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
pout, perr = p.communicate(s)
return pout
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
Matt Mackall
many, many trivial check-code fixups
r10282 if code:
raise Abort(_("command '%s' failed: %s") %
(cmd, explain_exit(code)))
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 fp = open(outname, 'rb')
r = fp.read()
fp.close()
return r
Bryan O'Sullivan
Enhance the file filtering capabilities....
r1293 finally:
try:
Matt Mackall
many, many trivial check-code fixups
r10282 if inname:
os.unlink(inname)
except:
pass
Bryan O'Sullivan
Enhance the file filtering capabilities....
r1293 try:
Matt Mackall
many, many trivial check-code fixups
r10282 if outname:
os.unlink(outname)
except:
pass
Bryan O'Sullivan
Enhance the file filtering capabilities....
r1293
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"""
Martin Geisler
util: return boolean result directly in util.binary
r8118 return bool(s and '\0' in s)
Matt Mackall
util: add sort helper
r6762
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)
Matt Mackall
move util.Abort to error.py
r7947 Abort = error.Abort
mpm@selenic.com
[PATCH] Harden os.system...
r508
Matt Mackall
many, many trivial check-code fixups
r10282 def always(fn):
return True
def never(fn):
return False
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724
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 '''
Matt Mackall
many, many trivial check-code fixups
r10282 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
Martin Geisler
util: use 'auditor' as consistent name for path auditors
r12078 def canonpath(root, cwd, myname, auditor=None):
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 """return the canonical path of myname, given cwd and root"""
Nicolas Dumazet
util: canonpath: simplify logic...
r9386 if 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)
Martin Geisler
util: use 'auditor' as consistent name for path auditors
r12078 if auditor is None:
auditor = 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):]
Martin Geisler
util: use 'auditor' as consistent name for path auditors
r12078 auditor(name)
Thomas Arendsen Hein
Enable path validation for copy, rename, debugwalk and other canonpath users....
r1976 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)
Martin Geisler
util: use 'auditor' as consistent name for path auditors
r12078 auditor(name)
Jim Meyering
Fix issue 165: `hg status' with abs path containing a symlink-to-dir fails
r2115 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
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:
Nicolas Dumazet
util: use sys.argv[0] if $HG is unset and 'hg' is not in PATH...
r9632 exe = find_exe('hg') or os.path.basename(sys.argv[0])
set_hgexecutable(exe)
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
Maxim Khitrov
http: deliver hook output to client
r11469 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None, out=None):
Vadim Gelfer
merge util.esystem and util.system.
r1882 '''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
Maxim Khitrov
http: deliver hook output to client
r11469 exception.
if out is specified, it is assumed to be a file-like object that has a
write() method. stdout and stderr will be redirected to out.'''
Mads Kiilerich
util: flush stdout before calling external processes...
r13439 try:
sys.stdout.flush()
except Exception:
pass
Vadim Gelfer
move most of tag code to localrepository class.
r2601 def py2shell(val):
'convert python object into string that is useful to shell'
Martin Geisler
util: use "is" for True/False/None comparisons
r8534 if val is None or val is False:
Vadim Gelfer
move most of tag code to localrepository class.
r2601 return '0'
Martin Geisler
util: use "is" for True/False/None comparisons
r8534 if val is True:
Vadim Gelfer
move most of tag code to localrepository class.
r2601 return '1'
return str(val)
Alexis S. L. Carvalho
util.system: fix quoting on windows
r3905 origcmd = cmd
Steve Borho
util: concentrate quoting knowledge to windows.py quotecommand()...
r13188 cmd = quotecommand(cmd)
Mads Kiilerich
util.system: Use subprocess instead of os.system...
r9517 env = dict(os.environ)
env.update((k, py2shell(v)) for k, v in environ.iteritems())
env['HG'] = hgexecutable()
Maxim Khitrov
http: deliver hook output to client
r11469 if out is None:
rc = subprocess.call(cmd, shell=True, close_fds=closefds,
env=env, cwd=cwd)
else:
proc = subprocess.Popen(cmd, shell=True, close_fds=closefds,
env=env, cwd=cwd, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
for line in proc.stdout:
out.write(line)
proc.wait()
rc = proc.returncode
Mads Kiilerich
util.system: Use subprocess instead of os.system...
r9517 if sys.platform == 'OpenVMS' and rc & 1:
rc = 0
if rc and onerr:
errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
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
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
Adrian Buehlmann
set NOT_CONTENT_INDEXED on .hg dir (issue2694)...
r13795 def makedir(path, notindexed):
os.mkdir(path)
Adrian Buehlmann
rename util.unlink to unlinkpath
r13235 def unlinkpath(f):
Benoit Boissinot
refactor some unlink/remove code and make sure we prune empty dir
r1415 """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)
Brodie Rao
record: move copystat() hack out of util.copyfile() and into record...
r13099 shutil.copymode(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
Adrian Buehlmann
clone: print number of linked/copied files on --debug
r11251 num = 0
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)
Adrian Buehlmann
clone: print number of linked/copied files on --debug
r11251 hardlink, n = copyfiles(srcname, dstname, hardlink)
num += n
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)
Adrian Buehlmann
clone: print number of linked/copied files on --debug
r11251 num += 1
Thomas Arendsen Hein
Use python function instead of external 'cp' command when cloning repos....
r698
Adrian Buehlmann
clone: print number of linked/copied files on --debug
r11251 return hardlink, num
Adrian Buehlmann
util.copyfiles: don't try os_link() again if it failed before...
r11254
Adrian Buehlmann
util: new function checkfilename...
r13944 def checkfilename(f):
'''Check that the filename f is an acceptable filename for a tracked file'''
if '\r' in f or '\n' in f:
raise Abort(_("'\\n' and '\\r' disallowed in filenames: %r") % f)
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916 _windows_reserved_filenames = '''con prn aux nul
com1 com2 com3 com4 com5 com6 com7 com8 com9
lpt1 lpt2 lpt3 lpt4 lpt5 lpt6 lpt7 lpt8 lpt9'''.split()
_windows_reserved_chars = ':*?"<>|'
def checkwinfilename(path):
'''Check that the base-relative path is a valid filename on Windows.
Returns None if the path is ok, or a UI string describing the problem.
>>> checkwinfilename("just/a/normal/path")
>>> checkwinfilename("foo/bar/con.xml")
"filename contains 'con', which is reserved on Windows"
>>> checkwinfilename("foo/con.xml/bar")
"filename contains 'con', which is reserved on Windows"
>>> checkwinfilename("foo/bar/xml.con")
>>> checkwinfilename("foo/bar/AUX/bla.txt")
"filename contains 'AUX', which is reserved on Windows"
>>> checkwinfilename("foo/bar/bla:.txt")
"filename contains ':', which is reserved on Windows"
>>> checkwinfilename("foo/bar/b\07la.txt")
Adrian Buehlmann
checkwinfilename: use %r in format string
r13947 "filename contains '\\\\x07', which is invalid on Windows"
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916 >>> checkwinfilename("foo/bar/bla ")
"filename ends with ' ', which is not allowed on Windows"
'''
for n in path.replace('\\', '/').split('/'):
if not n:
continue
for c in n:
if c in _windows_reserved_chars:
return _("filename contains '%s', which is reserved "
"on Windows") % c
if ord(c) <= 31:
Adrian Buehlmann
checkwinfilename: use %r in format string
r13947 return _("filename contains %r, which is invalid "
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916 "on Windows") % c
base = n.split('.')[0]
if base and base.lower() in _windows_reserved_filenames:
return _("filename contains '%s', which is reserved "
"on Windows") % base
t = n[-1]
if t in '. ':
return _("filename ends with '%s', which is not allowed "
"on Windows") % t
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:
Jim Hague
opener: forbid paths ending with directory separator (issue2507)...
r13197 - ends with a directory separator
Bryan O'Sullivan
Make audit_path more stringent....
r5158 - under top-level .hg
- starts at the root of a windows drive
- contains ".."
- traverses a symlink (e.g. a/symlink_here/b)
Martin Geisler
path_auditor: delegate checking of nested repos to a callback
r12079 - inside a nested repository (a callback can be used to approve
some nested repositories, e.g., subrepositories)
'''
Bryan O'Sullivan
Make audit_path more stringent....
r5158
Martin Geisler
path_auditor: delegate checking of nested repos to a callback
r12079 def __init__(self, root, callback=None):
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
Martin Geisler
path_auditor: delegate checking of nested repos to a callback
r12079 self.callback = callback
Bryan O'Sullivan
Make audit_path more stringent....
r5158
def __call__(self, path):
Adrian Buehlmann
path_auditor: eliminate local function 'check' in __call__
r13928 '''Check the relative path.
path may contain a pattern (e.g. foodir/**.txt)'''
Bryan O'Sullivan
Make audit_path more stringent....
r5158 if path in self.audited:
return
Jim Hague
opener: forbid paths ending with directory separator (issue2507)...
r13197 # AIX ignores "/" at end of path, others raise EISDIR.
if endswithsep(path):
raise Abort(_("path ends in directory separator: %s") % path)
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])
Matt Mackall
audit: improve nested repo message
r13910 raise Abort(_('path %r is inside nested repo %r')
% (path, base))
Adrian Buehlmann
path_auditor: eliminate local function 'check' in __call__
r13928
parts.pop()
prefixes = []
while parts:
prefix = os.sep.join(parts)
if prefix in self.auditeddir:
break
Bryan O'Sullivan
Make audit_path more stringent....
r5158 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'))):
Martin Geisler
path_auditor: delegate checking of nested repos to a callback
r12079 if not self.callback or not self.callback(curpath):
Matt Mackall
audit: improve nested repo message
r13910 raise Abort(_('path %r is inside nested repo %r') %
Martin Geisler
path_auditor: delegate checking of nested repos to a callback
r12079 (path, prefix))
Alexis S. L. Carvalho
path_auditor: cache names of audited directories...
r5200 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
Sune Foldager
util: don't overwrite os-specific functions with general ones
r8011 def lookup_reg(key, name=None, scope=None):
return None
Patrick Mezard
cmdutil: hide child window created by win32 spawndetached()...
r10240 def hidewindow():
"""Hide current shell window.
Used to hide the window opened when starting asynchronous
child process under Windows, unneeded on other systems.
"""
pass
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 if os.name == 'nt':
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916 checkosfilename = checkwinfilename
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 from windows import *
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
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 fp = posixfile(pathname)
r = fp.read()
fp.close()
return r
Thomas Arendsen Hein
Make makelock and readlock work on filesystems without symlink support....
r704
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)
Matt Mackall
backout most of 4f8067c94729
r12401 if name[l] == os.sep or name[l] == os.altsep:
Paul Moore
Add a new function, fspath...
r6676 l = l + 1
name = name[l:]
Patrick Mezard
Use lexists() instead of exists() where appropriate
r12344 if not os.path.lexists(os.path.join(root, name)):
Paul Moore
Add a new function, fspath...
r6676 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()
Simon Heimberg
util: quicker fspath, do not lower names when the length is different
r9397 lenp = len(part)
Paul Moore
Add a new function, fspath...
r6676 for n in contents:
Simon Heimberg
util: quicker fspath, do not lower names when the length is different
r9397 if lenp == len(n) and n.lower() == lpart:
Paul Moore
Add a new function, fspath...
r6676 result.append(n)
break
else:
# Cannot happen, as the file exists!
result.append(part)
dir = os.path.join(dir, lpart)
return ''.join(result)
Adrian Buehlmann
opener: check hardlink count reporting (issue1866)...
r12938 def checknlink(testfile):
'''check whether hardlink count reporting works properly'''
Adrian Buehlmann
checknlink: use two testfiles (issue2543)...
r13204 # testfile may be open, so we need a separate file for checking to
# work around issue2543 (or testfile may get lost on Samba shares)
f1 = testfile + ".hgtmp1"
if os.path.lexists(f1):
return False
Adrian Buehlmann
opener: check hardlink count reporting (issue1866)...
r12938 try:
Adrian Buehlmann
checknlink: use two testfiles (issue2543)...
r13204 posixfile(f1, 'w').close()
except IOError:
Adrian Buehlmann
opener: check hardlink count reporting (issue1866)...
r12938 return False
Adrian Buehlmann
checknlink: use two testfiles (issue2543)...
r13204 f2 = testfile + ".hgtmp2"
fd = None
Adrian Buehlmann
opener: check hardlink count reporting (issue1866)...
r12938 try:
Adrian Buehlmann
checknlink: use two testfiles (issue2543)...
r13204 try:
os_link(f1, f2)
except OSError:
return False
Adrian Buehlmann
opener: check hardlink count reporting (issue1866)...
r12938 # nlinks() may behave differently for files on Windows shares if
# the file is open.
Adrian Buehlmann
opener: use posixfile to hold file open when calling nlinks()...
r13342 fd = posixfile(f2)
Adrian Buehlmann
checknlink: use two testfiles (issue2543)...
r13204 return nlinks(f2) > 1
Adrian Buehlmann
opener: check hardlink count reporting (issue1866)...
r12938 finally:
Adrian Buehlmann
checknlink: use two testfiles (issue2543)...
r13204 if fd is not None:
fd.close()
for f in (f1, f2):
try:
os.unlink(f)
except OSError:
pass
Adrian Buehlmann
opener: check hardlink count reporting (issue1866)...
r12938
return False
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?'''
Dan Villiom Podlaski Christiansen
util: add Mac-specific check whether we're in a GUI session (issue2553)...
r13734 if sys.platform == 'darwin':
if 'SSH_CONNECTION' in os.environ:
# handle SSH access to a box where the user is logged in
return False
elif getattr(osutil, 'isgui', None):
# check if a CoreGraphics session is available
return osutil.isgui()
else:
# pure build; use a safe default
return True
else:
return os.name == "nt" or os.environ.get("DISPLAY")
Matt Mackall
filemerge: add config item for GUI tools...
r6007
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
Benoit Boissinot
use new style classes
r8778 class atomictempfile(object):
Alexis S. L. Carvalho
turn util.opener into a class
r4827 """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.
"""
Yuya Nishihara
util: give appropriate default args to atomictempfile()...
r11212 def __init__(self, name, mode='w+b', createmode=None):
Alexis S. L. Carvalho
turn util.opener into a class
r4827 self.__name = name
Bryan O'Sullivan
util: make atomictempfile saner if mktempcopy fails
r8420 self._fp = None
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)
Bryan O'Sullivan
atomictempfile: delegate to posixfile instead of inheriting from it
r8327 self._fp = posixfile(self.temp, mode)
def __getattr__(self, name):
return getattr(self._fp, name)
Alexis S. L. Carvalho
turn util.opener into a class
r4827
def rename(self):
Benoit Boissinot
atomictempfile: fix exception in __del__ if mktempcopy fails (self._fp is None)...
r8785 if not self._fp.closed:
Bryan O'Sullivan
atomictempfile: delegate to posixfile instead of inheriting from it
r8327 self._fp.close()
Alexis S. L. Carvalho
turn util.opener into a class
r4827 rename(self.temp, localpath(self.__name))
Dan Villiom Podlaski Christiansen
util: make atomicfiles closable
r13098 def close(self):
Benoit Boissinot
atomictempfile: fix exception in __del__ if mktempcopy fails (self._fp is None)...
r8785 if not self._fp:
return
if not self._fp.closed:
Alexis S. L. Carvalho
turn util.opener into a class
r4827 try:
os.unlink(self.temp)
except: pass
Bryan O'Sullivan
atomictempfile: delegate to posixfile instead of inheriting from it
r8327 self._fp.close()
Alexis S. L. Carvalho
turn util.opener into a class
r4827
Dan Villiom Podlaski Christiansen
util: make atomicfiles closable
r13098 def __del__(self):
self.close()
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"""
Adrian Buehlmann
makedirs: abort if parent == name (issue2531)...
r13068 parent = os.path.abspath(os.path.dirname(name))
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 try:
os.mkdir(name)
if mode is not None:
os.chmod(name, mode)
return
except OSError, err:
if err.errno == errno.EEXIST:
return
Adrian Buehlmann
makedirs: abort if parent == name (issue2531)...
r13068 if not name or parent == name or err.errno != errno.ENOENT:
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 raise
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:
Martin Geisler
util: use 'auditor' as consistent name for path auditors
r12078 self.auditor = path_auditor(base)
Bryan O'Sullivan
Make audit_path more stringent....
r5158 else:
Martin Geisler
util: use 'auditor' as consistent name for path auditors
r12078 self.auditor = always
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 self.createmode = None
Adrian Buehlmann
opener: check hardlink count reporting (issue1866)...
r12938 self._trustnlink = None
Vadim Gelfer
fix file handling bugs on windows....
r2176
Simon Heimberg
util: use propertycache in opener instead of __getattr__
r9112 @propertycache
def _can_symlink(self):
return checklink(self.base)
Alexis S. L. Carvalho
Add symlink method to util.opener....
r4828
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):
Adrian Buehlmann
util: move checkosfilename call from path_auditor to opener...
r13926 r = checkosfilename(path)
if r:
Adrian Buehlmann
opener: use %r in format string for abort
r13943 raise Abort("%s: %r" % (r, path))
Martin Geisler
util: use 'auditor' as consistent name for path auditors
r12078 self.auditor(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
Adrian Buehlmann
util: refactor opener...
r12927 dirname, basename = os.path.split(f)
# If basename is empty, then the path is malformed because it points
# to a directory. Let the posixfile() call below raise IOError.
if basename and mode not in ('r', 'rb'):
if atomictemp:
if not os.path.isdir(dirname):
makedirs(dirname, self.createmode)
return atomictempfile(f, mode, self.createmode)
Vadim Gelfer
fix file handling bugs on windows....
r2176 try:
Adrian Buehlmann
util: refactor opener...
r12927 if 'w' in mode:
Adrian Buehlmann
opener: use util.unlink (issue2524)
r13282 unlink(f)
Adrian Buehlmann
util: refactor opener...
r12927 nlink = 0
else:
Adrian Buehlmann
opener: check hardlink count reporting (issue1866)...
r12938 # nlinks() may behave differently for files on Windows
# shares if the file is open.
Adrian Buehlmann
opener: use posixfile to hold file open when calling nlinks()...
r13342 fd = posixfile(f)
Adrian Buehlmann
util: refactor opener...
r12927 nlink = nlinks(f)
Adrian Buehlmann
opener: force copy on 'a'ppend if nlinks() returns 0 (issue1922)...
r13305 if nlink < 1:
nlink = 2 # force mktempcopy (issue1922)
Adrian Buehlmann
opener: check hardlink count reporting (issue1866)...
r12938 fd.close()
Adrian Buehlmann
opener: check exception for ENOENT
r13279 except (OSError, IOError), e:
if e.errno != errno.ENOENT:
raise
Alexis S. L. Carvalho
util.opener: if requested, use atomicfile even if the file doesn't exist...
r4328 nlink = 0
Adrian Buehlmann
util: refactor opener...
r12927 if not os.path.isdir(dirname):
Martin Geisler
opener: do not create "foo" directory when writing to "foo/"...
r12877 makedirs(dirname, self.createmode)
Adrian Buehlmann
opener: check hardlink count reporting (issue1866)...
r12938 if nlink > 0:
if self._trustnlink is None:
self._trustnlink = nlink > 1 or checknlink(f)
if nlink > 1 or not self._trustnlink:
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:
Adrian Buehlmann
opener: always reset flags on 'w'rite...
r13112 self._fixfilemode(f)
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 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):
Martin Geisler
util: use 'auditor' as consistent name for path auditors
r12078 self.auditor(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."""
Benoit Boissinot
chunkbuffer: split big strings directly in chunkbuffer
r11670 def splitbig(chunks):
for chunk in chunks:
if len(chunk) > 2**20:
pos = 0
while pos < len(chunk):
end = pos + 2 ** 18
yield chunk[pos:end]
pos = end
else:
yield chunk
self.iter = splitbig(in_iter)
Matt Mackall
chunkbuffer: use += rather than cStringIO to reduce memory footprint...
r11758 self._queue = []
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
chunkbuffer: use += rather than cStringIO to reduce memory footprint...
r11758 left = l
buf = ''
queue = self._queue
while left > 0:
# refill the queue
if not queue:
target = 2**18
for chunk in self.iter:
queue.append(chunk)
target -= len(chunk)
if target <= 0:
break
if not queue:
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 break
Matt Mackall
chunkbuffer: use += rather than cStringIO to reduce memory footprint...
r11758
chunk = queue.pop(0)
left -= len(chunk)
if left < 0:
queue.insert(0, chunk[left:])
buf += chunk[:left]
else:
buf += chunk
return buf
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:
Matt Mackall
many, many trivial check-code fixups
r10282 if limit is None:
nbytes = size
else:
nbytes = min(limit, size)
Vadim Gelfer
util: add limit to amount filechunkiter will read
r2462 s = nbytes and f.read(nbytes)
Matt Mackall
many, many trivial check-code fixups
r10282 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
Adrian Buehlmann
makedate: abort on negative timestamps (issue2513)...
r13063 t = time.mktime(lt)
if t < 0:
hint = _("check your clock")
raise Abort(_("negative timestamp: %d") % t, hint=hint)
return t, 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()
Adrian Buehlmann
util.datestr: do not crash on revisions with negative timestamp (issue2513)...
r13039 if t < 0:
t = 0 # time.gmtime(lt) fails on Windows for lt < -43200
tz = 0
Matt Mackall
dates: improve timezone handling...
r6229 if "%1" in format or "%2" in format:
sign = (tz > 0) and "-" or "+"
Alejandro Santos
compat: use // for integer division
r9029 minutes = abs(tz) // 60
format = format.replace("%1", "%c%02d" % (sign, minutes // 60))
Matt Mackall
dates: improve timezone handling...
r6229 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
backout most of 4f8067c94729
r12401 if tz == "GMT" or tz == "UTC":
Matt Mackall
parsedate: add UTC and GMT timezones
r3809 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
Martin Geisler
code style: prefer 'is' and 'is not' tests with singletons
r13031 if offset is not None:
Matt Mackall
parsedate: add UTC and GMT timezones
r3809 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
Matt Mackall
date: fix matching of underspecified date ranges...
r13212 usenow = False # default to using biased defaults
for part in ("S", "M", "HI", "d", "mb", "yY"): # decreasing specificity
Matt Mackall
Add date matching support...
r3812 found = [True for p in part if ("%"+p) in format]
if not found:
Matt Mackall
date: fix matching of underspecified date ranges...
r13212 date += "@" + defaults[part][usenow]
Matt Mackall
Add date matching support...
r3812 format += "@%" + part[0]
Matt Mackall
date: fix matching of underspecified date ranges...
r13212 else:
# We've found a specific time element, less specific time
# elements are relative to today
usenow = True
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
date: fix matching of underspecified date ranges...
r13212 def parsedate(date, formats=None, bias={}):
"""parse a localized date/time and return a (unixtime, offset) tuple.
Thomas Arendsen Hein
Fix bad behaviour when specifying an invalid date (issue700)...
r6139
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
now = makedate()
Matt Mackall
date: fix matching of underspecified date ranges...
r13212 defaults = {}
nowmap = {}
David Soria Parra
avoid .split() in for loops and use tuples instead...
r13200 for part in ("d", "mb", "yY", "HI", "M", "S"):
Matt Mackall
date: fix matching of underspecified date ranges...
r13212 # this piece is for rounding the specific end of unknowns
b = bias.get(part)
if b is None:
Matt Mackall
Add date matching support...
r3812 if part[0] in "HMS":
Matt Mackall
date: fix matching of underspecified date ranges...
r13212 b = "00"
Matt Mackall
Add date matching support...
r3812 else:
Matt Mackall
date: fix matching of underspecified date ranges...
r13212 b = "0"
# this piece is for matching the generic end to today's date
n = datestr(now, "%" + part[0])
defaults[part] = (b, n)
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:
Nicolas Dumazet
util: get rid of extra trailing whitespace in parsedate abort message
r12105 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)
Adrian Buehlmann
parsedate: abort on negative dates (issue2513)...
r13062 if when < 0:
raise Abort(_('negative date value: %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
Matt Mackall
date: fix matching of underspecified date ranges...
r13212 >>> p1 = parsedate("10:29:59")
>>> p2 = parsedate("10:30:00")
>>> p3 = parsedate("10:30:59")
>>> p4 = parsedate("10:31:00")
>>> p5 = parsedate("Sep 15 10:30:00 1999")
>>> f = matchdate("10:30")
>>> f(p1[0])
False
>>> f(p2[0])
True
>>> f(p3[0])
True
>>> f(p4[0])
False
>>> f(p5[0])
False
Matt Mackall
Add date matching support...
r3812 """
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")
David Soria Parra
avoid .split() in for loops and use tuples instead...
r13200 for days in ("31", "30", "29"):
Matt Mackall
Add date matching support...
r3812 try:
d["d"] = days
return parsedate(date, extendeddateformats, d)[0]
except:
pass
d["d"] = "28"
return parsedate(date, extendeddateformats, d)[0]
Justin Peng
Correct a bug on date formats with '>' or '<' accompanied by space characters.
r7953 date = date.strip()
Idan Kamara
util: dates cannot consist entirely of whitespace (issue2732)
r13780
if not date:
raise Abort(_("dates cannot consist entirely of whitespace"))
elif date[0] == "<":
Matt Mackall
date: fixup breakage from ">" fix
r13869 if not date[1:]:
Martin Geisler
help/dates: use DATE as place-holder in help and abort texts...
r13886 raise Abort(_("invalid day spec, use '<DATE'"))
Matt Mackall
Add date matching support...
r3812 when = upper(date[1:])
return lambda x: x <= when
elif date[0] == ">":
Matt Mackall
date: fixup breakage from ">" fix
r13869 if not date[1:]:
Martin Geisler
help/dates: use DATE as place-holder in help and abort texts...
r13886 raise Abort(_("invalid day spec, use '>DATE'"))
Matt Mackall
Add date matching support...
r3812 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:])
Yun Lee
util: make 'hg log -d --2' abort (issue2734)
r13889 if days < 0:
raise Abort(_("%s must be nonnegative (see 'hg help dates')")
% date[1:])
Matt Mackall
Add date matching support...
r3812 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:
Matt Mackall
many, many trivial check-code fixups
r10282 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('>')
Matt Mackall
many, many trivial check-code fixups
r10282 if r == -1:
r = None
return author[author.find('<') + 1:r]
Matt Mackall
templater: move email function to util
r5975
Yuya Nishihara
util: fix ellipsis() not to break multi-byte sequence (issue2564)...
r13225 def _ellipsis(text, maxlength):
if len(text) <= maxlength:
return text, False
else:
return "%s..." % (text[:maxlength - 3]), True
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."""
Yuya Nishihara
util: fix ellipsis() not to break multi-byte sequence (issue2564)...
r13225 try:
# use unicode not to split at intermediate multi-byte sequence
utext, truncated = _ellipsis(text.decode(encoding.encoding),
maxlength)
if not truncated:
return text
return utext.encode(encoding.encoding)
except (UnicodeDecodeError, UnicodeEncodeError):
return _ellipsis(text, maxlength)[0]
Thomas Arendsen Hein
Move ellipsis code to util.ellipsis() and improve maxlength handling.
r3767
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):
Dirkjan Ochtman
util: sort paths in walkrepos() (fixes test failures in test-hgwebdir)
r9732 dirs.sort()
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):
Matt Mackall
many, many trivial check-code fixups
r10282 if not p:
continue
Alexander Solovyov
make path expanding more consistent...
r9610 p = expandpath(p)
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 = (
Matt Mackall
many, many trivial check-code fixups
r10282 (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')),
Vadim Gelfer
add support for streaming clone....
r2612 (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
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
Matt Mackall
util: delay loading of textwrap
r13316 # delay import of textwrap
def MBTextWrapper(**kwargs):
class tw(textwrap.TextWrapper):
"""
Extend TextWrapper for double-width characters.
Nicolas Dumazet
util: clarify purpose of MBTextWrapper class...
r12957
Matt Mackall
util: delay loading of textwrap
r13316 Some Asian characters use two terminal columns instead of one.
A good example of this behavior can be seen with u'\u65e5\u672c',
the two Japanese characters for "Japan":
len() returns 2, but when printed to a terminal, they eat 4 columns.
Nicolas Dumazet
util: clarify purpose of MBTextWrapper class...
r12957
Matt Mackall
util: delay loading of textwrap
r13316 (Note that this has nothing to do whatsoever with unicode
representation, or encoding of the underlying string)
"""
def __init__(self, **kwargs):
textwrap.TextWrapper.__init__(self, **kwargs)
FUJIWARA Katsunori
replace Python standard textwrap by MBCS sensitive one for i18n text...
r11297
Matt Mackall
util: delay loading of textwrap
r13316 def _cutdown(self, str, space_left):
l = 0
ucstr = unicode(str, encoding.encoding)
colwidth = unicodedata.east_asian_width
for i in xrange(len(ucstr)):
l += colwidth(ucstr[i]) in 'WFA' and 2 or 1
if space_left < l:
return (ucstr[:i].encode(encoding.encoding),
ucstr[i:].encode(encoding.encoding))
return str, ''
FUJIWARA Katsunori
replace Python standard textwrap by MBCS sensitive one for i18n text...
r11297
Matt Mackall
util: delay loading of textwrap
r13316 # overriding of base class
def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
space_left = max(width - cur_len, 1)
FUJIWARA Katsunori
replace Python standard textwrap by MBCS sensitive one for i18n text...
r11297
Matt Mackall
util: delay loading of textwrap
r13316 if self.break_long_words:
cut, res = self._cutdown(reversed_chunks[-1], space_left)
cur_line.append(cut)
reversed_chunks[-1] = res
elif not cur_line:
cur_line.append(reversed_chunks.pop())
FUJIWARA Katsunori
replace Python standard textwrap by MBCS sensitive one for i18n text...
r11297
Matt Mackall
util: delay loading of textwrap
r13316 global MBTextWrapper
MBTextWrapper = tw
return tw(**kwargs)
FUJIWARA Katsunori
replace Python standard textwrap by MBCS sensitive one for i18n text...
r11297
Matt Mackall
util: make wrap() require a width argument...
r12698 def wrap(line, width, initindent='', hangindent=''):
FUJIWARA Katsunori
replace Python standard textwrap by MBCS sensitive one for i18n text...
r11297 maxindent = max(len(hangindent), len(initindent))
if width <= maxindent:
Martin Geisler
util, minirst: do not crash with COLUMNS=0
r9417 # adjust for weird terminal size
FUJIWARA Katsunori
replace Python standard textwrap by MBCS sensitive one for i18n text...
r11297 width = max(78, maxindent + 1)
wrapper = MBTextWrapper(width=width,
initial_indent=initindent,
subsequent_indent=hangindent)
return wrapper.fill(line)
Martin Geisler
commands: wrap short descriptions in 'hg help'...
r8938
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
Alexander Solovyov
make path expanding more consistent...
r9610
def expandpath(path):
return os.path.expanduser(os.path.expandvars(path))
Patrick Mezard
Find right hg command for detached process...
r10239
def hgcmd():
"""Return the command used to execute current hg
This is different from hgexecutable() because on Windows we want
to avoid things opening new shell windows like batch files, so we
get either the python call or current executable.
"""
if main_is_frozen():
return [sys.executable]
return gethgcmd()
Patrick Mezard
util: make spawndetached() handle subprocess early terminations...
r10344
def rundetached(args, condfn):
"""Execute the argument list in a detached process.
Augie Fackler
util: fix trailing whitespace found by check-code
r10422
Patrick Mezard
util: make spawndetached() handle subprocess early terminations...
r10344 condfn is a callable which is called repeatedly and should return
True once the child process is known to have started successfully.
At this point, the child process PID is returned. If the child
process fails to start or finishes before condfn() evaluates to
True, return -1.
"""
# Windows case is easier because the child process is either
# successfully starting and validating the condition or exiting
# on failure. We just poll on its PID. On Unix, if the child
# process fails to start, it will be left in a zombie state until
# the parent wait on it, which we cannot do since we expect a long
# running process on success. Instead we listen for SIGCHLD telling
# us our child process terminated.
terminated = set()
def handler(signum, frame):
terminated.add(os.wait())
prevhandler = None
if hasattr(signal, 'SIGCHLD'):
prevhandler = signal.signal(signal.SIGCHLD, handler)
try:
pid = spawndetached(args)
while not condfn():
if ((pid in terminated or not testpid(pid))
and not condfn()):
return -1
time.sleep(0.1)
return pid
finally:
if prevhandler is not None:
signal.signal(signal.SIGCHLD, prevhandler)
Steve Losh
util: add any() and all() functions for Python 2.4 compatibility...
r10438
Steve Losh
util: use the built-in any() and all() methods if they are available
r10487 try:
any, all = any, all
except NameError:
def any(iterable):
for i in iterable:
if i:
return True
return False
Steve Losh
util: add any() and all() functions for Python 2.4 compatibility...
r10438
Steve Losh
util: use the built-in any() and all() methods if they are available
r10487 def all(iterable):
for i in iterable:
if not i:
return False
return True
Patrick Mezard
util: fix default termwidth() under Windows...
r11010
Roman Sokolov
dispatch: support for $ escaping in shell-alias definition...
r13392 def interpolate(prefix, mapping, s, fn=None, escape_prefix=False):
Steve Losh
util: add an interpolate() function to for replacing multiple values...
r11988 """Return the result of interpolating items in the mapping into string s.
prefix is a single character string, or a two character string with
a backslash as the first character if the prefix needs to be escaped in
a regular expression.
fn is an optional function that will be applied to the replacement text
just before replacement.
Roman Sokolov
dispatch: support for $ escaping in shell-alias definition...
r13392
escape_prefix is an optional flag that allows using doubled prefix for
its escaping.
Steve Losh
util: add an interpolate() function to for replacing multiple values...
r11988 """
fn = fn or (lambda s: s)
Roman Sokolov
dispatch: support for $ escaping in shell-alias definition...
r13392 patterns = '|'.join(mapping.keys())
if escape_prefix:
patterns += '|' + prefix
if len(prefix) > 1:
prefix_char = prefix[1:]
else:
prefix_char = prefix
mapping[prefix_char] = prefix_char
r = re.compile(r'%s(%s)' % (prefix, patterns))
Steve Losh
util: add an interpolate() function to for replacing multiple values...
r11988 return r.sub(lambda x: fn(mapping[x.group()[1:]]), s)
Brodie Rao
mail/hgweb: support service names for ports (issue2350)...
r12076 def getport(port):
"""Return the port for a given network service.
If port is an integer, it's returned as is. If it's a string, it's
looked up using socket.getservbyname(). If there's no matching
service, util.Abort is raised.
"""
try:
return int(port)
except ValueError:
pass
try:
return socket.getservbyname(port)
except socket.error:
raise Abort(_("no port number associated with service '%s'") % port)
Augie Fackler
parsebool: create new function and use it for config parsing
r12087
Augie Fackler
parsebool: accept always as true and never as false
r12088 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True, 'always': True,
'0': False, 'no': False, 'false': False, 'off': False,
'never': False}
Augie Fackler
parsebool: create new function and use it for config parsing
r12087
def parsebool(s):
"""Parse s into a boolean.
If s is not a valid boolean, returns None.
"""
return _booleans.get(s.lower(), None)