--- a/mercurial/patch.py Sat Oct 18 23:45:45 2008 +0200
+++ b/mercurial/patch.py Sat Oct 18 23:45:46 2008 +0200
@@ -166,15 +166,9 @@
isexec = mode & 0100
self.mode = (islink, isexec)
-def readgitpatch(fp, firstline=None):
+def readgitpatch(lr):
"""extract git-style metadata about patches from <patchname>"""
- def reader(fp, firstline):
- if firstline is not None:
- yield firstline
- for line in fp:
- yield line
-
# Filter patch for git information
gitre = re.compile('diff --git a/(.*) b/(.*)')
gp = None
@@ -183,7 +177,7 @@
dopatch = 0
lineno = 0
- for line in reader(fp, firstline):
+ for line in lr:
lineno += 1
if line.startswith('diff --git'):
m = gitre.match(line)
@@ -461,7 +455,7 @@
self.lenb = int(self.lenb)
self.starta = int(self.starta)
self.startb = int(self.startb)
- diffhelpers.addlines(lr.fp, self.hunk, self.lena, self.lenb, self.a, self.b)
+ diffhelpers.addlines(lr, self.hunk, self.lena, self.lenb, self.a, self.b)
# if we hit eof before finishing out the hunk, the last line will
# be zero length. Lets try to fix it up.
while len(self.hunk[-1]) == 0:
@@ -771,7 +765,8 @@
self.buf = []
def push(self, line):
- self.buf.append(line)
+ if line is not None:
+ self.buf.append(line)
def readline(self):
if self.buf:
@@ -780,6 +775,39 @@
return l
return self.fp.readline()
+ def __iter__(self):
+ while 1:
+ l = self.readline()
+ if not l:
+ break
+ yield l
+
+def scangitpatch(lr, firstline):
+ """
+ Git patches can emit:
+ - rename a to b
+ - change b
+ - copy a to c
+ - change c
+
+ We cannot apply this sequence as-is, the renamed 'a' could not be
+ found for it would have been renamed already. And we cannot copy
+ from 'b' instead because 'b' would have been changed already. So
+ we scan the git patch for copy and rename commands so we can
+ perform the copies ahead of time.
+ """
+ pos = 0
+ try:
+ pos = lr.fp.tell()
+ fp = lr.fp
+ except IOError:
+ fp = cStringIO.StringIO(lr.fp.read())
+ gitlr = linereader(fp)
+ gitlr.push(firstline)
+ (dopatch, gitpatches) = readgitpatch(gitlr)
+ fp.seek(pos)
+ return fp, dopatch, gitpatches
+
def iterhunks(ui, fp, sourcefile=None):
"""Read a patch and yield the following events:
- ("file", afile, bfile, firsthunk): select a new target file.
@@ -788,24 +816,6 @@
- ("git", gitchanges): current diff is in git format, gitchanges
maps filenames to gitpatch records. Unique event.
"""
-
- def scangitpatch(fp, firstline):
- '''git patches can modify a file, then copy that file to
- a new file, but expect the source to be the unmodified form.
- So we scan the patch looking for that case so we can do
- the copies ahead of time.'''
-
- pos = 0
- try:
- pos = fp.tell()
- except IOError:
- fp = cStringIO.StringIO(fp.read())
-
- (dopatch, gitpatches) = readgitpatch(fp, firstline)
- fp.seek(pos)
-
- return fp, dopatch, gitpatches
-
changed = {}
current_hunk = None
afile = ""
@@ -869,7 +879,7 @@
afile, bfile = m.group(1, 2)
if not git:
git = True
- fp, dopatch, gitpatches = scangitpatch(fp, x)
+ fp, dopatch, gitpatches = scangitpatch(lr, x)
yield 'git', gitpatches
for gp in gitpatches:
changed[gp.path] = gp