Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(658)

Unified Diff: patch.py

Issue 6792028: Move patch.py and rietveld.py from commit-queue. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: fixed remaining issues Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « .gitignore ('k') | pylintrc » ('j') | tests/local_rietveld.py » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: patch.py
diff --git a/patch.py b/patch.py
new file mode 100644
index 0000000000000000000000000000000000000000..b22e32e55efbd5318d2fd3d922c5cd9e5048519e
--- /dev/null
+++ b/patch.py
@@ -0,0 +1,184 @@
+# coding=utf8
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Utility functions to handle patches."""
+
+import re
+
+
+class UnsupportedPatchFormat(Exception):
+ def __init__(self, filename, status):
+ super(UnsupportedPatchFormat, self).__init__(filename, status)
+ self.filename = filename
+ self.status = status
+
+ def __str__(self):
+ out = 'Can\'t process patch for file %s.' % self.filename
+ if self.status:
+ out += '\n%s' % self.status
+ return out
+
+
+class FilePatchBase(object):
+ """Defines a single file being modified."""
+ is_delete = False
+ is_binary = False
+
+ def get(self):
+ raise NotImplementedError('Nothing to grab')
+
+
+class FilePatchDelete(FilePatchBase):
+ """Deletes a file."""
+ is_delete = True
+
+ def __init__(self, filename, is_binary):
+ super(FilePatchDelete, self).__init__()
+ self.filename = filename
+ self.is_binary = is_binary
+
+ def get(self):
+ raise NotImplementedError('Nothing to grab')
+
+
+class FilePatchBinary(FilePatchBase):
+ """Content of a new binary file."""
+ is_binary = True
+
+ def __init__(self, filename, data, svn_properties):
+ super(FilePatchBinary, self).__init__()
+ self.filename = filename
+ self.data = data
+ self.svn_properties = svn_properties or []
+
+ def get(self):
+ return self.data
+
+
+class FilePatchDiff(FilePatchBase):
+ """Patch for a single file."""
+
+ def __init__(self, filename, diff, svn_properties):
+ super(FilePatchDiff, self).__init__()
+ self.filename = filename
+ self.diff = diff
+ self.svn_properties = svn_properties or []
+ self.is_git_diff = self._is_git_diff(diff)
+ if self.is_git_diff:
+ self.patchlevel = 1
+ self._verify_git_patch(filename, diff)
+ assert not svn_properties
+ else:
+ self.patchlevel = 0
+ self._verify_svn_patch(filename, diff)
+
+ def get(self):
+ return self.diff
+
+ @staticmethod
+ def _is_git_diff(diff):
+ """Returns True if the diff for a single files was generated with gt.
+
+ Expects the following format:
+
+ Index: <filename>
+ diff --git a/<filename> b/<filename>
+ <filemode changes>
+ <index>
+ --- <filename>
+ +++ <filename>
+ <hunks>
+
+ Index: is a rietveld specific line.
+ """
+ # Delete: http://codereview.chromium.org/download/issue6368055_22_29.diff
+ # Rename partial change:
+ # http://codereview.chromium.org/download/issue6250123_3013_6010.diff
+ # Rename no change:
+ # http://codereview.chromium.org/download/issue6287022_3001_4010.diff
+ return any(l.startswith('diff --git') for l in diff.splitlines()[:3])
+
+ @staticmethod
+ def _verify_git_patch(filename, diff):
+ lines = diff.splitlines()
+ # First fine the git diff header:
+ while lines:
+ line = lines.pop(0)
+ match = re.match(r'^diff \-\-git a\/(.*?) b\/(.*)$', line)
+ if match:
+ a = match.group(1)
+ b = match.group(2)
+ if a != filename and a != 'dev/null':
+ raise UnsupportedPatchFormat(
+ filename, 'Unexpected git diff input name.')
+ if b != filename and b != 'dev/null':
+ raise UnsupportedPatchFormat(
+ filename, 'Unexpected git diff output name.')
+ if a == 'dev/null' and b == 'dev/null':
+ raise UnsupportedPatchFormat(
+ filename, 'Unexpected /dev/null git diff.')
+ break
+ else:
+ raise UnsupportedPatchFormat(
+ filename, 'Unexpected git diff; couldn\'t find git header.')
+
+ while lines:
+ line = lines.pop(0)
+ match = re.match(r'^--- a/(.*)$', line)
+ if match:
+ if a != match.group(1):
+ raise UnsupportedPatchFormat(
+ filename, 'Unexpected git diff: %s != %s.' % (a, match.group(1)))
+ match = re.match(r'^\+\+\+ b/(.*)$', lines.pop(0))
+ if not match:
+ raise UnsupportedPatchFormat(
+ filename, 'Unexpected git diff: --- not following +++.')
+ if b != match.group(1):
+ raise UnsupportedPatchFormat(
+ filename, 'Unexpected git diff: %s != %s.' % (b, match.group(1)))
+ break
+ # Don't fail if the patch header is not found, the diff could be a
+ # file-mode-change-only diff.
+
+ @staticmethod
+ def _verify_svn_patch(filename, diff):
+ lines = diff.splitlines()
+ while lines:
+ line = lines.pop(0)
+ match = re.match(r'^--- ([^\t]+).*$', line)
+ if match:
+ if match.group(1) not in (filename, '/dev/null'):
+ raise UnsupportedPatchFormat(
+ filename,
+ 'Unexpected diff: %s != %s.' % (filename, match.group(1)))
+ # Grab next line.
+ line2 = lines.pop(0)
+ match = re.match(r'^\+\+\+ ([^\t]+).*$', line2)
+ if not match:
+ raise UnsupportedPatchFormat(
+ filename,
+ 'Unexpected diff: --- not following +++.:\n%s\n%s' % (
+ line, line2))
+ if match.group(1) not in (filename, '/dev/null'):
+ raise UnsupportedPatchFormat(
+ filename,
+ 'Unexpected diff: %s != %s.' % (filename, match.group(1)))
+ break
+ # Don't fail if the patch header is not found, the diff could be a
+ # svn-property-change-only diff.
+
+
+class PatchSet(object):
+ """A list of FilePatch* objects."""
+
+ def __init__(self, patches):
+ self.patches = patches
+
+ def __iter__(self):
+ for patch in self.patches:
+ yield patch
+
+ @property
+ def filenames(self):
+ return [p.filename for p in self.patches]
« no previous file with comments | « .gitignore ('k') | pylintrc » ('j') | tests/local_rietveld.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698