Skip to content

Commit 11abc5e

Browse files
Tamer TasCommit Bot
authored andcommitted
[test] create a CacheableSourceFileProcessor superclass for changed files
Added tests for the existing FileContentsCache, and created a superclass that removes the duplicated code from Torque and CPP linters [email protected],[email protected] CC=​​​​[email protected] NOTRY=true Bug: v8:8482 Change-Id: Ic7a0b3d58c64f395e790d4ff668fa804c05478be Reviewed-on: https://chromium-review.googlesource.com/c/1369949 Commit-Queue: Tamer Tas <[email protected]> Reviewed-by: Michael Achenbach <[email protected]> Cr-Commit-Position: refs/heads/master@{#58321}
1 parent f9d033d commit 11abc5e

2 files changed

Lines changed: 193 additions & 79 deletions

File tree

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#!/usr/bin/env python
2+
# Copyright 2018 the V8 project authors. All rights reserved.
3+
# Use of this source code is governed by a BSD-style license that can be
4+
# found in the LICENSE file.
5+
6+
import os
7+
import sys
8+
import tempfile
9+
import unittest
10+
11+
# Configuring the path for the v8_presubmit module
12+
TOOLS_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
13+
sys.path.append(TOOLS_ROOT)
14+
15+
from v8_presubmit import FileContentsCache, CacheableSourceFileProcessor
16+
17+
18+
class FakeCachedProcessor(CacheableSourceFileProcessor):
19+
def __init__(self, cache_file_path):
20+
super(FakeCachedProcessor, self).__init__(
21+
cache_file_path=cache_file_path, file_type='.test')
22+
def GetProcessorWorker(self):
23+
return object
24+
def GetProcessorScript(self):
25+
return "echo", []
26+
def DetectUnformattedFiles(_, cmd, worker, files):
27+
raise NotImplementedError
28+
29+
class FileContentsCacheTest(unittest.TestCase):
30+
def setUp(self):
31+
_, self.cache_file_path = tempfile.mkstemp()
32+
cache = FileContentsCache(self.cache_file_path)
33+
cache.Load()
34+
35+
def generate_file():
36+
_, file_name = tempfile.mkstemp()
37+
with open(file_name, "w") as f:
38+
f.write(file_name)
39+
40+
return file_name
41+
42+
self.target_files = [generate_file() for _ in range(2)]
43+
unchanged_files = cache.FilterUnchangedFiles(self.target_files)
44+
self.assertEqual(len(unchanged_files), 2)
45+
cache.Save()
46+
47+
def tearDown(self):
48+
for file in [self.cache_file_path] + self.target_files:
49+
os.remove(file)
50+
51+
def testCachesFiles(self):
52+
cache = FileContentsCache(self.cache_file_path)
53+
cache.Load()
54+
55+
changed_files = cache.FilterUnchangedFiles(self.target_files)
56+
self.assertListEqual(changed_files, [])
57+
58+
modified_file = self.target_files[0]
59+
with open(modified_file, "w") as f:
60+
f.write("modification")
61+
62+
changed_files = cache.FilterUnchangedFiles(self.target_files)
63+
self.assertListEqual(changed_files, [modified_file])
64+
65+
def testCacheableSourceFileProcessor(self):
66+
class CachedProcessor(FakeCachedProcessor):
67+
def DetectFilesToChange(_, files):
68+
self.assertListEqual(files, [])
69+
return []
70+
71+
cached_processor = CachedProcessor(cache_file_path=self.cache_file_path)
72+
cached_processor.ProcessFiles(self.target_files)
73+
74+
def testCacheableSourceFileProcessorWithModifications(self):
75+
modified_file = self.target_files[0]
76+
with open(modified_file, "w") as f:
77+
f.write("modification")
78+
79+
class CachedProcessor(FakeCachedProcessor):
80+
def DetectFilesToChange(_, files):
81+
self.assertListEqual(files, [modified_file])
82+
return []
83+
84+
cached_processor = CachedProcessor(
85+
cache_file_path=self.cache_file_path,
86+
)
87+
cached_processor.ProcessFiles(self.target_files)
88+
89+
90+
if __name__ == '__main__':
91+
unittest.main()

tools/v8_presubmit.py

Lines changed: 102 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -228,17 +228,94 @@ def FindFilesIn(self, path):
228228
return result
229229

230230

