1#!/usr/bin/env python3 2# 3# Arm SCP/MCP Software 4# Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved. 5# 6# SPDX-License-Identifier: BSD-3-Clause 7# 8""" 9 Check for tabs in the source code. 10""" 11import argparse 12import os 13import shutil 14import subprocess 15import sys 16import tempfile 17import glob 18from utils import banner, get_filtered_files 19 20# 21# Directories to exclude 22# 23 24# Exclude all mod_test 'mocks' directories 25UNIT_TEST_MOCKS = glob.glob('module/**/test/**/mocks', recursive=True) +\ 26 glob.glob('product/**/test/**/mocks', recursive=True) 27 28EXCLUDE_DIRECTORIES = [ 29 '.git', 30 'build', 31 'contrib', 32 'product/rcar/src/CMSIS-FreeRTOS', 33 'unit_test/unity_mocks', 34] + UNIT_TEST_MOCKS 35 36# 37# File types to check 38# 39FILE_TYPES = [ 40 '*.c', 41 '*.h', 42 '*.py', 43 'CMakeLists.txt', 44] 45 46 47def convert_tabs_to_spaces(path): 48 print(f'\tConverting all tabs in {path} into spaces...') 49 try: 50 _, temp_file = tempfile.mkstemp(prefix='tabs_to_spaces_') 51 print(f'Using {temp_file}') 52 subprocess.check_call(f'expand -t4 {path} > {temp_file}', 53 shell=True) 54 shutil.copyfile(temp_file, path) 55 except Exception as e: 56 print(f'Error: Failed to convert file {path} with {e}') 57 sys.exit(1) 58 finally: 59 if os.path.exists(temp_file): 60 os.remove(temp_file) 61 62 63def check_files(file_paths, convert): 64 tabs_found_count = 0 65 66 for path in file_paths: 67 try: 68 with open(path, encoding='utf-8') as file: 69 file_has_tabs = False 70 for line, string in enumerate(file): 71 if '\t' in string: 72 print(f'{path}:{line + 1} has tab instead of spaces') 73 tabs_found_count += 1 74 file_has_tabs = True 75 if convert and file_has_tabs: 76 convert_tabs_to_spaces(path) 77 except UnicodeDecodeError: 78 print(f'Invalid file format {path}') 79 return tabs_found_count 80 81 82def run(convert=False): 83 print(banner('Checking the presence of tabs in the code...')) 84 85 if convert: 86 print('Conversion mode is enabled.') 87 88 files = get_filtered_files(EXCLUDE_DIRECTORIES, FILE_TYPES) 89 tabs_found_count = check_files(files, convert) 90 if tabs_found_count == 0: 91 print('No tabs found') 92 return True 93 94 print(f'{tabs_found_count} tab(s) found.') 95 return False 96 97 98def parse_args(argv, prog_name): 99 parser = argparse.ArgumentParser( 100 prog=prog_name, 101 description='Perform checks for presence of tabs in the code') 102 103 parser.add_argument('-c', '--convert', dest='convert', 104 required=False, default=False, action='store_true', 105 help='Convert tabs to 4 spaces.') 106 107 return parser.parse_args(argv) 108 109 110def main(argv=[], prog_name=''): 111 args = parse_args(argv, prog_name) 112 return 0 if run(args.convert) else 1 113 114 115if __name__ == '__main__': 116 sys.exit(main(sys.argv[1:], sys.argv[0])) 117