Skip to content

Commit

Permalink
cpplint: add --quiet flag to suppress all output when there's no errors
Browse files Browse the repository at this point in the history
Example:

   cpplint.py --quiet <file-names>

Will now return with an exit code of 0 and return empty output if there
were no errors. This makes it particularly useful to be driven by a build system
such as makefiles or gradle.

In particular, these messages are now suppressed:

  Ignoring <filename>, excluded by CPPLINT.cfg, ...
  Done processing <filename>
  Total errors found: 0

If there were any errors, the above messages are printed nevertheless.

There is no behavior change if --quiet is not passed in.
  • Loading branch information
iam committed Nov 10, 2017
1 parent 8a87a46 commit e8ffd7c
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 3 deletions.
39 changes: 36 additions & 3 deletions cpplint/cpplint.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
[--counting=total|toplevel|detailed] [--root=subdir]
[--linelength=digits] [--headers=x,y,...]
[--quiet]
<file> [file] ...
The style guidelines this tries to follow are those in
Expand All @@ -83,6 +84,9 @@
verbose=#
Specify a number 0-5 to restrict errors to certain verbosity levels.
quiet
Don't print anything if no errors are found.
filter=-x,+y,...
Specify a comma-separated list of category-filters to apply: only
error messages whose category names pass the filters will be printed.
Expand Down Expand Up @@ -861,6 +865,7 @@ def __init__(self):
self._filters_backup = self.filters[:]
self.counting = 'total' # In what way are we counting errors?
self.errors_by_category = {} # string to int dict storing error counts
self.quiet = False # Suppress non-error messagess?

# output format:
# "emacs" - format that emacs can parse (default)
Expand All @@ -871,6 +876,12 @@ def SetOutputFormat(self, output_format):
"""Sets the output format for errors."""
self.output_format = output_format

def SetQuiet(self, quiet):
"""Sets the module's quiet settings, and returns the previous setting."""
last_quiet = self.quiet
self.quiet = quiet
return last_quiet

def SetVerboseLevel(self, level):
"""Sets the module's verbosity, and returns the previous setting."""
last_verbose_level = self.verbose_level
Expand Down Expand Up @@ -952,6 +963,14 @@ def _SetOutputFormat(output_format):
"""Sets the module's output format."""
_cpplint_state.SetOutputFormat(output_format)

def _Quiet():
"""Return's the module's quiet setting."""
return _cpplint_state.quiet

def _SetQuiet(quiet):
"""Set the module's quiet status, and return previous setting."""
return _cpplint_state.SetQuiet(quiet)


def _VerboseLevel():
"""Returns the module's verbosity setting."""
Expand Down Expand Up @@ -5955,6 +5974,9 @@ def ProcessConfigOverrides(filename):
if base_name:
pattern = re.compile(val)
if pattern.match(base_name):
if _cpplint_state.quiet:
# Suppress "Ignoring file" warning when using --quiet.
return False
sys.stderr.write('Ignoring "%s": file excluded by "%s". '
'File path component "%s" matches '
'pattern "%s"\n' %
Expand Down Expand Up @@ -6006,6 +6028,7 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]):

_SetVerboseLevel(vlevel)
_BackupFilters()
old_errors = _cpplint_state.error_count

if not ProcessConfigOverrides(filename):
_RestoreFilters()
Expand Down Expand Up @@ -6074,7 +6097,10 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]):
Error(filename, linenum, 'whitespace/newline', 1,
'Unexpected \\r (^M) found; better to use only \\n')

sys.stdout.write('Done processing %s\n' % filename)
# Suppress printing anything if --quiet was passed unless the error
# count has increased after processing this file.
if not _cpplint_state.quiet or old_errors != _cpplint_state.error_count:
sys.stdout.write('Done processing %s\n' % filename)
_RestoreFilters()


Expand Down Expand Up @@ -6118,13 +6144,15 @@ def ParseArguments(args):
'root=',
'linelength=',
'extensions=',
'headers='])
'headers=',
'quiet'])
except getopt.GetoptError:
PrintUsage('Invalid arguments.')

verbosity = _VerboseLevel()
output_format = _OutputFormat()
filters = ''
quiet = _Quiet()
counting_style = ''

