1*c8dee2aaSAndroid Build Coastguard Worker#!/usr/bin/env python 2*c8dee2aaSAndroid Build Coastguard Worker# Copyright (c) 2012 The Chromium Authors. All rights reserved. 3*c8dee2aaSAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*c8dee2aaSAndroid Build Coastguard Worker# found in the LICENSE file. 5*c8dee2aaSAndroid Build Coastguard Worker 6*c8dee2aaSAndroid Build Coastguard Worker 7*c8dee2aaSAndroid Build Coastguard Worker"""Module that sanitizes source files with specified modifiers.""" 8*c8dee2aaSAndroid Build Coastguard Worker 9*c8dee2aaSAndroid Build Coastguard Worker 10*c8dee2aaSAndroid Build Coastguard Workerfrom __future__ import print_function 11*c8dee2aaSAndroid Build Coastguard Workerimport commands 12*c8dee2aaSAndroid Build Coastguard Workerimport os 13*c8dee2aaSAndroid Build Coastguard Workerimport sys 14*c8dee2aaSAndroid Build Coastguard Worker 15*c8dee2aaSAndroid Build Coastguard Worker 16*c8dee2aaSAndroid Build Coastguard Worker_FILE_EXTENSIONS_TO_SANITIZE = ['cpp', 'h', 'c'] 17*c8dee2aaSAndroid Build Coastguard Worker 18*c8dee2aaSAndroid Build Coastguard Worker_SUBDIRS_TO_IGNORE = ['.git', '.svn', 'third_party'] 19*c8dee2aaSAndroid Build Coastguard Worker 20*c8dee2aaSAndroid Build Coastguard Worker 21*c8dee2aaSAndroid Build Coastguard Workerdef SanitizeFilesWithModifiers(directory, file_modifiers, line_modifiers): 22*c8dee2aaSAndroid Build Coastguard Worker """Sanitizes source files with the specified file and line modifiers. 23*c8dee2aaSAndroid Build Coastguard Worker 24*c8dee2aaSAndroid Build Coastguard Worker Args: 25*c8dee2aaSAndroid Build Coastguard Worker directory: string - The directory which will be recursively traversed to 26*c8dee2aaSAndroid Build Coastguard Worker find source files to apply modifiers to. 27*c8dee2aaSAndroid Build Coastguard Worker file_modifiers: list - file-modification methods which should be applied to 28*c8dee2aaSAndroid Build Coastguard Worker the complete file content (Eg: EOFOneAndOnlyOneNewlineAdder). 29*c8dee2aaSAndroid Build Coastguard Worker line_modifiers: list - line-modification methods which should be applied to 30*c8dee2aaSAndroid Build Coastguard Worker lines in a file (Eg: TabReplacer). 31*c8dee2aaSAndroid Build Coastguard Worker """ 32*c8dee2aaSAndroid Build Coastguard Worker for item in os.listdir(directory): 33*c8dee2aaSAndroid Build Coastguard Worker 34*c8dee2aaSAndroid Build Coastguard Worker full_item_path = os.path.join(directory, item) 35*c8dee2aaSAndroid Build Coastguard Worker 36*c8dee2aaSAndroid Build Coastguard Worker if os.path.isfile(full_item_path): # Item is a file. 37*c8dee2aaSAndroid Build Coastguard Worker 38*c8dee2aaSAndroid Build Coastguard Worker # Only sanitize files with extensions we care about. 39*c8dee2aaSAndroid Build Coastguard Worker if (len(full_item_path.split('.')) > 1 and 40*c8dee2aaSAndroid Build Coastguard Worker full_item_path.split('.')[-1] in _FILE_EXTENSIONS_TO_SANITIZE): 41*c8dee2aaSAndroid Build Coastguard Worker f = file(full_item_path) 42*c8dee2aaSAndroid Build Coastguard Worker try: 43*c8dee2aaSAndroid Build Coastguard Worker lines = f.readlines() 44*c8dee2aaSAndroid Build Coastguard Worker finally: 45*c8dee2aaSAndroid Build Coastguard Worker f.close() 46*c8dee2aaSAndroid Build Coastguard Worker 47*c8dee2aaSAndroid Build Coastguard Worker new_lines = [] # Collect changed lines here. 48*c8dee2aaSAndroid Build Coastguard Worker line_number = 0 # Keeps track of line numbers in the source file. 49*c8dee2aaSAndroid Build Coastguard Worker write_to_file = False # File is written to only if this flag is set. 50*c8dee2aaSAndroid Build Coastguard Worker 51*c8dee2aaSAndroid Build Coastguard Worker # Run the line modifiers for each line in this file. 52*c8dee2aaSAndroid Build Coastguard Worker for line in lines: 53*c8dee2aaSAndroid Build Coastguard Worker original_line = line 54*c8dee2aaSAndroid Build Coastguard Worker line_number += 1 55*c8dee2aaSAndroid Build Coastguard Worker 56*c8dee2aaSAndroid Build Coastguard Worker for modifier in line_modifiers: 57*c8dee2aaSAndroid Build Coastguard Worker line = modifier(line, full_item_path, line_number) 58*c8dee2aaSAndroid Build Coastguard Worker if original_line != line: 59*c8dee2aaSAndroid Build Coastguard Worker write_to_file = True 60*c8dee2aaSAndroid Build Coastguard Worker new_lines.append(line) 61*c8dee2aaSAndroid Build Coastguard Worker 62*c8dee2aaSAndroid Build Coastguard Worker # Run the file modifiers. 63*c8dee2aaSAndroid Build Coastguard Worker old_content = ''.join(lines) 64*c8dee2aaSAndroid Build Coastguard Worker new_content = ''.join(new_lines) 65*c8dee2aaSAndroid Build Coastguard Worker for modifier in file_modifiers: 66*c8dee2aaSAndroid Build Coastguard Worker new_content = modifier(new_content, full_item_path) 67*c8dee2aaSAndroid Build Coastguard Worker if new_content != old_content: 68*c8dee2aaSAndroid Build Coastguard Worker write_to_file = True 69*c8dee2aaSAndroid Build Coastguard Worker 70*c8dee2aaSAndroid Build Coastguard Worker # Write modifications to the file. 71*c8dee2aaSAndroid Build Coastguard Worker if write_to_file: 72*c8dee2aaSAndroid Build Coastguard Worker f = file(full_item_path, 'w') 73*c8dee2aaSAndroid Build Coastguard Worker try: 74*c8dee2aaSAndroid Build Coastguard Worker f.write(new_content) 75*c8dee2aaSAndroid Build Coastguard Worker finally: 76*c8dee2aaSAndroid Build Coastguard Worker f.close() 77*c8dee2aaSAndroid Build Coastguard Worker print('Made changes to %s' % full_item_path) 78*c8dee2aaSAndroid Build Coastguard Worker 79*c8dee2aaSAndroid Build Coastguard Worker elif item not in _SUBDIRS_TO_IGNORE: 80*c8dee2aaSAndroid Build Coastguard Worker # Item is a directory recursively call the method. 81*c8dee2aaSAndroid Build Coastguard Worker SanitizeFilesWithModifiers(full_item_path, file_modifiers, line_modifiers) 82*c8dee2aaSAndroid Build Coastguard Worker 83*c8dee2aaSAndroid Build Coastguard Worker 84*c8dee2aaSAndroid Build Coastguard Worker############## Line Modification methods ############## 85*c8dee2aaSAndroid Build Coastguard Worker 86*c8dee2aaSAndroid Build Coastguard Worker 87*c8dee2aaSAndroid Build Coastguard Workerdef TrailingWhitespaceRemover(line, file_path, line_number): 88*c8dee2aaSAndroid Build Coastguard Worker """Strips out trailing whitespaces from the specified line.""" 89*c8dee2aaSAndroid Build Coastguard Worker stripped_line = line.rstrip() + '\n' 90*c8dee2aaSAndroid Build Coastguard Worker if line != stripped_line: 91*c8dee2aaSAndroid Build Coastguard Worker print('Removing trailing whitespace in %s:%s' % (file_path, line_number)) 92*c8dee2aaSAndroid Build Coastguard Worker return stripped_line 93*c8dee2aaSAndroid Build Coastguard Worker 94*c8dee2aaSAndroid Build Coastguard Worker 95*c8dee2aaSAndroid Build Coastguard Workerdef CrlfReplacer(line, file_path, line_number): 96*c8dee2aaSAndroid Build Coastguard Worker """Replaces CRLF with LF.""" 97*c8dee2aaSAndroid Build Coastguard Worker if '\r\n' in line: 98*c8dee2aaSAndroid Build Coastguard Worker print('Replacing CRLF with LF in %s:%s' % (file_path, line_number)) 99*c8dee2aaSAndroid Build Coastguard Worker return line.replace('\r\n', '\n') 100*c8dee2aaSAndroid Build Coastguard Worker 101*c8dee2aaSAndroid Build Coastguard Worker 102*c8dee2aaSAndroid Build Coastguard Workerdef TabReplacer(line, file_path, line_number): 103*c8dee2aaSAndroid Build Coastguard Worker """Replaces Tabs with 4 whitespaces.""" 104*c8dee2aaSAndroid Build Coastguard Worker if '\t' in line: 105*c8dee2aaSAndroid Build Coastguard Worker print('Replacing Tab with whitespace in %s:%s' % (file_path, line_number)) 106*c8dee2aaSAndroid Build Coastguard Worker return line.replace('\t', ' ') 107*c8dee2aaSAndroid Build Coastguard Worker 108*c8dee2aaSAndroid Build Coastguard Worker 109*c8dee2aaSAndroid Build Coastguard Worker############## File Modification methods ############## 110*c8dee2aaSAndroid Build Coastguard Worker 111*c8dee2aaSAndroid Build Coastguard Worker 112*c8dee2aaSAndroid Build Coastguard Workerdef CopywriteChecker(file_content, unused_file_path): 113*c8dee2aaSAndroid Build Coastguard Worker """Ensures that the copywrite information is correct.""" 114*c8dee2aaSAndroid Build Coastguard Worker # TODO(rmistry): Figure out the legal implications of changing old copyright 115*c8dee2aaSAndroid Build Coastguard Worker # headers. 116*c8dee2aaSAndroid Build Coastguard Worker return file_content 117*c8dee2aaSAndroid Build Coastguard Worker 118*c8dee2aaSAndroid Build Coastguard Worker 119*c8dee2aaSAndroid Build Coastguard Workerdef EOFOneAndOnlyOneNewlineAdder(file_content, file_path): 120*c8dee2aaSAndroid Build Coastguard Worker """Adds one and only one LF at the end of the file.""" 121*c8dee2aaSAndroid Build Coastguard Worker if file_content and (file_content[-1] != '\n' or file_content[-2:-1] == '\n'): 122*c8dee2aaSAndroid Build Coastguard Worker file_content = file_content.rstrip() 123*c8dee2aaSAndroid Build Coastguard Worker file_content += '\n' 124*c8dee2aaSAndroid Build Coastguard Worker print('Added exactly one newline to %s' % file_path) 125*c8dee2aaSAndroid Build Coastguard Worker return file_content 126*c8dee2aaSAndroid Build Coastguard Worker 127*c8dee2aaSAndroid Build Coastguard Worker 128*c8dee2aaSAndroid Build Coastguard Workerdef SvnEOLChecker(file_content, file_path): 129*c8dee2aaSAndroid Build Coastguard Worker """Sets svn:eol-style property to LF.""" 130*c8dee2aaSAndroid Build Coastguard Worker output = commands.getoutput( 131*c8dee2aaSAndroid Build Coastguard Worker 'svn propget svn:eol-style %s' % file_path) 132*c8dee2aaSAndroid Build Coastguard Worker if output != 'LF': 133*c8dee2aaSAndroid Build Coastguard Worker print('Setting svn:eol-style property to LF in %s' % file_path) 134*c8dee2aaSAndroid Build Coastguard Worker os.system('svn ps svn:eol-style LF %s' % file_path) 135*c8dee2aaSAndroid Build Coastguard Worker return file_content 136*c8dee2aaSAndroid Build Coastguard Worker 137*c8dee2aaSAndroid Build Coastguard Worker 138*c8dee2aaSAndroid Build Coastguard Worker####################################################### 139*c8dee2aaSAndroid Build Coastguard Worker 140*c8dee2aaSAndroid Build Coastguard Worker 141*c8dee2aaSAndroid Build Coastguard Workerif '__main__' == __name__: 142*c8dee2aaSAndroid Build Coastguard Worker sys.exit(SanitizeFilesWithModifiers( 143*c8dee2aaSAndroid Build Coastguard Worker os.getcwd(), 144*c8dee2aaSAndroid Build Coastguard Worker file_modifiers=[ 145*c8dee2aaSAndroid Build Coastguard Worker CopywriteChecker, 146*c8dee2aaSAndroid Build Coastguard Worker EOFOneAndOnlyOneNewlineAdder, 147*c8dee2aaSAndroid Build Coastguard Worker SvnEOLChecker, 148*c8dee2aaSAndroid Build Coastguard Worker ], 149*c8dee2aaSAndroid Build Coastguard Worker line_modifiers=[ 150*c8dee2aaSAndroid Build Coastguard Worker CrlfReplacer, 151*c8dee2aaSAndroid Build Coastguard Worker TabReplacer, 152*c8dee2aaSAndroid Build Coastguard Worker TrailingWhitespaceRemover, 153*c8dee2aaSAndroid Build Coastguard Worker ], 154*c8dee2aaSAndroid Build Coastguard Worker )) 155