mirror of https://github.com/python/cpython
GH-109408: Move the C file whitespace check from patchcheck to pre-commit (#109890)
Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com>
This commit is contained in:
parent
e24f9ae703
commit
f5edb56328
|
@ -32,6 +32,21 @@ repos:
|
||||||
types: [python]
|
types: [python]
|
||||||
exclude: '^(Lib/test/tokenizedata/|Tools/c-analyzer/cpython/_parser).*$'
|
exclude: '^(Lib/test/tokenizedata/|Tools/c-analyzer/cpython/_parser).*$'
|
||||||
|
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: c-file-whitespace
|
||||||
|
name: "Check C file whitespace"
|
||||||
|
entry: "python Tools/patchcheck/untabify.py"
|
||||||
|
language: "system"
|
||||||
|
types_or: ['c', 'c++']
|
||||||
|
# Don't check the style of vendored libraries
|
||||||
|
exclude: |
|
||||||
|
(?x)^(
|
||||||
|
Modules/_decimal/.*
|
||||||
|
| Modules/libmpdec/.*
|
||||||
|
| Modules/expat/.*
|
||||||
|
)$
|
||||||
|
|
||||||
- repo: https://github.com/sphinx-contrib/sphinx-lint
|
- repo: https://github.com/sphinx-contrib/sphinx-lint
|
||||||
rev: v0.6.8
|
rev: v0.6.8
|
||||||
hooks:
|
hooks:
|
||||||
|
|
|
@ -1,29 +1,15 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""Check proposed changes for common issues."""
|
"""Check proposed changes for common issues."""
|
||||||
import re
|
|
||||||
import sys
|
import sys
|
||||||
import shutil
|
|
||||||
import os.path
|
import os.path
|
||||||
import subprocess
|
import subprocess
|
||||||
import sysconfig
|
import sysconfig
|
||||||
|
|
||||||
import untabify
|
|
||||||
|
|
||||||
|
|
||||||
def get_python_source_dir():
|
def get_python_source_dir():
|
||||||
src_dir = sysconfig.get_config_var('abs_srcdir')
|
src_dir = sysconfig.get_config_var('abs_srcdir')
|
||||||
if not src_dir:
|
if not src_dir:
|
||||||
src_dir = sysconfig.get_config_var('srcdir')
|
src_dir = sysconfig.get_config_var('srcdir')
|
||||||
return os.path.abspath(src_dir)
|
return os.path.abspath(src_dir)
|
||||||
|
|
||||||
|
|
||||||
# Excluded directories which are copies of external libraries:
|
|
||||||
# don't check their coding style
|
|
||||||
EXCLUDE_DIRS = [
|
|
||||||
os.path.join('Modules', '_decimal', 'libmpdec'),
|
|
||||||
os.path.join('Modules', 'expat'),
|
|
||||||
os.path.join('Modules', 'zlib'),
|
|
||||||
]
|
|
||||||
SRCDIR = get_python_source_dir()
|
SRCDIR = get_python_source_dir()
|
||||||
|
|
||||||
|
|
||||||
|
@ -154,47 +140,8 @@ def changed_files(base_branch=None):
|
||||||
else:
|
else:
|
||||||
sys.exit('need a git checkout to get modified files')
|
sys.exit('need a git checkout to get modified files')
|
||||||
|
|
||||||
filenames2 = []
|
# Normalize the path to be able to match using str.startswith()
|
||||||
for filename in filenames:
|
return list(map(os.path.normpath, filenames))
|
||||||
# Normalize the path to be able to match using .startswith()
|
|
||||||
filename = os.path.normpath(filename)
|
|
||||||
if any(filename.startswith(path) for path in EXCLUDE_DIRS):
|
|
||||||
# Exclude the file
|
|
||||||
continue
|
|
||||||
filenames2.append(filename)
|
|
||||||
|
|
||||||
return filenames2
|
|
||||||
|
|
||||||
|
|
||||||
def report_modified_files(file_paths):
|
|
||||||
count = len(file_paths)
|
|
||||||
if count == 0:
|
|
||||||
return n_files_str(count)
|
|
||||||
else:
|
|
||||||
lines = [f"{n_files_str(count)}:"]
|
|
||||||
for path in file_paths:
|
|
||||||
lines.append(f" {path}")
|
|
||||||
return "\n".join(lines)
|
|
||||||
|
|
||||||
|
|
||||||
#: Python files that have tabs by design:
|
|
||||||
_PYTHON_FILES_WITH_TABS = frozenset({
|
|
||||||
'Tools/c-analyzer/cpython/_parser.py',
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
@status("Fixing C file whitespace", info=report_modified_files)
|
|
||||||
def normalize_c_whitespace(file_paths):
|
|
||||||
"""Report if any C files """
|
|
||||||
fixed = []
|
|
||||||
for path in file_paths:
|
|
||||||
abspath = os.path.join(SRCDIR, path)
|
|
||||||
with open(abspath, 'r') as f:
|
|
||||||
if '\t' not in f.read():
|
|
||||||
continue
|
|
||||||
untabify.process(abspath, 8, verbose=False)
|
|
||||||
fixed.append(path)
|
|
||||||
return fixed
|
|
||||||
|
|
||||||
|
|
||||||
@status("Docs modified", modal=True)
|
@status("Docs modified", modal=True)
|
||||||
|
@ -234,33 +181,12 @@ def regenerated_pyconfig_h_in(file_paths):
|
||||||
return "not needed"
|
return "not needed"
|
||||||
|
|
||||||
|
|
||||||
def ci(pull_request):
|
|
||||||
if pull_request == 'false':
|
|
||||||
print('Not a pull request; skipping')
|
|
||||||
return
|
|
||||||
base_branch = get_base_branch()
|
|
||||||
file_paths = changed_files(base_branch)
|
|
||||||
c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))]
|
|
||||||
fixed = []
|
|
||||||
fixed.extend(normalize_c_whitespace(c_files))
|
|
||||||
if not fixed:
|
|
||||||
print('No whitespace issues found')
|
|
||||||
else:
|
|
||||||
count = len(fixed)
|
|
||||||
print(f'Please fix the {n_files_str(count)} with whitespace issues')
|
|
||||||
print('(on Unix you can run `make patchcheck` to make the fixes)')
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
base_branch = get_base_branch()
|
base_branch = get_base_branch()
|
||||||
file_paths = changed_files(base_branch)
|
file_paths = changed_files(base_branch)
|
||||||
c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))]
|
|
||||||
doc_files = [fn for fn in file_paths if fn.startswith('Doc') and
|
doc_files = [fn for fn in file_paths if fn.startswith('Doc') and
|
||||||
fn.endswith(('.rst', '.inc'))]
|
fn.endswith(('.rst', '.inc'))]
|
||||||
misc_files = {p for p in file_paths if p.startswith('Misc')}
|
misc_files = {p for p in file_paths if p.startswith('Misc')}
|
||||||
# C rules enforcement.
|
|
||||||
normalize_c_whitespace(c_files)
|
|
||||||
# Docs updated.
|
# Docs updated.
|
||||||
docs_modified(doc_files)
|
docs_modified(doc_files)
|
||||||
# Misc/ACKS changed.
|
# Misc/ACKS changed.
|
||||||
|
@ -283,12 +209,4 @@ def main():
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import argparse
|
|
||||||
parser = argparse.ArgumentParser(description=__doc__)
|
|
||||||
parser.add_argument('--ci',
|
|
||||||
help='Perform pass/fail checks')
|
|
||||||
args = parser.parse_args()
|
|
||||||
if args.ci:
|
|
||||||
ci(args.ci)
|
|
||||||
else:
|
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -21,8 +21,7 @@ def main():
|
||||||
if optname == '-t':
|
if optname == '-t':
|
||||||
tabsize = int(optvalue)
|
tabsize = int(optvalue)
|
||||||
|
|
||||||
for filename in args:
|
return max(process(filename, tabsize) for filename in args)
|
||||||
process(filename, tabsize)
|
|
||||||
|
|
||||||
|
|
||||||
def process(filename, tabsize, verbose=True):
|
def process(filename, tabsize, verbose=True):
|
||||||
|
@ -32,10 +31,10 @@ def process(filename, tabsize, verbose=True):
|
||||||
encoding = f.encoding
|
encoding = f.encoding
|
||||||
except IOError as msg:
|
except IOError as msg:
|
||||||
print("%r: I/O error: %s" % (filename, msg))
|
print("%r: I/O error: %s" % (filename, msg))
|
||||||
return
|
return 2
|
||||||
newtext = text.expandtabs(tabsize)
|
newtext = text.expandtabs(tabsize)
|
||||||
if newtext == text:
|
if newtext == text:
|
||||||
return
|
return 0
|
||||||
backup = filename + "~"
|
backup = filename + "~"
|
||||||
try:
|
try:
|
||||||
os.unlink(backup)
|
os.unlink(backup)
|
||||||
|
@ -49,7 +48,8 @@ def process(filename, tabsize, verbose=True):
|
||||||
f.write(newtext)
|
f.write(newtext)
|
||||||
if verbose:
|
if verbose:
|
||||||
print(filename)
|
print(filename)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
raise SystemExit(main())
|
||||||
|
|
Loading…
Reference in New Issue