comparison mercurial/commands.py @ 8849:80cc4b1a62d0

compare grep result between target and its parent I found that typical case is that grep target is added at (*) revision in the tree shown below. +--- 1(*) --- 3 0 +--- 2 ------ 4 Now, I expect 'hg grep --all' to show only rev:1 which is first appearance of target line. But 'hg grep --all' will tell: target line dis-appeared at 3 => 4 target line appeared at 2 => 3 target line dis-appeared at 1 => 2 target line appeared at 0 => 1 because current 'hg grep' implementation compares not between target revision and its parent, but between neighbor revisions in walkthrough order. I checked performance of this patch by "hg grep --follow --all walkchangerevs" on whole Mercurial repo, and patched version could complete as fast as un-patched one.
author FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
date Tue, 19 May 2009 16:49:54 +0900
parents 6d36fc70754e
children f331de880cbb
comparison
equal deleted inserted replaced
8848:89b71acdac9a 8849:80cc4b1a62d0
1228 for i in xrange(alo, ahi): 1228 for i in xrange(alo, ahi):
1229 yield ('-', a[i]) 1229 yield ('-', a[i])
1230 for i in xrange(blo, bhi): 1230 for i in xrange(blo, bhi):
1231 yield ('+', b[i]) 1231 yield ('+', b[i])
1232 1232
1233 prev = {} 1233 def display(fn, r, pstates, states):
1234 def display(fn, rev, states, prevstates):
1235 datefunc = ui.quiet and util.shortdate or util.datestr 1234 datefunc = ui.quiet and util.shortdate or util.datestr
1236 found = False 1235 found = False
1237 filerevmatches = {} 1236 filerevmatches = {}
1238 r = prev.get(fn, -1)
1239 if opts.get('all'): 1237 if opts.get('all'):
1240 iter = difflinestates(states, prevstates) 1238 iter = difflinestates(pstates, states)
1241 else: 1239 else:
1242 iter = [('', l) for l in prevstates] 1240 iter = [('', l) for l in states]
1243 for change, l in iter: 1241 for change, l in iter:
1244 cols = [fn, str(r)] 1242 cols = [fn, str(r)]
1245 if opts.get('line_number'): 1243 if opts.get('line_number'):
1246 cols.append(str(l.linenum)) 1244 cols.append(str(l.linenum))
1247 if opts.get('all'): 1245 if opts.get('all'):
1259 cols.append(l.line) 1257 cols.append(l.line)
1260 ui.write(sep.join(cols), eol) 1258 ui.write(sep.join(cols), eol)
1261 found = True 1259 found = True
1262 return found 1260 return found
1263 1261
1264 fstate = {}
1265 skip = {} 1262 skip = {}
1263 revfiles = {}
1266 get = util.cachefunc(lambda r: repo[r].changeset()) 1264 get = util.cachefunc(lambda r: repo[r].changeset())
1267 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts) 1265 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1268 found = False 1266 found = False
1269 follow = opts.get('follow') 1267 follow = opts.get('follow')
1270 for st, rev, fns in changeiter: 1268 for st, rev, fns in changeiter:
1271 if st == 'window': 1269 if st == 'window':
1272 matches.clear() 1270 matches.clear()
1271 revfiles.clear()
1273 elif st == 'add': 1272 elif st == 'add':
1274 ctx = repo[rev] 1273 ctx = repo[rev]
1275 matches[rev] = {} 1274 pctx = ctx.parents()[0]
1275 parent = pctx.rev()
1276 matches.setdefault(rev, {})
1277 matches.setdefault(parent, {})
1278 files = revfiles.setdefault(rev, [])
1276 for fn in fns: 1279 for fn in fns:
1280 flog = getfile(fn)
1281 try:
1282 fnode = ctx.filenode(fn)
1283 except error.LookupError:
1284 continue
1285
1286 copied = flog.renamed(fnode)
1287 copy = follow and copied and copied[0]
1288 if copy:
1289 copies.setdefault(rev, {})[fn] = copy
1277 if fn in skip: 1290 if fn in skip:
1291 if copy:
1292 skip[copy] = True
1278 continue 1293 continue
1279 try: 1294 files.append(fn)
1280 grepbody(fn, rev, getfile(fn).read(ctx.filenode(fn))) 1295
1281 fstate.setdefault(fn, []) 1296 if not matches[rev].has_key(fn):
1282 if follow: 1297 grepbody(fn, rev, flog.read(fnode))
1283 copied = getfile(fn).renamed(ctx.filenode(fn)) 1298
1284 if copied: 1299 pfn = copy or fn
1285 copies.setdefault(rev, {})[fn] = copied[0] 1300 if not matches[parent].has_key(pfn):
1286 except error.LookupError: 1301 try:
1287 pass 1302 fnode = pctx.filenode(pfn)
1303 grepbody(pfn, parent, flog.read(fnode))
1304 except error.LookupError:
1305 pass
1288 elif st == 'iter': 1306 elif st == 'iter':
1289 for fn, m in sorted(matches[rev].items()): 1307 parent = repo[rev].parents()[0].rev()
1308 for fn in sorted(revfiles.get(rev, [])):
1309 states = matches[rev][fn]
1290 copy = copies.get(rev, {}).get(fn) 1310 copy = copies.get(rev, {}).get(fn)
1291 if fn in skip: 1311 if fn in skip:
1292 if copy: 1312 if copy:
1293 skip[copy] = True 1313 skip[copy] = True
1294 continue 1314 continue
1295 if fn in prev or fstate[fn]: 1315 pstates = matches.get(parent, {}).get(copy or fn, [])
1296 r = display(fn, rev, m, fstate[fn]) 1316 if pstates or states:
1317 r = display(fn, rev, pstates, states)
1297 found = found or r 1318 found = found or r
1298 if r and not opts.get('all'): 1319 if r and not opts.get('all'):
1299 skip[fn] = True 1320 skip[fn] = True
1300 if copy: 1321 if copy:
1301 skip[copy] = True 1322 skip[copy] = True
1302 fstate[fn] = m
1303 if copy:
1304 fstate[copy] = m
1305 prev[fn] = rev
1306
1307 for fn, state in sorted(fstate.items()):
1308 if fn in skip:
1309 continue
1310 if fn not in copies.get(prev[fn], {}):
1311 found = display(fn, rev, {}, state) or found
1312 return (not found and 1) or 0
1313 1323
1314 def heads(ui, repo, *branchrevs, **opts): 1324 def heads(ui, repo, *branchrevs, **opts):
1315 """show current repository heads or show branch heads 1325 """show current repository heads or show branch heads
1316 1326
1317 With no arguments, show all repository head changesets. 1327 With no arguments, show all repository head changesets.