231-
class CppLintProcessor(SourceFileProcessor):
231+
class CacheableSourceFileProcessor(SourceFileProcessor):
232+
"""Utility class that allows caching ProcessFiles() method calls.
233+
234+
In order to use it, create a ProcessFilesWithoutCaching method that returns
235+
the files requiring intervention after processing the source files.
236+
"""
237+
238+
def __init__(self, cache_file_path, file_type):
239+
self.cache_file_path = cache_file_path
240+
self.file_type = file_type
241+
242+
def GetProcessorWorker(self):
243+
"""Expected to return the worker function to run the formatter."""
244+
raise NotImplementedError
245+
246+
def GetProcessorScript(self):
247+
"""Expected to return a tuple
248+
(path to the format processor script, list of arguments)."""
249+
raise NotImplementedError
250+
251+
def GetProcessorCommand(self):
252+
format_processor, options = self.GetProcessorScript()
253+
if not format_processor:
254+
print('Could not find the formatter for % files' % self.file_type)
255+
sys.exit(1)
256+
257+
command = [sys.executable, format_processor]
258+
command.extend(options)
259+
260+
return command
261+
262+
def ProcessFiles(self, files):
263+
cache = FileContentsCache(self.cache_file_path)
264+
cache.Load()
265+
files = cache.FilterUnchangedFiles(files)
266+
267+
if len(files) == 0:
268+
print 'No changes in %s files detected. Skipping check' % self.file_type
269+
return True
270+
271+
files_requiring_changes = self.DetectFilesToChange(files)
272+
print (
273+
'Total %s files found that require formatting: %d' %
274+
(self.file_type, len(files_requiring_changes)))
275+
for file in files_requiring_changes:
276+
cache.RemoveFile(file)
277+
278+
cache.Save()
279+
return files_requiring_changes == []
280+
281+
def DetectFilesToChange(self, files):
282+
command = self.GetProcessorCommand()
283+
worker = self.GetProcessorWorker()
284+
285+
commands = [command + [file] for file in files]
286+
count = multiprocessing.cpu_count()
287+
pool = multiprocessing.Pool(count)
288+
try:
289+
results = pool.map_async(worker, commands).get(timeout=240)
290+
except KeyboardInterrupt:
291+
print "\nCaught KeyboardInterrupt, terminating workers."
292+
pool.terminate()
293+
pool.join()
294+
sys.exit(1)
295+
296+
unformatted_files = []
297+
for index, errors in enumerate(results):
298+
if errors > 0:
299+
unformatted_files.append(files[index])
300+
301+
return unformatted_files
302+
303+
304+
class CppLintProcessor(CacheableSourceFileProcessor):
232305
"""
233306
Lint files to check that they follow the google code style.
234307
"""
235308

309+
def __init__(self):
310+
super(CppLintProcessor, self).__init__(
311+
cache_file_path='.cpplint-cache', file_type='C/C++')
312+
236313
def IsRelevant(self, name):
237314
return name.endswith('.cc') or name.endswith('.h')
238315

239316
def IgnoreDir(self, name):
240317
return (super(CppLintProcessor, self).IgnoreDir(name)
241-
or (name == 'third_party'))
318+
or (name == 'third_party'))
242319

243320
IGNORE_LINT = ['export-template.h', 'flag-definitions.h']
244321

@@ -251,55 +328,30 @@ def GetPathsToSearch(self):
251328
test_dirs = ['cctest', 'common', 'fuzzer', 'inspector', 'unittests']
252329
return dirs + [join('test', dir) for dir in test_dirs]
253330

