Commit 61e0b691 authored by maruel@chromium.org's avatar maruel@chromium.org

Add script to apply a patch from rietveld.

At the moment it just fetches the patch. It's still useful to debug rietveld
issues.

Improve resiliency to invalid patches.

R=dpranke@chromium.org
BUG=
TEST=

Review URL: http://codereview.chromium.org/6825085

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@81305 0039d316-1c4b-4281-b951-d872f2087c98
parent 4a982271
#!/usr/bin/env python
# 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.
"""Applies an issue from Rietveld.
"""
import logging
import optparse
import sys
import breakpad # pylint: disable=W0611
import fix_encoding
import rietveld
def main():
parser = optparse.OptionParser(description=sys.modules[__name__].__doc__)
parser.add_option(
'-v', '--verbose', action='count', help='Prints debugging infos')
parser.add_option(
'-i', '--issue', type='int', help='Rietveld issue number')
parser.add_option(
'-p', '--patchset', type='int', help='Rietveld issue\'s patchset number')
parser.add_option(
'-r',
'--root_dir',
action='store',
help='Root directory to apply the patch')
parser.add_option(
'-s',
'--server',
action='store',
default='http://codereview.chromium.org',
help='Rietveld server')
options, args = parser.parse_args()
LOG_FORMAT = '%(levelname)s %(filename)s(%(lineno)d): %(message)s'
if not options.verbose:
logging.basicConfig(level=logging.WARNING, format=LOG_FORMAT)
elif options.verbose == 1:
logging.basicConfig(level=logging.INFO, format=LOG_FORMAT)
elif options.verbose > 1:
logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT)
if args:
parser.error('Extra argument(s) "%s" not understood' % ' '.join(args))
if not options.issue:
parser.error('Require --issue')
obj = rietveld.Rietveld(options.server, None, None)
if not options.patchset:
options.patchset = obj.get_issue_properties(
options.issue, False)['patchsets'][-1]
logging.info('Using patchset %d' % options.patchset)
obj.get_patch(options.issue, options.patchset)
return 0
if __name__ == "__main__":
fix_encoding.fix_encoding()
sys.exit(main())
...@@ -89,6 +89,8 @@ class FilePatchDiff(FilePatchBase): ...@@ -89,6 +89,8 @@ class FilePatchDiff(FilePatchBase):
def __init__(self, filename, diff, svn_properties): def __init__(self, filename, diff, svn_properties):
super(FilePatchDiff, self).__init__(filename) super(FilePatchDiff, self).__init__(filename)
if not diff:
self._fail('File doesn\'t have a diff.')
self.diff_header, self.diff_hunks = self._split_header(diff) self.diff_header, self.diff_hunks = self._split_header(diff)
self.svn_properties = svn_properties or [] self.svn_properties = svn_properties or []
self.is_git_diff = self._is_git_diff_header(self.diff_header) self.is_git_diff = self._is_git_diff_header(self.diff_header)
......
...@@ -112,10 +112,11 @@ class Rietveld(object): ...@@ -112,10 +112,11 @@ class Rietveld(object):
props = self.get_patchset_properties(issue, patchset) or {} props = self.get_patchset_properties(issue, patchset) or {}
out = [] out = []
for filename, state in props.get('files', {}).iteritems(): for filename, state in props.get('files', {}).iteritems():
logging.debug('%s' % filename)
status = state.get('status') status = state.get('status')
if status is None: if status is None:
raise patch.UnsupportedPatchFormat( raise patch.UnsupportedPatchFormat(
filename, 'File\'s status is None, patchset upload is incomplete') filename, 'File\'s status is None, patchset upload is incomplete.')
# TODO(maruel): That's bad, it confuses property change. # TODO(maruel): That's bad, it confuses property change.
status = status.strip() status = status.strip()
...@@ -137,7 +138,8 @@ class Rietveld(object): ...@@ -137,7 +138,8 @@ class Rietveld(object):
if state['num_chunks']: if state['num_chunks']:
diff = self.get_file_diff(issue, patchset, state['id']) diff = self.get_file_diff(issue, patchset, state['id'])
else: else:
diff = None raise patch.UnsupportedPatchFormat(
filename, 'File doesn\'t have a diff.')
out.append(patch.FilePatchDiff(filename, diff, props)) out.append(patch.FilePatchDiff(filename, diff, props))
else: else:
# Line too long (N/80) # Line too long (N/80)
...@@ -188,6 +190,7 @@ class Rietveld(object): ...@@ -188,6 +190,7 @@ class Rietveld(object):
maxtries = 5 maxtries = 5
for retry in xrange(maxtries): for retry in xrange(maxtries):
try: try:
logging.debug('%s' % request_path)
result = self.rpc_server.Send(request_path, **kwargs) result = self.rpc_server.Send(request_path, **kwargs)
# Sometimes GAE returns a HTTP 200 but with HTTP 500 as the content. How # Sometimes GAE returns a HTTP 200 but with HTTP 500 as the content. How
# nice. # nice.
......
...@@ -192,6 +192,20 @@ class PatchTest(unittest.TestCase): ...@@ -192,6 +192,20 @@ class PatchTest(unittest.TestCase):
except patch.UnsupportedPatchFormat: except patch.UnsupportedPatchFormat:
pass pass
def testFilePatchNoDiff(self):
try:
patch.FilePatchDiff('foo', '', [])
self.fail()
except patch.UnsupportedPatchFormat:
pass
def testFilePatchNoneDiff(self):
try:
patch.FilePatchDiff('foo', None, [])
self.fail()
except patch.UnsupportedPatchFormat:
pass
def testFilePatchBadDiffName(self): def testFilePatchBadDiffName(self):
try: try:
patch.FilePatchDiff('foo', SVN_PATCH, []) patch.FilePatchDiff('foo', SVN_PATCH, [])
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment