def find_unconflicted(self): """Return a list of ranges in base that are not conflicted.""" am = patiencediff.PatienceSequenceMatcher( None, self.base, self.a).get_matching_blocks() bm = patiencediff.PatienceSequenceMatcher( None, self.base, self.b).get_matching_blocks() unc = [] while am and bm: # there is an unconflicted block at i; how long does it # extend? until whichever one ends earlier. a1 = am[0][0] a2 = a1 + am[0][2] b1 = bm[0][0] b2 = b1 + bm[0][2] i = intersect((a1, a2), (b1, b2)) if i: unc.append(i) if a2 < b2: del am[0] else: del bm[0] return unc
def find_sync_regions(self): """Return a list of sync regions, where both descendents match the base. Generates a list of (base1, base2, a1, a2, b1, b2). There is always a zero-length sync region at the end of all the files. """ ia = ib = 0 amatches = patiencediff.PatienceSequenceMatcher( None, self.base, self.a).get_matching_blocks() bmatches = patiencediff.PatienceSequenceMatcher( None, self.base, self.b).get_matching_blocks() len_a = len(amatches) len_b = len(bmatches) sl = [] while ia < len_a and ib < len_b: abase, amatch, alen = amatches[ia] bbase, bmatch, blen = bmatches[ib] # there is an unconflicted block at i; how long does it # extend? until whichever one ends earlier. i = intersect((abase, abase + alen), (bbase, bbase + blen)) if i: intbase = i[0] intend = i[1] intlen = intend - intbase # found a match of base[i[0], i[1]]; this may be less than # the region that matches in either one # assert intlen <= alen # assert intlen <= blen # assert abase <= intbase # assert bbase <= intbase asub = amatch + (intbase - abase) bsub = bmatch + (intbase - bbase) aend = asub + intlen bend = bsub + intlen # assert self.base[intbase:intend] == self.a[asub:aend], \ # (self.base[intbase:intend], self.a[asub:aend]) # assert self.base[intbase:intend] == self.b[bsub:bend] sl.append((intbase, intend, asub, aend, bsub, bend)) # advance whichever one ends first in the base text if (abase + alen) < (bbase + blen): ia += 1 else: ib += 1 intbase = len(self.base) abase = len(self.a) bbase = len(self.b) sl.append((intbase, intbase, abase, abase, bbase, bbase)) return sl
def reprocess_merge_regions(self, merge_regions): """Where there are conflict regions, remove the agreed lines. Lines where both A and B have made the same changes are eliminated. """ for region in merge_regions: if region[0] != "conflict": yield region continue type, iz, zmatch, ia, amatch, ib, bmatch = region a_region = self.a[ia:amatch] b_region = self.b[ib:bmatch] matches = patiencediff.PatienceSequenceMatcher( None, a_region, b_region).get_matching_blocks() next_a = ia next_b = ib for region_ia, region_ib, region_len in matches[:-1]: region_ia += ia region_ib += ib reg = self.mismatch_region(next_a, region_ia, next_b, region_ib) if reg is not None: yield reg yield 'same', region_ia, region_len + region_ia next_a = region_ia + region_len next_b = region_ib + region_len reg = self.mismatch_region(next_a, amatch, next_b, bmatch) if reg is not None: yield reg
def find_sync_regions(self): """Return a list of sync regions, where both descendents match the base. Generates a list of (base1, base2, a1, a2, b1, b2). There is always a zero-length sync region at the end of all the files. """ ia = ib = 0 amatches = patiencediff.PatienceSequenceMatcher( None, self.base, self.a).get_matching_blocks() bmatches = patiencediff.PatienceSequenceMatcher( None, self.base, self.b).get_matching_blocks() len_a = len(amatches) len_b = len(bmatches) sl = [] while ia < len_a and ib < len_b: abase, amatch, alen = amatches[ia] bbase, bmatch, blen = bmatches[ib] # there is an unconflicted block at i; how long does it # extend? until whichever one ends earlier. i = intersect((abase, abase+alen), (bbase, bbase+blen)) if i: intbase = i[0] intend = i[1] intlen = intend - intbase # found a match of base[i[0], i[1]]; this may be less than # the region that matches in either one # assert intlen <= alen # assert intlen <= blen # assert abase <= intbase # assert bbase <= intbase asub = amatch + (intbase - abase) bsub = bmatch + (intbase - bbase) aend = asub + intlen bend = bsub + intlen # assert self.base[intbase:intend] == self.a[asub:aend], \ # (self.base[intbase:intend], self.a[asub:aend]) # assert self.base[intbase:intend] == sel :param allow_objects: if True, do not require that base, a and b are plain Python strs. Also prevents BinaryFile from being raised. Lines can be any sequence of comparable and hashable Python objects.
def test_compare_two_parents_blocks(self): matcher = patiencediff.PatienceSequenceMatcher(None, LINES_2, LINES_1) blocks = matcher.get_matching_blocks() diff = multiparent.MultiParent.from_lines(LINES_1, [LINES_2, LINES_3], left_blocks=blocks) self.assertEqual([multiparent.ParentText(1, 0, 0, 4), multiparent.ParentText(0, 3, 4, 1)], diff.hunks)
def _reannotate(parent_lines, new_lines, new_revision_id, matching_blocks=None): new_cur = 0 if matching_blocks is None: plain_parent_lines = [l for r, l in parent_lines] matcher = patiencediff.PatienceSequenceMatcher(None, plain_parent_lines, new_lines) matching_blocks = matcher.get_matching_blocks() lines = [] for i, j, n in matching_blocks: for line in new_lines[new_cur:j]: lines.append((new_revision_id, line)) lines.extend(parent_lines[i:i+n]) new_cur = j + n return lines
def _refine_cherrypick_conflict(self, zstart, zend, astart, aend, bstart, bend): """When cherrypicking b => a, ignore matches with b and base.""" # Do not emit regions which match, only regions which do not match matches = patiencediff.PatienceSequenceMatcher( None, self.base[zstart:zend], self.b[bstart:bend]).get_matching_blocks() last_base_idx = 0 last_b_idx = 0 last_b_idx = 0 yielded_a = False for base_idx, b_idx, match_len in matches: conflict_z_len = base_idx - last_base_idx conflict_b_len = b_idx - last_b_idx if conflict_b_len == 0: # There are no lines in b which conflict, # so skip it pass else: if yielded_a: yield ('conflict', zstart + last_base_idx, zstart + base_idx, aend, aend, bstart + last_b_idx, bstart + b_idx) else: # The first conflict gets the a-range yielded_a = True yield ('conflict', zstart + last_base_idx, zstart + base_idx, astart, aend, bstart + last_b_idx, bstart + b_idx) last_base_idx = base_idx + match_len last_b_idx = b_idx + match_len if last_base_idx != zend - zstart or last_b_idx != bend - bstart: if yielded_a: yield ('conflict', zstart + last_base_idx, zstart + base_idx, aend, aend, bstart + last_b_idx, bstart + b_idx) else: # The first conflict gets the a-range yielded_a = True yield ('conflict', zstart + last_base_idx, zstart + base_idx, astart, aend, bstart + last_b_idx, bstart + b_idx) if not yielded_a: yield ('conflict', zstart, zend, astart, aend, bstart, bend)
def _count_changed_regions(old_lines, new_lines): matcher = patiencediff.PatienceSequenceMatcher(None, old_lines, new_lines) blocks = matcher.get_matching_blocks() return len(blocks) - 2
def _get_matching_blocks(old, new): matcher = patiencediff.PatienceSequenceMatcher(None, old, new) return matcher.get_matching_blocks()
def _matched_lines(old, new): matcher = patiencediff.PatienceSequenceMatcher(None, old, new) matched_lines = sum (n for i, j, n in matcher.get_matching_blocks()) return matched_lines