blob: c3d89ca5fdac3696d92a54bcffeb730eaef03839 [file] [log] [blame]
Søren Gjesseffc06192022-06-03 11:11:27 +02001#!/usr/bin/env python3
2#
3#===- google-java-format-diff.py - google-java-format Diff Reformatter -----===#
4#
5# The LLVM Compiler Infrastructure
6#
7# This file is distributed under the University of Illinois Open Source
8# License. See LICENSE.TXT for details.
9#
10#===------------------------------------------------------------------------===#
Søren Gjesseffc06192022-06-03 11:11:27 +020011"""
12google-java-format Diff Reformatter
13============================
14
15This script reads input from a unified diff and reformats all the changed
16lines. This is useful to reformat all the lines touched by a specific patch.
17Example usage for git/svn users:
18
19 git diff -U0 HEAD^ | google-java-format-diff.py -p1 -i
20 svn diff --diff-cmd=diff -x-U0 | google-java-format-diff.py -i
21
22For perforce users:
23
24 P4DIFF="git --no-pager diff --no-index" p4 diff | ./google-java-format-diff.py -i -p7
25
26"""
27
28import argparse
29import difflib
30import re
31import string
32import subprocess
33import io
34import os
35import sys
36from shutil import which
37
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +020038
Søren Gjesseffc06192022-06-03 11:11:27 +020039def main():
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +020040 parser = argparse.ArgumentParser(
41 description='Reformat changed lines in diff. Without -i '
42 'option just output the diff that would be '
43 'introduced.')
44 parser.add_argument(
45 '-i',
46 action='store_true',
47 default=False,
48 help='apply edits to files instead of displaying a diff')
Søren Gjesseffc06192022-06-03 11:11:27 +020049
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +020050 parser.add_argument('-p',
51 metavar='NUM',
52 default=0,
53 help='strip the smallest prefix containing P slashes')
54 parser.add_argument('-regex',
55 metavar='PATTERN',
56 default=None,
57 help='custom pattern selecting file paths to reformat '
58 '(case sensitive, overrides -iregex)')
59 parser.add_argument('-iregex',
60 metavar='PATTERN',
61 default=r'.*\.java',
62 help='custom pattern selecting file paths to reformat '
63 '(case insensitive, overridden by -regex)')
64 parser.add_argument('-v',
65 '--verbose',
66 action='store_true',
67 help='be more verbose, ineffective without -i')
68 parser.add_argument(
69 '-a',
70 '--aosp',
71 action='store_true',
72 help='use AOSP style instead of Google Style (4-space indentation)')
73 parser.add_argument('--skip-sorting-imports',
74 action='store_true',
75 help='do not fix the import order')
76 parser.add_argument('--skip-removing-unused-imports',
77 action='store_true',
78 help='do not remove ununsed imports')
79 parser.add_argument('--skip-javadoc-formatting',
80 action='store_true',
81 default=False,
82 help='do not reformat javadoc')
83 parser.add_argument('-b',
84 '--binary',
85 help='path to google-java-format binary')
86 parser.add_argument('--google-java-format-jar',
87 metavar='ABSOLUTE_PATH',
88 default=None,
89 help='use a custom google-java-format jar')
Søren Gjesseffc06192022-06-03 11:11:27 +020090
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +020091 args = parser.parse_args()
Søren Gjesseffc06192022-06-03 11:11:27 +020092
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +020093 # Extract changed lines for each file.
94 filename = None
95 lines_by_file = {}
Søren Gjesseffc06192022-06-03 11:11:27 +020096
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +020097 for line in sys.stdin:
98 match = re.search('^\+\+\+\ (.*?/){%s}(\S*)' % args.p, line)
99 if match:
100 filename = match.group(2)
101 if filename == None:
102 continue
Søren Gjesseffc06192022-06-03 11:11:27 +0200103
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200104 if args.regex is not None:
105 if not re.match('^%s$' % args.regex, filename):
106 continue
107 else:
108 if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE):
109 continue
110
111 match = re.search('^@@.*\+(\d+)(,(\d+))?', line)
112 if match:
113 start_line = int(match.group(1))
114 line_count = 1
115 if match.group(3):
116 line_count = int(match.group(3))
117 if line_count == 0:
118 continue
119 end_line = start_line + line_count - 1
120 lines_by_file.setdefault(filename, []).extend(
121 ['-lines', str(start_line) + ':' + str(end_line)])
122
123 if args.binary:
124 base_command = [args.binary]
125 elif args.google_java_format_jar:
126 base_command = [
127 os.path.join('third_party', 'openjdk', 'jdk-17', 'linux', 'bin',
128 'java'), '-jar',
129 '--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED',
130 '--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED',
131 '--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED',
132 '--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED',
133 '--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED',
134 '--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED',
135 args.google_java_format_jar
136 ]
Søren Gjesseffc06192022-06-03 11:11:27 +0200137 else:
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200138 binary = which('google-java-format') or '/usr/bin/google-java-format'
139 base_command = [binary]
Søren Gjesseffc06192022-06-03 11:11:27 +0200140
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200141 # Reformat files containing changes in place.
142 for filename, lines in lines_by_file.items():
143 if args.i and args.verbose:
144 print('Formatting', filename)
145 command = base_command[:]
146 if args.i:
147 command.append('-i')
148 if args.aosp:
149 command.append('--aosp')
150 if args.skip_sorting_imports:
151 command.append('--skip-sorting-imports')
152 if args.skip_removing_unused_imports:
153 command.append('--skip-removing-unused-imports')
154 if args.skip_javadoc_formatting:
155 command.append('--skip-javadoc-formatting')
156 command.extend(lines)
157 command.append(filename)
158 p = subprocess.Popen(command,
159 stdout=subprocess.PIPE,
160 stderr=None,
161 stdin=subprocess.PIPE)
162 stdout, stderr = p.communicate()
163 if p.returncode != 0:
164 sys.exit(p.returncode)
Søren Gjesseffc06192022-06-03 11:11:27 +0200165
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200166 if not args.i:
167 with open(filename) as f:
168 code = f.readlines()
169 formatted_code = io.StringIO(stdout.decode('utf-8')).readlines()
170 diff = difflib.unified_diff(code, formatted_code, filename,
171 filename, '(before formatting)',
172 '(after formatting)')
173 diff_string = ''.join(diff)
174 if len(diff_string) > 0:
175 sys.stdout.write(diff_string)
Søren Gjesseffc06192022-06-03 11:11:27 +0200176
Søren Gjesseffc06192022-06-03 11:11:27 +0200177
178if __name__ == '__main__':
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200179 main()