comparison mercurial/patch.py @ 16121:ccba74472af2 stable

patch: fuzz old and new lines at the same time In theory, the fuzzed offsets for old and new lines should be exactly the same as they are based on hunk parsing. Make it true in practice.
author Patrick Mezard <patrick@mezard.eu>
date Mon, 13 Feb 2012 13:21:00 +0100
parents d7829b2ecf32
children 9ef3a4a2c6c0
comparison
equal deleted inserted replaced
16119:5de83d9ca79c 16121:ccba74472af2
726 # hunk data before patching. Otherwise, preserve input 726 # hunk data before patching. Otherwise, preserve input
727 # line-endings. 727 # line-endings.
728 h = h.getnormalized() 728 h = h.getnormalized()
729 729
730 # fast case first, no offsets, no fuzz 730 # fast case first, no offsets, no fuzz
731 old = h.old() 731 old, new = h.fuzzit(0, False)
732 start = h.starta + self.offset 732 start = h.starta + self.offset
733 # zero length hunk ranges already have their start decremented 733 # zero length hunk ranges already have their start decremented
734 if h.lena: 734 if h.lena:
735 start -= 1 735 start -= 1
736 orig_start = start 736 orig_start = start
739 # fast case code 739 # fast case code
740 if self.skew == 0 and diffhelpers.testhunk(old, self.lines, start) == 0: 740 if self.skew == 0 and diffhelpers.testhunk(old, self.lines, start) == 0:
741 if self.remove: 741 if self.remove:
742 self.backend.unlink(self.fname) 742 self.backend.unlink(self.fname)
743 else: 743 else:
744 self.lines[start : start + h.lena] = h.new() 744 self.lines[start : start + h.lena] = new
745 self.offset += h.lenb - h.lena 745 self.offset += h.lenb - h.lena
746 self.dirty = True 746 self.dirty = True
747 return 0 747 return 0
748 748
749 # ok, we couldn't match the hunk. Lets look for offsets and fuzz it 749 # ok, we couldn't match the hunk. Lets look for offsets and fuzz it
757 else: 757 else:
758 search_start = orig_start + self.skew 758 search_start = orig_start + self.skew
759 759
760 for fuzzlen in xrange(3): 760 for fuzzlen in xrange(3):
761 for toponly in [True, False]: 761 for toponly in [True, False]:
762 old = h.old(fuzzlen, toponly) 762 old, new = h.fuzzit(fuzzlen, toponly)
763 763
764 cand = self.findlines(old[0][1:], search_start) 764 cand = self.findlines(old[0][1:], search_start)
765 for l in cand: 765 for l in cand:
766 if diffhelpers.testhunk(old, self.lines, l) == 0: 766 if diffhelpers.testhunk(old, self.lines, l) == 0:
767 newlines = h.new(fuzzlen, toponly) 767 self.lines[l : l + len(old)] = new
768 self.lines[l : l + len(old)] = newlines 768 self.offset += len(new) - len(old)
769 self.offset += len(newlines) - len(old)
770 self.skew = l - orig_start 769 self.skew = l - orig_start
771 self.dirty = True 770 self.dirty = True
772 offset = l - orig_start - fuzzlen 771 offset = l - orig_start - fuzzlen
773 if fuzzlen: 772 if fuzzlen:
774 msg = _("Hunk #%d succeeded at %d " 773 msg = _("Hunk #%d succeeded at %d "
969 lr.push(l) 968 lr.push(l)
970 969
971 def complete(self): 970 def complete(self):
972 return len(self.a) == self.lena and len(self.b) == self.lenb 971 return len(self.a) == self.lena and len(self.b) == self.lenb
973 972
974 def fuzzit(self, l, fuzz, toponly): 973 def _fuzzit(self, old, new, fuzz, toponly):
975 # this removes context lines from the top and bottom of list 'l'. It 974 # this removes context lines from the top and bottom of list 'l'. It
976 # checks the hunk to make sure only context lines are removed, and then 975 # checks the hunk to make sure only context lines are removed, and then
977 # returns a new shortened list of lines. 976 # returns a new shortened list of lines.
978 fuzz = min(fuzz, len(l)-1) 977 fuzz = min(fuzz, len(old)-1)
979 if fuzz: 978 if fuzz:
980 top = 0 979 top = 0
981 bot = 0 980 bot = 0
982 hlen = len(self.hunk) 981 hlen = len(self.hunk)
983 for x in xrange(hlen - 1): 982 for x in xrange(hlen - 1):
1003 if top < context: 1002 if top < context:
1004 top = max(0, fuzz - (context - top)) 1003 top = max(0, fuzz - (context - top))
1005 else: 1004 else:
1006 top = min(fuzz, top) 1005 top = min(fuzz, top)
1007 1006
1008 return l[top:len(l)-bot] 1007 return old[top:len(old)-bot], new[top:len(new)-bot]
1009 return l 1008 return old, new
1010 1009
1011 def old(self, fuzz=0, toponly=False): 1010 def fuzzit(self, fuzz, toponly):
1012 return self.fuzzit(self.a, fuzz, toponly) 1011 return self._fuzzit(self.a, self.b, fuzz, toponly)
1013
1014 def new(self, fuzz=0, toponly=False):
1015 return self.fuzzit(self.b, fuzz, toponly)
1016 1012
1017 class binhunk(object): 1013 class binhunk(object):
1018 'A binary patch file. Only understands literals so far.' 1014 'A binary patch file. Only understands literals so far.'
1019 def __init__(self, lr): 1015 def __init__(self, lr):
1020 self.text = None 1016 self.text = None