| #!/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()) |