Reduce the amount of stat traffic generated by a walk.

When we switched to the new walk code for commands, we no longer passed a
list of specific files to the repo or dirstate walk or changes methods.
This meant that we always walked and attempted to match everything,
which was not efficient.

Now, if we are given any patterns to match, or nothing at all, we still
walk everything.  But if we are given only file names that contain no
glob characters, we only walk those.
This commit is contained in:
Bryan O'Sullivan 2005-07-29 12:30:12 -08:00
parent 6ed9c3aea0
commit 4d6bf4b62a
2 changed files with 29 additions and 8 deletions

View File

@ -47,7 +47,8 @@ def walk(repo, pats, opts, head = ''):
cwd = repo.getcwd()
c = 0
if cwd: c = len(cwd) + 1
for src, fn in repo.walk(match = matchpats(cwd, pats, opts, head)):
files, matchfn = matchpats(cwd, pats, opts, head)
for src, fn in repo.walk(files = files, match = matchfn):
yield src, fn, fn[c:]
revrangesep = ':'
@ -1007,7 +1008,8 @@ def status(ui, repo, *pats, **opts):
R = removed
? = not tracked'''
(c, a, d, u) = repo.changes(match = matchpats(repo.getcwd(), pats, opts))
files, matchfn = matchpats(repo.getcwd(), pats, opts)
(c, a, d, u) = repo.changes(files = files, match = matchfn)
(c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
for f in c:

View File

@ -66,7 +66,15 @@ def globre(pat, head = '^', tail = '$'):
res += re.escape(c)
return head + res + tail
def matcher(cwd, pats, inc, exc, head = ''):
_globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
def matcher(cwd, names, inc, exc, head = ''):
def patlike(name):
for prefix in 're:', 'glob:', 'path:':
if name.startswith(prefix): return True
for c in name:
if c in _globchars: return True
def regex(name, tail):
'''convert a pattern into a regular expression'''
if name.startswith('re:'):
@ -77,6 +85,8 @@ def matcher(cwd, pats, inc, exc, head = ''):
return head + globre(name[5:], '', tail)
return head + globre(name, '', tail)
cwdsep = cwd + os.sep
def under(fn):
"""check if fn is under our cwd"""
return not cwd or fn.startswith(cwdsep)
@ -86,16 +96,25 @@ def matcher(cwd, pats, inc, exc, head = ''):
if pats:
pat = '(?:%s)' % '|'.join([regex(p, tail) for p in pats])
if cwd:
pat = re.escape(cwd + os.sep) + pat
pat = re.escape(cwdsep) + pat
return re.compile(pat).match
cwdsep = cwd + os.sep
patmatch = matchfn(pats, '$') or (lambda fn: True)
pats = filter(patlike, names)
files = [n for n in names if not patlike(n)]
if pats: plain = []
elif cwd: plain = [cwdsep + f for f in files]
else: plain = files
patmatch = matchfn(pats, '$')
filematch = matchfn(files, '(?:/|$)')
incmatch = matchfn(inc, '(?:/|$)') or under
excmatch = matchfn(exc, '(?:/|$)') or (lambda fn: False)
return lambda fn: (incmatch(fn) and not excmatch(fn) and
(fn.endswith('/') or patmatch(fn)))
return plain, 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))))
def system(cmd, errprefix=None):
"""execute a shell command that must succeed"""