| Index: patch.py
 | 
| diff --git a/patch.py b/patch.py
 | 
| index 333cbb9f61815521ff83f1b14539f2a14a7b7a17..888e10095a7e25d68eb791f81f6141df5bceb941 100644
 | 
| --- a/patch.py
 | 
| +++ b/patch.py
 | 
| @@ -33,6 +33,8 @@ class FilePatchBase(object):
 | 
|  
 | 
|    def __init__(self, filename):
 | 
|      self.filename = self._process_filename(filename)
 | 
| +    # Set when the file is copied or moved.
 | 
| +    self.source_filename = None
 | 
|  
 | 
|    @staticmethod
 | 
|    def _process_filename(filename):
 | 
| @@ -59,6 +61,9 @@ class FilePatchBase(object):
 | 
|        self._fail('Relative path starts with %s' % relpath[0])
 | 
|      self.filename = self._process_filename(
 | 
|          posixpath.join(relpath, self.filename))
 | 
| +    if self.source_filename:
 | 
| +      self.source_filename = self._process_filename(
 | 
| +          posixpath.join(relpath, self.source_filename))
 | 
|  
 | 
|    def _fail(self, msg):
 | 
|      """Shortcut function to raise UnsupportedPatchFormat."""
 | 
| @@ -112,9 +117,21 @@ class FilePatchDiff(FilePatchBase):
 | 
|  
 | 
|    def set_relpath(self, relpath):
 | 
|      old_filename = self.filename
 | 
| +    old_source_filename = self.source_filename or self.filename
 | 
|      super(FilePatchDiff, self).set_relpath(relpath)
 | 
|      # Update the header too.
 | 
| -    self.diff_header = self.diff_header.replace(old_filename, self.filename)
 | 
| +    source_filename = self.source_filename or self.filename
 | 
| +    lines = self.diff_header.splitlines(True)
 | 
| +    for i, line in enumerate(lines):
 | 
| +      if line.startswith('diff --git'):
 | 
| +        lines[i] = line.replace(
 | 
| +            'a/' + old_source_filename, source_filename).replace(
 | 
| +                'b/' + old_filename, self.filename)
 | 
| +      elif re.match(r'^\w+ from .+$', line) or line.startswith('---'):
 | 
| +        lines[i] = line.replace(old_source_filename, source_filename)
 | 
| +      elif re.match(r'^\w+ to .+$', line) or line.startswith('+++'):
 | 
| +        lines[i] = line.replace(old_filename, self.filename)
 | 
| +    self.diff_header = ''.join(lines)
 | 
|  
 | 
|    def _split_header(self, diff):
 | 
|      """Splits a diff in two: the header and the hunks."""
 | 
| @@ -186,12 +203,11 @@ class FilePatchDiff(FilePatchBase):
 | 
|        match = re.match(r'^diff \-\-git (.*?) (.*)$', lines.pop(0))
 | 
|        if not match:
 | 
|          continue
 | 
| -      old = match.group(1).replace('\\', '/')
 | 
| -      new = match.group(2).replace('\\', '/')
 | 
| -      if old.startswith('a/') and new.startswith('b/'):
 | 
| +      if match.group(1).startswith('a/') and match.group(2).startswith('b/'):
 | 
|          self.patchlevel = 1
 | 
| -        old = old[2:]
 | 
| -        new = new[2:]
 | 
| +      old = self.mangle(match.group(1))
 | 
| +      new = self.mangle(match.group(2))
 | 
| +
 | 
|        # The rename is about the new file so the old file can be anything.
 | 
|        if new not in (self.filename, 'dev/null'):
 | 
|          self._fail('Unexpected git diff output name %s.' % new)
 | 
| @@ -202,13 +218,15 @@ class FilePatchDiff(FilePatchBase):
 | 
|      if not old or not new:
 | 
|        self._fail('Unexpected git diff; couldn\'t find git header.')
 | 
|  
 | 
| +    if old not in (self.filename, 'dev/null'):
 | 
| +      # Copy or rename.
 | 
| +      self.source_filename = old
 | 
| +
 | 
|      last_line = ''
 | 
|  
 | 
|      while lines:
 | 
|        line = lines.pop(0)
 | 
| -      # TODO(maruel): old should be replace with self.source_file
 | 
| -      # TODO(maruel): new == self.filename and remove new
 | 
