diff options
author | Sven Panne <svenpanne@gmail.com> | 2016-11-08 10:45:46 +0100 |
---|---|---|
committer | Kim Gräsman <kim.grasman@gmail.com> | 2016-11-28 20:48:43 +0100 |
commit | d53f86d8f55b659cba94788c4b42e8265e15e5b4 (patch) | |
tree | 2a0b371d99e5f2586746d4944b504b9c602ef9b2 | |
parent | eb7f5d1ef02836575aebfe5a95977f067064cee2 (diff) |
Add a new option for a more tool-friendly output.
The standard output format of iwyu is not very friendly for tools like
Jenkins' warnings-plugin (https://github.com/jenkinsci/warnings-plugin) or
editors. This change adds a new -o/--output-format command line option with
'iwyu' being the traditional format and 'clang' the new one for mangling the
output into something clang-like, enabling nice integration into
emacs/Jenkins/etc. out of the box.
Somehow this should probably be the default and be handled on the native
side (not as a post-processing step), but the current change is probably the
least controversial and easiest one for now.
-rwxr-xr-x | iwyu_tool.py | 88 |
1 files changed, 80 insertions, 8 deletions
diff --git a/iwyu_tool.py b/iwyu_tool.py index b06876b..19de45b 100755 --- a/iwyu_tool.py +++ b/iwyu_tool.py @@ -25,9 +25,77 @@ import sys import json import argparse import subprocess - - -def run_iwyu(cwd, compile_command, iwyu_args, verbose): +import re + + +def iwyu_formatter(output): + """ Process iwyu's output, basically a no-op. """ + print('\n'.join(output)) + + +CORRECT_RE = re.compile(r'^\((.*?) has correct #includes/fwd-decls\)$') +SHOULD_ADD_RE = re.compile(r'^(.*?) should add these lines:$') +SHOULD_REMOVE_RE = re.compile(r'^(.*?) should remove these lines:$') +FULL_LIST_RE = re.compile(r'The full include-list for (.*?):$') +END_RE = re.compile(r'^---$') +LINES_RE = re.compile(r'^- (.*?) // lines ([0-9]+)-[0-9]+$') + + +GENERAL, ADD, REMOVE, LIST = range(4) + + +def clang_formatter(output): + """ Process iwyu's output into something clang-like. """ + state = (GENERAL, None) + for line in output: + match = CORRECT_RE.match(line) + if match: + print('%s:1:1: note: #includes/fwd-decls are correct' % match.groups(1)) + continue + match = SHOULD_ADD_RE.match(line) + if match: + state = (ADD, match.group(1)) + continue + match = SHOULD_REMOVE_RE.match(line) + if match: + state = (REMOVE, match.group(1)) + continue + match = FULL_LIST_RE.match(line) + if match: + state = (LIST, match.group(1)) + elif END_RE.match(line): + state = (GENERAL, None) + elif not line.strip(): + continue + elif state[0] == GENERAL: + print(line) + elif state[0] == ADD: + print('%s:1:1: error: add the following line' % state[1]) + print(line) + elif state[0] == REMOVE: + match = LINES_RE.match(line) + line_no = match.group(2) if match else '1' + print('%s:%s:1: error: remove the following line' % (state[1], line_no)) + print(match.group(1)) + + +DEFAULT_FORMAT = 'iwyu' +FORMATTERS = { + 'iwyu': iwyu_formatter, + 'clang': clang_formatter +} + +def get_output(cwd, command): + """ Run the given command and return its output as a string. """ + process = subprocess.Popen(command, + cwd=cwd, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + return process.communicate()[0].decode("utf-8").splitlines() + + +def run_iwyu(cwd, compile_command, iwyu_args, verbose, formatter): """ Rewrite compile_command to an IWYU command, and run it. """ compiler, _, args = compile_command.partition(' ') if compiler.endswith('cl.exe'): @@ -43,10 +111,10 @@ def run_iwyu(cwd, compile_command, iwyu_args, verbose): if verbose: print('%s:' % command) - return subprocess.call(command, cwd=cwd, shell=True) + formatter(get_output(cwd, command)) -def main(compilation_db_path, source_files, verbose, iwyu_args): +def main(compilation_db_path, source_files, verbose, formatter, iwyu_args): """ Entry point. """ # Canonicalize compilation database path if os.path.isdir(compilation_db_path): @@ -87,7 +155,7 @@ def main(compilation_db_path, source_files, verbose, iwyu_args): try: for entry in entries: cwd, compile_command = entry['directory'], entry['command'] - run_iwyu(cwd, compile_command, iwyu_args, verbose) + run_iwyu(cwd, compile_command, iwyu_args, verbose, formatter) except OSError as why: print('ERROR: Failed to launch include-what-you-use: %s' % why) return 1 @@ -127,6 +195,9 @@ def _bootstrap(): parser.add_argument('-v', '--verbose', action='store_true', help='Print IWYU commands') + parser.add_argument('-o', '--output-format', type=str, + choices=FORMATTERS.keys(), default=DEFAULT_FORMAT, + help='Output format (default: %s)' % DEFAULT_FORMAT) parser.add_argument('-p', metavar='<build-path>', required=True, help='Compilation database path', dest='dbpath') parser.add_argument('source', nargs='*', @@ -140,10 +211,11 @@ def _bootstrap(): return argv[:double_dash], argv[double_dash+1:] except ValueError: return argv, [] - argv, iwyu_args = partition_args(sys.argv[1:]) args = parser.parse_args(argv) - sys.exit(main(args.dbpath, args.source, args.verbose, iwyu_args)) + + sys.exit(main(args.dbpath, args.source, args.verbose, + FORMATTERS[args.output_format], iwyu_args)) if __name__ == '__main__': |