Add InputApi.ReadFile() and presubmit_canned_checks.CheckChangeHasNoCR().

ReadFile limits to reading files inside the repository.
CheckChangeHasNoCR reads the text files looking for \r and fails if found.

TEST=none
BUG=none

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@17857 0039d316-1c4b-4281-b951-d872f2087c98
experimental/szager/collated-output
maruel@chromium.org 16 years ago
parent f32e8a8337
commit 44a17adf95

@ -68,6 +68,18 @@ def CheckDoNotSubmit(input_api, output_api):
) )
def CheckChangeHasNoCR(input_api, output_api):
"""Checks that there are no \r, \r\n (CR or CRLF) characters in any of the
text files to be submitted.
"""
outputs = []
for f in input_api.AffectedTextFiles():
if '\r' in input_api.ReadFile(f, 'rb'):
outputs.append(output_api.PresubmitPromptWarning(
"Found a CR character in %s" % f.LocalPath()))
return outputs
def CheckChangeHasNoTabs(input_api, output_api): def CheckChangeHasNoTabs(input_api, output_api):
"""Checks that there are no tab characters in any of the text files to be """Checks that there are no tab characters in any of the text files to be
submitted. submitted.

@ -6,7 +6,7 @@
"""Enables directory-specific presubmit checks to run at upload and/or commit. """Enables directory-specific presubmit checks to run at upload and/or commit.
""" """
__version__ = '1.3' __version__ = '1.3.1'
# TODO(joi) Add caching where appropriate/needed. The API is designed to allow # TODO(joi) Add caching where appropriate/needed. The API is designed to allow
# caching (between all different invocations of presubmit scripts for a given # caching (between all different invocations of presubmit scripts for a given
@ -271,6 +271,17 @@ class InputApi(object):
filter(lambda x: x.IsTextFile(), filter(lambda x: x.IsTextFile(),
self.AffectedFiles(include_deletes=False))) self.AffectedFiles(include_deletes=False)))
def ReadFile(self, file, mode='r'):
"""Reads an arbitrary file.
Deny reading anything outside the repository.
"""
if isinstance(file, AffectedFile):
file = file.AbsoluteLocalPath()
if not file.startswith(self.change.RepositoryRoot()):
raise IOError('Access outside the repository root is denied.')
return gcl.ReadFile(file, mode)
@staticmethod @staticmethod
def _RightHandSideLinesImpl(affected_files): def _RightHandSideLinesImpl(affected_files):
"""Implements RightHandSideLines for InputApi and GclChange.""" """Implements RightHandSideLines for InputApi and GclChange."""

