##// END OF EJS Templates
dirstate.changes() now distinguishes 'hg remove'd or just deleted files....
dirstate.changes() now distinguishes 'hg remove'd or just deleted files. Interface is not yet changed. Non-regular files are considered to be removed or deleted. Removed the unneeded match(fn) call for adding to the unknown list.

File last commit:

r839:9c918287 merge default
r861:cbe5c4d0 default
Show More
util.py
238 lines | 6.9 KiB | text/x-python | PythonLexer
mpm@selenic.com
[PATCH] file seperator handling for the other 'OS'...
r419 # util.py - 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.
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
Move dirstate.uniq to util.unique...
r556 def unique(g):
seen = {}
for f in g:
if f not in seen:
seen[f] = 1
yield f
mpm@selenic.com
[PATCH] Harden os.system...
r508 class CommandError(Exception): pass
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
def globre(pat, head = '^', tail = '$'):
"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}
def matcher(cwd, names, inc, exc, head = ''):
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820 def patkind(name):
Bryan O'Sullivan
Reduce the amount of stat traffic generated by a walk....
r812 for prefix in 're:', 'glob:', 'path:':
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
cwdsep = cwd + os.sep
Bryan O'Sullivan
Reduce the amount of stat traffic generated by a walk....
r812
mpm@selenic.com
Refactor matchpats and walk...
r742 def regex(name, tail):
'''convert a pattern into a regular expression'''
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820 kind, name = patkind(name)
if kind == 're':
return name
elif kind == 'path':
return '^' + re.escape(name) + '$'
if cwd: name = os.path.join(cwdsep, name)
name = os.path.normpath(name)
if name == '.': name = '**'
mpm@selenic.com
Refactor matchpats and walk...
r742 return head + globre(name, '', tail)
def under(fn):
"""check if fn is under our cwd"""
return not cwd or fn.startswith(cwdsep)
def matchfn(pats, tail):
"""build a matching function from a set of patterns"""
if pats:
pat = '(?:%s)' % '|'.join([regex(p, tail) for p in pats])
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)
return os.sep.join(root)
patkinds = map(patkind, names)
pats = [name for (kind, name) in patkinds if kind != 'relpath']
files = [name for (kind, name) in patkinds if kind == 'relpath']
roots = filter(None, map(globprefix, pats)) + files
if cwd: roots = [cwdsep + r for r in roots]
Bryan O'Sullivan
Reduce the amount of stat traffic generated by a walk....
r812
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
incmatch = matchfn(inc, '(?:/|$)') or always
mpm@selenic.com
Refactor matchpats and walk...
r742 excmatch = matchfn(exc, '(?:/|$)') or (lambda fn: False)
Bryan O'Sullivan
Clean up walk and changes code to use normalised names properly....
r820 return roots, lambda fn: (incmatch(fn) and not excmatch(fn) and
Bryan O'Sullivan
Reduce the amount of stat traffic generated by a walk....
r812 (fn.endswith('/') or
(not pats and not files) or
(pats and patmatch(fn)) or
(files and filematch(fn))))
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)
mpm@selenic.com
[PATCH] Harden os.system...
r508 raise CommandError(errmsg)
mpm@selenic.com
[PATCH] rename under the other OS...
r421 def rename(src, dst):
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:
raise IOError("Not a regular file: %r" % srcname)
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
[PATCH] rename under the other OS...
r421 # Platfor specific varients
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
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):
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
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"""
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):
val = os.STOPSIG(code)
return "stopped by signal %d" % val, val
raise ValueError("invalid exit code")