##// END OF EJS Templates
Break apart hg.py...
Break apart hg.py - move the various parts of hg.py into their own files - create node.py to store node manipulation functions

File last commit:

r1082:ce96e316 default
r1089:142b5d5e default
Show More
util.py
327 lines | 9.3 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>
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
Thomas Arendsen Hein
Make makelock and readlock work on filesystems without symlink support....
r704 import os, errno
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724 from demandload import *
demandload(globals(), "re")
mpm@selenic.com
[PATCH] file seperator handling for the other 'OS'...
r419
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
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 += '|'
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('/')
Bryan O'Sullivan
Fix walk code for files that do not exist anywhere, and unhandled types....
r884 a.reverse(), b.reverse()
while a and b and a[-1] == b[-1]:
a.pop(), b.pop()
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"""
mpm@selenic.com
Change canonpath to not know about repo objects...
r1081 rootsep = root + os.sep
Bryan O'Sullivan
Teach walk code about absolute paths....
r870 name = myname
if not name.startswith(os.sep):
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)
if name.startswith(rootsep):
Bryan O'Sullivan
Fix walk path handling on Windows
r886 return pconvert(name[len(rootsep):])
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:
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
mpm@selenic.com
Change canonpath to not know about repo objects...
r1081 def matcher(canonroot, cwd, names, inc, exc, head=''):
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:
're:<regex>'
'glob:<shellglob>'
'path:<explicit path>'
'relpath:<relative path>'
'<relative path>'
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
"""
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820 def patkind(name):
Bryan O'Sullivan
Fix up handling of regexp paths.
r888 for prefix in 're:', 'glob:', 'path:', 'relpath:':
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820 if name.startswith(prefix): return name.split(':', 1)
Bryan O'Sullivan
Reduce the amount of stat traffic generated by a walk....
r812 for c in name:
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820 if c in _globchars: return 'glob', name
return 'relpath', name
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) + '(?:/|$)'
elif kind == 'relpath':
return head + re.escape(name) + tail
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"""
if pats:
Bryan O'Sullivan
Fix up handling of regexp paths.
r888 pat = '(?:%s)' % '|'.join([regex(k, p, tail) for (k, p) in pats])
mpm@selenic.com
Refactor matchpats and walk...
r742 return re.compile(pat).match
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):
if patkind(p)[0] == 'glob': break
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 = []
for kind, name in map(patkind, names):
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:
incmatch = matchfn(map(patkind, inc), '(?:/|$)')
excmatch = lambda fn: False
if exc:
excmatch = matchfn(map(patkind, exc), '(?:/|$)')
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
mpm@selenic.com
[PATCH] Fix use of util.CommandError...
r521 def system(cmd, errprefix=None):
mpm@selenic.com
[PATCH] Harden os.system...
r508 """execute a shell command that must succeed"""
rc = os.system(cmd)
if rc:
mpm@selenic.com
[PATCH] Fix use of util.CommandError...
r521 errmsg = "%s %s" % (os.path.basename(cmd.split(None, 1)[0]),
explain_exit(rc)[0])
if errprefix:
errmsg = "%s: %s" % (errprefix, errmsg)
Bryan O'Sullivan
Teach walk code about absolute paths....
r870 raise Abort(errmsg)
mpm@selenic.com
[PATCH] Harden os.system...
r508
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)
except:
os.unlink(dst)
os.rename(src, dst)
Thomas Arendsen Hein
Use python function instead of external 'cp' command when cloning repos....
r698 def copytree(src, dst, copyfile):
"""Copy a directory tree, files are copied using 'copyfile'."""
names = os.listdir(src)
os.mkdir(dst)
for name in names:
srcname = os.path.join(src, name)
dstname = os.path.join(dst, name)
if os.path.isdir(srcname):
copytree(srcname, dstname, copyfile)
elif os.path.isfile(srcname):
copyfile(srcname, dstname)
else:
mpm@selenic.com
Fix hg clone race with writer...
r917 pass
Thomas Arendsen Hein
Use python function instead of external 'cp' command when cloning repos....
r698
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):
return file(pathname).read()
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':
mpm@selenic.com
[PATCH] /dev/null for other OS...
r461 nulldev = 'NUL:'
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
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
thananck@yahoo.com
Provided platform dependent implementations for explain_exit...
r782 def explain_exit(code):
return "exited with status %d" % code, code
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'
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"""
mpm@selenic.com
Permission handling for the other OS...
r441 return (os.stat(f).st_mode & 0100 != 0)
def set_exec(f, mode):
s = os.stat(f).st_mode
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)
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
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
def explain_exit(code):
"""return a 2-tuple (desc, code) describing a process's status"""
Volker.Kleinfeld@gmx.de
Fixed system command abord reason on windows.
r1075 if os.name == 'nt': # os.WIFxx is not supported on windows
return "aborted with error." , -1
thananck@yahoo.com
Provided platform dependent implementations for explain_exit...
r782 if os.WIFEXITED(code):
val = os.WEXITSTATUS(code)
return "exited with status %d" % val, val
elif os.WIFSIGNALED(code):
val = os.WTERMSIG(code)
return "killed by signal %d" % val, val
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)
thananck@yahoo.com
Provided platform dependent implementations for explain_exit...
r782 return "stopped by signal %d" % val, val
raise ValueError("invalid exit code")