comparison mercurial/copies.py @ 26656:3e3d783b0d59

copies: factor out setupctx into _makegetfctx This reduces the scope of mergecopies a bit
author Matt Mackall <mpm@selenic.com>
date Wed, 19 Aug 2015 15:17:33 -0500
parents f3c6540f2cd1
children 1ae898cfe857
comparison
equal deleted inserted replaced
26655:f3c6540f2cd1 26656:3e3d783b0d59
235 if u2: 235 if u2:
236 repo.ui.debug(" unmatched files in other:\n %s\n" 236 repo.ui.debug(" unmatched files in other:\n %s\n"
237 % "\n ".join(u2)) 237 % "\n ".join(u2))
238 return u1, u2 238 return u1, u2
239 239
240 def _makegetfctx(ctx):
241 """return a 'getfctx' function suitable for checkcopies usage
242
243 We have to re-setup the function building 'filectx' for each
244 'checkcopies' to ensure the linkrev adjustement is properly setup for
245 each. Linkrev adjustment is important to avoid bug in rename
246 detection. Moreover, having a proper '_ancestrycontext' setup ensures
247 the performance impact of this adjustment is kept limited. Without it,
248 each file could do a full dag traversal making the time complexity of
249 the operation explode (see issue4537).
250
251 This function exists here mostly to limit the impact on stable. Feel
252 free to refactor on default.
253 """
254 rev = ctx.rev()
255 repo = ctx._repo
256 ac = getattr(ctx, '_ancestrycontext', None)
257 if ac is None:
258 revs = [rev]
259 if rev is None:
260 revs = [p.rev() for p in ctx.parents()]
261 ac = repo.changelog.ancestors(revs, inclusive=True)
262 ctx._ancestrycontext = ac
263 def makectx(f, n):
264 if len(n) != 20: # in a working context?
265 if ctx.rev() is None:
266 return ctx.filectx(f)
267 return repo[None][f]
268 fctx = repo.filectx(f, fileid=n)
269 # setup only needed for filectx not create from a changectx
270 fctx._ancestrycontext = ac
271 fctx._descendantrev = rev
272 return fctx
273 return util.lrucachefunc(makectx)
274
240 def mergecopies(repo, c1, c2, ca): 275 def mergecopies(repo, c1, c2, ca):
241 """ 276 """
242 Find moves and copies between context c1 and c2 that are relevant 277 Find moves and copies between context c1 and c2 that are relevant
243 for merging. 278 for merging.
244 279
281 316
282 m1 = c1.manifest() 317 m1 = c1.manifest()
283 m2 = c2.manifest() 318 m2 = c2.manifest()
284 ma = ca.manifest() 319 ma = ca.manifest()
285 320
286
287 def setupctx(ctx):
288 """return a 'getfctx' function suitable for checkcopies usage
289
290 We have to re-setup the function building 'filectx' for each
291 'checkcopies' to ensure the linkrev adjustement is properly setup for
292 each. Linkrev adjustment is important to avoid bug in rename
293 detection. Moreover, having a proper '_ancestrycontext' setup ensures
294 the performance impact of this adjustment is kept limited. Without it,
295 each file could do a full dag traversal making the time complexity of
296 the operation explode (see issue4537).
297
298 This function exists here mostly to limit the impact on stable. Feel
299 free to refactor on default.
300 """
301 rev = ctx.rev()
302 ac = getattr(ctx, '_ancestrycontext', None)
303 repo = ctx._repo
304 if ac is None:
305 revs = [rev]
306 if rev is None:
307 revs = [p.rev() for p in ctx.parents()]
308 ac = ctx._repo.changelog.ancestors(revs, inclusive=True)
309 ctx._ancestrycontext = ac
310 def makectx(f, n):
311 if len(n) != 20: # in a working context?
312 if ctx.rev() is None:
313 return ctx.filectx(f)
314 return repo[None][f]
315 fctx = repo.filectx(f, fileid=n)
316 # setup only needed for filectx not create from a changectx
317 fctx._ancestrycontext = ac
318 fctx._descendantrev = rev
319 return fctx
320 return util.lrucachefunc(makectx)
321
322 copy1, copy2, = {}, {} 321 copy1, copy2, = {}, {}
323 movewithdir1, movewithdir2 = {}, {} 322 movewithdir1, movewithdir2 = {}, {}
324 fullcopy1, fullcopy2 = {}, {} 323 fullcopy1, fullcopy2 = {}, {}
325 diverge = {} 324 diverge = {}
326 325
327 addedinm1 = m1.filesnotin(ma) 326 addedinm1 = m1.filesnotin(ma)
328 addedinm2 = m2.filesnotin(ma) 327 addedinm2 = m2.filesnotin(ma)
329 u1, u2 = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2) 328 u1, u2 = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2)
330 329
331 for f in u1: 330 for f in u1:
332 getfctx = setupctx(c1) 331 getfctx = _makegetfctx(c1)
333 checkcopies(getfctx, f, m1, m2, ca, limit, diverge, copy1, fullcopy1) 332 checkcopies(getfctx, f, m1, m2, ca, limit, diverge, copy1, fullcopy1)
334 333
335 for f in u2: 334 for f in u2:
336 getfctx = setupctx(c2) 335 getfctx = _makegetfctx(c2)
337 checkcopies(getfctx, f, m2, m1, ca, limit, diverge, copy2, fullcopy2) 336 checkcopies(getfctx, f, m2, m1, ca, limit, diverge, copy2, fullcopy2)
338 337
339 copy = dict(copy1.items() + copy2.items()) 338 copy = dict(copy1.items() + copy2.items())
340 movewithdir = dict(movewithdir1.items() + movewithdir2.items()) 339 movewithdir = dict(movewithdir1.items() + movewithdir2.items())
341 fullcopy = dict(fullcopy1.items() + fullcopy2.items()) 340 fullcopy = dict(fullcopy1.items() + fullcopy2.items())
358 if bothnew: 357 if bothnew:
359 repo.ui.debug(" unmatched files new in both:\n %s\n" 358 repo.ui.debug(" unmatched files new in both:\n %s\n"
360 % "\n ".join(bothnew)) 359 % "\n ".join(bothnew))
361 bothdiverge, _copy, _fullcopy = {}, {}, {} 360 bothdiverge, _copy, _fullcopy = {}, {}, {}
362 for f in bothnew: 361 for f in bothnew:
363 getfctx = setupctx(c1) 362 getfctx = _makegetfctx(c1)
364 checkcopies(getfctx, f, m1, m2, ca, limit, bothdiverge, 363 checkcopies(getfctx, f, m1, m2, ca, limit, bothdiverge,
365 _copy, _fullcopy) 364 _copy, _fullcopy)
366 getfctx = setupctx(c2) 365 getfctx = _makegetfctx(c2)
367 checkcopies(getfctx, f, m2, m1, ca, limit, bothdiverge, 366 checkcopies(getfctx, f, m2, m1, ca, limit, bothdiverge,
368 _copy, _fullcopy) 367 _copy, _fullcopy)
369 for of, fl in bothdiverge.items(): 368 for of, fl in bothdiverge.items():
370 if len(fl) == 2 and fl[0] == fl[1]: 369 if len(fl) == 2 and fl[0] == fl[1]:
371 copy[fl[0]] = of # not actually divergent, just matching renames 370 copy[fl[0]] = of # not actually divergent, just matching renames