for (opt, val) in opts:
Expand All @@ -6134,6 +6162,8 @@ def ParseArguments(args):
if val not in ('emacs', 'vs7', 'eclipse'):
PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.')
output_format = val
elif opt == '--quiet':
quiet = True
elif opt == '--verbose':
verbosity = int(val)
elif opt == '--filter':
Expand Down Expand Up @@ -6166,6 +6196,7 @@ def ParseArguments(args):
PrintUsage('No files were specified.')

_SetOutputFormat(output_format)
_SetQuiet(quiet)
_SetVerboseLevel(verbosity)
_SetFilters(filters)
_SetCountingStyle(counting_style)
Expand All @@ -6186,7 +6217,9 @@ def main():
_cpplint_state.ResetErrorCounts()
for filename in filenames:
ProcessFile(filename, _cpplint_state.verbose_level)
_cpplint_state.PrintErrorCounts()
# If --quiet is passed, suppress printing error count unless there are errors.
if not _cpplint_state.quiet or _cpplint_state.error_count > 0:
_cpplint_state.PrintErrorCounts()

sys.exit(_cpplint_state.error_count > 0)

Expand Down
78 changes: 78 additions & 0 deletions cpplint/cpplint_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import os
import random
import re
import subprocess
import sys
import unittest

Expand Down Expand Up @@ -5686,6 +5687,83 @@ def testInlineAssembly(self):
self.assertEquals(len(self.nesting_state.stack), 0)


class QuietTest(unittest.TestCase):

def setUp(self):
self.this_dir_path = os.path.dirname(os.path.abspath(__file__))
self.python_executable = sys.executable or 'python'
self.cpplint_test_h = os.path.join(self.this_dir_path,
'cpplint_test_header.h')

def _runCppLint(self, *args):
cpplint_abspath = os.path.join(self.this_dir_path, 'cpplint.py')

cmd_line = [self.python_executable, cpplint_abspath] + \
list(args) + \
[ self.cpplint_test_h ]

return_code = 0
try:
output = subprocess.check_output(cmd_line,
stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as err:
return_code = err.returncode
output = err.output

return (return_code, output)

def testNonQuietWithErrors(self):
# This will fail: the test header is missing a copyright and header guard.
(return_code, output) = self._runCppLint()
self.assertEquals(1, return_code)
# Always-on behavior: Print error messages as they come up.
self.assertIn("[legal/copyright]", output)
self.assertIn("[build/header_guard]", output)
# If --quiet was unspecified: Print 'Done processing' and 'Total errors..'
self.assertIn("Done processing", output)
self.assertIn("Total errors found:", output)

def testQuietWithErrors(self):
# When there are errors, behavior is identical to not passing --quiet.
(return_code, output) = self._runCppLint('--quiet')
self.assertEquals(1, return_code)
self.assertIn("[legal/copyright]", output)
self.assertIn("[build/header_guard]", output)
# Even though --quiet was used, print these since there were errors.
self.assertIn("Done processing", output)
self.assertIn("Total errors found:", output)

def testNonQuietWithoutErrors(self):
# This will succeed. We filtered out all the known errors for that file.
(return_code, output) = self._runCppLint('--filter=' +
'-legal/copyright,' +
'-build/header_guard')
self.assertEquals(0, return_code, output)
# No cpplint errors are printed since there were no errors.
self.assertNotIn("[legal/copyright]", output)
self.assertNotIn("[build/header_guard]", output)
# Print 'Done processing' and 'Total errors found' since
# --quiet was not specified.
self.assertIn("Done processing", output)
self.assertIn("Total errors found:", output)

def testQuietWithoutErrors(self):
# This will succeed. We filtered out all the known errors for that file.
(return_code, output) = self._runCppLint('--quiet',
'--filter=' +
'-legal/copyright,' +
'-build/header_guard')
self.assertEquals(0, return_code, output)
# No cpplint errors are printed since there were no errors.
self.assertNotIn("[legal/copyright]", output)
self.assertNotIn("[build/header_guard]", output)
# --quiet was specified and there were no errors:
# skip the printing of 'Done processing' and 'Total errors..'
self.assertNotIn("Done processing", output)
self.assertNotIn("Total errors found:", output)
# Output with no errors must be completely blank!
self.assertEquals("", output)

# pylint: disable-msg=C6409
def setUp():
"""Runs before all tests are executed.
Expand Down

0 comments on commit e8ffd7c

Please sign in to comment.