scripts: Improve output formatting in linting CLI
This CL improves the formatting for our CLI linting tools (lint_package)
to make it default to a human readable format, and creates an option to
specify one JSON per line with a --json flag.
BUG=b:229143726
TEST=lint_package -b=atlas smogcheck
TEST=https://screenshot.googleplex.com/3zkijn7RqkSUbWC
TEST=https://screenshot.googleplex.com/9K6neCzeFZ8HtmV
TEST=lint_package -b=atlas --json smogcheck
TEST=https://screenshot.googleplex.com/5SxXcBZDrD2fHZC
Change-Id: Icc73e5f0cfe29168c4a9b986c5d49838e266a3ab
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/3821742
Auto-Submit: Ryan Beltran <ryanbeltran@chromium.org>
Commit-Queue: Ryan Beltran <ryanbeltran@chromium.org>
Tested-by: Ryan Beltran <ryanbeltran@chromium.org>
Reviewed-by: Alex Klein <saklein@chromium.org>
diff --git a/scripts/lint_package.py b/scripts/lint_package.py
index cd82f3a..51e1e01 100644
--- a/scripts/lint_package.py
+++ b/scripts/lint_package.py
@@ -10,12 +10,13 @@
import json
import sys
-from typing import List
+from typing import List, Text
from chromite.lib import build_target_lib
from chromite.lib import commandline
from chromite.lib import cros_build_lib
from chromite.lib import portage_util
+from chromite.lib import terminal
from chromite.lib import workon_helper
from chromite.lib.parser import package_info
from chromite.service import toolchain
@@ -50,6 +51,45 @@
return package_infos
+def format_lint(lint: toolchain.LinterFinding) -> Text:
+ """Formats a lint for human readable printing.
+
+ Example output:
+ [ClangTidy] In 'path/to/file.c' on line 36:
+ Also in 'path/to/file.c' on line 40:
+ Also in 'path/to/file.c' on lines 50-53:
+ You did something bad, don't do it.
+
+ Args:
+ lint: A linter finding from the toolchain service.
+
+ Returns:
+ A correctly formatted string ready to be displayed to the user.
+ """
+
+ color = terminal.Color(True)
+ lines = []
+ linter_prefix = color.Color(terminal.Color.YELLOW, f'[{lint.linter}]',
+ background_color=terminal.Color.BLACK)
+ for loc in lint.locations:
+ if not lines:
+ location_prefix = f'\n{linter_prefix} In'
+ else:
+ location_prefix = ' and in'
+ if loc.line_start != loc.line_end:
+ lines.append(
+ f"{location_prefix} '{loc.filepath}' "
+ f'lines {loc.line_start}-{loc.line_end}:')
+ else:
+ lines.append(
+ f"{location_prefix} '{loc.filepath}' line {loc.line_start}:")
+ message_lines = lint.message.split('\n')
+ for line in message_lines:
+ lines.append(f' {line}')
+ lines.append('')
+ return '\n'.join(lines)
+
+
def get_arg_parser() -> commandline.ArgumentParser:
"""Creates an argument parser for this script."""
default_board = cros_build_lib.GetDefaultBoard()
@@ -82,6 +122,10 @@
default=sys.stdout,
help='File to use instead of stdout.')
parser.add_argument(
+ '--json',
+ action='store_true',
+ help='Output lints in JSON format.')
+ parser.add_argument(
'--no-clippy',
dest='clippy',
action='store_false',
@@ -138,5 +182,13 @@
lints = build_linter.emerge_with_linting(
use_clippy=opts.clippy, use_tidy=opts.tidy, use_golint=opts.golint)
+ if opts.json:
+ formatted_output = json.dumps([lint._asdict() for lint in lints])
+ else:
+ formatted_output = '\n'.join(format_lint(lint) for lint in lints)
+
with file_util.Open(opts.output, 'w') as output_file:
- json.dump(lints, output_file)
+ output_file.write(formatted_output)
+ if not opts.json:
+ output_file.write(f'\nFound {len(lints)} lints.')
+ output_file.write('\n')