Index: patch.py |
diff --git a/patch.py b/patch.py |
index 8b0407fab0aaec979a2d66b5a86d1b4484e1c820..4c96de3561339925048cd4398b3636191634b599 100644 |
--- a/patch.py |
+++ b/patch.py |
@@ -32,6 +32,7 @@ class FilePatchBase(object): |
is_new = False |
def __init__(self, filename): |
+ assert self.__class__ is not FilePatchBase |
self.filename = self._process_filename(filename) |
# Set when the file is copied or moved. |
self.source_filename = None |
@@ -50,9 +51,6 @@ class FilePatchBase(object): |
filename, 'Filename can\'t start with \'%s\'.' % i) |
return filename |
- def get(self): # pragma: no coverage |
- raise NotImplementedError('Nothing to grab') |
- |
def set_relpath(self, relpath): |
if not relpath: |
return |
@@ -69,6 +67,27 @@ class FilePatchBase(object): |
"""Shortcut function to raise UnsupportedPatchFormat.""" |
raise UnsupportedPatchFormat(self.filename, msg) |
+ def __str__(self): |
+ # Use a status-like board. |
+ out = '' |
+ if self.is_binary: |
+ out += 'B' |
+ else: |
+ out += ' ' |
+ if self.is_delete: |
+ out += 'D' |
+ else: |
+ out += ' ' |
+ if self.is_new: |
+ out += 'N' |
+ else: |
+ out += ' ' |
+ if self.source_filename: |
+ out += 'R' |
+ else: |
+ out += ' ' |
+ return out + ' %s->%s' % (self.source_filename, self.filename) |
+ |
class FilePatchDelete(FilePatchBase): |
"""Deletes a file.""" |
@@ -78,9 +97,6 @@ class FilePatchDelete(FilePatchBase): |
super(FilePatchDelete, self).__init__(filename) |
self.is_binary = is_binary |
- def get(self): |
- raise NotImplementedError('Nothing to grab') |
- |
class FilePatchBinary(FilePatchBase): |
"""Content of a new binary file.""" |
@@ -111,9 +127,18 @@ class FilePatchDiff(FilePatchBase): |
self._verify_git_header() |
else: |
self._verify_svn_header() |
+ if self.source_filename and not self.is_new: |
+ self._fail('If source_filename is set, is_new must be also be set') |
- def get(self): |
- return self.diff_header + self.diff_hunks |
+ def get(self, for_git): |
+ if for_git or not self.source_filename: |
+ return self.diff_header + self.diff_hunks |
+ else: |
+ # patch is stupid. It patches the source_filename instead so get rid of |
+ # any source_filename reference if needed. |
+ return ( |
+ self.diff_header.replace(self.source_filename, self.filename) + |
+ self.diff_hunks) |
def set_relpath(self, relpath): |
old_filename = self.filename |
@@ -264,6 +289,7 @@ class FilePatchDiff(FilePatchBase): |
(match.group(1), line)) |
return |
+ # Ignore "deleted file mode 100644" since it's not needed. |
match = re.match(r'^new(| file) mode (\d{6})$', line) |
if match: |
mode = match.group(2) |
@@ -356,10 +382,23 @@ class PatchSet(object): |
"""A list of FilePatch* objects.""" |
def __init__(self, patches): |
- self.patches = patches |
- for p in self.patches: |
+ for p in patches: |
assert isinstance(p, FilePatchBase) |
+ def key(p): |
+ """Sort by ordering of application. |
+ |
+ File move are first. |
+ Deletes are last. |
+ """ |
+ if p.source_filename: |
+ return (p.is_delete, p.source_filename, p.filename) |
+ else: |
+ # tuple are always greater than string, abuse that fact. |
+ return (p.is_delete, (p.filename,), p.filename) |
+ |
+ self.patches = sorted(patches, key=key) |
+ |
def set_relpath(self, relpath): |
"""Used to offset the patch into a subdirectory.""" |
for patch in self.patches: |
@@ -369,6 +408,9 @@ class PatchSet(object): |
for patch in self.patches: |
yield patch |
+ def __getitem__(self, key): |
+ return self.patches[key] |
+ |
@property |
def filenames(self): |
return [p.filename for p in self.patches] |