| -      self._verify_git_header_process_line(lines, line, last_line, old, new)
 | 
| +      self._verify_git_header_process_line(lines, line, last_line)
 | 
|        last_line = line
 | 
|  
 | 
|      # Cheap check to make sure the file name is at least mentioned in the
 | 
| @@ -216,7 +234,7 @@ class FilePatchDiff(FilePatchBase):
 | 
|      if not self.filename in self.diff_header:
 | 
|        self._fail('Diff seems corrupted.')
 | 
|  
 | 
| -  def _verify_git_header_process_line(self, lines, line, last_line, old, new):
 | 
| +  def _verify_git_header_process_line(self, lines, line, last_line):
 | 
|      """Processes a single line of the header.
 | 
|  
 | 
|      Returns True if it should continue looping.
 | 
| @@ -225,6 +243,7 @@ class FilePatchDiff(FilePatchBase):
 | 
|      http://www.kernel.org/pub/software/scm/git/docs/git-diff.html
 | 
|      """
 | 
|      match = re.match(r'^(rename|copy) from (.+)$', line)
 | 
| +    old = self.source_filename or self.filename
 | 
|      if match:
 | 
|        if old != match.group(2):
 | 
|          self._fail('Unexpected git diff input name for line %s.' % line)
 | 
| @@ -236,7 +255,7 @@ class FilePatchDiff(FilePatchBase):
 | 
|  
 | 
|      match = re.match(r'^(rename|copy) to (.+)$', line)
 | 
|      if match:
 | 
| -      if new != match.group(2):
 | 
| +      if self.filename != match.group(2):
 | 
|          self._fail('Unexpected git diff output name for line %s.' % line)
 | 
|        if not last_line.startswith('%s from ' % match.group(1)):
 | 
|          self._fail(
 | 
| @@ -258,7 +277,7 @@ class FilePatchDiff(FilePatchBase):
 | 
|          self._fail('--- and +++ are reversed')
 | 
|        self.is_new = match.group(1) == '/dev/null'
 | 
|        # TODO(maruel): Use self.source_file.
 | 
| -      if old != self.mangle(match.group(1)) and match.group(1) != '/dev/null':
 | 
| +      if self.mangle(match.group(1)) not in (old, 'dev/null'):
 | 
|          self._fail('Unexpected git diff: %s != %s.' % (old, match.group(1)))
 | 
|        if not lines or not lines[0].startswith('+++'):
 | 
|          self._fail('Missing git diff output name.')
 | 
| @@ -271,8 +290,9 @@ class FilePatchDiff(FilePatchBase):
 | 
|        # TODO(maruel): new == self.filename.
 | 
|        if '/dev/null' == match.group(1):
 | 
|          self.is_delete = True
 | 
| -      elif new != self.mangle(match.group(1)):
 | 
| -        self._fail('Unexpected git diff: %s != %s.' % (new, match.group(1)))
 | 
| +      elif self.filename != self.mangle(match.group(1)):
 | 
| +        self._fail(
 | 
| +            'Unexpected git diff: %s != %s.' % (self.filename, match.group(1)))
 | 
|        if lines:
 | 
|          self._fail('Crap after +++')
 | 
|        # We're done.
 | 
| @@ -308,13 +328,9 @@ class FilePatchDiff(FilePatchBase):
 | 
|        if last_line[:3] in ('---', '+++'):
 | 
|          self._fail('--- and +++ are reversed')
 | 
|        self.is_new = match.group(1) == '/dev/null'
 | 
| -      # For copy and renames, it's possible that the -- line doesn't match
 | 
| -      # +++, so don't check match.group(1) to match self.filename or
 | 
| -      # '/dev/null', it can be anything else.
 | 
| -      # TODO(maruel): Handle rename/copy explicitly.
 | 
| -      # if (self.mangle(match.group(1)) != self.filename and
 | 
| -      #     match.group(1) != '/dev/null'):
 | 
| -      #  self.source_file = match.group(1)
 | 
| +      if (self.mangle(match.group(1)) != self.filename and
 | 
| +           match.group(1) != '/dev/null'):
 | 
| +        self.source_filename = match.group(1)
 | 
|        if not lines or not lines[0].startswith('+++'):
 | 
|          self._fail('Nothing after header.')
 | 
|        return
 | 
| 
 |