##// END OF EJS Templates
fix issue 322....
fix issue 322. do not allow to add files that shadow files or directories already in dirstate.

File last commit:

r2953:3d554784 default
r2953:3d554784 default
Show More
util.py
997 lines | 30.9 KiB | text/x-python | PythonLexer
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 """
util.py - Mercurial utility functions and platform specfic implementations
Copyright 2005 K. Thananchayan <thananck@yahoo.com>
Vadim Gelfer
update copyrights.
r2859 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
This contains helper routines that are independent of the SCM core and hide
platform-specific details from the core.
"""
mpm@selenic.com
[PATCH] file seperator handling for the other 'OS'...
r419
Benoit Boissinot
i18n first part: make '_' available for files who need it
r1400 from i18n import gettext as _
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724 from demandload import *
Vadim Gelfer
fix windows username problem.
r2652 demandload(globals(), "cStringIO errno getpass popen2 re shutil sys tempfile")
Vadim Gelfer
use demandload more.
r2470 demandload(globals(), "os threading time")
mpm@selenic.com
Add file encoding/decoding support
r1258
Chris Mason
util.parsedate should understand dates from hg export
r2609 # used by parsedate
defaultdateformats = ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M',
'%a %b %d %H:%M:%S %Y')
Vadim Gelfer
move SignalInterrupt class into util module.
r2153 class SignalInterrupt(Exception):
"""Exception raised on SIGTERM and SIGHUP."""
Bryan O'Sullivan
Enhance the file filtering capabilities....
r1293 def pipefilter(s, cmd):
'''filter string S through command CMD, returning its output'''
mpm@selenic.com
Add file encoding/decoding support
r1258 (pout, pin) = popen2.popen2(cmd, -1, 'b')
def writer():
Alexis S. L. Carvalho
Ignore EPIPE in pipefilter...
r2096 try:
pin.write(s)
pin.close()
except IOError, inst:
if inst.errno != errno.EPIPE:
raise
mpm@selenic.com
Add file encoding/decoding support
r1258
# we should use select instead on UNIX, but this will work on most
# systems, including Windows
w = threading.Thread(target=writer)
w.start()
f = pout.read()
pout.close()
w.join()
return f
mpm@selenic.com
[PATCH] file seperator handling for the other 'OS'...
r419
Bryan O'Sullivan
Enhance the file filtering capabilities....
r1293 def tempfilter(s, cmd):
'''filter string S through a pair of temporary files with CMD.
CMD is used as a template to create the real command to be run,
with the strings INFILE and OUTFILE replaced by the real names of
the temporary files generated.'''
inname, outname = None, None
try:
Thomas Arendsen Hein
Use better names (hg-{usage}-{random}.{suffix}) for temporary files.
r2165 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
Bryan O'Sullivan
Enhance the file filtering capabilities....
r1293 fp = os.fdopen(infd, 'wb')
fp.write(s)
fp.close()
Thomas Arendsen Hein
Use better names (hg-{usage}-{random}.{suffix}) for temporary files.
r2165 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
Bryan O'Sullivan
Enhance the file filtering capabilities....
r1293 os.close(outfd)
cmd = cmd.replace('INFILE', inname)
cmd = cmd.replace('OUTFILE', outname)
code = os.system(cmd)
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)
Vadim Gelfer
import: use gpatch if present on system. patch is broken on solaris....
r2071 def find_in_path(name, path, default=None):
'''find name in search path. path can be string (will be split
with os.pathsep), or iterable thing that returns strings. if name
found, return path to name. else return default.'''
if isinstance(path, str):
path = path.split(os.pathsep)
for p in path:
p_name = os.path.join(p, name)
if os.path.exists(p_name):
return p_name
return default
mpm@selenic.com
Add automatic binary file detection to diff and export...
r1015 def binary(s):
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 """return true if a string is binary data using diff's heuristic"""
mpm@selenic.com
Add automatic binary file detection to diff and export...
r1015 if s and '\0' in s[:4096]:
return True
return False
mpm@selenic.com
Move dirstate.uniq to util.unique...
r556 def unique(g):
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 """return the uniq elements of iterable g"""
mpm@selenic.com
Move dirstate.uniq to util.unique...
r556 seen = {}
for f in g:
if f not in seen:
seen[f] = 1
yield f
Bryan O'Sullivan
Teach walk code about absolute paths....
r870 class Abort(Exception):
"""Raised if a command needs to print an error and exit."""
mpm@selenic.com
[PATCH] Harden os.system...
r508
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724 def always(fn): return True
def never(fn): return False
Robin Farine
export patkind() from util
r1563 def patkind(name, dflt_pat='glob'):
"""Split a string into an optional pattern kind prefix and the
actual pattern."""
for prefix in 're', 'glob', 'path', 'relglob', 'relpath', 'relre':
if name.startswith(prefix + ':'): return name.split(':', 1)
return dflt_pat, name
benoit.boissinot@ens-lyon.fr
pep-0008 cleanup...
r1062 def globre(pat, head='^', tail='$'):
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724 "convert a glob pattern into a regexp"
i, n = 0, len(pat)
res = ''
group = False
def peek(): return i < n and pat[i]
while i < n:
c = pat[i]
i = i+1
if c == '*':
if peek() == '*':
i += 1
res += '.*'
else:
res += '[^/]*'
elif c == '?':
res += '.'
elif c == '[':
j = i
if j < n and pat[j] in '!]':
j += 1
while j < n and pat[j] != ']':
j += 1
if j >= n:
res += '\\['
else:
stuff = pat[i:j].replace('\\','\\\\')
i = j + 1
if stuff[0] == '!':
stuff = '^' + stuff[1:]
elif stuff[0] == '^':
stuff = '\\' + stuff
res = '%s[%s]' % (res, stuff)
elif c == '{':
group = True
res += '(?:'
elif c == '}' and group:
res += ')'
group = False
elif c == ',' and group:
res += '|'
Benoit Boissinot
make it possible to escape characters in a glob expression
r1990 elif c == '\\':
p = peek()
if p:
i += 1
res += re.escape(p)
else:
res += re.escape(c)
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724 else:
res += re.escape(c)
return head + res + tail
Bryan O'Sullivan
Reduce the amount of stat traffic generated by a walk....
r812 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
Bryan O'Sullivan
Fix walk code for files that do not exist anywhere, and unhandled types....
r884 def pathto(n1, n2):
Bryan O'Sullivan
Fix walk path handling on Windows
r886 '''return the relative path from one place to another.
this returns a path in the form used by the local filesystem, not hg.'''
if not n1: return localpath(n2)
a, b = n1.split('/'), n2.split('/')
twaldmann@thinkmo.de
fixed some stuff pychecker shows, marked unclear/wrong stuff with XXX
r1541 a.reverse()
b.reverse()
Bryan O'Sullivan
Fix walk code for files that do not exist anywhere, and unhandled types....
r884 while a and b and a[-1] == b[-1]:
twaldmann@thinkmo.de
fixed some stuff pychecker shows, marked unclear/wrong stuff with XXX
r1541 a.pop()
b.pop()
Bryan O'Sullivan
Fix walk code for files that do not exist anywhere, and unhandled types....
r884 b.reverse()
return os.sep.join((['..'] * len(a)) + b)
mpm@selenic.com
Change canonpath to not know about repo objects...
r1081 def canonpath(root, cwd, myname):
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 """return the canonical path of myname, given cwd and root"""
Arun Sharma
Handle hg under /
r1566 if root == os.sep:
rootsep = os.sep
Manpreet Singh
Make it possible to use the root directory as the root of a repository.
r2271 elif root.endswith(os.sep):
rootsep = root
Arun Sharma
Handle hg under /
r1566 else:
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 rootsep = root + os.sep
Bryan O'Sullivan
Teach walk code about absolute paths....
r870 name = myname
Vadim Gelfer
fix util.canonpath on windows....
r2090 if not os.path.isabs(name):
mpm@selenic.com
Change canonpath to not know about repo objects...
r1081 name = os.path.join(root, cwd, name)
Bryan O'Sullivan
Teach walk code about absolute paths....
r870 name = os.path.normpath(name)
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):
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
Vadim Gelfer
if hgignore contains errors, print message that is not confusing.
r1610 def matcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None):
return _matcher(canonroot, cwd, names, inc, exc, head, 'glob', src)
Benoit Boissinot
Do not use 'glob' expansion by default on OS != 'nt'
r1413
Vadim Gelfer
if hgignore contains errors, print message that is not confusing.
r1610 def cmdmatcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None):
Benoit Boissinot
Do not use 'glob' expansion by default on OS != 'nt'
r1413 if os.name == 'nt':
dflt_pat = 'glob'
else:
dflt_pat = 'relpath'
Vadim Gelfer
if hgignore contains errors, print message that is not confusing.
r1610 return _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src)
Benoit Boissinot
Do not use 'glob' expansion by default on OS != 'nt'
r1413
Vadim Gelfer
if hgignore contains errors, print message that is not confusing.
r1610 def _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src):
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 """build a function to match a set of file patterns
arguments:
canonroot - the canonical root of the tree you're matching against
cwd - the current working directory, if relevant
names - patterns to find
inc - patterns to include
exc - patterns to exclude
head - a regex to prepend to patterns to control whether a match is rooted
a pattern is one of:
Bryan O'Sullivan
Switch to new syntax for .hgignore files....
r1270 'glob:<rooted glob>'
're:<rooted regexp>'
'path:<rooted path>'
'relglob:<relative glob>'
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 'relpath:<relative path>'
Bryan O'Sullivan
Switch to new syntax for .hgignore files....
r1270 'relre:<relative regexp>'
'<rooted path or regexp>'
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082
returns:
a 3-tuple containing
- list of explicit non-pattern names passed in
- a bool match(filename) function
- a bool indicating if any patterns were passed in
todo:
make head regex a rooted bool
"""
Benoit Boissinot
Do not use 'glob' expansion by default on OS != 'nt'
r1413 def contains_glob(name):
Bryan O'Sullivan
Reduce the amount of stat traffic generated by a walk....
r812 for c in name:
Benoit Boissinot
Do not use 'glob' expansion by default on OS != 'nt'
r1413 if c in _globchars: return True
return False
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820
Bryan O'Sullivan
Fix up handling of regexp paths.
r888 def regex(kind, name, tail):
mpm@selenic.com
Refactor matchpats and walk...
r742 '''convert a pattern into a regular expression'''
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820 if kind == 're':
return name
elif kind == 'path':
Bryan O'Sullivan
Fix up handling of regexp paths.
r888 return '^' + re.escape(name) + '(?:/|$)'
Bryan O'Sullivan
Switch to new syntax for .hgignore files....
r1270 elif kind == 'relglob':
return head + globre(name, '(?:|.*/)', tail)
Bryan O'Sullivan
Fix up handling of regexp paths.
r888 elif kind == 'relpath':
return head + re.escape(name) + tail
Bryan O'Sullivan
Switch to new syntax for .hgignore files....
r1270 elif kind == 'relre':
if name.startswith('^'):
return name
return '.*' + name
mpm@selenic.com
Refactor matchpats and walk...
r742 return head + globre(name, '', tail)
def matchfn(pats, tail):
"""build a matching function from a set of patterns"""
Benoit Boissinot
further fix traceback on invalid .hgignore patterns...
r1454 if not pats:
return
Benoit Boissinot
abort on invalid pattern in matcher
r1446 matches = []
for k, p in pats:
try:
pat = '(?:%s)' % regex(k, p, tail)
matches.append(re.compile(pat).match)
twaldmann@thinkmo.de
fixed some stuff pychecker shows, marked unclear/wrong stuff with XXX
r1541 except re.error:
Vadim Gelfer
make invalid pattern message not confusing.
r1611 if src: raise Abort("%s: invalid pattern (%s): %s" % (src, k, p))
else: raise Abort("invalid pattern (%s): %s" % (k, p))
Benoit Boissinot
abort on invalid pattern in matcher
r1446
def buildfn(text):
for m in matches:
r = m(text)
if r:
return r
return buildfn
mpm@selenic.com
Refactor matchpats and walk...
r742
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820 def globprefix(pat):
'''return the non-glob prefix of a path, e.g. foo/* -> foo'''
root = []
for p in pat.split(os.sep):
Benoit Boissinot
Do not use 'glob' expansion by default on OS != 'nt'
r1413 if contains_glob(p): break
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820 root.append(p)
Bryan O'Sullivan
Fix walk path handling on Windows
r886 return '/'.join(root)
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820
Bryan O'Sullivan
Teach walk code about absolute paths....
r870 pats = []
files = []
roots = []
Benoit Boissinot
Do not use 'glob' expansion by default on OS != 'nt'
r1413 for kind, name in [patkind(p, dflt_pat) for p in names]:
Bryan O'Sullivan
Teach walk code about absolute paths....
r870 if kind in ('glob', 'relpath'):
mpm@selenic.com
Change canonpath to not know about repo objects...
r1081 name = canonpath(canonroot, cwd, name)
Bryan O'Sullivan
Teach walk code about absolute paths....
r870 if name == '':
kind, name = 'glob', '**'
Bryan O'Sullivan
Fix up handling of regexp paths.
r888 if kind in ('glob', 'path', 're'):
pats.append((kind, name))
Bryan O'Sullivan
Teach walk code about absolute paths....
r870 if kind == 'glob':
root = globprefix(name)
if root: roots.append(root)
elif kind == 'relpath':
Bryan O'Sullivan
Fix up handling of regexp paths.
r888 files.append((kind, name))
Bryan O'Sullivan
Teach walk code about absolute paths....
r870 roots.append(name)
mpm@selenic.com
Fix bug with empty inc and exc...
r897
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820 patmatch = matchfn(pats, '$') or always
filematch = matchfn(files, '(?:/|$)') or always
mpm@selenic.com
Fix bug with empty inc and exc...
r897 incmatch = always
if inc:
Vadim Gelfer
fix -I/-X when relative paths used or in subdir
r2480 inckinds = [patkind(canonpath(canonroot, cwd, i)) for i in inc]
incmatch = matchfn(inckinds, '(?:/|$)')
mpm@selenic.com
Fix bug with empty inc and exc...
r897 excmatch = lambda fn: False
if exc:
Vadim Gelfer
fix -I/-X when relative paths used or in subdir
r2480 exckinds = [patkind(canonpath(canonroot, cwd, x)) for x in exc]
excmatch = matchfn(exckinds, '(?:/|$)')
mpm@selenic.com
Refactor matchpats and walk...
r742
Bryan O'Sullivan
Rewrite log command. New version is faster and more featureful....
r1031 return (roots,
lambda fn: (incmatch(fn) and not excmatch(fn) and
(fn.endswith('/') or
(not pats and not files) or
(pats and patmatch(fn)) or
(files and filematch(fn)))),
(inc or exc or (pats and pats != [('glob', '**')])) and True)
mpm@selenic.com
Refactor matchpats and walk...
r742
Vadim Gelfer
merge util.esystem and util.system.
r1882 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
'''enhanced shell command execution.
run with environment maybe modified, maybe in different dir.
mpm@selenic.com
[PATCH] Harden os.system...
r508
Vadim Gelfer
merge util.esystem and util.system.
r1882 if command fails and onerr is None, return status. if ui object,
print error message and return status, else raise onerr object as
exception.'''
Vadim Gelfer
move most of tag code to localrepository class.
r2601 def py2shell(val):
'convert python object into string that is useful to shell'
if val in (None, False):
return '0'
if val == True:
return '1'
return str(val)
Vadim Gelfer
fix broken environment save/restore when a hook runs....
r1880 oldenv = {}
for k in environ:
oldenv[k] = os.environ.get(k)
if cwd is not None:
oldcwd = os.getcwd()
try:
for k, v in environ.iteritems():
Vadim Gelfer
move most of tag code to localrepository class.
r2601 os.environ[k] = py2shell(v)
Vadim Gelfer
fix broken environment save/restore when a hook runs....
r1880 if cwd is not None and oldcwd != cwd:
os.chdir(cwd)
Vadim Gelfer
merge util.esystem and util.system.
r1882 rc = os.system(cmd)
if rc and onerr:
errmsg = '%s %s' % (os.path.basename(cmd.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 finally:
for k, v in oldenv.iteritems():
if v is None:
del os.environ[k]
else:
os.environ[k] = v
if cwd is not None and oldcwd != cwd:
os.chdir(oldcwd)
mpm@selenic.com
[PATCH] rename under the other OS...
r421 def rename(src, dst):
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 """forcibly rename a file"""
mpm@selenic.com
[PATCH] rename under the other OS...
r421 try:
os.rename(src, dst)
Vadim Gelfer
fix file handling bugs on windows....
r2176 except OSError, err:
# on windows, rename to existing file is not allowed, so we
# must delete destination first. but if file is open, unlink
# schedules it for delete but does not delete it. rename
# happens immediately even for open files, so we create
# temporary file, delete it, rename destination to that name,
# then delete that. then rename is safe to do.
fd, temp = tempfile.mkstemp(dir=os.path.dirname(dst) or '.')
os.close(fd)
os.unlink(temp)
os.rename(dst, temp)
os.unlink(temp)
mpm@selenic.com
[PATCH] rename under the other OS...
r421 os.rename(src, dst)
Benoit Boissinot
refactor some unlink/remove code and make sure we prune empty dir
r1415 def unlink(f):
"""unlink and remove the directory if it is empty"""
os.unlink(f)
# try removing directories that might now be empty
Vadim Gelfer
util.unlink should only catch OSError.
r2064 try:
os.removedirs(os.path.dirname(f))
except OSError:
pass
Benoit Boissinot
refactor some unlink/remove code and make sure we prune empty dir
r1415
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241 def copyfiles(src, dst, hardlink=None):
"""Copy a directory tree using hardlinks if possible"""
if hardlink is None:
hardlink = (os.stat(src).st_dev ==
os.stat(os.path.dirname(dst)).st_dev)
Thomas Arendsen Hein
Use python function instead of external 'cp' command when cloning repos....
r698
mpm@selenic.com
Rewrite copytree as copyfiles...
r1207 if os.path.isdir(src):
os.mkdir(dst)
for name in os.listdir(src):
srcname = os.path.join(src, name)
dstname = os.path.join(dst, name)
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241 copyfiles(srcname, dstname, hardlink)
mpm@selenic.com
Rewrite copytree as copyfiles...
r1207 else:
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241 if hardlink:
try:
os_link(src, dst)
Vadim Gelfer
util.copyfiles: only switch to copy if hardlink raises IOError or OSError....
r2050 except (IOError, OSError):
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241 hardlink = False
Benoit Boissinot
do not copy atime and mtime in util.copyfiles...
r1591 shutil.copy(src, dst)
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241 else:
Benoit Boissinot
do not copy atime and mtime in util.copyfiles...
r1591 shutil.copy(src, dst)
Thomas Arendsen Hein
Use python function instead of external 'cp' command when cloning repos....
r698
Thomas Arendsen Hein
Validate paths before reading or writing files in repository or working dir....
r1835 def audit_path(path):
"""Abort if path contains dangerous components"""
parts = os.path.normcase(path).split(os.sep)
if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '')
or os.pardir in parts):
raise Abort(_("path contains illegal component: %s\n") % path)
Thomas Arendsen Hein
Make makelock and readlock work on filesystems without symlink support....
r704 def _makelock_file(info, pathname):
ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
os.write(ld, info)
os.close(ld)
def _readlock_file(pathname):
Vadim Gelfer
fix file handling bugs on windows....
r2176 return posixfile(pathname).read()
Thomas Arendsen Hein
Make makelock and readlock work on filesystems without symlink support....
r704
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241 def nlinks(pathname):
"""Return number of hardlinks for the given file."""
Vadim Gelfer
replace os.stat with os.lstat in some where.
r2448 return os.lstat(pathname).st_nlink
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241
if hasattr(os, 'link'):
os_link = os.link
else:
def os_link(src, dst):
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 raise OSError(0, _("Hardlinks not supported"))
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241
Vadim Gelfer
fix file handling bugs on windows....
r2176 def fstat(fp):
'''stat file object that may not have fileno method.'''
try:
return os.fstat(fp.fileno())
except AttributeError:
return os.stat(fp.name)
posixfile = file
Vadim Gelfer
windows: revlog.lazyparser not always safe to use....
r2250 def is_win_9x():
'''return true if run on windows 95, 98 or me.'''
try:
return sys.getwindowsversion()[3] == 1
except AttributeError:
return os.name == 'nt' and 'command' in os.environ.get('comspec', '')
Vadim Gelfer
fix windows username problem.
r2652 getuser_fallback = None
def getuser():
'''return name of current user'''
try:
return getpass.getuser()
except ImportError:
Vadim Gelfer
util.getuser: better comments
r2655 # import of pwd will fail on windows - try fallback
Vadim Gelfer
util.getuser: raise exception if win32api not available.
r2654 if getuser_fallback:
return getuser_fallback()
Vadim Gelfer
util.getuser: better comments
r2655 # raised if win32api not available
raise Abort(_('user name not available - set USERNAME '
'environment variable'))
Vadim Gelfer
fix windows username problem.
r2652
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 # Platform specific variants
mpm@selenic.com
[PATCH] file seperator handling for the other 'OS'...
r419 if os.name == 'nt':
olivier.maquelin@intel.com
Avoid insertion/deletion of CRs on stdio during hg serve
r1420 demandload(globals(), "msvcrt")
mpm@selenic.com
[PATCH] /dev/null for other OS...
r461 nulldev = 'NUL:'
Vadim Gelfer
eliminate backtrace when piping output on windows....
r1609
class winstdout:
'''stdout on windows misbehaves if sent through a pipe'''
def __init__(self, fp):
self.fp = fp
def __getattr__(self, key):
return getattr(self.fp, key)
def close(self):
try:
self.fp.close()
except: pass
def write(self, s):
try:
return self.fp.write(s)
except IOError, inst:
if inst.errno != 0: raise
self.close()
raise IOError(errno.EPIPE, 'Broken pipe')
sys.stdout = winstdout(sys.stdout)
Vadim Gelfer
fix exception handling on windows....
r2054 def system_rcpath():
Vadim Gelfer
fix issue 217....
r2117 try:
return system_rcpath_win32()
except:
return [r'c:\mercurial\mercurial.ini']
Vadim Gelfer
fix exception handling on windows....
r2054
Vadim Gelfer
add HGRCPATH env var, list of places to look for hgrc files....
r1951 def os_rcpath():
'''return default os-specific hgrc search path'''
Thomas Arendsen Hein
On Windows look for mercurial.ini in $USERPROFILE, too, if available...
r2280 path = system_rcpath()
Volker Kleinfeld
On win98 os.path.expanuser('~') does not result in a useable directory....
r2284 path.append(user_rcpath())
Thomas Arendsen Hein
On Windows look for mercurial.ini in $USERPROFILE, too, if available...
r2280 userprofile = os.environ.get('USERPROFILE')
if userprofile:
path.append(os.path.join(userprofile, 'mercurial.ini'))
return path
Bryan O'Sullivan
Use platform-appropriate rc file names.
r1292
Volker Kleinfeld
On win98 os.path.expanuser('~') does not result in a useable directory....
r2284 def user_rcpath():
'''return os-specific hgrc search path to the user dir'''
return os.path.join(os.path.expanduser('~'), 'mercurial.ini')
Volker Kleinfeld
Make 'hg import' platform independent....
r1285 def parse_patch_output(output_line):
"""parses the output produced by patch and returns the file name"""
pf = output_line[14:]
if pf[0] == '`':
pf = pf[1:-1] # Remove the quotes
return pf
Vadim Gelfer
fix exception handling on windows....
r2054 def testpid(pid):
'''return False if pid dead, True if running or not known'''
return True
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241
mpm@selenic.com
Permission handling for the other OS...
r441 def is_exec(f, last):
return last
def set_exec(f, mode):
pass
mpm@selenic.com
Whitespace cleanups...
r515
olivier.maquelin@intel.com
Avoid insertion/deletion of CRs on stdio during hg serve
r1420 def set_binary(fd):
msvcrt.setmode(fd.fileno(), os.O_BINARY)
mpm@selenic.com
[PATCH] file seperator handling for the other 'OS'...
r419 def pconvert(path):
return path.replace("\\", "/")
mpm@selenic.com
[PATCH] Enables lock work under the other 'OS'...
r422
Bryan O'Sullivan
Fix walk path handling on Windows
r886 def localpath(path):
return path.replace('/', '\\')
def normpath(path):
return pconvert(os.path.normpath(path))
Thomas Arendsen Hein
Make makelock and readlock work on filesystems without symlink support....
r704 makelock = _makelock_file
readlock = _readlock_file
mpm@selenic.com
[PATCH] /dev/null for other OS...
r461
Vadim Gelfer
add util.samestat function for windows....
r2193 def samestat(s1, s2):
return False
Brendan Cully
Add portable shell-quoting function; teach mq to use it.
r2791 def shellquote(s):
return '"%s"' % s.replace('"', '\\"')
thananck@yahoo.com
Provided platform dependent implementations for explain_exit...
r782 def explain_exit(code):
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 return _("exited with status %d") % code, code
thananck@yahoo.com
Provided platform dependent implementations for explain_exit...
r782
Vadim Gelfer
fix exception handling on windows....
r2054 try:
# override functions with win32 versions if possible
from util_win32 import *
Vadim Gelfer
windows: revlog.lazyparser not always safe to use....
r2250 if not is_win_9x():
posixfile = posixfile_nt
Vadim Gelfer
fix exception handling on windows....
r2054 except ImportError:
pass
mpm@selenic.com
[PATCH] file seperator handling for the other 'OS'...
r419 else:
mpm@selenic.com
[PATCH] /dev/null for other OS...
r461 nulldev = '/dev/null'
Vadim Gelfer
make mercurial look in more places for config files....
r1583 def rcfiles(path):
rcs = [os.path.join(path, 'hgrc')]
rcdir = os.path.join(path, 'hgrc.d')
try:
rcs.extend([os.path.join(rcdir, f) for f in os.listdir(rcdir)
if f.endswith(".rc")])
except OSError, inst: pass
return rcs
Vadim Gelfer
add HGRCPATH env var, list of places to look for hgrc files....
r1951
def os_rcpath():
'''return default os-specific hgrc search path'''
path = []
Vadim Gelfer
make reason for sys.argv change obvious in code.
r2263 # old mod_python does not set sys.argv
Shun-ichi GOTO
Check existance of sys.argv for the use from mod_python.
r2261 if len(getattr(sys, 'argv', [])) > 0:
Vadim Gelfer
add HGRCPATH env var, list of places to look for hgrc files....
r1951 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
'/../etc/mercurial'))
path.extend(rcfiles('/etc/mercurial'))
path.append(os.path.expanduser('~/.hgrc'))
path = [os.path.normpath(f) for f in path]
return path
Bryan O'Sullivan
Use platform-appropriate rc file names.
r1292
Volker Kleinfeld
Make 'hg import' platform independent....
r1285 def parse_patch_output(output_line):
"""parses the output produced by patch and returns the file name"""
Benoit Boissinot
if a filename contains spaces, patch adds quote around it
r1593 pf = output_line[14:]
Benoit Boissinot
use __contains__, index or split instead of str.find...
r2579 if pf.startswith("'") and pf.endswith("'") and " " in pf:
Benoit Boissinot
if a filename contains spaces, patch adds quote around it
r1593 pf = pf[1:-1] # Remove the quotes
return pf
Volker Kleinfeld
Make 'hg import' platform independent....
r1285
mpm@selenic.com
Permission handling for the other OS...
r441 def is_exec(f, last):
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 """check whether a file is executable"""
Vadim Gelfer
replace os.stat with os.lstat in some where.
r2448 return (os.lstat(f).st_mode & 0100 != 0)
mpm@selenic.com
Permission handling for the other OS...
r441
def set_exec(f, mode):
Vadim Gelfer
replace os.stat with os.lstat in some where.
r2448 s = os.lstat(f).st_mode
mpm@selenic.com
Permission handling for the other OS...
r441 if (s & 0100 != 0) == mode:
return
if mode:
# Turn on +x for every +r bit when making a file executable
# and obey umask.
umask = os.umask(0)
os.umask(umask)
os.chmod(f, s | (s & 0444) >> 2 & ~umask)
else:
os.chmod(f, s & 0666)
olivier.maquelin@intel.com
Avoid insertion/deletion of CRs on stdio during hg serve
r1420 def set_binary(fd):
pass
mpm@selenic.com
[PATCH] file seperator handling for the other 'OS'...
r419 def pconvert(path):
return path
Bryan O'Sullivan
Fix walk path handling on Windows
r886 def localpath(path):
return path
normpath = os.path.normpath
Vadim Gelfer
add util.samestat function for windows....
r2193 samestat = os.path.samestat
Bryan O'Sullivan
Fix walk path handling on Windows
r886
mpm@selenic.com
[PATCH] Enables lock work under the other 'OS'...
r422 def makelock(info, pathname):
Thomas Arendsen Hein
Make makelock and readlock work on filesystems without symlink support....
r704 try:
os.symlink(info, pathname)
except OSError, why:
if why.errno == errno.EEXIST:
raise
else:
_makelock_file(info, pathname)
mpm@selenic.com
[PATCH] Enables lock work under the other 'OS'...
r422
def readlock(pathname):
Thomas Arendsen Hein
Make makelock and readlock work on filesystems without symlink support....
r704 try:
return os.readlink(pathname)
except OSError, why:
if why.errno == errno.EINVAL:
return _readlock_file(pathname)
else:
raise
thananck@yahoo.com
Provided platform dependent implementations for explain_exit...
r782
Brendan Cully
Add portable shell-quoting function; teach mq to use it.
r2791 def shellquote(s):
return "'%s'" % s.replace("'", "'\\''")
Vadim Gelfer
change lock format to let us detect and break stale locks....
r1877 def testpid(pid):
'''return False if pid dead, True if running or not sure'''
try:
os.kill(pid, 0)
return True
except OSError, inst:
return inst.errno != errno.ESRCH
thananck@yahoo.com
Provided platform dependent implementations for explain_exit...
r782 def explain_exit(code):
"""return a 2-tuple (desc, code) describing a process's status"""
if os.WIFEXITED(code):
val = os.WEXITSTATUS(code)
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 return _("exited with status %d") % val, val
thananck@yahoo.com
Provided platform dependent implementations for explain_exit...
r782 elif os.WIFSIGNALED(code):
val = os.WTERMSIG(code)
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 return _("killed by signal %d") % val, val
thananck@yahoo.com
Provided platform dependent implementations for explain_exit...
r782 elif os.WIFSTOPPED(code):
mark.williamson@cl.cam.ac.uk
Minor tweak: os.STOPSIG -> os.WSTOPSIG. Pychecker spotted this one.
r912 val = os.WSTOPSIG(code)
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 return _("stopped by signal %d") % val, val
raise ValueError(_("invalid exit code"))
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199
Vadim Gelfer
fix file handling bugs on windows....
r2176 def opener(base, audit=True):
"""
return a function that opens files relative to base
this function is used to hide the details of COW semantics and
remote file access from higher level code.
"""
p = base
audit_p = audit
def mktempcopy(name):
d, fn = os.path.split(name)
Vadim Gelfer
merge with crew.
r2177 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
Vadim Gelfer
fix file handling bugs on windows....
r2176 os.close(fd)
Vadim Gelfer
reduce memory used by util.opener when making a temp copy of a file.
r2237 ofp = posixfile(temp, "wb")
Vadim Gelfer
fix file handling bugs on windows....
r2176 try:
Vadim Gelfer
add filename to IOError if read of file fails....
r2220 try:
Vadim Gelfer
reduce memory used by util.opener when making a temp copy of a file.
r2237 ifp = posixfile(name, "rb")
Vadim Gelfer
add filename to IOError if read of file fails....
r2220 except IOError, inst:
if not getattr(inst, 'filename', None):
inst.filename = name
raise
Vadim Gelfer
reduce memory used by util.opener when making a temp copy of a file.
r2237 for chunk in filechunkiter(ifp):
ofp.write(chunk)
ifp.close()
ofp.close()
Vadim Gelfer
fix file handling bugs on windows....
r2176 except:
try: os.unlink(temp)
except: pass
raise
st = os.lstat(name)
os.chmod(temp, st.st_mode)
return temp
class atomictempfile(posixfile):
"""the file will only be copied when rename is called"""
def __init__(self, name, mode):
self.__name = name
self.temp = mktempcopy(name)
posixfile.__init__(self, self.temp, mode)
def rename(self):
if not self.closed:
posixfile.close(self)
Thomas Arendsen Hein
Use platform path for renaming file in util.atomictempfile.rename()
r2308 rename(self.temp, localpath(self.__name))
Vadim Gelfer
fix file handling bugs on windows....
r2176 def __del__(self):
if not self.closed:
try:
os.unlink(self.temp)
except: pass
posixfile.close(self)
class atomicfile(atomictempfile):
"""the file will only be copied on close"""
def __init__(self, name, mode):
atomictempfile.__init__(self, name, mode)
def close(self):
self.rename()
def __del__(self):
self.rename()
def o(path, mode="r", text=False, atomic=False, atomictemp=False):
if audit_p:
audit_path(path)
f = os.path.join(p, path)
if not text:
mode += "b" # for that other OS
if mode[0] != "r":
try:
nlink = nlinks(f)
except OSError:
d = os.path.dirname(f)
if not os.path.isdir(d):
os.makedirs(d)
else:
if atomic:
return atomicfile(f, mode)
elif atomictemp:
return atomictempfile(f, mode)
if nlink > 1:
rename(mktempcopy(f), f)
return posixfile(f, mode)
return o
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 class chunkbuffer(object):
"""Allow arbitrary sized chunks of data to be efficiently read from an
iterator over chunks of arbitrary size."""
Bryan O'Sullivan
Minor cleanups.
r1200
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 def __init__(self, in_iter, targetsize = 2**16):
"""in_iter is the iterator that's iterating over the input chunks.
targetsize is how big a buffer to try to maintain."""
self.in_iter = iter(in_iter)
self.buf = ''
self.targetsize = int(targetsize)
Bryan O'Sullivan
Minor cleanups.
r1200 if self.targetsize <= 0:
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 raise ValueError(_("targetsize must be greater than 0, was %d") %
Bryan O'Sullivan
Minor cleanups.
r1200 targetsize)
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 self.iterempty = False
Bryan O'Sullivan
Minor cleanups.
r1200
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 def fillbuf(self):
Bryan O'Sullivan
Minor cleanups.
r1200 """Ignore target size; read every chunk from iterator until empty."""
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 if not self.iterempty:
collector = cStringIO.StringIO()
collector.write(self.buf)
for ch in self.in_iter:
collector.write(ch)
self.buf = collector.getvalue()
self.iterempty = True
def read(self, l):
Bryan O'Sullivan
Minor cleanups.
r1200 """Read L bytes of data from the iterator of chunks of data.
Thomas Arendsen Hein
Cleanup of tabs and trailing spaces.
r1308 Returns less than L bytes if the iterator runs dry."""
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 if l > len(self.buf) and not self.iterempty:
# Clamp to a multiple of self.targetsize
targetsize = self.targetsize * ((l // self.targetsize) + 1)
collector = cStringIO.StringIO()
collector.write(self.buf)
collected = len(self.buf)
for chunk in self.in_iter:
collector.write(chunk)
collected += len(chunk)
if collected >= targetsize:
break
if collected < targetsize:
self.iterempty = True
self.buf = collector.getvalue()
Bryan O'Sullivan
Minor cleanups.
r1200 s, self.buf = self.buf[:l], buffer(self.buf, l)
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 return s
Vadim Gelfer
util: add limit to amount filechunkiter will read
r2462 def filechunkiter(f, size=65536, limit=None):
"""Create a generator that produces the data in the file size
(default 65536) bytes at a time, up to optional limit (default is
to read all data). Chunks may be less than size bytes if the
chunk is the last chunk in the file, or the file is a socket or
some other type of file that sometimes reads less data than is
requested."""
assert size >= 0
assert limit is None or limit >= 0
while True:
if limit is None: nbytes = size
else: nbytes = min(limit, size)
s = nbytes and f.read(nbytes)
if not s: break
if limit: limit -= len(s)
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 yield s
Bryan O'Sullivan
Fix up representation of dates in hgweb....
r1320
Bryan O'Sullivan
Clean up date and timezone handling....
r1321 def makedate():
Benoit Boissinot
fix handling of daylight saving time
r1482 lt = time.localtime()
if lt[8] == 1 and time.daylight:
tz = time.altzone
else:
tz = time.timezone
return time.mktime(lt), tz
Bryan O'Sullivan
Allow files to be opened in text mode, even on Windows.
r1329
Vadim Gelfer
add changelog style to command line template....
r1987 def datestr(date=None, format='%a %b %d %H:%M:%S %Y', timezone=True):
Bryan O'Sullivan
Clean up date and timezone handling....
r1321 """represent a (unixtime, offset) tuple as a localized time.
unixtime is seconds since the epoch, and offset is the time zone's
Vadim Gelfer
add changelog style to command line template....
r1987 number of seconds away from UTC. if timezone is false, do not
append time zone to string."""
Bryan O'Sullivan
Clean up date and timezone handling....
r1321 t, tz = date or makedate()
Vadim Gelfer
add changelog style to command line template....
r1987 s = time.strftime(format, time.gmtime(float(t) - tz))
if timezone:
s += " %+03d%02d" % (-tz / 3600, ((-tz % 3600) / 60))
return s
Vadim Gelfer
hgwebdir: export collections of repos...
r1829
Jose M. Prieto
Allow the use of human readable dates (issue 251)
r2522 def strdate(string, format='%a %b %d %H:%M:%S %Y'):
"""parse a localized time string and return a (unixtime, offset) tuple.
if the string cannot be parsed, ValueError is raised."""
def hastimezone(string):
return (string[-4:].isdigit() and
(string[-5] == '+' or string[-5] == '-') and
string[-6].isspace())
if hastimezone(string):
Benoit Boissinot
str.rsplit does not exist in python 2.3
r2546 date, tz = string[:-6], string[-5:]
Jose M. Prieto
Allow the use of human readable dates (issue 251)
r2522 tz = int(tz)
offset = - 3600 * (tz / 100) - 60 * (tz % 100)
else:
date, offset = string, 0
when = int(time.mktime(time.strptime(date, format))) + offset
return when, offset
Chris Mason
util.parsedate should understand dates from hg export
r2609 def parsedate(string, formats=None):
Jose M. Prieto
Allow the use of human readable dates (issue 251)
r2522 """parse a localized time string and return a (unixtime, offset) tuple.
The date may be a "unixtime offset" string or in one of the specified
formats."""
Chris Mason
util.parsedate should understand dates from hg export
r2609 if not formats:
formats = defaultdateformats
Jose M. Prieto
Allow the use of human readable dates (issue 251)
r2522 try:
when, offset = map(int, string.split(' '))
Benoit Boissinot
validate the resulting date in parsedate
r2523 except ValueError:
for format in formats:
try:
when, offset = strdate(string, format)
except ValueError:
pass
else:
break
else:
raise ValueError(_('invalid date: %r') % string)
# 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:
raise ValueError(_('date exceeds 32 bits: %d') % when)
if offset < -50400 or offset > 43200:
raise ValueError(_('impossible time zone offset: %d') % offset)
return when, offset
Jose M. Prieto
Allow the use of human readable dates (issue 251)
r2522
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:]
return user
Vadim Gelfer
merge with crew.
r1920
Vadim Gelfer
hgwebdir: export collections of repos...
r1829 def walkrepos(path):
'''yield every hg repository under path, recursively.'''
def errhandler(err):
if err.filename == path:
raise err
for root, dirs, files in os.walk(path, onerror=errhandler):
for d in dirs:
if d == '.hg':
yield root
dirs[:] = []
break
Vadim Gelfer
add HGRCPATH env var, list of places to look for hgrc files....
r1951
_rcpath = None
def rcpath():
'''return hgrc search path. if env var HGRCPATH is set, use it.
for each item in path, if directory, use files ending in .rc,
else use item.
make HGRCPATH empty to only look in .hg/hgrc of current repo.
if no HGRCPATH, use default os-specific path.'''
global _rcpath
if _rcpath is None:
if 'HGRCPATH' in os.environ:
_rcpath = []
for p in os.environ['HGRCPATH'].split(os.pathsep):
if not p: continue
Benoit Boissinot
use a proper test instead of catching every exception
r1956 if os.path.isdir(p):
Vadim Gelfer
add HGRCPATH env var, list of places to look for hgrc files....
r1951 for f in os.listdir(p):
if f.endswith('.rc'):
_rcpath.append(os.path.join(p, f))
Benoit Boissinot
use a proper test instead of catching every exception
r1956 else:
_rcpath.append(p)
Vadim Gelfer
add HGRCPATH env var, list of places to look for hgrc files....
r1951 else:
_rcpath = os_rcpath()
return _rcpath
Vadim Gelfer
add support for streaming clone....
r2612
def bytecount(nbytes):
'''return byte count formatted as readable string, with units'''
units = (
(100, 1<<30, _('%.0f GB')),
(10, 1<<30, _('%.1f GB')),
(1, 1<<30, _('%.2f GB')),
(100, 1<<20, _('%.0f MB')),
(10, 1<<20, _('%.1f MB')),
(1, 1<<20, _('%.2f MB')),
(100, 1<<10, _('%.0f KB')),
(10, 1<<10, _('%.1f KB')),
(1, 1<<10, _('%.2f KB')),
(1, 1, _('%.0f bytes')),
)
for multiplier, divisor, format in units:
if nbytes >= divisor * multiplier:
return format % (nbytes / float(divisor))
return units[-1][2] % nbytes
Vadim Gelfer
clean up hg.py: move repo constructor code into each repo module
r2740
def drop_scheme(scheme, path):
sc = scheme + ':'
if path.startswith(sc):
path = path[len(sc):]
if path.startswith('//'):
path = path[2:]
return path