diff --git a/git_cl.py b/git_cl.py index 3c8e4acff..d4d190d8d 100755 --- a/git_cl.py +++ b/git_cl.py @@ -55,6 +55,7 @@ import subprocess2 import swift_format import watchlists +from lib import utils from third_party import six from six.moves import urllib @@ -6131,7 +6132,6 @@ def CMDlol(parser, args): def CMDversion(parser, args): - import utils print(utils.depot_tools_version()) diff --git a/lib/__init__.py b/lib/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/lib/utils.py b/lib/utils.py new file mode 100644 index 000000000..b7ee4cd07 --- /dev/null +++ b/lib/utils.py @@ -0,0 +1,95 @@ +# Copyright 2022 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. + +""" A collection of commonly used functions across depot_tools. +""" + +import logging +import os +import re +import subprocess + + +def depot_tools_version(): + depot_tools_root = os.path.dirname(os.path.abspath(__file__)) + try: + commit_hash = subprocess.check_output(['git', 'rev-parse', 'HEAD'], + cwd=depot_tools_root).decode( + 'utf-8', 'ignore') + return 'git-%s' % commit_hash + except Exception: + pass + + # git check failed, let's check last modification of frequently checked file + try: + mtime = os.path.getmtime( + os.path.join(depot_tools_root, 'infra', 'config', 'recipes.cfg')) + return 'recipes.cfg-%d' % (mtime) + except Exception: + return 'unknown' + + +def normpath(path): + '''Version of os.path.normpath that also changes backward slashes to + forward slashes when not running on Windows. + ''' + # This is safe to always do because the Windows version of os.path.normpath + # will replace forward slashes with backward slashes. + path = path.replace(os.sep, '/') + return os.path.normpath(path) + + +def ListRelevantFilesInSourceCheckout(files, root, match_re, exclude_re): + """Finds all files that apply to a given set of source files, e.g. PRESUBMIT. + + If inherit-review-settings-ok is present right under root, looks for matches + in directories enclosing root. + + Args: + files: An iterable container containing file paths. + root: Path where to stop searching. + match_re: regex to match filename + exclude_re: regex to exclude filename + + Return: + List of absolute paths of the existing PRESUBMIT.py scripts. + """ + files = [normpath(os.path.join(root, f)) for f in files] + + # List all the individual directories containing files. + directories = {os.path.dirname(f) for f in files} + + # Ignore root if inherit-review-settings-ok is present. + if os.path.isfile(os.path.join(root, 'inherit-review-settings-ok')): + root = None + + # Collect all unique directories that may contain PRESUBMIT.py. + candidates = set() + for directory in directories: + while True: + if directory in candidates: + break + candidates.add(directory) + if directory == root: + break + parent_dir = os.path.dirname(directory) + if parent_dir == directory: + # We hit the system root directory. + break + directory = parent_dir + + # Look for PRESUBMIT.py in all candidate directories. + results = [] + for directory in sorted(list(candidates)): + try: + for f in os.listdir(directory): + p = os.path.join(directory, f) + if os.path.isfile(p) and re.match(match_re, + f) and not re.match(exclude_re, f): + results.append(p) + except OSError: + pass + + logging.debug('Presubmit files: %s', ','.join(results)) + return results diff --git a/presubmit_support.py b/presubmit_support.py index 2375d7635..fe6e819aa 100755 --- a/presubmit_support.py +++ b/presubmit_support.py @@ -50,6 +50,7 @@ import presubmit_canned_checks import rdb_wrapper import scm import subprocess2 as subprocess # Exposed through the API. +from lib import utils if sys.version_info.major == 2: # TODO(1009814): Expose urllib2 only through urllib_request and urllib_error @@ -69,6 +70,9 @@ _ASKED_FOR_FEEDBACK = False # are coming from. _SHOW_CALLSTACKS = False +_PRESUBMIT_FILE_REGEX = r'PRESUBMIT.*\.py$' +_PRESUBMIT_FILE_EXCLUDE = r'PRESUBMIT_test' + def time_time(): # Use this so that it can be mocked in tests without interfering with python @@ -285,16 +289,6 @@ class ThreadPool(object): return self._messages -def normpath(path): - '''Version of os.path.normpath that also changes backward slashes to - forward slashes when not running on Windows. - ''' - # This is safe to always do because the Windows version of os.path.normpath - # will replace forward slashes with backward slashes. - path = path.replace(os.sep, '/') - return os.path.normpath(path) - - def _RightHandSideLinesImpl(affected_files): """Implements RightHandSideLines for InputApi and GclChange.""" for af in affected_files: @@ -729,15 +723,17 @@ class InputApi(object): script, or subdirectories thereof. Note that files are listed using the OS path separator, so backslashes are used as separators on Windows. """ - dir_with_slash = normpath(self.PresubmitLocalPath()) + dir_with_slash = utils.normpath(self.PresubmitLocalPath()) # normpath strips trailing path separators, so the trailing separator has to # be added after the normpath call. if len(dir_with_slash) > 0: dir_with_slash += os.path.sep - return list(filter( - lambda x: normpath(x.AbsoluteLocalPath()).startswith(dir_with_slash), - self.change.AffectedFiles(include_deletes, file_filter))) + return list( + filter( + lambda x: utils.normpath(x.AbsoluteLocalPath()).startswith( + dir_with_slash), + self.change.AffectedFiles(include_deletes, file_filter))) def LocalPaths(self): """Returns local paths of input_api.AffectedFiles().""" @@ -958,7 +954,7 @@ class _GitDiffCache(_DiffCache): current_diff.append(x) self._diffs_by_file = dict( - (normpath(path), ''.join(diff)) for path, diff in diffs.items()) + (utils.normpath(path), ''.join(diff)) for path, diff in diffs.items()) if path not in self._diffs_by_file: # SCM didn't have any diff on this file. It could be that the file was not @@ -997,7 +993,7 @@ class AffectedFile(object): because presubmit checks are run with CWD=PresubmitLocalPath() (which is often != client root). """ - return normpath(self._path) + return utils.normpath(self._path) def AbsoluteLocalPath(self): """Returns the absolute path of this file on the local disk. @@ -1358,59 +1354,6 @@ class GitChange(Change): cwd=root).decode('utf-8', 'ignore').splitlines() -def ListRelevantPresubmitFiles(files, root): - """Finds all presubmit files that apply to a given set of source files. - - If inherit-review-settings-ok is present right under root, looks for - PRESUBMIT.py in directories enclosing root. - - Args: - files: An iterable container containing file paths. - root: Path where to stop searching. - - Return: - List of absolute paths of the existing PRESUBMIT.py scripts. - """ - files = [normpath(os.path.join(root, f)) for f in files] - - # List all the individual directories containing files. - directories = {os.path.dirname(f) for f in files} - - # Ignore root if inherit-review-settings-ok is present. - if os.path.isfile(os.path.join(root, 'inherit-review-settings-ok')): - root = None - - # Collect all unique directories that may contain PRESUBMIT.py. - candidates = set() - for directory in directories: - while True: - if directory in candidates: - break - candidates.add(directory) - if directory == root: - break - parent_dir = os.path.dirname(directory) - if parent_dir == directory: - # We hit the system root directory. - break - directory = parent_dir - - # Look for PRESUBMIT.py in all candidate directories. - results = [] - for directory in sorted(list(candidates)): - try: - for f in os.listdir(directory): - p = os.path.join(directory, f) - if os.path.isfile(p) and re.match( - r'PRESUBMIT.*\.py$', f) and not f.startswith('PRESUBMIT_test'): - results.append(p) - except OSError: - pass - - logging.debug('Presubmit files: %s', ','.join(results)) - return results - - class GetPostUploadExecuter(object): def __init__(self, change, gerrit_obj, use_python3): """ @@ -1491,15 +1434,16 @@ def DoPostUploadExecuter(change, gerrit_obj, verbose, use_python3=False): """ python_version = 'Python %s' % sys.version_info.major sys.stdout.write('Running %s post upload checks ...\n' % python_version) - presubmit_files = ListRelevantPresubmitFiles( - change.LocalPaths(), change.RepositoryRoot()) + presubmit_files = utils.ListRelevantFilesInSourceCheckout( + change.LocalPaths(), change.RepositoryRoot(), _PRESUBMIT_FILE_REGEX, + _PRESUBMIT_FILE_EXCLUDE) if not presubmit_files and verbose: sys.stdout.write('Warning, no PRESUBMIT.py found.\n') results = [] executer = GetPostUploadExecuter(change, gerrit_obj, use_python3) # The root presubmit file should be executed after the ones in subdirectories. # i.e. the specific post upload hooks should run before the general ones. - # Thus, reverse the order provided by ListRelevantPresubmitFiles. + # Thus, reverse the order. presubmit_files.reverse() for filename in presubmit_files: @@ -1771,8 +1715,9 @@ def DoPresubmitChecks(change, sys.stdout.write('Running %s presubmit upload checks ...\n' % python_version) start_time = time_time() - presubmit_files = ListRelevantPresubmitFiles( - change.AbsoluteLocalPaths(), change.RepositoryRoot()) + presubmit_files = utils.ListRelevantFilesInSourceCheckout( + change.AbsoluteLocalPaths(), change.RepositoryRoot(), + _PRESUBMIT_FILE_REGEX, _PRESUBMIT_FILE_EXCLUDE) if not presubmit_files and verbose: sys.stdout.write('Warning, no PRESUBMIT.py found.\n') results = [] @@ -2123,7 +2068,6 @@ def main(argv=None): options.use_python3, options.no_diffs) except PresubmitFailure as e: - import utils print(e, file=sys.stderr) print('Maybe your depot_tools is out of date?', file=sys.stderr) print('depot_tools version: %s' % utils.depot_tools_version(), diff --git a/tests/presubmit_unittest.py b/tests/presubmit_unittest.py index 00a65bab8..5a1ee9dfb 100755 --- a/tests/presubmit_unittest.py +++ b/tests/presubmit_unittest.py @@ -47,6 +47,7 @@ import presubmit_support as presubmit import rdb_wrapper import scm import subprocess2 as subprocess +from lib import utils # Shortcut. @@ -220,7 +221,6 @@ index fe3de7b..54ae6e1 100755 class PresubmitUnittest(PresubmitTestsBase): """General presubmit_support.py tests (excluding InputApi and OutputApi).""" - _INHERIT_SETTINGS = 'inherit-review-settings-ok' fake_root_dir = '/foo/bar' def testCannedCheckFilter(self): @@ -231,78 +231,6 @@ class PresubmitUnittest(PresubmitTestsBase): self.assertEqual(canned.CheckOwners(None, None), []) self.assertEqual(canned.CheckOwners, orig) - def testListRelevantPresubmitFiles(self): - files = [ - 'blat.cc', - os.path.join('foo', 'haspresubmit', 'yodle', 'smart.h'), - os.path.join('moo', 'mat', 'gat', 'yo.h'), - os.path.join('foo', 'luck.h'), - ] - - known_files = [ - os.path.join(self.fake_root_dir, 'PRESUBMIT.py'), - os.path.join(self.fake_root_dir, 'foo', 'haspresubmit', 'PRESUBMIT.py'), - os.path.join( - self.fake_root_dir, 'foo', 'haspresubmit', 'yodle', 'PRESUBMIT.py'), - ] - os.path.isfile.side_effect = lambda f: f in known_files - - dirs_with_presubmit = [ - self.fake_root_dir, - os.path.join(self.fake_root_dir, 'foo', 'haspresubmit'), - os.path.join(self.fake_root_dir, 'foo', 'haspresubmit', 'yodle'), - ] - os.listdir.side_effect = ( - lambda d: ['PRESUBMIT.py'] if d in dirs_with_presubmit else []) - - presubmit_files = presubmit.ListRelevantPresubmitFiles( - files, self.fake_root_dir) - self.assertEqual(presubmit_files, known_files) - - def testListUserPresubmitFiles(self): - files = ['blat.cc',] - - os.path.isfile.side_effect = lambda f: 'PRESUBMIT' in f - os.listdir.return_value = [ - 'PRESUBMIT.py', 'PRESUBMIT_test.py', 'PRESUBMIT-user.py'] - - presubmit_files = presubmit.ListRelevantPresubmitFiles( - files, self.fake_root_dir) - self.assertEqual(presubmit_files, [ - os.path.join(self.fake_root_dir, 'PRESUBMIT.py'), - os.path.join(self.fake_root_dir, 'PRESUBMIT-user.py'), - ]) - - def testListRelevantPresubmitFilesInheritSettings(self): - sys_root_dir = self._OS_SEP - root_dir = os.path.join(sys_root_dir, 'foo', 'bar') - inherit_path = os.path.join(root_dir, self._INHERIT_SETTINGS) - files = [ - 'test.cc', - os.path.join('moo', 'test2.cc'), - os.path.join('zoo', 'test3.cc') - ] - - known_files = [ - inherit_path, - os.path.join(sys_root_dir, 'foo', 'PRESUBMIT.py'), - os.path.join(sys_root_dir, 'foo', 'bar', 'moo', 'PRESUBMIT.py'), - ] - os.path.isfile.side_effect = lambda f: f in known_files - - dirs_with_presubmit = [ - os.path.join(sys_root_dir, 'foo'), - os.path.join(sys_root_dir, 'foo', 'bar','moo'), - ] - os.listdir.side_effect = ( - lambda d: ['PRESUBMIT.py'] if d in dirs_with_presubmit else []) - - presubmit_files = presubmit.ListRelevantPresubmitFiles(files, root_dir) - self.assertEqual(presubmit_files, [ - os.path.join(sys_root_dir, 'foo', 'PRESUBMIT.py'), - os.path.join(sys_root_dir, 'foo', 'bar', 'moo', 'PRESUBMIT.py') - ]) - def testTagLineRe(self): m = presubmit.Change.TAG_LINE_RE.match(' BUG =1223, 1445 \t') self.assertIsNotNone(m) @@ -994,11 +922,11 @@ def CheckChangeOnCommit(input_api, output_api): presubmit.main( ['--root', self.fake_root_dir, 'random_file.txt', '--post_upload'])) - @mock.patch('presubmit_support.ListRelevantPresubmitFiles') + @mock.patch('lib.utils.ListRelevantFilesInSourceCheckout') def testMainUnversioned(self, *_mocks): gclient_utils.FileRead.return_value = '' scm.determine_scm.return_value = None - presubmit.ListRelevantPresubmitFiles.return_value = [ + utils.ListRelevantFilesInSourceCheckout.return_value = [ os.path.join(self.fake_root_dir, 'PRESUBMIT.py') ] @@ -1006,14 +934,14 @@ def CheckChangeOnCommit(input_api, output_api): 0, presubmit.main(['--root', self.fake_root_dir, 'random_file.txt'])) - @mock.patch('presubmit_support.ListRelevantPresubmitFiles') + @mock.patch('lib.utils.ListRelevantFilesInSourceCheckout') def testMainUnversionedChecksFail(self, *_mocks): gclient_utils.FileRead.return_value = ( 'USE_PYTHON3 = ' + str(sys.version_info.major == 3) + '\n' 'def CheckChangeOnUpload(input_api, output_api):\n' ' return [output_api.PresubmitError("!!")]\n') scm.determine_scm.return_value = None - presubmit.ListRelevantPresubmitFiles.return_value = [ + utils.ListRelevantFilesInSourceCheckout.return_value = [ os.path.join(self.fake_root_dir, 'PRESUBMIT.py') ] @@ -1285,26 +1213,22 @@ class InputApiUnittest(PresubmitTestsBase): # Doesn't filter much got_files = input_api.AffectedFiles() self.assertEqual(len(got_files), 7) - self.assertEqual(got_files[0].LocalPath(), presubmit.normpath(files[0][1])) - self.assertEqual(got_files[1].LocalPath(), presubmit.normpath(files[1][1])) - self.assertEqual(got_files[2].LocalPath(), presubmit.normpath(files[2][1])) - self.assertEqual(got_files[3].LocalPath(), presubmit.normpath(files[3][1])) - self.assertEqual(got_files[4].LocalPath(), presubmit.normpath(files[4][1])) - self.assertEqual(got_files[5].LocalPath(), presubmit.normpath(files[5][1])) - self.assertEqual(got_files[6].LocalPath(), presubmit.normpath(files[6][1])) + self.assertEqual(got_files[0].LocalPath(), utils.normpath(files[0][1])) + self.assertEqual(got_files[1].LocalPath(), utils.normpath(files[1][1])) + self.assertEqual(got_files[2].LocalPath(), utils.normpath(files[2][1])) + self.assertEqual(got_files[3].LocalPath(), utils.normpath(files[3][1])) + self.assertEqual(got_files[4].LocalPath(), utils.normpath(files[4][1])) + self.assertEqual(got_files[5].LocalPath(), utils.normpath(files[5][1])) + self.assertEqual(got_files[6].LocalPath(), utils.normpath(files[6][1])) # Ignores weird because of check_list, third_party because of skip_list, # binary isn't a text file and being deleted doesn't exist. The rest is # outside foo/. rhs_lines = list(input_api.RightHandSideLines(None)) self.assertEqual(len(rhs_lines), 14) - self.assertEqual(rhs_lines[0][0].LocalPath(), - presubmit.normpath(files[0][1])) - self.assertEqual(rhs_lines[3][0].LocalPath(), - presubmit.normpath(files[0][1])) - self.assertEqual(rhs_lines[7][0].LocalPath(), - presubmit.normpath(files[4][1])) - self.assertEqual(rhs_lines[13][0].LocalPath(), - presubmit.normpath(files[4][1])) + self.assertEqual(rhs_lines[0][0].LocalPath(), utils.normpath(files[0][1])) + self.assertEqual(rhs_lines[3][0].LocalPath(), utils.normpath(files[0][1])) + self.assertEqual(rhs_lines[7][0].LocalPath(), utils.normpath(files[4][1])) + self.assertEqual(rhs_lines[13][0].LocalPath(), utils.normpath(files[4][1])) def testInputApiFilterSourceFile(self): files = [ @@ -1344,10 +1268,10 @@ class InputApiUnittest(PresubmitTestsBase): got_files = input_api.AffectedSourceFiles(None) self.assertEqual(len(got_files), 4) # blat.cc, another.h, WebKit.cpp, and blink.cc remain. - self.assertEqual(got_files[0].LocalPath(), presubmit.normpath(files[0][1])) - self.assertEqual(got_files[1].LocalPath(), presubmit.normpath(files[4][1])) - self.assertEqual(got_files[2].LocalPath(), presubmit.normpath(files[5][1])) - self.assertEqual(got_files[3].LocalPath(), presubmit.normpath(files[7][1])) + self.assertEqual(got_files[0].LocalPath(), utils.normpath(files[0][1])) + self.assertEqual(got_files[1].LocalPath(), utils.normpath(files[4][1])) + self.assertEqual(got_files[2].LocalPath(), utils.normpath(files[5][1])) + self.assertEqual(got_files[3].LocalPath(), utils.normpath(files[7][1])) def testDefaultFilesToCheckFilesToSkipFilters(self): def f(x): @@ -1430,8 +1354,7 @@ class InputApiUnittest(PresubmitTestsBase): for item in files: results = list(filter(input_api.FilterSourceFile, item[0])) for i in range(len(results)): - self.assertEqual(results[i].LocalPath(), - presubmit.normpath(item[1][i])) + self.assertEqual(results[i].LocalPath(), utils.normpath(item[1][i])) # Same number of expected results. self.assertEqual(sorted([f.LocalPath().replace(os.sep, '/') for f in results]), @@ -1491,7 +1414,7 @@ class InputApiUnittest(PresubmitTestsBase): self.assertEqual(got_files[1].LocalPath(), 'eecaee') def testGetAbsoluteLocalPath(self): - normpath = presubmit.normpath + normpath = utils.normpath # Regression test for bug of presubmit stuff that relies on invoking # SVN (e.g. to get mime type of file) not working unless gcl invoked # from the client root (e.g. if you were at 'src' and did 'cd base' before @@ -1512,13 +1435,11 @@ class InputApiUnittest(PresubmitTestsBase): self.assertEqual(affected_files[0].LocalPath(), normpath('isdir')) self.assertEqual(affected_files[1].LocalPath(), normpath('isdir/blat.cc')) # Absolute paths should be prefixed - self.assertEqual( - affected_files[0].AbsoluteLocalPath(), - presubmit.normpath(os.path.join(self.fake_root_dir, 'isdir'))) + self.assertEqual(affected_files[0].AbsoluteLocalPath(), + utils.normpath(os.path.join(self.fake_root_dir, 'isdir'))) self.assertEqual( affected_files[1].AbsoluteLocalPath(), - presubmit.normpath(os.path.join( - self.fake_root_dir, 'isdir/blat.cc'))) + utils.normpath(os.path.join(self.fake_root_dir, 'isdir/blat.cc'))) # New helper functions need to work paths_from_change = change.AbsoluteLocalPaths() @@ -1530,17 +1451,14 @@ class InputApiUnittest(PresubmitTestsBase): is_committing=True, gerrit_obj=None, verbose=False) paths_from_api = api.AbsoluteLocalPaths() self.assertEqual(len(paths_from_api), 1) - self.assertEqual( - paths_from_change[0], - presubmit.normpath(os.path.join(self.fake_root_dir, 'isdir'))) + self.assertEqual(paths_from_change[0], + utils.normpath(os.path.join(self.fake_root_dir, 'isdir'))) self.assertEqual( paths_from_change[1], - presubmit.normpath(os.path.join(self.fake_root_dir, 'isdir', - 'blat.cc'))) + utils.normpath(os.path.join(self.fake_root_dir, 'isdir', 'blat.cc'))) self.assertEqual( paths_from_api[0], - presubmit.normpath(os.path.join(self.fake_root_dir, 'isdir', - 'blat.cc'))) + utils.normpath(os.path.join(self.fake_root_dir, 'isdir', 'blat.cc'))) def testDeprecated(self): change = presubmit.Change( @@ -1665,7 +1583,7 @@ class AffectedFileUnittest(PresubmitTestsBase): def testAffectedFile(self): gclient_utils.FileRead.return_value = 'whatever\ncookie' af = presubmit.GitAffectedFile('foo/blat.cc', 'M', self.fake_root_dir, None) - self.assertEqual(presubmit.normpath('foo/blat.cc'), af.LocalPath()) + self.assertEqual(utils.normpath('foo/blat.cc'), af.LocalPath()) self.assertEqual('M', af.Action()) self.assertEqual(['whatever', 'cookie'], af.NewContents()) diff --git a/tests/utils_test.py b/tests/utils_test.py index 89620dbeb..a7bc8b91b 100755 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -17,13 +17,10 @@ DEPOT_TOOLS_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, DEPOT_TOOLS_ROOT) from testing_support import coverage_utils -import utils +from lib import utils class GitCacheTest(unittest.TestCase): - def setUp(self): - pass - @mock.patch('subprocess.check_output', lambda x, **kwargs: b'foo') def testVersionWithGit(self): version = utils.depot_tools_version() @@ -45,6 +42,91 @@ class GitCacheTest(unittest.TestCase): self.assertEqual(version, 'unknown') +class ListRelevantFilesInSourceCheckoutTest(unittest.TestCase): + fake_root_dir = os.path.join(os.sep, 'foo', 'bar') + _INHERIT_SETTINGS = 'inherit-review-settings-ok' + + def setUp(self): + mock.patch('os.listdir').start() + mock.patch('os.path.isfile').start() + + def testListRelevantPresubmitFiles(self): + files = [ + 'blat.cc', + os.path.join('foo', 'haspresubmit', 'yodle', 'smart.h'), + os.path.join('moo', 'mat', 'gat', 'yo.h'), + os.path.join('foo', 'luck.h'), + ] + + known_files = [ + os.path.join(self.fake_root_dir, 'PRESUBMIT.py'), + os.path.join(self.fake_root_dir, 'foo', 'haspresubmit', 'PRESUBMIT.py'), + os.path.join(self.fake_root_dir, 'foo', 'haspresubmit', 'yodle', + 'PRESUBMIT.py'), + ] + os.path.isfile.side_effect = lambda f: f in known_files + + dirs_with_presubmit = [ + self.fake_root_dir, + os.path.join(self.fake_root_dir, 'foo', 'haspresubmit'), + os.path.join(self.fake_root_dir, 'foo', 'haspresubmit', 'yodle'), + ] + os.listdir.side_effect = ( + lambda d: ['PRESUBMIT.py'] if d in dirs_with_presubmit else []) + + presubmit_files = utils.ListRelevantFilesInSourceCheckout( + files, self.fake_root_dir, r'PRESUBMIT.*', r'PRESUBMIT_test') + self.assertEqual(presubmit_files, known_files) + + def testListUserPresubmitFiles(self): + files = [ + 'blat.cc', + ] + + os.path.isfile.side_effect = lambda f: 'PRESUBMIT' in f + os.listdir.return_value = [ + 'PRESUBMIT.py', 'PRESUBMIT_test.py', 'PRESUBMIT-user.py' + ] + + presubmit_files = utils.ListRelevantFilesInSourceCheckout( + files, self.fake_root_dir, r'PRESUBMIT.*', r'PRESUBMIT_test') + self.assertEqual(presubmit_files, [ + os.path.join(self.fake_root_dir, 'PRESUBMIT.py'), + os.path.join(self.fake_root_dir, 'PRESUBMIT-user.py'), + ]) + + def testListRelevantPresubmitFilesInheritSettings(self): + sys_root_dir = os.sep + root_dir = os.path.join(sys_root_dir, 'foo', 'bar') + inherit_path = os.path.join(root_dir, self._INHERIT_SETTINGS) + files = [ + 'test.cc', + os.path.join('moo', 'test2.cc'), + os.path.join('zoo', 'test3.cc') + ] + + known_files = [ + inherit_path, + os.path.join(sys_root_dir, 'foo', 'PRESUBMIT.py'), + os.path.join(sys_root_dir, 'foo', 'bar', 'moo', 'PRESUBMIT.py'), + ] + os.path.isfile.side_effect = lambda f: f in known_files + + dirs_with_presubmit = [ + os.path.join(sys_root_dir, 'foo'), + os.path.join(sys_root_dir, 'foo', 'bar', 'moo'), + ] + os.listdir.side_effect = ( + lambda d: ['PRESUBMIT.py'] if d in dirs_with_presubmit else []) + + presubmit_files = utils.ListRelevantFilesInSourceCheckout( + files, root_dir, r'PRESUBMIT.*', r'PRESUBMIT_test') + self.assertEqual(presubmit_files, [ + os.path.join(sys_root_dir, 'foo', 'PRESUBMIT.py'), + os.path.join(sys_root_dir, 'foo', 'bar', 'moo', 'PRESUBMIT.py') + ]) + + if __name__ == '__main__': logging.basicConfig( level=logging.DEBUG if '-v' in sys.argv else logging.ERROR) diff --git a/utils.py b/utils.py deleted file mode 100644 index 3f16ce98b..000000000 --- a/utils.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2022 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. - -import os -import subprocess - - -def depot_tools_version(): - depot_tools_root = os.path.dirname(os.path.abspath(__file__)) - try: - commit_hash = subprocess.check_output(['git', 'rev-parse', 'HEAD'], - cwd=depot_tools_root).decode( - 'utf-8', 'ignore') - return 'git-%s' % commit_hash - except Exception: - pass - - # git check failed, let's check last modification of frequently checked file - try: - mtime = os.path.getmtime( - os.path.join(depot_tools_root, 'infra', 'config', 'recipes.cfg')) - return 'recipes.cfg-%d' % (mtime) - except Exception: - return 'unknown'