| #!/usr/bin/env python3 | |
| # Copyright lowRISC contributors. | |
| # Licensed under the Apache License, Version 2.0, see LICENSE for details. | |
| # SPDX-License-Identifier: Apache-2.0 | |
| # fix_trailing_whitespace.py script ensures that all files passed into it satisfy | |
| # various requirements in terms of whitespace: | |
| # - There is no leading whitespace in the file. | |
| # - Lines do not have trailing non-newline whitespace and have UNIX-style line endings. | |
| # - The file ends in a single newline. | |
| import argparse | |
| import sys | |
| import subprocess | |
| from pathlib import Path | |
| # This file is $REPO_TOP/util/fix_trailing_newlines.py, so it takes two parent() | |
| # calls to get back to the top. | |
| REPO_TOP = Path(__file__).resolve().parent.parent | |
| def is_ignored(path): | |
| return subprocess.run(['git', 'check-ignore', path]).returncode == 0 | |
| def walk_tree(paths=[REPO_TOP]): | |
| for path in paths: | |
| if isinstance(path, str): | |
| path = Path(path) | |
| if path.is_symlink() or is_ignored(path) or 'LICENSE' in path.parts: | |
| continue | |
| if path.is_dir() and 'vendor' not in path.parts: | |
| yield from walk_tree(path.iterdir()) | |
| else: | |
| yield path | |
| def main(): | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument( | |
| '--dry-run', | |
| action='store_true', | |
| help='report writes which would have happened') | |
| parser.add_argument( | |
| '--recursive', '-r', | |
| action='store_true', | |
| default=False, | |
| help='traverse the entire tree modolo .gitignore' | |
| ) | |
| parser.add_argument( | |
| '--verbose', '-v', | |
| action='store_true', | |
| help='verbose output') | |
| parser.add_argument( | |
| 'files', | |
| type=str, | |
| nargs='*', | |
| help='files to fix whitespace for') | |
| args = parser.parse_args() | |
| files = args.files | |
| if args.recursive: | |
| files = walk_tree(args.files) | |
| total_fixable = 0 | |
| for path in files: | |
| path = Path(path).resolve().relative_to(REPO_TOP) | |
| if not path.is_file() or path.is_symlink(): | |
| continue | |
| if 'vendor' in path.parts or path.suffix in ['.patch', '.svg', '.tpl']: | |
| continue | |
| if args.verbose: | |
| print(f'Checking: "{path}"') | |
| try: | |
| old_text = path.read_text() | |
| except UnicodeDecodeError: | |
| print(f'Binary file: "{path}"') | |
| continue | |
| new_text = "\n".join([line.rstrip() for line in old_text.strip().split("\n")]) + "\n" | |
| if old_text != new_text: | |
| print(f'Fixing file: "{path}"', file=sys.stdout) | |
| total_fixable += 1 | |
| if not args.dry_run: | |
| path.write_text(new_text) | |
| if total_fixable: | |
| verb = 'Would have fixed' if args.dry_run else 'Fixed' | |
| print(f'{verb} {total_fixable} files.', file=sys.stderr) | |
| # Pass if we fixed everything or there was nothing to fix. | |
| return 1 if total_fixable > 0 else 0 | |
| if __name__ == '__main__': | |
| sys.exit(main()) |