-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathcheck-google-java-format.py
More file actions
executable file
·142 lines (113 loc) · 4.39 KB
/
check-google-java-format.py
File metadata and controls
executable file
·142 lines (113 loc) · 4.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!/usr/bin/env python3
"""A wrapper around the google-java-format program, with improvements.
This script checks whether the files supplied on the command line conform
to the Google Java style (as enforced by the google-java-format program,
but with improvements to the formatting of annotations in comments).
If any files would be affected by running run-google-java-format.py,
this script prints their names and returns a non-zero status.
If called with no arguments, it reads from standard input.
You could invoke this program, for example, in a git pre-commit hook.
"""
# TODO: Thanks to https://github.com/google/google-java-format/pull/106
# this script can be eliminated, or its interface simplified.
import filecmp
import pathlib
import shutil
import stat
import subprocess
import sys
import tempfile
from pathlib import Path
from shutil import copyfileobj
try:
from urllib import urlopen # type: ignore[attr-defined]
except ImportError:
from urllib.request import urlopen
debug = False
# debug = True
script_dir = Path.resolve(Path(__file__)).parent
run_py_name = "run-google-java-format.py"
run_py_path = script_dir / run_py_name
# For some reason, the "git ls-files" must be run from the root.
# (I can run "git ls-files" from the command line in any directory.)
def under_git(directory: Path, filename: str) -> bool:
"""Return true if `filename` in `directory` is under git control.
Args:
directory: the directory
filename: the file name
Returns:
true if `filename` in `directory` is under git control.
"""
if not shutil.which("git"):
if debug:
print("no git executable found")
return False
with subprocess.Popen(
["git", "ls-files", filename, "--error-unmatch"],
cwd=directory,
stdout=subprocess.DEVNULL,
stderr=subprocess.STDOUT,
) as p:
p.wait()
if debug:
print("p.returncode", p.returncode)
return p.returncode == 0
def urlretrieve(url: str, filename: Path) -> None:
"""Like urllib.urlretrieve."""
with urlopen(url) as in_stream, pathlib.Path(filename).open("wb") as out_file:
copyfileobj(in_stream, out_file)
# Don't replace local with remote if local is under version control.
# It would be better to just test whether the remote is newer than local,
# but raw GitHub URLs don't have the necessary last-modified information.
if not under_git(script_dir, run_py_name):
url = "https://raw.githubusercontent.com/plume-lib/run-google-java-format/master/" + run_py_name
try:
urlretrieve(url, run_py_path)
except Exception:
if run_py_path.exists():
print("Couldn't retrieve " + run_py_name + " from " + url + "; using cached version")
else:
print("Couldn't retrieve " + run_py_name + " from " + url)
sys.exit(1)
run_py_path.chmod(run_py_path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
temp_dir = tempfile.mkdtemp(prefix="check-google-java-format-")
def temporary_file_name() -> str:
"""Return the name of a temporary file.
Returns:
the name of a temporary file.
"""
return str(Path(temp_dir) / next(tempfile._get_candidate_names())) # type: ignore[attr-defined] # noqa: SLF001
def cleanup() -> None:
"""Clean up temporary files."""
shutil.rmtree(temp_dir)
files = sys.argv[1:]
if len(files) == 0:
content = sys.stdin.read()
fname = temporary_file_name() + ".java"
with pathlib.Path(fname).open("w") as outfile:
print(content, file=outfile)
files = [fname]
temps = []
cmdlineargs = [f for f in files if f.startswith("-")]
files = [f for f in files if not f.startswith("-")]
for fname in files:
ftemp = temporary_file_name() + "_" + pathlib.Path(fname).name
shutil.copyfile(fname, ftemp)
temps.append(ftemp)
if debug:
print("Running " + run_py_name)
# Problem: if a file is syntactically illegal, this outputs the temporary file
# name rather than the real file name.
# Minor optimization: To save one process creation, could call directly in Python.
result = subprocess.call([run_py_path, *cmdlineargs, *temps])
if result != 0:
cleanup()
sys.exit(result)
exit_code = 0
for i, file in enumerate(files):
if not filecmp.cmp(file, temps[i]):
# TODO: gives temporary file name if reading from stdin
print("Improper formatting:", file)
exit_code = 1
cleanup()
sys.exit(exit_code)