@ -94,6 +94,12 @@ def CheckChangeOnUpload(input_api, output_api):
if not x.startswith('_')] if not x.startswith('_')]
self.assertEqual(actual_members, sorted(members)) self.assertEqual(actual_members, sorted(members))
def MakeBasicChange(self, name, description, root=None):
ci = presubmit.gcl.ChangeInfo(name, 0, 0, description, None)
if root is None:
root = self.fake_root_dir
return presubmit.GclChange(ci, root)
class PresubmitUnittest(PresubmitTestsBase): class PresubmitUnittest(PresubmitTestsBase):
"""General presubmit_support.py tests (excluding InputApi and OutputApi).""" """General presubmit_support.py tests (excluding InputApi and OutputApi)."""
@ -519,7 +525,7 @@ class InputApiUnittest(PresubmitTestsBase):
members = [ members = [
'AbsoluteLocalPaths', 'AffectedFiles', 'AffectedTextFiles', 'AbsoluteLocalPaths', 'AffectedFiles', 'AffectedTextFiles',
'DepotToLocalPath', 'LocalPaths', 'LocalToDepotPath', 'DepotToLocalPath', 'LocalPaths', 'LocalToDepotPath',
'PresubmitLocalPath', 'RightHandSideLines', 'ServerPaths', 'PresubmitLocalPath', 'RightHandSideLines', 'ReadFile', 'ServerPaths',
'basename', 'cPickle', 'cStringIO', 'canned_checks', 'change', 'basename', 'cPickle', 'cStringIO', 'canned_checks', 'change',
'is_committing', 'marshal', 'os_path', 'pickle', 'platform', 'is_committing', 'marshal', 'os_path', 'pickle', 'platform',
're', 'subprocess', 'tempfile', 'traceback', 'unittest', 'urllib2', 're', 'subprocess', 'tempfile', 'traceback', 'unittest', 'urllib2',
@ -672,6 +678,34 @@ class InputApiUnittest(PresubmitTestsBase):
api = presubmit.InputApi(change, 'foo/PRESUBMIT.py', True) api = presubmit.InputApi(change, 'foo/PRESUBMIT.py', True)
api.AffectedTextFiles(include_deletes=False) api.AffectedTextFiles(include_deletes=False)
def testReadFileStringDenied(self):
self.mox.ReplayAll()
input_api = presubmit.InputApi(None, './p', False)
input_api.change = self.MakeBasicChange('foo', 'Foo\n', '/AA')
self.assertRaises(IOError, input_api.ReadFile, 'boo', 'x')
def testReadFileStringAccepted(self):
presubmit.gcl.ReadFile('/AA/boo', 'x').AndReturn(None)
self.mox.ReplayAll()
input_api = presubmit.InputApi(None, './p', False)
input_api.change = self.MakeBasicChange('foo', 'Foo\n', '/AA')
input_api.ReadFile('/AA/boo', 'x')
def testReadFileAffectedFileDenied(self):
file = presubmit.AffectedFile('boo', 'M')
self.mox.ReplayAll()
input_api = presubmit.InputApi(None, './p', False)
input_api.change = self.MakeBasicChange('foo', 'Foo\n', '/AA')
self.assertRaises(IOError, input_api.ReadFile, 'boo', 'x')
def testReadFileAffectedFileAccepted(self):
file = presubmit.AffectedFile('/AA/boo', 'M')
presubmit.gcl.ReadFile('/AA/boo', 'x').AndReturn(None)
self.mox.ReplayAll()
input_api = presubmit.InputApi(None, './p', False)
input_api.change = self.MakeBasicChange('foo', 'Foo\n', '/AA')
input_api.ReadFile('/AA/boo', 'x')
class OuputApiUnittest(PresubmitTestsBase): class OuputApiUnittest(PresubmitTestsBase):
"""Tests presubmit.OutputApi.""" """Tests presubmit.OutputApi."""
@ -836,14 +870,10 @@ class CannedChecksUnittest(PresubmitTestsBase):
input_api.unittest = unittest input_api.unittest = unittest
return input_api return input_api
def MakeBasicChange(self, name, description):
ci = presubmit.gcl.ChangeInfo(name, 0, 0, description, None)
return presubmit.GclChange(ci, self.fake_root_dir)
def testMembersChanged(self): def testMembersChanged(self):
self.mox.ReplayAll() self.mox.ReplayAll()
members = [ members = [
'CheckChangeHasBugField', 'CheckChangeHasNoTabs', 'CheckChangeHasBugField', 'CheckChangeHasNoCR', 'CheckChangeHasNoTabs',
'CheckChangeHasQaField', 'CheckChangeHasTestedField', 'CheckChangeHasQaField', 'CheckChangeHasTestedField',
'CheckChangeHasTestField', 'CheckDoNotSubmit', 'CheckChangeHasTestField', 'CheckDoNotSubmit',
'CheckDoNotSubmitInDescription', 'CheckDoNotSubmitInFiles', 'CheckDoNotSubmitInDescription', 'CheckDoNotSubmitInFiles',
@ -922,6 +952,31 @@ class CannedChecksUnittest(PresubmitTestsBase):
'DO NOTSUBMIT', 'DO NOT ' + 'SUBMIT', 'DO NOTSUBMIT', 'DO NOT ' + 'SUBMIT',
presubmit.OutputApi.PresubmitError) presubmit.OutputApi.PresubmitError)
def testCheckChangeHasNoCR(self):
input_api1 = self.MockInputApi()
self.mox.StubOutWithMock(input_api1, 'ReadFile')
input_api1.change = self.MakeBasicChange('foo', 'Foo\n')
affected_file1 = self.mox.CreateMock(presubmit.SvnAffectedFile)
input_api1.AffectedTextFiles().AndReturn([affected_file1])
input_api1.ReadFile(affected_file1, 'rb').AndReturn("Hey!\nHo!\n")
input_api2 = self.MockInputApi()
self.mox.StubOutWithMock(input_api2, 'ReadFile')
input_api2.change = self.MakeBasicChange('foo', 'Foo\n')
affected_file2 = self.mox.CreateMock(presubmit.SvnAffectedFile)
input_api2.AffectedTextFiles().AndReturn([affected_file2])
input_api2.ReadFile(affected_file2, 'rb').AndReturn("Hey!\r\nHo!\r\n")
affected_file2.LocalPath().AndReturn('bar.cc')
self.mox.ReplayAll()
results = presubmit_canned_checks.CheckChangeHasNoCR(
input_api1, presubmit.OutputApi)
self.assertEquals(results, [])
results2 = presubmit_canned_checks.CheckChangeHasNoCR(
input_api2, presubmit.OutputApi)
self.assertEquals(len(results2), 1)
self.assertEquals(results2[0].__class__,
presubmit.OutputApi.PresubmitPromptWarning)
def testCannedCheckChangeHasNoTabs(self): def testCannedCheckChangeHasNoTabs(self):
self.TestContent(presubmit_canned_checks.CheckChangeHasNoTabs, self.TestContent(presubmit_canned_checks.CheckChangeHasNoTabs,
'blah blah', 'blah\tblah', 'blah blah', 'blah\tblah',

Loading…
Cancel
Save