Add AffectedFile.IsTextFile() and deprecate AffectedTextFiles().

Make DepotToLocalPath() and LocalToDepotPath() not static. It is necessary for a subsequent change since I need to factor out it's SCM assumption.

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@17091 0039d316-1c4b-4281-b951-d872f2087c98
experimental/szager/collated-output
maruel@chromium.org 16 years ago
parent 6ebe68a73d
commit 1e08c00d60

@ -27,6 +27,7 @@ import sys # Parts exposed through API.
import tempfile # Exposed through the API. import tempfile # Exposed through the API.
import types import types
import urllib2 # Exposed through the API. import urllib2 # Exposed through the API.
import warnings
# Local imports. # Local imports.
# TODO(joi) Would be cleaner to factor out utils in gcl to separate module, but # TODO(joi) Would be cleaner to factor out utils in gcl to separate module, but
@ -54,6 +55,21 @@ def normpath(path):
return os.path.normpath(path) return os.path.normpath(path)
def deprecated(func):
"""This is a decorator which can be used to mark functions as deprecated.
It will result in a warning being emmitted when the function is used."""
def newFunc(*args, **kwargs):
warnings.warn("Call to deprecated function %s." % func.__name__,
category=DeprecationWarning,
stacklevel=2)
return func(*args, **kwargs)
newFunc.__name__ = func.__name__
newFunc.__doc__ = func.__doc__
newFunc.__dict__.update(func.__dict__)
return newFunc
class OutputApi(object): class OutputApi(object):
"""This class (more like a module) gets passed to presubmit scripts so that """This class (more like a module) gets passed to presubmit scripts so that
they can specify various types of results. they can specify various types of results.
@ -177,8 +193,7 @@ class InputApi(object):
""" """
return self._current_presubmit_path return self._current_presubmit_path
@staticmethod def DepotToLocalPath(self, depot_path):
def DepotToLocalPath(depot_path):
"""Translate a depot path to a local path (relative to client root). """Translate a depot path to a local path (relative to client root).
Args: Args:
@ -191,13 +206,10 @@ class InputApi(object):
Remember to check for the None case and show an appropriate error! Remember to check for the None case and show an appropriate error!
""" """
local_path = gclient.CaptureSVNInfo(depot_path).get('Path') local_path = gclient.CaptureSVNInfo(depot_path).get('Path')
if not local_path: if local_path:
return None
else:
return local_path return local_path
@staticmethod def LocalToDepotPath(self, local_path):
def LocalToDepotPath(local_path):
"""Translate a local path to a depot path. """Translate a local path to a depot path.
Args: Args:
@ -207,9 +219,7 @@ class InputApi(object):
The depot path (SVN URL) of the file if mapped, otherwise None. The depot path (SVN URL) of the file if mapped, otherwise None.
""" """
depot_path = gclient.CaptureSVNInfo(local_path).get('URL') depot_path = gclient.CaptureSVNInfo(local_path).get('URL')
if not depot_path: if depot_path:
return None
else:
return depot_path return depot_path
@staticmethod @staticmethod
@ -260,6 +270,7 @@ class InputApi(object):
"""Returns server paths of input_api.AffectedFiles().""" """Returns server paths of input_api.AffectedFiles()."""
return [af.ServerPath() for af in self.AffectedFiles(include_dirs)] return [af.ServerPath() for af in self.AffectedFiles(include_dirs)]
@deprecated
def AffectedTextFiles(self, include_deletes=True): def AffectedTextFiles(self, include_deletes=True):
"""Same as input_api.change.AffectedTextFiles() except only lists files """Same as input_api.change.AffectedTextFiles() except only lists files
in the same directory as the current presubmit script, or subdirectories in the same directory as the current presubmit script, or subdirectories
@ -287,7 +298,8 @@ class InputApi(object):
the contents of the line as a string. the contents of the line as a string.
""" """
return InputApi._RightHandSideLinesImpl( return InputApi._RightHandSideLinesImpl(
self.AffectedTextFiles(include_deletes=False)) filter(lambda x: x.IsTextFile(),
self.AffectedFiles(include_deletes=False)))
@staticmethod @staticmethod
def _RightHandSideLinesImpl(affected_files): def _RightHandSideLinesImpl(affected_files):
@ -348,6 +360,10 @@ class AffectedFile(object):
""" """
return self.properties.get(property_name, None) return self.properties.get(property_name, None)
def IsTextFile(self):
"""Returns True if the file is a text file and not a binary file."""
raise NotImplementedError() # Implement when needed
def NewContents(self): def NewContents(self):
"""Returns an iterator over the lines in the new version of file. """Returns an iterator over the lines in the new version of file.
@ -405,6 +421,15 @@ class SvnAffectedFile(AffectedFile):
self.AbsoluteLocalPath(), property_name) self.AbsoluteLocalPath(), property_name)
return self.properties[property_name] return self.properties[property_name]
def IsTextFile(self):
if self.Action() == 'D':
return False
mime_type = gcl.GetSVNFileProperty(self.AbsoluteLocalPath(),
'svn:mime-type')
if not mime_type or mime_type.startswith('text/'):
return True
return False
class GclChange(object): class GclChange(object):
"""Describe a change. """Describe a change.
@ -496,6 +521,7 @@ class GclChange(object):
else: else:
return filter(lambda x: x.Action() != 'D', affected) return filter(lambda x: x.Action() != 'D', affected)
@deprecated
def AffectedTextFiles(self, include_deletes=True): def AffectedTextFiles(self, include_deletes=True):
"""Return a list of the text files in a change. """Return a list of the text files in a change.
@ -535,7 +561,8 @@ class GclChange(object):
the contents of the line as a string. the contents of the line as a string.
""" """
return InputApi._RightHandSideLinesImpl( return InputApi._RightHandSideLinesImpl(
self.AffectedTextFiles(include_deletes=False)) filter(lambda x: x.IsTextFile(),
self.AffectedFiles(include_deletes=False)))
def ListRelevantPresubmitFiles(files): def ListRelevantPresubmitFiles(files):
@ -574,6 +601,7 @@ class PresubmitExecuter(object):
change_info: The ChangeInfo object for the change. change_info: The ChangeInfo object for the change.
committing: True if 'gcl commit' is running, False if 'gcl upload' is. committing: True if 'gcl commit' is running, False if 'gcl upload' is.
""" """
# TODO(maruel): Determine the SCM.
self.change = GclChange(change_info, gcl.GetRepositoryRoot()) self.change = GclChange(change_info, gcl.GetRepositoryRoot())
self.committing = committing self.committing = committing

