# HG changeset patch # User Pierre-Yves David # Date 1542592365 0 # Node ID bccd5c2786ba8b49abd12ef56f87ae2dd9c61f31 # Parent 697ec7c2f3251ae52834ca3f7e95794d2fce02e4 compat: drop 4.3 monkey patch of `copies.mergecopies` diff -r 697ec7c2f325 -r bccd5c2786ba hgext3rd/evolve/compat.py --- a/hgext3rd/evolve/compat.py Mon Nov 19 01:45:34 2018 +0000 +++ b/hgext3rd/evolve/compat.py Mon Nov 19 01:52:45 2018 +0000 @@ -466,256 +466,8 @@ return copy, movewithdir, diverge, renamedelete, dirmove -# code imported from Mercurial core at 4.3 + patch -def fixoldmergecopies(repo, c1, c2, base): - - from mercurial import pathutil - - # avoid silly behavior for update from empty dir - if not c1 or not c2 or c1 == c2: - return {}, {}, {}, {}, {} - - # avoid silly behavior for parent -> working dir - if c2.node() is None and c1.node() == repo.dirstate.p1(): - return repo.dirstate.copies(), {}, {}, {}, {} - - # Copy trace disabling is explicitly below the node == p1 logic above - # because the logic above is required for a simple copy to be kept across a - # rebase. - if repo.ui.configbool('experimental', 'disablecopytrace'): - return {}, {}, {}, {}, {} - - # In certain scenarios (e.g. graft, update or rebase), base can be - # overridden We still need to know a real common ancestor in this case We - # can't just compute _c1.ancestor(_c2) and compare it to ca, because there - # can be multiple common ancestors, e.g. in case of bidmerge. Because our - # caller may not know if the revision passed in lieu of the CA is a genuine - # common ancestor or not without explicitly checking it, it's better to - # determine that here. - # - # base.descendant(wc) and base.descendant(base) are False, work around that - _c1 = c1.p1() if c1.rev() is None else c1 - _c2 = c2.p1() if c2.rev() is None else c2 - # an endpoint is "dirty" if it isn't a descendant of the merge base - # if we have a dirty endpoint, we need to trigger graft logic, and also - # keep track of which endpoint is dirty - dirtyc1 = not (base == _c1 or base.descendant(_c1)) - dirtyc2 = not (base == _c2 or base.descendant(_c2)) - graft = dirtyc1 or dirtyc2 - tca = base - if graft: - tca = _c1.ancestor(_c2) - - limit = copies._findlimit(repo, c1.rev(), c2.rev()) - if limit is None: - # no common ancestor, no copies - return {}, {}, {}, {}, {} - repo.ui.debug(" searching for copies back to rev %d\n" % limit) - - m1 = c1.manifest() - m2 = c2.manifest() - mb = base.manifest() - - # gather data from _checkcopies: - # - diverge = record all diverges in this dict - # - copy = record all non-divergent copies in this dict - # - fullcopy = record all copies in this dict - # - incomplete = record non-divergent partial copies here - # - incompletediverge = record divergent partial copies here - diverge = {} # divergence data is shared - incompletediverge = {} - data1 = {'copy': {}, - 'fullcopy': {}, - 'incomplete': {}, - 'diverge': diverge, - 'incompletediverge': incompletediverge, - } - data2 = {'copy': {}, - 'fullcopy': {}, - 'incomplete': {}, - 'diverge': diverge, - 'incompletediverge': incompletediverge, - } - - # find interesting file sets from manifests - addedinm1 = m1.filesnotin(mb) - addedinm2 = m2.filesnotin(mb) - bothnew = sorted(addedinm1 & addedinm2) - if tca == base: - # unmatched file from base - u1r, u2r = copies._computenonoverlap(repo, c1, c2, addedinm1, addedinm2) - u1u, u2u = u1r, u2r - else: - # unmatched file from base (DAG rotation in the graft case) - u1r, u2r = copies._computenonoverlap(repo, c1, c2, addedinm1, addedinm2, - baselabel='base') - # unmatched file from topological common ancestors (no DAG rotation) - # need to recompute this for directory move handling when grafting - mta = tca.manifest() - u1u, u2u = copies._computenonoverlap(repo, c1, c2, m1.filesnotin(mta), - m2.filesnotin(mta), - baselabel='topological common ancestor') - - for f in u1u: - copies._checkcopies(c1, c2, f, base, tca, dirtyc1, limit, data1) - - for f in u2u: - copies._checkcopies(c2, c1, f, base, tca, dirtyc2, limit, data2) - - copy = dict(data1['copy']) - copy.update(data2['copy']) - fullcopy = dict(data1['fullcopy']) - fullcopy.update(data2['fullcopy']) - - if dirtyc1: - copies._combinecopies(data2['incomplete'], data1['incomplete'], copy, diverge, - incompletediverge) - else: - copies._combinecopies(data1['incomplete'], data2['incomplete'], copy, diverge, - incompletediverge) - - renamedelete = {} - renamedeleteset = set() - divergeset = set() - for of, fl in diverge.items(): - if len(fl) == 1 or of in c1 or of in c2: - del diverge[of] # not actually divergent, or not a rename - if of not in c1 and of not in c2: - # renamed on one side, deleted on the other side, but filter - # out files that have been renamed and then deleted - renamedelete[of] = [f for f in fl if f in c1 or f in c2] - renamedeleteset.update(fl) # reverse map for below - else: - divergeset.update(fl) # reverse map for below - - if bothnew: - repo.ui.debug(" unmatched files new in both:\n %s\n" - % "\n ".join(bothnew)) - bothdiverge = {} - bothincompletediverge = {} - remainder = {} - both1 = {'copy': {}, - 'fullcopy': {}, - 'incomplete': {}, - 'diverge': bothdiverge, - 'incompletediverge': bothincompletediverge - } - both2 = {'copy': {}, - 'fullcopy': {}, - 'incomplete': {}, - 'diverge': bothdiverge, - 'incompletediverge': bothincompletediverge - } - for f in bothnew: - copies._checkcopies(c1, c2, f, base, tca, dirtyc1, limit, both1) - copies._checkcopies(c2, c1, f, base, tca, dirtyc2, limit, both2) - if dirtyc1 and dirtyc2: - pass - elif dirtyc1: - # incomplete copies may only be found on the "dirty" side for bothnew - assert not both2['incomplete'] - remainder = copies._combinecopies({}, both1['incomplete'], copy, bothdiverge, - bothincompletediverge) - elif dirtyc2: - assert not both1['incomplete'] - remainder = copies._combinecopies({}, both2['incomplete'], copy, bothdiverge, - bothincompletediverge) - else: - # incomplete copies and divergences can't happen outside grafts - assert not both1['incomplete'] - assert not both2['incomplete'] - assert not bothincompletediverge - for f in remainder: - assert f not in bothdiverge - ic = remainder[f] - if ic[0] in (m1 if dirtyc1 else m2): - # backed-out rename on one side, but watch out for deleted files - bothdiverge[f] = ic - for of, fl in bothdiverge.items(): - if len(fl) == 2 and fl[0] == fl[1]: - copy[fl[0]] = of # not actually divergent, just matching renames - - if fullcopy and repo.ui.debugflag: - repo.ui.debug(" all copies found (* = to merge, ! = divergent, " - "% = renamed and deleted):\n") - for f in sorted(fullcopy): - note = "" - if f in copy: - note += "*" - if f in divergeset: - note += "!" - if f in renamedeleteset: - note += "%" - repo.ui.debug(" src: '%s' -> dst: '%s' %s\n" % (fullcopy[f], f, - note)) - del divergeset - - if not fullcopy: - return copy, {}, diverge, renamedelete, {} - - repo.ui.debug(" checking for directory renames\n") - - # generate a directory move map - d1, d2 = c1.dirs(), c2.dirs() - # Hack for adding '', which is not otherwise added, to d1 and d2 - d1.addpath('/') - d2.addpath('/') - invalid = set() - dirmove = {} - - # examine each file copy for a potential directory move, which is - # when all the files in a directory are moved to a new directory - for dst, src in fullcopy.iteritems(): - dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst) - if dsrc in invalid: - # already seen to be uninteresting - continue - elif dsrc in d1 and ddst in d1: - # directory wasn't entirely moved locally - invalid.add(dsrc + "/") - elif dsrc in d2 and ddst in d2: - # directory wasn't entirely moved remotely - invalid.add(dsrc + "/") - elif dsrc + "/" in dirmove and dirmove[dsrc + "/"] != ddst + "/": - # files from the same directory moved to two different places - invalid.add(dsrc + "/") - else: - # looks good so far - dirmove[dsrc + "/"] = ddst + "/" - - for i in invalid: - if i in dirmove: - del dirmove[i] - del d1, d2, invalid - - if not dirmove: - return copy, {}, diverge, renamedelete, {} - - for d in dirmove: - repo.ui.debug(" discovered dir src: '%s' -> dst: '%s'\n" % - (d, dirmove[d])) - - movewithdir = {} - # check unaccounted nonoverlapping files against directory moves - for f in u1r + u2r: - if f not in fullcopy: - for d in dirmove: - if f.startswith(d): - # new file added in a directory that was moved, move it - df = dirmove[d] + f[len(d):] - if df not in copy: - movewithdir[f] = df - repo.ui.debug((" pending file src: '%s' -> " - "dst: '%s'\n") % (f, df)) - break - - return copy, movewithdir, diverge, renamedelete, dirmove - if util.safehasattr(copies, '_fullcopytracing'): copies._fullcopytracing = fixedcopytracing -elif util.safehasattr(copies, 'mergecopies'): - # compat fix for hg <= 4.3 - copies.mergecopies = fixoldmergecopies if not util.safehasattr(obsutil, "_succs"): class _succs(list):