| #!/usr/bin/env python3 | |
| # | |
| #===- google-java-format-diff.py - google-java-format Diff Reformatter -----===# | |
| # | |
| # The LLVM Compiler Infrastructure | |
| # | |
| # This file is distributed under the University of Illinois Open Source | |
| # License. See LICENSE.TXT for details. | |
| # | |
| #===------------------------------------------------------------------------===# | |
| import difflib | |
| import io | |
| import os | |
| import re | |
| import subprocess | |
| def parse_diff(diff_lines, prefix_strip=0): | |
| filename = None | |
| lines_by_file = {} | |
| for line in diff_lines: | |
| if line.startswith('diff --git') or line.startswith('--- '): | |
| filename = None | |
| match = re.search(r'^\+\+\+\ (.*?/){%s}(\S*)' % prefix_strip, line) | |
| if match: | |
| filename = match.group(2) | |
| if filename is None or not filename.endswith('.java'): | |
| continue | |
| match = re.search(r'^@@.*\+(\d+)(,(\d+))?', line) | |
| if match: | |
| start_line = int(match.group(1)) | |
| line_count = 1 | |
| if match.group(3): | |
| line_count = int(match.group(3)) | |
| if line_count == 0: | |
| continue | |
| end_line = start_line + line_count - 1 | |
| lines_by_file.setdefault(filename, []).extend( | |
| ['-lines', f'{start_line}:{end_line}']) | |
| return lines_by_file | |
| def get_base_command(java_binary, google_java_format_jar): | |
| return [ | |
| java_binary, | |
| # Disable hsperfdata to prevent lock contention on /tmp/hsperfdata_<user> during parallel execution. | |
| '-XX:+PerfDisableSharedMem', | |
| '--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED', | |
| '--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED', | |
| '--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', | |
| '--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED', | |
| '--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', | |
| '--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED', | |
| '-jar', | |
| google_java_format_jar, | |
| ] | |
| def format_file(filename, base_command, lines=None, fix_formatting=False): | |
| if not os.path.exists(filename): | |
| return [] | |
| command = base_command[:] | |
| if fix_formatting: | |
| command.append('-i') | |
| if lines: | |
| command.extend(lines) | |
| command.append(filename) | |
| p = subprocess.Popen(command, | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.PIPE) | |
| stdout, stderr = p.communicate() | |
| if p.returncode != 0: | |
| err_msg = stderr.decode('utf-8') if stderr else "Unknown error" | |
| return [f"Java formatting error on {filename}:\n{err_msg}"] | |
| if not fix_formatting: | |
| with open(filename) as f: | |
| code = f.readlines() | |
| formatted_code = io.StringIO(stdout.decode('utf-8')).readlines() | |
| diff = list( | |
| difflib.unified_diff(code, formatted_code, filename, filename, | |
| '(before formatting)', '(after formatting)')) | |
| if diff: | |
| return [''.join(diff)] | |
| return [] | |
| def format_files(lines_by_file, base_command, fix_formatting=False): | |
| errors = [] | |
| for filename, lines in lines_by_file.items(): | |
| errors.extend( | |
| format_file(filename, | |
| base_command, | |
| lines=lines, | |
| fix_formatting=fix_formatting)) | |
| return errors | |
| def format_diff(diff_text, | |
| google_java_format_jar, | |
| java_binary, | |
| fix_formatting=False, | |
| prefix_strip=0): | |
| lines_by_file = parse_diff(diff_text.splitlines(), | |
| prefix_strip=prefix_strip) | |
| if not lines_by_file: | |
| return [] | |
| base_command = get_base_command(java_binary, google_java_format_jar) | |
| return format_files(lines_by_file, | |
| base_command, | |
| fix_formatting=fix_formatting) |