@ -9,6 +9,7 @@ import os
import StringIO import StringIO
import sys import sys
import unittest import unittest
import warnings
# Local imports # Local imports
import gcl import gcl
@ -20,6 +21,8 @@ import presubmit_canned_checks
class PresubmitTestsBase(unittest.TestCase): class PresubmitTestsBase(unittest.TestCase):
"""Setups and tear downs the mocks but doesn't test anything as-is.""" """Setups and tear downs the mocks but doesn't test anything as-is."""
def setUp(self): def setUp(self):
self._warnings_stack = warnings.catch_warnings()
warnings.simplefilter("ignore", DeprecationWarning)
self.original_IsFile = os.path.isfile self.original_IsFile = os.path.isfile
def MockIsFile(f): def MockIsFile(f):
dir = os.path.dirname(f) dir = os.path.dirname(f)
@ -92,6 +95,7 @@ def CheckChangeOnUpload(input_api, output_api):
gcl.ReadFile = self.original_ReadFile gcl.ReadFile = self.original_ReadFile
gcl.GetRepositoryRoot = self.original_GetRepositoryRoot gcl.GetRepositoryRoot = self.original_GetRepositoryRoot
sys.stdout = self._sys_stdout sys.stdout = self._sys_stdout
self._warnings_stack = None
@staticmethod @staticmethod
def MakeBasicChange(name, description): def MakeBasicChange(name, description):
@ -117,10 +121,11 @@ class PresubmitUnittest(PresubmitTestsBase):
'AffectedFile', 'DoPresubmitChecks', 'GclChange', 'InputApi', 'AffectedFile', 'DoPresubmitChecks', 'GclChange', 'InputApi',
'ListRelevantPresubmitFiles', 'Main', 'NotImplementedException', 'ListRelevantPresubmitFiles', 'Main', 'NotImplementedException',
'OutputApi', 'ParseFiles', 'PresubmitExecuter', 'OutputApi', 'ParseFiles', 'PresubmitExecuter',
'ScanSubDirs', 'SvnAffectedFile', 'cPickle', 'cStringIO', 'exceptions', 'ScanSubDirs', 'SvnAffectedFile',
'cPickle', 'cStringIO', 'deprecated', 'exceptions',
'fnmatch', 'gcl', 'gclient', 'glob', 'marshal', 'normpath', 'optparse', 'fnmatch', 'gcl', 'gclient', 'glob', 'marshal', 'normpath', 'optparse',
'os', 'pickle', 'presubmit_canned_checks', 're', 'subprocess', 'sys', 'os', 'pickle', 'presubmit_canned_checks', 're', 'subprocess', 'sys',
'tempfile', 'types', 'urllib2', 'tempfile', 'types', 'urllib2', 'warnings',
] ]
# If this test fails, you should add the relevant test. # If this test fails, you should add the relevant test.
self.compareMembers(presubmit, members) self.compareMembers(presubmit, members)
@ -449,15 +454,16 @@ class InputApiUnittest(PresubmitTestsBase):
self.compareMembers(presubmit.InputApi(None, './.'), members) self.compareMembers(presubmit.InputApi(None, './.'), members)
def testDepotToLocalPath(self): def testDepotToLocalPath(self):
path = presubmit.InputApi.DepotToLocalPath('svn:/foo/smurf') path = presubmit.InputApi(None, './p').DepotToLocalPath('svn:/foo/smurf')
self.failUnless(path == 'smurf') self.failUnless(path == 'smurf')
path = presubmit.InputApi.DepotToLocalPath('svn:/foo/notfound/burp') path = presubmit.InputApi(None, './p').DepotToLocalPath(
'svn:/foo/notfound/burp')
self.failUnless(path == None) self.failUnless(path == None)
def testLocalToDepotPath(self): def testLocalToDepotPath(self):
path = presubmit.InputApi.LocalToDepotPath('smurf') path = presubmit.InputApi(None, './p').LocalToDepotPath('smurf')
self.failUnless(path == 'svn:/foo/smurf') self.failUnless(path == 'svn:/foo/smurf')
path = presubmit.InputApi.LocalToDepotPath('notfound-food') path = presubmit.InputApi(None, './p').LocalToDepotPath('notfound-food')
self.failUnless(path == None) self.failUnless(path == None)
def testInputApiConstruction(self): def testInputApiConstruction(self):
@ -524,7 +530,7 @@ class InputApiUnittest(PresubmitTestsBase):
for line in api.RightHandSideLines(): for line in api.RightHandSideLines():
rhs_lines.append(line) rhs_lines.append(line)
self.failUnless(len(rhs_lines) == 2) self.failUnless(len(rhs_lines) == 2)
self.failUnless(rhs_lines[0][0].LocalPath() == self.assertEqual(rhs_lines[0][0].LocalPath(),
presubmit.normpath('foo/blat.cc')) presubmit.normpath('foo/blat.cc'))
def testGetAbsoluteLocalPath(self): def testGetAbsoluteLocalPath(self):
@ -623,7 +629,8 @@ class OuputApiUnittest(PresubmitTestsBase):
class AffectedFileUnittest(PresubmitTestsBase): class AffectedFileUnittest(PresubmitTestsBase):
def testMembersChanged(self): def testMembersChanged(self):
members = [ members = [
'AbsoluteLocalPath', 'Action', 'IsDirectory', 'LocalPath', 'NewContents', 'AbsoluteLocalPath', 'Action', 'IsDirectory', 'IsTextFile',
'LocalPath', 'NewContents',
'OldContents', 'OldFileTempPath', 'Property', 'ServerPath', 'action', 'OldContents', 'OldFileTempPath', 'Property', 'ServerPath', 'action',
'is_directory', 'path', 'properties', 'repository_root', 'server_path', 'is_directory', 'path', 'properties', 'repository_root', 'server_path',
] ]

Loading…
Cancel
Save