##// END OF EJS Templates
test-command-template: test 'file_copies' keyword
test-command-template: test 'file_copies' keyword

File last commit:

r9996:2770d03a stable
r10059:9dd4e285 default
Show More
util.py
1270 lines | 39.1 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
# GNU General Public License version 2, incorporated herein by reference.
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
Simon Heimberg
separate import lines from mercurial and general python modules
r8312 import cStringIO, errno, re, shutil, sys, tempfile, traceback
Adrian Buehlmann
util: move rename into posix.py and windows.py
r9549 import os, stat, time, calendar, textwrap
Matt Mackall
move encoding bits from util to encoding...
r7948 import imp
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.
Martin Geisler
util: initialize md5 and sha1 without using extra global variables...
r8281 try:
Martin Geisler
util: stop overwriting sha1, overwrite _fastsha1 instead...
r8297 from hashlib import sha1 as _sha1
Martin Geisler
util: initialize md5 and sha1 without using extra global variables...
r8281 except ImportError:
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)
Martin Geisler
util: always use subprocess
r8280 import subprocess
closefds = os.name == 'posix'
Martin Geisler
util: remove unused bufsize argument...
r9089 def popen2(cmd):
# 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,
Martin Geisler
util: always use subprocess
r8280 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
return p.stdin, p.stdout
Martin Geisler
util: remove unused bufsize argument...
r9089 def popen3(cmd):
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,
stderr=subprocess.PIPE)
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
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"""
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
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724 def always(fn): return True
def never(fn): return False
Alexis S. L. Carvalho
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"""
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)
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
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
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'
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
if os.name == 'nt':
cmd = '"%s"' % 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()
rc = subprocess.call(cmd, shell=True, close_fds=closefds,
env=env, cwd=cwd)
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
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
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 = []
Martin Geisler
util: simplify range expression...
r8631 while parts:
Shun-ichi GOTO
Fix not to use os.sep directly....
r5845 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
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
Sune Foldager
util: don't overwrite os-specific functions with general ones
r8011 def lookup_reg(key, name=None, scope=None):
return None
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 if os.name == 'nt':
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
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
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()
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)
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")
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.
"""
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
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))
def __del__(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
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
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):
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 "+"
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
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]
Justin Peng
Correct a bug on date formats with '>' or '<' accompanied by space characters.
r7953 date = date.strip()
Matt Mackall
Add date matching support...
r3812 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):
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):
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 = (
(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('//'):
Sune Foldager
handle file URIs correctly, according to RFC 2396 (issue1153)...
r9996 if scheme == 'file':
i = path.find('/', 2)
if i == -1:
return ''
# On Windows, absolute paths are rooted at the current drive
# root. On POSIX they are rooted at the file system root.
if os.name == 'nt':
droot = os.path.splitdrive(os.getcwd())[0] + '/'
path = os.path.join(droot, path[i+1:])
else:
path = path[i:]
else:
path = path[2:]
Vadim Gelfer
clean up hg.py: move repo constructor code into each repo module
r2740 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:
Bryan O'Sullivan
util.termwidth: a file-like object may legitimately lack a fileno() method...
r8347 try:
fd = dev.fileno()
except AttributeError:
continue
Alexander Solovyov
python implementation of diffstat...
r7547 if not os.isatty(fd):
continue
arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8)
return array.array('h', arri)[1]
except ValueError:
pass
Dirkjan Ochtman
kill trailing whitespace
r9712 except IOError, e:
if e[0] == errno.EINVAL:
pass
else:
raise
Alexander Solovyov
python implementation of diffstat...
r7547 except ImportError:
pass
return 80
Alexander Solovyov <piranha at piranha.org.ua>
templater: ability to display diffstat for log-like commands
r7879
Martin Geisler
util: wrap at termwidth-2 by default
r9155 def wrap(line, hangindent, width=None):
if width is None:
width = termwidth() - 2
Martin Geisler
util, minirst: do not crash with COLUMNS=0
r9417 if width <= hangindent:
# adjust for weird terminal size
width = max(78, hangindent + 1)
Martin Geisler
commands: wrap short descriptions in 'hg help'...
r8938 padding = '\n' + ' ' * hangindent
Martin Geisler
util: do not corrupt multi-byte characters in wrap
r9480 # To avoid corrupting multi-byte characters in line, we must wrap
# a Unicode string instead of a bytestring.
Martin Geisler
ui: guard against UnicodeDecodeErrors in ui.wrap
r9495 try:
u = line.decode(encoding.encoding)
w = padding.join(textwrap.wrap(u, width=width - hangindent))
return w.encode(encoding.encoding)
except UnicodeDecodeError:
return padding.join(textwrap.wrap(line, width=width - hangindent))
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))