# HG changeset patch # User Bryan O'Sullivan # Date 1122669012 28800 # Node ID b65af904d6d7ca1bc82f204ab5af74db820bdb6d # Parent fa9aaf3bbdd755ca2ff37efecdae34dd87ba8657 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. diff -r fa9aaf3bbdd7 -r b65af904d6d7 mercurial/commands.py --- a/mercurial/commands.py Fri Jul 29 08:51:42 2005 -0800 +++ b/mercurial/commands.py Fri Jul 29 12:30:12 2005 -0800 @@ -47,7 +47,8 @@ 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 @@ 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: diff -r fa9aaf3bbdd7 -r b65af904d6d7 mercurial/util.py --- a/mercurial/util.py Fri Jul 29 08:51:42 2005 -0800 +++ b/mercurial/util.py Fri Jul 29 12:30:12 2005 -0800 @@ -66,7 +66,15 @@ 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 @@ 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 @@ 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"""