254-
def GetCpplintScript(self, prio_path):
255-
for path in [prio_path] + os.environ["PATH"].split(os.pathsep):
331+
def GetProcessorWorker(self):
332+
return CppLintWorker
333+
334+
def GetProcessorScript(self):
335+
filters = ','.join([n for n in LINT_RULES])
336+
arguments = ['--filter', filters]
337+
for path in [TOOLS_PATH] + os.environ["PATH"].split(os.pathsep):
256338
path = path.strip('"')
257-
cpplint = os.path.join(path, "cpplint.py")
339+
cpplint = os.path.join(path, 'cpplint.py')
258340
if os.path.isfile(cpplint):
259-
return cpplint
260-
261-
return None
262-
263-
def ProcessFiles(self, files):
264-
good_files_cache = FileContentsCache('.cpplint-cache')
265-
good_files_cache.Load()
266-
files = good_files_cache.FilterUnchangedFiles(files)
267-
if len(files) == 0:
268-
print 'No changes in C/C++ files detected. Skipping cpplint check.'
269-
return True
270-
271-
filters = ",".join([n for n in LINT_RULES])
272-
cpplint = self.GetCpplintScript(TOOLS_PATH)
273-
if cpplint is None:
274-
print('Could not find cpplint.py. Make sure '
275-
'depot_tools is installed and in the path.')
276-
sys.exit(1)
277-
278-
command = [sys.executable, cpplint, '--filter', filters]
279-
280-
commands = [command + [file] for file in files]
281-
count = multiprocessing.cpu_count()
282-
pool = multiprocessing.Pool(count)
283-
try:
284-
results = pool.map_async(CppLintWorker, commands).get(999999)
285-
except KeyboardInterrupt:
286-
print "\nCaught KeyboardInterrupt, terminating workers."
287-
sys.exit(1)
341+
return cpplint, arguments
288342

289-
for i in range(len(files)):
290-
if results[i] > 0:
291-
good_files_cache.RemoveFile(files[i])
343+
return None, arguments
292344

293-
total_errors = sum(results)
294-
print "Total C/C++ files found that require formatting: %d" % total_errors
295-
good_files_cache.Save()
296-
return total_errors == 0
297345

298-
class TorqueFormatProcessor(SourceFileProcessor):
346+
class TorqueFormatProcessor(CacheableSourceFileProcessor):
299347
"""
300348
Check .tq files to verify they follow the Torque style guide.
301349
"""
302350

351+
def __init__(self):
352+
super(TorqueFormatProcessor, self).__init__(
353+
cache_file_path='.torquelint-cache', file_type='Torque')
354+
303355
def IsRelevant(self, name):
304356
return name.endswith('.tq')
305357

@@ -308,47 +360,17 @@ def GetPathsToSearch(self):
308360
test_dirs = ['torque']
309361
return dirs + [join('test', dir) for dir in test_dirs]
310362

311-
def GetTorquelintScript(self):
363+
def GetProcessorWorker(self):
364+
return TorqueLintWorker
365+
366+
def GetProcessorScript(self):
312367
torque_tools = os.path.join(TOOLS_PATH, "torque")
313368
torque_path = os.path.join(torque_tools, "format-torque.py")
314-
369+
arguments = ['-l']
315370
if os.path.isfile(torque_path):
316-
return torque_path
371+
return torque_path, arguments
317372

318-
return None
319-
320-
def ProcessFiles(self, files):
321-
good_files_cache = FileContentsCache('.torquelint-cache')
322-
good_files_cache.Load()
323-
files = good_files_cache.FilterUnchangedFiles(files)
324-
if len(files) == 0:
325-
print 'No changes in Torque files detected. Skipping Torque lint check.'
326-
return True
327-
328-
torquelint = self.GetTorquelintScript()
329-
if torquelint is None:
330-
print('Could not find format-torque.')
331-
sys.exit(1)
332-
333-
command = [sys.executable, torquelint, '-l']
334-
335-
commands = [command + [file] for file in files]
336-
count = multiprocessing.cpu_count()
337-
pool = multiprocessing.Pool(count)
338-
try:
339-
results = pool.map_async(TorqueLintWorker, commands).get()
340-
except KeyboardInterrupt:
341-
print "\nCaught KeyboardInterrupt, terminating workers."
342-
sys.exit(1)
343-
344-
for i in range(len(files)):
345-
if results[i] > 0:
346-
good_files_cache.RemoveFile(files[i])
347-
348-
total_errors = sum(results)
349-
print "Total Torque files requiring formatting: %d" % total_errors
350-
good_files_cache.Save()
351-
return total_errors == 0
373+
return None, arguments
352374

353375
COPYRIGHT_HEADER_PATTERN = re.compile(
354376
r'Copyright [\d-]*20[0-1][0-9] the V8 project authors. All rights reserved.')
@@ -630,6 +652,7 @@ def PyTests(workspace):
630652
print 'Running ' + script
631653
result &= subprocess.call(
632654
[sys.executable, script], stdout=subprocess.PIPE) == 0
655+
633656
return result
634657

635658

0 commit comments

Comments
 (0)