|  |  |  |  |  |  | 
														
													
														
															|  |  |  |  |  | import argparse | 
														
													
														
															|  |  |  |  |  | from typing_extensions import Protocol | 
														
													
														
															|  |  |  |  |  | 
 | 
														
													
														
															|  |  |  |  |  | import yapf | 
														
													
														
															|  |  |  |  |  | 
 | 
														
													
														
															|  |  |  |  |  | from . import paths, proc | 
														
													
														
															|  |  |  |  |  | 
 | 
														
													
														
															|  |  |  |  |  | 
 | 
														
													
														
															|  |  |  |  |  | class FormatArguments(Protocol): | 
														
													
														
															|  |  |  |  |  | check: bool | 
														
													
														
															|  |  |  |  |  | cpp: bool | 
														
													
														
															|  |  |  |  |  | py: bool | 
														
													
														
															|  |  |  |  |  | 
 | 
														
													
														
															|  |  |  |  |  | 
 | 
														
													
														
															|  |  |  |  |  | def start() -> None: | 
														
													
														
															|  |  |  |  |  | parser = argparse.ArgumentParser() | 
														
													
														
															|  |  |  |  |  | parser.add_argument('--check', | 
														
													
														
															|  |  |  |  |  | help='Check whether files need to be formatted, but do not modify them.', | 
														
													
														
															|  |  |  |  |  | action='store_true') | 
														
													
														
															|  |  |  |  |  | parser.add_argument('--no-cpp', help='Skip formatting/checking C++ files', action='store_false', dest='cpp') | 
														
													
														
															|  |  |  |  |  | parser.add_argument('--no-py', help='Skip formatting/checking Python files', action='store_false', dest='py') | 
														
													
														
															|  |  |  |  |  | args: FormatArguments = parser.parse_args() | 
														
													
														
															|  |  |  |  |  | 
 | 
														
													
														
															|  |  |  |  |  | if args.cpp: | 
														
													
														
															|  |  |  |  |  | format_cpp(args) | 
														
													
														
															|  |  |  |  |  | if args.py: | 
														
													
														
															|  |  |  |  |  | format_py(args) | 
														
													
														
															|  |  |  |  |  | 
 | 
														
													
														
															|  |  |  |  |  | 
 | 
														
													
														
															|  |  |  |  |  | def format_cpp(args: FormatArguments) -> None: | 
														
													
														
															|  |  |  |  |  | src_dir = paths.PROJECT_ROOT / 'src' | 
														
													
														
															|  |  |  |  |  | cpp_files = src_dir.glob('**/*.[hc]pp') | 
														
													
														
															|  |  |  |  |  | cf_args: proc.CommandLine = [ | 
														
													
														
															|  |  |  |  |  | ('--dry-run', '--Werror') if args.check else (), | 
														
													
														
															|  |  |  |  |  | '-i',  # Modify files in-place | 
														
													
														
															|  |  |  |  |  | '--verbose', | 
														
													
														
															|  |  |  |  |  | ] | 
														
													
														
															|  |  |  |  |  | for cf_cand in ('clang-format-10', 'clang-format-9', 'clang-format-8', 'clang-format'): | 
														
													
														
															|  |  |  |  |  | cf = paths.find_exe(cf_cand) | 
														
													
														
															|  |  |  |  |  | if not cf: | 
														
													
														
															|  |  |  |  |  | continue | 
														
													
														
															|  |  |  |  |  | break | 
														
													
														
															|  |  |  |  |  | else: | 
														
													
														
															|  |  |  |  |  | raise RuntimeError('No clang-format executable found') | 
														
													
														
															|  |  |  |  |  | 
 | 
														
													
														
															|  |  |  |  |  | print(f'Using clang-format: {cf_cand}') | 
														
													
														
															|  |  |  |  |  | res = proc.run([cf, cf_args, cpp_files]) | 
														
													
														
															|  |  |  |  |  | if res.returncode and args.check: | 
														
													
														
															|  |  |  |  |  | raise RuntimeError('Format checks failed for one or more C++ files. (See above.)') | 
														
													
														
															|  |  |  |  |  | if res.returncode: | 
														
													
														
															|  |  |  |  |  | raise RuntimeError('Format execution failed. Check output above.') | 
														
													
														
															|  |  |  |  |  | 
 | 
														
													
														
															|  |  |  |  |  | 
 | 
														
													
														
															|  |  |  |  |  | def format_py(args: FormatArguments) -> None: | 
														
													
														
															|  |  |  |  |  | py_files = paths.TOOLS_DIR.rglob('*.py') | 
														
													
														
															|  |  |  |  |  | rc = yapf.main( | 
														
													
														
															|  |  |  |  |  | list(proc.flatten_cmd([ | 
														
													
														
															|  |  |  |  |  | '--parallel', | 
														
													
														
															|  |  |  |  |  | '--verbose', | 
														
													
														
															|  |  |  |  |  | ('--diff') if args.check else ('--in-place'), | 
														
													
														
															|  |  |  |  |  | py_files, | 
														
													
														
															|  |  |  |  |  | ]))) | 
														
													
														
															|  |  |  |  |  | if rc and args.check: | 
														
													
														
															|  |  |  |  |  | raise RuntimeError('Format checks for one or more Python files. (See above.)') | 
														
													
														
															|  |  |  |  |  | if rc: | 
														
													
														
															|  |  |  |  |  | raise RuntimeError('Format execution failed for Python code. See above.') | 
														
													
														
															|  |  |  |  |  | 
 | 
														
													
														
															|  |  |  |  |  | 
 | 
														
													
														
															|  |  |  |  |  | if __name__ == "__main__": | 
														
													
														
															|  |  |  |  |  | start() |