comparison mercurial/cmdutil.py @ 9652:2cb0cab10d2e

walkchangerevs: pull out matchfn * * * imported patch mercurial/commands.py
author Matt Mackall <mpm@selenic.com>
date Sun, 25 Oct 2009 18:43:56 -0500
parents f57640bf10d4
children e4de75343743
comparison
equal deleted inserted replaced
9632:16698d87ad20 9652:2cb0cab10d2e
1022 1022
1023 def finddate(ui, repo, date): 1023 def finddate(ui, repo, date):
1024 """Find the tipmost changeset that matches the given date spec""" 1024 """Find the tipmost changeset that matches the given date spec"""
1025 df = util.matchdate(date) 1025 df = util.matchdate(date)
1026 get = util.cachefunc(lambda r: repo[r]) 1026 get = util.cachefunc(lambda r: repo[r])
1027 changeiter, matchfn = walkchangerevs(ui, repo, [], get, {'rev':None}) 1027 m = matchall(repo)
1028 results = {} 1028 results = {}
1029 for st, rev, fns in changeiter: 1029 for st, rev, fns in walkchangerevs(ui, repo, m, get, {'rev':None}):
1030 if st == 'add': 1030 if st == 'add':
1031 d = get(rev).date() 1031 d = get(rev).date()
1032 if df(d[0]): 1032 if df(d[0]):
1033 results[rev] = d 1033 results[rev] = d
1034 elif st == 'iter': 1034 elif st == 'iter':
1037 (rev, util.datestr(results[rev]))) 1037 (rev, util.datestr(results[rev])))
1038 return str(rev) 1038 return str(rev)
1039 1039
1040 raise util.Abort(_("revision matching date not found")) 1040 raise util.Abort(_("revision matching date not found"))
1041 1041
1042 def walkchangerevs(ui, repo, pats, change, opts): 1042 def walkchangerevs(ui, repo, match, change, opts):
1043 '''Iterate over files and the revs in which they changed. 1043 '''Iterate over files and the revs in which they changed.
1044 1044
1045 Callers most commonly need to iterate backwards over the history 1045 Callers most commonly need to iterate backwards over the history
1046 in which they are interested. Doing so has awful (quadratic-looking) 1046 in which they are interested. Doing so has awful (quadratic-looking)
1047 performance, so we use iterators in a "windowed" way. 1047 performance, so we use iterators in a "windowed" way.
1048 1048
1049 We walk a window of revisions in the desired order. Within the 1049 We walk a window of revisions in the desired order. Within the
1050 window, we first walk forwards to gather data, then in the desired 1050 window, we first walk forwards to gather data, then in the desired
1051 order (usually backwards) to display it. 1051 order (usually backwards) to display it.
1052 1052
1053 This function returns an (iterator, matchfn) tuple. The iterator 1053 This function returns an iterator. The iterator yields 3-tuples.
1054 yields 3-tuples. They will be of one of the following forms: 1054 They will be of one of the following forms:
1055 1055
1056 "window", incrementing, lastrev: stepping through a window, 1056 "window", incrementing, lastrev: stepping through a window,
1057 positive if walking forwards through revs, last rev in the 1057 positive if walking forwards through revs, last rev in the
1058 sequence iterated over - use to reset state for the current window 1058 sequence iterated over - use to reset state for the current window
1059 1059
1076 yield start, min(windowsize, start-end-1) 1076 yield start, min(windowsize, start-end-1)
1077 start -= windowsize 1077 start -= windowsize
1078 if windowsize < sizelimit: 1078 if windowsize < sizelimit:
1079 windowsize *= 2 1079 windowsize *= 2
1080 1080
1081 m = match(repo, pats, opts)
1082 follow = opts.get('follow') or opts.get('follow_first') 1081 follow = opts.get('follow') or opts.get('follow_first')
1083 1082
1084 if not len(repo): 1083 if not len(repo):
1085 return [], m 1084 return []
1086 1085
1087 if follow: 1086 if follow:
1088 defrange = '%s:0' % repo['.'].rev() 1087 defrange = '%s:0' % repo['.'].rev()
1089 else: 1088 else:
1090 defrange = '-1:0' 1089 defrange = '-1:0'
1091 revs = revrange(repo, opts['rev'] or [defrange]) 1090 revs = revrange(repo, opts['rev'] or [defrange])
1092 wanted = set() 1091 wanted = set()
1093 slowpath = m.anypats() or (m.files() and opts.get('removed')) 1092 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1094 fncache = {} 1093 fncache = {}
1095 1094
1096 if not slowpath and not m.files(): 1095 if not slowpath and not match.files():
1097 # No files, no patterns. Display all revs. 1096 # No files, no patterns. Display all revs.
1098 wanted = set(revs) 1097 wanted = set(revs)
1099 copies = [] 1098 copies = []
1100 if not slowpath: 1099 if not slowpath:
1101 # Only files, no patterns. Check the history of each file. 1100 # Only files, no patterns. Check the history of each file.
1115 # only yield rev for which we have the changelog, it can 1114 # only yield rev for which we have the changelog, it can
1116 # happen while doing "hg log" during a pull or commit 1115 # happen while doing "hg log" during a pull or commit
1117 if rev[0] < cl_count: 1116 if rev[0] < cl_count:
1118 yield rev 1117 yield rev
1119 def iterfiles(): 1118 def iterfiles():
1120 for filename in m.files(): 1119 for filename in match.files():
1121 yield filename, None 1120 yield filename, None
1122 for filename_node in copies: 1121 for filename_node in copies:
1123 yield filename_node 1122 yield filename_node
1124 minrev, maxrev = min(revs), max(revs) 1123 minrev, maxrev = min(revs), max(revs)
1125 for file_, node in iterfiles(): 1124 for file_, node in iterfiles():
1155 for i, window in increasing_windows(len(repo) - 1, nullrev): 1154 for i, window in increasing_windows(len(repo) - 1, nullrev):
1156 for j in xrange(i - window, i + 1): 1155 for j in xrange(i - window, i + 1):
1157 yield change(j) 1156 yield change(j)
1158 1157
1159 for ctx in changerevgen(): 1158 for ctx in changerevgen():
1160 matches = filter(m, ctx.files()) 1159 matches = filter(match, ctx.files())
1161 if matches: 1160 if matches:
1162 fncache[ctx.rev()] = matches 1161 fncache[ctx.rev()] = matches
1163 wanted.add(ctx.rev()) 1162 wanted.add(ctx.rev())
1164 1163
1165 class followfilter(object): 1164 class followfilter(object):
1208 for x in xrange(rev, stop-1, -1): 1207 for x in xrange(rev, stop-1, -1):
1209 if ff.match(x): 1208 if ff.match(x):
1210 wanted.discard(x) 1209 wanted.discard(x)
1211 1210
1212 def iterate(): 1211 def iterate():
1213 if follow and not m.files(): 1212 if follow and not match.files():
1214 ff = followfilter(onlyfirst=opts.get('follow_first')) 1213 ff = followfilter(onlyfirst=opts.get('follow_first'))
1215 def want(rev): 1214 def want(rev):
1216 return ff.match(rev) and rev in wanted 1215 return ff.match(rev) and rev in wanted
1217 else: 1216 else:
1218 def want(rev): 1217 def want(rev):
1224 for rev in sorted(nrevs): 1223 for rev in sorted(nrevs):
1225 fns = fncache.get(rev) 1224 fns = fncache.get(rev)
1226 if not fns: 1225 if not fns:
1227 def fns_generator(): 1226 def fns_generator():
1228 for f in change(rev).files(): 1227 for f in change(rev).files():
1229 if m(f): 1228 if match(f):
1230 yield f 1229 yield f
1231 fns = fns_generator() 1230 fns = fns_generator()
1232 yield 'add', rev, fns 1231 yield 'add', rev, fns
1233 for rev in nrevs: 1232 for rev in nrevs:
1234 yield 'iter', rev, None 1233 yield 'iter', rev, None
1235 return iterate(), m 1234 return iterate()
1236 1235
1237 def commit(ui, repo, commitfunc, pats, opts): 1236 def commit(ui, repo, commitfunc, pats, opts):
1238 '''commit the specified files or all outstanding changes''' 1237 '''commit the specified files or all outstanding changes'''
1239 date = opts.get('date') 1238 date = opts.get('date')
1240 if date: 1239 if date: